3 * Sequential API Internal module
8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
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.
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
33 * This file is part of the lwIP TCP/IP stack.
35 * Author: Adam Dunkels <adam@sics.se>
41 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
43 #include "lwip/priv/api_msg.h"
46 #include "lwip/ip_addr.h"
51 #include "lwip/memp.h"
52 #include "lwip/igmp.h"
54 #include "lwip/mld6.h"
55 #include "lwip/priv/tcpip_priv.h"
59 /* netconns are polled once per second (e.g. continue write on memory error) */
60 #define NETCONN_TCP_POLL_INTERVAL 2
62 #define SET_NONBLOCKING_CONNECT(conn, val) do { if (val) { \
63 (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \
65 (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0)
66 #define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0)
68 /* forward declarations */
70 #if LWIP_TCPIP_CORE_LOCKING
71 #define WRITE_DELAYED , 1
72 #define WRITE_DELAYED_PARAM , u8_t delayed
73 #else /* LWIP_TCPIP_CORE_LOCKING */
75 #define WRITE_DELAYED_PARAM
76 #endif /* LWIP_TCPIP_CORE_LOCKING */
77 static err_t lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM);
78 static err_t lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM);
81 #if LWIP_TCPIP_CORE_LOCKING
82 #define TCPIP_APIMSG_ACK(m) NETCONN_SET_SAFE_ERR((m)->conn, (m)->err)
83 #else /* LWIP_TCPIP_CORE_LOCKING */
84 #define TCPIP_APIMSG_ACK(m) do { NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
85 #endif /* LWIP_TCPIP_CORE_LOCKING */
93 * Receive callback function for RAW netconns.
94 * Doesn't 'eat' the packet, only copies it and sends it to
97 * @see raw.h (struct raw_pcb.recv) for parameters and return value
100 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
101 const ip_addr_t *addr)
105 struct netconn *conn;
107 LWIP_UNUSED_ARG(addr);
108 conn = (struct netconn *)arg;
110 if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) {
113 SYS_ARCH_GET(conn->recv_avail, recv_avail);
114 if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
117 #endif /* LWIP_SO_RCVBUF */
118 /* copy the whole packet into new pbufs */
119 q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
121 if (pbuf_copy(q, p) != ERR_OK) {
129 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
137 ip_addr_copy(buf->addr, *ip_current_src_addr());
138 buf->port = pcb->protocol;
141 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
146 SYS_ARCH_INC(conn->recv_avail, len);
147 #endif /* LWIP_SO_RCVBUF */
148 /* Register event with callback */
149 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
154 return 0; /* do not eat the packet */
160 * Receive callback function for UDP netconns.
161 * Posts the packet to conn->recvmbox or deletes it on memory error.
163 * @see udp.h (struct udp_pcb.recv) for parameters
166 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
167 const ip_addr_t *addr, u16_t port)
170 struct netconn *conn;
174 #endif /* LWIP_SO_RCVBUF */
176 LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
177 LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
178 LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
179 conn = (struct netconn *)arg;
186 LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
189 SYS_ARCH_GET(conn->recv_avail, recv_avail);
190 if (!sys_mbox_valid(&conn->recvmbox) ||
191 ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
192 #else /* LWIP_SO_RCVBUF */
193 if (!sys_mbox_valid(&conn->recvmbox)) {
194 #endif /* LWIP_SO_RCVBUF */
199 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
206 ip_addr_set(&buf->addr, addr);
208 #if LWIP_NETBUF_RECVINFO
210 /* get the UDP header - always in the first pbuf, ensured by udp_input */
211 const struct udp_hdr* udphdr = (const struct udp_hdr*)ip_next_header_ptr();
212 #if LWIP_CHECKSUM_ON_COPY
213 buf->flags = NETBUF_FLAG_DESTADDR;
214 #endif /* LWIP_CHECKSUM_ON_COPY */
215 ip_addr_set(&buf->toaddr, ip_current_dest_addr());
216 buf->toport_chksum = udphdr->dest;
218 #endif /* LWIP_NETBUF_RECVINFO */
222 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
227 SYS_ARCH_INC(conn->recv_avail, len);
228 #endif /* LWIP_SO_RCVBUF */
229 /* Register event with callback */
230 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
233 #endif /* LWIP_UDP */
237 * Receive callback function for TCP netconns.
238 * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
240 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
243 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
245 struct netconn *conn;
248 LWIP_UNUSED_ARG(pcb);
249 LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
250 LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
251 conn = (struct netconn *)arg;
256 LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
258 if (!sys_mbox_valid(&conn->recvmbox)) {
259 /* recvmbox already deleted */
261 tcp_recved(pcb, p->tot_len);
266 /* Unlike for UDP or RAW pcbs, don't check for available space
267 using recv_avail since that could break the connection
268 (data is already ACKed) */
270 /* don't overwrite fatal errors! */
272 NETCONN_SET_SAFE_ERR(conn, err);
281 if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) {
282 /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
286 SYS_ARCH_INC(conn->recv_avail, len);
287 #endif /* LWIP_SO_RCVBUF */
288 /* Register event with callback */
289 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
296 * Poll callback function for TCP netconns.
297 * Wakes up an application thread that waits for a connection to close
298 * or data to be sent. The application thread then takes the
299 * appropriate action to go on.
301 * Signals the conn->sem.
302 * netconn_close waits for conn->sem if closing failed.
304 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
307 poll_tcp(void *arg, struct tcp_pcb *pcb)
309 struct netconn *conn = (struct netconn *)arg;
311 LWIP_UNUSED_ARG(pcb);
312 LWIP_ASSERT("conn != NULL", (conn != NULL));
314 if (conn->state == NETCONN_WRITE) {
315 lwip_netconn_do_writemore(conn WRITE_DELAYED);
316 } else if (conn->state == NETCONN_CLOSE) {
317 #if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER
318 if (conn->current_msg && conn->current_msg->msg.sd.polls_left) {
319 conn->current_msg->msg.sd.polls_left--;
321 #endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */
322 lwip_netconn_do_close_internal(conn WRITE_DELAYED);
324 /* @todo: implement connect timeout here? */
326 /* Did a nonblocking write fail before? Then check available write-space. */
327 if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
328 /* If the queued byte- or pbuf-count drops below the configured low-water limit,
329 let select mark this pcb as writable again. */
330 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
331 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
332 conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
333 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
341 * Sent callback function for TCP netconns.
342 * Signals the conn->sem and calls API_EVENT.
343 * netconn_write waits for conn->sem if send buffer is low.
345 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
348 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
350 struct netconn *conn = (struct netconn *)arg;
352 LWIP_UNUSED_ARG(pcb);
353 LWIP_ASSERT("conn != NULL", (conn != NULL));
356 if (conn->state == NETCONN_WRITE) {
357 lwip_netconn_do_writemore(conn WRITE_DELAYED);
358 } else if (conn->state == NETCONN_CLOSE) {
359 lwip_netconn_do_close_internal(conn WRITE_DELAYED);
362 /* If the queued byte- or pbuf-count drops below the configured low-water limit,
363 let select mark this pcb as writable again. */
364 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
365 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
366 conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
367 API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
375 * Error callback function for TCP netconns.
376 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
377 * The application thread has then to decide what to do.
379 * @see tcp.h (struct tcp_pcb.err) for parameters
382 err_tcp(void *arg, err_t err)
384 struct netconn *conn;
385 enum netconn_state old_state;
387 conn = (struct netconn *)arg;
388 LWIP_ASSERT("conn != NULL", (conn != NULL));
390 conn->pcb.tcp = NULL;
392 /* reset conn->state now before waking up other threads */
393 old_state = conn->state;
394 conn->state = NETCONN_NONE;
396 if (old_state == NETCONN_CLOSE) {
397 /* RST during close: let close return success & dealloc the netconn */
399 NETCONN_SET_SAFE_ERR(conn, ERR_OK);
401 /* no check since this is always fatal! */
402 SYS_ARCH_SET(conn->last_err, err);
405 /* @todo: the type of NETCONN_EVT created should depend on 'old_state' */
407 /* Notify the user layer about a connection error. Used to signal select. */
408 API_EVENT(conn, NETCONN_EVT_ERROR, 0);
409 /* Try to release selects pending on 'read' or 'write', too.
410 They will get an error if they actually try to read or write. */
411 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
412 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
414 /* pass NULL-message to recvmbox to wake up pending recv */
415 if (sys_mbox_valid(&conn->recvmbox)) {
416 /* use trypost to prevent deadlock */
417 sys_mbox_trypost(&conn->recvmbox, NULL);
419 /* pass NULL-message to acceptmbox to wake up pending accept */
420 if (sys_mbox_valid(&conn->acceptmbox)) {
421 /* use trypost to preven deadlock */
422 sys_mbox_trypost(&conn->acceptmbox, NULL);
425 if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
426 (old_state == NETCONN_CONNECT)) {
427 /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary
428 since the pcb has already been deleted! */
429 int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
430 SET_NONBLOCKING_CONNECT(conn, 0);
432 if (!was_nonblocking_connect) {
433 sys_sem_t* op_completed_sem;
434 /* set error return code */
435 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
436 conn->current_msg->err = err;
437 op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
438 LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem));
439 conn->current_msg = NULL;
440 /* wake up the waiting task */
441 NETCONN_SET_SAFE_ERR(conn, err);
442 sys_sem_signal(op_completed_sem);
445 LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
450 * Setup a tcp_pcb with the correct callback function pointers
451 * and their arguments.
453 * @param conn the TCP netconn to setup
456 setup_tcp(struct netconn *conn)
462 tcp_recv(pcb, recv_tcp);
463 tcp_sent(pcb, sent_tcp);
464 tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL);
465 tcp_err(pcb, err_tcp);
469 * Accept callback function for TCP netconns.
470 * Allocates a new netconn and posts that to conn->acceptmbox.
472 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
475 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
477 struct netconn *newconn;
478 struct netconn *conn = (struct netconn *)arg;
483 if (!sys_mbox_valid(&conn->acceptmbox)) {
484 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
488 if (newpcb == NULL) {
489 /* out-of-pcbs during connect: pass on this error to the application */
490 if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) {
491 /* Register event with callback */
492 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
497 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state)));
499 /* We have to set the callback here even though
500 * the new socket is unknown. newconn->socket is marked as -1. */
501 newconn = netconn_alloc(conn->type, conn->callback);
502 if (newconn == NULL) {
503 /* outof netconns: pass on this error to the application */
504 if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) {
505 /* Register event with callback */
506 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
510 newconn->pcb.tcp = newpcb;
512 /* no protection: when creating the pcb, the netconn is not yet known
513 to the application thread */
514 newconn->last_err = err;
516 /* handle backlog counter */
517 tcp_backlog_delayed(newpcb);
519 if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
520 /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
521 so do nothing here! */
522 /* remove all references to this netconn from the pcb */
523 struct tcp_pcb* pcb = newconn->pcb.tcp;
527 tcp_poll(pcb, NULL, 0);
529 /* remove reference from to the pcb from this netconn */
530 newconn->pcb.tcp = NULL;
531 /* no need to drain since we know the recvmbox is empty. */
532 sys_mbox_free(&newconn->recvmbox);
533 sys_mbox_set_invalid(&newconn->recvmbox);
534 netconn_free(newconn);
537 /* Register event with callback */
538 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
543 #endif /* LWIP_TCP */
546 * Create a new pcb of a specific type.
547 * Called from lwip_netconn_do_newconn().
549 * @param msg the api_msg_msg describing the connection type
552 pcb_new(struct api_msg *msg)
554 enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4;
556 LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
558 #if LWIP_IPV6 && LWIP_IPV4
559 /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */
560 if(NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) {
561 iptype = IPADDR_TYPE_ANY;
565 /* Allocate a PCB for this connection */
566 switch(NETCONNTYPE_GROUP(msg->conn->type)) {
569 msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto);
570 if (msg->conn->pcb.raw != NULL) {
572 /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */
573 if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) {
574 msg->conn->pcb.raw->chksum_reqd = 1;
575 msg->conn->pcb.raw->chksum_offset = 2;
577 #endif /* LWIP_IPV6 */
578 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
581 #endif /* LWIP_RAW */
584 msg->conn->pcb.udp = udp_new_ip_type(iptype);
585 if (msg->conn->pcb.udp != NULL) {
587 if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
588 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
590 #endif /* LWIP_UDPLITE */
591 if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) {
592 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
594 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
597 #endif /* LWIP_UDP */
600 msg->conn->pcb.tcp = tcp_new_ip_type(iptype);
601 if (msg->conn->pcb.tcp != NULL) {
602 setup_tcp(msg->conn);
605 #endif /* LWIP_TCP */
607 /* Unsupported netconn type, e.g. protocol disabled */
611 if (msg->conn->pcb.ip == NULL) {
617 * Create a new pcb of a specific type inside a netconn.
618 * Called from netconn_new_with_proto_and_callback.
620 * @param m the api_msg_msg describing the connection type
623 lwip_netconn_do_newconn(void *m)
625 struct api_msg *msg = (struct api_msg*)m;
628 if (msg->conn->pcb.tcp == NULL) {
631 /* Else? This "new" connection already has a PCB allocated. */
632 /* Is this an error condition? Should it be deleted? */
633 /* We currently just are happy and return. */
635 TCPIP_APIMSG_ACK(msg);
639 * Create a new netconn (of a specific type) that has a callback function.
640 * The corresponding pcb is NOT created!
642 * @param t the type of 'connection' to create (@see enum netconn_type)
643 * @param callback a function to call on status changes (RX available, TX'ed)
644 * @return a newly allocated struct netconn or
645 * NULL on memory error
648 netconn_alloc(enum netconn_type t, netconn_callback callback)
650 struct netconn *conn;
653 conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
658 conn->last_err = ERR_OK;
660 conn->pcb.tcp = NULL;
662 /* If all sizes are the same, every compiler should optimize this switch to nothing */
663 switch(NETCONNTYPE_GROUP(t)) {
666 size = DEFAULT_RAW_RECVMBOX_SIZE;
668 #endif /* LWIP_RAW */
671 size = DEFAULT_UDP_RECVMBOX_SIZE;
673 #endif /* LWIP_UDP */
676 size = DEFAULT_TCP_RECVMBOX_SIZE;
678 #endif /* LWIP_TCP */
680 LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
681 goto free_and_return;
684 if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
685 goto free_and_return;
687 #if !LWIP_NETCONN_SEM_PER_THREAD
688 if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
689 sys_mbox_free(&conn->recvmbox);
690 goto free_and_return;
695 sys_mbox_set_invalid(&conn->acceptmbox);
697 conn->state = NETCONN_NONE;
699 /* initialize socket to -1 since 0 is a valid socket */
701 #endif /* LWIP_SOCKET */
702 conn->callback = callback;
704 conn->current_msg = NULL;
705 conn->write_offset = 0;
706 #endif /* LWIP_TCP */
708 conn->send_timeout = 0;
709 #endif /* LWIP_SO_SNDTIMEO */
711 conn->recv_timeout = 0;
712 #endif /* LWIP_SO_RCVTIMEO */
714 conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
715 conn->recv_avail = 0;
716 #endif /* LWIP_SO_RCVBUF */
719 #endif /* LWIP_SO_LINGER */
723 memp_free(MEMP_NETCONN, conn);
728 * Delete a netconn and all its resources.
729 * The pcb is NOT freed (since we might not be in the right thread context do this).
731 * @param conn the netconn to free
734 netconn_free(struct netconn *conn)
736 LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
737 LWIP_ASSERT("recvmbox must be deallocated before calling this function",
738 !sys_mbox_valid(&conn->recvmbox));
740 LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
741 !sys_mbox_valid(&conn->acceptmbox));
742 #endif /* LWIP_TCP */
744 #if !LWIP_NETCONN_SEM_PER_THREAD
745 sys_sem_free(&conn->op_completed);
746 sys_sem_set_invalid(&conn->op_completed);
749 memp_free(MEMP_NETCONN, conn);
753 * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
756 * @param conn the netconn to free
757 * @bytes_drained bytes drained from recvmbox
758 * @accepts_drained pending connections drained from acceptmbox
761 netconn_drain(struct netconn *conn)
766 #endif /* LWIP_TCP */
768 /* This runs in tcpip_thread, so we don't need to lock against rx packets */
770 /* Delete and drain the recvmbox. */
771 if (sys_mbox_valid(&conn->recvmbox)) {
772 while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
774 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
776 p = (struct pbuf*)mem;
777 /* pcb might be set to NULL already by err_tcp() */
778 if (conn->pcb.tcp != NULL) {
779 tcp_recved(conn->pcb.tcp, p->tot_len);
784 #endif /* LWIP_TCP */
786 netbuf_delete((struct netbuf *)mem);
789 sys_mbox_free(&conn->recvmbox);
790 sys_mbox_set_invalid(&conn->recvmbox);
793 /* Delete and drain the acceptmbox. */
795 if (sys_mbox_valid(&conn->acceptmbox)) {
796 while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
797 if (mem != &netconn_aborted) {
798 struct netconn *newconn = (struct netconn *)mem;
799 /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
800 /* pcb might be set to NULL already by err_tcp() */
802 netconn_drain(newconn);
803 if (newconn->pcb.tcp != NULL) {
804 tcp_abort(newconn->pcb.tcp);
805 newconn->pcb.tcp = NULL;
807 netconn_free(newconn);
810 sys_mbox_free(&conn->acceptmbox);
811 sys_mbox_set_invalid(&conn->acceptmbox);
813 #endif /* LWIP_TCP */
818 * Internal helper function to close a TCP netconn: since this sometimes
819 * doesn't work at the first attempt, this function is called from multiple
822 * @param conn the TCP netconn to close
825 lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM)
828 u8_t shut, shut_rx, shut_tx, close;
829 u8_t close_finished = 0;
830 struct tcp_pcb* tpcb;
832 u8_t linger_wait_required = 0;
833 #endif /* LWIP_SO_LINGER */
835 LWIP_ASSERT("invalid conn", (conn != NULL));
836 LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
837 LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
838 LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
839 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
841 tpcb = conn->pcb.tcp;
842 shut = conn->current_msg->msg.sd.shut;
843 shut_rx = shut & NETCONN_SHUT_RD;
844 shut_tx = shut & NETCONN_SHUT_WR;
845 /* shutting down both ends is the same as closing
846 (also if RD or WR side was shut down before already) */
847 if (shut == NETCONN_SHUT_RDWR) {
849 } else if (shut_rx &&
850 ((tpcb->state == FIN_WAIT_1) ||
851 (tpcb->state == FIN_WAIT_2) ||
852 (tpcb->state == CLOSING))) {
854 } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) {
860 /* Set back some callback pointers */
864 if (tpcb->state == LISTEN) {
865 tcp_accept(tpcb, NULL);
867 /* some callbacks have to be reset if tcp_close is not successful */
869 tcp_recv(tpcb, NULL);
870 tcp_accept(tpcb, NULL);
873 tcp_sent(tpcb, NULL);
876 tcp_poll(tpcb, NULL, 0);
880 /* Try to close the connection */
883 /* check linger possibilites before calling tcp_close */
885 /* linger enabled/required at all? (i.e. is there untransmitted data left?) */
886 if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) {
887 if ((conn->linger == 0)) {
888 /* data left but linger prevents waiting */
891 } else if (conn->linger > 0) {
892 /* data left and linger says we should wait */
893 if (netconn_is_nonblocking(conn)) {
894 /* data left on a nonblocking netconn -> cannot linger */
895 err = ERR_WOULDBLOCK;
896 } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >=
897 (conn->linger * 1000)) {
898 /* data left but linger timeout has expired (this happens on further
899 calls to this function through poll_tcp */
903 /* data left -> need to wait for ACK after successful close */
904 linger_wait_required = 1;
908 if ((err == ERR_OK) && (tpcb != NULL))
909 #endif /* LWIP_SO_LINGER */
911 err = tcp_close(tpcb);
914 err = tcp_shutdown(tpcb, shut_rx, shut_tx);
919 if (linger_wait_required) {
920 /* wait for ACK of all unsent/unacked data by just getting called again */
922 err = ERR_INPROGRESS;
924 #endif /* LWIP_SO_LINGER */
926 if (err == ERR_MEM) {
927 /* Closing failed because of memory shortage, try again later. Even for
928 nonblocking netconns, we have to wait since no standard socket application
929 is prepared for close failing because of resource shortage.
930 Check the timeout: this is kind of an lwip addition to the standard sockets:
931 we wait for some time when failing to allocate a segment for the FIN */
932 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
933 s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
935 if (conn->send_timeout > 0) {
936 close_timeout = conn->send_timeout;
938 #endif /* LWIP_SO_SNDTIMEO */
940 if (conn->linger >= 0) {
941 /* use linger timeout (seconds) */
942 close_timeout = conn->linger * 1000U;
945 if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
946 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
947 if (conn->current_msg->msg.sd.polls_left == 0) {
948 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
951 /* in this case, we want to RST the connection */
957 /* Closing failed for a non-memory error: give up */
961 if (close_finished) {
962 /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */
963 sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
964 conn->current_msg->err = err;
965 conn->current_msg = NULL;
966 conn->state = NETCONN_NONE;
969 /* Set back some callback pointers as conn is going away */
970 conn->pcb.tcp = NULL;
971 /* Trigger select() in socket layer. Make sure everybody notices activity
972 on the connection, error first! */
973 API_EVENT(conn, NETCONN_EVT_ERROR, 0);
976 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
979 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
982 NETCONN_SET_SAFE_ERR(conn, err);
983 #if LWIP_TCPIP_CORE_LOCKING
987 /* wake up the application task */
988 sys_sem_signal(op_completed_sem);
992 if (!close_finished) {
993 /* Closing failed and we want to wait: restore some of the callbacks */
994 /* Closing of listen pcb will never fail! */
995 LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN));
997 tcp_sent(tpcb, sent_tcp);
999 /* when waiting for close, set up poll interval to 500ms */
1000 tcp_poll(tpcb, poll_tcp, 1);
1001 tcp_err(tpcb, err_tcp);
1002 tcp_arg(tpcb, conn);
1003 /* don't restore recv callback: we don't want to receive any more data */
1005 /* If closing didn't succeed, we get called again either
1006 from poll_tcp or from sent_tcp */
1007 LWIP_ASSERT("err != ERR_OK", err != ERR_OK);
1010 #endif /* LWIP_TCP */
1013 * Delete the pcb inside a netconn.
1014 * Called from netconn_delete.
1016 * @param m the api_msg_msg pointing to the connection
1019 lwip_netconn_do_delconn(void *m)
1021 struct api_msg *msg = (struct api_msg*)m;
1023 enum netconn_state state = msg->conn->state;
1024 LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */
1025 (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP));
1026 #if LWIP_NETCONN_FULLDUPLEX
1027 /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */
1028 if (state != NETCONN_NONE) {
1029 if ((state == NETCONN_WRITE) ||
1030 ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1031 /* close requested, abort running write/connect */
1032 sys_sem_t* op_completed_sem;
1033 LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
1034 op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
1035 msg->conn->current_msg->err = ERR_CLSD;
1036 msg->conn->current_msg = NULL;
1037 msg->conn->write_offset = 0;
1038 msg->conn->state = NETCONN_NONE;
1039 NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
1040 sys_sem_signal(op_completed_sem);
1043 #else /* LWIP_NETCONN_FULLDUPLEX */
1044 if (((state != NETCONN_NONE) &&
1045 (state != NETCONN_LISTEN) &&
1046 (state != NETCONN_CONNECT)) ||
1047 ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1048 /* This means either a blocking write or blocking connect is running
1049 (nonblocking write returns and sets state to NONE) */
1050 msg->err = ERR_INPROGRESS;
1052 #endif /* LWIP_NETCONN_FULLDUPLEX */
1054 LWIP_ASSERT("blocking connect in progress",
1055 (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
1057 /* Drain and delete mboxes */
1058 netconn_drain(msg->conn);
1060 if (msg->conn->pcb.tcp != NULL) {
1062 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1065 raw_remove(msg->conn->pcb.raw);
1067 #endif /* LWIP_RAW */
1070 msg->conn->pcb.udp->recv_arg = NULL;
1071 udp_remove(msg->conn->pcb.udp);
1073 #endif /* LWIP_UDP */
1076 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1077 msg->conn->write_offset == 0);
1078 msg->conn->state = NETCONN_CLOSE;
1079 msg->msg.sd.shut = NETCONN_SHUT_RDWR;
1080 msg->conn->current_msg = msg;
1081 #if LWIP_TCPIP_CORE_LOCKING
1082 if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
1083 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
1084 UNLOCK_TCPIP_CORE();
1085 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1087 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1089 #else /* LWIP_TCPIP_CORE_LOCKING */
1090 lwip_netconn_do_close_internal(msg->conn);
1091 #endif /* LWIP_TCPIP_CORE_LOCKING */
1092 /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing
1093 the application thread, so we can return at this point! */
1095 #endif /* LWIP_TCP */
1099 msg->conn->pcb.tcp = NULL;
1101 /* tcp netconns don't come here! */
1103 /* @todo: this lets select make the socket readable and writable,
1104 which is wrong! errfd instead? */
1105 API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
1106 API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
1108 if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) {
1109 TCPIP_APIMSG_ACK(msg);
1114 * Bind a pcb contained in a netconn
1115 * Called from netconn_bind.
1117 * @param m the api_msg_msg pointing to the connection and containing
1118 * the IP address and port to bind to
1121 lwip_netconn_do_bind(void *m)
1123 struct api_msg *msg = (struct api_msg*)m;
1125 if (ERR_IS_FATAL(msg->conn->last_err)) {
1126 msg->err = msg->conn->last_err;
1129 if (msg->conn->pcb.tcp != NULL) {
1130 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1133 msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1135 #endif /* LWIP_RAW */
1138 msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1140 #endif /* LWIP_UDP */
1143 msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1145 #endif /* LWIP_TCP */
1151 TCPIP_APIMSG_ACK(msg);
1156 * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has
1157 * been established (or reset by the remote host).
1159 * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
1162 lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
1164 struct netconn *conn;
1166 sys_sem_t* op_completed_sem = NULL;
1168 LWIP_UNUSED_ARG(pcb);
1170 conn = (struct netconn *)arg;
1176 LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
1177 LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
1178 (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
1180 if (conn->current_msg != NULL) {
1181 conn->current_msg->err = err;
1182 op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1184 if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
1187 was_blocking = !IN_NONBLOCKING_CONNECT(conn);
1188 SET_NONBLOCKING_CONNECT(conn, 0);
1189 LWIP_ASSERT("blocking connect state error",
1190 (was_blocking && op_completed_sem != NULL) ||
1191 (!was_blocking && op_completed_sem == NULL));
1192 conn->current_msg = NULL;
1193 conn->state = NETCONN_NONE;
1194 NETCONN_SET_SAFE_ERR(conn, ERR_OK);
1195 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
1198 sys_sem_signal(op_completed_sem);
1202 #endif /* LWIP_TCP */
1205 * Connect a pcb contained inside a netconn
1206 * Called from netconn_connect.
1208 * @param m the api_msg_msg pointing to the connection and containing
1209 * the IP address and port to connect to
1212 lwip_netconn_do_connect(void *m)
1214 struct api_msg *msg = (struct api_msg*)m;
1216 if (msg->conn->pcb.tcp == NULL) {
1217 /* This may happen when calling netconn_connect() a second time */
1218 msg->err = ERR_CLSD;
1220 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1223 msg->err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1225 #endif /* LWIP_RAW */
1228 msg->err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1230 #endif /* LWIP_UDP */
1233 /* Prevent connect while doing any other action. */
1234 if (msg->conn->state == NETCONN_CONNECT) {
1235 msg->err = ERR_ALREADY;
1236 } else if (msg->conn->state != NETCONN_NONE) {
1237 msg->err = ERR_ISCONN;
1239 setup_tcp(msg->conn);
1240 msg->err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr),
1241 msg->msg.bc.port, lwip_netconn_do_connected);
1242 if (msg->err == ERR_OK) {
1243 u8_t non_blocking = netconn_is_nonblocking(msg->conn);
1244 msg->conn->state = NETCONN_CONNECT;
1245 SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
1247 msg->err = ERR_INPROGRESS;
1249 msg->conn->current_msg = msg;
1250 /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()),
1251 when the connection is established! */
1252 #if LWIP_TCPIP_CORE_LOCKING
1253 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT);
1254 UNLOCK_TCPIP_CORE();
1255 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1257 LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT);
1258 #endif /* LWIP_TCPIP_CORE_LOCKING */
1264 #endif /* LWIP_TCP */
1266 LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
1270 /* For all other protocols, netconn_connect() calls TCPIP_APIMSG(),
1271 so use TCPIP_APIMSG_ACK() here. */
1272 TCPIP_APIMSG_ACK(msg);
1276 * Disconnect a pcb contained inside a netconn
1277 * Only used for UDP netconns.
1278 * Called from netconn_disconnect.
1280 * @param m the api_msg_msg pointing to the connection to disconnect
1283 lwip_netconn_do_disconnect(void *m)
1285 struct api_msg *msg = (struct api_msg*)m;
1288 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1289 udp_disconnect(msg->conn->pcb.udp);
1292 #endif /* LWIP_UDP */
1296 TCPIP_APIMSG_ACK(msg);
1301 * Set a TCP pcb contained in a netconn into listen mode
1302 * Called from netconn_listen.
1304 * @param m the api_msg_msg pointing to the connection
1307 lwip_netconn_do_listen(void *m)
1309 struct api_msg *msg = (struct api_msg*)m;
1311 if (ERR_IS_FATAL(msg->conn->last_err)) {
1312 msg->err = msg->conn->last_err;
1314 msg->err = ERR_CONN;
1315 if (msg->conn->pcb.tcp != NULL) {
1316 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1317 if (msg->conn->state == NETCONN_NONE) {
1318 struct tcp_pcb* lpcb;
1319 if (msg->conn->pcb.tcp->state != CLOSED) {
1320 /* connection is not closed, cannot listen */
1325 #if TCP_LISTEN_BACKLOG
1326 backlog = msg->msg.lb.backlog;
1327 #else /* TCP_LISTEN_BACKLOG */
1328 backlog = TCP_DEFAULT_LISTEN_BACKLOG;
1329 #endif /* TCP_LISTEN_BACKLOG */
1330 #if LWIP_IPV4 && LWIP_IPV6
1331 /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
1332 * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
1334 if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) &&
1335 (netconn_get_ipv6only(msg->conn) == 0)) {
1336 /* change PCB type to IPADDR_TYPE_ANY */
1337 IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip, IPADDR_TYPE_ANY);
1338 IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY);
1340 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1342 lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
1345 /* in this case, the old pcb is still allocated */
1348 /* delete the recvmbox and allocate the acceptmbox */
1349 if (sys_mbox_valid(&msg->conn->recvmbox)) {
1350 /** @todo: should we drain the recvmbox here? */
1351 sys_mbox_free(&msg->conn->recvmbox);
1352 sys_mbox_set_invalid(&msg->conn->recvmbox);
1355 if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
1356 msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
1358 if (msg->err == ERR_OK) {
1359 msg->conn->state = NETCONN_LISTEN;
1360 msg->conn->pcb.tcp = lpcb;
1361 tcp_arg(msg->conn->pcb.tcp, msg->conn);
1362 tcp_accept(msg->conn->pcb.tcp, accept_function);
1364 /* since the old pcb is already deallocated, free lpcb now */
1366 msg->conn->pcb.tcp = NULL;
1370 } else if (msg->conn->state == NETCONN_LISTEN) {
1371 /* already listening, allow updating of the backlog */
1373 tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog);
1380 TCPIP_APIMSG_ACK(msg);
1382 #endif /* LWIP_TCP */
1385 * Send some data on a RAW or UDP pcb contained in a netconn
1386 * Called from netconn_send
1388 * @param m the api_msg_msg pointing to the connection
1391 lwip_netconn_do_send(void *m)
1393 struct api_msg *msg = (struct api_msg*)m;
1395 if (ERR_IS_FATAL(msg->conn->last_err)) {
1396 msg->err = msg->conn->last_err;
1398 msg->err = ERR_CONN;
1399 if (msg->conn->pcb.tcp != NULL) {
1400 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1403 if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1404 msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
1406 msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
1412 #if LWIP_CHECKSUM_ON_COPY
1413 if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1414 msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1415 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1417 msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1418 &msg->msg.b->addr, msg->msg.b->port,
1419 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1421 #else /* LWIP_CHECKSUM_ON_COPY */
1422 if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1423 msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
1425 msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
1427 #endif /* LWIP_CHECKSUM_ON_COPY */
1429 #endif /* LWIP_UDP */
1435 TCPIP_APIMSG_ACK(msg);
1440 * Indicate data has been received from a TCP pcb contained in a netconn
1441 * Called from netconn_recv
1443 * @param m the api_msg_msg pointing to the connection
1446 lwip_netconn_do_recv(void *m)
1448 struct api_msg *msg = (struct api_msg*)m;
1451 if (msg->conn->pcb.tcp != NULL) {
1452 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1453 u32_t remaining = msg->msg.r.len;
1455 u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
1456 tcp_recved(msg->conn->pcb.tcp, recved);
1457 remaining -= recved;
1458 } while (remaining != 0);
1461 TCPIP_APIMSG_ACK(msg);
1464 #if TCP_LISTEN_BACKLOG
1465 /** Indicate that a TCP pcb has been accepted
1466 * Called from netconn_accept
1468 * @param m the api_msg_msg pointing to the connection
1471 lwip_netconn_do_accepted(void *m)
1473 struct api_msg *msg = (struct api_msg*)m;
1476 if (msg->conn->pcb.tcp != NULL) {
1477 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1478 tcp_backlog_accepted(msg->conn->pcb.tcp);
1481 TCPIP_APIMSG_ACK(msg);
1483 #endif /* TCP_LISTEN_BACKLOG */
1486 * See if more data needs to be written from a previous call to netconn_write.
1487 * Called initially from lwip_netconn_do_write. If the first call can't send all data
1488 * (because of low memory or empty send-buffer), this function is called again
1489 * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
1490 * blocking application thread (waiting in netconn_write) is released.
1492 * @param conn netconn (that is currently in state NETCONN_WRITE) to process
1494 * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
1497 lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM)
1500 const void *dataptr;
1501 u16_t len, available;
1502 u8_t write_finished = 0;
1507 LWIP_ASSERT("conn != NULL", conn != NULL);
1508 LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
1509 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
1510 LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
1511 LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
1512 conn->write_offset < conn->current_msg->msg.w.len);
1514 apiflags = conn->current_msg->msg.w.apiflags;
1515 dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
1517 #if LWIP_SO_SNDTIMEO
1518 if ((conn->send_timeout != 0) &&
1519 ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
1521 if (conn->write_offset == 0) {
1522 /* nothing has been written */
1523 err = ERR_WOULDBLOCK;
1524 conn->current_msg->msg.w.len = 0;
1528 conn->current_msg->msg.w.len = conn->write_offset;
1529 conn->write_offset = 0;
1532 #endif /* LWIP_SO_SNDTIMEO */
1534 dataptr = (const u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
1535 diff = conn->current_msg->msg.w.len - conn->write_offset;
1536 if (diff > 0xffffUL) { /* max_u16_t */
1538 apiflags |= TCP_WRITE_FLAG_MORE;
1542 available = tcp_sndbuf(conn->pcb.tcp);
1543 if (available < len) {
1544 /* don't try to write more than sendbuf */
1548 err = ERR_WOULDBLOCK;
1552 apiflags |= TCP_WRITE_FLAG_MORE;
1555 LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
1556 err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
1557 /* if OK or memory error, check available space */
1558 if ((err == ERR_OK) || (err == ERR_MEM)) {
1560 if (dontblock && (len < conn->current_msg->msg.w.len)) {
1561 /* non-blocking write did not write everything: mark the pcb non-writable
1562 and let poll_tcp check writable space to mark the pcb writable again */
1563 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
1564 conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
1565 } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
1566 (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
1567 /* The queued byte- or pbuf-count exceeds the configured low-water limit,
1568 let select mark this pcb as non-writable. */
1569 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
1573 if (err == ERR_OK) {
1575 conn->write_offset += len;
1576 if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) {
1577 /* return sent length */
1578 conn->current_msg->msg.w.len = conn->write_offset;
1579 /* everything was written */
1582 out_err = tcp_output(conn->pcb.tcp);
1583 if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) {
1584 /* If tcp_output fails with fatal error or no route is found,
1585 don't try writing any more but return the error
1586 to the application thread. */
1589 conn->current_msg->msg.w.len = 0;
1591 } else if (err == ERR_MEM) {
1592 /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called.
1593 For blocking sockets, we do NOT return to the application
1594 thread, since ERR_MEM is only a temporary error! Non-blocking
1595 will remain non-writable until sent_tcp/poll_tcp is called */
1597 /* tcp_write returned ERR_MEM, try tcp_output anyway */
1598 err_t out_err = tcp_output(conn->pcb.tcp);
1599 if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) {
1600 /* If tcp_output fails with fatal error or no route is found,
1601 don't try writing any more but return the error
1602 to the application thread. */
1605 conn->current_msg->msg.w.len = 0;
1606 } else if (dontblock) {
1607 /* non-blocking write is done on ERR_MEM */
1608 err = ERR_WOULDBLOCK;
1610 conn->current_msg->msg.w.len = 0;
1613 /* On errors != ERR_MEM, we don't try writing any more but return
1614 the error to the application thread. */
1616 conn->current_msg->msg.w.len = 0;
1619 if (write_finished) {
1620 /* everything was written: set back connection state
1621 and back to application task */
1622 sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1623 conn->current_msg->err = err;
1624 conn->current_msg = NULL;
1625 conn->write_offset = 0;
1626 conn->state = NETCONN_NONE;
1627 NETCONN_SET_SAFE_ERR(conn, err);
1628 #if LWIP_TCPIP_CORE_LOCKING
1632 sys_sem_signal(op_completed_sem);
1635 #if LWIP_TCPIP_CORE_LOCKING
1642 #endif /* LWIP_TCP */
1645 * Send some data on a TCP pcb contained in a netconn
1646 * Called from netconn_write
1648 * @param m the api_msg_msg pointing to the connection
1651 lwip_netconn_do_write(void *m)
1653 struct api_msg *msg = (struct api_msg*)m;
1655 if (ERR_IS_FATAL(msg->conn->last_err)) {
1656 msg->err = msg->conn->last_err;
1658 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1660 if (msg->conn->state != NETCONN_NONE) {
1661 /* netconn is connecting, closing or in blocking write */
1662 msg->err = ERR_INPROGRESS;
1663 } else if (msg->conn->pcb.tcp != NULL) {
1664 msg->conn->state = NETCONN_WRITE;
1665 /* set all the variables used by lwip_netconn_do_writemore */
1666 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1667 msg->conn->write_offset == 0);
1668 LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
1669 msg->conn->current_msg = msg;
1670 msg->conn->write_offset = 0;
1671 #if LWIP_TCPIP_CORE_LOCKING
1672 if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) {
1673 LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
1674 UNLOCK_TCPIP_CORE();
1675 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1677 LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE);
1679 #else /* LWIP_TCPIP_CORE_LOCKING */
1680 lwip_netconn_do_writemore(msg->conn);
1681 #endif /* LWIP_TCPIP_CORE_LOCKING */
1682 /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG
1683 since lwip_netconn_do_writemore ACKs it! */
1686 msg->err = ERR_CONN;
1688 #else /* LWIP_TCP */
1690 #endif /* LWIP_TCP */
1691 #if (LWIP_UDP || LWIP_RAW)
1694 #endif /* (LWIP_UDP || LWIP_RAW) */
1697 TCPIP_APIMSG_ACK(msg);
1701 * Return a connection's local or remote address
1702 * Called from netconn_getaddr
1704 * @param m the api_msg_msg pointing to the connection
1707 lwip_netconn_do_getaddr(void *m)
1709 struct api_msg *msg = (struct api_msg*)m;
1711 if (msg->conn->pcb.ip != NULL) {
1712 if (msg->msg.ad.local) {
1713 ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
1714 msg->conn->pcb.ip->local_ip);
1716 ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
1717 msg->conn->pcb.ip->remote_ip);
1721 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1724 if (msg->msg.ad.local) {
1725 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
1727 /* return an error as connecting is only a helper for upper layers */
1728 msg->err = ERR_CONN;
1731 #endif /* LWIP_RAW */
1734 if (msg->msg.ad.local) {
1735 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
1737 if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
1738 msg->err = ERR_CONN;
1740 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
1744 #endif /* LWIP_UDP */
1747 if ((msg->msg.ad.local == 0) &&
1748 ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) {
1749 /* pcb is not connected and remote name is requested */
1750 msg->err = ERR_CONN;
1752 API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port);
1755 #endif /* LWIP_TCP */
1757 LWIP_ASSERT("invalid netconn_type", 0);
1761 msg->err = ERR_CONN;
1763 TCPIP_APIMSG_ACK(msg);
1767 * Close or half-shutdown a TCP pcb contained in a netconn
1768 * Called from netconn_close
1769 * In contrast to closing sockets, the netconn is not deallocated.
1771 * @param m the api_msg_msg pointing to the connection
1774 lwip_netconn_do_close(void *m)
1776 struct api_msg *msg = (struct api_msg*)m;
1779 enum netconn_state state = msg->conn->state;
1780 /* First check if this is a TCP netconn and if it is in a correct state
1781 (LISTEN doesn't support half shutdown) */
1782 if ((msg->conn->pcb.tcp != NULL) &&
1783 (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) &&
1784 ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) {
1785 /* Check if we are in a connected state */
1786 if (state == NETCONN_CONNECT) {
1787 /* TCP connect in progress: cannot shutdown */
1788 msg->err = ERR_CONN;
1789 } else if (state == NETCONN_WRITE) {
1790 #if LWIP_NETCONN_FULLDUPLEX
1791 if (msg->msg.sd.shut & NETCONN_SHUT_WR) {
1792 /* close requested, abort running write */
1793 sys_sem_t* write_completed_sem;
1794 LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
1795 write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
1796 msg->conn->current_msg->err = ERR_CLSD;
1797 msg->conn->current_msg = NULL;
1798 msg->conn->write_offset = 0;
1799 msg->conn->state = NETCONN_NONE;
1800 state = NETCONN_NONE;
1801 NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
1802 sys_sem_signal(write_completed_sem);
1804 LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD);
1805 /* In this case, let the write continue and do not interfere with
1806 conn->current_msg or conn->state! */
1807 msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0);
1810 if (state == NETCONN_NONE) {
1811 #else /* LWIP_NETCONN_FULLDUPLEX */
1812 msg->err = ERR_INPROGRESS;
1814 #endif /* LWIP_NETCONN_FULLDUPLEX */
1815 if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
1816 /* Drain and delete mboxes */
1817 netconn_drain(msg->conn);
1819 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1820 msg->conn->write_offset == 0);
1821 msg->conn->state = NETCONN_CLOSE;
1822 msg->conn->current_msg = msg;
1823 #if LWIP_TCPIP_CORE_LOCKING
1824 if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
1825 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
1826 UNLOCK_TCPIP_CORE();
1827 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1829 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1831 #else /* LWIP_TCPIP_CORE_LOCKING */
1832 lwip_netconn_do_close_internal(msg->conn);
1833 #endif /* LWIP_TCPIP_CORE_LOCKING */
1834 /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */
1838 #endif /* LWIP_TCP */
1840 msg->err = ERR_CONN;
1842 TCPIP_APIMSG_ACK(msg);
1845 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
1847 * Join multicast groups for UDP netconns.
1848 * Called from netconn_join_leave_group
1850 * @param m the api_msg_msg pointing to the connection
1853 lwip_netconn_do_join_leave_group(void *m)
1855 struct api_msg *msg = (struct api_msg*)m;
1857 if (ERR_IS_FATAL(msg->conn->last_err)) {
1858 msg->err = msg->conn->last_err;
1860 if (msg->conn->pcb.tcp != NULL) {
1861 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1863 #if LWIP_IPV6 && LWIP_IPV6_MLD
1864 if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
1865 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
1866 msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
1867 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
1869 msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
1870 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
1874 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
1877 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
1878 msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
1879 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
1881 msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
1882 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
1884 #endif /* LWIP_IGMP */
1886 #endif /* LWIP_UDP */
1887 #if (LWIP_TCP || LWIP_RAW)
1890 #endif /* (LWIP_TCP || LWIP_RAW) */
1893 msg->err = ERR_CONN;
1896 TCPIP_APIMSG_ACK(msg);
1898 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
1902 * Callback function that is called when DNS name is resolved
1903 * (or on timeout). A waiting application thread is waked up by
1904 * signaling the semaphore.
1907 lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg)
1909 struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1911 /* we trust the internal implementation to be correct :-) */
1912 LWIP_UNUSED_ARG(name);
1914 if (ipaddr == NULL) {
1915 /* timeout or memory error */
1916 API_EXPR_DEREF(msg->err) = ERR_VAL;
1918 /* address was resolved */
1919 API_EXPR_DEREF(msg->err) = ERR_OK;
1920 API_EXPR_DEREF(msg->addr) = *ipaddr;
1922 /* wake up the application task waiting in netconn_gethostbyname */
1923 sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
1927 * Execute a DNS query
1928 * Called from netconn_gethostbyname
1930 * @param arg the dns_api_msg pointing to the query
1933 lwip_netconn_do_gethostbyname(void *arg)
1935 struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1937 #if LWIP_IPV4 && LWIP_IPV6
1940 LWIP_DNS_ADDRTYPE_DEFAULT;
1943 API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name,
1944 API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype);
1945 if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) {
1946 /* on error or immediate success, wake up the application
1947 * task waiting in netconn_gethostbyname */
1948 sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
1951 #endif /* LWIP_DNS */
1953 #endif /* LWIP_NETCONN */