Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_api_lib.c Source File

lwip_api_lib.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Sequential API External module
00004  *
00005  * @defgroup netconn Netconn API
00006  * @ingroup sequential_api
00007  * Thread-safe, to be called from non-TCPIP threads only.
00008  * TX/RX handling based on @ref netbuf (containing @ref pbuf)
00009  * to avoid copying data around.
00010  *
00011  * @defgroup netconn_common Common functions
00012  * @ingroup netconn
00013  * For use with TCP and UDP
00014  *
00015  * @defgroup netconn_tcp TCP only
00016  * @ingroup netconn
00017  * TCP only functions
00018  *
00019  * @defgroup netconn_udp UDP only
00020  * @ingroup netconn
00021  * UDP only functions
00022  */
00023 
00024 /*
00025  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00026  * All rights reserved.
00027  *
00028  * Redistribution and use in source and binary forms, with or without modification,
00029  * are permitted provided that the following conditions are met:
00030  *
00031  * 1. Redistributions of source code must retain the above copyright notice,
00032  *    this list of conditions and the following disclaimer.
00033  * 2. Redistributions in binary form must reproduce the above copyright notice,
00034  *    this list of conditions and the following disclaimer in the documentation
00035  *    and/or other materials provided with the distribution.
00036  * 3. The name of the author may not be used to endorse or promote products
00037  *    derived from this software without specific prior written permission.
00038  *
00039  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00040  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00041  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00042  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00043  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00044  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00045  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00046  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00047  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00048  * OF SUCH DAMAGE.
00049  *
00050  * This file is part of the lwIP TCP/IP stack.
00051  *
00052  * Author: Adam Dunkels <adam@sics.se>
00053  */
00054 
00055 /* This is the part of the API that is linked with
00056    the application */
00057 
00058 #include "lwip/opt.h"
00059 
00060 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
00061 
00062 #include "lwip/api.h"
00063 #include "lwip/memp.h"
00064 
00065 #include "lwip/ip.h"
00066 #include "lwip/raw.h"
00067 #include "lwip/udp.h"
00068 #include "lwip/priv/api_msg.h"
00069 #include "lwip/priv/tcp_priv.h"
00070 #include "lwip/priv/tcpip_priv.h"
00071 
00072 #ifdef LWIP_HOOK_FILENAME
00073 #include LWIP_HOOK_FILENAME
00074 #endif
00075 
00076 #include <string.h>
00077 
00078 #define API_MSG_VAR_REF(name)               API_VAR_REF(name)
00079 #define API_MSG_VAR_DECLARE(name)           API_VAR_DECLARE(struct api_msg, name)
00080 #define API_MSG_VAR_ALLOC(name)             API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, ERR_MEM)
00081 #define API_MSG_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, NULL)
00082 #define API_MSG_VAR_FREE(name)              API_VAR_FREE(MEMP_API_MSG, name)
00083 
00084 #if TCP_LISTEN_BACKLOG
00085 /* need to allocate API message for accept so empty message pool does not result in event loss
00086  * see bug #47512: MPU_COMPATIBLE may fail on empty pool */
00087 #define API_MSG_VAR_ALLOC_ACCEPT(msg) API_MSG_VAR_ALLOC(msg)
00088 #define API_MSG_VAR_FREE_ACCEPT(msg) API_MSG_VAR_FREE(msg)
00089 #else /* TCP_LISTEN_BACKLOG */
00090 #define API_MSG_VAR_ALLOC_ACCEPT(msg)
00091 #define API_MSG_VAR_FREE_ACCEPT(msg)
00092 #endif /* TCP_LISTEN_BACKLOG */
00093 
00094 #if LWIP_NETCONN_FULLDUPLEX
00095 #define NETCONN_RECVMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->recvmbox) && (((conn)->flags & NETCONN_FLAG_MBOXINVALID) == 0))
00096 #define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & (NETCONN_FLAG_MBOXCLOSED|NETCONN_FLAG_MBOXINVALID)) == 0))
00097 #define NETCONN_MBOX_WAITING_INC(conn) SYS_ARCH_INC(conn->mbox_threads_waiting, 1)
00098 #define NETCONN_MBOX_WAITING_DEC(conn) SYS_ARCH_DEC(conn->mbox_threads_waiting, 1)
00099 #else /* LWIP_NETCONN_FULLDUPLEX */
00100 #define NETCONN_RECVMBOX_WAITABLE(conn)   sys_mbox_valid(&(conn)->recvmbox)
00101 #define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & NETCONN_FLAG_MBOXCLOSED) == 0))
00102 #define NETCONN_MBOX_WAITING_INC(conn)
00103 #define NETCONN_MBOX_WAITING_DEC(conn)
00104 #endif /* LWIP_NETCONN_FULLDUPLEX */
00105 
00106 static err_t netconn_close_shutdown(struct netconn *conn, u8_t how);
00107 
00108 /**
00109  * Call the lower part of a netconn_* function
00110  * This function is then running in the thread context
00111  * of tcpip_thread and has exclusive access to lwIP core code.
00112  *
00113  * @param fn function to call
00114  * @param apimsg a struct containing the function to call and its parameters
00115  * @return ERR_OK if the function was called, another err_t if not
00116  */
00117 static err_t
00118 netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg)
00119 {
00120   err_t err;
00121 
00122 #ifdef LWIP_DEBUG
00123   /* catch functions that don't set err */
00124   apimsg->err = ERR_VAL;
00125 #endif /* LWIP_DEBUG */
00126 
00127 #if LWIP_NETCONN_SEM_PER_THREAD
00128   apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
00129 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
00130 
00131   if (sys_tcpip_thread_check()) {
00132       fn(apimsg);
00133       return ERR_OK;
00134   } else {
00135       err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg));
00136 
00137       if (err == ERR_OK) {
00138         return apimsg->err;
00139       }
00140 
00141       return err;
00142   }
00143 }
00144 
00145 /**
00146  * Create a new netconn (of a specific type) that has a callback function.
00147  * The corresponding pcb is also created.
00148  *
00149  * @param t the type of 'connection' to create (@see enum netconn_type)
00150  * @param proto the IP protocol for RAW IP pcbs
00151  * @param callback a function to call on status changes (RX available, TX'ed)
00152  * @return a newly allocated struct netconn or
00153  *         NULL on memory error
00154  */
00155 struct netconn *
00156 netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
00157 {
00158   struct netconn *conn;
00159   API_MSG_VAR_DECLARE(msg);
00160   API_MSG_VAR_ALLOC_RETURN_NULL(msg);
00161 
00162   conn = netconn_alloc(t, callback);
00163   if (conn != NULL) {
00164     err_t err;
00165 
00166     API_MSG_VAR_REF(msg).msg.n.proto = proto;
00167     API_MSG_VAR_REF(msg).conn = conn;
00168     err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg));
00169     if (err != ERR_OK) {
00170       LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
00171       LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
00172 #if LWIP_TCP
00173       LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
00174 #endif /* LWIP_TCP */
00175 #if !LWIP_NETCONN_SEM_PER_THREAD
00176       LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
00177       sys_sem_free(&conn->op_completed);
00178 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
00179       sys_mbox_free(&conn->recvmbox);
00180       memp_free(MEMP_NETCONN, conn);
00181       API_MSG_VAR_FREE(msg);
00182       return NULL;
00183     }
00184   }
00185   API_MSG_VAR_FREE(msg);
00186   return conn;
00187 }
00188 
00189 /**
00190  * @ingroup netconn_common
00191  * Close a netconn 'connection' and free all its resources but not the netconn itself.
00192  * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
00193  * after this returns.
00194  *
00195  * @param conn the netconn to delete
00196  * @return ERR_OK if the connection was deleted
00197  */
00198 err_t
00199 netconn_prepare_delete(struct netconn *conn)
00200 {
00201   err_t err;
00202   API_MSG_VAR_DECLARE(msg);
00203 
00204   /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
00205   if (conn == NULL) {
00206     return ERR_OK;
00207   }
00208 
00209   API_MSG_VAR_ALLOC(msg);
00210   API_MSG_VAR_REF(msg).conn = conn;
00211 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
00212   /* get the time we started, which is later compared to
00213      sys_now() + conn->send_timeout */
00214   API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
00215 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
00216 #if LWIP_TCP
00217   API_MSG_VAR_REF(msg).msg.sd.polls_left =
00218     ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
00219 #endif /* LWIP_TCP */
00220 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
00221   err = netconn_apimsg(lwip_netconn_do_delconn, &API_MSG_VAR_REF(msg));
00222   API_MSG_VAR_FREE(msg);
00223 
00224   if (err != ERR_OK) {
00225     return err;
00226   }
00227   return ERR_OK;
00228 }
00229 
00230 /**
00231  * @ingroup netconn_common
00232  * Close a netconn 'connection' and free its resources.
00233  * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
00234  * after this returns.
00235  *
00236  * @param conn the netconn to delete
00237  * @return ERR_OK if the connection was deleted
00238  */
00239 err_t
00240 netconn_delete(struct netconn *conn)
00241 {
00242   err_t err;
00243 
00244   /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
00245   if (conn == NULL) {
00246     return ERR_OK;
00247   }
00248 
00249 #if LWIP_NETCONN_FULLDUPLEX
00250   if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
00251     /* Already called netconn_prepare_delete() before */
00252     err = ERR_OK;
00253   } else
00254 #endif /* LWIP_NETCONN_FULLDUPLEX */
00255   {
00256     err = netconn_prepare_delete(conn);
00257   }
00258   if (err == ERR_OK) {
00259     netconn_free(conn);
00260   }
00261   return err;
00262 }
00263 
00264 /**
00265  * Get the local or remote IP address and port of a netconn.
00266  * For RAW netconns, this returns the protocol instead of a port!
00267  *
00268  * @param conn the netconn to query
00269  * @param addr a pointer to which to save the IP address
00270  * @param port a pointer to which to save the port (or protocol for RAW)
00271  * @param local 1 to get the local IP address, 0 to get the remote one
00272  * @return ERR_CONN for invalid connections
00273  *         ERR_OK if the information was retrieved
00274  */
00275 err_t
00276 netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
00277 {
00278   API_MSG_VAR_DECLARE(msg);
00279   err_t err;
00280 
00281   LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
00282   LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
00283   LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
00284 
00285   API_MSG_VAR_ALLOC(msg);
00286   API_MSG_VAR_REF(msg).conn = conn;
00287   API_MSG_VAR_REF(msg).msg.ad.local = local;
00288 #if LWIP_MPU_COMPATIBLE
00289   err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg));
00290   *addr = msg->msg.ad.ipaddr;
00291   *port = msg->msg.ad.port;
00292 #else /* LWIP_MPU_COMPATIBLE */
00293   msg.msg.ad.ipaddr = addr;
00294   msg.msg.ad.port = port;
00295   err = netconn_apimsg(lwip_netconn_do_getaddr, &msg);
00296 #endif /* LWIP_MPU_COMPATIBLE */
00297   API_MSG_VAR_FREE(msg);
00298 
00299   return err;
00300 }
00301 
00302 /**
00303  * @ingroup netconn_common
00304  * Bind a netconn to a specific local IP address and port.
00305  * Binding one netconn twice might not always be checked correctly!
00306  *
00307  * @param conn the netconn to bind
00308  * @param addr the local IP address to bind the netconn to
00309  *             (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses)
00310  * @param port the local port to bind the netconn to (not used for RAW)
00311  * @return ERR_OK if bound, any other err_t on failure
00312  */
00313 err_t
00314 netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port)
00315 {
00316   API_MSG_VAR_DECLARE(msg);
00317   err_t err;
00318 
00319   LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
00320 
00321 #if LWIP_IPV4
00322   /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
00323   if (addr == NULL) {
00324     addr = IP4_ADDR_ANY;
00325   }
00326 #endif /* LWIP_IPV4 */
00327 
00328 #if LWIP_IPV4 && LWIP_IPV6
00329   /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY,
00330    * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind
00331    */
00332   if ((netconn_get_ipv6only(conn) == 0) &&
00333       ip_addr_cmp(addr, IP6_ADDR_ANY)) {
00334     addr = IP_ANY_TYPE;
00335   }
00336 #endif /* LWIP_IPV4 && LWIP_IPV6 */
00337 
00338   API_MSG_VAR_ALLOC(msg);
00339   API_MSG_VAR_REF(msg).conn = conn;
00340   API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
00341   API_MSG_VAR_REF(msg).msg.bc.port = port;
00342   err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg));
00343   API_MSG_VAR_FREE(msg);
00344 
00345   return err;
00346 }
00347 
00348 /**
00349  * @ingroup netconn_common
00350  * Bind a netconn to a specific interface and port.
00351  * Binding one netconn twice might not always be checked correctly!
00352  *
00353  * @param conn the netconn to bind
00354  * @param if_idx the local interface index to bind the netconn to
00355  * @return ERR_OK if bound, any other err_t on failure
00356  */
00357 err_t
00358 netconn_bind_if(struct netconn *conn, u8_t if_idx)
00359 {
00360   API_MSG_VAR_DECLARE(msg);
00361   err_t err;
00362 
00363   LWIP_ERROR("netconn_bind_if: invalid conn", (conn != NULL), return ERR_ARG;);
00364 
00365   API_MSG_VAR_ALLOC(msg);
00366   API_MSG_VAR_REF(msg).conn = conn;
00367   API_MSG_VAR_REF(msg).msg.bc.if_idx = if_idx;
00368   err = netconn_apimsg(lwip_netconn_do_bind_if, &API_MSG_VAR_REF(msg));
00369   API_MSG_VAR_FREE(msg);
00370 
00371   return err;
00372 }
00373 
00374 /**
00375  * @ingroup netconn_common
00376  * Connect a netconn to a specific remote IP address and port.
00377  *
00378  * @param conn the netconn to connect
00379  * @param addr the remote IP address to connect to
00380  * @param port the remote port to connect to (no used for RAW)
00381  * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
00382  */
00383 err_t
00384 netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port)
00385 {
00386   API_MSG_VAR_DECLARE(msg);
00387   err_t err;
00388 
00389   LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
00390 
00391 #if LWIP_IPV4
00392   /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
00393   if (addr == NULL) {
00394     addr = IP4_ADDR_ANY;
00395   }
00396 #endif /* LWIP_IPV4 */
00397 
00398   API_MSG_VAR_ALLOC(msg);
00399   API_MSG_VAR_REF(msg).conn = conn;
00400   API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
00401   API_MSG_VAR_REF(msg).msg.bc.port = port;
00402   err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg));
00403   API_MSG_VAR_FREE(msg);
00404 
00405   return err;
00406 }
00407 
00408 /**
00409  * @ingroup netconn_udp
00410  * Disconnect a netconn from its current peer (only valid for UDP netconns).
00411  *
00412  * @param conn the netconn to disconnect
00413  * @return See @ref err_t
00414  */
00415 err_t
00416 netconn_disconnect(struct netconn *conn)
00417 {
00418   API_MSG_VAR_DECLARE(msg);
00419   err_t err;
00420 
00421   LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
00422 
00423   API_MSG_VAR_ALLOC(msg);
00424   API_MSG_VAR_REF(msg).conn = conn;
00425   err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg));
00426   API_MSG_VAR_FREE(msg);
00427 
00428   return err;
00429 }
00430 
00431 /**
00432  * @ingroup netconn_tcp
00433  * Set a TCP netconn into listen mode
00434  *
00435  * @param conn the tcp netconn to set to listen mode
00436  * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
00437  * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
00438  *         don't return any error (yet?))
00439  */
00440 err_t
00441 netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
00442 {
00443 #if LWIP_TCP
00444   API_MSG_VAR_DECLARE(msg);
00445   err_t err;
00446 
00447   /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
00448   LWIP_UNUSED_ARG(backlog);
00449 
00450   LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
00451 
00452   API_MSG_VAR_ALLOC(msg);
00453   API_MSG_VAR_REF(msg).conn = conn;
00454 #if TCP_LISTEN_BACKLOG
00455   API_MSG_VAR_REF(msg).msg.lb.backlog = backlog;
00456 #endif /* TCP_LISTEN_BACKLOG */
00457   err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg));
00458   API_MSG_VAR_FREE(msg);
00459 
00460   return err;
00461 #else /* LWIP_TCP */
00462   LWIP_UNUSED_ARG(conn);
00463   LWIP_UNUSED_ARG(backlog);
00464   return ERR_ARG;
00465 #endif /* LWIP_TCP */
00466 }
00467 
00468 /**
00469  * @ingroup netconn_tcp
00470  * Accept a new connection on a TCP listening netconn.
00471  *
00472  * @param conn the TCP listen netconn
00473  * @param new_conn pointer where the new connection is stored
00474  * @return ERR_OK if a new connection has been received or an error
00475  *                code otherwise
00476  */
00477 err_t
00478 netconn_accept(struct netconn *conn, struct netconn **new_conn)
00479 {
00480 #if LWIP_TCP
00481   err_t err;
00482   void *accept_ptr;
00483   struct netconn *newconn;
00484 #if TCP_LISTEN_BACKLOG
00485   API_MSG_VAR_DECLARE(msg);
00486 #endif /* TCP_LISTEN_BACKLOG */
00487 
00488   LWIP_ERROR("netconn_accept: invalid pointer",    (new_conn != NULL),                  return ERR_ARG;);
00489   *new_conn = NULL;
00490   LWIP_ERROR("netconn_accept: invalid conn",       (conn != NULL),                      return ERR_ARG;);
00491 
00492   /* NOTE: Although the opengroup spec says a pending error shall be returned to
00493            send/recv/getsockopt(SO_ERROR) only, we return it for listening
00494            connections also, to handle embedded-system errors */
00495   err = netconn_err(conn);
00496   if (err != ERR_OK) {
00497     /* return pending error */
00498     return err;
00499   }
00500   if (!NETCONN_ACCEPTMBOX_WAITABLE(conn)) {
00501     /* don't accept if closed: this might block the application task
00502        waiting on acceptmbox forever! */
00503     return ERR_CLSD;
00504   }
00505 
00506   API_MSG_VAR_ALLOC_ACCEPT(msg);
00507 
00508   NETCONN_MBOX_WAITING_INC(conn);
00509   if (netconn_is_nonblocking(conn)) {
00510     if (sys_arch_mbox_tryfetch(&conn->acceptmbox, &accept_ptr) == SYS_ARCH_TIMEOUT) {
00511       API_MSG_VAR_FREE_ACCEPT(msg);
00512       NETCONN_MBOX_WAITING_DEC(conn);
00513       return ERR_WOULDBLOCK;
00514     }
00515   } else {
00516 #if LWIP_SO_RCVTIMEO
00517     if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
00518       API_MSG_VAR_FREE_ACCEPT(msg);
00519       NETCONN_MBOX_WAITING_DEC(conn);
00520       return ERR_TIMEOUT;
00521     }
00522 #else
00523     sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0);
00524 #endif /* LWIP_SO_RCVTIMEO*/
00525   }
00526   NETCONN_MBOX_WAITING_DEC(conn);
00527 #if LWIP_NETCONN_FULLDUPLEX
00528   if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
00529     if (lwip_netconn_is_deallocated_msg(accept_ptr)) {
00530       /* the netconn has been closed from another thread */
00531       API_MSG_VAR_FREE_ACCEPT(msg);
00532       return ERR_CONN;
00533     }
00534   }
00535 #endif
00536 
00537   /* Register event with callback */
00538   API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
00539 
00540   if (lwip_netconn_is_err_msg(accept_ptr, &err)) {
00541     /* a connection has been aborted: e.g. out of pcbs or out of netconns during accept */
00542     API_MSG_VAR_FREE_ACCEPT(msg);
00543     return err;
00544   }
00545   if (accept_ptr == NULL) {
00546     /* connection has been aborted */
00547     API_MSG_VAR_FREE_ACCEPT(msg);
00548     return ERR_CLSD;
00549   }
00550   newconn = (struct netconn *)accept_ptr;
00551 #if TCP_LISTEN_BACKLOG
00552   /* Let the stack know that we have accepted the connection. */
00553   API_MSG_VAR_REF(msg).conn = newconn;
00554   /* don't care for the return value of lwip_netconn_do_recv */
00555   netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg));
00556   API_MSG_VAR_FREE(msg);
00557 #endif /* TCP_LISTEN_BACKLOG */
00558 
00559   *new_conn = newconn;
00560   /* don't set conn->last_err: it's only ERR_OK, anyway */
00561   return ERR_OK;
00562 #else /* LWIP_TCP */
00563   LWIP_UNUSED_ARG(conn);
00564   LWIP_UNUSED_ARG(new_conn);
00565   return ERR_ARG;
00566 #endif /* LWIP_TCP */
00567 }
00568 
00569 /**
00570  * @ingroup netconn_common
00571  * Receive data: actual implementation that doesn't care whether pbuf or netbuf
00572  * is received (this is internal, it's just here for describing common errors)
00573  *
00574  * @param conn the netconn from which to receive data
00575  * @param new_buf pointer where a new pbuf/netbuf is stored when received data
00576  * @param apiflags flags that control function behaviour. For now only:
00577  * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
00578  * @return ERR_OK if data has been received, an error code otherwise (timeout,
00579  *                memory error or another error)
00580  *         ERR_CONN if not connected
00581  *         ERR_CLSD if TCP connection has been closed
00582  *         ERR_WOULDBLOCK if the netconn is nonblocking but would block to wait for data
00583  *         ERR_TIMEOUT if the netconn has a receive timeout and no data was received
00584  */
00585 static err_t
00586 netconn_recv_data(struct netconn *conn, void **new_buf, u8_t apiflags)
00587 {
00588   void *buf = NULL;
00589   u16_t len;
00590 
00591   LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
00592   *new_buf = NULL;
00593   LWIP_ERROR("netconn_recv: invalid conn",    (conn != NULL),    return ERR_ARG;);
00594 
00595   if (!NETCONN_RECVMBOX_WAITABLE(conn)) {
00596     err_t err = netconn_err(conn);
00597     if (err != ERR_OK) {
00598       /* return pending error */
00599       return err;
00600     }
00601     return ERR_CONN;
00602   }
00603 
00604   NETCONN_MBOX_WAITING_INC(conn);
00605   if (netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK) ||
00606       (conn->flags & NETCONN_FLAG_MBOXCLOSED) || (conn->pending_err != ERR_OK)) {
00607     if (sys_arch_mbox_tryfetch(&conn->recvmbox, &buf) == SYS_ARCH_TIMEOUT) {
00608       err_t err;
00609       NETCONN_MBOX_WAITING_DEC(conn);
00610       err = netconn_err(conn);
00611       if (err != ERR_OK) {
00612         /* return pending error */
00613         return err;
00614       }
00615       if (conn->flags & NETCONN_FLAG_MBOXCLOSED) {
00616         return ERR_CONN;
00617       }
00618       return ERR_WOULDBLOCK;
00619     }
00620   } else {
00621 #if LWIP_SO_RCVTIMEO
00622     if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
00623       NETCONN_MBOX_WAITING_DEC(conn);
00624       return ERR_TIMEOUT;
00625     }
00626 #else
00627     sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
00628 #endif /* LWIP_SO_RCVTIMEO*/
00629   }
00630   NETCONN_MBOX_WAITING_DEC(conn);
00631 #if LWIP_NETCONN_FULLDUPLEX
00632   if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
00633     if (lwip_netconn_is_deallocated_msg(buf)) {
00634       /* the netconn has been closed from another thread */
00635       API_MSG_VAR_FREE_ACCEPT(msg);
00636       return ERR_CONN;
00637     }
00638   }
00639 #endif
00640 
00641 #if LWIP_TCP
00642 #if (LWIP_UDP || LWIP_RAW)
00643   if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
00644 #endif /* (LWIP_UDP || LWIP_RAW) */
00645   {
00646     err_t err;
00647     /* Check if this is an error message or a pbuf */
00648     if (lwip_netconn_is_err_msg(buf, &err)) {
00649       /* new_buf has been zeroed above already */
00650       if (err == ERR_CLSD) {
00651         /* connection closed translates to ERR_OK with *new_buf == NULL */
00652         return ERR_OK;
00653       }
00654       return err;
00655     }
00656     len = ((struct pbuf *)buf)->tot_len;
00657   }
00658 #endif /* LWIP_TCP */
00659 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
00660   else
00661 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
00662 #if (LWIP_UDP || LWIP_RAW)
00663   {
00664     LWIP_ASSERT("buf != NULL", buf != NULL);
00665     len = netbuf_len((struct netbuf *)buf);
00666   }
00667 #endif /* (LWIP_UDP || LWIP_RAW) */
00668 
00669 #if LWIP_SO_RCVBUF
00670   SYS_ARCH_DEC(conn->recv_avail, len);
00671 #endif /* LWIP_SO_RCVBUF */
00672   /* Register event with callback */
00673   API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
00674 
00675   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
00676 
00677   *new_buf = buf;
00678   /* don't set conn->last_err: it's only ERR_OK, anyway */
00679   return ERR_OK;
00680 }
00681 
00682 #if LWIP_TCP
00683 static err_t
00684 netconn_tcp_recvd_msg(struct netconn *conn, size_t len, struct api_msg *msg)
00685 {
00686   LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
00687              NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
00688 
00689   msg->conn = conn;
00690   msg->msg.r.len = len;
00691 
00692   return netconn_apimsg(lwip_netconn_do_recv, msg);
00693 }
00694 
00695 err_t
00696 netconn_tcp_recvd(struct netconn *conn, size_t len)
00697 {
00698   err_t err;
00699   API_MSG_VAR_DECLARE(msg);
00700   LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
00701              NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
00702 
00703   API_MSG_VAR_ALLOC(msg);
00704   err = netconn_tcp_recvd_msg(conn, len, &API_VAR_REF(msg));
00705   API_MSG_VAR_FREE(msg);
00706   return err;
00707 }
00708 
00709 static err_t
00710 netconn_recv_data_tcp(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags)
00711 {
00712   err_t err;
00713   struct pbuf *buf;
00714   API_MSG_VAR_DECLARE(msg);
00715 #if LWIP_MPU_COMPATIBLE
00716   msg = NULL;
00717 #endif
00718 
00719   if (!NETCONN_RECVMBOX_WAITABLE(conn)) {
00720     /* This only happens when calling this function more than once *after* receiving FIN */
00721     return ERR_CONN;
00722   }
00723   if (netconn_is_flag_set(conn, NETCONN_FIN_RX_PENDING)) {
00724     netconn_clear_flags(conn, NETCONN_FIN_RX_PENDING);
00725     goto handle_fin;
00726   }
00727 
00728   if (!(apiflags & NETCONN_NOAUTORCVD)) {
00729     /* need to allocate API message here so empty message pool does not result in event loss
00730       * see bug #47512: MPU_COMPATIBLE may fail on empty pool */
00731     API_MSG_VAR_ALLOC(msg);
00732   }
00733 
00734   err = netconn_recv_data(conn, (void **)new_buf, apiflags);
00735   if (err != ERR_OK) {
00736     if (!(apiflags & NETCONN_NOAUTORCVD)) {
00737       API_MSG_VAR_FREE(msg);
00738     }
00739     return err;
00740   }
00741   buf = *new_buf;
00742   if (!(apiflags & NETCONN_NOAUTORCVD)) {
00743     /* Let the stack know that we have taken the data. */
00744     u16_t len = buf ? buf->tot_len : 1;
00745     /* don't care for the return value of lwip_netconn_do_recv */
00746     /* @todo: this should really be fixed, e.g. by retrying in poll on error */
00747     netconn_tcp_recvd_msg(conn, len,  &API_VAR_REF(msg));
00748     API_MSG_VAR_FREE(msg);
00749   }
00750 
00751   /* If we are closed, we indicate that we no longer wish to use the socket */
00752   if (buf == NULL) {
00753     if (apiflags & NETCONN_NOFIN) {
00754       /* received a FIN but the caller cannot handle it right now:
00755          re-enqueue it and return "no data" */
00756       netconn_set_flags(conn, NETCONN_FIN_RX_PENDING);
00757       return ERR_WOULDBLOCK;
00758     } else {
00759 handle_fin:
00760       API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
00761       if (conn->pcb.ip == NULL) {
00762         /* race condition: RST during recv */
00763         err = netconn_err(conn);
00764         if (err != ERR_OK) {
00765           return err;
00766         }
00767         return ERR_RST;
00768       }
00769       /* RX side is closed, so deallocate the recvmbox */
00770       netconn_close_shutdown(conn, NETCONN_SHUT_RD);
00771       /* Don' store ERR_CLSD as conn->err since we are only half-closed */
00772       return ERR_CLSD;
00773     }
00774   }
00775   return err;
00776 }
00777 
00778 /**
00779  * @ingroup netconn_tcp
00780  * Receive data (in form of a pbuf) from a TCP netconn
00781  *
00782  * @param conn the netconn from which to receive data
00783  * @param new_buf pointer where a new pbuf is stored when received data
00784  * @return ERR_OK if data has been received, an error code otherwise (timeout,
00785  *                memory error or another error, @see netconn_recv_data)
00786  *         ERR_ARG if conn is not a TCP netconn
00787  */
00788 err_t
00789 netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
00790 {
00791   LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
00792              NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
00793 
00794   return netconn_recv_data_tcp(conn, new_buf, 0);
00795 }
00796 
00797 /**
00798  * @ingroup netconn_tcp
00799  * Receive data (in form of a pbuf) from a TCP netconn
00800  *
00801  * @param conn the netconn from which to receive data
00802  * @param new_buf pointer where a new pbuf is stored when received data
00803  * @param apiflags flags that control function behaviour. For now only:
00804  * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
00805  * @return ERR_OK if data has been received, an error code otherwise (timeout,
00806  *                memory error or another error, @see netconn_recv_data)
00807  *         ERR_ARG if conn is not a TCP netconn
00808  */
00809 err_t
00810 netconn_recv_tcp_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags)
00811 {
00812   LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
00813              NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
00814 
00815   return netconn_recv_data_tcp(conn, new_buf, apiflags);
00816 }
00817 #endif /* LWIP_TCP */
00818 
00819 /**
00820  * Receive data (in form of a netbuf) from a UDP or RAW netconn
00821  *
00822  * @param conn the netconn from which to receive data
00823  * @param new_buf pointer where a new netbuf is stored when received data
00824  * @return ERR_OK if data has been received, an error code otherwise (timeout,
00825  *                memory error or another error)
00826  *         ERR_ARG if conn is not a UDP/RAW netconn
00827  */
00828 err_t
00829 netconn_recv_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf)
00830 {
00831   LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) &&
00832              NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;);
00833 
00834   return netconn_recv_data(conn, (void **)new_buf, 0);
00835 }
00836 
00837 /**
00838  * Receive data (in form of a netbuf) from a UDP or RAW netconn
00839  *
00840  * @param conn the netconn from which to receive data
00841  * @param new_buf pointer where a new netbuf is stored when received data
00842  * @param apiflags flags that control function behaviour. For now only:
00843  * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
00844  * @return ERR_OK if data has been received, an error code otherwise (timeout,
00845  *                memory error or another error)
00846  *         ERR_ARG if conn is not a UDP/RAW netconn
00847  */
00848 err_t
00849 netconn_recv_udp_raw_netbuf_flags(struct netconn *conn, struct netbuf **new_buf, u8_t apiflags)
00850 {
00851   LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) &&
00852              NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;);
00853 
00854   return netconn_recv_data(conn, (void **)new_buf, apiflags);
00855 }
00856 
00857 /**
00858  * @ingroup netconn_common
00859  * Receive data (in form of a netbuf containing a packet buffer) from a netconn
00860  *
00861  * @param conn the netconn from which to receive data
00862  * @param new_buf pointer where a new netbuf is stored when received data
00863  * @return ERR_OK if data has been received, an error code otherwise (timeout,
00864  *                memory error or another error)
00865  */
00866 err_t
00867 netconn_recv(struct netconn *conn, struct netbuf **new_buf)
00868 {
00869 #if LWIP_TCP
00870   struct netbuf *buf = NULL;
00871   err_t err;
00872 #endif /* LWIP_TCP */
00873 
00874   LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
00875   *new_buf = NULL;
00876   LWIP_ERROR("netconn_recv: invalid conn",    (conn != NULL),    return ERR_ARG;);
00877 
00878 #if LWIP_TCP
00879 #if (LWIP_UDP || LWIP_RAW)
00880   if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
00881 #endif /* (LWIP_UDP || LWIP_RAW) */
00882   {
00883     struct pbuf *p = NULL;
00884     /* This is not a listening netconn, since recvmbox is set */
00885 
00886     buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
00887     if (buf == NULL) {
00888       return ERR_MEM;
00889     }
00890 
00891     err = netconn_recv_data_tcp(conn, &p, 0);
00892     if (err != ERR_OK) {
00893       memp_free(MEMP_NETBUF, buf);
00894       return err;
00895     }
00896     LWIP_ASSERT("p != NULL", p != NULL);
00897 
00898     buf->p = p;
00899     buf->ptr = p;
00900     buf->port = 0;
00901     ip_addr_set_zero(&buf->addr);
00902     *new_buf = buf;
00903     /* don't set conn->last_err: it's only ERR_OK, anyway */
00904     return ERR_OK;
00905   }
00906 #endif /* LWIP_TCP */
00907 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
00908   else
00909 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
00910   {
00911 #if (LWIP_UDP || LWIP_RAW)
00912     return netconn_recv_data(conn, (void **)new_buf, 0);
00913 #endif /* (LWIP_UDP || LWIP_RAW) */
00914   }
00915 }
00916 
00917 /**
00918  * @ingroup netconn_udp
00919  * Send data (in form of a netbuf) to a specific remote IP address and port.
00920  * Only to be used for UDP and RAW netconns (not TCP).
00921  *
00922  * @param conn the netconn over which to send data
00923  * @param buf a netbuf containing the data to send
00924  * @param addr the remote IP address to which to send the data
00925  * @param port the remote port to which to send the data
00926  * @return ERR_OK if data was sent, any other err_t on error
00927  */
00928 err_t
00929 netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port)
00930 {
00931   if (buf != NULL) {
00932     ip_addr_set(&buf->addr, addr);
00933     buf->port = port;
00934     return netconn_send(conn, buf);
00935   }
00936   return ERR_VAL;
00937 }
00938 
00939 /**
00940  * @ingroup netconn_udp
00941  * Send data over a UDP or RAW netconn (that is already connected).
00942  *
00943  * @param conn the UDP or RAW netconn over which to send data
00944  * @param buf a netbuf containing the data to send
00945  * @return ERR_OK if data was sent, any other err_t on error
00946  */
00947 err_t
00948 netconn_send(struct netconn *conn, struct netbuf *buf)
00949 {
00950   API_MSG_VAR_DECLARE(msg);
00951   err_t err;
00952 
00953   LWIP_ERROR("netconn_send: invalid conn",  (conn != NULL), return ERR_ARG;);
00954 
00955   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
00956 
00957   API_MSG_VAR_ALLOC(msg);
00958   API_MSG_VAR_REF(msg).conn = conn;
00959   API_MSG_VAR_REF(msg).msg.b = buf;
00960   err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg));
00961   API_MSG_VAR_FREE(msg);
00962 
00963   return err;
00964 }
00965 
00966 /**
00967  * @ingroup netconn_tcp
00968  * Send data over a TCP netconn.
00969  *
00970  * @param conn the TCP netconn over which to send data
00971  * @param dataptr pointer to the application buffer that contains the data to send
00972  * @param size size of the application data to send
00973  * @param apiflags combination of following flags :
00974  * - NETCONN_COPY: data will be copied into memory belonging to the stack
00975  * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
00976  * - NETCONN_DONTBLOCK: only write the data if all data can be written at once
00977  * @param bytes_written pointer to a location that receives the number of written bytes
00978  * @return ERR_OK if data was sent, any other err_t on error
00979  */
00980 err_t
00981 netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
00982                      u8_t apiflags, size_t *bytes_written)
00983 {
00984   struct netvector vector;
00985   vector.ptr = dataptr;
00986   vector.len = size;
00987   return netconn_write_vectors_partly(conn, &vector, 1, apiflags, bytes_written);
00988 }
00989 
00990 /**
00991  * Send vectorized data atomically over a TCP netconn.
00992  *
00993  * @param conn the TCP netconn over which to send data
00994  * @param vectors array of vectors containing data to send
00995  * @param vectorcnt number of vectors in the array
00996  * @param apiflags combination of following flags :
00997  * - NETCONN_COPY: data will be copied into memory belonging to the stack
00998  * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
00999  * - NETCONN_DONTBLOCK: only write the data if all data can be written at once
01000  * @param bytes_written pointer to a location that receives the number of written bytes
01001  * @return ERR_OK if data was sent, any other err_t on error
01002  */
01003 err_t
01004 netconn_write_vectors_partly(struct netconn *conn, struct netvector *vectors, u16_t vectorcnt,
01005                              u8_t apiflags, size_t *bytes_written)
01006 {
01007   API_MSG_VAR_DECLARE(msg);
01008   err_t err;
01009   u8_t dontblock;
01010   size_t size;
01011   int i;
01012 
01013   LWIP_ERROR("netconn_write: invalid conn",  (conn != NULL), return ERR_ARG;);
01014   LWIP_ERROR("netconn_write: invalid conn->type",  (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP), return ERR_VAL;);
01015   dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
01016 #if LWIP_SO_SNDTIMEO
01017   if (conn->send_timeout != 0) {
01018     dontblock = 1;
01019   }
01020 #endif /* LWIP_SO_SNDTIMEO */
01021   if (dontblock && !bytes_written) {
01022     /* This implies netconn_write() cannot be used for non-blocking send, since
01023        it has no way to return the number of bytes written. */
01024     return ERR_VAL;
01025   }
01026 
01027   /* sum up the total size */
01028   size = 0;
01029   for (i = 0; i < vectorcnt; i++) {
01030     size += vectors[i].len;
01031     if (size < vectors[i].len) {
01032       /* overflow */
01033       return ERR_VAL;
01034     }
01035   }
01036   if (size == 0) {
01037     return ERR_OK;
01038   } else if (size > SSIZE_MAX) {
01039     ssize_t limited;
01040     /* this is required by the socket layer (cannot send full size_t range) */
01041     if (!bytes_written) {
01042       return ERR_VAL;
01043     }
01044     /* limit the amount of data to send */
01045     limited = SSIZE_MAX;
01046     size = (size_t)limited;
01047   }
01048 
01049   API_MSG_VAR_ALLOC(msg);
01050   /* non-blocking write sends as much  */
01051   API_MSG_VAR_REF(msg).conn = conn;
01052   API_MSG_VAR_REF(msg).msg.w.vector = vectors;
01053   API_MSG_VAR_REF(msg).msg.w.vector_cnt = vectorcnt;
01054   API_MSG_VAR_REF(msg).msg.w.vector_off = 0;
01055   API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags;
01056   API_MSG_VAR_REF(msg).msg.w.len = size;
01057   API_MSG_VAR_REF(msg).msg.w.offset = 0;
01058 #if LWIP_SO_SNDTIMEO
01059   if (conn->send_timeout != 0) {
01060     /* get the time we started, which is later compared to
01061         sys_now() + conn->send_timeout */
01062     API_MSG_VAR_REF(msg).msg.w.time_started = sys_now();
01063   } else {
01064     API_MSG_VAR_REF(msg).msg.w.time_started = 0;
01065   }
01066 #endif /* LWIP_SO_SNDTIMEO */
01067 
01068   /* For locking the core: this _can_ be delayed on low memory/low send buffer,
01069      but if it is, this is done inside api_msg.c:do_write(), so we can use the
01070      non-blocking version here. */
01071   err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg));
01072   if (err == ERR_OK) {
01073     if (bytes_written != NULL) {
01074       *bytes_written = API_MSG_VAR_REF(msg).msg.w.offset;
01075     }
01076     /* for blocking, check all requested bytes were written, NOTE: send_timeout is
01077        treated as dontblock (see dontblock assignment above) */
01078     if (!dontblock) {
01079       LWIP_ASSERT("do_write failed to write all bytes", API_MSG_VAR_REF(msg).msg.w.offset == size);
01080     }
01081   }
01082   API_MSG_VAR_FREE(msg);
01083 
01084   return err;
01085 }
01086 
01087 /**
01088  * @ingroup netconn_tcp
01089  * Close or shutdown a TCP netconn (doesn't delete it).
01090  *
01091  * @param conn the TCP netconn to close or shutdown
01092  * @param how fully close or only shutdown one side?
01093  * @return ERR_OK if the netconn was closed, any other err_t on error
01094  */
01095 static err_t
01096 netconn_close_shutdown(struct netconn *conn, u8_t how)
01097 {
01098   API_MSG_VAR_DECLARE(msg);
01099   err_t err;
01100   LWIP_UNUSED_ARG(how);
01101 
01102   LWIP_ERROR("netconn_close: invalid conn",  (conn != NULL), return ERR_ARG;);
01103 
01104   API_MSG_VAR_ALLOC(msg);
01105   API_MSG_VAR_REF(msg).conn = conn;
01106 #if LWIP_TCP
01107   /* shutting down both ends is the same as closing */
01108   API_MSG_VAR_REF(msg).msg.sd.shut = how;
01109 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
01110   /* get the time we started, which is later compared to
01111      sys_now() + conn->send_timeout */
01112   API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
01113 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
01114   API_MSG_VAR_REF(msg).msg.sd.polls_left =
01115     ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
01116 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
01117 #endif /* LWIP_TCP */
01118   err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg));
01119   API_MSG_VAR_FREE(msg);
01120 
01121   return err;
01122 }
01123 
01124 /**
01125  * @ingroup netconn_tcp
01126  * Close a TCP netconn (doesn't delete it).
01127  *
01128  * @param conn the TCP netconn to close
01129  * @return ERR_OK if the netconn was closed, any other err_t on error
01130  */
01131 err_t
01132 netconn_close(struct netconn *conn)
01133 {
01134   /* shutting down both ends is the same as closing */
01135   return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
01136 }
01137 
01138 /**
01139  * @ingroup netconn_common
01140  * Get and reset pending error on a netconn
01141  *
01142  * @param conn the netconn to get the error from
01143  * @return and pending error or ERR_OK if no error was pending
01144  */
01145 err_t
01146 netconn_err(struct netconn *conn)
01147 {
01148   err_t err;
01149   SYS_ARCH_DECL_PROTECT(lev);
01150   if (conn == NULL) {
01151     return ERR_OK;
01152   }
01153   SYS_ARCH_PROTECT(lev);
01154   err = conn->pending_err;
01155   conn->pending_err = ERR_OK;
01156   SYS_ARCH_UNPROTECT(lev);
01157   return err;
01158 }
01159 
01160 /**
01161  * @ingroup netconn_tcp
01162  * Shut down one or both sides of a TCP netconn (doesn't delete it).
01163  *
01164  * @param conn the TCP netconn to shut down
01165  * @param shut_rx shut down the RX side (no more read possible after this)
01166  * @param shut_tx shut down the TX side (no more write possible after this)
01167  * @return ERR_OK if the netconn was closed, any other err_t on error
01168  */
01169 err_t
01170 netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
01171 {
01172   return netconn_close_shutdown(conn, (u8_t)((shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)));
01173 }
01174 
01175 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
01176 /**
01177  * @ingroup netconn_udp
01178  * Join multicast groups for UDP netconns.
01179  *
01180  * @param conn the UDP netconn for which to change multicast addresses
01181  * @param multiaddr IP address of the multicast group to join or leave
01182  * @param netif_addr the IP address of the network interface on which to send
01183  *                  the igmp message
01184  * @param join_or_leave flag whether to send a join- or leave-message
01185  * @return ERR_OK if the action was taken, any err_t on error
01186  */
01187 err_t
01188 netconn_join_leave_group(struct netconn *conn,
01189                          const ip_addr_t *multiaddr,
01190                          const ip_addr_t *netif_addr,
01191                          enum netconn_igmp join_or_leave)
01192 {
01193   API_MSG_VAR_DECLARE(msg);
01194   err_t err;
01195 
01196   LWIP_ERROR("netconn_join_leave_group: invalid conn",  (conn != NULL), return ERR_ARG;);
01197 
01198   API_MSG_VAR_ALLOC(msg);
01199 
01200 #if LWIP_IPV4
01201   /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
01202   if (multiaddr == NULL) {
01203     multiaddr = IP4_ADDR_ANY;
01204   }
01205   if (netif_addr == NULL) {
01206     netif_addr = IP4_ADDR_ANY;
01207   }
01208 #endif /* LWIP_IPV4 */
01209 
01210   API_MSG_VAR_REF(msg).conn = conn;
01211   API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
01212   API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr);
01213   API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
01214   err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg));
01215   API_MSG_VAR_FREE(msg);
01216 
01217   return err;
01218 }
01219 /**
01220  * @ingroup netconn_udp
01221  * Join multicast groups for UDP netconns.
01222  *
01223  * @param conn the UDP netconn for which to change multicast addresses
01224  * @param multiaddr IP address of the multicast group to join or leave
01225  * @param if_idx the index of the netif
01226  * @param join_or_leave flag whether to send a join- or leave-message
01227  * @return ERR_OK if the action was taken, any err_t on error
01228  */
01229 err_t
01230 netconn_join_leave_group_netif(struct netconn *conn,
01231                                const ip_addr_t *multiaddr,
01232                                u8_t if_idx,
01233                                enum netconn_igmp join_or_leave)
01234 {
01235   API_MSG_VAR_DECLARE(msg);
01236   err_t err;
01237 
01238   LWIP_ERROR("netconn_join_leave_group: invalid conn",  (conn != NULL), return ERR_ARG;);
01239 
01240   API_MSG_VAR_ALLOC(msg);
01241 
01242 #if LWIP_IPV4
01243   /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
01244   if (multiaddr == NULL) {
01245     multiaddr = IP4_ADDR_ANY;
01246   }
01247   if (if_idx == NETIF_NO_INDEX) {
01248     return ERR_IF;
01249   }
01250 #endif /* LWIP_IPV4 */
01251 
01252   API_MSG_VAR_REF(msg).conn = conn;
01253   API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
01254   API_MSG_VAR_REF(msg).msg.jl.if_idx = if_idx;
01255   API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
01256   err = netconn_apimsg(lwip_netconn_do_join_leave_group_netif, &API_MSG_VAR_REF(msg));
01257   API_MSG_VAR_FREE(msg);
01258 
01259   return err;
01260 }
01261 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
01262 
01263 #if LWIP_DNS
01264 #if LWIP_FULL_DNS
01265 
01266 /**
01267  * @ingroup netconn_common
01268  * Execute a DNS query, only one IP address is returned
01269  *
01270  * @param name a string representation of the DNS host name to query
01271  * @param addr a preallocated ip_addr_t where to store the resolved IP address
01272  * @param dns_addrtype IP address type (IPv4 / IPv6)
01273  * @return ERR_OK: resolving succeeded
01274  *         ERR_MEM: memory error, try again later
01275  *         ERR_ARG: dns client not initialized or invalid hostname
01276  *         ERR_VAL: dns server response was invalid
01277  */
01278 #if LWIP_IPV4 && LWIP_IPV6
01279 err_t
01280 netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype)
01281 #else
01282 err_t
01283 netconn_gethostbyname(const char *name, ip_addr_t *addr)
01284 #endif
01285 {
01286   API_VAR_DECLARE(struct dns_api_msg, msg);
01287 #if !LWIP_MPU_COMPATIBLE
01288   sys_sem_t sem;
01289 #endif /* LWIP_MPU_COMPATIBLE */
01290   err_t err;
01291   err_t cberr;
01292 
01293   LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
01294   LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
01295 #if LWIP_MPU_COMPATIBLE
01296   if (strlen(name) >= DNS_MAX_NAME_LENGTH) {
01297     return ERR_ARG;
01298   }
01299 #endif
01300 
01301 #ifdef LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE
01302 #if LWIP_IPV4 && LWIP_IPV6
01303   if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, dns_addrtype, &err)) {
01304 #else
01305   if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, NETCONN_DNS_DEFAULT, &err)) {
01306 #endif /* LWIP_IPV4 && LWIP_IPV6 */
01307     return err;
01308   }
01309 #endif /* LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE */
01310 
01311   API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM);
01312 #if LWIP_MPU_COMPATIBLE
01313   strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH - 1);
01314   API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH - 1] = 0;
01315 #else /* LWIP_MPU_COMPATIBLE */
01316   msg.err = &err;
01317   msg.sem = &sem;
01318   API_VAR_REF(msg).addr = API_VAR_REF(addr);
01319   API_VAR_REF(msg).name = name;
01320 #endif /* LWIP_MPU_COMPATIBLE */
01321 #if LWIP_IPV4 && LWIP_IPV6
01322   API_VAR_REF(msg).dns_addrtype = dns_addrtype;
01323 #endif /* LWIP_IPV4 && LWIP_IPV6 */
01324 #if LWIP_NETCONN_SEM_PER_THREAD
01325   API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET();
01326 #else /* LWIP_NETCONN_SEM_PER_THREAD*/
01327   err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0);
01328   if (err != ERR_OK) {
01329     API_VAR_FREE(MEMP_DNS_API_MSG, msg);
01330     return err;
01331   }
01332 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
01333 
01334   cberr = tcpip_send_msg_wait_sem(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg), API_EXPR_REF(API_VAR_REF(msg).sem));
01335 #if !LWIP_NETCONN_SEM_PER_THREAD
01336   sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
01337 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
01338   if (cberr != ERR_OK) {
01339     API_VAR_FREE(MEMP_DNS_API_MSG, msg);
01340     return cberr;
01341   }
01342 
01343 #if LWIP_MPU_COMPATIBLE
01344   *addr = msg->addr;
01345   err = msg->err;
01346 #endif /* LWIP_MPU_COMPATIBLE */
01347 
01348   API_VAR_FREE(MEMP_DNS_API_MSG, msg);
01349   return err;
01350 }
01351 
01352 #endif /* LWIP_FULL_DNS */
01353 #endif /* LWIP_DNS*/
01354 
01355 #if LWIP_NETCONN_SEM_PER_THREAD
01356 void
01357 netconn_thread_init(void)
01358 {
01359   sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
01360   if ((sem == NULL) || !sys_sem_valid(sem)) {
01361     /* call alloc only once */
01362     LWIP_NETCONN_THREAD_SEM_ALLOC();
01363     LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET()));
01364   }
01365 }
01366 
01367 void
01368 netconn_thread_cleanup(void)
01369 {
01370   sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
01371   if ((sem != NULL) && sys_sem_valid(sem)) {
01372     /* call free only once */
01373     LWIP_NETCONN_THREAD_SEM_FREE();
01374   }
01375 }
01376 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
01377 
01378 #endif /* LWIP_NETCONN */