ReactOS 0.4.16-dev-1059-gb1cf981
api_msg.c
Go to the documentation of this file.
1
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"
56
57#include <string.h>
58
59/* netconns are polled once per second (e.g. continue write on memory error) */
60#define NETCONN_TCP_POLL_INTERVAL 2
61
62#define SET_NONBLOCKING_CONNECT(conn, val) do { if (val) { \
63 netconn_set_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); \
64} else { \
65 netconn_clear_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); }} while(0)
66#define IN_NONBLOCKING_CONNECT(conn) netconn_is_flag_set(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT)
67
68#if LWIP_NETCONN_FULLDUPLEX
69#define NETCONN_MBOX_VALID(conn, mbox) (sys_mbox_valid(mbox) && ((conn->flags & NETCONN_FLAG_MBOXINVALID) == 0))
70#else
71#define NETCONN_MBOX_VALID(conn, mbox) sys_mbox_valid(mbox)
72#endif
73
74/* forward declarations */
75#if LWIP_TCP
76#if LWIP_TCPIP_CORE_LOCKING
77#define WRITE_DELAYED , 1
78#define WRITE_DELAYED_PARAM , u8_t delayed
79#else /* LWIP_TCPIP_CORE_LOCKING */
80#define WRITE_DELAYED
81#define WRITE_DELAYED_PARAM
82#endif /* LWIP_TCPIP_CORE_LOCKING */
83static err_t lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM);
84static err_t lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM);
85#endif
86
87static void netconn_drain(struct netconn *conn);
88
89#if LWIP_TCPIP_CORE_LOCKING
90#define TCPIP_APIMSG_ACK(m)
91#else /* LWIP_TCPIP_CORE_LOCKING */
92#define TCPIP_APIMSG_ACK(m) do { sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
93#endif /* LWIP_TCPIP_CORE_LOCKING */
94
95#if LWIP_NETCONN_FULLDUPLEX
96static const u8_t netconn_deleted = 0;
97
98int
99lwip_netconn_is_deallocated_msg(void *msg)
100{
101 if (msg == &netconn_deleted) {
102 return 1;
103 }
104 return 0;
105}
106#endif /* LWIP_NETCONN_FULLDUPLEX */
107
108#if LWIP_TCP
109static const u8_t netconn_aborted = 0;
110static const u8_t netconn_reset = 0;
111static const u8_t netconn_closed = 0;
112
114static void *
115lwip_netconn_err_to_msg(err_t err)
116{
117 switch (err) {
118 case ERR_ABRT:
119 return LWIP_CONST_CAST(void *, &netconn_aborted);
120 case ERR_RST:
121 return LWIP_CONST_CAST(void *, &netconn_reset);
122 case ERR_CLSD:
123 return LWIP_CONST_CAST(void *, &netconn_closed);
124 default:
125 LWIP_ASSERT("unhandled error", err == ERR_OK);
126 return NULL;
127 }
128}
129
130int
131lwip_netconn_is_err_msg(void *msg, err_t *err)
132{
133 LWIP_ASSERT("err != NULL", err != NULL);
134
135 if (msg == &netconn_aborted) {
136 *err = ERR_ABRT;
137 return 1;
138 } else if (msg == &netconn_reset) {
139 *err = ERR_RST;
140 return 1;
141 } else if (msg == &netconn_closed) {
142 *err = ERR_CLSD;
143 return 1;
144 }
145 return 0;
146}
147#endif /* LWIP_TCP */
148
149
150#if LWIP_RAW
158static u8_t
159recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
160 const ip_addr_t *addr)
161{
162 struct pbuf *q;
163 struct netbuf *buf;
164 struct netconn *conn;
165
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 */
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;
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
217static void
218recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
219 const ip_addr_t *addr, u16_t port)
220{
221 struct netbuf *buf;
222 struct netconn *conn;
223 u16_t len;
224 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;
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
295static err_t
296recv_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
359static err_t
360poll_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
400static err_t
401sent_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
434static void
435err_tcp(void *arg, err_t err)
436{
437 struct netconn *conn;
438 enum netconn_state old_state;
439 void *mbox_msg;
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
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
516static void
517setup_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
535static err_t
536accept_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
611static void
612pcb_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
682void
683lwip_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
707struct netconn *
708netconn_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:
731 break;
732#endif /* LWIP_RAW */
733#if LWIP_UDP
734 case NETCONN_UDP:
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:
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;
786free_and_return:
787 memp_free(MEMP_NETCONN, conn);
788 return NULL;
789}
790
797void
798netconn_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
830static void
831netconn_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
895static void
896netconn_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
923static err_t
924lwip_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 */
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;
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
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
1116void
1117lwip_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);
1184 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
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
1219void
1220lwip_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}
1259void
1260lwip_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
1304static err_t
1305lwip_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
1353void
1354lwip_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) {
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);
1398 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
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
1428void
1429lwip_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
1452void
1453lwip_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 */
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)) {
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
1535void
1536lwip_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
1592void
1593lwip_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
1617void
1618lwip_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
1643static err_t
1644lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM)
1645{
1646 err_t err;
1647 const void *dataptr;
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 */
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)) {
1733err_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
1816void
1817lwip_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 */
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);
1838 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
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
1870void
1871lwip_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
1937void
1938lwip_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);
1992 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
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)
2017void
2018lwip_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}
2063void
2064lwip_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
2109done:
2110 TCPIP_APIMSG_ACK(msg);
2111}
2112#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
2113
2114#if LWIP_DNS
2120static void
2121lwip_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 :-) */
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 */
2138}
2139
2146void
2147lwip_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) {
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 */
2172 }
2173#endif /* LWIP_TCPIP_CORE_LOCKING */
2174}
2175#endif /* LWIP_DNS */
2176
2177#endif /* LWIP_NETCONN */
static int state
Definition: maze.c:121
#define msg(x)
Definition: auth_time.c:54
STREAM tcp_recv(STREAM s, uint32 length)
Definition: tcp.c:344
RD_BOOL tcp_connect(char *server)
Definition: tcp.c:717
#define NULL
Definition: types.h:112
static WCHAR available[MAX_STRING_RESOURCE_LEN]
Definition: object.c:2336
USHORT port
Definition: uri.c:228
#define SYS_ARCH_UNPROTECT(lev)
Definition: cc.h:39
#define SYS_ARCH_PROTECT(lev)
Definition: cc.h:38
#define SYS_ARCH_DECL_PROTECT(lev)
Definition: cc.h:37
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:158
#define LWIP_ERROR(message, expression, handler)
Definition: debug.h:130
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
#define ip_current_src_addr()
Definition: ip.h:223
#define ip_current_dest_addr()
Definition: ip.h:225
#define LOCK_TCPIP_CORE()
Definition: tcpip.h:62
#define UNLOCK_TCPIP_CORE()
Definition: tcpip.h:63
#define ERR_MEM
Definition: fontsub.h:52
GLdouble GLdouble t
Definition: gl.h:2047
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
GLsizeiptr size
Definition: glext.h:5919
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLenum const GLvoid * addr
Definition: glext.h:9621
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
const GLfloat * m
Definition: glext.h:10848
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
int32_t s32_t
Definition: arch.h:130
uint8_t u8_t
Definition: arch.h:125
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:373
uint16_t u16_t
Definition: arch.h:127
#define LWIP_CONST_CAST(target_type, val)
Definition: arch.h:240
s8_t err_t
Definition: err.h:96
@ ERR_INPROGRESS
Definition: err.h:65
@ ERR_RST
Definition: err.h:84
@ ERR_IF
Definition: err.h:79
@ ERR_ISCONN
Definition: err.h:75
@ ERR_RTE
Definition: err.h:63
@ ERR_OK
Definition: err.h:55
@ ERR_CLSD
Definition: err.h:86
@ ERR_VAL
Definition: err.h:67
@ ERR_CONN
Definition: err.h:77
@ ERR_ARG
Definition: err.h:88
@ ERR_WOULDBLOCK
Definition: err.h:69
@ ERR_ALREADY
Definition: err.h:73
@ ERR_ABRT
Definition: err.h:82
lwip_ip_addr_type
Definition: ip_addr.h:54
@ IPADDR_TYPE_ANY
Definition: ip_addr.h:60
@ IPADDR_TYPE_V4
Definition: ip_addr.h:56
#define API_MSG_DEBUG
Definition: opt.h:3357
#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT
Definition: opt.h:2100
#define RECV_BUFSIZE_DEFAULT
Definition: opt.h:2093
#define TCP_SNDQUEUELOWAT
Definition: opt.h:1391
#define TCP_DEFAULT_LISTEN_BACKLOG
Definition: opt.h:1453
#define TCP_SNDLOWAT
Definition: opt.h:1382
#define DEFAULT_UDP_RECVMBOX_SIZE
Definition: opt.h:1910
#define DEFAULT_TCP_RECVMBOX_SIZE
Definition: opt.h:1919
#define DEFAULT_RAW_RECVMBOX_SIZE
Definition: opt.h:1901
#define DEFAULT_ACCEPTMBOX_SIZE
Definition: opt.h:1928
struct netif * netif_get_by_index(u8_t idx)
Definition: netif.c:1730
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:727
struct pbuf * pbuf_clone(pbuf_layer layer, pbuf_type type, struct pbuf *p)
Definition: pbuf.c:1337
@ PBUF_RAM
Definition: pbuf.h:152
@ PBUF_RAW
Definition: pbuf.h:111
void sys_mbox_set_invalid(sys_mbox_t *mbox)
Definition: sys_arch.c:146
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
Definition: sys_arch.c:247
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
Definition: sys_arch.c:128
void sys_mbox_free(sys_mbox_t *mbox)
Definition: sys_arch.c:152
void sys_sem_set_invalid(sys_sem_t *sem)
Definition: sys_arch.c:66
void sys_sem_free(sys_sem_t *sem)
Definition: sys_arch.c:72
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
Definition: sys_arch.c:86
void sys_sem_signal(sys_sem_t *sem)
Definition: sys_arch.c:80
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
Definition: sys_arch.c:46
u32_t sys_now(void)
Definition: sys_arch.c:23
#define ip_2_ip6(ipaddr)
Definition: ip_addr.h:356
#define ip_addr_isany(ipaddr)
Definition: ip_addr.h:377
#define ip_addr_set(dest, src)
Definition: ip_addr.h:363
#define ip_addr_eq(addr1, addr2)
Definition: ip_addr.h:374
#define ip_addr_copy(dest, src)
Definition: ip_addr.h:360
#define IP_IS_ANY_TYPE_VAL(ipaddr)
Definition: ip_addr.h:351
ip6_addr_t ip_addr_t
Definition: ip_addr.h:344
#define IP_SET_TYPE_VAL(ipaddr, iptype)
Definition: ip_addr.h:352
#define ip_addr_isany_val(ipaddr)
Definition: ip_addr.h:378
int const JOCTET * dataptr
Definition: jpeglib.h:1031
if(dx< 0)
Definition: linetemp.h:194
#define sys_mbox_valid(mbox)
Definition: sys_arch.h:50
#define sys_sem_valid(sema)
Definition: sys_arch.h:36
void * memp_malloc(memp_t type)
Definition: memp.c:337
void memp_free(memp_t type, void *mem)
Definition: memp.c:420
static IPrintDialogCallback callback
Definition: printdlg.c:326
#define IP6_NEXTH_ICMP6
Definition: ip6.h:72
#define err(...)
char * name
Definition: compiler.c:66
Definition: mem.c:349
Definition: name.c:39
Definition: types.h:144
Definition: netif.h:269
Definition: pbuf.h:186
Definition: udp.h:53
Definition: dhcpd.h:79
#define SYS_ARCH_GET(var, ret)
Definition: sys.h:544
#define sys_sem_wait(sem)
Definition: sys.h:227
#define SYS_ARCH_LOCKED(code)
Definition: sys.h:562
#define sys_mbox_valid_val(mbox)
Definition: sys.h:395
#define SYS_MBOX_EMPTY
Definition: sys.h:92
#define sys_mbox_tryfetch(mbox, msg)
Definition: sys.h:360
#define SYS_ARCH_INC(var, val)
Definition: sys.h:526
void tcp_close(struct sock *sk, long timeout)
struct sock * tcp_accept(struct sock *sk, int flags, int *err)
void tcp_shutdown(struct sock *sk, int how)
unsigned int tcp_poll(struct file *file, struct socket *sock, struct poll_table_struct *wait)
#define API_EXPR_REF(expr)
Definition: tcpip_priv.h:90
#define API_EXPR_DEREF(expr)
Definition: tcpip_priv.h:92
#define API_EXPR_REF_SEM(expr)
Definition: tcpip_priv.h:91