STM32F7 Ethernet interface for nucleo STM32F767

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 #include <string.h>
00073 
00074 #define API_MSG_VAR_REF(name)               API_VAR_REF(name)
00075 #define API_MSG_VAR_DECLARE(name)           API_VAR_DECLARE(struct api_msg, name)
00076 #define API_MSG_VAR_ALLOC(name)             API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, ERR_MEM)
00077 #define API_MSG_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, NULL)
00078 #define API_MSG_VAR_FREE(name)              API_VAR_FREE(MEMP_API_MSG, name)
00079 
00080 static err_t netconn_close_shutdown(struct netconn *conn, u8_t how);
00081 
00082 /**
00083  * Call the lower part of a netconn_* function
00084  * This function is then running in the thread context
00085  * of tcpip_thread and has exclusive access to lwIP core code.
00086  *
00087  * @param fn function to call
00088  * @param apimsg a struct containing the function to call and its parameters
00089  * @return ERR_OK if the function was called, another err_t if not
00090  */
00091 static err_t
00092 netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg)
00093 {
00094   err_t err;
00095 
00096 #ifdef LWIP_DEBUG
00097   /* catch functions that don't set err */
00098   apimsg->err = ERR_VAL;
00099 #endif /* LWIP_DEBUG */
00100 
00101 #if LWIP_NETCONN_SEM_PER_THREAD
00102   apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
00103 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
00104 
00105   err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg));
00106   if (err == ERR_OK) {
00107     return apimsg->err;
00108   }
00109   return err;
00110 }
00111 
00112 /**
00113  * Create a new netconn (of a specific type) that has a callback function.
00114  * The corresponding pcb is also created.
00115  *
00116  * @param t the type of 'connection' to create (@see enum netconn_type)
00117  * @param proto the IP protocol for RAW IP pcbs
00118  * @param callback a function to call on status changes (RX available, TX'ed)
00119  * @return a newly allocated struct netconn or
00120  *         NULL on memory error
00121  */
00122 struct netconn*
00123 netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
00124 {
00125   struct netconn *conn;
00126   API_MSG_VAR_DECLARE(msg);
00127   API_MSG_VAR_ALLOC_RETURN_NULL(msg);
00128 
00129   conn = netconn_alloc(t, callback);
00130   if (conn != NULL) {
00131     err_t err;
00132 
00133     API_MSG_VAR_REF(msg).msg.n.proto = proto;
00134     API_MSG_VAR_REF(msg).conn = conn;
00135     err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg));
00136     if (err != ERR_OK) {
00137       LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
00138       LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
00139 #if LWIP_TCP
00140       LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
00141 #endif /* LWIP_TCP */
00142 #if !LWIP_NETCONN_SEM_PER_THREAD
00143       LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
00144       sys_sem_free(&conn->op_completed);
00145 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
00146       sys_mbox_free(&conn->recvmbox);
00147       memp_free(MEMP_NETCONN, conn);
00148       API_MSG_VAR_FREE(msg);
00149       return NULL;
00150     }
00151   }
00152   API_MSG_VAR_FREE(msg);
00153   return conn;
00154 }
00155 
00156 /**
00157  * @ingroup netconn_common
00158  * Close a netconn 'connection' and free its resources.
00159  * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
00160  * after this returns.
00161  *
00162  * @param conn the netconn to delete
00163  * @return ERR_OK if the connection was deleted
00164  */
00165 err_t
00166 netconn_delete(struct netconn *conn)
00167 {
00168   err_t err;
00169   API_MSG_VAR_DECLARE(msg);
00170 
00171   /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
00172   if (conn == NULL) {
00173     return ERR_OK;
00174   }
00175 
00176   API_MSG_VAR_ALLOC(msg);
00177   API_MSG_VAR_REF(msg).conn = conn;
00178 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
00179   /* get the time we started, which is later compared to
00180      sys_now() + conn->send_timeout */
00181   API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
00182 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
00183 #if LWIP_TCP
00184   API_MSG_VAR_REF(msg).msg.sd.polls_left =
00185     ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
00186 #endif /* LWIP_TCP */
00187 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
00188   err = netconn_apimsg(lwip_netconn_do_delconn, &API_MSG_VAR_REF(msg));
00189   API_MSG_VAR_FREE(msg);
00190 
00191   if (err != ERR_OK) {
00192     return err;
00193   }
00194 
00195   netconn_free(conn);
00196 
00197   return ERR_OK;
00198 }
00199 
00200 /**
00201  * Get the local or remote IP address and port of a netconn.
00202  * For RAW netconns, this returns the protocol instead of a port!
00203  *
00204  * @param conn the netconn to query
00205  * @param addr a pointer to which to save the IP address
00206  * @param port a pointer to which to save the port (or protocol for RAW)
00207  * @param local 1 to get the local IP address, 0 to get the remote one
00208  * @return ERR_CONN for invalid connections
00209  *         ERR_OK if the information was retrieved
00210  */
00211 err_t
00212 netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
00213 {
00214   API_MSG_VAR_DECLARE(msg);
00215   err_t err;
00216 
00217   LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
00218   LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
00219   LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
00220 
00221   API_MSG_VAR_ALLOC(msg);
00222   API_MSG_VAR_REF(msg).conn = conn;
00223   API_MSG_VAR_REF(msg).msg.ad.local = local;
00224 #if LWIP_MPU_COMPATIBLE
00225   err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg));
00226   *addr = msg->msg.ad.ipaddr;
00227   *port = msg->msg.ad.port;
00228 #else /* LWIP_MPU_COMPATIBLE */
00229   msg.msg.ad.ipaddr = addr;
00230   msg.msg.ad.port = port;
00231   err = netconn_apimsg(lwip_netconn_do_getaddr, &msg);
00232 #endif /* LWIP_MPU_COMPATIBLE */
00233   API_MSG_VAR_FREE(msg);
00234 
00235   return err;
00236 }
00237 
00238 /**
00239  * @ingroup netconn_common
00240  * Bind a netconn to a specific local IP address and port.
00241  * Binding one netconn twice might not always be checked correctly!
00242  *
00243  * @param conn the netconn to bind
00244  * @param addr the local IP address to bind the netconn to 
00245  *             (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses)
00246  * @param port the local port to bind the netconn to (not used for RAW)
00247  * @return ERR_OK if bound, any other err_t on failure
00248  */
00249 err_t
00250 netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port)
00251 {
00252   API_MSG_VAR_DECLARE(msg);
00253   err_t err;
00254   
00255   LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
00256 
00257 #if LWIP_IPV4
00258   /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
00259   if (addr == NULL) {
00260     addr = IP4_ADDR_ANY;
00261   }
00262 #endif /* LWIP_IPV4 */
00263   
00264 #if LWIP_IPV4 && LWIP_IPV6
00265   /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY,
00266    * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind
00267    */
00268   if ((netconn_get_ipv6only(conn) == 0) &&
00269      ip_addr_cmp(addr, IP6_ADDR_ANY)) {
00270     addr = IP_ANY_TYPE;
00271   }
00272 #endif /* LWIP_IPV4 && LWIP_IPV6 */
00273 
00274   API_MSG_VAR_ALLOC(msg);
00275   API_MSG_VAR_REF(msg).conn = conn;
00276   API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
00277   API_MSG_VAR_REF(msg).msg.bc.port = port;
00278   err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg));
00279   API_MSG_VAR_FREE(msg);
00280 
00281   return err;
00282 }
00283 
00284 /**
00285  * @ingroup netconn_common
00286  * Connect a netconn to a specific remote IP address and port.
00287  *
00288  * @param conn the netconn to connect
00289  * @param addr the remote IP address to connect to
00290  * @param port the remote port to connect to (no used for RAW)
00291  * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
00292  */
00293 err_t
00294 netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port)
00295 {
00296   API_MSG_VAR_DECLARE(msg);
00297   err_t err;
00298 
00299   LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
00300 
00301 #if LWIP_IPV4
00302   /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
00303   if (addr == NULL) {
00304     addr = IP4_ADDR_ANY;
00305   }
00306 #endif /* LWIP_IPV4 */
00307 
00308   API_MSG_VAR_ALLOC(msg);
00309   API_MSG_VAR_REF(msg).conn = conn;
00310   API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
00311   API_MSG_VAR_REF(msg).msg.bc.port = port;
00312   err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg));
00313   API_MSG_VAR_FREE(msg);
00314 
00315   return err;
00316 }
00317 
00318 /**
00319  * @ingroup netconn_udp
00320  * Disconnect a netconn from its current peer (only valid for UDP netconns).
00321  *
00322  * @param conn the netconn to disconnect
00323  * @return See @ref err_t
00324  */
00325 err_t
00326 netconn_disconnect(struct netconn *conn)
00327 {
00328   API_MSG_VAR_DECLARE(msg);
00329   err_t err;
00330 
00331   LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
00332 
00333   API_MSG_VAR_ALLOC(msg);
00334   API_MSG_VAR_REF(msg).conn = conn;
00335   err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg));
00336   API_MSG_VAR_FREE(msg);
00337 
00338   return err;
00339 }
00340 
00341 /**
00342  * @ingroup netconn_tcp
00343  * Set a TCP netconn into listen mode
00344  *
00345  * @param conn the tcp netconn to set to listen mode
00346  * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
00347  * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
00348  *         don't return any error (yet?))
00349  */
00350 err_t
00351 netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
00352 {
00353 #if LWIP_TCP
00354   API_MSG_VAR_DECLARE(msg);
00355   err_t err;
00356 
00357   /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
00358   LWIP_UNUSED_ARG(backlog);
00359 
00360   LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
00361 
00362   API_MSG_VAR_ALLOC(msg);
00363   API_MSG_VAR_REF(msg).conn = conn;
00364 #if TCP_LISTEN_BACKLOG
00365   API_MSG_VAR_REF(msg).msg.lb.backlog = backlog;
00366 #endif /* TCP_LISTEN_BACKLOG */
00367   err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg));
00368   API_MSG_VAR_FREE(msg);
00369 
00370   return err;
00371 #else /* LWIP_TCP */
00372   LWIP_UNUSED_ARG(conn);
00373   LWIP_UNUSED_ARG(backlog);
00374   return ERR_ARG;
00375 #endif /* LWIP_TCP */
00376 }
00377 
00378 /**
00379  * @ingroup netconn_tcp
00380  * Accept a new connection on a TCP listening netconn.
00381  *
00382  * @param conn the TCP listen netconn
00383  * @param new_conn pointer where the new connection is stored
00384  * @return ERR_OK if a new connection has been received or an error
00385  *                code otherwise
00386  */
00387 err_t
00388 netconn_accept(struct netconn *conn, struct netconn **new_conn)
00389 {
00390 #if LWIP_TCP
00391   void *accept_ptr;
00392   struct netconn *newconn;
00393 #if TCP_LISTEN_BACKLOG
00394   API_MSG_VAR_DECLARE(msg);
00395 #endif /* TCP_LISTEN_BACKLOG */
00396 
00397   LWIP_ERROR("netconn_accept: invalid pointer",    (new_conn != NULL),                  return ERR_ARG;);
00398   *new_conn = NULL;
00399   LWIP_ERROR("netconn_accept: invalid conn",       (conn != NULL),                      return ERR_ARG;);
00400 
00401   if (ERR_IS_FATAL(conn->last_err)) {
00402     /* don't recv on fatal errors: this might block the application task
00403        waiting on acceptmbox forever! */
00404     return conn->last_err;
00405   }
00406   if (!sys_mbox_valid(&conn->acceptmbox)) {
00407     return ERR_CLSD;
00408   }
00409 
00410 #if TCP_LISTEN_BACKLOG
00411   API_MSG_VAR_ALLOC(msg);
00412 #endif /* TCP_LISTEN_BACKLOG */
00413 
00414 #if LWIP_SO_RCVTIMEO
00415   if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
00416 #if TCP_LISTEN_BACKLOG
00417     API_MSG_VAR_FREE(msg);
00418 #endif /* TCP_LISTEN_BACKLOG */
00419     return ERR_TIMEOUT;
00420   }
00421 #else
00422   sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0);
00423 #endif /* LWIP_SO_RCVTIMEO*/
00424   newconn = (struct netconn *)accept_ptr;
00425   /* Register event with callback */
00426   API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
00427 
00428   if (accept_ptr == &netconn_aborted) {
00429     /* a connection has been aborted: out of pcbs or out of netconns during accept */
00430     /* @todo: set netconn error, but this would be fatal and thus block further accepts */
00431 #if TCP_LISTEN_BACKLOG
00432     API_MSG_VAR_FREE(msg);
00433 #endif /* TCP_LISTEN_BACKLOG */
00434     return ERR_ABRT;
00435   }
00436   if (newconn == NULL) {
00437     /* connection has been aborted */
00438     /* in this special case, we set the netconn error from application thread, as
00439        on a ready-to-accept listening netconn, there should not be anything running
00440        in tcpip_thread */
00441     NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
00442 #if TCP_LISTEN_BACKLOG
00443     API_MSG_VAR_FREE(msg);
00444 #endif /* TCP_LISTEN_BACKLOG */
00445     return ERR_CLSD;
00446   }
00447 #if TCP_LISTEN_BACKLOG
00448   /* Let the stack know that we have accepted the connection. */
00449   API_MSG_VAR_REF(msg).conn = newconn;
00450   /* don't care for the return value of lwip_netconn_do_recv */
00451   netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg));
00452   API_MSG_VAR_FREE(msg);
00453 #endif /* TCP_LISTEN_BACKLOG */
00454 
00455   *new_conn = newconn;
00456   /* don't set conn->last_err: it's only ERR_OK, anyway */
00457   return ERR_OK;
00458 #else /* LWIP_TCP */
00459   LWIP_UNUSED_ARG(conn);
00460   LWIP_UNUSED_ARG(new_conn);
00461   return ERR_ARG;
00462 #endif /* LWIP_TCP */
00463 }
00464 
00465 /**
00466  * @ingroup netconn_common
00467  * Receive data: actual implementation that doesn't care whether pbuf or netbuf
00468  * is received
00469  *
00470  * @param conn the netconn from which to receive data
00471  * @param new_buf pointer where a new pbuf/netbuf is stored when received data
00472  * @return ERR_OK if data has been received, an error code otherwise (timeout,
00473  *                memory error or another error)
00474  */
00475 static err_t
00476 netconn_recv_data(struct netconn *conn, void **new_buf)
00477 {
00478   void *buf = NULL;
00479   u16_t len;
00480 #if LWIP_TCP
00481   API_MSG_VAR_DECLARE(msg);
00482 #if LWIP_MPU_COMPATIBLE
00483   msg = NULL;
00484 #endif
00485 #endif /* LWIP_TCP */
00486 
00487   LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
00488   *new_buf = NULL;
00489   LWIP_ERROR("netconn_recv: invalid conn",    (conn != NULL),    return ERR_ARG;);
00490 #if LWIP_TCP
00491 #if (LWIP_UDP || LWIP_RAW)
00492   if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
00493 #endif /* (LWIP_UDP || LWIP_RAW) */
00494   {
00495     if (!sys_mbox_valid(&conn->recvmbox)) {
00496       /* This happens when calling this function after receiving FIN */
00497       return sys_mbox_valid(&conn->acceptmbox) ? ERR_CONN : ERR_CLSD;
00498     }
00499   }
00500 #endif /* LWIP_TCP */
00501   LWIP_ERROR("netconn_recv: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
00502 
00503   if (ERR_IS_FATAL(conn->last_err)) {
00504     /* don't recv on fatal errors: this might block the application task
00505        waiting on recvmbox forever! */
00506     /* @todo: this does not allow us to fetch data that has been put into recvmbox
00507        before the fatal error occurred - is that a problem? */
00508     return conn->last_err;
00509   }
00510 #if LWIP_TCP
00511 #if (LWIP_UDP || LWIP_RAW)
00512   if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
00513 #endif /* (LWIP_UDP || LWIP_RAW) */
00514   {
00515     API_MSG_VAR_ALLOC(msg);
00516   }
00517 #endif /* LWIP_TCP */
00518 
00519 #if LWIP_SO_RCVTIMEO
00520   if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
00521 #if LWIP_TCP
00522 #if (LWIP_UDP || LWIP_RAW)
00523     if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
00524 #endif /* (LWIP_UDP || LWIP_RAW) */
00525     {
00526       API_MSG_VAR_FREE(msg);
00527     }
00528 #endif /* LWIP_TCP */
00529     return ERR_TIMEOUT;
00530   }
00531 #else
00532   sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
00533 #endif /* LWIP_SO_RCVTIMEO*/
00534 
00535 #if LWIP_TCP
00536 #if (LWIP_UDP || LWIP_RAW)
00537   if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
00538 #endif /* (LWIP_UDP || LWIP_RAW) */
00539   {
00540     /* Let the stack know that we have taken the data. */
00541     /* @todo: Speedup: Don't block and wait for the answer here
00542        (to prevent multiple thread-switches). */
00543     API_MSG_VAR_REF(msg).conn = conn;
00544     if (buf != NULL) {
00545       API_MSG_VAR_REF(msg).msg.r.len = ((struct pbuf *)buf)->tot_len;
00546     } else {
00547       API_MSG_VAR_REF(msg).msg.r.len = 1;
00548     }
00549 
00550     /* don't care for the return value of lwip_netconn_do_recv */
00551     netconn_apimsg(lwip_netconn_do_recv, &API_MSG_VAR_REF(msg));
00552     API_MSG_VAR_FREE(msg);
00553 
00554     /* If we are closed, we indicate that we no longer wish to use the socket */
00555     if (buf == NULL) {
00556       API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
00557       if (conn->pcb.ip == NULL) {
00558         /* race condition: RST during recv */
00559         return conn->last_err == ERR_OK ? ERR_RST : conn->last_err;
00560       }
00561       /* RX side is closed, so deallocate the recvmbox */
00562       netconn_close_shutdown(conn, NETCONN_SHUT_RD);
00563       /* Don' store ERR_CLSD as conn->err since we are only half-closed */
00564       return ERR_CLSD;
00565     }
00566     len = ((struct pbuf *)buf)->tot_len;
00567   }
00568 #endif /* LWIP_TCP */
00569 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
00570   else
00571 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
00572 #if (LWIP_UDP || LWIP_RAW)
00573   {
00574     LWIP_ASSERT("buf != NULL", buf != NULL);
00575     len = netbuf_len((struct netbuf*)buf);
00576   }
00577 #endif /* (LWIP_UDP || LWIP_RAW) */
00578 
00579 #if LWIP_SO_RCVBUF
00580   SYS_ARCH_DEC(conn->recv_avail, len);
00581 #endif /* LWIP_SO_RCVBUF */
00582   /* Register event with callback */
00583   API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
00584 
00585   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
00586 
00587   *new_buf = buf;
00588   /* don't set conn->last_err: it's only ERR_OK, anyway */
00589   return ERR_OK;
00590 }
00591 
00592 /**
00593  * @ingroup netconn_tcp
00594  * Receive data (in form of a pbuf) from a TCP netconn
00595  *
00596  * @param conn the netconn from which to receive data
00597  * @param new_buf pointer where a new pbuf is stored when received data
00598  * @return ERR_OK if data has been received, an error code otherwise (timeout,
00599  *                memory error or another error)
00600  *         ERR_ARG if conn is not a TCP netconn
00601  */
00602 err_t
00603 netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
00604 {
00605   LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
00606              NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
00607 
00608   return netconn_recv_data(conn, (void **)new_buf);
00609 }
00610 
00611 /**
00612  * @ingroup netconn_common
00613  * Receive data (in form of a netbuf containing a packet buffer) from a netconn
00614  *
00615  * @param conn the netconn from which to receive data
00616  * @param new_buf pointer where a new netbuf is stored when received data
00617  * @return ERR_OK if data has been received, an error code otherwise (timeout,
00618  *                memory error or another error)
00619  */
00620 err_t
00621 netconn_recv(struct netconn *conn, struct netbuf **new_buf)
00622 {
00623 #if LWIP_TCP
00624   struct netbuf *buf = NULL;
00625   err_t err;
00626 #endif /* LWIP_TCP */
00627 
00628   LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
00629   *new_buf = NULL;
00630   LWIP_ERROR("netconn_recv: invalid conn",    (conn != NULL),    return ERR_ARG;);
00631 
00632 #if LWIP_TCP
00633 #if (LWIP_UDP || LWIP_RAW)
00634   if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
00635 #endif /* (LWIP_UDP || LWIP_RAW) */
00636   {
00637     struct pbuf *p = NULL;
00638     /* This is not a listening netconn, since recvmbox is set */
00639 
00640     buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
00641     if (buf == NULL) {
00642       return ERR_MEM;
00643     }
00644 
00645     err = netconn_recv_data(conn, (void **)&p);
00646     if (err != ERR_OK) {
00647       memp_free(MEMP_NETBUF, buf);
00648       return err;
00649     }
00650     LWIP_ASSERT("p != NULL", p != NULL);
00651 
00652     buf->p = p;
00653     buf->ptr = p;
00654     buf->port = 0;
00655     ip_addr_set_zero(&buf->addr);
00656     *new_buf = buf;
00657     /* don't set conn->last_err: it's only ERR_OK, anyway */
00658     return ERR_OK;
00659   }
00660 #endif /* LWIP_TCP */
00661 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
00662   else
00663 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
00664   {
00665 #if (LWIP_UDP || LWIP_RAW)
00666     return netconn_recv_data(conn, (void **)new_buf);
00667 #endif /* (LWIP_UDP || LWIP_RAW) */
00668   }
00669 }
00670 
00671 /**
00672  * @ingroup netconn_udp
00673  * Send data (in form of a netbuf) to a specific remote IP address and port.
00674  * Only to be used for UDP and RAW netconns (not TCP).
00675  *
00676  * @param conn the netconn over which to send data
00677  * @param buf a netbuf containing the data to send
00678  * @param addr the remote IP address to which to send the data
00679  * @param port the remote port to which to send the data
00680  * @return ERR_OK if data was sent, any other err_t on error
00681  */
00682 err_t
00683 netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port)
00684 {
00685   if (buf != NULL) {
00686     ip_addr_set(&buf->addr, addr);
00687     buf->port = port;
00688     return netconn_send(conn, buf);
00689   }
00690   return ERR_VAL;
00691 }
00692 
00693 /**
00694  * @ingroup netconn_udp
00695  * Send data over a UDP or RAW netconn (that is already connected).
00696  *
00697  * @param conn the UDP or RAW netconn over which to send data
00698  * @param buf a netbuf containing the data to send
00699  * @return ERR_OK if data was sent, any other err_t on error
00700  */
00701 err_t
00702 netconn_send(struct netconn *conn, struct netbuf *buf)
00703 {
00704   API_MSG_VAR_DECLARE(msg);
00705   err_t err;
00706 
00707   LWIP_ERROR("netconn_send: invalid conn",  (conn != NULL), return ERR_ARG;);
00708 
00709   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
00710 
00711   API_MSG_VAR_ALLOC(msg);
00712   API_MSG_VAR_REF(msg).conn = conn;
00713   API_MSG_VAR_REF(msg).msg.b = buf;
00714   err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg));
00715   API_MSG_VAR_FREE(msg);
00716 
00717   return err;
00718 }
00719 
00720 /**
00721  * @ingroup netconn_tcp
00722  * Send data over a TCP netconn.
00723  *
00724  * @param conn the TCP netconn over which to send data
00725  * @param dataptr pointer to the application buffer that contains the data to send
00726  * @param size size of the application data to send
00727  * @param apiflags combination of following flags :
00728  * - NETCONN_COPY: data will be copied into memory belonging to the stack
00729  * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
00730  * - NETCONN_DONTBLOCK: only write the data if all data can be written at once
00731  * @param bytes_written pointer to a location that receives the number of written bytes
00732  * @return ERR_OK if data was sent, any other err_t on error
00733  */
00734 err_t
00735 netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
00736                      u8_t apiflags, size_t *bytes_written)
00737 {
00738   API_MSG_VAR_DECLARE(msg);
00739   err_t err;
00740   u8_t dontblock;
00741 
00742   LWIP_ERROR("netconn_write: invalid conn",  (conn != NULL), return ERR_ARG;);
00743   LWIP_ERROR("netconn_write: invalid conn->type",  (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;);
00744   if (size == 0) {
00745     return ERR_OK;
00746   }
00747   dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
00748 #if LWIP_SO_SNDTIMEO
00749   if (conn->send_timeout != 0) {
00750     dontblock = 1;
00751   }
00752 #endif /* LWIP_SO_SNDTIMEO */
00753   if (dontblock && !bytes_written) {
00754     /* This implies netconn_write() cannot be used for non-blocking send, since
00755        it has no way to return the number of bytes written. */
00756     return ERR_VAL;
00757   }
00758 
00759   API_MSG_VAR_ALLOC(msg);
00760   /* non-blocking write sends as much  */
00761   API_MSG_VAR_REF(msg).conn = conn;
00762   API_MSG_VAR_REF(msg).msg.w.dataptr = dataptr;
00763   API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags;
00764   API_MSG_VAR_REF(msg).msg.w.len = size;
00765 #if LWIP_SO_SNDTIMEO
00766   if (conn->send_timeout != 0) {
00767     /* get the time we started, which is later compared to
00768         sys_now() + conn->send_timeout */
00769     API_MSG_VAR_REF(msg).msg.w.time_started = sys_now();
00770   } else {
00771     API_MSG_VAR_REF(msg).msg.w.time_started = 0;
00772   }
00773 #endif /* LWIP_SO_SNDTIMEO */
00774 
00775   /* For locking the core: this _can_ be delayed on low memory/low send buffer,
00776      but if it is, this is done inside api_msg.c:do_write(), so we can use the
00777      non-blocking version here. */
00778   err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg));
00779   if ((err == ERR_OK) && (bytes_written != NULL)) {
00780     if (dontblock) {
00781       /* nonblocking write: maybe the data has been sent partly */
00782       *bytes_written = API_MSG_VAR_REF(msg).msg.w.len;
00783     } else {
00784       /* blocking call succeeded: all data has been sent if it */
00785       *bytes_written = size;
00786     }
00787   }
00788   API_MSG_VAR_FREE(msg);
00789 
00790   return err;
00791 }
00792 
00793 /**
00794  * @ingroup netconn_tcp
00795  * Close or shutdown a TCP netconn (doesn't delete it).
00796  *
00797  * @param conn the TCP netconn to close or shutdown
00798  * @param how fully close or only shutdown one side?
00799  * @return ERR_OK if the netconn was closed, any other err_t on error
00800  */
00801 static err_t
00802 netconn_close_shutdown(struct netconn *conn, u8_t how)
00803 {
00804   API_MSG_VAR_DECLARE(msg);
00805   err_t err;
00806   LWIP_UNUSED_ARG(how);
00807 
00808   LWIP_ERROR("netconn_close: invalid conn",  (conn != NULL), return ERR_ARG;);
00809 
00810   API_MSG_VAR_ALLOC(msg);
00811   API_MSG_VAR_REF(msg).conn = conn;
00812 #if LWIP_TCP
00813   /* shutting down both ends is the same as closing */
00814   API_MSG_VAR_REF(msg).msg.sd.shut = how;
00815 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
00816   /* get the time we started, which is later compared to
00817      sys_now() + conn->send_timeout */
00818   API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
00819 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
00820   API_MSG_VAR_REF(msg).msg.sd.polls_left =
00821     ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
00822 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
00823 #endif /* LWIP_TCP */
00824   err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg));
00825   API_MSG_VAR_FREE(msg);
00826 
00827   return err;
00828 }
00829 
00830 /**
00831  * @ingroup netconn_tcp
00832  * Close a TCP netconn (doesn't delete it).
00833  *
00834  * @param conn the TCP netconn to close
00835  * @return ERR_OK if the netconn was closed, any other err_t on error
00836  */
00837 err_t
00838 netconn_close(struct netconn *conn)
00839 {
00840   /* shutting down both ends is the same as closing */
00841   return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
00842 }
00843 
00844 /**
00845  * @ingroup netconn_tcp
00846  * Shut down one or both sides of a TCP netconn (doesn't delete it).
00847  *
00848  * @param conn the TCP netconn to shut down
00849  * @param shut_rx shut down the RX side (no more read possible after this)
00850  * @param shut_tx shut down the TX side (no more write possible after this)
00851  * @return ERR_OK if the netconn was closed, any other err_t on error
00852  */
00853 err_t
00854 netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
00855 {
00856   return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
00857 }
00858 
00859 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
00860 /**
00861  * @ingroup netconn_udp
00862  * Join multicast groups for UDP netconns.
00863  *
00864  * @param conn the UDP netconn for which to change multicast addresses
00865  * @param multiaddr IP address of the multicast group to join or leave
00866  * @param netif_addr the IP address of the network interface on which to send
00867  *                  the igmp message
00868  * @param join_or_leave flag whether to send a join- or leave-message
00869  * @return ERR_OK if the action was taken, any err_t on error
00870  */
00871 err_t
00872 netconn_join_leave_group(struct netconn *conn,
00873                          const ip_addr_t *multiaddr,
00874                          const ip_addr_t *netif_addr,
00875                          enum netconn_igmp join_or_leave)
00876 {
00877   API_MSG_VAR_DECLARE(msg);
00878   err_t err;
00879 
00880   LWIP_ERROR("netconn_join_leave_group: invalid conn",  (conn != NULL), return ERR_ARG;);
00881 
00882   API_MSG_VAR_ALLOC(msg);
00883 
00884 #if LWIP_IPV4
00885   /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
00886   if (multiaddr == NULL) {
00887     multiaddr = IP4_ADDR_ANY;
00888   }
00889   if (netif_addr == NULL) {
00890     netif_addr = IP4_ADDR_ANY;
00891   }
00892 #endif /* LWIP_IPV4 */
00893 
00894   API_MSG_VAR_REF(msg).conn = conn;
00895   API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
00896   API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr);
00897   API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
00898   err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg));
00899   API_MSG_VAR_FREE(msg);
00900 
00901   return err;
00902 }
00903 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
00904 
00905 #if LWIP_DNS
00906 /**
00907  * @ingroup netconn_common
00908  * Execute a DNS query, only one IP address is returned
00909  *
00910  * @param name a string representation of the DNS host name to query
00911  * @param addr a preallocated ip_addr_t where to store the resolved IP address
00912  * @param dns_addrtype IP address type (IPv4 / IPv6)
00913  * @return ERR_OK: resolving succeeded
00914  *         ERR_MEM: memory error, try again later
00915  *         ERR_ARG: dns client not initialized or invalid hostname
00916  *         ERR_VAL: dns server response was invalid
00917  */
00918 #if LWIP_IPV4 && LWIP_IPV6
00919 err_t
00920 netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype)
00921 #else
00922 err_t
00923 netconn_gethostbyname(const char *name, ip_addr_t *addr)
00924 #endif
00925 {
00926   API_VAR_DECLARE(struct dns_api_msg, msg);
00927 #if !LWIP_MPU_COMPATIBLE
00928   sys_sem_t sem;
00929 #endif /* LWIP_MPU_COMPATIBLE */
00930   err_t err;
00931   err_t cberr;
00932 
00933   LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
00934   LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
00935 #if LWIP_MPU_COMPATIBLE
00936   if (strlen(name) >= DNS_MAX_NAME_LENGTH) {
00937     return ERR_ARG;
00938   }
00939 #endif
00940 
00941   API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM);
00942 #if LWIP_MPU_COMPATIBLE
00943   strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH-1);
00944   API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH-1] = 0;
00945 #else /* LWIP_MPU_COMPATIBLE */
00946   msg.err = &err;
00947   msg.sem = &sem;
00948   API_VAR_REF(msg).addr = API_VAR_REF(addr);
00949   API_VAR_REF(msg).name = name;
00950 #endif /* LWIP_MPU_COMPATIBLE */
00951 #if LWIP_IPV4 && LWIP_IPV6
00952   API_VAR_REF(msg).dns_addrtype = dns_addrtype;
00953 #endif /* LWIP_IPV4 && LWIP_IPV6 */
00954 #if LWIP_NETCONN_SEM_PER_THREAD
00955   API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET();
00956 #else /* LWIP_NETCONN_SEM_PER_THREAD*/
00957   err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0);
00958   if (err != ERR_OK) {
00959     API_VAR_FREE(MEMP_DNS_API_MSG, msg);
00960     return err;
00961   }
00962 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
00963 
00964   cberr = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg));
00965   if (cberr != ERR_OK) {
00966 #if !LWIP_NETCONN_SEM_PER_THREAD
00967     sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
00968 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
00969     API_VAR_FREE(MEMP_DNS_API_MSG, msg);
00970     return cberr;
00971   }
00972   sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem));
00973 #if !LWIP_NETCONN_SEM_PER_THREAD
00974   sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
00975 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
00976 
00977 #if LWIP_MPU_COMPATIBLE
00978   *addr = msg->addr;
00979   err = msg->err;
00980 #endif /* LWIP_MPU_COMPATIBLE */
00981 
00982   API_VAR_FREE(MEMP_DNS_API_MSG, msg);
00983   return err;
00984 }
00985 #endif /* LWIP_DNS*/
00986 
00987 #if LWIP_NETCONN_SEM_PER_THREAD
00988 void
00989 netconn_thread_init(void)
00990 {
00991   sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
00992   if ((sem == NULL) || !sys_sem_valid(sem)) {
00993     /* call alloc only once */
00994     LWIP_NETCONN_THREAD_SEM_ALLOC();
00995     LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET()));
00996   }
00997 }
00998 
00999 void
01000 netconn_thread_cleanup(void)
01001 {
01002   sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
01003   if ((sem != NULL) && sys_sem_valid(sem)) {
01004     /* call free only once */
01005     LWIP_NETCONN_THREAD_SEM_FREE();
01006   }
01007 }
01008 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
01009 
01010 #endif /* LWIP_NETCONN */