Daiki Kato / mbed-os-lychee

Dependents:   mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more

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       raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
00566     }
00567     break;
00568 #endif /* LWIP_RAW */
00569 #if LWIP_UDP
00570   case NETCONN_UDP:
00571     msg->conn->pcb.udp = udp_new_ip_type(iptype);
00572     if (msg->conn->pcb.udp != NULL) {
00573 #if LWIP_UDPLITE
00574       if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
00575         udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
00576       }
00577 #endif /* LWIP_UDPLITE */
00578       if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) {
00579         udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
00580       }
00581       udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
00582     }
00583     break;
00584 #endif /* LWIP_UDP */
00585 #if LWIP_TCP
00586   case NETCONN_TCP:
00587     msg->conn->pcb.tcp = tcp_new_ip_type(iptype);
00588     if (msg->conn->pcb.tcp != NULL) {
00589       setup_tcp(msg->conn);
00590     }
00591     break;
00592 #endif /* LWIP_TCP */
00593   default:
00594     /* Unsupported netconn type, e.g. protocol disabled */
00595     msg->err = ERR_VAL;
00596     return;
00597   }
00598   if (msg->conn->pcb.ip == NULL) {
00599     msg->err = ERR_MEM;
00600   }
00601 }
00602 
00603 /**
00604  * Create a new pcb of a specific type inside a netconn.
00605  * Called from netconn_new_with_proto_and_callback.
00606  *
00607  * @param m the api_msg_msg describing the connection type
00608  */
00609 void
00610 lwip_netconn_do_newconn(void *m)
00611 {
00612   struct api_msg *msg = (struct api_msg*)m;
00613 
00614   msg->err = ERR_OK;
00615   if (msg->conn->pcb.tcp == NULL) {
00616     pcb_new(msg);
00617   }
00618   /* Else? This "new" connection already has a PCB allocated. */
00619   /* Is this an error condition? Should it be deleted? */
00620   /* We currently just are happy and return. */
00621 
00622   TCPIP_APIMSG_ACK(msg);
00623 }
00624 
00625 /**
00626  * Create a new netconn (of a specific type) that has a callback function.
00627  * The corresponding pcb is NOT created!
00628  *
00629  * @param t the type of 'connection' to create (@see enum netconn_type)
00630  * @param callback a function to call on status changes (RX available, TX'ed)
00631  * @return a newly allocated struct netconn or
00632  *         NULL on memory error
00633  */
00634 struct netconn*
00635 netconn_alloc(enum netconn_type t, netconn_callback callback)
00636 {
00637   struct netconn *conn;
00638   int size;
00639 
00640   conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
00641   if (conn == NULL) {
00642     return NULL;
00643   }
00644 
00645   conn->last_err = ERR_OK;
00646   conn->type = t;
00647   conn->pcb.tcp = NULL;
00648 
00649   /* If all sizes are the same, every compiler should optimize this switch to nothing */
00650   switch(NETCONNTYPE_GROUP(t)) {
00651 #if LWIP_RAW
00652   case NETCONN_RAW:
00653     size = DEFAULT_RAW_RECVMBOX_SIZE;
00654     break;
00655 #endif /* LWIP_RAW */
00656 #if LWIP_UDP
00657   case NETCONN_UDP:
00658     size = DEFAULT_UDP_RECVMBOX_SIZE;
00659     break;
00660 #endif /* LWIP_UDP */
00661 #if LWIP_TCP
00662   case NETCONN_TCP:
00663     size = DEFAULT_TCP_RECVMBOX_SIZE;
00664     break;
00665 #endif /* LWIP_TCP */
00666   default:
00667     LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
00668     goto free_and_return;
00669   }
00670 
00671   if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
00672     goto free_and_return;
00673   }
00674 #if !LWIP_NETCONN_SEM_PER_THREAD
00675   if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
00676     sys_mbox_free(&conn->recvmbox);
00677     goto free_and_return;
00678   }
00679 #endif
00680 
00681 #if LWIP_TCP
00682   sys_mbox_set_invalid(&conn->acceptmbox);
00683 #endif
00684   conn->state        = NETCONN_NONE;
00685 #if LWIP_SOCKET
00686   /* initialize socket to -1 since 0 is a valid socket */
00687   conn->socket       = -1;
00688 #endif /* LWIP_SOCKET */
00689   conn->callback     = callback;
00690 #if LWIP_TCP
00691   conn->current_msg  = NULL;
00692   conn->write_offset = 0;
00693 #endif /* LWIP_TCP */
00694 #if LWIP_SO_SNDTIMEO
00695   conn->send_timeout = 0;
00696 #endif /* LWIP_SO_SNDTIMEO */
00697 #if LWIP_SO_RCVTIMEO
00698   conn->recv_timeout = 0;
00699 #endif /* LWIP_SO_RCVTIMEO */
00700 #if LWIP_SO_RCVBUF
00701   conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
00702   conn->recv_avail   = 0;
00703 #endif /* LWIP_SO_RCVBUF */
00704 #if LWIP_SO_LINGER
00705   conn->linger = -1;
00706 #endif /* LWIP_SO_LINGER */
00707   conn->flags = 0;
00708   return conn;
00709 free_and_return:
00710   memp_free(MEMP_NETCONN, conn);
00711   return NULL;
00712 }
00713 
00714 /**
00715  * Delete a netconn and all its resources.
00716  * The pcb is NOT freed (since we might not be in the right thread context do this).
00717  *
00718  * @param conn the netconn to free
00719  */
00720 void
00721 netconn_free(struct netconn *conn)
00722 {
00723   LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
00724   LWIP_ASSERT("recvmbox must be deallocated before calling this function",
00725     !sys_mbox_valid(&conn->recvmbox));
00726 #if LWIP_TCP
00727   LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
00728     !sys_mbox_valid(&conn->acceptmbox));
00729 #endif /* LWIP_TCP */
00730 
00731 #if !LWIP_NETCONN_SEM_PER_THREAD
00732   sys_sem_free(&conn->op_completed);
00733   sys_sem_set_invalid(&conn->op_completed);
00734 #endif
00735 
00736   memp_free(MEMP_NETCONN, conn);
00737 }
00738 
00739 /**
00740  * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
00741  * these mboxes
00742  *
00743  * @param conn the netconn to free
00744  * @bytes_drained bytes drained from recvmbox
00745  * @accepts_drained pending connections drained from acceptmbox
00746  */
00747 static void
00748 netconn_drain(struct netconn *conn)
00749 {
00750   void *mem;
00751 #if LWIP_TCP
00752   struct pbuf *p;
00753 #endif /* LWIP_TCP */
00754 
00755   /* This runs in tcpip_thread, so we don't need to lock against rx packets */
00756 
00757   /* Delete and drain the recvmbox. */
00758   if (sys_mbox_valid(&conn->recvmbox)) {
00759     while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
00760 #if LWIP_TCP
00761       if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
00762         if (mem != NULL) {
00763           p = (struct pbuf*)mem;
00764           /* pcb might be set to NULL already by err_tcp() */
00765           if (conn->pcb.tcp != NULL) {
00766             tcp_recved(conn->pcb.tcp, p->tot_len);
00767           }
00768           pbuf_free(p);
00769         }
00770       } else
00771 #endif /* LWIP_TCP */
00772       {
00773         netbuf_delete((struct netbuf *)mem);
00774       }
00775     }
00776     sys_mbox_free(&conn->recvmbox);
00777     sys_mbox_set_invalid(&conn->recvmbox);
00778   }
00779 
00780   /* Delete and drain the acceptmbox. */
00781 #if LWIP_TCP
00782   if (sys_mbox_valid(&conn->acceptmbox)) {
00783     while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
00784       if (mem != &netconn_aborted) {
00785         struct netconn *newconn = (struct netconn *)mem;
00786         /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
00787         /* pcb might be set to NULL already by err_tcp() */
00788         /* drain recvmbox */
00789         netconn_drain(newconn);
00790         if (newconn->pcb.tcp != NULL) {
00791           tcp_abort(newconn->pcb.tcp);
00792           newconn->pcb.tcp = NULL;
00793         }
00794         netconn_free(newconn);
00795       }
00796     }
00797     sys_mbox_free(&conn->acceptmbox);
00798     sys_mbox_set_invalid(&conn->acceptmbox);
00799   }
00800 #endif /* LWIP_TCP */
00801 }
00802 
00803 #if LWIP_TCP
00804 /**
00805  * Internal helper function to close a TCP netconn: since this sometimes
00806  * doesn't work at the first attempt, this function is called from multiple
00807  * places.
00808  *
00809  * @param conn the TCP netconn to close
00810  */
00811 static err_t
00812 lwip_netconn_do_close_internal(struct netconn *conn  WRITE_DELAYED_PARAM)
00813 {
00814   err_t err;
00815   u8_t shut, shut_rx, shut_tx, close;
00816   u8_t close_finished = 0;
00817   struct tcp_pcb* tpcb;
00818 #if LWIP_SO_LINGER
00819   u8_t linger_wait_required = 0;
00820 #endif /* LWIP_SO_LINGER */
00821 
00822   LWIP_ASSERT("invalid conn", (conn != NULL));
00823   LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
00824   LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
00825   LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
00826   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
00827 
00828   tpcb = conn->pcb.tcp;
00829   shut = conn->current_msg->msg.sd.shut;
00830   shut_rx = shut & NETCONN_SHUT_RD;
00831   shut_tx = shut & NETCONN_SHUT_WR;
00832   /* shutting down both ends is the same as closing
00833      (also if RD or WR side was shut down before already) */
00834   if (shut == NETCONN_SHUT_RDWR) {
00835     close = 1;
00836   } else if (shut_rx &&
00837              ((tpcb->state == FIN_WAIT_1) ||
00838               (tpcb->state == FIN_WAIT_2) ||
00839               (tpcb->state == CLOSING))) {
00840     close = 1;
00841   } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) {
00842     close = 1;
00843   } else {
00844     close = 0;
00845   }
00846 
00847   /* Set back some callback pointers */
00848   if (close) {
00849     tcp_arg(tpcb, NULL);
00850   }
00851   if (tpcb->state == LISTEN) {
00852     tcp_accept(tpcb, NULL);
00853   } else {
00854     /* some callbacks have to be reset if tcp_close is not successful */
00855     if (shut_rx) {
00856       tcp_recv(tpcb, NULL);
00857       tcp_accept(tpcb, NULL);
00858     }
00859     if (shut_tx) {
00860       tcp_sent(tpcb, NULL);
00861     }
00862     if (close) {
00863       tcp_poll(tpcb, NULL, 0);
00864       tcp_err(tpcb, NULL);
00865     }
00866   }
00867   /* Try to close the connection */
00868   if (close) {
00869 #if LWIP_SO_LINGER
00870     /* check linger possibilites before calling tcp_close */
00871     err = ERR_OK;
00872     /* linger enabled/required at all? (i.e. is there untransmitted data left?) */
00873     if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) {
00874       if ((conn->linger == 0)) {
00875         /* data left but linger prevents waiting */
00876         tcp_abort(tpcb);
00877         tpcb = NULL;
00878       } else if (conn->linger > 0) {
00879         /* data left and linger says we should wait */
00880         if (netconn_is_nonblocking(conn)) {
00881           /* data left on a nonblocking netconn -> cannot linger */
00882           err = ERR_WOULDBLOCK;
00883         } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >=
00884           (conn->linger * 1000)) {
00885           /* data left but linger timeout has expired (this happens on further
00886              calls to this function through poll_tcp */
00887           tcp_abort(tpcb);
00888           tpcb = NULL;
00889         } else {
00890           /* data left -> need to wait for ACK after successful close */
00891           linger_wait_required = 1;
00892         }
00893       }
00894     }
00895     if ((err == ERR_OK) && (tpcb != NULL))
00896 #endif /* LWIP_SO_LINGER */
00897     {
00898       err = tcp_close(tpcb);
00899     }
00900   } else {
00901     err = tcp_shutdown(tpcb, shut_rx, shut_tx);
00902   }
00903   if (err == ERR_OK) {
00904     close_finished = 1;
00905 #if LWIP_SO_LINGER
00906     if (linger_wait_required) {
00907       /* wait for ACK of all unsent/unacked data by just getting called again */
00908       close_finished = 0;
00909       err = ERR_INPROGRESS;
00910     }
00911 #endif /* LWIP_SO_LINGER */
00912   } else {
00913     if (err == ERR_MEM) {
00914       /* Closing failed because of memory shortage, try again later. Even for
00915          nonblocking netconns, we have to wait since no standard socket application
00916          is prepared for close failing because of resource shortage.
00917          Check the timeout: this is kind of an lwip addition to the standard sockets:
00918          we wait for some time when failing to allocate a segment for the FIN */
00919 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
00920       s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
00921 #if LWIP_SO_SNDTIMEO
00922       if (conn->send_timeout > 0) {
00923         close_timeout = conn->send_timeout;
00924       }
00925 #endif /* LWIP_SO_SNDTIMEO */
00926 #if LWIP_SO_LINGER
00927       if (conn->linger >= 0) {
00928         /* use linger timeout (seconds) */
00929         close_timeout = conn->linger * 1000U;
00930       }
00931 #endif
00932       if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
00933 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
00934       if (conn->current_msg->msg.sd.polls_left == 0) {
00935 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
00936         close_finished = 1;
00937         if (close) {
00938           /* in this case, we want to RST the connection */
00939           tcp_abort(tpcb);
00940           err = ERR_OK;
00941         }
00942       }
00943     } else {
00944       /* Closing failed for a non-memory error: give up */
00945       close_finished = 1;
00946     }
00947   }
00948   if (close_finished) {
00949     /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */
00950     sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
00951     conn->current_msg->err = err;
00952     conn->current_msg = NULL;
00953     conn->state = NETCONN_NONE;
00954     if (err == ERR_OK) {
00955       if (close) {
00956         /* Set back some callback pointers as conn is going away */
00957         conn->pcb.tcp = NULL;
00958         /* Trigger select() in socket layer. Make sure everybody notices activity
00959          on the connection, error first! */
00960         API_EVENT(conn, NETCONN_EVT_ERROR, 0);
00961       }
00962       if (shut_rx) {
00963         API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
00964       }
00965       if (shut_tx) {
00966         API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
00967       }
00968     }
00969     NETCONN_SET_SAFE_ERR(conn, err);
00970 #if LWIP_TCPIP_CORE_LOCKING
00971     if (delayed)
00972 #endif
00973     {
00974       /* wake up the application task */
00975       sys_sem_signal(op_completed_sem);
00976     }
00977     return ERR_OK;
00978   }
00979   if (!close_finished) {
00980     /* Closing failed and we want to wait: restore some of the callbacks */
00981     /* Closing of listen pcb will never fail! */
00982     LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN));
00983     if (shut_tx) {
00984       tcp_sent(tpcb, sent_tcp);
00985     }
00986     /* when waiting for close, set up poll interval to 500ms */
00987     tcp_poll(tpcb, poll_tcp, 1);
00988     tcp_err(tpcb, err_tcp);
00989     tcp_arg(tpcb, conn);
00990     /* don't restore recv callback: we don't want to receive any more data */
00991   }
00992   /* If closing didn't succeed, we get called again either
00993      from poll_tcp or from sent_tcp */
00994   LWIP_ASSERT("err != ERR_OK", err != ERR_OK);
00995   return err;
00996 }
00997 #endif /* LWIP_TCP */
00998 
00999 /**
01000  * Delete the pcb inside a netconn.
01001  * Called from netconn_delete.
01002  *
01003  * @param m the api_msg_msg pointing to the connection
01004  */
01005 void
01006 lwip_netconn_do_delconn(void *m)
01007 {
01008   struct api_msg *msg = (struct api_msg*)m;
01009 
01010   enum netconn_state state = msg->conn->state;
01011   LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */
01012     (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP));
01013 #if LWIP_NETCONN_FULLDUPLEX
01014   /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */
01015   if (state != NETCONN_NONE) {
01016     if ((state == NETCONN_WRITE) ||
01017         ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
01018       /* close requested, abort running write/connect */
01019       sys_sem_t* op_completed_sem;
01020       LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
01021       op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
01022       msg->conn->current_msg->err = ERR_CLSD;
01023       msg->conn->current_msg = NULL;
01024       msg->conn->write_offset = 0;
01025       msg->conn->state = NETCONN_NONE;
01026       NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
01027       sys_sem_signal(op_completed_sem);
01028     }
01029   }
01030 #else /* LWIP_NETCONN_FULLDUPLEX */
01031   if (((state != NETCONN_NONE) &&
01032        (state != NETCONN_LISTEN) &&
01033        (state != NETCONN_CONNECT)) ||
01034       ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
01035     /* This means either a blocking write or blocking connect is running
01036        (nonblocking write returns and sets state to NONE) */
01037     msg->err = ERR_INPROGRESS;
01038   } else
01039 #endif /* LWIP_NETCONN_FULLDUPLEX */
01040   {
01041     LWIP_ASSERT("blocking connect in progress",
01042       (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
01043     msg->err = ERR_OK;
01044     /* Drain and delete mboxes */
01045     netconn_drain(msg->conn);
01046 
01047     if (msg->conn->pcb.tcp != NULL) {
01048 
01049       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01050 #if LWIP_RAW
01051       case NETCONN_RAW:
01052         raw_remove(msg->conn->pcb.raw);
01053         break;
01054 #endif /* LWIP_RAW */
01055 #if LWIP_UDP
01056       case NETCONN_UDP:
01057         msg->conn->pcb.udp->recv_arg = NULL;
01058         udp_remove(msg->conn->pcb.udp);
01059         break;
01060 #endif /* LWIP_UDP */
01061 #if LWIP_TCP
01062       case NETCONN_TCP:
01063         LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
01064           msg->conn->write_offset == 0);
01065         msg->conn->state = NETCONN_CLOSE;
01066         msg->msg.sd.shut = NETCONN_SHUT_RDWR;
01067         msg->conn->current_msg = msg;
01068 #if LWIP_TCPIP_CORE_LOCKING
01069         if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
01070           LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
01071           UNLOCK_TCPIP_CORE();
01072           sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
01073           LOCK_TCPIP_CORE();
01074           LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
01075         }
01076 #else /* LWIP_TCPIP_CORE_LOCKING */
01077         lwip_netconn_do_close_internal(msg->conn);
01078 #endif /* LWIP_TCPIP_CORE_LOCKING */
01079         /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing
01080            the application thread, so we can return at this point! */
01081         return;
01082 #endif /* LWIP_TCP */
01083       default:
01084         break;
01085       }
01086       msg->conn->pcb.tcp = NULL;
01087     }
01088     /* tcp netconns don't come here! */
01089 
01090     /* @todo: this lets select make the socket readable and writable,
01091        which is wrong! errfd instead? */
01092     API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
01093     API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
01094   }
01095   if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) {
01096     TCPIP_APIMSG_ACK(msg);
01097   }
01098 }
01099 
01100 /**
01101  * Bind a pcb contained in a netconn
01102  * Called from netconn_bind.
01103  *
01104  * @param m the api_msg_msg pointing to the connection and containing
01105  *          the IP address and port to bind to
01106  */
01107 void
01108 lwip_netconn_do_bind(void *m)
01109 {
01110   struct api_msg *msg = (struct api_msg*)m;
01111 
01112   if (ERR_IS_FATAL(msg->conn->last_err)) {
01113     msg->err = msg->conn->last_err;
01114   } else {
01115     msg->err = ERR_VAL;
01116     if (msg->conn->pcb.tcp != NULL) {
01117       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01118 #if LWIP_RAW
01119       case NETCONN_RAW:
01120         msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
01121         break;
01122 #endif /* LWIP_RAW */
01123 #if LWIP_UDP
01124       case NETCONN_UDP:
01125         msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
01126         break;
01127 #endif /* LWIP_UDP */
01128 #if LWIP_TCP
01129       case NETCONN_TCP:
01130         msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
01131         break;
01132 #endif /* LWIP_TCP */
01133       default:
01134         break;
01135       }
01136     }
01137   }
01138   TCPIP_APIMSG_ACK(msg);
01139 }
01140 
01141 #if LWIP_TCP
01142 /**
01143  * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has
01144  * been established (or reset by the remote host).
01145  *
01146  * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
01147  */
01148 static err_t
01149 lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
01150 {
01151   struct netconn *conn;
01152   int was_blocking;
01153   sys_sem_t* op_completed_sem = NULL;
01154 
01155   LWIP_UNUSED_ARG(pcb);
01156 
01157   conn = (struct netconn *)arg;
01158 
01159   if (conn == NULL) {
01160     return ERR_VAL;
01161   }
01162 
01163   LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
01164   LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
01165     (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
01166 
01167   if (conn->current_msg != NULL) {
01168     conn->current_msg->err = err;
01169     op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
01170   }
01171   if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
01172     setup_tcp(conn);
01173   }
01174   was_blocking = !IN_NONBLOCKING_CONNECT(conn);
01175   SET_NONBLOCKING_CONNECT(conn, 0);
01176   LWIP_ASSERT("blocking connect state error",
01177     (was_blocking && op_completed_sem != NULL) ||
01178     (!was_blocking && op_completed_sem == NULL));
01179   conn->current_msg = NULL;
01180   conn->state = NETCONN_NONE;
01181   NETCONN_SET_SAFE_ERR(conn, ERR_OK);
01182   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
01183 
01184   if (was_blocking) {
01185     sys_sem_signal(op_completed_sem);
01186   }
01187   return ERR_OK;
01188 }
01189 #endif /* LWIP_TCP */
01190 
01191 /**
01192  * Connect a pcb contained inside a netconn
01193  * Called from netconn_connect.
01194  *
01195  * @param m the api_msg_msg pointing to the connection and containing
01196  *          the IP address and port to connect to
01197  */
01198 void
01199 lwip_netconn_do_connect(void *m)
01200 {
01201   struct api_msg *msg = (struct api_msg*)m;
01202 
01203   if (msg->conn->pcb.tcp == NULL) {
01204     /* This may happen when calling netconn_connect() a second time */
01205     msg->err = ERR_CLSD;
01206   } else {
01207     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01208 #if LWIP_RAW
01209     case NETCONN_RAW:
01210       msg->err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
01211       break;
01212 #endif /* LWIP_RAW */
01213 #if LWIP_UDP
01214     case NETCONN_UDP:
01215       msg->err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
01216       break;
01217 #endif /* LWIP_UDP */
01218 #if LWIP_TCP
01219     case NETCONN_TCP:
01220       /* Prevent connect while doing any other action. */
01221       if (msg->conn->state == NETCONN_CONNECT) {
01222         msg->err = ERR_ALREADY;
01223       } else if (msg->conn->state != NETCONN_NONE) {
01224         msg->err = ERR_ISCONN;
01225       } else {
01226         setup_tcp(msg->conn);
01227         msg->err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr),
01228           msg->msg.bc.port, lwip_netconn_do_connected);
01229         if (msg->err == ERR_OK) {
01230           u8_t non_blocking = netconn_is_nonblocking(msg->conn);
01231           msg->conn->state = NETCONN_CONNECT;
01232           SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
01233           if (non_blocking) {
01234             msg->err = ERR_INPROGRESS;
01235           } else {
01236             msg->conn->current_msg = msg;
01237             /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()),
01238                when the connection is established! */
01239 #if LWIP_TCPIP_CORE_LOCKING
01240             LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT);
01241             UNLOCK_TCPIP_CORE();
01242             sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
01243             LOCK_TCPIP_CORE();
01244             LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT);
01245 #endif /* LWIP_TCPIP_CORE_LOCKING */
01246             return;
01247           }
01248         }
01249       }
01250       break;
01251 #endif /* LWIP_TCP */
01252     default:
01253       LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
01254       break;
01255     }
01256   }
01257   /* For all other protocols, netconn_connect() calls TCPIP_APIMSG(),
01258      so use TCPIP_APIMSG_ACK() here. */
01259   TCPIP_APIMSG_ACK(msg);
01260 }
01261 
01262 /**
01263  * Disconnect a pcb contained inside a netconn
01264  * Only used for UDP netconns.
01265  * Called from netconn_disconnect.
01266  *
01267  * @param m the api_msg_msg pointing to the connection to disconnect
01268  */
01269 void
01270 lwip_netconn_do_disconnect(void *m)
01271 {
01272   struct api_msg *msg = (struct api_msg*)m;
01273 
01274 #if LWIP_UDP
01275   if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
01276     udp_disconnect(msg->conn->pcb.udp);
01277     msg->err = ERR_OK;
01278   } else
01279 #endif /* LWIP_UDP */
01280   {
01281     msg->err = ERR_VAL;
01282   }
01283   TCPIP_APIMSG_ACK(msg);
01284 }
01285 
01286 #if LWIP_TCP
01287 /**
01288  * Set a TCP pcb contained in a netconn into listen mode
01289  * Called from netconn_listen.
01290  *
01291  * @param m the api_msg_msg pointing to the connection
01292  */
01293 void
01294 lwip_netconn_do_listen(void *m)
01295 {
01296   struct api_msg *msg = (struct api_msg*)m;
01297 
01298   if (ERR_IS_FATAL(msg->conn->last_err)) {
01299     msg->err = msg->conn->last_err;
01300   } else {
01301     msg->err = ERR_CONN;
01302     if (msg->conn->pcb.tcp != NULL) {
01303       if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
01304         if (msg->conn->state == NETCONN_NONE) {
01305           struct tcp_pcb* lpcb;
01306           if (msg->conn->pcb.tcp->state != CLOSED) {
01307             /* connection is not closed, cannot listen */
01308             msg->err = ERR_VAL;
01309           } else {
01310             err_t err;
01311             u8_t backlog;
01312 #if TCP_LISTEN_BACKLOG
01313             backlog = msg->msg.lb.backlog;
01314 #else  /* TCP_LISTEN_BACKLOG */
01315             backlog = TCP_DEFAULT_LISTEN_BACKLOG;
01316 #endif /* TCP_LISTEN_BACKLOG */
01317 #if LWIP_IPV4 && LWIP_IPV6
01318             /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
01319              * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
01320              */
01321             if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) &&
01322                 (netconn_get_ipv6only(msg->conn) == 0)) {
01323               /* change PCB type to IPADDR_TYPE_ANY */
01324               IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip,  IPADDR_TYPE_ANY);
01325               IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY);
01326             }
01327 #endif /* LWIP_IPV4 && LWIP_IPV6 */
01328 
01329             lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
01330 
01331             if (lpcb == NULL) {
01332               /* in this case, the old pcb is still allocated */
01333               msg->err = err;
01334             } else {
01335               /* delete the recvmbox and allocate the acceptmbox */
01336               if (sys_mbox_valid(&msg->conn->recvmbox)) {
01337                 /** @todo: should we drain the recvmbox here? */
01338                 sys_mbox_free(&msg->conn->recvmbox);
01339                 sys_mbox_set_invalid(&msg->conn->recvmbox);
01340               }
01341               msg->err = ERR_OK;
01342               if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
01343                 msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
01344               }
01345               if (msg->err == ERR_OK) {
01346                 msg->conn->state = NETCONN_LISTEN;
01347                 msg->conn->pcb.tcp = lpcb;
01348                 tcp_arg(msg->conn->pcb.tcp, msg->conn);
01349                 tcp_accept(msg->conn->pcb.tcp, accept_function);
01350               } else {
01351                 /* since the old pcb is already deallocated, free lpcb now */
01352                 tcp_close(lpcb);
01353                 msg->conn->pcb.tcp = NULL;
01354               }
01355             }
01356           }
01357         } else if (msg->conn->state == NETCONN_LISTEN) {
01358           /* already listening, allow updating of the backlog */
01359           msg->err = ERR_OK;
01360           tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog);
01361         }
01362       } else {
01363         msg->err = ERR_ARG;
01364       }
01365     }
01366   }
01367   TCPIP_APIMSG_ACK(msg);
01368 }
01369 #endif /* LWIP_TCP */
01370 
01371 /**
01372  * Send some data on a RAW or UDP pcb contained in a netconn
01373  * Called from netconn_send
01374  *
01375  * @param m the api_msg_msg pointing to the connection
01376  */
01377 void
01378 lwip_netconn_do_send(void *m)
01379 {
01380   struct api_msg *msg = (struct api_msg*)m;
01381 
01382   if (ERR_IS_FATAL(msg->conn->last_err)) {
01383     msg->err = msg->conn->last_err;
01384   } else {
01385     msg->err = ERR_CONN;
01386     if (msg->conn->pcb.tcp != NULL) {
01387       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01388 #if LWIP_RAW
01389       case NETCONN_RAW:
01390         if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
01391           msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
01392         } else {
01393           msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
01394         }
01395         break;
01396 #endif
01397 #if LWIP_UDP
01398       case NETCONN_UDP:
01399 #if LWIP_CHECKSUM_ON_COPY
01400         if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
01401           msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
01402             msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
01403         } else {
01404           msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
01405             &msg->msg.b->addr, msg->msg.b->port,
01406             msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
01407         }
01408 #else /* LWIP_CHECKSUM_ON_COPY */
01409         if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
01410           msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
01411         } else {
01412           msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
01413         }
01414 #endif /* LWIP_CHECKSUM_ON_COPY */
01415         break;
01416 #endif /* LWIP_UDP */
01417       default:
01418         break;
01419       }
01420     }
01421   }
01422   TCPIP_APIMSG_ACK(msg);
01423 }
01424 
01425 #if LWIP_TCP
01426 /**
01427  * Indicate data has been received from a TCP pcb contained in a netconn
01428  * Called from netconn_recv
01429  *
01430  * @param m the api_msg_msg pointing to the connection
01431  */
01432 void
01433 lwip_netconn_do_recv(void *m)
01434 {
01435   struct api_msg *msg = (struct api_msg*)m;
01436 
01437   msg->err = ERR_OK;
01438   if (msg->conn->pcb.tcp != NULL) {
01439     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
01440       u32_t remaining = msg->msg.r.len;
01441       do {
01442         u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
01443         tcp_recved(msg->conn->pcb.tcp, recved);
01444         remaining -= recved;
01445       } while (remaining != 0);
01446     }
01447   }
01448   TCPIP_APIMSG_ACK(msg);
01449 }
01450 
01451 #if TCP_LISTEN_BACKLOG
01452 /** Indicate that a TCP pcb has been accepted
01453  * Called from netconn_accept
01454  *
01455  * @param m the api_msg_msg pointing to the connection
01456  */
01457 void
01458 lwip_netconn_do_accepted(void *m)
01459 {
01460   struct api_msg *msg = (struct api_msg*)m;
01461 
01462   msg->err = ERR_OK;
01463   if (msg->conn->pcb.tcp != NULL) {
01464     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
01465       tcp_backlog_accepted(msg->conn->pcb.tcp);
01466     }
01467   }
01468   TCPIP_APIMSG_ACK(msg);
01469 }
01470 #endif /* TCP_LISTEN_BACKLOG */
01471 
01472 /**
01473  * See if more data needs to be written from a previous call to netconn_write.
01474  * Called initially from lwip_netconn_do_write. If the first call can't send all data
01475  * (because of low memory or empty send-buffer), this function is called again
01476  * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
01477  * blocking application thread (waiting in netconn_write) is released.
01478  *
01479  * @param conn netconn (that is currently in state NETCONN_WRITE) to process
01480  * @return ERR_OK
01481  *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
01482  */
01483 static err_t
01484 lwip_netconn_do_writemore(struct netconn *conn  WRITE_DELAYED_PARAM)
01485 {
01486   err_t err;
01487   const void *dataptr;
01488   u16_t len, available;
01489   u8_t write_finished = 0;
01490   size_t diff;
01491   u8_t dontblock;
01492   u8_t apiflags;
01493 
01494   LWIP_ASSERT("conn != NULL", conn != NULL);
01495   LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
01496   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
01497   LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
01498   LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
01499     conn->write_offset < conn->current_msg->msg.w.len);
01500 
01501   apiflags = conn->current_msg->msg.w.apiflags;
01502   dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
01503 
01504 #if LWIP_SO_SNDTIMEO
01505   if ((conn->send_timeout != 0) &&
01506       ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
01507     write_finished = 1;
01508     if (conn->write_offset == 0) {
01509       /* nothing has been written */
01510       err = ERR_WOULDBLOCK;
01511       conn->current_msg->msg.w.len = 0;
01512     } else {
01513       /* partial write */
01514       err = ERR_OK;
01515       conn->current_msg->msg.w.len = conn->write_offset;
01516       conn->write_offset = 0;
01517     }
01518   } else
01519 #endif /* LWIP_SO_SNDTIMEO */
01520   {
01521     dataptr = (const u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
01522     diff = conn->current_msg->msg.w.len - conn->write_offset;
01523     if (diff > 0xffffUL) { /* max_u16_t */
01524       len = 0xffff;
01525       apiflags |= TCP_WRITE_FLAG_MORE;
01526     } else {
01527       len = (u16_t)diff;
01528     }
01529     available = tcp_sndbuf(conn->pcb.tcp);
01530     if (available < len) {
01531       /* don't try to write more than sendbuf */
01532       len = available;
01533       if (dontblock) {
01534         if (!len) {
01535           err = ERR_WOULDBLOCK;
01536           goto err_mem;
01537         }
01538       } else {
01539         apiflags |= TCP_WRITE_FLAG_MORE;
01540       }
01541     }
01542     LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
01543     err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
01544     /* if OK or memory error, check available space */
01545     if ((err == ERR_OK) || (err == ERR_MEM)) {
01546 err_mem:
01547       if (dontblock && (len < conn->current_msg->msg.w.len)) {
01548         /* non-blocking write did not write everything: mark the pcb non-writable
01549            and let poll_tcp check writable space to mark the pcb writable again */
01550         API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
01551         conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
01552       } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
01553                  (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
01554         /* The queued byte- or pbuf-count exceeds the configured low-water limit,
01555            let select mark this pcb as non-writable. */
01556         API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
01557       }
01558     }
01559 
01560     if (err == ERR_OK) {
01561       err_t out_err;
01562       conn->write_offset += len;
01563       if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) {
01564         /* return sent length */
01565         conn->current_msg->msg.w.len = conn->write_offset;
01566         /* everything was written */
01567         write_finished = 1;
01568       }
01569       out_err = tcp_output(conn->pcb.tcp);
01570       if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) {
01571         /* If tcp_output fails with fatal error or no route is found,
01572            don't try writing any more but return the error
01573            to the application thread. */
01574         err = out_err;
01575         write_finished = 1;
01576         conn->current_msg->msg.w.len = 0;
01577       }
01578     } else if (err == ERR_MEM) {
01579       /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called.
01580          For blocking sockets, we do NOT return to the application
01581          thread, since ERR_MEM is only a temporary error! Non-blocking
01582          will remain non-writable until sent_tcp/poll_tcp is called */
01583 
01584       /* tcp_write returned ERR_MEM, try tcp_output anyway */
01585       err_t out_err = tcp_output(conn->pcb.tcp);
01586       if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) {
01587         /* If tcp_output fails with fatal error or no route is found,
01588            don't try writing any more but return the error
01589            to the application thread. */
01590         err = out_err;
01591         write_finished = 1;
01592         conn->current_msg->msg.w.len = 0;
01593       } else if (dontblock) {
01594         /* non-blocking write is done on ERR_MEM */
01595         err = ERR_WOULDBLOCK;
01596         write_finished = 1;
01597         conn->current_msg->msg.w.len = 0;
01598       }
01599     } else {
01600       /* On errors != ERR_MEM, we don't try writing any more but return
01601          the error to the application thread. */
01602       write_finished = 1;
01603       conn->current_msg->msg.w.len = 0;
01604     }
01605   }
01606   if (write_finished) {
01607     /* everything was written: set back connection state
01608        and back to application task */
01609     sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
01610     conn->current_msg->err = err;
01611     conn->current_msg = NULL;
01612     conn->write_offset = 0;
01613     conn->state = NETCONN_NONE;
01614     NETCONN_SET_SAFE_ERR(conn, err);
01615 #if LWIP_TCPIP_CORE_LOCKING
01616     if (delayed)
01617 #endif
01618     {
01619       sys_sem_signal(op_completed_sem);
01620     }
01621   }
01622 #if LWIP_TCPIP_CORE_LOCKING
01623   else {
01624     return ERR_MEM;
01625   }
01626 #endif
01627   return ERR_OK;
01628 }
01629 #endif /* LWIP_TCP */
01630 
01631 /**
01632  * Send some data on a TCP pcb contained in a netconn
01633  * Called from netconn_write
01634  *
01635  * @param m the api_msg_msg pointing to the connection
01636  */
01637 void
01638 lwip_netconn_do_write(void *m)
01639 {
01640   struct api_msg *msg = (struct api_msg*)m;
01641 
01642   if (ERR_IS_FATAL(msg->conn->last_err)) {
01643     msg->err = msg->conn->last_err;
01644   } else {
01645     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
01646 #if LWIP_TCP
01647       if (msg->conn->state != NETCONN_NONE) {
01648         /* netconn is connecting, closing or in blocking write */
01649         msg->err = ERR_INPROGRESS;
01650       } else if (msg->conn->pcb.tcp != NULL) {
01651         msg->conn->state = NETCONN_WRITE;
01652         /* set all the variables used by lwip_netconn_do_writemore */
01653         LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
01654           msg->conn->write_offset == 0);
01655         LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
01656         msg->conn->current_msg = msg;
01657         msg->conn->write_offset = 0;
01658 #if LWIP_TCPIP_CORE_LOCKING
01659         if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) {
01660           LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
01661           UNLOCK_TCPIP_CORE();
01662           sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
01663           LOCK_TCPIP_CORE();
01664           LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE);
01665         }
01666 #else /* LWIP_TCPIP_CORE_LOCKING */
01667         lwip_netconn_do_writemore(msg->conn);
01668 #endif /* LWIP_TCPIP_CORE_LOCKING */
01669         /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG
01670            since lwip_netconn_do_writemore ACKs it! */
01671         return;
01672       } else {
01673         msg->err = ERR_CONN;
01674       }
01675 #else /* LWIP_TCP */
01676       msg->err = ERR_VAL;
01677 #endif /* LWIP_TCP */
01678 #if (LWIP_UDP || LWIP_RAW)
01679     } else {
01680       msg->err = ERR_VAL;
01681 #endif /* (LWIP_UDP || LWIP_RAW) */
01682     }
01683   }
01684   TCPIP_APIMSG_ACK(msg);
01685 }
01686 
01687 /**
01688  * Return a connection's local or remote address
01689  * Called from netconn_getaddr
01690  *
01691  * @param m the api_msg_msg pointing to the connection
01692  */
01693 void
01694 lwip_netconn_do_getaddr(void *m)
01695 {
01696   struct api_msg *msg = (struct api_msg*)m;
01697 
01698   if (msg->conn->pcb.ip != NULL) {
01699     if (msg->msg.ad.local) {
01700       ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
01701         msg->conn->pcb.ip->local_ip);
01702     } else {
01703       ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
01704         msg->conn->pcb.ip->remote_ip);
01705     }
01706 
01707     msg->err = ERR_OK;
01708     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01709 #if LWIP_RAW
01710     case NETCONN_RAW:
01711       if (msg->msg.ad.local) {
01712         API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
01713       } else {
01714         /* return an error as connecting is only a helper for upper layers */
01715         msg->err = ERR_CONN;
01716       }
01717       break;
01718 #endif /* LWIP_RAW */
01719 #if LWIP_UDP
01720     case NETCONN_UDP:
01721       if (msg->msg.ad.local) {
01722         API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
01723       } else {
01724         if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
01725           msg->err = ERR_CONN;
01726         } else {
01727           API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
01728         }
01729       }
01730       break;
01731 #endif /* LWIP_UDP */
01732 #if LWIP_TCP
01733     case NETCONN_TCP:
01734       if ((msg->msg.ad.local == 0) &&
01735           ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) {
01736         /* pcb is not connected and remote name is requested */
01737         msg->err = ERR_CONN;
01738       } else {
01739         API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port);
01740       }
01741       break;
01742 #endif /* LWIP_TCP */
01743     default:
01744       LWIP_ASSERT("invalid netconn_type", 0);
01745       break;
01746     }
01747   } else {
01748     msg->err = ERR_CONN;
01749   }
01750   TCPIP_APIMSG_ACK(msg);
01751 }
01752 
01753 /**
01754  * Close or half-shutdown a TCP pcb contained in a netconn
01755  * Called from netconn_close
01756  * In contrast to closing sockets, the netconn is not deallocated.
01757  *
01758  * @param m the api_msg_msg pointing to the connection
01759  */
01760 void
01761 lwip_netconn_do_close(void *m)
01762 {
01763   struct api_msg *msg = (struct api_msg*)m;
01764 
01765 #if LWIP_TCP
01766   enum netconn_state state = msg->conn->state;
01767   /* First check if this is a TCP netconn and if it is in a correct state
01768       (LISTEN doesn't support half shutdown) */
01769   if ((msg->conn->pcb.tcp != NULL) &&
01770       (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) &&
01771       ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) {
01772     /* Check if we are in a connected state */
01773     if (state == NETCONN_CONNECT) {
01774       /* TCP connect in progress: cannot shutdown */
01775       msg->err = ERR_CONN;
01776     } else if (state == NETCONN_WRITE) {
01777 #if LWIP_NETCONN_FULLDUPLEX
01778       if (msg->msg.sd.shut & NETCONN_SHUT_WR) {
01779         /* close requested, abort running write */
01780         sys_sem_t* op_completed_sem;
01781         LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
01782         op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
01783         msg->conn->current_msg->err = ERR_CLSD;
01784         msg->conn->current_msg = NULL;
01785         msg->conn->write_offset = 0;
01786         msg->conn->state = NETCONN_NONE;
01787         NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
01788         sys_sem_signal(op_completed_sem);
01789       } else {
01790         LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD);
01791         /* In this case, let the write continue and do not interfere with
01792            conn->current_msg or conn->state! */
01793         msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0);
01794       }
01795 #else /* LWIP_NETCONN_FULLDUPLEX */
01796       msg->err = ERR_INPROGRESS;
01797 #endif /* LWIP_NETCONN_FULLDUPLEX */
01798     } else {
01799       if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
01800         /* Drain and delete mboxes */
01801         netconn_drain(msg->conn);
01802       }
01803       LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
01804         msg->conn->write_offset == 0);
01805       msg->conn->state = NETCONN_CLOSE;
01806       msg->conn->current_msg = msg;
01807 #if LWIP_TCPIP_CORE_LOCKING
01808       if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
01809         LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
01810         UNLOCK_TCPIP_CORE();
01811         sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
01812         LOCK_TCPIP_CORE();
01813         LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
01814       }
01815 #else /* LWIP_TCPIP_CORE_LOCKING */
01816       lwip_netconn_do_close_internal(msg->conn);
01817 #endif /* LWIP_TCPIP_CORE_LOCKING */
01818       /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */
01819       return;
01820     }
01821   } else
01822 #endif /* LWIP_TCP */
01823   {
01824     msg->err = ERR_CONN;
01825   }
01826   TCPIP_APIMSG_ACK(msg);
01827 }
01828 
01829 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
01830 /**
01831  * Join multicast groups for UDP netconns.
01832  * Called from netconn_join_leave_group
01833  *
01834  * @param m the api_msg_msg pointing to the connection
01835  */
01836 void
01837 lwip_netconn_do_join_leave_group(void *m)
01838 {
01839   struct api_msg *msg = (struct api_msg*)m;
01840 
01841   if (ERR_IS_FATAL(msg->conn->last_err)) {
01842     msg->err = msg->conn->last_err;
01843   } else {
01844     if (msg->conn->pcb.tcp != NULL) {
01845       if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
01846 #if LWIP_UDP
01847 #if LWIP_IPV6 && LWIP_IPV6_MLD
01848         if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
01849           if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
01850             msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
01851               ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
01852           } else {
01853             msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
01854               ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
01855           }
01856         }
01857         else
01858 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
01859         {
01860 #if LWIP_IGMP
01861           if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
01862             msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
01863               ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
01864           } else {
01865             msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
01866               ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
01867           }
01868 #endif /* LWIP_IGMP */
01869         }
01870 #endif /* LWIP_UDP */
01871 #if (LWIP_TCP || LWIP_RAW)
01872       } else {
01873         msg->err = ERR_VAL;
01874 #endif /* (LWIP_TCP || LWIP_RAW) */
01875       }
01876     } else {
01877       msg->err = ERR_CONN;
01878     }
01879   }
01880   TCPIP_APIMSG_ACK(msg);
01881 }
01882 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
01883 
01884 #if LWIP_DNS
01885 /**
01886  * Callback function that is called when DNS name is resolved
01887  * (or on timeout). A waiting application thread is waked up by
01888  * signaling the semaphore.
01889  */
01890 static void
01891 lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg)
01892 {
01893   struct dns_api_msg *msg = (struct dns_api_msg*)arg;
01894 
01895   /* we trust the internal implementation to be correct :-) */
01896   LWIP_UNUSED_ARG(name);
01897 
01898   if (ipaddr == NULL) {
01899     /* timeout or memory error */
01900     API_EXPR_DEREF(msg->err) = ERR_VAL;
01901   } else {
01902     /* address was resolved */
01903     API_EXPR_DEREF(msg->err) = ERR_OK;
01904     API_EXPR_DEREF(msg->addr) = *ipaddr;
01905   }
01906   /* wake up the application task waiting in netconn_gethostbyname */
01907   sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
01908 }
01909 
01910 /**
01911  * Execute a DNS query
01912  * Called from netconn_gethostbyname
01913  *
01914  * @param arg the dns_api_msg pointing to the query
01915  */
01916 void
01917 lwip_netconn_do_gethostbyname(void *arg)
01918 {
01919   struct dns_api_msg *msg = (struct dns_api_msg*)arg;
01920   u8_t addrtype =
01921 #if LWIP_IPV4 && LWIP_IPV6
01922     msg->dns_addrtype;
01923 #else
01924     LWIP_DNS_ADDRTYPE_DEFAULT;
01925 #endif
01926 
01927   API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name,
01928     API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype);
01929   if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) {
01930     /* on error or immediate success, wake up the application
01931      * task waiting in netconn_gethostbyname */
01932     sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
01933   }
01934 }
01935 #endif /* LWIP_DNS */
01936 
01937 #endif /* LWIP_NETCONN */