ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

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