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/api_msg.h"
50 #include "lwip/memp.h"
51 #include "lwip/tcpip.h"
52 #include "lwip/igmp.h"
57 /* forward declarations */
59 static err_t do_writemore(struct netconn *conn);
60 static void do_close_internal(struct netconn *conn);
65 * Receive callback function for RAW netconns.
66 * Doesn't 'eat' the packet, only references it and sends it to
69 * @see raw.h (struct raw_pcb.recv) for parameters and return value
72 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
80 #endif /* LWIP_SO_RCVBUF */
82 LWIP_UNUSED_ARG(addr);
86 SYS_ARCH_GET(conn->recv_avail, recv_avail);
87 if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) &&
88 ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) {
89 #else /* LWIP_SO_RCVBUF */
90 if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) {
91 #endif /* LWIP_SO_RCVBUF */
92 /* copy the whole packet into new pbufs */
93 q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
95 if (pbuf_copy(q, p) != ERR_OK) {
102 buf = memp_malloc(MEMP_NETBUF);
110 buf->addr = &(((struct ip_hdr*)(q->payload))->src);
111 buf->port = pcb->protocol;
113 if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
117 SYS_ARCH_INC(conn->recv_avail, q->tot_len);
118 /* Register event with callback */
119 API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len);
124 return 0; /* do not eat the packet */
130 * Receive callback function for UDP netconns.
131 * Posts the packet to conn->recvmbox or deletes it on memory error.
133 * @see udp.h (struct udp_pcb.recv) for parameters
136 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
137 struct ip_addr *addr, u16_t port)
140 struct netconn *conn;
143 #endif /* LWIP_SO_RCVBUF */
145 LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
146 LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
147 LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
149 LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
152 SYS_ARCH_GET(conn->recv_avail, recv_avail);
153 if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) ||
154 ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
155 #else /* LWIP_SO_RCVBUF */
156 if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {
157 #endif /* LWIP_SO_RCVBUF */
162 buf = memp_malloc(MEMP_NETBUF);
171 #if LWIP_NETBUF_RECVINFO
173 const struct ip_hdr* iphdr = ip_current_header();
174 /* get the UDP header - always in the first pbuf, ensured by udp_input */
175 const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
176 buf->toaddr = (struct ip_addr*)&iphdr->dest;
177 buf->toport = udphdr->dest;
179 #endif /* LWIP_NETBUF_RECVINFO */
182 if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
186 SYS_ARCH_INC(conn->recv_avail, p->tot_len);
187 /* Register event with callback */
188 API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
191 #endif /* LWIP_UDP */
195 * Receive callback function for TCP netconns.
196 * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
198 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
201 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
203 struct netconn *conn;
206 LWIP_UNUSED_ARG(pcb);
207 LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
208 LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
210 LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
215 if (conn->recvmbox == SYS_MBOX_NULL) {
216 /* recvmbox already deleted */
218 tcp_recved(pcb, p->tot_len);
224 /* don't overwrite fatal errors! */
225 NETCONN_SET_SAFE_ERR(conn, err);
229 SYS_ARCH_INC(conn->recv_avail, len);
234 if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {
237 /* Register event with callback */
238 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
245 * Poll callback function for TCP netconns.
246 * Wakes up an application thread that waits for a connection to close
247 * or data to be sent. The application thread then takes the
248 * appropriate action to go on.
250 * Signals the conn->sem.
251 * netconn_close waits for conn->sem if closing failed.
253 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
256 poll_tcp(void *arg, struct tcp_pcb *pcb)
258 struct netconn *conn = arg;
260 LWIP_UNUSED_ARG(pcb);
261 LWIP_ASSERT("conn != NULL", (conn != NULL));
263 if (conn->state == NETCONN_WRITE) {
265 } else if (conn->state == NETCONN_CLOSE) {
266 do_close_internal(conn);
273 * Sent callback function for TCP netconns.
274 * Signals the conn->sem and calls API_EVENT.
275 * netconn_write waits for conn->sem if send buffer is low.
277 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
280 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
282 struct netconn *conn = arg;
284 LWIP_UNUSED_ARG(pcb);
285 LWIP_ASSERT("conn != NULL", (conn != NULL));
287 if (conn->state == NETCONN_WRITE) {
288 LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
290 } else if (conn->state == NETCONN_CLOSE) {
291 do_close_internal(conn);
295 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) {
296 API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
304 * Error callback function for TCP netconns.
305 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
306 * The application thread has then to decide what to do.
308 * @see tcp.h (struct tcp_pcb.err) for parameters
311 err_tcp(void *arg, err_t err)
313 struct netconn *conn;
314 enum netconn_state old_state;
315 SYS_ARCH_DECL_PROTECT(lev);
318 LWIP_ASSERT("conn != NULL", (conn != NULL));
320 conn->pcb.tcp = NULL;
322 /* no check since this is always fatal */
323 SYS_ARCH_PROTECT(lev);
324 conn->last_err = err;
325 SYS_ARCH_UNPROTECT(lev);
327 /* API_EVENT might call tcp_tmr, so reset conn->state now */
328 old_state = conn->state;
329 conn->state = NETCONN_NONE;
331 if (conn->recvmbox != SYS_MBOX_NULL) {
332 /* Register event with callback */
333 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
334 /* use trypot to preven deadlock */
335 sys_mbox_trypost(conn->recvmbox, NULL);
337 if (conn->acceptmbox != SYS_MBOX_NULL) {
338 /* Register event with callback */
339 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
340 /* use trypot to preven deadlock */
341 sys_mbox_trypost(conn->acceptmbox, NULL);
343 if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
344 (old_state == NETCONN_CONNECT)) {
345 /* calling do_writemore/do_close_internal is not necessary
346 since the pcb has already been deleted! */
348 /* set error return code */
349 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
350 conn->current_msg->err = err;
351 conn->current_msg = NULL;
352 /* wake up the waiting task */
353 sys_sem_signal(conn->op_completed);
355 LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
360 * Setup a tcp_pcb with the correct callback function pointers
361 * and their arguments.
363 * @param conn the TCP netconn to setup
366 setup_tcp(struct netconn *conn)
372 tcp_recv(pcb, recv_tcp);
373 tcp_sent(pcb, sent_tcp);
374 tcp_poll(pcb, poll_tcp, 4);
375 tcp_err(pcb, err_tcp);
379 * Accept callback function for TCP netconns.
380 * Allocates a new netconn and posts that to conn->acceptmbox.
382 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
385 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
387 struct netconn *newconn;
388 struct netconn *conn;
392 tcp_debug_print_state(newpcb->state);
393 #endif /* TCP_DEBUG */
394 #endif /* API_MSG_DEBUG */
395 conn = (struct netconn *)arg;
397 if (conn->acceptmbox == SYS_MBOX_NULL) {
398 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
402 /* We have to set the callback here even though
403 * the new socket is unknown. conn->socket is marked as -1. */
404 newconn = netconn_alloc(conn->type, conn->callback);
405 if (newconn == NULL) {
408 newconn->pcb.tcp = newpcb;
410 /* no protection: when creating the pcb, the netconn is not yet known
411 to the application thread */
412 newconn->last_err = err;
414 if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {
415 /* When returning != ERR_OK, the connection is aborted in tcp_process(),
416 so do nothing here! */
417 newconn->pcb.tcp = NULL;
418 /* no need to drain since we know the recvmbox is empty. */
419 sys_mbox_free(newconn->recvmbox);
420 newconn->recvmbox = SYS_MBOX_NULL;
421 netconn_free(newconn);
424 /* Register event with callback */
425 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
430 #endif /* LWIP_TCP */
433 * Create a new pcb of a specific type.
434 * Called from do_newconn().
436 * @param msg the api_msg_msg describing the connection type
437 * @return msg->conn->err, but the return value is currently ignored
440 pcb_new(struct api_msg_msg *msg)
442 LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
444 /* Allocate a PCB for this connection */
445 switch(NETCONNTYPE_GROUP(msg->conn->type)) {
448 msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
449 if(msg->conn->pcb.raw == NULL) {
453 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
455 #endif /* LWIP_RAW */
458 msg->conn->pcb.udp = udp_new();
459 if(msg->conn->pcb.udp == NULL) {
464 if (msg->conn->type==NETCONN_UDPLITE) {
465 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
467 #endif /* LWIP_UDPLITE */
468 if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
469 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
471 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
473 #endif /* LWIP_UDP */
476 msg->conn->pcb.tcp = tcp_new();
477 if(msg->conn->pcb.tcp == NULL) {
481 setup_tcp(msg->conn);
483 #endif /* LWIP_TCP */
485 /* Unsupported netconn type, e.g. protocol disabled */
492 * Create a new pcb of a specific type inside a netconn.
493 * Called from netconn_new_with_proto_and_callback.
495 * @param msg the api_msg_msg describing the connection type
498 do_newconn(struct api_msg_msg *msg)
501 if(msg->conn->pcb.tcp == NULL) {
504 /* Else? This "new" connection already has a PCB allocated. */
505 /* Is this an error condition? Should it be deleted? */
506 /* We currently just are happy and return. */
508 TCPIP_APIMSG_ACK(msg);
512 * Create a new netconn (of a specific type) that has a callback function.
513 * The corresponding pcb is NOT created!
515 * @param t the type of 'connection' to create (@see enum netconn_type)
516 * @param proto the IP protocol for RAW IP pcbs
517 * @param callback a function to call on status changes (RX available, TX'ed)
518 * @return a newly allocated struct netconn or
519 * NULL on memory error
522 netconn_alloc(enum netconn_type t, netconn_callback callback)
524 struct netconn *conn;
527 conn = memp_malloc(MEMP_NETCONN);
532 conn->last_err = ERR_OK;
534 conn->pcb.tcp = NULL;
536 #if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \
537 (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE)
538 size = DEFAULT_RAW_RECVMBOX_SIZE;
540 switch(NETCONNTYPE_GROUP(t)) {
543 size = DEFAULT_RAW_RECVMBOX_SIZE;
545 #endif /* LWIP_RAW */
548 size = DEFAULT_UDP_RECVMBOX_SIZE;
550 #endif /* LWIP_UDP */
553 size = DEFAULT_TCP_RECVMBOX_SIZE;
555 #endif /* LWIP_TCP */
557 LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
562 if ((conn->op_completed = sys_sem_new(0)) == SYS_SEM_NULL) {
563 memp_free(MEMP_NETCONN, conn);
566 if ((conn->recvmbox = sys_mbox_new(size)) == SYS_MBOX_NULL) {
567 sys_sem_free(conn->op_completed);
568 memp_free(MEMP_NETCONN, conn);
572 conn->acceptmbox = SYS_MBOX_NULL;
573 conn->state = NETCONN_NONE;
574 /* initialize socket to -1 since 0 is a valid socket */
576 conn->callback = callback;
577 conn->recv_avail = 0;
579 conn->current_msg = NULL;
580 conn->write_offset = 0;
581 #if LWIP_TCPIP_CORE_LOCKING
582 conn->write_delayed = 0;
583 #endif /* LWIP_TCPIP_CORE_LOCKING */
584 #endif /* LWIP_TCP */
586 conn->recv_timeout = 0;
587 #endif /* LWIP_SO_RCVTIMEO */
589 conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
590 #endif /* LWIP_SO_RCVBUF */
595 * Delete a netconn and all its resources.
596 * The pcb is NOT freed (since we might not be in the right thread context do this).
598 * @param conn the netconn to free
601 netconn_free(struct netconn *conn)
603 LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
604 LWIP_ASSERT("recvmbox must be deallocated before calling this function",
605 conn->recvmbox == SYS_MBOX_NULL);
606 LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
607 conn->acceptmbox == SYS_MBOX_NULL);
609 sys_sem_free(conn->op_completed);
610 conn->op_completed = SYS_SEM_NULL;
612 memp_free(MEMP_NETCONN, conn);
616 * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
619 * @param conn the netconn to free
620 * @bytes_drained bytes drained from recvmbox
621 * @accepts_drained pending connections drained from acceptmbox
624 netconn_drain(struct netconn *conn)
630 /* Delete and drain the recvmbox. */
631 mbox = conn->recvmbox;
632 conn->recvmbox = SYS_MBOX_NULL;
633 if (mbox != SYS_MBOX_NULL) {
634 while (sys_mbox_tryfetch(mbox, &mem) != SYS_MBOX_EMPTY) {
635 if (conn->type == NETCONN_TCP) {
637 p = (struct pbuf*)mem;
638 /* pcb might be set to NULL already by err_tcp() */
639 if (conn->pcb.tcp != NULL) {
640 tcp_recved(conn->pcb.tcp, p->tot_len);
645 netbuf_delete((struct netbuf *)mem);
651 /* Delete and drain the acceptmbox. */
652 mbox = conn->acceptmbox;
653 conn->acceptmbox = SYS_MBOX_NULL;
654 if (mbox != SYS_MBOX_NULL) {
655 while (sys_mbox_tryfetch(mbox, &mem) != SYS_MBOX_EMPTY) {
656 /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
657 /* pcb might be set to NULL already by err_tcp() */
658 if (conn->pcb.tcp != NULL) {
659 tcp_accepted(conn->pcb.tcp);
661 netconn_delete((struct netconn *)mem);
669 * Internal helper function to close a TCP netconn: since this sometimes
670 * doesn't work at the first attempt, this function is called from multiple
673 * @param conn the TCP netconn to close
676 do_close_internal(struct netconn *conn)
680 LWIP_ASSERT("invalid conn", (conn != NULL));
681 LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
682 LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
683 LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
684 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
686 /* Set back some callback pointers */
687 tcp_arg(conn->pcb.tcp, NULL);
688 if (conn->pcb.tcp->state == LISTEN) {
689 tcp_accept(conn->pcb.tcp, NULL);
691 tcp_recv(conn->pcb.tcp, NULL);
692 tcp_accept(conn->pcb.tcp, NULL);
693 /* some callbacks have to be reset if tcp_close is not successful */
694 tcp_sent(conn->pcb.tcp, NULL);
695 tcp_poll(conn->pcb.tcp, NULL, 4);
696 tcp_err(conn->pcb.tcp, NULL);
698 /* Try to close the connection */
699 err = tcp_close(conn->pcb.tcp);
701 /* Closing succeeded */
702 conn->current_msg->err = ERR_OK;
703 conn->current_msg = NULL;
704 conn->state = NETCONN_NONE;
705 /* Set back some callback pointers as conn is going away */
706 conn->pcb.tcp = NULL;
707 /* Trigger select() in socket layer. This send should something else so the
708 errorfd is set, not the read and write fd! */
709 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
710 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
711 /* wake up the application task */
712 sys_sem_signal(conn->op_completed);
714 /* Closing failed, restore some of the callbacks */
715 /* Closing of listen pcb will never fail! */
716 LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN));
717 tcp_sent(conn->pcb.tcp, sent_tcp);
718 tcp_poll(conn->pcb.tcp, poll_tcp, 4);
719 tcp_err(conn->pcb.tcp, err_tcp);
720 tcp_arg(conn->pcb.tcp, conn);
722 /* If closing didn't succeed, we get called again either
723 from poll_tcp or from sent_tcp */
725 #endif /* LWIP_TCP */
728 * Delete the pcb inside a netconn.
729 * Called from netconn_delete.
731 * @param msg the api_msg_msg pointing to the connection
734 do_delconn(struct api_msg_msg *msg)
736 /* Drain and delete mboxes */
737 netconn_drain(msg->conn);
739 if (msg->conn->pcb.tcp != NULL) {
741 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
744 raw_remove(msg->conn->pcb.raw);
746 #endif /* LWIP_RAW */
749 msg->conn->pcb.udp->recv_arg = NULL;
750 udp_remove(msg->conn->pcb.udp);
752 #endif /* LWIP_UDP */
755 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
756 msg->conn->write_offset == 0);
757 msg->conn->state = NETCONN_CLOSE;
758 msg->conn->current_msg = msg;
759 do_close_internal(msg->conn);
760 /* API_EVENT is called inside do_close_internal, before releasing
761 the application thread, so we can return at this point! */
763 #endif /* LWIP_TCP */
768 /* tcp netconns don't come here! */
770 /* Trigger select() in socket layer. This send should something else so the
771 errorfd is set, not the read and write fd! */
772 API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
773 API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
775 if (msg->conn->op_completed != SYS_SEM_NULL) {
776 sys_sem_signal(msg->conn->op_completed);
781 * Bind a pcb contained in a netconn
782 * Called from netconn_bind.
784 * @param msg the api_msg_msg pointing to the connection and containing
785 * the IP address and port to bind to
788 do_bind(struct api_msg_msg *msg)
790 if (ERR_IS_FATAL(msg->conn->last_err)) {
791 msg->err = msg->conn->last_err;
794 if (msg->conn->pcb.tcp != NULL) {
795 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
798 msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
800 #endif /* LWIP_RAW */
803 msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
805 #endif /* LWIP_UDP */
808 msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);
810 #endif /* LWIP_TCP */
816 TCPIP_APIMSG_ACK(msg);
821 * TCP callback function if a connection (opened by tcp_connect/do_connect) has
822 * been established (or reset by the remote host).
824 * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
827 do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
829 struct netconn *conn;
831 LWIP_UNUSED_ARG(pcb);
839 LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
840 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
842 conn->current_msg->err = err;
843 if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {
846 conn->current_msg = NULL;
847 conn->state = NETCONN_NONE;
848 sys_sem_signal(conn->op_completed);
851 #endif /* LWIP_TCP */
854 * Connect a pcb contained inside a netconn
855 * Called from netconn_connect.
857 * @param msg the api_msg_msg pointing to the connection and containing
858 * the IP address and port to connect to
861 do_connect(struct api_msg_msg *msg)
863 if (msg->conn->pcb.tcp == NULL) {
864 /* This may happen when calling netconn_connect() a second time */
866 sys_sem_signal(msg->conn->op_completed);
870 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
873 msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
874 sys_sem_signal(msg->conn->op_completed);
876 #endif /* LWIP_RAW */
879 msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
880 sys_sem_signal(msg->conn->op_completed);
882 #endif /* LWIP_UDP */
885 setup_tcp(msg->conn);
886 msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,
888 /* sys_sem_signal() is called from do_connected (or err_tcp()),
889 * when the connection is established! */
890 if (msg->err == ERR_OK) {
891 msg->conn->state = NETCONN_CONNECT;
892 msg->conn->current_msg = msg;
894 /* tcp_connect failed, so do_connected will not be called: return now */
895 sys_sem_signal(msg->conn->op_completed);
898 #endif /* LWIP_TCP */
900 LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL;
901 sys_sem_signal(msg->conn->op_completed); }while(0));
907 * Connect a pcb contained inside a netconn
908 * Only used for UDP netconns.
909 * Called from netconn_disconnect.
911 * @param msg the api_msg_msg pointing to the connection to disconnect
914 do_disconnect(struct api_msg_msg *msg)
917 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
918 udp_disconnect(msg->conn->pcb.udp);
921 #endif /* LWIP_UDP */
925 TCPIP_APIMSG_ACK(msg);
929 * Set a TCP pcb contained in a netconn into listen mode
930 * Called from netconn_listen.
932 * @param msg the api_msg_msg pointing to the connection
935 do_listen(struct api_msg_msg *msg)
938 if (ERR_IS_FATAL(msg->conn->last_err)) {
939 msg->err = msg->conn->last_err;
942 if (msg->conn->pcb.tcp != NULL) {
943 if (msg->conn->type == NETCONN_TCP) {
944 if (msg->conn->pcb.tcp->state == CLOSED) {
945 #if TCP_LISTEN_BACKLOG
946 struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
947 #else /* TCP_LISTEN_BACKLOG */
948 struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);
949 #endif /* TCP_LISTEN_BACKLOG */
953 /* delete the recvmbox and allocate the acceptmbox */
954 if (msg->conn->recvmbox != SYS_MBOX_NULL) {
955 /** @todo: should we drain the recvmbox here? */
956 sys_mbox_free(msg->conn->recvmbox);
957 msg->conn->recvmbox = SYS_MBOX_NULL;
960 if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
961 if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) {
965 if (msg->err == ERR_OK) {
966 msg->conn->state = NETCONN_LISTEN;
967 msg->conn->pcb.tcp = lpcb;
968 tcp_arg(msg->conn->pcb.tcp, msg->conn);
969 tcp_accept(msg->conn->pcb.tcp, accept_function);
976 #endif /* LWIP_TCP */
977 TCPIP_APIMSG_ACK(msg);
981 * Send some data on a RAW or UDP pcb contained in a netconn
982 * Called from netconn_send
984 * @param msg the api_msg_msg pointing to the connection
987 do_send(struct api_msg_msg *msg)
989 if (ERR_IS_FATAL(msg->conn->last_err)) {
990 msg->err = msg->conn->last_err;
993 if (msg->conn->pcb.tcp != NULL) {
994 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
997 if (msg->msg.b->addr == NULL) {
998 msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
1000 msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr);
1006 if (msg->msg.b->addr == NULL) {
1007 msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
1009 msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port);
1012 #endif /* LWIP_UDP */
1018 TCPIP_APIMSG_ACK(msg);
1022 * Indicate data has been received from a TCP pcb contained in a netconn
1023 * Called from netconn_recv
1025 * @param msg the api_msg_msg pointing to the connection
1028 do_recv(struct api_msg_msg *msg)
1032 if (msg->conn->pcb.tcp != NULL) {
1033 if (msg->conn->type == NETCONN_TCP) {
1034 #if TCP_LISTEN_BACKLOG
1035 if (msg->conn->pcb.tcp->state == LISTEN) {
1036 tcp_accepted(msg->conn->pcb.tcp);
1038 #endif /* TCP_LISTEN_BACKLOG */
1040 tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len);
1044 #endif /* LWIP_TCP */
1045 TCPIP_APIMSG_ACK(msg);
1050 * See if more data needs to be written from a previous call to netconn_write.
1051 * Called initially from do_write. If the first call can't send all data
1052 * (because of low memory or empty send-buffer), this function is called again
1053 * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
1054 * blocking application thread (waiting in netconn_write) is released.
1056 * @param conn netconn (that is currently in state NETCONN_WRITE) to process
1058 * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
1061 do_writemore(struct netconn *conn)
1065 u16_t len, available;
1066 u8_t write_finished = 0;
1069 LWIP_ASSERT("conn != NULL", conn != NULL);
1070 LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
1071 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
1073 dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
1074 diff = conn->current_msg->msg.w.len - conn->write_offset;
1075 if (diff > 0xffffUL) { /* max_u16_t */
1077 #if LWIP_TCPIP_CORE_LOCKING
1078 conn->write_delayed = 1;
1083 available = tcp_sndbuf(conn->pcb.tcp);
1084 if (available < len) {
1085 /* don't try to write more than sendbuf */
1087 #if LWIP_TCPIP_CORE_LOCKING
1088 conn->write_delayed = 1;
1092 err = tcp_write(conn->pcb.tcp, dataptr, len, conn->current_msg->msg.w.apiflags);
1093 LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
1094 if (err == ERR_OK) {
1095 conn->write_offset += len;
1096 if (conn->write_offset == conn->current_msg->msg.w.len) {
1097 /* everything was written */
1099 conn->write_offset = 0;
1100 /* API_EVENT might call tcp_tmr, so reset conn->state now */
1101 conn->state = NETCONN_NONE;
1103 err = tcp_output_nagle(conn->pcb.tcp);
1104 if ((err == ERR_OK) && (tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT)) {
1105 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
1107 } else if (err == ERR_MEM) {
1108 /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
1109 we do NOT return to the application thread, since ERR_MEM is
1110 only a temporary error! */
1112 /* tcp_enqueue returned ERR_MEM, try tcp_output anyway */
1113 err = tcp_output(conn->pcb.tcp);
1115 #if LWIP_TCPIP_CORE_LOCKING
1116 conn->write_delayed = 1;
1119 /* On errors != ERR_MEM, we don't try writing any more but return
1120 the error to the application thread. */
1124 if (write_finished) {
1125 /* everything was written: set back connection state
1126 and back to application task */
1127 conn->current_msg->err = err;
1128 conn->current_msg = NULL;
1129 conn->state = NETCONN_NONE;
1130 #if LWIP_TCPIP_CORE_LOCKING
1131 if (conn->write_delayed != 0)
1134 sys_sem_signal(conn->op_completed);
1137 #if LWIP_TCPIP_CORE_LOCKING
1143 #endif /* LWIP_TCP */
1146 * Send some data on a TCP pcb contained in a netconn
1147 * Called from netconn_write
1149 * @param msg the api_msg_msg pointing to the connection
1152 do_write(struct api_msg_msg *msg)
1154 if (ERR_IS_FATAL(msg->conn->last_err)) {
1155 msg->err = msg->conn->last_err;
1157 if (msg->conn->type == NETCONN_TCP) {
1159 if (msg->conn->pcb.tcp != NULL) {
1160 msg->conn->state = NETCONN_WRITE;
1161 /* set all the variables used by do_writemore */
1162 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1163 msg->conn->write_offset == 0);
1164 msg->conn->current_msg = msg;
1165 msg->conn->write_offset = 0;
1166 #if LWIP_TCPIP_CORE_LOCKING
1167 msg->conn->write_delayed = 0;
1168 if (do_writemore(msg->conn) != ERR_OK) {
1169 LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
1170 UNLOCK_TCPIP_CORE();
1171 sys_arch_sem_wait(msg->conn->op_completed, 0);
1173 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1175 #else /* LWIP_TCPIP_CORE_LOCKING */
1176 do_writemore(msg->conn);
1177 #endif /* LWIP_TCPIP_CORE_LOCKING */
1178 /* for both cases: if do_writemore was called, don't ACK the APIMSG
1179 since do_writemore ACKs it! */
1182 msg->err = ERR_CONN;
1184 #else /* LWIP_TCP */
1186 #endif /* LWIP_TCP */
1187 #if (LWIP_UDP || LWIP_RAW)
1190 #endif /* (LWIP_UDP || LWIP_RAW) */
1193 TCPIP_APIMSG_ACK(msg);
1197 * Return a connection's local or remote address
1198 * Called from netconn_getaddr
1200 * @param msg the api_msg_msg pointing to the connection
1203 do_getaddr(struct api_msg_msg *msg)
1205 if (msg->conn->pcb.ip != NULL) {
1206 *(msg->msg.ad.ipaddr) = (msg->msg.ad.local?msg->conn->pcb.ip->local_ip:msg->conn->pcb.ip->remote_ip);
1209 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1212 if (msg->msg.ad.local) {
1213 *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
1215 /* return an error as connecting is only a helper for upper layers */
1216 msg->err = ERR_CONN;
1219 #endif /* LWIP_RAW */
1222 if (msg->msg.ad.local) {
1223 *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
1225 if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
1226 msg->err = ERR_CONN;
1228 *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
1232 #endif /* LWIP_UDP */
1235 *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port);
1237 #endif /* LWIP_TCP */
1240 msg->err = ERR_CONN;
1242 TCPIP_APIMSG_ACK(msg);
1246 * Close a TCP pcb contained in a netconn
1247 * Called from netconn_close
1249 * @param msg the api_msg_msg pointing to the connection
1252 do_close(struct api_msg_msg *msg)
1255 if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
1256 netconn_drain(msg->conn);
1257 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1258 msg->conn->write_offset == 0);
1259 msg->conn->state = NETCONN_CLOSE;
1260 msg->conn->current_msg = msg;
1261 do_close_internal(msg->conn);
1262 /* for tcp netconns, do_close_internal ACKs the message */
1264 #endif /* LWIP_TCP */
1267 sys_sem_signal(msg->conn->op_completed);
1273 * Join multicast groups for UDP netconns.
1274 * Called from netconn_join_leave_group
1276 * @param msg the api_msg_msg pointing to the connection
1279 do_join_leave_group(struct api_msg_msg *msg)
1281 if (ERR_IS_FATAL(msg->conn->last_err)) {
1282 msg->err = msg->conn->last_err;
1284 if (msg->conn->pcb.tcp != NULL) {
1285 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1287 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
1288 msg->err = igmp_joingroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);
1290 msg->err = igmp_leavegroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);
1292 #endif /* LWIP_UDP */
1293 #if (LWIP_TCP || LWIP_RAW)
1296 #endif /* (LWIP_TCP || LWIP_RAW) */
1299 msg->err = ERR_CONN;
1302 TCPIP_APIMSG_ACK(msg);
1304 #endif /* LWIP_IGMP */
1308 * Callback function that is called when DNS name is resolved
1309 * (or on timeout). A waiting application thread is waked up by
1310 * signaling the semaphore.
1313 do_dns_found(const char *name, struct ip_addr *ipaddr, void *arg)
1315 struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1317 LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0);
1318 LWIP_UNUSED_ARG(name);
1320 if (ipaddr == NULL) {
1321 /* timeout or memory error */
1322 *msg->err = ERR_VAL;
1324 /* address was resolved */
1326 *msg->addr = *ipaddr;
1328 /* wake up the application task waiting in netconn_gethostbyname */
1329 sys_sem_signal(msg->sem);
1333 * Execute a DNS query
1334 * Called from netconn_gethostbyname
1336 * @param arg the dns_api_msg pointing to the query
1339 do_gethostbyname(void *arg)
1341 struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1343 *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg);
1344 if (*msg->err != ERR_INPROGRESS) {
1345 /* on error or immediate success, wake up the application
1346 * task waiting in netconn_gethostbyname */
1347 sys_sem_signal(msg->sem);
1350 #endif /* LWIP_DNS */
1352 #endif /* LWIP_NETCONN */