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