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