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