Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_api_msg.c Source File

lwip_api_msg.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Sequential API Internal module
00004  *
00005  */
00006 
00007 /*
00008  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00009  * All rights reserved.
00010  *
00011  * Redistribution and use in source and binary forms, with or without modification,
00012  * are permitted provided that the following conditions are met:
00013  *
00014  * 1. Redistributions of source code must retain the above copyright notice,
00015  *    this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright notice,
00017  *    this list of conditions and the following disclaimer in the documentation
00018  *    and/or other materials provided with the distribution.
00019  * 3. The name of the author may not be used to endorse or promote products
00020  *    derived from this software without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00023  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00025  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00027  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00030  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00031  * OF SUCH DAMAGE.
00032  *
00033  * This file is part of the lwIP TCP/IP stack.
00034  *
00035  * Author: Adam Dunkels <adam@sics.se>
00036  *
00037  */
00038 
00039 #include "lwip/opt.h"
00040 
00041 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
00042 
00043 #include "lwip/priv/api_msg.h"
00044 
00045 #include "lwip/ip.h"
00046 #include "lwip/ip_addr.h"
00047 #include "lwip/udp.h"
00048 #include "lwip/tcp.h"
00049 #include "lwip/raw.h"
00050 
00051 #include "lwip/memp.h"
00052 #include "lwip/igmp.h"
00053 #include "lwip/dns.h"
00054 #include "lwip/mld6.h"
00055 #include "lwip/priv/tcpip_priv.h"
00056 
00057 #include <string.h>
00058 
00059 /* netconns are polled once per second (e.g. continue write on memory error) */
00060 #define NETCONN_TCP_POLL_INTERVAL 2
00061 
00062 #define SET_NONBLOCKING_CONNECT(conn, val)  do { if (val) { \
00063   (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \
00064 } else { \
00065   (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0)
00066 #define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0)
00067 
00068 /* forward declarations */
00069 #if LWIP_TCP
00070 #if LWIP_TCPIP_CORE_LOCKING
00071 #define WRITE_DELAYED         , 1
00072 #define WRITE_DELAYED_PARAM   , u8_t delayed
00073 #else /* LWIP_TCPIP_CORE_LOCKING */
00074 #define WRITE_DELAYED
00075 #define WRITE_DELAYED_PARAM
00076 #endif /* LWIP_TCPIP_CORE_LOCKING */
00077 static err_t lwip_netconn_do_writemore(struct netconn *conn  WRITE_DELAYED_PARAM);
00078 static err_t lwip_netconn_do_close_internal(struct netconn *conn  WRITE_DELAYED_PARAM);
00079 #endif
00080 
00081 #if LWIP_TCPIP_CORE_LOCKING
00082 #define TCPIP_APIMSG_ACK(m)   NETCONN_SET_SAFE_ERR((m)->conn, (m)->err)
00083 #else /* LWIP_TCPIP_CORE_LOCKING */
00084 #define TCPIP_APIMSG_ACK(m)   do { NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
00085 #endif /* LWIP_TCPIP_CORE_LOCKING */
00086 
00087 #if LWIP_TCP
00088 u8_t netconn_aborted;
00089 #endif /* LWIP_TCP */
00090 
00091 #if LWIP_RAW
00092 /**
00093  * Receive callback function for RAW netconns.
00094  * Doesn't 'eat' the packet, only copies it and sends it to
00095  * conn->recvmbox
00096  *
00097  * @see raw.h (struct raw_pcb.recv) for parameters and return value
00098  */
00099 static u8_t
00100 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
00101     const ip_addr_t *addr)
00102 {
00103   struct pbuf *q;
00104   struct netbuf *buf;
00105   struct netconn *conn;
00106 
00107   LWIP_UNUSED_ARG(addr);
00108   conn = (struct netconn *)arg;
00109 
00110   if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) {
00111 #if LWIP_SO_RCVBUF
00112     int recv_avail;
00113     SYS_ARCH_GET(conn->recv_avail, recv_avail);
00114     if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
00115       return 0;
00116     }
00117 #endif /* LWIP_SO_RCVBUF */
00118     /* copy the whole packet into new pbufs */
00119     q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
00120     if (q != NULL) {
00121       if (pbuf_copy(q, p) != ERR_OK) {
00122         pbuf_free(q);
00123         q = NULL;
00124       }
00125     }
00126 
00127     if (q != NULL) {
00128       u16_t len;
00129       buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
00130       if (buf == NULL) {
00131         pbuf_free(q);
00132         return 0;
00133       }
00134 
00135       buf->p = q;
00136       buf->ptr = q;
00137       ip_addr_copy(buf->addr, *ip_current_src_addr());
00138       buf->port = pcb->protocol;
00139 
00140       len = q->tot_len;
00141       if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
00142         netbuf_delete(buf);
00143         return 0;
00144       } else {
00145 #if LWIP_SO_RCVBUF
00146         SYS_ARCH_INC(conn->recv_avail, len);
00147 #endif /* LWIP_SO_RCVBUF */
00148         /* Register event with callback */
00149         API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
00150       }
00151     }
00152   }
00153 
00154   return 0; /* do not eat the packet */
00155 }
00156 #endif /* LWIP_RAW*/
00157 
00158 #if LWIP_UDP
00159 /**
00160  * Receive callback function for UDP netconns.
00161  * Posts the packet to conn->recvmbox or deletes it on memory error.
00162  *
00163  * @see udp.h (struct udp_pcb.recv) for parameters
00164  */
00165 static void
00166 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
00167    const ip_addr_t *addr, u16_t port)
00168 {
00169   struct netbuf *buf;
00170   struct netconn *conn;
00171   u16_t len;
00172 #if LWIP_SO_RCVBUF
00173   int recv_avail;
00174 #endif /* LWIP_SO_RCVBUF */
00175 
00176   LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
00177   LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
00178   LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
00179   conn = (struct netconn *)arg;
00180   LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
00181 
00182 #if LWIP_SO_RCVBUF
00183   SYS_ARCH_GET(conn->recv_avail, recv_avail);
00184   if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) ||
00185       ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
00186 #else  /* LWIP_SO_RCVBUF */
00187   if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) {
00188 #endif /* LWIP_SO_RCVBUF */
00189     pbuf_free(p);
00190     return;
00191   }
00192 
00193   buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
00194   if (buf == NULL) {
00195     pbuf_free(p);
00196     return;
00197   } else {
00198     buf->p = p;
00199     buf->ptr = p;
00200     ip_addr_set(&buf->addr, addr);
00201     buf->port = port;
00202 #if LWIP_NETBUF_RECVINFO
00203     {
00204       /* get the UDP header - always in the first pbuf, ensured by udp_input */
00205       const struct udp_hdr* udphdr = (const struct udp_hdr*)ip_next_header_ptr();
00206 #if LWIP_CHECKSUM_ON_COPY
00207       buf->flags = NETBUF_FLAG_DESTADDR;
00208 #endif /* LWIP_CHECKSUM_ON_COPY */
00209       ip_addr_set(&buf->toaddr, ip_current_dest_addr());
00210       buf->toport_chksum = udphdr->dest;
00211     }
00212 #endif /* LWIP_NETBUF_RECVINFO */
00213   }
00214 
00215   len = p->tot_len;
00216   if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
00217     netbuf_delete(buf);
00218     return;
00219   } else {
00220 #if LWIP_SO_RCVBUF
00221     SYS_ARCH_INC(conn->recv_avail, len);
00222 #endif /* LWIP_SO_RCVBUF */
00223     /* Register event with callback */
00224     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
00225   }
00226 }
00227 #endif /* LWIP_UDP */
00228 
00229 #if LWIP_TCP
00230 /**
00231  * Receive callback function for TCP netconns.
00232  * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
00233  *
00234  * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
00235  */
00236 static err_t
00237 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
00238 {
00239   struct netconn *conn;
00240   u16_t len;
00241 
00242   LWIP_UNUSED_ARG(pcb);
00243   LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
00244   LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
00245   conn = (struct netconn *)arg;
00246 
00247   if (conn == NULL) {
00248     return ERR_VAL;
00249   }
00250   LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
00251 
00252   if (!sys_mbox_valid(&conn->recvmbox)) {
00253     /* recvmbox already deleted */
00254     if (p != NULL) {
00255       tcp_recved(pcb, p->tot_len);
00256       pbuf_free(p);
00257     }
00258     return ERR_OK;
00259   }
00260   /* Unlike for UDP or RAW pcbs, don't check for available space
00261      using recv_avail since that could break the connection
00262      (data is already ACKed) */
00263 
00264   /* don't overwrite fatal errors! */
00265   if (err != ERR_OK) {
00266     NETCONN_SET_SAFE_ERR(conn, err);
00267   }
00268 
00269   if (p != NULL) {
00270     len = p->tot_len;
00271   } else {
00272     len = 0;
00273   }
00274 
00275   if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) {
00276     /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
00277     return ERR_MEM;
00278   } else {
00279 #if LWIP_SO_RCVBUF
00280     SYS_ARCH_INC(conn->recv_avail, len);
00281 #endif /* LWIP_SO_RCVBUF */
00282     /* Register event with callback */
00283     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
00284   }
00285 
00286   return ERR_OK;
00287 }
00288 
00289 /**
00290  * Poll callback function for TCP netconns.
00291  * Wakes up an application thread that waits for a connection to close
00292  * or data to be sent. The application thread then takes the
00293  * appropriate action to go on.
00294  *
00295  * Signals the conn->sem.
00296  * netconn_close waits for conn->sem if closing failed.
00297  *
00298  * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
00299  */
00300 static err_t
00301 poll_tcp(void *arg, struct tcp_pcb *pcb)
00302 {
00303   struct netconn *conn = (struct netconn *)arg;
00304 
00305   LWIP_UNUSED_ARG(pcb);
00306   LWIP_ASSERT("conn != NULL", (conn != NULL));
00307 
00308   if (conn->state == NETCONN_WRITE) {
00309     lwip_netconn_do_writemore(conn  WRITE_DELAYED);
00310   } else if (conn->state == NETCONN_CLOSE) {
00311 #if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER
00312     if (conn->current_msg && conn->current_msg->msg.sd.polls_left) {
00313       conn->current_msg->msg.sd.polls_left--;
00314     }
00315 #endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */
00316     lwip_netconn_do_close_internal(conn  WRITE_DELAYED);
00317   }
00318   /* @todo: implement connect timeout here? */
00319 
00320   /* Did a nonblocking write fail before? Then check available write-space. */
00321   if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
00322     /* If the queued byte- or pbuf-count drops below the configured low-water limit,
00323        let select mark this pcb as writable again. */
00324     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
00325       (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
00326       conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
00327       API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
00328     }
00329   }
00330 
00331   return ERR_OK;
00332 }
00333 
00334 /**
00335  * Sent callback function for TCP netconns.
00336  * Signals the conn->sem and calls API_EVENT.
00337  * netconn_write waits for conn->sem if send buffer is low.
00338  *
00339  * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
00340  */
00341 static err_t
00342 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
00343 {
00344   struct netconn *conn = (struct netconn *)arg;
00345 
00346   LWIP_UNUSED_ARG(pcb);
00347   LWIP_ASSERT("conn != NULL", (conn != NULL));
00348 
00349   if (conn) {
00350     if (conn->state == NETCONN_WRITE) {
00351       lwip_netconn_do_writemore(conn  WRITE_DELAYED);
00352     } else if (conn->state == NETCONN_CLOSE) {
00353       lwip_netconn_do_close_internal(conn  WRITE_DELAYED);
00354     }
00355 
00356     /* If the queued byte- or pbuf-count drops below the configured low-water limit,
00357        let select mark this pcb as writable again. */
00358     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
00359       (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
00360       conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
00361       API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
00362     }
00363   }
00364 
00365   return ERR_OK;
00366 }
00367 
00368 /**
00369  * Error callback function for TCP netconns.
00370  * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
00371  * The application thread has then to decide what to do.
00372  *
00373  * @see tcp.h (struct tcp_pcb.err) for parameters
00374  */
00375 static void
00376 err_tcp(void *arg, err_t err)
00377 {
00378   struct netconn *conn;
00379   enum netconn_state old_state;
00380 
00381   conn = (struct netconn *)arg;
00382   LWIP_ASSERT("conn != NULL", (conn != NULL));
00383 
00384   conn->pcb.tcp = NULL;
00385 
00386   /* reset conn->state now before waking up other threads */
00387   old_state = conn->state;
00388   conn->state = NETCONN_NONE;
00389 
00390   if (old_state == NETCONN_CLOSE) {
00391     /* RST during close: let close return success & dealloc the netconn */
00392     err = ERR_OK;
00393     NETCONN_SET_SAFE_ERR(conn, ERR_OK);
00394   } else {
00395     /* no check since this is always fatal! */
00396     SYS_ARCH_SET(conn->last_err, err);
00397   }
00398 
00399   /* @todo: the type of NETCONN_EVT created should depend on 'old_state' */
00400 
00401   /* Notify the user layer about a connection error. Used to signal select. */
00402   API_EVENT(conn, NETCONN_EVT_ERROR, 0);
00403   /* Try to release selects pending on 'read' or 'write', too.
00404      They will get an error if they actually try to read or write. */
00405   API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
00406   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
00407 
00408   /* pass NULL-message to recvmbox to wake up pending recv */
00409   if (sys_mbox_valid(&conn->recvmbox)) {
00410     /* use trypost to prevent deadlock */
00411     sys_mbox_trypost(&conn->recvmbox, NULL);
00412   }
00413   /* pass NULL-message to acceptmbox to wake up pending accept */
00414   if (sys_mbox_valid(&conn->acceptmbox)) {
00415     /* use trypost to preven deadlock */
00416     sys_mbox_trypost(&conn->acceptmbox, NULL);
00417   }
00418 
00419   if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
00420       (old_state == NETCONN_CONNECT)) {
00421     /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary
00422        since the pcb has already been deleted! */
00423     int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
00424     SET_NONBLOCKING_CONNECT(conn, 0);
00425 
00426     if (!was_nonblocking_connect) {
00427       sys_sem_t* op_completed_sem;
00428       /* set error return code */
00429       LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
00430       conn->current_msg->err = err;
00431       op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
00432       LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem));
00433       conn->current_msg = NULL;
00434       /* wake up the waiting task */
00435       NETCONN_SET_SAFE_ERR(conn, err);
00436       sys_sem_signal(op_completed_sem);
00437     }
00438   } else {
00439     LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
00440   }
00441 }
00442 
00443 /**
00444  * Setup a tcp_pcb with the correct callback function pointers
00445  * and their arguments.
00446  *
00447  * @param conn the TCP netconn to setup
00448  */
00449 static void
00450 setup_tcp(struct netconn *conn)
00451 {
00452   struct tcp_pcb *pcb;
00453 
00454   pcb = conn->pcb.tcp;
00455   tcp_arg(pcb, conn);
00456   tcp_recv(pcb, recv_tcp);
00457   tcp_sent(pcb, sent_tcp);
00458   tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL);
00459   tcp_err(pcb, err_tcp);
00460 }
00461 
00462 /**
00463  * Accept callback function for TCP netconns.
00464  * Allocates a new netconn and posts that to conn->acceptmbox.
00465  *
00466  * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
00467  */
00468 static err_t
00469 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
00470 {
00471   struct netconn *newconn;
00472   struct netconn *conn = (struct netconn *)arg;
00473 
00474   LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state)));
00475 
00476   if (conn == NULL) {
00477     return ERR_VAL;
00478   }
00479   if (!sys_mbox_valid(&conn->acceptmbox)) {
00480     LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
00481     return ERR_VAL;
00482   }
00483 
00484   if (newpcb == NULL) {
00485     /* out-of-pcbs during connect: pass on this error to the application */
00486     if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) {
00487       /* Register event with callback */
00488       API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
00489     }
00490     return ERR_VAL;
00491   }
00492 
00493   /* We have to set the callback here even though
00494    * the new socket is unknown. newconn->socket is marked as -1. */
00495   newconn = netconn_alloc(conn->type, conn->callback);
00496   if (newconn == NULL) {
00497     /* outof netconns: pass on this error to the application */
00498     if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) {
00499       /* Register event with callback */
00500       API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
00501     }
00502     return ERR_MEM;
00503   }
00504   newconn->pcb.tcp = newpcb;
00505   setup_tcp(newconn);
00506   /* no protection: when creating the pcb, the netconn is not yet known
00507      to the application thread */
00508   newconn->last_err = err;
00509 
00510   /* handle backlog counter */
00511   tcp_backlog_delayed(newpcb);
00512 
00513   if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
00514     /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
00515        so do nothing here! */
00516     /* remove all references to this netconn from the pcb */
00517     struct tcp_pcb* pcb = newconn->pcb.tcp;
00518     tcp_arg(pcb, NULL);
00519     tcp_recv(pcb, NULL);
00520     tcp_sent(pcb, NULL);
00521     tcp_poll(pcb, NULL, 0);
00522     tcp_err(pcb, NULL);
00523     /* remove reference from to the pcb from this netconn */
00524     newconn->pcb.tcp = NULL;
00525     /* no need to drain since we know the recvmbox is empty. */
00526     sys_mbox_free(&newconn->recvmbox);
00527     sys_mbox_set_invalid(&newconn->recvmbox);
00528     netconn_free(newconn);
00529     return ERR_MEM;
00530   } else {
00531     /* Register event with callback */
00532     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
00533   }
00534 
00535   return ERR_OK;
00536 }
00537 #endif /* LWIP_TCP */
00538 
00539 /**
00540  * Create a new pcb of a specific type.
00541  * Called from lwip_netconn_do_newconn().
00542  *
00543  * @param msg the api_msg_msg describing the connection type
00544  */
00545 static void
00546 pcb_new(struct api_msg *msg)
00547 {
00548   enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4;
00549 
00550   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
00551  
00552 #if LWIP_IPV6 && LWIP_IPV4
00553   /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */
00554   if(NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) {
00555     iptype = IPADDR_TYPE_ANY;
00556   }
00557 #endif
00558   
00559   /* Allocate a PCB for this connection */
00560   switch(NETCONNTYPE_GROUP(msg->conn->type)) {
00561 #if LWIP_RAW
00562   case NETCONN_RAW:
00563     msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto);
00564     if (msg->conn->pcb.raw != NULL) {
00565 #if LWIP_IPV6
00566       /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */
00567       if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) {
00568         msg->conn->pcb.raw->chksum_reqd = 1;
00569         msg->conn->pcb.raw->chksum_offset = 2;
00570       }
00571 #endif /* LWIP_IPV6 */
00572       raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
00573     }
00574     break;
00575 #endif /* LWIP_RAW */
00576 #if LWIP_UDP
00577   case NETCONN_UDP:
00578     msg->conn->pcb.udp = udp_new_ip_type(iptype);
00579     if (msg->conn->pcb.udp != NULL) {
00580 #if LWIP_UDPLITE
00581       if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
00582         udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
00583       }
00584 #endif /* LWIP_UDPLITE */
00585       if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) {
00586         udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
00587       }
00588       udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
00589     }
00590     break;
00591 #endif /* LWIP_UDP */
00592 #if LWIP_TCP
00593   case NETCONN_TCP:
00594     msg->conn->pcb.tcp = tcp_new_ip_type(iptype);
00595     if (msg->conn->pcb.tcp != NULL) {
00596       setup_tcp(msg->conn);
00597     }
00598     break;
00599 #endif /* LWIP_TCP */
00600   default:
00601     /* Unsupported netconn type, e.g. protocol disabled */
00602     msg->err = ERR_VAL;
00603     return;
00604   }
00605   if (msg->conn->pcb.ip == NULL) {
00606     msg->err = ERR_MEM;
00607   }
00608 }
00609 
00610 /**
00611  * Create a new pcb of a specific type inside a netconn.
00612  * Called from netconn_new_with_proto_and_callback.
00613  *
00614  * @param m the api_msg_msg describing the connection type
00615  */
00616 void
00617 lwip_netconn_do_newconn(void *m)
00618 {
00619   struct api_msg *msg = (struct api_msg*)m;
00620 
00621   msg->err = ERR_OK;
00622   if (msg->conn->pcb.tcp == NULL) {
00623     pcb_new(msg);
00624   }
00625   /* Else? This "new" connection already has a PCB allocated. */
00626   /* Is this an error condition? Should it be deleted? */
00627   /* We currently just are happy and return. */
00628 
00629   TCPIP_APIMSG_ACK(msg);
00630 }
00631 
00632 /**
00633  * Create a new netconn (of a specific type) that has a callback function.
00634  * The corresponding pcb is NOT created!
00635  *
00636  * @param t the type of 'connection' to create (@see enum netconn_type)
00637  * @param callback a function to call on status changes (RX available, TX'ed)
00638  * @return a newly allocated struct netconn or
00639  *         NULL on memory error
00640  */
00641 struct netconn*
00642 netconn_alloc(enum netconn_type t, netconn_callback callback)
00643 {
00644   struct netconn *conn;
00645   int size;
00646 
00647   conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
00648   if (conn == NULL) {
00649     return NULL;
00650   }
00651 
00652   conn->last_err = ERR_OK;
00653   conn->type = t;
00654   conn->pcb.tcp = NULL;
00655 
00656   /* If all sizes are the same, every compiler should optimize this switch to nothing */
00657   switch(NETCONNTYPE_GROUP(t)) {
00658 #if LWIP_RAW
00659   case NETCONN_RAW:
00660     size = DEFAULT_RAW_RECVMBOX_SIZE;
00661     break;
00662 #endif /* LWIP_RAW */
00663 #if LWIP_UDP
00664   case NETCONN_UDP:
00665     size = DEFAULT_UDP_RECVMBOX_SIZE;
00666     break;
00667 #endif /* LWIP_UDP */
00668 #if LWIP_TCP
00669   case NETCONN_TCP:
00670     size = DEFAULT_TCP_RECVMBOX_SIZE;
00671     break;
00672 #endif /* LWIP_TCP */
00673   default:
00674     LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
00675     goto free_and_return;
00676   }
00677 
00678   if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
00679     goto free_and_return;
00680   }
00681 #if !LWIP_NETCONN_SEM_PER_THREAD
00682   if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
00683     sys_mbox_free(&conn->recvmbox);
00684     goto free_and_return;
00685   }
00686 #endif
00687 
00688 #if LWIP_TCP
00689   sys_mbox_set_invalid(&conn->acceptmbox);
00690 #endif
00691   conn->state        = NETCONN_NONE;
00692 #if LWIP_SOCKET
00693   /* initialize socket to -1 since 0 is a valid socket */
00694   conn->socket       = -1;
00695 #endif /* LWIP_SOCKET */
00696   conn->callback     = callback;
00697 #if LWIP_TCP
00698   conn->current_msg  = NULL;
00699   conn->write_offset = 0;
00700 #endif /* LWIP_TCP */
00701 #if LWIP_SO_SNDTIMEO
00702   conn->send_timeout = 0;
00703 #endif /* LWIP_SO_SNDTIMEO */
00704 #if LWIP_SO_RCVTIMEO
00705   conn->recv_timeout = 0;
00706 #endif /* LWIP_SO_RCVTIMEO */
00707 #if LWIP_SO_RCVBUF
00708   conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
00709   conn->recv_avail   = 0;
00710 #endif /* LWIP_SO_RCVBUF */
00711 #if LWIP_SO_LINGER
00712   conn->linger = -1;
00713 #endif /* LWIP_SO_LINGER */
00714   conn->flags = 0;
00715   return conn;
00716 free_and_return:
00717   memp_free(MEMP_NETCONN, conn);
00718   return NULL;
00719 }
00720 
00721 /**
00722  * Delete a netconn and all its resources.
00723  * The pcb is NOT freed (since we might not be in the right thread context do this).
00724  *
00725  * @param conn the netconn to free
00726  */
00727 void
00728 netconn_free(struct netconn *conn)
00729 {
00730   LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
00731   LWIP_ASSERT("recvmbox must be deallocated before calling this function",
00732     !sys_mbox_valid(&conn->recvmbox));
00733 #if LWIP_TCP
00734   LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
00735     !sys_mbox_valid(&conn->acceptmbox));
00736 #endif /* LWIP_TCP */
00737 
00738 #if !LWIP_NETCONN_SEM_PER_THREAD
00739   sys_sem_free(&conn->op_completed);
00740   sys_sem_set_invalid(&conn->op_completed);
00741 #endif
00742 
00743   memp_free(MEMP_NETCONN, conn);
00744 }
00745 
00746 /**
00747  * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
00748  * these mboxes
00749  *
00750  * @param conn the netconn to free
00751  * @bytes_drained bytes drained from recvmbox
00752  * @accepts_drained pending connections drained from acceptmbox
00753  */
00754 static void
00755 netconn_drain(struct netconn *conn)
00756 {
00757   void *mem;
00758 #if LWIP_TCP
00759   struct pbuf *p;
00760 #endif /* LWIP_TCP */
00761 
00762   /* This runs in tcpip_thread, so we don't need to lock against rx packets */
00763 
00764   /* Delete and drain the recvmbox. */
00765   if (sys_mbox_valid(&conn->recvmbox)) {
00766     while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
00767 #if LWIP_TCP
00768       if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
00769         if (mem != NULL) {
00770           p = (struct pbuf*)mem;
00771           /* pcb might be set to NULL already by err_tcp() */
00772           if (conn->pcb.tcp != NULL) {
00773             tcp_recved(conn->pcb.tcp, p->tot_len);
00774           }
00775           pbuf_free(p);
00776         }
00777       } else
00778 #endif /* LWIP_TCP */
00779       {
00780         netbuf_delete((struct netbuf *)mem);
00781       }
00782     }
00783     sys_mbox_free(&conn->recvmbox);
00784     sys_mbox_set_invalid(&conn->recvmbox);
00785   }
00786 
00787   /* Delete and drain the acceptmbox. */
00788 #if LWIP_TCP
00789   if (sys_mbox_valid(&conn->acceptmbox)) {
00790     while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
00791       if (mem != &netconn_aborted) {
00792         struct netconn *newconn = (struct netconn *)mem;
00793         /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
00794         /* pcb might be set to NULL already by err_tcp() */
00795         /* drain recvmbox */
00796         netconn_drain(newconn);
00797         if (newconn->pcb.tcp != NULL) {
00798           tcp_abort(newconn->pcb.tcp);
00799           newconn->pcb.tcp = NULL;
00800         }
00801         netconn_free(newconn);
00802       }
00803     }
00804     sys_mbox_free(&conn->acceptmbox);
00805     sys_mbox_set_invalid(&conn->acceptmbox);
00806   }
00807 #endif /* LWIP_TCP */
00808 }
00809 
00810 #if LWIP_TCP
00811 /**
00812  * Internal helper function to close a TCP netconn: since this sometimes
00813  * doesn't work at the first attempt, this function is called from multiple
00814  * places.
00815  *
00816  * @param conn the TCP netconn to close
00817  */
00818 static err_t
00819 lwip_netconn_do_close_internal(struct netconn *conn  WRITE_DELAYED_PARAM)
00820 {
00821   err_t err;
00822   u8_t shut, shut_rx, shut_tx, close;
00823   u8_t close_finished = 0;
00824   struct tcp_pcb* tpcb;
00825 #if LWIP_SO_LINGER
00826   u8_t linger_wait_required = 0;
00827 #endif /* LWIP_SO_LINGER */
00828 
00829   LWIP_ASSERT("invalid conn", (conn != NULL));
00830   LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
00831   LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
00832   LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
00833   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
00834 
00835   tpcb = conn->pcb.tcp;
00836   shut = conn->current_msg->msg.sd.shut;
00837   shut_rx = shut & NETCONN_SHUT_RD;
00838   shut_tx = shut & NETCONN_SHUT_WR;
00839   /* shutting down both ends is the same as closing
00840      (also if RD or WR side was shut down before already) */
00841   if (shut == NETCONN_SHUT_RDWR) {
00842     close = 1;
00843   } else if (shut_rx &&
00844              ((tpcb->state == FIN_WAIT_1) ||
00845               (tpcb->state == FIN_WAIT_2) ||
00846               (tpcb->state == CLOSING))) {
00847     close = 1;
00848   } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) {
00849     close = 1;
00850   } else {
00851     close = 0;
00852   }
00853 
00854   /* Set back some callback pointers */
00855   if (close) {
00856     tcp_arg(tpcb, NULL);
00857   }
00858   if (tpcb->state == LISTEN) {
00859     tcp_accept(tpcb, NULL);
00860   } else {
00861     /* some callbacks have to be reset if tcp_close is not successful */
00862     if (shut_rx) {
00863       tcp_recv(tpcb, NULL);
00864       tcp_accept(tpcb, NULL);
00865     }
00866     if (shut_tx) {
00867       tcp_sent(tpcb, NULL);
00868     }
00869     if (close) {
00870       tcp_poll(tpcb, NULL, 0);
00871       tcp_err(tpcb, NULL);
00872     }
00873   }
00874   /* Try to close the connection */
00875   if (close) {
00876 #if LWIP_SO_LINGER
00877     /* check linger possibilites before calling tcp_close */
00878     err = ERR_OK;
00879     /* linger enabled/required at all? (i.e. is there untransmitted data left?) */
00880     if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) {
00881       if ((conn->linger == 0)) {
00882         /* data left but linger prevents waiting */
00883         tcp_abort(tpcb);
00884         tpcb = NULL;
00885       } else if (conn->linger > 0) {
00886         /* data left and linger says we should wait */
00887         if (netconn_is_nonblocking(conn)) {
00888           /* data left on a nonblocking netconn -> cannot linger */
00889           err = ERR_WOULDBLOCK;
00890         } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >=
00891           (conn->linger * 1000)) {
00892           /* data left but linger timeout has expired (this happens on further
00893              calls to this function through poll_tcp */
00894           tcp_abort(tpcb);
00895           tpcb = NULL;
00896         } else {
00897           /* data left -> need to wait for ACK after successful close */
00898           linger_wait_required = 1;
00899         }
00900       }
00901     }
00902     if ((err == ERR_OK) && (tpcb != NULL))
00903 #endif /* LWIP_SO_LINGER */
00904     {
00905       err = tcp_close(tpcb);
00906     }
00907   } else {
00908     err = tcp_shutdown(tpcb, shut_rx, shut_tx);
00909   }
00910   if (err == ERR_OK) {
00911     close_finished = 1;
00912 #if LWIP_SO_LINGER
00913     if (linger_wait_required) {
00914       /* wait for ACK of all unsent/unacked data by just getting called again */
00915       close_finished = 0;
00916       err = ERR_INPROGRESS;
00917     }
00918 #endif /* LWIP_SO_LINGER */
00919   } else {
00920     if (err == ERR_MEM) {
00921       /* Closing failed because of memory shortage, try again later. Even for
00922          nonblocking netconns, we have to wait since no standard socket application
00923          is prepared for close failing because of resource shortage.
00924          Check the timeout: this is kind of an lwip addition to the standard sockets:
00925          we wait for some time when failing to allocate a segment for the FIN */
00926 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
00927       s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
00928 #if LWIP_SO_SNDTIMEO
00929       if (conn->send_timeout > 0) {
00930         close_timeout = conn->send_timeout;
00931       }
00932 #endif /* LWIP_SO_SNDTIMEO */
00933 #if LWIP_SO_LINGER
00934       if (conn->linger >= 0) {
00935         /* use linger timeout (seconds) */
00936         close_timeout = conn->linger * 1000U;
00937       }
00938 #endif
00939       if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
00940 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
00941       if (conn->current_msg->msg.sd.polls_left == 0) {
00942 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
00943         close_finished = 1;
00944         if (close) {
00945           /* in this case, we want to RST the connection */
00946           tcp_abort(tpcb);
00947           err = ERR_OK;
00948         }
00949       }
00950     } else {
00951       /* Closing failed for a non-memory error: give up */
00952       close_finished = 1;
00953     }
00954   }
00955   if (close_finished) {
00956     /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */
00957     sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
00958     conn->current_msg->err = err;
00959     conn->current_msg = NULL;
00960     conn->state = NETCONN_NONE;
00961     if (err == ERR_OK) {
00962       if (close) {
00963         /* Set back some callback pointers as conn is going away */
00964         conn->pcb.tcp = NULL;
00965         /* Trigger select() in socket layer. Make sure everybody notices activity
00966          on the connection, error first! */
00967         API_EVENT(conn, NETCONN_EVT_ERROR, 0);
00968       }
00969       if (shut_rx) {
00970         API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
00971       }
00972       if (shut_tx) {
00973         API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
00974       }
00975     }
00976     NETCONN_SET_SAFE_ERR(conn, err);
00977 #if LWIP_TCPIP_CORE_LOCKING
00978     if (delayed)
00979 #endif
00980     {
00981       /* wake up the application task */
00982       sys_sem_signal(op_completed_sem);
00983     }
00984     return ERR_OK;
00985   }
00986   if (!close_finished) {
00987     /* Closing failed and we want to wait: restore some of the callbacks */
00988     /* Closing of listen pcb will never fail! */
00989     LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN));
00990     if (shut_tx) {
00991       tcp_sent(tpcb, sent_tcp);
00992     }
00993     /* when waiting for close, set up poll interval to 500ms */
00994     tcp_poll(tpcb, poll_tcp, 1);
00995     tcp_err(tpcb, err_tcp);
00996     tcp_arg(tpcb, conn);
00997     /* don't restore recv callback: we don't want to receive any more data */
00998   }
00999   /* If closing didn't succeed, we get called again either
01000      from poll_tcp or from sent_tcp */
01001   LWIP_ASSERT("err != ERR_OK", err != ERR_OK);
01002   return err;
01003 }
01004 #endif /* LWIP_TCP */
01005 
01006 /**
01007  * Delete the pcb inside a netconn.
01008  * Called from netconn_delete.
01009  *
01010  * @param m the api_msg_msg pointing to the connection
01011  */
01012 void
01013 lwip_netconn_do_delconn(void *m)
01014 {
01015   struct api_msg *msg = (struct api_msg*)m;
01016 
01017   enum netconn_state state = msg->conn->state;
01018   LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */
01019     (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP));
01020 #if LWIP_NETCONN_FULLDUPLEX
01021   /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */
01022   if (state != NETCONN_NONE) {
01023     if ((state == NETCONN_WRITE) ||
01024         ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
01025       /* close requested, abort running write/connect */
01026       sys_sem_t* op_completed_sem;
01027       LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
01028       op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
01029       msg->conn->current_msg->err = ERR_CLSD;
01030       msg->conn->current_msg = NULL;
01031       msg->conn->write_offset = 0;
01032       msg->conn->state = NETCONN_NONE;
01033       NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
01034       sys_sem_signal(op_completed_sem);
01035     }
01036   }
01037 #else /* LWIP_NETCONN_FULLDUPLEX */
01038   if (((state != NETCONN_NONE) &&
01039        (state != NETCONN_LISTEN) &&
01040        (state != NETCONN_CONNECT)) ||
01041       ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
01042     /* This means either a blocking write or blocking connect is running
01043        (nonblocking write returns and sets state to NONE) */
01044     msg->err = ERR_INPROGRESS;
01045   } else
01046 #endif /* LWIP_NETCONN_FULLDUPLEX */
01047   {
01048     LWIP_ASSERT("blocking connect in progress",
01049       (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
01050     msg->err = ERR_OK;
01051     /* Drain and delete mboxes */
01052     netconn_drain(msg->conn);
01053 
01054     if (msg->conn->pcb.tcp != NULL) {
01055 
01056       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01057 #if LWIP_RAW
01058       case NETCONN_RAW:
01059         raw_remove(msg->conn->pcb.raw);
01060         break;
01061 #endif /* LWIP_RAW */
01062 #if LWIP_UDP
01063       case NETCONN_UDP:
01064         msg->conn->pcb.udp->recv_arg = NULL;
01065         udp_remove(msg->conn->pcb.udp);
01066         break;
01067 #endif /* LWIP_UDP */
01068 #if LWIP_TCP
01069       case NETCONN_TCP:
01070         LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
01071           msg->conn->write_offset == 0);
01072         msg->conn->state = NETCONN_CLOSE;
01073         msg->msg.sd.shut = NETCONN_SHUT_RDWR;
01074         msg->conn->current_msg = msg;
01075 #if LWIP_TCPIP_CORE_LOCKING
01076         if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
01077           LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
01078           UNLOCK_TCPIP_CORE();
01079           sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
01080           LOCK_TCPIP_CORE();
01081           LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
01082         }
01083 #else /* LWIP_TCPIP_CORE_LOCKING */
01084         lwip_netconn_do_close_internal(msg->conn);
01085 #endif /* LWIP_TCPIP_CORE_LOCKING */
01086         /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing
01087            the application thread, so we can return at this point! */
01088         return;
01089 #endif /* LWIP_TCP */
01090       default:
01091         break;
01092       }
01093       msg->conn->pcb.tcp = NULL;
01094     }
01095     /* tcp netconns don't come here! */
01096 
01097     /* @todo: this lets select make the socket readable and writable,
01098        which is wrong! errfd instead? */
01099     API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
01100     API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
01101   }
01102   if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) {
01103     TCPIP_APIMSG_ACK(msg);
01104   }
01105 }
01106 
01107 /**
01108  * Bind a pcb contained in a netconn
01109  * Called from netconn_bind.
01110  *
01111  * @param m the api_msg_msg pointing to the connection and containing
01112  *          the IP address and port to bind to
01113  */
01114 void
01115 lwip_netconn_do_bind(void *m)
01116 {
01117   struct api_msg *msg = (struct api_msg*)m;
01118 
01119   if (ERR_IS_FATAL(msg->conn->last_err)) {
01120     msg->err = msg->conn->last_err;
01121   } else {
01122     msg->err = ERR_VAL;
01123     if (msg->conn->pcb.tcp != NULL) {
01124       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01125 #if LWIP_RAW
01126       case NETCONN_RAW:
01127         msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
01128         break;
01129 #endif /* LWIP_RAW */
01130 #if LWIP_UDP
01131       case NETCONN_UDP:
01132         msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
01133         break;
01134 #endif /* LWIP_UDP */
01135 #if LWIP_TCP
01136       case NETCONN_TCP:
01137         msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
01138         break;
01139 #endif /* LWIP_TCP */
01140       default:
01141         break;
01142       }
01143     }
01144   }
01145   TCPIP_APIMSG_ACK(msg);
01146 }
01147 
01148 #if LWIP_TCP
01149 /**
01150  * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has
01151  * been established (or reset by the remote host).
01152  *
01153  * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
01154  */
01155 static err_t
01156 lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
01157 {
01158   struct netconn *conn;
01159   int was_blocking;
01160   sys_sem_t* op_completed_sem = NULL;
01161 
01162   LWIP_UNUSED_ARG(pcb);
01163 
01164   conn = (struct netconn *)arg;
01165 
01166   if (conn == NULL) {
01167     return ERR_VAL;
01168   }
01169 
01170   LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
01171   LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
01172     (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
01173 
01174   if (conn->current_msg != NULL) {
01175     conn->current_msg->err = err;
01176     op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
01177   }
01178   if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
01179     setup_tcp(conn);
01180   }
01181   was_blocking = !IN_NONBLOCKING_CONNECT(conn);
01182   SET_NONBLOCKING_CONNECT(conn, 0);
01183   LWIP_ASSERT("blocking connect state error",
01184     (was_blocking && op_completed_sem != NULL) ||
01185     (!was_blocking && op_completed_sem == NULL));
01186   conn->current_msg = NULL;
01187   conn->state = NETCONN_NONE;
01188   NETCONN_SET_SAFE_ERR(conn, ERR_OK);
01189   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
01190 
01191   if (was_blocking) {
01192     sys_sem_signal(op_completed_sem);
01193   }
01194   return ERR_OK;
01195 }
01196 #endif /* LWIP_TCP */
01197 
01198 /**
01199  * Connect a pcb contained inside a netconn
01200  * Called from netconn_connect.
01201  *
01202  * @param m the api_msg_msg pointing to the connection and containing
01203  *          the IP address and port to connect to
01204  */
01205 void
01206 lwip_netconn_do_connect(void *m)
01207 {
01208   struct api_msg *msg = (struct api_msg*)m;
01209 
01210   if (msg->conn->pcb.tcp == NULL) {
01211     /* This may happen when calling netconn_connect() a second time */
01212     msg->err = ERR_CLSD;
01213   } else {
01214     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01215 #if LWIP_RAW
01216     case NETCONN_RAW:
01217       msg->err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
01218       break;
01219 #endif /* LWIP_RAW */
01220 #if LWIP_UDP
01221     case NETCONN_UDP:
01222       msg->err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
01223       break;
01224 #endif /* LWIP_UDP */
01225 #if LWIP_TCP
01226     case NETCONN_TCP:
01227       /* Prevent connect while doing any other action. */
01228       if (msg->conn->state == NETCONN_CONNECT) {
01229         msg->err = ERR_ALREADY;
01230       } else if (msg->conn->state != NETCONN_NONE) {
01231         msg->err = ERR_ISCONN;
01232       } else {
01233         setup_tcp(msg->conn);
01234         msg->err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr),
01235           msg->msg.bc.port, lwip_netconn_do_connected);
01236         if (msg->err == ERR_OK) {
01237           u8_t non_blocking = netconn_is_nonblocking(msg->conn);
01238           msg->conn->state = NETCONN_CONNECT;
01239           SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
01240           if (non_blocking) {
01241             msg->err = ERR_INPROGRESS;
01242           } else {
01243             msg->conn->current_msg = msg;
01244             /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()),
01245                when the connection is established! */
01246 #if LWIP_TCPIP_CORE_LOCKING
01247             LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT);
01248             UNLOCK_TCPIP_CORE();
01249             sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
01250             LOCK_TCPIP_CORE();
01251             LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT);
01252 #endif /* LWIP_TCPIP_CORE_LOCKING */
01253             return;
01254           }
01255         }
01256       }
01257       break;
01258 #endif /* LWIP_TCP */
01259     default:
01260       LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
01261       break;
01262     }
01263   }
01264   /* For all other protocols, netconn_connect() calls TCPIP_APIMSG(),
01265      so use TCPIP_APIMSG_ACK() here. */
01266   TCPIP_APIMSG_ACK(msg);
01267 }
01268 
01269 /**
01270  * Disconnect a pcb contained inside a netconn
01271  * Only used for UDP netconns.
01272  * Called from netconn_disconnect.
01273  *
01274  * @param m the api_msg_msg pointing to the connection to disconnect
01275  */
01276 void
01277 lwip_netconn_do_disconnect(void *m)
01278 {
01279   struct api_msg *msg = (struct api_msg*)m;
01280 
01281 #if LWIP_UDP
01282   if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
01283     udp_disconnect(msg->conn->pcb.udp);
01284     msg->err = ERR_OK;
01285   } else
01286 #endif /* LWIP_UDP */
01287   {
01288     msg->err = ERR_VAL;
01289   }
01290   TCPIP_APIMSG_ACK(msg);
01291 }
01292 
01293 #if LWIP_TCP
01294 /**
01295  * Set a TCP pcb contained in a netconn into listen mode
01296  * Called from netconn_listen.
01297  *
01298  * @param m the api_msg_msg pointing to the connection
01299  */
01300 void
01301 lwip_netconn_do_listen(void *m)
01302 {
01303   struct api_msg *msg = (struct api_msg*)m;
01304 
01305   if (ERR_IS_FATAL(msg->conn->last_err)) {
01306     msg->err = msg->conn->last_err;
01307   } else {
01308     msg->err = ERR_CONN;
01309     if (msg->conn->pcb.tcp != NULL) {
01310       if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
01311         if (msg->conn->state == NETCONN_NONE) {
01312           struct tcp_pcb* lpcb;
01313           if (msg->conn->pcb.tcp->state != CLOSED) {
01314             /* connection is not closed, cannot listen */
01315             msg->err = ERR_VAL;
01316           } else {
01317             err_t err;
01318             u8_t backlog;
01319 #if TCP_LISTEN_BACKLOG
01320             backlog = msg->msg.lb.backlog;
01321 #else  /* TCP_LISTEN_BACKLOG */
01322             backlog = TCP_DEFAULT_LISTEN_BACKLOG;
01323 #endif /* TCP_LISTEN_BACKLOG */
01324 #if LWIP_IPV4 && LWIP_IPV6
01325             /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
01326              * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
01327              */
01328             if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) &&
01329                 (netconn_get_ipv6only(msg->conn) == 0)) {
01330               /* change PCB type to IPADDR_TYPE_ANY */
01331               IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip,  IPADDR_TYPE_ANY);
01332               IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY);
01333             }
01334 #endif /* LWIP_IPV4 && LWIP_IPV6 */
01335 
01336             lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
01337 
01338             if (lpcb == NULL) {
01339               /* in this case, the old pcb is still allocated */
01340               msg->err = err;
01341             } else {
01342               /* delete the recvmbox and allocate the acceptmbox */
01343               if (sys_mbox_valid(&msg->conn->recvmbox)) {
01344                 /** @todo: should we drain the recvmbox here? */
01345                 sys_mbox_free(&msg->conn->recvmbox);
01346                 sys_mbox_set_invalid(&msg->conn->recvmbox);
01347               }
01348               msg->err = ERR_OK;
01349               if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
01350                 msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
01351               }
01352               if (msg->err == ERR_OK) {
01353                 msg->conn->state = NETCONN_LISTEN;
01354                 msg->conn->pcb.tcp = lpcb;
01355                 tcp_arg(msg->conn->pcb.tcp, msg->conn);
01356                 tcp_accept(msg->conn->pcb.tcp, accept_function);
01357               } else {
01358                 /* since the old pcb is already deallocated, free lpcb now */
01359                 tcp_close(lpcb);
01360                 msg->conn->pcb.tcp = NULL;
01361               }
01362             }
01363           }
01364         } else if (msg->conn->state == NETCONN_LISTEN) {
01365           /* already listening, allow updating of the backlog */
01366           msg->err = ERR_OK;
01367           tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog);
01368         }
01369       } else {
01370         msg->err = ERR_ARG;
01371       }
01372     }
01373   }
01374   TCPIP_APIMSG_ACK(msg);
01375 }
01376 #endif /* LWIP_TCP */
01377 
01378 /**
01379  * Send some data on a RAW or UDP pcb contained in a netconn
01380  * Called from netconn_send
01381  *
01382  * @param m the api_msg_msg pointing to the connection
01383  */
01384 void
01385 lwip_netconn_do_send(void *m)
01386 {
01387   struct api_msg *msg = (struct api_msg*)m;
01388 
01389   if (ERR_IS_FATAL(msg->conn->last_err)) {
01390     msg->err = msg->conn->last_err;
01391   } else {
01392     msg->err = ERR_CONN;
01393     if (msg->conn->pcb.tcp != NULL) {
01394       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01395 #if LWIP_RAW
01396       case NETCONN_RAW:
01397         if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
01398           msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
01399         } else {
01400           msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
01401         }
01402         break;
01403 #endif
01404 #if LWIP_UDP
01405       case NETCONN_UDP:
01406 #if LWIP_CHECKSUM_ON_COPY
01407         if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
01408           msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
01409             msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
01410         } else {
01411           msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
01412             &msg->msg.b->addr, msg->msg.b->port,
01413             msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
01414         }
01415 #else /* LWIP_CHECKSUM_ON_COPY */
01416         if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
01417           msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
01418         } else {
01419           msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
01420         }
01421 #endif /* LWIP_CHECKSUM_ON_COPY */
01422         break;
01423 #endif /* LWIP_UDP */
01424       default:
01425         break;
01426       }
01427     }
01428   }
01429   TCPIP_APIMSG_ACK(msg);
01430 }
01431 
01432 #if LWIP_TCP
01433 /**
01434  * Indicate data has been received from a TCP pcb contained in a netconn
01435  * Called from netconn_recv
01436  *
01437  * @param m the api_msg_msg pointing to the connection
01438  */
01439 void
01440 lwip_netconn_do_recv(void *m)
01441 {
01442   struct api_msg *msg = (struct api_msg*)m;
01443 
01444   msg->err = ERR_OK;
01445   if (msg->conn->pcb.tcp != NULL) {
01446     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
01447       u32_t remaining = msg->msg.r.len;
01448       do {
01449         u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
01450         tcp_recved(msg->conn->pcb.tcp, recved);
01451         remaining -= recved;
01452       } while (remaining != 0);
01453     }
01454   }
01455   TCPIP_APIMSG_ACK(msg);
01456 }
01457 
01458 #if TCP_LISTEN_BACKLOG
01459 /** Indicate that a TCP pcb has been accepted
01460  * Called from netconn_accept
01461  *
01462  * @param m the api_msg_msg pointing to the connection
01463  */
01464 void
01465 lwip_netconn_do_accepted(void *m)
01466 {
01467   struct api_msg *msg = (struct api_msg*)m;
01468 
01469   msg->err = ERR_OK;
01470   if (msg->conn->pcb.tcp != NULL) {
01471     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
01472       tcp_backlog_accepted(msg->conn->pcb.tcp);
01473     }
01474   }
01475   TCPIP_APIMSG_ACK(msg);
01476 }
01477 #endif /* TCP_LISTEN_BACKLOG */
01478 
01479 /**
01480  * See if more data needs to be written from a previous call to netconn_write.
01481  * Called initially from lwip_netconn_do_write. If the first call can't send all data
01482  * (because of low memory or empty send-buffer), this function is called again
01483  * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
01484  * blocking application thread (waiting in netconn_write) is released.
01485  *
01486  * @param conn netconn (that is currently in state NETCONN_WRITE) to process
01487  * @return ERR_OK
01488  *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
01489  */
01490 static err_t
01491 lwip_netconn_do_writemore(struct netconn *conn  WRITE_DELAYED_PARAM)
01492 {
01493   err_t err;
01494   const void *dataptr;
01495   u16_t len, available;
01496   u8_t write_finished = 0;
01497   size_t diff;
01498   u8_t dontblock;
01499   u8_t apiflags;
01500 
01501   LWIP_ASSERT("conn != NULL", conn != NULL);
01502   LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
01503   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
01504   LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
01505   LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
01506     conn->write_offset < conn->current_msg->msg.w.len);
01507 
01508   apiflags = conn->current_msg->msg.w.apiflags;
01509   dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
01510 
01511 #if LWIP_SO_SNDTIMEO
01512   if ((conn->send_timeout != 0) &&
01513       ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
01514     write_finished = 1;
01515     if (conn->write_offset == 0) {
01516       /* nothing has been written */
01517       err = ERR_WOULDBLOCK;
01518       conn->current_msg->msg.w.len = 0;
01519     } else {
01520       /* partial write */
01521       err = ERR_OK;
01522       conn->current_msg->msg.w.len = conn->write_offset;
01523       conn->write_offset = 0;
01524     }
01525   } else
01526 #endif /* LWIP_SO_SNDTIMEO */
01527   {
01528     dataptr = (const u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
01529     diff = conn->current_msg->msg.w.len - conn->write_offset;
01530     if (diff > 0xffffUL) { /* max_u16_t */
01531       len = 0xffff;
01532       apiflags |= TCP_WRITE_FLAG_MORE;
01533     } else {
01534       len = (u16_t)diff;
01535     }
01536     available = tcp_sndbuf(conn->pcb.tcp);
01537     if (available < len) {
01538       /* don't try to write more than sendbuf */
01539       len = available;
01540       if (dontblock) {
01541         if (!len) {
01542           err = ERR_WOULDBLOCK;
01543           goto err_mem;
01544         }
01545       } else {
01546         apiflags |= TCP_WRITE_FLAG_MORE;
01547       }
01548     }
01549     LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
01550     err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
01551     /* if OK or memory error, check available space */
01552     if ((err == ERR_OK) || (err == ERR_MEM)) {
01553 err_mem:
01554       if (dontblock && (len < conn->current_msg->msg.w.len)) {
01555         /* non-blocking write did not write everything: mark the pcb non-writable
01556            and let poll_tcp check writable space to mark the pcb writable again */
01557         API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
01558         conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
01559       } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
01560                  (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
01561         /* The queued byte- or pbuf-count exceeds the configured low-water limit,
01562            let select mark this pcb as non-writable. */
01563         API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
01564       }
01565     }
01566 
01567     if (err == ERR_OK) {
01568       err_t out_err;
01569       conn->write_offset += len;
01570       if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) {
01571         /* return sent length */
01572         conn->current_msg->msg.w.len = conn->write_offset;
01573         /* everything was written */
01574         write_finished = 1;
01575       }
01576       out_err = tcp_output(conn->pcb.tcp);
01577       if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) {
01578         /* If tcp_output fails with fatal error or no route is found,
01579            don't try writing any more but return the error
01580            to the application thread. */
01581         err = out_err;
01582         write_finished = 1;
01583         conn->current_msg->msg.w.len = 0;
01584       }
01585     } else if (err == ERR_MEM) {
01586       /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called.
01587          For blocking sockets, we do NOT return to the application
01588          thread, since ERR_MEM is only a temporary error! Non-blocking
01589          will remain non-writable until sent_tcp/poll_tcp is called */
01590 
01591       /* tcp_write returned ERR_MEM, try tcp_output anyway */
01592       err_t out_err = tcp_output(conn->pcb.tcp);
01593       if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) {
01594         /* If tcp_output fails with fatal error or no route is found,
01595            don't try writing any more but return the error
01596            to the application thread. */
01597         err = out_err;
01598         write_finished = 1;
01599         conn->current_msg->msg.w.len = 0;
01600       } else if (dontblock) {
01601         /* non-blocking write is done on ERR_MEM */
01602         err = ERR_WOULDBLOCK;
01603         write_finished = 1;
01604         conn->current_msg->msg.w.len = 0;
01605       }
01606     } else {
01607       /* On errors != ERR_MEM, we don't try writing any more but return
01608          the error to the application thread. */
01609       write_finished = 1;
01610       conn->current_msg->msg.w.len = 0;
01611     }
01612   }
01613   if (write_finished) {
01614     /* everything was written: set back connection state
01615        and back to application task */
01616     sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
01617     conn->current_msg->err = err;
01618     conn->current_msg = NULL;
01619     conn->write_offset = 0;
01620     conn->state = NETCONN_NONE;
01621     NETCONN_SET_SAFE_ERR(conn, err);
01622 #if LWIP_TCPIP_CORE_LOCKING
01623     if (delayed)
01624 #endif
01625     {
01626       sys_sem_signal(op_completed_sem);
01627     }
01628   }
01629 #if LWIP_TCPIP_CORE_LOCKING
01630   else {
01631     return ERR_MEM;
01632   }
01633 #endif
01634   return ERR_OK;
01635 }
01636 #endif /* LWIP_TCP */
01637 
01638 /**
01639  * Send some data on a TCP pcb contained in a netconn
01640  * Called from netconn_write
01641  *
01642  * @param m the api_msg_msg pointing to the connection
01643  */
01644 void
01645 lwip_netconn_do_write(void *m)
01646 {
01647   struct api_msg *msg = (struct api_msg*)m;
01648 
01649   if (ERR_IS_FATAL(msg->conn->last_err)) {
01650     msg->err = msg->conn->last_err;
01651   } else {
01652     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
01653 #if LWIP_TCP
01654       if (msg->conn->state != NETCONN_NONE) {
01655         /* netconn is connecting, closing or in blocking write */
01656         msg->err = ERR_INPROGRESS;
01657       } else if (msg->conn->pcb.tcp != NULL) {
01658         msg->conn->state = NETCONN_WRITE;
01659         /* set all the variables used by lwip_netconn_do_writemore */
01660         LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
01661           msg->conn->write_offset == 0);
01662         LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
01663         msg->conn->current_msg = msg;
01664         msg->conn->write_offset = 0;
01665 #if LWIP_TCPIP_CORE_LOCKING
01666         if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) {
01667           LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
01668           UNLOCK_TCPIP_CORE();
01669           sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
01670           LOCK_TCPIP_CORE();
01671           LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE);
01672         }
01673 #else /* LWIP_TCPIP_CORE_LOCKING */
01674         lwip_netconn_do_writemore(msg->conn);
01675 #endif /* LWIP_TCPIP_CORE_LOCKING */
01676         /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG
01677            since lwip_netconn_do_writemore ACKs it! */
01678         return;
01679       } else {
01680         msg->err = ERR_CONN;
01681       }
01682 #else /* LWIP_TCP */
01683       msg->err = ERR_VAL;
01684 #endif /* LWIP_TCP */
01685 #if (LWIP_UDP || LWIP_RAW)
01686     } else {
01687       msg->err = ERR_VAL;
01688 #endif /* (LWIP_UDP || LWIP_RAW) */
01689     }
01690   }
01691   TCPIP_APIMSG_ACK(msg);
01692 }
01693 
01694 /**
01695  * Return a connection's local or remote address
01696  * Called from netconn_getaddr
01697  *
01698  * @param m the api_msg_msg pointing to the connection
01699  */
01700 void
01701 lwip_netconn_do_getaddr(void *m)
01702 {
01703   struct api_msg *msg = (struct api_msg*)m;
01704 
01705   if (msg->conn->pcb.ip != NULL) {
01706     if (msg->msg.ad.local) {
01707       ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
01708         msg->conn->pcb.ip->local_ip);
01709     } else {
01710       ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
01711         msg->conn->pcb.ip->remote_ip);
01712     }
01713 
01714     msg->err = ERR_OK;
01715     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01716 #if LWIP_RAW
01717     case NETCONN_RAW:
01718       if (msg->msg.ad.local) {
01719         API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
01720       } else {
01721         /* return an error as connecting is only a helper for upper layers */
01722         msg->err = ERR_CONN;
01723       }
01724       break;
01725 #endif /* LWIP_RAW */
01726 #if LWIP_UDP
01727     case NETCONN_UDP:
01728       if (msg->msg.ad.local) {
01729         API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
01730       } else {
01731         if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
01732           msg->err = ERR_CONN;
01733         } else {
01734           API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
01735         }
01736       }
01737       break;
01738 #endif /* LWIP_UDP */
01739 #if LWIP_TCP
01740     case NETCONN_TCP:
01741       if ((msg->msg.ad.local == 0) &&
01742           ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) {
01743         /* pcb is not connected and remote name is requested */
01744         msg->err = ERR_CONN;
01745       } else {
01746         API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port);
01747       }
01748       break;
01749 #endif /* LWIP_TCP */
01750     default:
01751       LWIP_ASSERT("invalid netconn_type", 0);
01752       break;
01753     }
01754   } else {
01755     msg->err = ERR_CONN;
01756   }
01757   TCPIP_APIMSG_ACK(msg);
01758 }
01759 
01760 /**
01761  * Close or half-shutdown a TCP pcb contained in a netconn
01762  * Called from netconn_close
01763  * In contrast to closing sockets, the netconn is not deallocated.
01764  *
01765  * @param m the api_msg_msg pointing to the connection
01766  */
01767 void
01768 lwip_netconn_do_close(void *m)
01769 {
01770   struct api_msg *msg = (struct api_msg*)m;
01771 
01772 #if LWIP_TCP
01773   enum netconn_state state = msg->conn->state;
01774   /* First check if this is a TCP netconn and if it is in a correct state
01775       (LISTEN doesn't support half shutdown) */
01776   if ((msg->conn->pcb.tcp != NULL) &&
01777       (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) &&
01778       ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) {
01779     /* Check if we are in a connected state */
01780     if (state == NETCONN_CONNECT) {
01781       /* TCP connect in progress: cannot shutdown */
01782       msg->err = ERR_CONN;
01783     } else if (state == NETCONN_WRITE) {
01784 #if LWIP_NETCONN_FULLDUPLEX
01785       if (msg->msg.sd.shut & NETCONN_SHUT_WR) {
01786         /* close requested, abort running write */
01787         sys_sem_t* write_completed_sem;
01788         LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
01789         write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
01790         msg->conn->current_msg->err = ERR_CLSD;
01791         msg->conn->current_msg = NULL;
01792         msg->conn->write_offset = 0;
01793         msg->conn->state = NETCONN_NONE;
01794         state = NETCONN_NONE;
01795         NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
01796         sys_sem_signal(write_completed_sem);
01797       } else {
01798         LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD);
01799         /* In this case, let the write continue and do not interfere with
01800            conn->current_msg or conn->state! */
01801         msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0);
01802       }
01803     }
01804     if (state == NETCONN_NONE) {
01805 #else /* LWIP_NETCONN_FULLDUPLEX */
01806       msg->err = ERR_INPROGRESS;
01807     } else {
01808 #endif /* LWIP_NETCONN_FULLDUPLEX */
01809       if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
01810         /* Drain and delete mboxes */
01811         netconn_drain(msg->conn);
01812       }
01813       LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
01814         msg->conn->write_offset == 0);
01815       msg->conn->state = NETCONN_CLOSE;
01816       msg->conn->current_msg = msg;
01817 #if LWIP_TCPIP_CORE_LOCKING
01818       if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
01819         LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
01820         UNLOCK_TCPIP_CORE();
01821         sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
01822         LOCK_TCPIP_CORE();
01823         LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
01824       }
01825 #else /* LWIP_TCPIP_CORE_LOCKING */
01826       lwip_netconn_do_close_internal(msg->conn);
01827 #endif /* LWIP_TCPIP_CORE_LOCKING */
01828       /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */
01829       return;
01830     }
01831   } else
01832 #endif /* LWIP_TCP */
01833   {
01834     msg->err = ERR_CONN;
01835   }
01836   TCPIP_APIMSG_ACK(msg);
01837 }
01838 
01839 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
01840 /**
01841  * Join multicast groups for UDP netconns.
01842  * Called from netconn_join_leave_group
01843  *
01844  * @param m the api_msg_msg pointing to the connection
01845  */
01846 void
01847 lwip_netconn_do_join_leave_group(void *m)
01848 {
01849   struct api_msg *msg = (struct api_msg*)m;
01850 
01851   if (ERR_IS_FATAL(msg->conn->last_err)) {
01852     msg->err = msg->conn->last_err;
01853   } else {
01854     if (msg->conn->pcb.tcp != NULL) {
01855       if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
01856 #if LWIP_UDP
01857 #if LWIP_IPV6 && LWIP_IPV6_MLD
01858         if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
01859           if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
01860             msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
01861               ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
01862           } else {
01863             msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
01864               ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
01865           }
01866         }
01867         else
01868 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
01869         {
01870 #if LWIP_IGMP
01871           if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
01872             msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
01873               ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
01874           } else {
01875             msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
01876               ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
01877           }
01878 #endif /* LWIP_IGMP */
01879         }
01880 #endif /* LWIP_UDP */
01881 #if (LWIP_TCP || LWIP_RAW)
01882       } else {
01883         msg->err = ERR_VAL;
01884 #endif /* (LWIP_TCP || LWIP_RAW) */
01885       }
01886     } else {
01887       msg->err = ERR_CONN;
01888     }
01889   }
01890   TCPIP_APIMSG_ACK(msg);
01891 }
01892 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
01893 
01894 #if LWIP_DNS
01895 /**
01896  * Callback function that is called when DNS name is resolved
01897  * (or on timeout). A waiting application thread is waked up by
01898  * signaling the semaphore.
01899  */
01900 static void
01901 lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg)
01902 {
01903   struct dns_api_msg *msg = (struct dns_api_msg*)arg;
01904 
01905   /* we trust the internal implementation to be correct :-) */
01906   LWIP_UNUSED_ARG(name);
01907 
01908   if (ipaddr == NULL) {
01909     /* timeout or memory error */
01910     API_EXPR_DEREF(msg->err) = ERR_VAL;
01911   } else {
01912     /* address was resolved */
01913     API_EXPR_DEREF(msg->err) = ERR_OK;
01914     API_EXPR_DEREF(msg->addr) = *ipaddr;
01915   }
01916   /* wake up the application task waiting in netconn_gethostbyname */
01917   sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
01918 }
01919 
01920 /**
01921  * Execute a DNS query
01922  * Called from netconn_gethostbyname
01923  *
01924  * @param arg the dns_api_msg pointing to the query
01925  */
01926 void
01927 lwip_netconn_do_gethostbyname(void *arg)
01928 {
01929   struct dns_api_msg *msg = (struct dns_api_msg*)arg;
01930   u8_t addrtype =
01931 #if LWIP_IPV4 && LWIP_IPV6
01932     msg->dns_addrtype;
01933 #else
01934     LWIP_DNS_ADDRTYPE_DEFAULT;
01935 #endif
01936 
01937   API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name,
01938     API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype);
01939   if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) {
01940     /* on error or immediate success, wake up the application
01941      * task waiting in netconn_gethostbyname */
01942     sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
01943   }
01944 }
01945 #endif /* LWIP_DNS */
01946 
01947 #endif /* LWIP_NETCONN */