• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /**
2   * @file
3   * Sequential API External module
4   *
5   * @defgroup netconn Netconn API
6   * @ingroup sequential_api
7   * Thread-safe, to be called from non-TCPIP threads only.
8   * TX/RX handling based on @ref netbuf (containing @ref pbuf)
9   * to avoid copying data around.
10   *
11   * @defgroup netconn_common Common functions
12   * @ingroup netconn
13   * For use with TCP and UDP
14   *
15   * @defgroup netconn_tcp TCP only
16   * @ingroup netconn
17   * TCP only functions
18   *
19   * @defgroup netconn_udp UDP only
20   * @ingroup netconn
21   * UDP only functions
22   */
23  
24  /*
25   * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
26   * All rights reserved.
27   *
28   * Redistribution and use in source and binary forms, with or without modification,
29   * are permitted provided that the following conditions are met:
30   *
31   * 1. Redistributions of source code must retain the above copyright notice,
32   *    this list of conditions and the following disclaimer.
33   * 2. Redistributions in binary form must reproduce the above copyright notice,
34   *    this list of conditions and the following disclaimer in the documentation
35   *    and/or other materials provided with the distribution.
36   * 3. The name of the author may not be used to endorse or promote products
37   *    derived from this software without specific prior written permission.
38   *
39   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
40   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
41   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
42   * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
43   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
44   * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
45   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
46   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
47   * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
48   * OF SUCH DAMAGE.
49   *
50   * This file is part of the lwIP TCP/IP stack.
51   *
52   * Author: Adam Dunkels <adam@sics.se>
53   */
54  
55  /* This is the part of the API that is linked with
56     the application */
57  
58  #include "lwip/opt.h"
59  
60  #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
61  
62  #include "lwip/api.h"
63  #include "lwip/memp.h"
64  
65  #include "lwip/ip.h"
66  #include "lwip/raw.h"
67  #include "lwip/udp.h"
68  #include "lwip/priv/api_msg.h"
69  #include "lwip/priv/tcp_priv.h"
70  #include "lwip/priv/tcpip_priv.h"
71  
72  #ifdef LWIP_HOOK_FILENAME
73  #include LWIP_HOOK_FILENAME
74  #endif
75  
76  #include <string.h>
77  
78  #define API_MSG_VAR_REF(name)               API_VAR_REF(name)
79  #define API_MSG_VAR_DECLARE(name)           API_VAR_DECLARE(struct api_msg, name)
80  #define API_MSG_VAR_ALLOC(name)             API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, ERR_MEM)
81  #define API_MSG_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, NULL)
82  #define API_MSG_VAR_FREE(name)              API_VAR_FREE(MEMP_API_MSG, name)
83  
84  #if TCP_LISTEN_BACKLOG
85  /* need to allocate API message for accept so empty message pool does not result in event loss
86   * see bug #47512: MPU_COMPATIBLE may fail on empty pool */
87  #define API_MSG_VAR_ALLOC_ACCEPT(msg) API_MSG_VAR_ALLOC(msg)
88  #define API_MSG_VAR_FREE_ACCEPT(msg) API_MSG_VAR_FREE(msg)
89  #else /* TCP_LISTEN_BACKLOG */
90  #define API_MSG_VAR_ALLOC_ACCEPT(msg)
91  #define API_MSG_VAR_FREE_ACCEPT(msg)
92  #endif /* TCP_LISTEN_BACKLOG */
93  
94  #if LWIP_NETCONN_FULLDUPLEX
95  #define NETCONN_RECVMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->recvmbox) && (((conn)->flags & NETCONN_FLAG_MBOXINVALID) == 0))
96  #define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & (NETCONN_FLAG_MBOXCLOSED|NETCONN_FLAG_MBOXINVALID)) == 0))
97  #define NETCONN_MBOX_WAITING_INC(conn) SYS_ARCH_INC(conn->mbox_threads_waiting, 1)
98  #define NETCONN_MBOX_WAITING_DEC(conn) SYS_ARCH_DEC(conn->mbox_threads_waiting, 1)
99  #else /* LWIP_NETCONN_FULLDUPLEX */
100  #define NETCONN_RECVMBOX_WAITABLE(conn)   sys_mbox_valid(&(conn)->recvmbox)
101  #define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & NETCONN_FLAG_MBOXCLOSED) == 0))
102  #define NETCONN_MBOX_WAITING_INC(conn)
103  #define NETCONN_MBOX_WAITING_DEC(conn)
104  #endif /* LWIP_NETCONN_FULLDUPLEX */
105  
106  static err_t netconn_close_shutdown(struct netconn *conn, u8_t how);
107  
108  /**
109   * Call the lower part of a netconn_* function
110   * This function is then running in the thread context
111   * of tcpip_thread and has exclusive access to lwIP core code.
112   *
113   * @param fn function to call
114   * @param apimsg a struct containing the function to call and its parameters
115   * @return ERR_OK if the function was called, another err_t if not
116   */
117  static err_t
netconn_apimsg(tcpip_callback_fn fn,struct api_msg * apimsg)118  netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg)
119  {
120    err_t err;
121  
122  #ifdef LWIP_DEBUG
123    /* catch functions that don't set err */
124    apimsg->err = ERR_VAL;
125  #endif /* LWIP_DEBUG */
126  
127  #if LWIP_NETCONN_SEM_PER_THREAD
128    apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
129  #endif /* LWIP_NETCONN_SEM_PER_THREAD */
130  
131    err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg));
132    if (err == ERR_OK) {
133      return apimsg->err;
134    }
135    return err;
136  }
137  
138  /**
139   * Create a new netconn (of a specific type) that has a callback function.
140   * The corresponding pcb is also created.
141   *
142   * @param t the type of 'connection' to create (@see enum netconn_type)
143   * @param proto the IP protocol for RAW IP pcbs
144   * @param callback a function to call on status changes (RX available, TX'ed)
145   * @return a newly allocated struct netconn or
146   *         NULL on memory error
147   */
148  struct netconn *
netconn_new_with_proto_and_callback(enum netconn_type t,u8_t proto,netconn_callback callback)149  netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
150  {
151    struct netconn *conn;
152    API_MSG_VAR_DECLARE(msg);
153    API_MSG_VAR_ALLOC_RETURN_NULL(msg);
154  
155    conn = netconn_alloc(t, callback);
156    if (conn != NULL) {
157      err_t err;
158  
159      API_MSG_VAR_REF(msg).msg.n.proto = proto;
160      API_MSG_VAR_REF(msg).conn = conn;
161      err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg));
162      if (err != ERR_OK) {
163        LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
164        LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
165  #if LWIP_TCP
166        LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
167  #endif /* LWIP_TCP */
168  #if !LWIP_NETCONN_SEM_PER_THREAD
169        LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
170        sys_sem_free(&conn->op_completed);
171  #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
172        sys_mbox_free(&conn->recvmbox);
173        memp_free(MEMP_NETCONN, conn);
174        API_MSG_VAR_FREE(msg);
175        return NULL;
176      }
177    }
178    API_MSG_VAR_FREE(msg);
179    return conn;
180  }
181  
182  /**
183   * @ingroup netconn_common
184   * Close a netconn 'connection' and free all its resources but not the netconn itself.
185   * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
186   * after this returns.
187   *
188   * @param conn the netconn to delete
189   * @return ERR_OK if the connection was deleted
190   */
191  err_t
netconn_prepare_delete(struct netconn * conn)192  netconn_prepare_delete(struct netconn *conn)
193  {
194    err_t err;
195    API_MSG_VAR_DECLARE(msg);
196  
197    /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
198    if (conn == NULL) {
199      return ERR_OK;
200    }
201  
202    API_MSG_VAR_ALLOC(msg);
203    API_MSG_VAR_REF(msg).conn = conn;
204  #if LWIP_TCP
205  #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
206    /* get the time we started, which is later compared to
207       sys_now() + conn->send_timeout */
208    API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
209  #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
210    API_MSG_VAR_REF(msg).msg.sd.polls_left =
211      ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
212  #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
213  #endif /* LWIP_TCP */
214    err = netconn_apimsg(lwip_netconn_do_delconn, &API_MSG_VAR_REF(msg));
215    API_MSG_VAR_FREE(msg);
216  
217    if (err != ERR_OK) {
218      return err;
219    }
220    return ERR_OK;
221  }
222  
223  /**
224   * @ingroup netconn_common
225   * Close a netconn 'connection' and free its resources.
226   * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
227   * after this returns.
228   *
229   * @param conn the netconn to delete
230   * @return ERR_OK if the connection was deleted
231   */
232  err_t
netconn_delete(struct netconn * conn)233  netconn_delete(struct netconn *conn)
234  {
235    err_t err;
236  
237    /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
238    if (conn == NULL) {
239      return ERR_OK;
240    }
241  
242  #if LWIP_NETCONN_FULLDUPLEX
243    if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
244      /* Already called netconn_prepare_delete() before */
245      err = ERR_OK;
246    } else
247  #endif /* LWIP_NETCONN_FULLDUPLEX */
248    {
249      err = netconn_prepare_delete(conn);
250    }
251    if (err == ERR_OK) {
252      netconn_free(conn);
253    }
254    return err;
255  }
256  
257  /**
258   * Get the local or remote IP address and port of a netconn.
259   * For RAW netconns, this returns the protocol instead of a port!
260   *
261   * @param conn the netconn to query
262   * @param addr a pointer to which to save the IP address
263   * @param port a pointer to which to save the port (or protocol for RAW)
264   * @param local 1 to get the local IP address, 0 to get the remote one
265   * @return ERR_CONN for invalid connections
266   *         ERR_OK if the information was retrieved
267   */
268  err_t
netconn_getaddr(struct netconn * conn,ip_addr_t * addr,u16_t * port,u8_t local)269  netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
270  {
271    API_MSG_VAR_DECLARE(msg);
272    err_t err;
273  
274    LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
275    LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
276    LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
277  
278    API_MSG_VAR_ALLOC(msg);
279    API_MSG_VAR_REF(msg).conn = conn;
280    API_MSG_VAR_REF(msg).msg.ad.local = local;
281  #if LWIP_MPU_COMPATIBLE
282    err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg));
283    *addr = msg->msg.ad.ipaddr;
284    *port = msg->msg.ad.port;
285  #else /* LWIP_MPU_COMPATIBLE */
286    msg.msg.ad.ipaddr = addr;
287    msg.msg.ad.port = port;
288    err = netconn_apimsg(lwip_netconn_do_getaddr, &msg);
289  #endif /* LWIP_MPU_COMPATIBLE */
290    API_MSG_VAR_FREE(msg);
291  
292    return err;
293  }
294  
295  /**
296   * @ingroup netconn_common
297   * Bind a netconn to a specific local IP address and port.
298   * Binding one netconn twice might not always be checked correctly!
299   *
300   * @param conn the netconn to bind
301   * @param addr the local IP address to bind the netconn to
302   *             (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses)
303   * @param port the local port to bind the netconn to (not used for RAW)
304   * @return ERR_OK if bound, any other err_t on failure
305   */
306  err_t
netconn_bind(struct netconn * conn,const ip_addr_t * addr,u16_t port)307  netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port)
308  {
309    API_MSG_VAR_DECLARE(msg);
310    err_t err;
311  
312    LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
313  
314  #if LWIP_IPV4
315    /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
316    if (addr == NULL) {
317      addr = IP4_ADDR_ANY;
318    }
319  #endif /* LWIP_IPV4 */
320  
321  #if LWIP_IPV4 && LWIP_IPV6
322    /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY,
323     * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind
324     */
325    if ((netconn_get_ipv6only(conn) == 0) &&
326        ip_addr_cmp(addr, IP6_ADDR_ANY)) {
327      addr = IP_ANY_TYPE;
328    }
329  #endif /* LWIP_IPV4 && LWIP_IPV6 */
330  
331    API_MSG_VAR_ALLOC(msg);
332    API_MSG_VAR_REF(msg).conn = conn;
333    API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
334    API_MSG_VAR_REF(msg).msg.bc.port = port;
335    err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg));
336    API_MSG_VAR_FREE(msg);
337  
338    return err;
339  }
340  
341  /**
342   * @ingroup netconn_common
343   * Bind a netconn to a specific interface and port.
344   * Binding one netconn twice might not always be checked correctly!
345   *
346   * @param conn the netconn to bind
347   * @param if_idx the local interface index to bind the netconn to
348   * @return ERR_OK if bound, any other err_t on failure
349   */
350  err_t
netconn_bind_if(struct netconn * conn,u8_t if_idx)351  netconn_bind_if(struct netconn *conn, u8_t if_idx)
352  {
353    API_MSG_VAR_DECLARE(msg);
354    err_t err;
355  
356    LWIP_ERROR("netconn_bind_if: invalid conn", (conn != NULL), return ERR_ARG;);
357  
358    API_MSG_VAR_ALLOC(msg);
359    API_MSG_VAR_REF(msg).conn = conn;
360    API_MSG_VAR_REF(msg).msg.bc.if_idx = if_idx;
361    err = netconn_apimsg(lwip_netconn_do_bind_if, &API_MSG_VAR_REF(msg));
362    API_MSG_VAR_FREE(msg);
363  
364    return err;
365  }
366  
367  /**
368   * @ingroup netconn_common
369   * Connect a netconn to a specific remote IP address and port.
370   *
371   * @param conn the netconn to connect
372   * @param addr the remote IP address to connect to
373   * @param port the remote port to connect to (no used for RAW)
374   * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
375   */
376  err_t
netconn_connect(struct netconn * conn,const ip_addr_t * addr,u16_t port)377  netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port)
378  {
379    API_MSG_VAR_DECLARE(msg);
380    err_t err;
381  
382    LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
383  
384  #if LWIP_IPV4
385    /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
386    if (addr == NULL) {
387      addr = IP4_ADDR_ANY;
388    }
389  #endif /* LWIP_IPV4 */
390  
391    API_MSG_VAR_ALLOC(msg);
392    API_MSG_VAR_REF(msg).conn = conn;
393    API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
394    API_MSG_VAR_REF(msg).msg.bc.port = port;
395    err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg));
396    API_MSG_VAR_FREE(msg);
397  
398    return err;
399  }
400  
401  /**
402   * @ingroup netconn_udp
403   * Disconnect a netconn from its current peer (only valid for UDP netconns).
404   *
405   * @param conn the netconn to disconnect
406   * @return See @ref err_t
407   */
408  err_t
netconn_disconnect(struct netconn * conn)409  netconn_disconnect(struct netconn *conn)
410  {
411    API_MSG_VAR_DECLARE(msg);
412    err_t err;
413  
414    LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
415  
416    API_MSG_VAR_ALLOC(msg);
417    API_MSG_VAR_REF(msg).conn = conn;
418    err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg));
419    API_MSG_VAR_FREE(msg);
420  
421    return err;
422  }
423  
424  /**
425   * @ingroup netconn_tcp
426   * Set a TCP netconn into listen mode
427   *
428   * @param conn the tcp netconn to set to listen mode
429   * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
430   * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
431   *         don't return any error (yet?))
432   */
433  err_t
netconn_listen_with_backlog(struct netconn * conn,u8_t backlog)434  netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
435  {
436  #if LWIP_TCP
437    API_MSG_VAR_DECLARE(msg);
438    err_t err;
439  
440    /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
441    LWIP_UNUSED_ARG(backlog);
442  
443    LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
444  
445    API_MSG_VAR_ALLOC(msg);
446    API_MSG_VAR_REF(msg).conn = conn;
447  #if TCP_LISTEN_BACKLOG
448    API_MSG_VAR_REF(msg).msg.lb.backlog = backlog;
449  #endif /* TCP_LISTEN_BACKLOG */
450    err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg));
451    API_MSG_VAR_FREE(msg);
452  
453    return err;
454  #else /* LWIP_TCP */
455    LWIP_UNUSED_ARG(conn);
456    LWIP_UNUSED_ARG(backlog);
457    return ERR_ARG;
458  #endif /* LWIP_TCP */
459  }
460  
461  /**
462   * @ingroup netconn_tcp
463   * Accept a new connection on a TCP listening netconn.
464   *
465   * @param conn the TCP listen netconn
466   * @param new_conn pointer where the new connection is stored
467   * @return ERR_OK if a new connection has been received or an error
468   *                code otherwise
469   */
470  err_t
netconn_accept(struct netconn * conn,struct netconn ** new_conn)471  netconn_accept(struct netconn *conn, struct netconn **new_conn)
472  {
473  #if LWIP_TCP
474    err_t err;
475    void *accept_ptr;
476    struct netconn *newconn;
477  #if TCP_LISTEN_BACKLOG
478    API_MSG_VAR_DECLARE(msg);
479  #endif /* TCP_LISTEN_BACKLOG */
480  
481    LWIP_ERROR("netconn_accept: invalid pointer",    (new_conn != NULL),                  return ERR_ARG;);
482    *new_conn = NULL;
483    LWIP_ERROR("netconn_accept: invalid conn",       (conn != NULL),                      return ERR_ARG;);
484  
485    /* NOTE: Although the opengroup spec says a pending error shall be returned to
486             send/recv/getsockopt(SO_ERROR) only, we return it for listening
487             connections also, to handle embedded-system errors */
488    err = netconn_err(conn);
489    if (err != ERR_OK) {
490      /* return pending error */
491      return err;
492    }
493    if (!NETCONN_ACCEPTMBOX_WAITABLE(conn)) {
494      /* don't accept if closed: this might block the application task
495         waiting on acceptmbox forever! */
496      return ERR_CLSD;
497    }
498  
499    API_MSG_VAR_ALLOC_ACCEPT(msg);
500  
501    NETCONN_MBOX_WAITING_INC(conn);
502    if (netconn_is_nonblocking(conn)) {
503      if (sys_arch_mbox_tryfetch(&conn->acceptmbox, &accept_ptr) == SYS_MBOX_EMPTY) {
504        API_MSG_VAR_FREE_ACCEPT(msg);
505        NETCONN_MBOX_WAITING_DEC(conn);
506        return ERR_WOULDBLOCK;
507      }
508    } else {
509  #if LWIP_SO_RCVTIMEO
510      if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
511        API_MSG_VAR_FREE_ACCEPT(msg);
512        NETCONN_MBOX_WAITING_DEC(conn);
513        return ERR_TIMEOUT;
514      }
515  #else
516      sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0);
517  #endif /* LWIP_SO_RCVTIMEO*/
518    }
519    NETCONN_MBOX_WAITING_DEC(conn);
520  #if LWIP_NETCONN_FULLDUPLEX
521    if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
522      if (lwip_netconn_is_deallocated_msg(accept_ptr)) {
523        /* the netconn has been closed from another thread */
524        API_MSG_VAR_FREE_ACCEPT(msg);
525        return ERR_CONN;
526      }
527    }
528  #endif
529  
530    /* Register event with callback */
531    API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
532  
533    if (lwip_netconn_is_err_msg(accept_ptr, &err)) {
534      /* a connection has been aborted: e.g. out of pcbs or out of netconns during accept */
535      API_MSG_VAR_FREE_ACCEPT(msg);
536      return err;
537    }
538    if (accept_ptr == NULL) {
539      /* connection has been aborted */
540      API_MSG_VAR_FREE_ACCEPT(msg);
541      return ERR_CLSD;
542    }
543    newconn = (struct netconn *)accept_ptr;
544  #if TCP_LISTEN_BACKLOG
545    /* Let the stack know that we have accepted the connection. */
546    API_MSG_VAR_REF(msg).conn = newconn;
547    /* don't care for the return value of lwip_netconn_do_recv */
548    netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg));
549    API_MSG_VAR_FREE(msg);
550  #endif /* TCP_LISTEN_BACKLOG */
551  
552    *new_conn = newconn;
553    /* don't set conn->last_err: it's only ERR_OK, anyway */
554    return ERR_OK;
555  #else /* LWIP_TCP */
556    LWIP_UNUSED_ARG(conn);
557    LWIP_UNUSED_ARG(new_conn);
558    return ERR_ARG;
559  #endif /* LWIP_TCP */
560  }
561  
562  /**
563   * @ingroup netconn_common
564   * Receive data: actual implementation that doesn't care whether pbuf or netbuf
565   * is received (this is internal, it's just here for describing common errors)
566   *
567   * @param conn the netconn from which to receive data
568   * @param new_buf pointer where a new pbuf/netbuf is stored when received data
569   * @param apiflags flags that control function behaviour. For now only:
570   * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
571   * @return ERR_OK if data has been received, an error code otherwise (timeout,
572   *                memory error or another error)
573   *         ERR_CONN if not connected
574   *         ERR_CLSD if TCP connection has been closed
575   *         ERR_WOULDBLOCK if the netconn is nonblocking but would block to wait for data
576   *         ERR_TIMEOUT if the netconn has a receive timeout and no data was received
577   */
578  static err_t
netconn_recv_data(struct netconn * conn,void ** new_buf,u8_t apiflags)579  netconn_recv_data(struct netconn *conn, void **new_buf, u8_t apiflags)
580  {
581    void *buf = NULL;
582    u16_t len;
583  
584    LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
585    *new_buf = NULL;
586    LWIP_ERROR("netconn_recv: invalid conn",    (conn != NULL),    return ERR_ARG;);
587  
588    if (!NETCONN_RECVMBOX_WAITABLE(conn)) {
589      err_t err = netconn_err(conn);
590      if (err != ERR_OK) {
591        /* return pending error */
592        return err;
593      }
594      return ERR_CONN;
595    }
596  
597    NETCONN_MBOX_WAITING_INC(conn);
598    if (netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK) ||
599        (conn->flags & NETCONN_FLAG_MBOXCLOSED) || (conn->pending_err != ERR_OK)) {
600      if (sys_arch_mbox_tryfetch(&conn->recvmbox, &buf) == SYS_MBOX_EMPTY) {
601        err_t err;
602        NETCONN_MBOX_WAITING_DEC(conn);
603        err = netconn_err(conn);
604        if (err != ERR_OK) {
605          /* return pending error */
606          return err;
607        }
608        if (conn->flags & NETCONN_FLAG_MBOXCLOSED) {
609          return ERR_CONN;
610        }
611        return ERR_WOULDBLOCK;
612      }
613    } else {
614  #if LWIP_SO_RCVTIMEO
615      if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
616        NETCONN_MBOX_WAITING_DEC(conn);
617        return ERR_TIMEOUT;
618      }
619  #else
620      sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
621  #endif /* LWIP_SO_RCVTIMEO*/
622    }
623    NETCONN_MBOX_WAITING_DEC(conn);
624  #if LWIP_NETCONN_FULLDUPLEX
625    if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
626      if (lwip_netconn_is_deallocated_msg(buf)) {
627        /* the netconn has been closed from another thread */
628        API_MSG_VAR_FREE_ACCEPT(msg);
629        return ERR_CONN;
630      }
631    }
632  #endif
633  
634  #if LWIP_TCP
635  #if (LWIP_UDP || LWIP_RAW)
636    if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
637  #endif /* (LWIP_UDP || LWIP_RAW) */
638    {
639      err_t err;
640      /* Check if this is an error message or a pbuf */
641      if (lwip_netconn_is_err_msg(buf, &err)) {
642        /* new_buf has been zeroed above already */
643        if (err == ERR_CLSD) {
644          /* connection closed translates to ERR_OK with *new_buf == NULL */
645          return ERR_OK;
646        }
647        return err;
648      }
649      len = ((struct pbuf *)buf)->tot_len;
650    }
651  #endif /* LWIP_TCP */
652  #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
653    else
654  #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
655  #if (LWIP_UDP || LWIP_RAW)
656    {
657      LWIP_ASSERT("buf != NULL", buf != NULL);
658      len = netbuf_len((struct netbuf *)buf);
659    }
660  #endif /* (LWIP_UDP || LWIP_RAW) */
661  
662  #if LWIP_SO_RCVBUF
663    SYS_ARCH_DEC(conn->recv_avail, len);
664  #endif /* LWIP_SO_RCVBUF */
665    /* Register event with callback */
666    API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
667  
668    LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
669  
670    *new_buf = buf;
671    /* don't set conn->last_err: it's only ERR_OK, anyway */
672    return ERR_OK;
673  }
674  
675  #if LWIP_TCP
676  static err_t
netconn_tcp_recvd_msg(struct netconn * conn,size_t len,struct api_msg * msg)677  netconn_tcp_recvd_msg(struct netconn *conn, size_t len, struct api_msg *msg)
678  {
679    LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
680               NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
681  
682    msg->conn = conn;
683    msg->msg.r.len = len;
684  
685    return netconn_apimsg(lwip_netconn_do_recv, msg);
686  }
687  
688  err_t
netconn_tcp_recvd(struct netconn * conn,size_t len)689  netconn_tcp_recvd(struct netconn *conn, size_t len)
690  {
691    err_t err;
692    API_MSG_VAR_DECLARE(msg);
693    LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
694               NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
695  
696    API_MSG_VAR_ALLOC(msg);
697    err = netconn_tcp_recvd_msg(conn, len, &API_VAR_REF(msg));
698    API_MSG_VAR_FREE(msg);
699    return err;
700  }
701  
702  static err_t
netconn_recv_data_tcp(struct netconn * conn,struct pbuf ** new_buf,u8_t apiflags)703  netconn_recv_data_tcp(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags)
704  {
705    err_t err;
706    struct pbuf *buf;
707    API_MSG_VAR_DECLARE(msg);
708  #if LWIP_MPU_COMPATIBLE
709    msg = NULL;
710  #endif
711  
712    if (!NETCONN_RECVMBOX_WAITABLE(conn)) {
713      /* This only happens when calling this function more than once *after* receiving FIN */
714      return ERR_CONN;
715    }
716    if (netconn_is_flag_set(conn, NETCONN_FIN_RX_PENDING)) {
717      netconn_clear_flags(conn, NETCONN_FIN_RX_PENDING);
718      goto handle_fin;
719    }
720  
721    if (!(apiflags & NETCONN_NOAUTORCVD)) {
722      /* need to allocate API message here so empty message pool does not result in event loss
723        * see bug #47512: MPU_COMPATIBLE may fail on empty pool */
724      API_MSG_VAR_ALLOC(msg);
725    }
726  
727    err = netconn_recv_data(conn, (void **)new_buf, apiflags);
728    if (err != ERR_OK) {
729      if (!(apiflags & NETCONN_NOAUTORCVD)) {
730        API_MSG_VAR_FREE(msg);
731      }
732      return err;
733    }
734    buf = *new_buf;
735    if (!(apiflags & NETCONN_NOAUTORCVD)) {
736      /* Let the stack know that we have taken the data. */
737      u16_t len = buf ? buf->tot_len : 1;
738      /* don't care for the return value of lwip_netconn_do_recv */
739      /* @todo: this should really be fixed, e.g. by retrying in poll on error */
740      netconn_tcp_recvd_msg(conn, len,  &API_VAR_REF(msg));
741      API_MSG_VAR_FREE(msg);
742    }
743  
744    /* If we are closed, we indicate that we no longer wish to use the socket */
745    if (buf == NULL) {
746      if (apiflags & NETCONN_NOFIN) {
747        /* received a FIN but the caller cannot handle it right now:
748           re-enqueue it and return "no data" */
749        netconn_set_flags(conn, NETCONN_FIN_RX_PENDING);
750        return ERR_WOULDBLOCK;
751      } else {
752  handle_fin:
753        API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
754        if (conn->pcb.ip == NULL) {
755          /* race condition: RST during recv */
756          err = netconn_err(conn);
757          if (err != ERR_OK) {
758            return err;
759          }
760          return ERR_RST;
761        }
762        /* RX side is closed, so deallocate the recvmbox */
763        netconn_close_shutdown(conn, NETCONN_SHUT_RD);
764        /* Don' store ERR_CLSD as conn->err since we are only half-closed */
765        return ERR_CLSD;
766      }
767    }
768    return err;
769  }
770  
771  /**
772   * @ingroup netconn_tcp
773   * Receive data (in form of a pbuf) from a TCP netconn
774   *
775   * @param conn the netconn from which to receive data
776   * @param new_buf pointer where a new pbuf is stored when received data
777   * @return ERR_OK if data has been received, an error code otherwise (timeout,
778   *                memory error or another error, @see netconn_recv_data)
779   *         ERR_ARG if conn is not a TCP netconn
780   */
781  err_t
netconn_recv_tcp_pbuf(struct netconn * conn,struct pbuf ** new_buf)782  netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
783  {
784    LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
785               NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
786  
787    return netconn_recv_data_tcp(conn, new_buf, 0);
788  }
789  
790  /**
791   * @ingroup netconn_tcp
792   * Receive data (in form of a pbuf) from a TCP netconn
793   *
794   * @param conn the netconn from which to receive data
795   * @param new_buf pointer where a new pbuf is stored when received data
796   * @param apiflags flags that control function behaviour. For now only:
797   * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
798   * @return ERR_OK if data has been received, an error code otherwise (timeout,
799   *                memory error or another error, @see netconn_recv_data)
800   *         ERR_ARG if conn is not a TCP netconn
801   */
802  err_t
netconn_recv_tcp_pbuf_flags(struct netconn * conn,struct pbuf ** new_buf,u8_t apiflags)803  netconn_recv_tcp_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags)
804  {
805    LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
806               NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
807  
808    return netconn_recv_data_tcp(conn, new_buf, apiflags);
809  }
810  #endif /* LWIP_TCP */
811  
812  /**
813   * Receive data (in form of a netbuf) from a UDP or RAW netconn
814   *
815   * @param conn the netconn from which to receive data
816   * @param new_buf pointer where a new netbuf is stored when received data
817   * @return ERR_OK if data has been received, an error code otherwise (timeout,
818   *                memory error or another error)
819   *         ERR_ARG if conn is not a UDP/RAW netconn
820   */
821  err_t
netconn_recv_udp_raw_netbuf(struct netconn * conn,struct netbuf ** new_buf)822  netconn_recv_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf)
823  {
824    LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) &&
825               NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;);
826  
827    return netconn_recv_data(conn, (void **)new_buf, 0);
828  }
829  
830  /**
831   * Receive data (in form of a netbuf) from a UDP or RAW netconn
832   *
833   * @param conn the netconn from which to receive data
834   * @param new_buf pointer where a new netbuf is stored when received data
835   * @param apiflags flags that control function behaviour. For now only:
836   * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
837   * @return ERR_OK if data has been received, an error code otherwise (timeout,
838   *                memory error or another error)
839   *         ERR_ARG if conn is not a UDP/RAW netconn
840   */
841  err_t
netconn_recv_udp_raw_netbuf_flags(struct netconn * conn,struct netbuf ** new_buf,u8_t apiflags)842  netconn_recv_udp_raw_netbuf_flags(struct netconn *conn, struct netbuf **new_buf, u8_t apiflags)
843  {
844    LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) &&
845               NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;);
846  
847    return netconn_recv_data(conn, (void **)new_buf, apiflags);
848  }
849  
850  /**
851   * @ingroup netconn_common
852   * Receive data (in form of a netbuf containing a packet buffer) from a netconn
853   *
854   * @param conn the netconn from which to receive data
855   * @param new_buf pointer where a new netbuf is stored when received data
856   * @return ERR_OK if data has been received, an error code otherwise (timeout,
857   *                memory error or another error)
858   */
859  err_t
netconn_recv(struct netconn * conn,struct netbuf ** new_buf)860  netconn_recv(struct netconn *conn, struct netbuf **new_buf)
861  {
862  #if LWIP_TCP
863    struct netbuf *buf = NULL;
864    err_t err;
865  #endif /* LWIP_TCP */
866  
867    LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
868    *new_buf = NULL;
869    LWIP_ERROR("netconn_recv: invalid conn",    (conn != NULL),    return ERR_ARG;);
870  
871  #if LWIP_TCP
872  #if (LWIP_UDP || LWIP_RAW)
873    if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
874  #endif /* (LWIP_UDP || LWIP_RAW) */
875    {
876      struct pbuf *p = NULL;
877      /* This is not a listening netconn, since recvmbox is set */
878  
879      buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
880      if (buf == NULL) {
881        return ERR_MEM;
882      }
883  
884      err = netconn_recv_data_tcp(conn, &p, 0);
885      if (err != ERR_OK) {
886        memp_free(MEMP_NETBUF, buf);
887        return err;
888      }
889      LWIP_ASSERT("p != NULL", p != NULL);
890  
891      buf->p = p;
892      buf->ptr = p;
893      buf->port = 0;
894      ip_addr_set_zero(&buf->addr);
895      *new_buf = buf;
896      /* don't set conn->last_err: it's only ERR_OK, anyway */
897      return ERR_OK;
898    }
899  #endif /* LWIP_TCP */
900  #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
901    else
902  #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
903    {
904  #if (LWIP_UDP || LWIP_RAW)
905      return netconn_recv_data(conn, (void **)new_buf, 0);
906  #endif /* (LWIP_UDP || LWIP_RAW) */
907    }
908  }
909  
910  /**
911   * @ingroup netconn_udp
912   * Send data (in form of a netbuf) to a specific remote IP address and port.
913   * Only to be used for UDP and RAW netconns (not TCP).
914   *
915   * @param conn the netconn over which to send data
916   * @param buf a netbuf containing the data to send
917   * @param addr the remote IP address to which to send the data
918   * @param port the remote port to which to send the data
919   * @return ERR_OK if data was sent, any other err_t on error
920   */
921  err_t
netconn_sendto(struct netconn * conn,struct netbuf * buf,const ip_addr_t * addr,u16_t port)922  netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port)
923  {
924    if (buf != NULL) {
925      ip_addr_set(&buf->addr, addr);
926      buf->port = port;
927      return netconn_send(conn, buf);
928    }
929    return ERR_VAL;
930  }
931  
932  /**
933   * @ingroup netconn_udp
934   * Send data over a UDP or RAW netconn (that is already connected).
935   *
936   * @param conn the UDP or RAW netconn over which to send data
937   * @param buf a netbuf containing the data to send
938   * @return ERR_OK if data was sent, any other err_t on error
939   */
940  err_t
netconn_send(struct netconn * conn,struct netbuf * buf)941  netconn_send(struct netconn *conn, struct netbuf *buf)
942  {
943    API_MSG_VAR_DECLARE(msg);
944    err_t err;
945  
946    LWIP_ERROR("netconn_send: invalid conn",  (conn != NULL), return ERR_ARG;);
947  
948    LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
949  
950    API_MSG_VAR_ALLOC(msg);
951    API_MSG_VAR_REF(msg).conn = conn;
952    API_MSG_VAR_REF(msg).msg.b = buf;
953    err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg));
954    API_MSG_VAR_FREE(msg);
955  
956    return err;
957  }
958  
959  /**
960   * @ingroup netconn_tcp
961   * Send data over a TCP netconn.
962   *
963   * @param conn the TCP netconn over which to send data
964   * @param dataptr pointer to the application buffer that contains the data to send
965   * @param size size of the application data to send
966   * @param apiflags combination of following flags :
967   * - NETCONN_COPY: data will be copied into memory belonging to the stack
968   * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
969   * - NETCONN_DONTBLOCK: only write the data if all data can be written at once
970   * @param bytes_written pointer to a location that receives the number of written bytes
971   * @return ERR_OK if data was sent, any other err_t on error
972   */
973  err_t
netconn_write_partly(struct netconn * conn,const void * dataptr,size_t size,u8_t apiflags,size_t * bytes_written)974  netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
975                       u8_t apiflags, size_t *bytes_written)
976  {
977    struct netvector vector;
978    vector.ptr = dataptr;
979    vector.len = size;
980    return netconn_write_vectors_partly(conn, &vector, 1, apiflags, bytes_written);
981  }
982  
983  /**
984   * Send vectorized data atomically over a TCP netconn.
985   *
986   * @param conn the TCP netconn over which to send data
987   * @param vectors array of vectors containing data to send
988   * @param vectorcnt number of vectors in the array
989   * @param apiflags combination of following flags :
990   * - NETCONN_COPY: data will be copied into memory belonging to the stack
991   * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
992   * - NETCONN_DONTBLOCK: only write the data if all data can be written at once
993   * @param bytes_written pointer to a location that receives the number of written bytes
994   * @return ERR_OK if data was sent, any other err_t on error
995   */
996  err_t
netconn_write_vectors_partly(struct netconn * conn,struct netvector * vectors,u16_t vectorcnt,u8_t apiflags,size_t * bytes_written)997  netconn_write_vectors_partly(struct netconn *conn, struct netvector *vectors, u16_t vectorcnt,
998                               u8_t apiflags, size_t *bytes_written)
999  {
1000    API_MSG_VAR_DECLARE(msg);
1001    err_t err;
1002    u8_t dontblock;
1003    size_t size;
1004    int i;
1005  
1006    LWIP_ERROR("netconn_write: invalid conn",  (conn != NULL), return ERR_ARG;);
1007    LWIP_ERROR("netconn_write: invalid conn->type",  (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP), return ERR_VAL;);
1008    dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
1009  #if LWIP_SO_SNDTIMEO
1010    if (conn->send_timeout != 0) {
1011      dontblock = 1;
1012    }
1013  #endif /* LWIP_SO_SNDTIMEO */
1014    if (dontblock && !bytes_written) {
1015      /* This implies netconn_write() cannot be used for non-blocking send, since
1016         it has no way to return the number of bytes written. */
1017      return ERR_VAL;
1018    }
1019  
1020    /* sum up the total size */
1021    size = 0;
1022    for (i = 0; i < vectorcnt; i++) {
1023      size += vectors[i].len;
1024      if (size < vectors[i].len) {
1025        /* overflow */
1026        return ERR_VAL;
1027      }
1028    }
1029    if (size == 0) {
1030      return ERR_OK;
1031    } else if (size > SSIZE_MAX) {
1032      ssize_t limited;
1033      /* this is required by the socket layer (cannot send full size_t range) */
1034      if (!bytes_written) {
1035        return ERR_VAL;
1036      }
1037      /* limit the amount of data to send */
1038      limited = SSIZE_MAX;
1039      size = (size_t)limited;
1040    }
1041  
1042    API_MSG_VAR_ALLOC(msg);
1043    /* non-blocking write sends as much  */
1044    API_MSG_VAR_REF(msg).conn = conn;
1045    API_MSG_VAR_REF(msg).msg.w.vector = vectors;
1046    API_MSG_VAR_REF(msg).msg.w.vector_cnt = vectorcnt;
1047    API_MSG_VAR_REF(msg).msg.w.vector_off = 0;
1048    API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags;
1049    API_MSG_VAR_REF(msg).msg.w.len = size;
1050    API_MSG_VAR_REF(msg).msg.w.offset = 0;
1051  #if LWIP_SO_SNDTIMEO
1052    if (conn->send_timeout != 0) {
1053      /* get the time we started, which is later compared to
1054          sys_now() + conn->send_timeout */
1055      API_MSG_VAR_REF(msg).msg.w.time_started = sys_now();
1056    } else {
1057      API_MSG_VAR_REF(msg).msg.w.time_started = 0;
1058    }
1059  #endif /* LWIP_SO_SNDTIMEO */
1060  
1061    /* For locking the core: this _can_ be delayed on low memory/low send buffer,
1062       but if it is, this is done inside api_msg.c:do_write(), so we can use the
1063       non-blocking version here. */
1064    err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg));
1065    if (err == ERR_OK) {
1066      if (bytes_written != NULL) {
1067        *bytes_written = API_MSG_VAR_REF(msg).msg.w.offset;
1068      }
1069      /* for blocking, check all requested bytes were written, NOTE: send_timeout is
1070         treated as dontblock (see dontblock assignment above) */
1071      if (!dontblock) {
1072        LWIP_ASSERT("do_write failed to write all bytes", API_MSG_VAR_REF(msg).msg.w.offset == size);
1073      }
1074    }
1075    API_MSG_VAR_FREE(msg);
1076  
1077    return err;
1078  }
1079  
1080  /**
1081   * @ingroup netconn_tcp
1082   * Close or shutdown a TCP netconn (doesn't delete it).
1083   *
1084   * @param conn the TCP netconn to close or shutdown
1085   * @param how fully close or only shutdown one side?
1086   * @return ERR_OK if the netconn was closed, any other err_t on error
1087   */
1088  static err_t
netconn_close_shutdown(struct netconn * conn,u8_t how)1089  netconn_close_shutdown(struct netconn *conn, u8_t how)
1090  {
1091    API_MSG_VAR_DECLARE(msg);
1092    err_t err;
1093    LWIP_UNUSED_ARG(how);
1094  
1095    LWIP_ERROR("netconn_close: invalid conn",  (conn != NULL), return ERR_ARG;);
1096  
1097    API_MSG_VAR_ALLOC(msg);
1098    API_MSG_VAR_REF(msg).conn = conn;
1099  #if LWIP_TCP
1100    /* shutting down both ends is the same as closing */
1101    API_MSG_VAR_REF(msg).msg.sd.shut = how;
1102  #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
1103    /* get the time we started, which is later compared to
1104       sys_now() + conn->send_timeout */
1105    API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
1106  #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1107    API_MSG_VAR_REF(msg).msg.sd.polls_left =
1108      ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
1109  #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1110  #endif /* LWIP_TCP */
1111    err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg));
1112    API_MSG_VAR_FREE(msg);
1113  
1114    return err;
1115  }
1116  
1117  /**
1118   * @ingroup netconn_tcp
1119   * Close a TCP netconn (doesn't delete it).
1120   *
1121   * @param conn the TCP netconn to close
1122   * @return ERR_OK if the netconn was closed, any other err_t on error
1123   */
1124  err_t
netconn_close(struct netconn * conn)1125  netconn_close(struct netconn *conn)
1126  {
1127    /* shutting down both ends is the same as closing */
1128    return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
1129  }
1130  
1131  /**
1132   * @ingroup netconn_common
1133   * Get and reset pending error on a netconn
1134   *
1135   * @param conn the netconn to get the error from
1136   * @return and pending error or ERR_OK if no error was pending
1137   */
1138  err_t
netconn_err(struct netconn * conn)1139  netconn_err(struct netconn *conn)
1140  {
1141    err_t err;
1142    SYS_ARCH_DECL_PROTECT(lev);
1143    if (conn == NULL) {
1144      return ERR_OK;
1145    }
1146    SYS_ARCH_PROTECT(lev);
1147    err = conn->pending_err;
1148    conn->pending_err = ERR_OK;
1149    SYS_ARCH_UNPROTECT(lev);
1150    return err;
1151  }
1152  
1153  /**
1154   * @ingroup netconn_tcp
1155   * Shut down one or both sides of a TCP netconn (doesn't delete it).
1156   *
1157   * @param conn the TCP netconn to shut down
1158   * @param shut_rx shut down the RX side (no more read possible after this)
1159   * @param shut_tx shut down the TX side (no more write possible after this)
1160   * @return ERR_OK if the netconn was closed, any other err_t on error
1161   */
1162  err_t
netconn_shutdown(struct netconn * conn,u8_t shut_rx,u8_t shut_tx)1163  netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
1164  {
1165    return netconn_close_shutdown(conn, (u8_t)((shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)));
1166  }
1167  
1168  #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
1169  /**
1170   * @ingroup netconn_udp
1171   * Join multicast groups for UDP netconns.
1172   *
1173   * @param conn the UDP netconn for which to change multicast addresses
1174   * @param multiaddr IP address of the multicast group to join or leave
1175   * @param netif_addr the IP address of the network interface on which to send
1176   *                  the igmp message
1177   * @param join_or_leave flag whether to send a join- or leave-message
1178   * @return ERR_OK if the action was taken, any err_t on error
1179   */
1180  err_t
netconn_join_leave_group(struct netconn * conn,const ip_addr_t * multiaddr,const ip_addr_t * netif_addr,enum netconn_igmp join_or_leave)1181  netconn_join_leave_group(struct netconn *conn,
1182                           const ip_addr_t *multiaddr,
1183                           const ip_addr_t *netif_addr,
1184                           enum netconn_igmp join_or_leave)
1185  {
1186    API_MSG_VAR_DECLARE(msg);
1187    err_t err;
1188  
1189    LWIP_ERROR("netconn_join_leave_group: invalid conn",  (conn != NULL), return ERR_ARG;);
1190  
1191    API_MSG_VAR_ALLOC(msg);
1192  
1193  #if LWIP_IPV4
1194    /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
1195    if (multiaddr == NULL) {
1196      multiaddr = IP4_ADDR_ANY;
1197    }
1198    if (netif_addr == NULL) {
1199      netif_addr = IP4_ADDR_ANY;
1200    }
1201  #endif /* LWIP_IPV4 */
1202  
1203    API_MSG_VAR_REF(msg).conn = conn;
1204    API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
1205    API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr);
1206    API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
1207    err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg));
1208    API_MSG_VAR_FREE(msg);
1209  
1210    return err;
1211  }
1212  /**
1213   * @ingroup netconn_udp
1214   * Join multicast groups for UDP netconns.
1215   *
1216   * @param conn the UDP netconn for which to change multicast addresses
1217   * @param multiaddr IP address of the multicast group to join or leave
1218   * @param if_idx the index of the netif
1219   * @param join_or_leave flag whether to send a join- or leave-message
1220   * @return ERR_OK if the action was taken, any err_t on error
1221   */
1222  err_t
netconn_join_leave_group_netif(struct netconn * conn,const ip_addr_t * multiaddr,u8_t if_idx,enum netconn_igmp join_or_leave)1223  netconn_join_leave_group_netif(struct netconn *conn,
1224                                 const ip_addr_t *multiaddr,
1225                                 u8_t if_idx,
1226                                 enum netconn_igmp join_or_leave)
1227  {
1228    API_MSG_VAR_DECLARE(msg);
1229    err_t err;
1230  
1231    LWIP_ERROR("netconn_join_leave_group: invalid conn",  (conn != NULL), return ERR_ARG;);
1232  
1233    API_MSG_VAR_ALLOC(msg);
1234  
1235  #if LWIP_IPV4
1236    /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
1237    if (multiaddr == NULL) {
1238      multiaddr = IP4_ADDR_ANY;
1239    }
1240    if (if_idx == NETIF_NO_INDEX) {
1241      return ERR_IF;
1242    }
1243  #endif /* LWIP_IPV4 */
1244  
1245    API_MSG_VAR_REF(msg).conn = conn;
1246    API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
1247    API_MSG_VAR_REF(msg).msg.jl.if_idx = if_idx;
1248    API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
1249    err = netconn_apimsg(lwip_netconn_do_join_leave_group_netif, &API_MSG_VAR_REF(msg));
1250    API_MSG_VAR_FREE(msg);
1251  
1252    return err;
1253  }
1254  #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
1255  
1256  #if LWIP_DNS
1257  /**
1258   * @ingroup netconn_common
1259   * Execute a DNS query, only one IP address is returned
1260   *
1261   * @param name a string representation of the DNS host name to query
1262   * @param addr a preallocated ip_addr_t where to store the resolved IP address
1263   * @param dns_addrtype IP address type (IPv4 / IPv6)
1264   * @return ERR_OK: resolving succeeded
1265   *         ERR_MEM: memory error, try again later
1266   *         ERR_ARG: dns client not initialized or invalid hostname
1267   *         ERR_VAL: dns server response was invalid
1268   */
1269  #if LWIP_IPV4 && LWIP_IPV6
1270  err_t
netconn_gethostbyname_addrtype(const char * name,ip_addr_t * addr,u8_t dns_addrtype)1271  netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype)
1272  #else
1273  err_t
1274  netconn_gethostbyname(const char *name, ip_addr_t *addr)
1275  #endif
1276  {
1277    API_VAR_DECLARE(struct dns_api_msg, msg);
1278  #if !LWIP_MPU_COMPATIBLE
1279    sys_sem_t sem;
1280  #endif /* LWIP_MPU_COMPATIBLE */
1281    err_t err;
1282    err_t cberr;
1283  
1284    LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
1285    LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
1286  #if LWIP_MPU_COMPATIBLE
1287    if (strlen(name) >= DNS_MAX_NAME_LENGTH) {
1288      return ERR_ARG;
1289    }
1290  #endif
1291  
1292  #ifdef LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE
1293  #if LWIP_IPV4 && LWIP_IPV6
1294    if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, dns_addrtype, &err)) {
1295  #else
1296    if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, NETCONN_DNS_DEFAULT, &err)) {
1297  #endif /* LWIP_IPV4 && LWIP_IPV6 */
1298      return err;
1299    }
1300  #endif /* LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE */
1301  
1302    API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM);
1303  #if LWIP_MPU_COMPATIBLE
1304    strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH - 1);
1305    API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH - 1] = 0;
1306  #else /* LWIP_MPU_COMPATIBLE */
1307    msg.err = &err;
1308    msg.sem = &sem;
1309    API_VAR_REF(msg).addr = API_VAR_REF(addr);
1310    API_VAR_REF(msg).name = name;
1311  #endif /* LWIP_MPU_COMPATIBLE */
1312  #if LWIP_IPV4 && LWIP_IPV6
1313    API_VAR_REF(msg).dns_addrtype = dns_addrtype;
1314  #endif /* LWIP_IPV4 && LWIP_IPV6 */
1315  #if LWIP_NETCONN_SEM_PER_THREAD
1316    API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET();
1317  #else /* LWIP_NETCONN_SEM_PER_THREAD*/
1318    err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0);
1319    if (err != ERR_OK) {
1320      API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1321      return err;
1322    }
1323  #endif /* LWIP_NETCONN_SEM_PER_THREAD */
1324  
1325    cberr = tcpip_send_msg_wait_sem(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg), API_EXPR_REF(API_VAR_REF(msg).sem));
1326  #if !LWIP_NETCONN_SEM_PER_THREAD
1327    sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
1328  #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
1329    if (cberr != ERR_OK) {
1330      API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1331      return cberr;
1332    }
1333  
1334  #if LWIP_MPU_COMPATIBLE
1335    *addr = msg->addr;
1336    err = msg->err;
1337  #endif /* LWIP_MPU_COMPATIBLE */
1338  
1339    API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1340    return err;
1341  }
1342  #endif /* LWIP_DNS*/
1343  
1344  #if LWIP_NETCONN_SEM_PER_THREAD
1345  void
1346  netconn_thread_init(void)
1347  {
1348    sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
1349    if (!sys_sem_valid(sem)) {
1350      /* call alloc only once */
1351      LWIP_NETCONN_THREAD_SEM_ALLOC();
1352      LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET()));
1353    }
1354  }
1355  
1356  void
1357  netconn_thread_cleanup(void)
1358  {
1359    sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
1360    if (sys_sem_valid(sem)) {
1361      /* call free only once */
1362      LWIP_NETCONN_THREAD_SEM_FREE();
1363    }
1364  }
1365  #endif /* LWIP_NETCONN_SEM_PER_THREAD */
1366  
1367  #endif /* LWIP_NETCONN */
1368