source: azure_iot_hub_f767zi/trunk/asp_baseplatform/lwip/lwip-2.1.2/src/api/api_msg.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 66.6 KB
Line 
1/**
2 * @file
3 * Sequential API Internal module
4 *
5 */
6
7/*
8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31 * OF SUCH DAMAGE.
32 *
33 * This file is part of the lwIP TCP/IP stack.
34 *
35 * Author: Adam Dunkels <adam@sics.se>
36 *
37 */
38
39#include "lwip/opt.h"
40
41#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
42
43#include "lwip/priv/api_msg.h"
44
45#include "lwip/ip.h"
46#include "lwip/ip_addr.h"
47#include "lwip/udp.h"
48#include "lwip/tcp.h"
49#include "lwip/raw.h"
50
51#include "lwip/memp.h"
52#include "lwip/igmp.h"
53#include "lwip/dns.h"
54#include "lwip/mld6.h"
55#include "lwip/priv/tcpip_priv.h"
56
57#include <string.h>
58
59/* netconns are polled once per second (e.g. continue write on memory error) */
60#define NETCONN_TCP_POLL_INTERVAL 2
61
62#define SET_NONBLOCKING_CONNECT(conn, val) do { if (val) { \
63 netconn_set_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); \
64} else { \
65 netconn_clear_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); }} while(0)
66#define IN_NONBLOCKING_CONNECT(conn) netconn_is_flag_set(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT)
67
68#if LWIP_NETCONN_FULLDUPLEX
69#define NETCONN_MBOX_VALID(conn, mbox) (sys_mbox_valid(mbox) && ((conn->flags & NETCONN_FLAG_MBOXINVALID) == 0))
70#else
71#define NETCONN_MBOX_VALID(conn, mbox) sys_mbox_valid(mbox)
72#endif
73
74/* forward declarations */
75#if LWIP_TCP
76#if LWIP_TCPIP_CORE_LOCKING
77#define WRITE_DELAYED , 1
78#define WRITE_DELAYED_PARAM , u8_t delayed
79#else /* LWIP_TCPIP_CORE_LOCKING */
80#define WRITE_DELAYED
81#define WRITE_DELAYED_PARAM
82#endif /* LWIP_TCPIP_CORE_LOCKING */
83static err_t lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM);
84static err_t lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM);
85#endif
86
87static void netconn_drain(struct netconn *conn);
88
89#if LWIP_TCPIP_CORE_LOCKING
90#define TCPIP_APIMSG_ACK(m)
91#else /* LWIP_TCPIP_CORE_LOCKING */
92#define TCPIP_APIMSG_ACK(m) do { sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
93#endif /* LWIP_TCPIP_CORE_LOCKING */
94
95#if LWIP_NETCONN_FULLDUPLEX
96const u8_t netconn_deleted = 0;
97
98int
99lwip_netconn_is_deallocated_msg(void *msg)
100{
101 if (msg == &netconn_deleted) {
102 return 1;
103 }
104 return 0;
105}
106#endif /* LWIP_NETCONN_FULLDUPLEX */
107
108#if LWIP_TCP
109const u8_t netconn_aborted = 0;
110const u8_t netconn_reset = 0;
111const u8_t netconn_closed = 0;
112
113/** Translate an error to a unique void* passed via an mbox */
114static void *
115lwip_netconn_err_to_msg(err_t err)
116{
117 switch (err) {
118 case ERR_ABRT:
119 return LWIP_CONST_CAST(void *, &netconn_aborted);
120 case ERR_RST:
121 return LWIP_CONST_CAST(void *, &netconn_reset);
122 case ERR_CLSD:
123 return LWIP_CONST_CAST(void *, &netconn_closed);
124 default:
125 LWIP_ASSERT("unhandled error", err == ERR_OK);
126 return NULL;
127 }
128}
129
130int
131lwip_netconn_is_err_msg(void *msg, err_t *err)
132{
133 LWIP_ASSERT("err != NULL", err != NULL);
134
135 if (msg == &netconn_aborted) {
136 *err = ERR_ABRT;
137 return 1;
138 } else if (msg == &netconn_reset) {
139 *err = ERR_RST;
140 return 1;
141 } else if (msg == &netconn_closed) {
142 *err = ERR_CLSD;
143 return 1;
144 }
145 return 0;
146}
147#endif /* LWIP_TCP */
148
149
150#if LWIP_RAW
151/**
152 * Receive callback function for RAW netconns.
153 * Doesn't 'eat' the packet, only copies it and sends it to
154 * conn->recvmbox
155 *
156 * @see raw.h (struct raw_pcb.recv) for parameters and return value
157 */
158static u8_t
159recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
160 const ip_addr_t *addr)
161{
162 struct pbuf *q;
163 struct netbuf *buf;
164 struct netconn *conn;
165
166 LWIP_UNUSED_ARG(addr);
167 conn = (struct netconn *)arg;
168
169 if ((conn != NULL) && NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
170#if LWIP_SO_RCVBUF
171 int recv_avail;
172 SYS_ARCH_GET(conn->recv_avail, recv_avail);
173 if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
174 return 0;
175 }
176#endif /* LWIP_SO_RCVBUF */
177 /* copy the whole packet into new pbufs */
178 q = pbuf_clone(PBUF_RAW, PBUF_RAM, p);
179 if (q != NULL) {
180 u16_t len;
181 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
182 if (buf == NULL) {
183 pbuf_free(q);
184 return 0;
185 }
186
187 buf->p = q;
188 buf->ptr = q;
189 ip_addr_copy(buf->addr, *ip_current_src_addr());
190 buf->port = pcb->protocol;
191
192 len = q->tot_len;
193 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
194 netbuf_delete(buf);
195 return 0;
196 } else {
197#if LWIP_SO_RCVBUF
198 SYS_ARCH_INC(conn->recv_avail, len);
199#endif /* LWIP_SO_RCVBUF */
200 /* Register event with callback */
201 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
202 }
203 }
204 }
205
206 return 0; /* do not eat the packet */
207}
208#endif /* LWIP_RAW*/
209
210#if LWIP_UDP
211/**
212 * Receive callback function for UDP netconns.
213 * Posts the packet to conn->recvmbox or deletes it on memory error.
214 *
215 * @see udp.h (struct udp_pcb.recv) for parameters
216 */
217static void
218recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
219 const ip_addr_t *addr, u16_t port)
220{
221 struct netbuf *buf;
222 struct netconn *conn;
223 u16_t len;
224#if LWIP_SO_RCVBUF
225 int recv_avail;
226#endif /* LWIP_SO_RCVBUF */
227
228 LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
229 LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
230 LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
231 conn = (struct netconn *)arg;
232
233 if (conn == NULL) {
234 pbuf_free(p);
235 return;
236 }
237
238 LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
239
240#if LWIP_SO_RCVBUF
241 SYS_ARCH_GET(conn->recv_avail, recv_avail);
242 if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox) ||
243 ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
244#else /* LWIP_SO_RCVBUF */
245 if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
246#endif /* LWIP_SO_RCVBUF */
247 pbuf_free(p);
248 return;
249 }
250
251 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
252 if (buf == NULL) {
253 pbuf_free(p);
254 return;
255 } else {
256 buf->p = p;
257 buf->ptr = p;
258 ip_addr_set(&buf->addr, addr);
259 buf->port = port;
260#if LWIP_NETBUF_RECVINFO
261 if (conn->flags & NETCONN_FLAG_PKTINFO) {
262 /* get the UDP header - always in the first pbuf, ensured by udp_input */
263 const struct udp_hdr *udphdr = (const struct udp_hdr *)ip_next_header_ptr();
264 buf->flags = NETBUF_FLAG_DESTADDR;
265 ip_addr_set(&buf->toaddr, ip_current_dest_addr());
266 buf->toport_chksum = udphdr->dest;
267 }
268#endif /* LWIP_NETBUF_RECVINFO */
269 }
270
271 len = p->tot_len;
272 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
273 netbuf_delete(buf);
274 return;
275 } else {
276#if LWIP_SO_RCVBUF
277 SYS_ARCH_INC(conn->recv_avail, len);
278#endif /* LWIP_SO_RCVBUF */
279 /* Register event with callback */
280 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
281 }
282}
283#endif /* LWIP_UDP */
284
285#if LWIP_TCP
286/**
287 * Receive callback function for TCP netconns.
288 * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
289 *
290 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
291 */
292static err_t
293recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
294{
295 struct netconn *conn;
296 u16_t len;
297 void *msg;
298
299 LWIP_UNUSED_ARG(pcb);
300 LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
301 LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
302 LWIP_ASSERT("err != ERR_OK unhandled", err == ERR_OK);
303 LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
304 conn = (struct netconn *)arg;
305
306 if (conn == NULL) {
307 return ERR_VAL;
308 }
309 LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
310
311 if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
312 /* recvmbox already deleted */
313 if (p != NULL) {
314 tcp_recved(pcb, p->tot_len);
315 pbuf_free(p);
316 }
317 return ERR_OK;
318 }
319 /* Unlike for UDP or RAW pcbs, don't check for available space
320 using recv_avail since that could break the connection
321 (data is already ACKed) */
322
323 if (p != NULL) {
324 msg = p;
325 len = p->tot_len;
326 } else {
327 msg = LWIP_CONST_CAST(void *, &netconn_closed);
328 len = 0;
329 }
330
331 if (sys_mbox_trypost(&conn->recvmbox, msg) != ERR_OK) {
332 /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
333 return ERR_MEM;
334 } else {
335#if LWIP_SO_RCVBUF
336 SYS_ARCH_INC(conn->recv_avail, len);
337#endif /* LWIP_SO_RCVBUF */
338 /* Register event with callback */
339 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
340 }
341
342 return ERR_OK;
343}
344
345/**
346 * Poll callback function for TCP netconns.
347 * Wakes up an application thread that waits for a connection to close
348 * or data to be sent. The application thread then takes the
349 * appropriate action to go on.
350 *
351 * Signals the conn->sem.
352 * netconn_close waits for conn->sem if closing failed.
353 *
354 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
355 */
356static err_t
357poll_tcp(void *arg, struct tcp_pcb *pcb)
358{
359 struct netconn *conn = (struct netconn *)arg;
360
361 LWIP_UNUSED_ARG(pcb);
362 LWIP_ASSERT("conn != NULL", (conn != NULL));
363
364 if (conn->state == NETCONN_WRITE) {
365 lwip_netconn_do_writemore(conn WRITE_DELAYED);
366 } else if (conn->state == NETCONN_CLOSE) {
367#if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER
368 if (conn->current_msg && conn->current_msg->msg.sd.polls_left) {
369 conn->current_msg->msg.sd.polls_left--;
370 }
371#endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */
372 lwip_netconn_do_close_internal(conn WRITE_DELAYED);
373 }
374 /* @todo: implement connect timeout here? */
375
376 /* Did a nonblocking write fail before? Then check available write-space. */
377 if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
378 /* If the queued byte- or pbuf-count drops below the configured low-water limit,
379 let select mark this pcb as writable again. */
380 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
381 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
382 netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE);
383 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
384 }
385 }
386
387 return ERR_OK;
388}
389
390/**
391 * Sent callback function for TCP netconns.
392 * Signals the conn->sem and calls API_EVENT.
393 * netconn_write waits for conn->sem if send buffer is low.
394 *
395 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
396 */
397static err_t
398sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
399{
400 struct netconn *conn = (struct netconn *)arg;
401
402 LWIP_UNUSED_ARG(pcb);
403 LWIP_ASSERT("conn != NULL", (conn != NULL));
404
405 if (conn) {
406 if (conn->state == NETCONN_WRITE) {
407 lwip_netconn_do_writemore(conn WRITE_DELAYED);
408 } else if (conn->state == NETCONN_CLOSE) {
409 lwip_netconn_do_close_internal(conn WRITE_DELAYED);
410 }
411
412 /* If the queued byte- or pbuf-count drops below the configured low-water limit,
413 let select mark this pcb as writable again. */
414 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
415 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
416 netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE);
417 API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
418 }
419 }
420
421 return ERR_OK;
422}
423
424/**
425 * Error callback function for TCP netconns.
426 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
427 * The application thread has then to decide what to do.
428 *
429 * @see tcp.h (struct tcp_pcb.err) for parameters
430 */
431static void
432err_tcp(void *arg, err_t err)
433{
434 struct netconn *conn;
435 enum netconn_state old_state;
436 void *mbox_msg;
437 SYS_ARCH_DECL_PROTECT(lev);
438
439 conn = (struct netconn *)arg;
440 LWIP_ASSERT("conn != NULL", (conn != NULL));
441
442 SYS_ARCH_PROTECT(lev);
443
444 /* when err is called, the pcb is deallocated, so delete the reference */
445 conn->pcb.tcp = NULL;
446 /* store pending error */
447 conn->pending_err = err;
448 /* prevent application threads from blocking on 'recvmbox'/'acceptmbox' */
449 conn->flags |= NETCONN_FLAG_MBOXCLOSED;
450
451 /* reset conn->state now before waking up other threads */
452 old_state = conn->state;
453 conn->state = NETCONN_NONE;
454
455 SYS_ARCH_UNPROTECT(lev);
456
457 /* Notify the user layer about a connection error. Used to signal select. */
458 API_EVENT(conn, NETCONN_EVT_ERROR, 0);
459 /* Try to release selects pending on 'read' or 'write', too.
460 They will get an error if they actually try to read or write. */
461 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
462 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
463
464 mbox_msg = lwip_netconn_err_to_msg(err);
465 /* pass error message to recvmbox to wake up pending recv */
466 if (NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
467 /* use trypost to prevent deadlock */
468 sys_mbox_trypost(&conn->recvmbox, mbox_msg);
469 }
470 /* pass error message to acceptmbox to wake up pending accept */
471 if (NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) {
472 /* use trypost to preven deadlock */
473 sys_mbox_trypost(&conn->acceptmbox, mbox_msg);
474 }
475
476 if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
477 (old_state == NETCONN_CONNECT)) {
478 /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary
479 since the pcb has already been deleted! */
480 int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
481 SET_NONBLOCKING_CONNECT(conn, 0);
482
483 if (!was_nonblocking_connect) {
484 sys_sem_t *op_completed_sem;
485 /* set error return code */
486 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
487 if (old_state == NETCONN_CLOSE) {
488 /* let close succeed: the connection is closed after all... */
489 conn->current_msg->err = ERR_OK;
490 } else {
491 /* Write and connect fail */
492 conn->current_msg->err = err;
493 }
494 op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
495 LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem));
496 conn->current_msg = NULL;
497 /* wake up the waiting task */
498 sys_sem_signal(op_completed_sem);
499 } else {
500 /* @todo: test what happens for error on nonblocking connect */
501 }
502 } else {
503 LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
504 }
505}
506
507/**
508 * Setup a tcp_pcb with the correct callback function pointers
509 * and their arguments.
510 *
511 * @param conn the TCP netconn to setup
512 */
513static void
514setup_tcp(struct netconn *conn)
515{
516 struct tcp_pcb *pcb;
517
518 pcb = conn->pcb.tcp;
519 tcp_arg(pcb, conn);
520 tcp_recv(pcb, recv_tcp);
521 tcp_sent(pcb, sent_tcp);
522 tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL);
523 tcp_err(pcb, err_tcp);
524}
525
526/**
527 * Accept callback function for TCP netconns.
528 * Allocates a new netconn and posts that to conn->acceptmbox.
529 *
530 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
531 */
532static err_t
533accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
534{
535 struct netconn *newconn;
536 struct netconn *conn = (struct netconn *)arg;
537
538 if (conn == NULL) {
539 return ERR_VAL;
540 }
541 if (!NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) {
542 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
543 return ERR_VAL;
544 }
545
546 if (newpcb == NULL) {
547 /* out-of-pcbs during connect: pass on this error to the application */
548 if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) {
549 /* Register event with callback */
550 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
551 }
552 return ERR_VAL;
553 }
554 LWIP_ASSERT("expect newpcb == NULL or err == ERR_OK", err == ERR_OK);
555 LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
556
557 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->state: %s\n", tcp_debug_state_str(newpcb->state)));
558
559 /* We have to set the callback here even though
560 * the new socket is unknown. newconn->socket is marked as -1. */
561 newconn = netconn_alloc(conn->type, conn->callback);
562 if (newconn == NULL) {
563 /* outof netconns: pass on this error to the application */
564 if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) {
565 /* Register event with callback */
566 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
567 }
568 return ERR_MEM;
569 }
570 newconn->pcb.tcp = newpcb;
571 setup_tcp(newconn);
572
573 /* handle backlog counter */
574 tcp_backlog_delayed(newpcb);
575
576 if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
577 /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
578 so do nothing here! */
579 /* remove all references to this netconn from the pcb */
580 struct tcp_pcb *pcb = newconn->pcb.tcp;
581 tcp_arg(pcb, NULL);
582 tcp_recv(pcb, NULL);
583 tcp_sent(pcb, NULL);
584 tcp_poll(pcb, NULL, 0);
585 tcp_err(pcb, NULL);
586 /* remove reference from to the pcb from this netconn */
587 newconn->pcb.tcp = NULL;
588 /* no need to drain since we know the recvmbox is empty. */
589 sys_mbox_free(&newconn->recvmbox);
590 sys_mbox_set_invalid(&newconn->recvmbox);
591 netconn_free(newconn);
592 return ERR_MEM;
593 } else {
594 /* Register event with callback */
595 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
596 }
597
598 return ERR_OK;
599}
600#endif /* LWIP_TCP */
601
602/**
603 * Create a new pcb of a specific type.
604 * Called from lwip_netconn_do_newconn().
605 *
606 * @param msg the api_msg describing the connection type
607 */
608static void
609pcb_new(struct api_msg *msg)
610{
611 enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4;
612
613 LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
614
615#if LWIP_IPV6 && LWIP_IPV4
616 /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */
617 if (NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) {
618 iptype = IPADDR_TYPE_ANY;
619 }
620#endif
621
622 /* Allocate a PCB for this connection */
623 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
624#if LWIP_RAW
625 case NETCONN_RAW:
626 msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto);
627 if (msg->conn->pcb.raw != NULL) {
628#if LWIP_IPV6
629 /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */
630 if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) {
631 msg->conn->pcb.raw->chksum_reqd = 1;
632 msg->conn->pcb.raw->chksum_offset = 2;
633 }
634#endif /* LWIP_IPV6 */
635 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
636 }
637 break;
638#endif /* LWIP_RAW */
639#if LWIP_UDP
640 case NETCONN_UDP:
641 msg->conn->pcb.udp = udp_new_ip_type(iptype);
642 if (msg->conn->pcb.udp != NULL) {
643#if LWIP_UDPLITE
644 if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
645 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
646 }
647#endif /* LWIP_UDPLITE */
648 if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) {
649 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
650 }
651 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
652 }
653 break;
654#endif /* LWIP_UDP */
655#if LWIP_TCP
656 case NETCONN_TCP:
657 msg->conn->pcb.tcp = tcp_new_ip_type(iptype);
658 if (msg->conn->pcb.tcp != NULL) {
659 setup_tcp(msg->conn);
660 }
661 break;
662#endif /* LWIP_TCP */
663 default:
664 /* Unsupported netconn type, e.g. protocol disabled */
665 msg->err = ERR_VAL;
666 return;
667 }
668 if (msg->conn->pcb.ip == NULL) {
669 msg->err = ERR_MEM;
670 }
671}
672
673/**
674 * Create a new pcb of a specific type inside a netconn.
675 * Called from netconn_new_with_proto_and_callback.
676 *
677 * @param m the api_msg describing the connection type
678 */
679void
680lwip_netconn_do_newconn(void *m)
681{
682 struct api_msg *msg = (struct api_msg *)m;
683
684 msg->err = ERR_OK;
685 if (msg->conn->pcb.tcp == NULL) {
686 pcb_new(msg);
687 }
688 /* Else? This "new" connection already has a PCB allocated. */
689 /* Is this an error condition? Should it be deleted? */
690 /* We currently just are happy and return. */
691
692 TCPIP_APIMSG_ACK(msg);
693}
694
695/**
696 * Create a new netconn (of a specific type) that has a callback function.
697 * The corresponding pcb is NOT created!
698 *
699 * @param t the type of 'connection' to create (@see enum netconn_type)
700 * @param callback a function to call on status changes (RX available, TX'ed)
701 * @return a newly allocated struct netconn or
702 * NULL on memory error
703 */
704struct netconn *
705netconn_alloc(enum netconn_type t, netconn_callback callback)
706{
707 struct netconn *conn;
708 int size;
709 u8_t init_flags = 0;
710
711 conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
712 if (conn == NULL) {
713 return NULL;
714 }
715
716 conn->pending_err = ERR_OK;
717 conn->type = t;
718 conn->pcb.tcp = NULL;
719
720 /* If all sizes are the same, every compiler should optimize this switch to nothing */
721 switch (NETCONNTYPE_GROUP(t)) {
722#if LWIP_RAW
723 case NETCONN_RAW:
724 size = DEFAULT_RAW_RECVMBOX_SIZE;
725 break;
726#endif /* LWIP_RAW */
727#if LWIP_UDP
728 case NETCONN_UDP:
729 size = DEFAULT_UDP_RECVMBOX_SIZE;
730#if LWIP_NETBUF_RECVINFO
731 init_flags |= NETCONN_FLAG_PKTINFO;
732#endif /* LWIP_NETBUF_RECVINFO */
733 break;
734#endif /* LWIP_UDP */
735#if LWIP_TCP
736 case NETCONN_TCP:
737 size = DEFAULT_TCP_RECVMBOX_SIZE;
738 break;
739#endif /* LWIP_TCP */
740 default:
741 LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
742 goto free_and_return;
743 }
744
745 if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
746 goto free_and_return;
747 }
748#if !LWIP_NETCONN_SEM_PER_THREAD
749 if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
750 sys_mbox_free(&conn->recvmbox);
751 goto free_and_return;
752 }
753#endif
754
755#if LWIP_TCP
756 sys_mbox_set_invalid(&conn->acceptmbox);
757#endif
758 conn->state = NETCONN_NONE;
759#if LWIP_SOCKET
760 /* initialize socket to -1 since 0 is a valid socket */
761 conn->socket = -1;
762#endif /* LWIP_SOCKET */
763 conn->callback = callback;
764#if LWIP_TCP
765 conn->current_msg = NULL;
766#endif /* LWIP_TCP */
767#if LWIP_SO_SNDTIMEO
768 conn->send_timeout = 0;
769#endif /* LWIP_SO_SNDTIMEO */
770#if LWIP_SO_RCVTIMEO
771 conn->recv_timeout = 0;
772#endif /* LWIP_SO_RCVTIMEO */
773#if LWIP_SO_RCVBUF
774 conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
775 conn->recv_avail = 0;
776#endif /* LWIP_SO_RCVBUF */
777#if LWIP_SO_LINGER
778 conn->linger = -1;
779#endif /* LWIP_SO_LINGER */
780 conn->flags = init_flags;
781 return conn;
782free_and_return:
783 memp_free(MEMP_NETCONN, conn);
784 return NULL;
785}
786
787/**
788 * Delete a netconn and all its resources.
789 * The pcb is NOT freed (since we might not be in the right thread context do this).
790 *
791 * @param conn the netconn to free
792 */
793void
794netconn_free(struct netconn *conn)
795{
796 LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
797
798#if LWIP_NETCONN_FULLDUPLEX
799 /* in fullduplex, netconn is drained here */
800 netconn_drain(conn);
801#endif /* LWIP_NETCONN_FULLDUPLEX */
802
803 LWIP_ASSERT("recvmbox must be deallocated before calling this function",
804 !sys_mbox_valid(&conn->recvmbox));
805#if LWIP_TCP
806 LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
807 !sys_mbox_valid(&conn->acceptmbox));
808#endif /* LWIP_TCP */
809
810#if !LWIP_NETCONN_SEM_PER_THREAD
811 sys_sem_free(&conn->op_completed);
812 sys_sem_set_invalid(&conn->op_completed);
813#endif
814
815 memp_free(MEMP_NETCONN, conn);
816}
817
818/**
819 * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
820 * these mboxes
821 *
822 * @param conn the netconn to free
823 * @bytes_drained bytes drained from recvmbox
824 * @accepts_drained pending connections drained from acceptmbox
825 */
826static void
827netconn_drain(struct netconn *conn)
828{
829 void *mem;
830
831 /* This runs when mbox and netconn are marked as closed,
832 so we don't need to lock against rx packets */
833#if LWIP_NETCONN_FULLDUPLEX
834 LWIP_ASSERT("netconn marked closed", conn->flags & NETCONN_FLAG_MBOXINVALID);
835#endif /* LWIP_NETCONN_FULLDUPLEX */
836
837 /* Delete and drain the recvmbox. */
838 if (sys_mbox_valid(&conn->recvmbox)) {
839 while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
840#if LWIP_NETCONN_FULLDUPLEX
841 if (!lwip_netconn_is_deallocated_msg(mem))
842#endif /* LWIP_NETCONN_FULLDUPLEX */
843 {
844#if LWIP_TCP
845 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
846 err_t err;
847 if (!lwip_netconn_is_err_msg(mem, &err)) {
848 pbuf_free((struct pbuf *)mem);
849 }
850 } else
851#endif /* LWIP_TCP */
852 {
853 netbuf_delete((struct netbuf *)mem);
854 }
855 }
856 }
857 sys_mbox_free(&conn->recvmbox);
858 sys_mbox_set_invalid(&conn->recvmbox);
859 }
860
861 /* Delete and drain the acceptmbox. */
862#if LWIP_TCP
863 if (sys_mbox_valid(&conn->acceptmbox)) {
864 while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
865#if LWIP_NETCONN_FULLDUPLEX
866 if (!lwip_netconn_is_deallocated_msg(mem))
867#endif /* LWIP_NETCONN_FULLDUPLEX */
868 {
869 err_t err;
870 if (!lwip_netconn_is_err_msg(mem, &err)) {
871 struct netconn *newconn = (struct netconn *)mem;
872 /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
873 /* pcb might be set to NULL already by err_tcp() */
874 /* drain recvmbox */
875 netconn_drain(newconn);
876 if (newconn->pcb.tcp != NULL) {
877 tcp_abort(newconn->pcb.tcp);
878 newconn->pcb.tcp = NULL;
879 }
880 netconn_free(newconn);
881 }
882 }
883 }
884 sys_mbox_free(&conn->acceptmbox);
885 sys_mbox_set_invalid(&conn->acceptmbox);
886 }
887#endif /* LWIP_TCP */
888}
889
890#if LWIP_NETCONN_FULLDUPLEX
891static void
892netconn_mark_mbox_invalid(struct netconn *conn)
893{
894 int i, num_waiting;
895 void *msg = LWIP_CONST_CAST(void *, &netconn_deleted);
896
897 /* Prevent new calls/threads from reading from the mbox */
898 conn->flags |= NETCONN_FLAG_MBOXINVALID;
899
900 SYS_ARCH_LOCKED(num_waiting = conn->mbox_threads_waiting);
901 for (i = 0; i < num_waiting; i++) {
902 if (sys_mbox_valid_val(conn->recvmbox)) {
903 sys_mbox_trypost(&conn->recvmbox, msg);
904 } else {
905 sys_mbox_trypost(&conn->acceptmbox, msg);
906 }
907 }
908}
909#endif /* LWIP_NETCONN_FULLDUPLEX */
910
911#if LWIP_TCP
912/**
913 * Internal helper function to close a TCP netconn: since this sometimes
914 * doesn't work at the first attempt, this function is called from multiple
915 * places.
916 *
917 * @param conn the TCP netconn to close
918 */
919static err_t
920lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM)
921{
922 err_t err;
923 u8_t shut, shut_rx, shut_tx, shut_close;
924 u8_t close_finished = 0;
925 struct tcp_pcb *tpcb;
926#if LWIP_SO_LINGER
927 u8_t linger_wait_required = 0;
928#endif /* LWIP_SO_LINGER */
929
930 LWIP_ASSERT("invalid conn", (conn != NULL));
931 LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
932 LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
933 LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
934 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
935
936 tpcb = conn->pcb.tcp;
937 shut = conn->current_msg->msg.sd.shut;
938 shut_rx = shut & NETCONN_SHUT_RD;
939 shut_tx = shut & NETCONN_SHUT_WR;
940 /* shutting down both ends is the same as closing
941 (also if RD or WR side was shut down before already) */
942 if (shut == NETCONN_SHUT_RDWR) {
943 shut_close = 1;
944 } else if (shut_rx &&
945 ((tpcb->state == FIN_WAIT_1) ||
946 (tpcb->state == FIN_WAIT_2) ||
947 (tpcb->state == CLOSING))) {
948 shut_close = 1;
949 } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) {
950 shut_close = 1;
951 } else {
952 shut_close = 0;
953 }
954
955 /* Set back some callback pointers */
956 if (shut_close) {
957 tcp_arg(tpcb, NULL);
958 }
959 if (tpcb->state == LISTEN) {
960 tcp_accept(tpcb, NULL);
961 } else {
962 /* some callbacks have to be reset if tcp_close is not successful */
963 if (shut_rx) {
964 tcp_recv(tpcb, NULL);
965 tcp_accept(tpcb, NULL);
966 }
967 if (shut_tx) {
968 tcp_sent(tpcb, NULL);
969 }
970 if (shut_close) {
971 tcp_poll(tpcb, NULL, 0);
972 tcp_err(tpcb, NULL);
973 }
974 }
975 /* Try to close the connection */
976 if (shut_close) {
977#if LWIP_SO_LINGER
978 /* check linger possibilites before calling tcp_close */
979 err = ERR_OK;
980 /* linger enabled/required at all? (i.e. is there untransmitted data left?) */
981 if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) {
982 if ((conn->linger == 0)) {
983 /* data left but linger prevents waiting */
984 tcp_abort(tpcb);
985 tpcb = NULL;
986 } else if (conn->linger > 0) {
987 /* data left and linger says we should wait */
988 if (netconn_is_nonblocking(conn)) {
989 /* data left on a nonblocking netconn -> cannot linger */
990 err = ERR_WOULDBLOCK;
991 } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >=
992 (conn->linger * 1000)) {
993 /* data left but linger timeout has expired (this happens on further
994 calls to this function through poll_tcp */
995 tcp_abort(tpcb);
996 tpcb = NULL;
997 } else {
998 /* data left -> need to wait for ACK after successful close */
999 linger_wait_required = 1;
1000 }
1001 }
1002 }
1003 if ((err == ERR_OK) && (tpcb != NULL))
1004#endif /* LWIP_SO_LINGER */
1005 {
1006 err = tcp_close(tpcb);
1007 }
1008 } else {
1009 err = tcp_shutdown(tpcb, shut_rx, shut_tx);
1010 }
1011 if (err == ERR_OK) {
1012 close_finished = 1;
1013#if LWIP_SO_LINGER
1014 if (linger_wait_required) {
1015 /* wait for ACK of all unsent/unacked data by just getting called again */
1016 close_finished = 0;
1017 err = ERR_INPROGRESS;
1018 }
1019#endif /* LWIP_SO_LINGER */
1020 } else {
1021 if (err == ERR_MEM) {
1022 /* Closing failed because of memory shortage, try again later. Even for
1023 nonblocking netconns, we have to wait since no standard socket application
1024 is prepared for close failing because of resource shortage.
1025 Check the timeout: this is kind of an lwip addition to the standard sockets:
1026 we wait for some time when failing to allocate a segment for the FIN */
1027#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
1028 s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
1029#if LWIP_SO_SNDTIMEO
1030 if (conn->send_timeout > 0) {
1031 close_timeout = conn->send_timeout;
1032 }
1033#endif /* LWIP_SO_SNDTIMEO */
1034#if LWIP_SO_LINGER
1035 if (conn->linger >= 0) {
1036 /* use linger timeout (seconds) */
1037 close_timeout = conn->linger * 1000U;
1038 }
1039#endif
1040 if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
1041#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1042 if (conn->current_msg->msg.sd.polls_left == 0) {
1043#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1044 close_finished = 1;
1045 if (shut_close) {
1046 /* in this case, we want to RST the connection */
1047 tcp_abort(tpcb);
1048 err = ERR_OK;
1049 }
1050 }
1051 } else {
1052 /* Closing failed for a non-memory error: give up */
1053 close_finished = 1;
1054 }
1055 }
1056 if (close_finished) {
1057 /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */
1058 sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1059 conn->current_msg->err = err;
1060 conn->current_msg = NULL;
1061 conn->state = NETCONN_NONE;
1062 if (err == ERR_OK) {
1063 if (shut_close) {
1064 /* Set back some callback pointers as conn is going away */
1065 conn->pcb.tcp = NULL;
1066 /* Trigger select() in socket layer. Make sure everybody notices activity
1067 on the connection, error first! */
1068 API_EVENT(conn, NETCONN_EVT_ERROR, 0);
1069 }
1070 if (shut_rx) {
1071 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
1072 }
1073 if (shut_tx) {
1074 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
1075 }
1076 }
1077#if LWIP_TCPIP_CORE_LOCKING
1078 if (delayed)
1079#endif
1080 {
1081 /* wake up the application task */
1082 sys_sem_signal(op_completed_sem);
1083 }
1084 return ERR_OK;
1085 }
1086 if (!close_finished) {
1087 /* Closing failed and we want to wait: restore some of the callbacks */
1088 /* Closing of listen pcb will never fail! */
1089 LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN));
1090 if (shut_tx) {
1091 tcp_sent(tpcb, sent_tcp);
1092 }
1093 /* when waiting for close, set up poll interval to 500ms */
1094 tcp_poll(tpcb, poll_tcp, 1);
1095 tcp_err(tpcb, err_tcp);
1096 tcp_arg(tpcb, conn);
1097 /* don't restore recv callback: we don't want to receive any more data */
1098 }
1099 /* If closing didn't succeed, we get called again either
1100 from poll_tcp or from sent_tcp */
1101 LWIP_ASSERT("err != ERR_OK", err != ERR_OK);
1102 return err;
1103}
1104#endif /* LWIP_TCP */
1105
1106/**
1107 * Delete the pcb inside a netconn.
1108 * Called from netconn_delete.
1109 *
1110 * @param m the api_msg pointing to the connection
1111 */
1112void
1113lwip_netconn_do_delconn(void *m)
1114{
1115 struct api_msg *msg = (struct api_msg *)m;
1116
1117 enum netconn_state state = msg->conn->state;
1118 LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */
1119 (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP));
1120#if LWIP_NETCONN_FULLDUPLEX
1121 /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */
1122 if (state != NETCONN_NONE) {
1123 if ((state == NETCONN_WRITE) ||
1124 ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1125 /* close requested, abort running write/connect */
1126 sys_sem_t *op_completed_sem;
1127 LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
1128 op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
1129 msg->conn->current_msg->err = ERR_CLSD;
1130 msg->conn->current_msg = NULL;
1131 msg->conn->state = NETCONN_NONE;
1132 sys_sem_signal(op_completed_sem);
1133 }
1134 }
1135#else /* LWIP_NETCONN_FULLDUPLEX */
1136 if (((state != NETCONN_NONE) &&
1137 (state != NETCONN_LISTEN) &&
1138 (state != NETCONN_CONNECT)) ||
1139 ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1140 /* This means either a blocking write or blocking connect is running
1141 (nonblocking write returns and sets state to NONE) */
1142 msg->err = ERR_INPROGRESS;
1143 } else
1144#endif /* LWIP_NETCONN_FULLDUPLEX */
1145 {
1146 LWIP_ASSERT("blocking connect in progress",
1147 (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
1148 msg->err = ERR_OK;
1149#if LWIP_NETCONN_FULLDUPLEX
1150 /* Mark mboxes invalid */
1151 netconn_mark_mbox_invalid(msg->conn);
1152#else /* LWIP_NETCONN_FULLDUPLEX */
1153 netconn_drain(msg->conn);
1154#endif /* LWIP_NETCONN_FULLDUPLEX */
1155
1156 if (msg->conn->pcb.tcp != NULL) {
1157
1158 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1159#if LWIP_RAW
1160 case NETCONN_RAW:
1161 raw_remove(msg->conn->pcb.raw);
1162 break;
1163#endif /* LWIP_RAW */
1164#if LWIP_UDP
1165 case NETCONN_UDP:
1166 msg->conn->pcb.udp->recv_arg = NULL;
1167 udp_remove(msg->conn->pcb.udp);
1168 break;
1169#endif /* LWIP_UDP */
1170#if LWIP_TCP
1171 case NETCONN_TCP:
1172 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
1173 msg->conn->state = NETCONN_CLOSE;
1174 msg->msg.sd.shut = NETCONN_SHUT_RDWR;
1175 msg->conn->current_msg = msg;
1176#if LWIP_TCPIP_CORE_LOCKING
1177 if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
1178 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
1179 UNLOCK_TCPIP_CORE();
1180 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1181 LOCK_TCPIP_CORE();
1182 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1183 }
1184#else /* LWIP_TCPIP_CORE_LOCKING */
1185 lwip_netconn_do_close_internal(msg->conn);
1186#endif /* LWIP_TCPIP_CORE_LOCKING */
1187 /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing
1188 the application thread, so we can return at this point! */
1189 return;
1190#endif /* LWIP_TCP */
1191 default:
1192 break;
1193 }
1194 msg->conn->pcb.tcp = NULL;
1195 }
1196 /* tcp netconns don't come here! */
1197
1198 /* @todo: this lets select make the socket readable and writable,
1199 which is wrong! errfd instead? */
1200 API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
1201 API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
1202 }
1203 if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) {
1204 TCPIP_APIMSG_ACK(msg);
1205 }
1206}
1207
1208/**
1209 * Bind a pcb contained in a netconn
1210 * Called from netconn_bind.
1211 *
1212 * @param m the api_msg pointing to the connection and containing
1213 * the IP address and port to bind to
1214 */
1215void
1216lwip_netconn_do_bind(void *m)
1217{
1218 struct api_msg *msg = (struct api_msg *)m;
1219 err_t err;
1220
1221 if (msg->conn->pcb.tcp != NULL) {
1222 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1223#if LWIP_RAW
1224 case NETCONN_RAW:
1225 err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1226 break;
1227#endif /* LWIP_RAW */
1228#if LWIP_UDP
1229 case NETCONN_UDP:
1230 err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1231 break;
1232#endif /* LWIP_UDP */
1233#if LWIP_TCP
1234 case NETCONN_TCP:
1235 err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1236 break;
1237#endif /* LWIP_TCP */
1238 default:
1239 err = ERR_VAL;
1240 break;
1241 }
1242 } else {
1243 err = ERR_VAL;
1244 }
1245 msg->err = err;
1246 TCPIP_APIMSG_ACK(msg);
1247}
1248/**
1249 * Bind a pcb contained in a netconn to an interface
1250 * Called from netconn_bind_if.
1251 *
1252 * @param m the api_msg pointing to the connection and containing
1253 * the IP address and port to bind to
1254 */
1255void
1256lwip_netconn_do_bind_if(void *m)
1257{
1258 struct netif *netif;
1259 struct api_msg *msg = (struct api_msg *)m;
1260 err_t err;
1261
1262 netif = netif_get_by_index(msg->msg.bc.if_idx);
1263
1264 if ((netif != NULL) && (msg->conn->pcb.tcp != NULL)) {
1265 err = ERR_OK;
1266 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1267#if LWIP_RAW
1268 case NETCONN_RAW:
1269 raw_bind_netif(msg->conn->pcb.raw, netif);
1270 break;
1271#endif /* LWIP_RAW */
1272#if LWIP_UDP
1273 case NETCONN_UDP:
1274 udp_bind_netif(msg->conn->pcb.udp, netif);
1275 break;
1276#endif /* LWIP_UDP */
1277#if LWIP_TCP
1278 case NETCONN_TCP:
1279 tcp_bind_netif(msg->conn->pcb.tcp, netif);
1280 break;
1281#endif /* LWIP_TCP */
1282 default:
1283 err = ERR_VAL;
1284 break;
1285 }
1286 } else {
1287 err = ERR_VAL;
1288 }
1289 msg->err = err;
1290 TCPIP_APIMSG_ACK(msg);
1291}
1292
1293#if LWIP_TCP
1294/**
1295 * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has
1296 * been established (or reset by the remote host).
1297 *
1298 * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
1299 */
1300static err_t
1301lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
1302{
1303 struct netconn *conn;
1304 int was_blocking;
1305 sys_sem_t *op_completed_sem = NULL;
1306
1307 LWIP_UNUSED_ARG(pcb);
1308
1309 conn = (struct netconn *)arg;
1310
1311 if (conn == NULL) {
1312 return ERR_VAL;
1313 }
1314
1315 LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
1316 LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
1317 (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
1318
1319 if (conn->current_msg != NULL) {
1320 conn->current_msg->err = err;
1321 op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1322 }
1323 if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
1324 setup_tcp(conn);
1325 }
1326 was_blocking = !IN_NONBLOCKING_CONNECT(conn);
1327 SET_NONBLOCKING_CONNECT(conn, 0);
1328 LWIP_ASSERT("blocking connect state error",
1329 (was_blocking && op_completed_sem != NULL) ||
1330 (!was_blocking && op_completed_sem == NULL));
1331 conn->current_msg = NULL;
1332 conn->state = NETCONN_NONE;
1333 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
1334
1335 if (was_blocking) {
1336 sys_sem_signal(op_completed_sem);
1337 }
1338 return ERR_OK;
1339}
1340#endif /* LWIP_TCP */
1341
1342/**
1343 * Connect a pcb contained inside a netconn
1344 * Called from netconn_connect.
1345 *
1346 * @param m the api_msg pointing to the connection and containing
1347 * the IP address and port to connect to
1348 */
1349void
1350lwip_netconn_do_connect(void *m)
1351{
1352 struct api_msg *msg = (struct api_msg *)m;
1353 err_t err;
1354
1355 if (msg->conn->pcb.tcp == NULL) {
1356 /* This may happen when calling netconn_connect() a second time */
1357 err = ERR_CLSD;
1358 } else {
1359 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1360#if LWIP_RAW
1361 case NETCONN_RAW:
1362 err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1363 break;
1364#endif /* LWIP_RAW */
1365#if LWIP_UDP
1366 case NETCONN_UDP:
1367 err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1368 break;
1369#endif /* LWIP_UDP */
1370#if LWIP_TCP
1371 case NETCONN_TCP:
1372 /* Prevent connect while doing any other action. */
1373 if (msg->conn->state == NETCONN_CONNECT) {
1374 err = ERR_ALREADY;
1375 } else if (msg->conn->state != NETCONN_NONE) {
1376 err = ERR_ISCONN;
1377 } else {
1378 setup_tcp(msg->conn);
1379 err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr),
1380 msg->msg.bc.port, lwip_netconn_do_connected);
1381 if (err == ERR_OK) {
1382 u8_t non_blocking = netconn_is_nonblocking(msg->conn);
1383 msg->conn->state = NETCONN_CONNECT;
1384 SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
1385 if (non_blocking) {
1386 err = ERR_INPROGRESS;
1387 } else {
1388 msg->conn->current_msg = msg;
1389 /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()),
1390 when the connection is established! */
1391#if LWIP_TCPIP_CORE_LOCKING
1392 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT);
1393 UNLOCK_TCPIP_CORE();
1394 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1395 LOCK_TCPIP_CORE();
1396 LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT);
1397#endif /* LWIP_TCPIP_CORE_LOCKING */
1398 return;
1399 }
1400 }
1401 }
1402 break;
1403#endif /* LWIP_TCP */
1404 default:
1405 LWIP_ERROR("Invalid netconn type", 0, do {
1406 err = ERR_VAL;
1407 } while (0));
1408 break;
1409 }
1410 }
1411 msg->err = err;
1412 /* For all other protocols, netconn_connect() calls netconn_apimsg(),
1413 so use TCPIP_APIMSG_ACK() here. */
1414 TCPIP_APIMSG_ACK(msg);
1415}
1416
1417/**
1418 * Disconnect a pcb contained inside a netconn
1419 * Only used for UDP netconns.
1420 * Called from netconn_disconnect.
1421 *
1422 * @param m the api_msg pointing to the connection to disconnect
1423 */
1424void
1425lwip_netconn_do_disconnect(void *m)
1426{
1427 struct api_msg *msg = (struct api_msg *)m;
1428
1429#if LWIP_UDP
1430 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1431 udp_disconnect(msg->conn->pcb.udp);
1432 msg->err = ERR_OK;
1433 } else
1434#endif /* LWIP_UDP */
1435 {
1436 msg->err = ERR_VAL;
1437 }
1438 TCPIP_APIMSG_ACK(msg);
1439}
1440
1441#if LWIP_TCP
1442/**
1443 * Set a TCP pcb contained in a netconn into listen mode
1444 * Called from netconn_listen.
1445 *
1446 * @param m the api_msg pointing to the connection
1447 */
1448void
1449lwip_netconn_do_listen(void *m)
1450{
1451 struct api_msg *msg = (struct api_msg *)m;
1452 err_t err;
1453
1454 if (msg->conn->pcb.tcp != NULL) {
1455 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1456 if (msg->conn->state == NETCONN_NONE) {
1457 struct tcp_pcb *lpcb;
1458 if (msg->conn->pcb.tcp->state != CLOSED) {
1459 /* connection is not closed, cannot listen */
1460 err = ERR_VAL;
1461 } else {
1462 u8_t backlog;
1463#if TCP_LISTEN_BACKLOG
1464 backlog = msg->msg.lb.backlog;
1465#else /* TCP_LISTEN_BACKLOG */
1466 backlog = TCP_DEFAULT_LISTEN_BACKLOG;
1467#endif /* TCP_LISTEN_BACKLOG */
1468#if LWIP_IPV4 && LWIP_IPV6
1469 /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
1470 * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
1471 */
1472 if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) &&
1473 (netconn_get_ipv6only(msg->conn) == 0)) {
1474 /* change PCB type to IPADDR_TYPE_ANY */
1475 IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip, IPADDR_TYPE_ANY);
1476 IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY);
1477 }
1478#endif /* LWIP_IPV4 && LWIP_IPV6 */
1479
1480 lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
1481
1482 if (lpcb == NULL) {
1483 /* in this case, the old pcb is still allocated */
1484 } else {
1485 /* delete the recvmbox and allocate the acceptmbox */
1486 if (sys_mbox_valid(&msg->conn->recvmbox)) {
1487 /** @todo: should we drain the recvmbox here? */
1488 sys_mbox_free(&msg->conn->recvmbox);
1489 sys_mbox_set_invalid(&msg->conn->recvmbox);
1490 }
1491 err = ERR_OK;
1492 if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
1493 err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
1494 }
1495 if (err == ERR_OK) {
1496 msg->conn->state = NETCONN_LISTEN;
1497 msg->conn->pcb.tcp = lpcb;
1498 tcp_arg(msg->conn->pcb.tcp, msg->conn);
1499 tcp_accept(msg->conn->pcb.tcp, accept_function);
1500 } else {
1501 /* since the old pcb is already deallocated, free lpcb now */
1502 tcp_close(lpcb);
1503 msg->conn->pcb.tcp = NULL;
1504 }
1505 }
1506 }
1507 } else if (msg->conn->state == NETCONN_LISTEN) {
1508 /* already listening, allow updating of the backlog */
1509 err = ERR_OK;
1510 tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog);
1511 } else {
1512 err = ERR_CONN;
1513 }
1514 } else {
1515 err = ERR_ARG;
1516 }
1517 } else {
1518 err = ERR_CONN;
1519 }
1520 msg->err = err;
1521 TCPIP_APIMSG_ACK(msg);
1522}
1523#endif /* LWIP_TCP */
1524
1525/**
1526 * Send some data on a RAW or UDP pcb contained in a netconn
1527 * Called from netconn_send
1528 *
1529 * @param m the api_msg pointing to the connection
1530 */
1531void
1532lwip_netconn_do_send(void *m)
1533{
1534 struct api_msg *msg = (struct api_msg *)m;
1535
1536 err_t err = netconn_err(msg->conn);
1537 if (err == ERR_OK) {
1538 if (msg->conn->pcb.tcp != NULL) {
1539 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1540#if LWIP_RAW
1541 case NETCONN_RAW:
1542 if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1543 err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
1544 } else {
1545 err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
1546 }
1547 break;
1548#endif
1549#if LWIP_UDP
1550 case NETCONN_UDP:
1551#if LWIP_CHECKSUM_ON_COPY
1552 if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1553 err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1554 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1555 } else {
1556 err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1557 &msg->msg.b->addr, msg->msg.b->port,
1558 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1559 }
1560#else /* LWIP_CHECKSUM_ON_COPY */
1561 if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1562 err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
1563 } else {
1564 err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
1565 }
1566#endif /* LWIP_CHECKSUM_ON_COPY */
1567 break;
1568#endif /* LWIP_UDP */
1569 default:
1570 err = ERR_CONN;
1571 break;
1572 }
1573 } else {
1574 err = ERR_CONN;
1575 }
1576 }
1577 msg->err = err;
1578 TCPIP_APIMSG_ACK(msg);
1579}
1580
1581#if LWIP_TCP
1582/**
1583 * Indicate data has been received from a TCP pcb contained in a netconn
1584 * Called from netconn_recv
1585 *
1586 * @param m the api_msg pointing to the connection
1587 */
1588void
1589lwip_netconn_do_recv(void *m)
1590{
1591 struct api_msg *msg = (struct api_msg *)m;
1592
1593 msg->err = ERR_OK;
1594 if (msg->conn->pcb.tcp != NULL) {
1595 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1596 size_t remaining = msg->msg.r.len;
1597 do {
1598 u16_t recved = (u16_t)((remaining > 0xffff) ? 0xffff : remaining);
1599 tcp_recved(msg->conn->pcb.tcp, recved);
1600 remaining -= recved;
1601 } while (remaining != 0);
1602 }
1603 }
1604 TCPIP_APIMSG_ACK(msg);
1605}
1606
1607#if TCP_LISTEN_BACKLOG
1608/** Indicate that a TCP pcb has been accepted
1609 * Called from netconn_accept
1610 *
1611 * @param m the api_msg pointing to the connection
1612 */
1613void
1614lwip_netconn_do_accepted(void *m)
1615{
1616 struct api_msg *msg = (struct api_msg *)m;
1617
1618 msg->err = ERR_OK;
1619 if (msg->conn->pcb.tcp != NULL) {
1620 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1621 tcp_backlog_accepted(msg->conn->pcb.tcp);
1622 }
1623 }
1624 TCPIP_APIMSG_ACK(msg);
1625}
1626#endif /* TCP_LISTEN_BACKLOG */
1627
1628/**
1629 * See if more data needs to be written from a previous call to netconn_write.
1630 * Called initially from lwip_netconn_do_write. If the first call can't send all data
1631 * (because of low memory or empty send-buffer), this function is called again
1632 * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
1633 * blocking application thread (waiting in netconn_write) is released.
1634 *
1635 * @param conn netconn (that is currently in state NETCONN_WRITE) to process
1636 * @return ERR_OK
1637 * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
1638 */
1639static err_t
1640lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM)
1641{
1642 err_t err;
1643 const void *dataptr;
1644 u16_t len, available;
1645 u8_t write_finished = 0;
1646 size_t diff;
1647 u8_t dontblock;
1648 u8_t apiflags;
1649 u8_t write_more;
1650
1651 LWIP_ASSERT("conn != NULL", conn != NULL);
1652 LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
1653 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
1654 LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
1655 LWIP_ASSERT("conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len",
1656 conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len);
1657 LWIP_ASSERT("conn->current_msg->msg.w.vector_cnt > 0", conn->current_msg->msg.w.vector_cnt > 0);
1658
1659 apiflags = conn->current_msg->msg.w.apiflags;
1660 dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
1661
1662#if LWIP_SO_SNDTIMEO
1663 if ((conn->send_timeout != 0) &&
1664 ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
1665 write_finished = 1;
1666 if (conn->current_msg->msg.w.offset == 0) {
1667 /* nothing has been written */
1668 err = ERR_WOULDBLOCK;
1669 } else {
1670 /* partial write */
1671 err = ERR_OK;
1672 }
1673 } else
1674#endif /* LWIP_SO_SNDTIMEO */
1675 {
1676 do {
1677 dataptr = (const u8_t *)conn->current_msg->msg.w.vector->ptr + conn->current_msg->msg.w.vector_off;
1678 diff = conn->current_msg->msg.w.vector->len - conn->current_msg->msg.w.vector_off;
1679 if (diff > 0xffffUL) { /* max_u16_t */
1680 len = 0xffff;
1681 apiflags |= TCP_WRITE_FLAG_MORE;
1682 } else {
1683 len = (u16_t)diff;
1684 }
1685 available = tcp_sndbuf(conn->pcb.tcp);
1686 if (available < len) {
1687 /* don't try to write more than sendbuf */
1688 len = available;
1689 if (dontblock) {
1690 if (!len) {
1691 /* set error according to partial write or not */
1692 err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK;
1693 goto err_mem;
1694 }
1695 } else {
1696 apiflags |= TCP_WRITE_FLAG_MORE;
1697 }
1698 }
1699 LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!",
1700 ((conn->current_msg->msg.w.vector_off + len) <= conn->current_msg->msg.w.vector->len));
1701 /* we should loop around for more sending in the following cases:
1702 1) We couldn't finish the current vector because of 16-bit size limitations.
1703 tcp_write() and tcp_sndbuf() both are limited to 16-bit sizes
1704 2) We are sending the remainder of the current vector and have more */
1705 if ((len == 0xffff && diff > 0xffffUL) ||
1706 (len == (u16_t)diff && conn->current_msg->msg.w.vector_cnt > 1)) {
1707 write_more = 1;
1708 apiflags |= TCP_WRITE_FLAG_MORE;
1709 } else {
1710 write_more = 0;
1711 }
1712 err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
1713 if (err == ERR_OK) {
1714 conn->current_msg->msg.w.offset += len;
1715 conn->current_msg->msg.w.vector_off += len;
1716 /* check if current vector is finished */
1717 if (conn->current_msg->msg.w.vector_off == conn->current_msg->msg.w.vector->len) {
1718 conn->current_msg->msg.w.vector_cnt--;
1719 /* if we have additional vectors, move on to them */
1720 if (conn->current_msg->msg.w.vector_cnt > 0) {
1721 conn->current_msg->msg.w.vector++;
1722 conn->current_msg->msg.w.vector_off = 0;
1723 }
1724 }
1725 }
1726 } while (write_more && err == ERR_OK);
1727 /* if OK or memory error, check available space */
1728 if ((err == ERR_OK) || (err == ERR_MEM)) {
1729err_mem:
1730 if (dontblock && (conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len)) {
1731 /* non-blocking write did not write everything: mark the pcb non-writable
1732 and let poll_tcp check writable space to mark the pcb writable again */
1733 API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
1734 conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
1735 } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
1736 (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
1737 /* The queued byte- or pbuf-count exceeds the configured low-water limit,
1738 let select mark this pcb as non-writable. */
1739 API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
1740 }
1741 }
1742
1743 if (err == ERR_OK) {
1744 err_t out_err;
1745 if ((conn->current_msg->msg.w.offset == conn->current_msg->msg.w.len) || dontblock) {
1746 /* return sent length (caller reads length from msg.w.offset) */
1747 write_finished = 1;
1748 }
1749 out_err = tcp_output(conn->pcb.tcp);
1750 if (out_err == ERR_RTE) {
1751 /* If tcp_output fails because no route is found,
1752 don't try writing any more but return the error
1753 to the application thread. */
1754 err = out_err;
1755 write_finished = 1;
1756 }
1757 } else if (err == ERR_MEM) {
1758 /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called.
1759 For blocking sockets, we do NOT return to the application
1760 thread, since ERR_MEM is only a temporary error! Non-blocking
1761 will remain non-writable until sent_tcp/poll_tcp is called */
1762
1763 /* tcp_write returned ERR_MEM, try tcp_output anyway */
1764 err_t out_err = tcp_output(conn->pcb.tcp);
1765 if (out_err == ERR_RTE) {
1766 /* If tcp_output fails because no route is found,
1767 don't try writing any more but return the error
1768 to the application thread. */
1769 err = out_err;
1770 write_finished = 1;
1771 } else if (dontblock) {
1772 /* non-blocking write is done on ERR_MEM, set error according
1773 to partial write or not */
1774 err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK;
1775 write_finished = 1;
1776 }
1777 } else {
1778 /* On errors != ERR_MEM, we don't try writing any more but return
1779 the error to the application thread. */
1780 write_finished = 1;
1781 }
1782 }
1783 if (write_finished) {
1784 /* everything was written: set back connection state
1785 and back to application task */
1786 sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1787 conn->current_msg->err = err;
1788 conn->current_msg = NULL;
1789 conn->state = NETCONN_NONE;
1790#if LWIP_TCPIP_CORE_LOCKING
1791 if (delayed)
1792#endif
1793 {
1794 sys_sem_signal(op_completed_sem);
1795 }
1796 }
1797#if LWIP_TCPIP_CORE_LOCKING
1798 else {
1799 return ERR_MEM;
1800 }
1801#endif
1802 return ERR_OK;
1803}
1804#endif /* LWIP_TCP */
1805
1806/**
1807 * Send some data on a TCP pcb contained in a netconn
1808 * Called from netconn_write
1809 *
1810 * @param m the api_msg pointing to the connection
1811 */
1812void
1813lwip_netconn_do_write(void *m)
1814{
1815 struct api_msg *msg = (struct api_msg *)m;
1816
1817 err_t err = netconn_err(msg->conn);
1818 if (err == ERR_OK) {
1819 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1820#if LWIP_TCP
1821 if (msg->conn->state != NETCONN_NONE) {
1822 /* netconn is connecting, closing or in blocking write */
1823 err = ERR_INPROGRESS;
1824 } else if (msg->conn->pcb.tcp != NULL) {
1825 msg->conn->state = NETCONN_WRITE;
1826 /* set all the variables used by lwip_netconn_do_writemore */
1827 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
1828 LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
1829 msg->conn->current_msg = msg;
1830#if LWIP_TCPIP_CORE_LOCKING
1831 if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) {
1832 LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
1833 UNLOCK_TCPIP_CORE();
1834 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1835 LOCK_TCPIP_CORE();
1836 LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE);
1837 }
1838#else /* LWIP_TCPIP_CORE_LOCKING */
1839 lwip_netconn_do_writemore(msg->conn);
1840#endif /* LWIP_TCPIP_CORE_LOCKING */
1841 /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG
1842 since lwip_netconn_do_writemore ACKs it! */
1843 return;
1844 } else {
1845 err = ERR_CONN;
1846 }
1847#else /* LWIP_TCP */
1848 err = ERR_VAL;
1849#endif /* LWIP_TCP */
1850#if (LWIP_UDP || LWIP_RAW)
1851 } else {
1852 err = ERR_VAL;
1853#endif /* (LWIP_UDP || LWIP_RAW) */
1854 }
1855 }
1856 msg->err = err;
1857 TCPIP_APIMSG_ACK(msg);
1858}
1859
1860/**
1861 * Return a connection's local or remote address
1862 * Called from netconn_getaddr
1863 *
1864 * @param m the api_msg pointing to the connection
1865 */
1866void
1867lwip_netconn_do_getaddr(void *m)
1868{
1869 struct api_msg *msg = (struct api_msg *)m;
1870
1871 if (msg->conn->pcb.ip != NULL) {
1872 if (msg->msg.ad.local) {
1873 ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
1874 msg->conn->pcb.ip->local_ip);
1875 } else {
1876 ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
1877 msg->conn->pcb.ip->remote_ip);
1878 }
1879
1880 msg->err = ERR_OK;
1881 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1882#if LWIP_RAW
1883 case NETCONN_RAW:
1884 if (msg->msg.ad.local) {
1885 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
1886 } else {
1887 /* return an error as connecting is only a helper for upper layers */
1888 msg->err = ERR_CONN;
1889 }
1890 break;
1891#endif /* LWIP_RAW */
1892#if LWIP_UDP
1893 case NETCONN_UDP:
1894 if (msg->msg.ad.local) {
1895 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
1896 } else {
1897 if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
1898 msg->err = ERR_CONN;
1899 } else {
1900 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
1901 }
1902 }
1903 break;
1904#endif /* LWIP_UDP */
1905#if LWIP_TCP
1906 case NETCONN_TCP:
1907 if ((msg->msg.ad.local == 0) &&
1908 ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) {
1909 /* pcb is not connected and remote name is requested */
1910 msg->err = ERR_CONN;
1911 } else {
1912 API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port);
1913 }
1914 break;
1915#endif /* LWIP_TCP */
1916 default:
1917 LWIP_ASSERT("invalid netconn_type", 0);
1918 break;
1919 }
1920 } else {
1921 msg->err = ERR_CONN;
1922 }
1923 TCPIP_APIMSG_ACK(msg);
1924}
1925
1926/**
1927 * Close or half-shutdown a TCP pcb contained in a netconn
1928 * Called from netconn_close
1929 * In contrast to closing sockets, the netconn is not deallocated.
1930 *
1931 * @param m the api_msg pointing to the connection
1932 */
1933void
1934lwip_netconn_do_close(void *m)
1935{
1936 struct api_msg *msg = (struct api_msg *)m;
1937
1938#if LWIP_TCP
1939 enum netconn_state state = msg->conn->state;
1940 /* First check if this is a TCP netconn and if it is in a correct state
1941 (LISTEN doesn't support half shutdown) */
1942 if ((msg->conn->pcb.tcp != NULL) &&
1943 (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) &&
1944 ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) {
1945 /* Check if we are in a connected state */
1946 if (state == NETCONN_CONNECT) {
1947 /* TCP connect in progress: cannot shutdown */
1948 msg->err = ERR_CONN;
1949 } else if (state == NETCONN_WRITE) {
1950#if LWIP_NETCONN_FULLDUPLEX
1951 if (msg->msg.sd.shut & NETCONN_SHUT_WR) {
1952 /* close requested, abort running write */
1953 sys_sem_t *write_completed_sem;
1954 LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
1955 write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
1956 msg->conn->current_msg->err = ERR_CLSD;
1957 msg->conn->current_msg = NULL;
1958 msg->conn->state = NETCONN_NONE;
1959 state = NETCONN_NONE;
1960 sys_sem_signal(write_completed_sem);
1961 } else {
1962 LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD);
1963 /* In this case, let the write continue and do not interfere with
1964 conn->current_msg or conn->state! */
1965 msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0);
1966 }
1967 }
1968 if (state == NETCONN_NONE) {
1969#else /* LWIP_NETCONN_FULLDUPLEX */
1970 msg->err = ERR_INPROGRESS;
1971 } else {
1972#endif /* LWIP_NETCONN_FULLDUPLEX */
1973 if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
1974#if LWIP_NETCONN_FULLDUPLEX
1975 /* Mark mboxes invalid */
1976 netconn_mark_mbox_invalid(msg->conn);
1977#else /* LWIP_NETCONN_FULLDUPLEX */
1978 netconn_drain(msg->conn);
1979#endif /* LWIP_NETCONN_FULLDUPLEX */
1980 }
1981 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
1982 msg->conn->state = NETCONN_CLOSE;
1983 msg->conn->current_msg = msg;
1984#if LWIP_TCPIP_CORE_LOCKING
1985 if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
1986 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
1987 UNLOCK_TCPIP_CORE();
1988 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1989 LOCK_TCPIP_CORE();
1990 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1991 }
1992#else /* LWIP_TCPIP_CORE_LOCKING */
1993 lwip_netconn_do_close_internal(msg->conn);
1994#endif /* LWIP_TCPIP_CORE_LOCKING */
1995 /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */
1996 return;
1997 }
1998 } else
1999#endif /* LWIP_TCP */
2000 {
2001 msg->err = ERR_CONN;
2002 }
2003 TCPIP_APIMSG_ACK(msg);
2004}
2005
2006#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
2007/**
2008 * Join multicast groups for UDP netconns.
2009 * Called from netconn_join_leave_group
2010 *
2011 * @param m the api_msg pointing to the connection
2012 */
2013void
2014lwip_netconn_do_join_leave_group(void *m)
2015{
2016 struct api_msg *msg = (struct api_msg *)m;
2017
2018 msg->err = ERR_CONN;
2019 if (msg->conn->pcb.tcp != NULL) {
2020 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
2021#if LWIP_UDP
2022#if LWIP_IPV6 && LWIP_IPV6_MLD
2023 if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
2024 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
2025 msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
2026 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
2027 } else {
2028 msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
2029 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
2030 }
2031 } else
2032#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
2033 {
2034#if LWIP_IGMP
2035 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
2036 msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
2037 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
2038 } else {
2039 msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
2040 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
2041 }
2042#endif /* LWIP_IGMP */
2043 }
2044#endif /* LWIP_UDP */
2045#if (LWIP_TCP || LWIP_RAW)
2046 } else {
2047 msg->err = ERR_VAL;
2048#endif /* (LWIP_TCP || LWIP_RAW) */
2049 }
2050 }
2051 TCPIP_APIMSG_ACK(msg);
2052}
2053/**
2054 * Join multicast groups for UDP netconns.
2055 * Called from netconn_join_leave_group_netif
2056 *
2057 * @param m the api_msg pointing to the connection
2058 */
2059void
2060lwip_netconn_do_join_leave_group_netif(void *m)
2061{
2062 struct api_msg *msg = (struct api_msg *)m;
2063 struct netif *netif;
2064
2065 netif = netif_get_by_index(msg->msg.jl.if_idx);
2066 if (netif == NULL) {
2067 msg->err = ERR_IF;
2068 goto done;
2069 }
2070
2071 msg->err = ERR_CONN;
2072 if (msg->conn->pcb.tcp != NULL) {
2073 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
2074#if LWIP_UDP
2075#if LWIP_IPV6 && LWIP_IPV6_MLD
2076 if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
2077 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
2078 msg->err = mld6_joingroup_netif(netif,
2079 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
2080 } else {
2081 msg->err = mld6_leavegroup_netif(netif,
2082 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
2083 }
2084 } else
2085#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
2086 {
2087#if LWIP_IGMP
2088 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
2089 msg->err = igmp_joingroup_netif(netif,
2090 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
2091 } else {
2092 msg->err = igmp_leavegroup_netif(netif,
2093 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
2094 }
2095#endif /* LWIP_IGMP */
2096 }
2097#endif /* LWIP_UDP */
2098#if (LWIP_TCP || LWIP_RAW)
2099 } else {
2100 msg->err = ERR_VAL;
2101#endif /* (LWIP_TCP || LWIP_RAW) */
2102 }
2103 }
2104
2105done:
2106 TCPIP_APIMSG_ACK(msg);
2107}
2108#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
2109
2110#if LWIP_DNS
2111/**
2112 * Callback function that is called when DNS name is resolved
2113 * (or on timeout). A waiting application thread is waked up by
2114 * signaling the semaphore.
2115 */
2116static void
2117lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg)
2118{
2119 struct dns_api_msg *msg = (struct dns_api_msg *)arg;
2120
2121 /* we trust the internal implementation to be correct :-) */
2122 LWIP_UNUSED_ARG(name);
2123
2124 if (ipaddr == NULL) {
2125 /* timeout or memory error */
2126 API_EXPR_DEREF(msg->err) = ERR_VAL;
2127 } else {
2128 /* address was resolved */
2129 API_EXPR_DEREF(msg->err) = ERR_OK;
2130 API_EXPR_DEREF(msg->addr) = *ipaddr;
2131 }
2132 /* wake up the application task waiting in netconn_gethostbyname */
2133 sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
2134}
2135
2136/**
2137 * Execute a DNS query
2138 * Called from netconn_gethostbyname
2139 *
2140 * @param arg the dns_api_msg pointing to the query
2141 */
2142void
2143lwip_netconn_do_gethostbyname(void *arg)
2144{
2145 struct dns_api_msg *msg = (struct dns_api_msg *)arg;
2146 u8_t addrtype =
2147#if LWIP_IPV4 && LWIP_IPV6
2148 msg->dns_addrtype;
2149#else
2150 LWIP_DNS_ADDRTYPE_DEFAULT;
2151#endif
2152
2153 API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name,
2154 API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype);
2155#if LWIP_TCPIP_CORE_LOCKING
2156 /* For core locking, only block if we need to wait for answer/timeout */
2157 if (API_EXPR_DEREF(msg->err) == ERR_INPROGRESS) {
2158 UNLOCK_TCPIP_CORE();
2159 sys_sem_wait(API_EXPR_REF_SEM(msg->sem));
2160 LOCK_TCPIP_CORE();
2161 LWIP_ASSERT("do_gethostbyname still in progress!!", API_EXPR_DEREF(msg->err) != ERR_INPROGRESS);
2162 }
2163#else /* LWIP_TCPIP_CORE_LOCKING */
2164 if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) {
2165 /* on error or immediate success, wake up the application
2166 * task waiting in netconn_gethostbyname */
2167 sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
2168 }
2169#endif /* LWIP_TCPIP_CORE_LOCKING */
2170}
2171#endif /* LWIP_DNS */
2172
2173#endif /* LWIP_NETCONN */
Note: See TracBrowser for help on using the repository browser.