• 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,u16_t proto,netconn_callback callback)149 netconn_new_with_proto_and_callback(enum netconn_type t, u16_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 /*
225  * @ingroup netconn_common
226  * Finish an initiated Close for a netconn 'connection' and free its resources.
227  * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
228  * after this returns.
229  *
230  * @param conn the netconn to delete
231  * @return ERR_OK if the connection was deleted
232  */
233 inline void
netconn_finish_delete(struct netconn * conn)234 netconn_finish_delete(struct netconn *conn)
235 {
236   netconn_free(conn);
237   return;
238 }
239 
240 /**
241  * @ingroup netconn_common
242  * Close a netconn 'connection' and free its resources.
243  * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
244  * after this returns.
245  *
246  * @param conn the netconn to delete
247  * @return ERR_OK if the connection was deleted
248  */
249 err_t
netconn_delete(struct netconn * conn)250 netconn_delete(struct netconn *conn)
251 {
252   err_t err;
253 
254   /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
255   if (conn == NULL) {
256     return ERR_OK;
257   }
258 
259 #if LWIP_NETCONN_FULLDUPLEX
260   if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
261     /* Already called netconn_prepare_delete() before */
262     err = ERR_OK;
263   } else
264 #endif /* LWIP_NETCONN_FULLDUPLEX */
265   {
266     err = netconn_prepare_delete(conn);
267   }
268   if (err == ERR_OK) {
269     netconn_free(conn);
270   }
271   return err;
272 }
273 
274 /**
275  * Get the local or remote IP address and port of a netconn.
276  * For RAW netconns, this returns the protocol instead of a port!
277  *
278  * @param conn the netconn to query
279  * @param addr a pointer to which to save the IP address
280  * @param port a pointer to which to save the port (or protocol for RAW)
281  * @param local 1 to get the local IP address, 0 to get the remote one
282  * @return ERR_CONN for invalid connections
283  *         ERR_OK if the information was retrieved
284  */
285 err_t
netconn_getaddr(struct netconn * conn,ip_addr_t * addr,u16_t * port,u8_t local)286 netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
287 {
288   API_MSG_VAR_DECLARE(msg);
289   err_t err;
290 
291   LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
292   LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
293   LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
294 
295   API_MSG_VAR_ALLOC(msg);
296   API_MSG_VAR_REF(msg).conn = conn;
297   API_MSG_VAR_REF(msg).msg.ad.local = local;
298 #if LWIP_MPU_COMPATIBLE
299   err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg));
300   *addr = msg->msg.ad.ipaddr;
301   *port = msg->msg.ad.port;
302 #else /* LWIP_MPU_COMPATIBLE */
303   msg.msg.ad.ipaddr = addr;
304   msg.msg.ad.port = port;
305   err = netconn_apimsg(lwip_netconn_do_getaddr, &msg);
306 #endif /* LWIP_MPU_COMPATIBLE */
307   API_MSG_VAR_FREE(msg);
308 
309   return err;
310 }
311 
312 #if PF_PKT_SUPPORT
313 /**
314  * Get the local or remote IP address and port of a netconn.
315  * For pf pkt netconns, this returns the struct pf_pkt_ll of the netconn!
316  *
317  * @param conn the netconn to query
318  * @param local 1 to get the local IP address, 0 to get the remote one
319  * @return ERR_CONN for invalid connections
320  *         ERR_OK if the information was retrieved
321  *         ERR_OPNOTSUPP if the option is not support
322  */
323 err_t
netconn_getaddr_pfpkt(struct netconn * conn,struct pf_pkt_ll * ll,u8_t local)324 netconn_getaddr_pfpkt(struct netconn *conn, struct pf_pkt_ll *ll, u8_t local)
325 {
326   API_MSG_VAR_DECLARE(msg);
327   err_t err;
328 
329   LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
330   LWIP_ERROR("netconn_getaddr: invalid sockaddr_ll", (ll != NULL), return ERR_ARG;);
331 
332   API_MSG_VAR_ALLOC(msg);
333   API_MSG_VAR_REF(msg).conn = conn;
334   API_MSG_VAR_REF(msg).msg.adpkt.local = local;
335 #if LWIP_MPU_COMPATIBLE
336   err = netconn_apimsg(lwip_netconn_do_getaddr_pfpkt, &API_MSG_VAR_REF(msg));
337   *ll = msg->msg.adpkt.ll;
338 #else /* LWIP_MPU_COMPATIBLE */
339   API_MSG_VAR_REF(msg).msg.adpkt.ll = ll;
340   err = netconn_apimsg(lwip_netconn_do_getaddr_pfpkt, &msg);
341 #endif /* LWIP_MPU_COMPATIBLE */
342   API_MSG_VAR_FREE(msg);
343 
344   return err;
345 }
346 #endif
347 
348 /**
349  * @ingroup netconn_common
350  * Bind a netconn to a specific local IP address and port.
351  * Binding one netconn twice might not always be checked correctly!
352  *
353  * @param conn the netconn to bind
354  * @param addr the local IP address to bind the netconn to
355  *             (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses)
356  * @param port the local port to bind the netconn to (not used for RAW)
357  * @return ERR_OK if bound, any other err_t on failure
358  */
359 err_t
360 #if PF_PKT_SUPPORT
netconn_bind(struct netconn * conn,const ip_addr_t * addr,u16_t port,u8_t ifindex)361 netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port, u8_t ifindex)
362 #else
363 netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port)
364 #endif
365 {
366   API_MSG_VAR_DECLARE(msg);
367   err_t err;
368 
369   LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
370 
371 #if LWIP_IPV4
372   /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
373   if (addr == NULL) {
374     addr = IP4_ADDR_ANY;
375   }
376 #endif /* LWIP_IPV4 */
377 
378 #if LWIP_IPV4 && LWIP_IPV6
379   /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY,
380    * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind
381    */
382   if ((netconn_get_ipv6only(conn) == 0) &&
383       ip_addr_cmp(addr, IP6_ADDR_ANY)) {
384     addr = IP_ANY_TYPE;
385   }
386 #endif /* LWIP_IPV4 && LWIP_IPV6 */
387 
388   API_MSG_VAR_ALLOC(msg);
389   API_MSG_VAR_REF(msg).conn = conn;
390   API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
391   API_MSG_VAR_REF(msg).msg.bc.port = port;
392 #if PF_PKT_SUPPORT
393   API_MSG_VAR_REF(msg).msg.bc.if_idx = ifindex;
394 #endif
395   err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg));
396   API_MSG_VAR_FREE(msg);
397 
398   return err;
399 }
400 
401 /**
402  * @ingroup netconn_common
403  * Bind a netconn to a specific interface and port.
404  * Binding one netconn twice might not always be checked correctly!
405  *
406  * @param conn the netconn to bind
407  * @param if_idx the local interface index to bind the netconn to
408  * @return ERR_OK if bound, any other err_t on failure
409  */
410 err_t
netconn_bind_if(struct netconn * conn,u8_t if_idx)411 netconn_bind_if(struct netconn *conn, u8_t if_idx)
412 {
413   API_MSG_VAR_DECLARE(msg);
414   err_t err;
415 
416   LWIP_ERROR("netconn_bind_if: invalid conn", (conn != NULL), return ERR_ARG;);
417 
418   API_MSG_VAR_ALLOC(msg);
419   API_MSG_VAR_REF(msg).conn = conn;
420   API_MSG_VAR_REF(msg).msg.bc.if_idx = if_idx;
421   err = netconn_apimsg(lwip_netconn_do_bind_if, &API_MSG_VAR_REF(msg));
422   API_MSG_VAR_FREE(msg);
423 
424   return err;
425 }
426 
427 /**
428  * @ingroup netconn_common
429  * Connect a netconn to a specific remote IP address and port.
430  *
431  * @param conn the netconn to connect
432  * @param addr the remote IP address to connect to
433  * @param port the remote port to connect to (no used for RAW)
434  * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
435  */
436 err_t
netconn_connect(struct netconn * conn,const ip_addr_t * addr,u16_t port)437 netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port)
438 {
439   API_MSG_VAR_DECLARE(msg);
440   err_t err;
441 
442   LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
443 
444 #if LWIP_IPV4
445   /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
446   if (addr == NULL) {
447     addr = IP4_ADDR_ANY;
448   }
449 #endif /* LWIP_IPV4 */
450 
451   API_MSG_VAR_ALLOC(msg);
452   API_MSG_VAR_REF(msg).conn = conn;
453   API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
454   API_MSG_VAR_REF(msg).msg.bc.port = port;
455   err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg));
456   API_MSG_VAR_FREE(msg);
457 
458   return err;
459 }
460 
461 /**
462  * @ingroup netconn_udp
463  * Disconnect a netconn from its current peer (only valid for UDP netconns).
464  *
465  * @param conn the netconn to disconnect
466  * @return See @ref err_t
467  */
468 err_t
netconn_disconnect(struct netconn * conn)469 netconn_disconnect(struct netconn *conn)
470 {
471   API_MSG_VAR_DECLARE(msg);
472   err_t err;
473 
474   LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
475 
476   API_MSG_VAR_ALLOC(msg);
477   API_MSG_VAR_REF(msg).conn = conn;
478   err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg));
479   API_MSG_VAR_FREE(msg);
480 
481   return err;
482 }
483 
484 /**
485  * @ingroup netconn_tcp
486  * Set a TCP netconn into listen mode
487  *
488  * @param conn the tcp netconn to set to listen mode
489  * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
490  * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
491  *         don't return any error (yet?))
492  */
493 err_t
netconn_listen_with_backlog(struct netconn * conn,u8_t backlog)494 netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
495 {
496 #if LWIP_TCP
497   API_MSG_VAR_DECLARE(msg);
498   err_t err;
499 
500   /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
501   LWIP_UNUSED_ARG(backlog);
502 
503   LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
504 
505   API_MSG_VAR_ALLOC(msg);
506   API_MSG_VAR_REF(msg).conn = conn;
507 #if TCP_LISTEN_BACKLOG
508   API_MSG_VAR_REF(msg).msg.lb.backlog = backlog;
509 #endif /* TCP_LISTEN_BACKLOG */
510   err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg));
511   API_MSG_VAR_FREE(msg);
512 
513   return err;
514 #else /* LWIP_TCP */
515   LWIP_UNUSED_ARG(conn);
516   LWIP_UNUSED_ARG(backlog);
517   return ERR_ARG;
518 #endif /* LWIP_TCP */
519 }
520 
521 /**
522  * @ingroup netconn_tcp
523  * Accept a new connection on a TCP listening netconn.
524  *
525  * @param conn the TCP listen netconn
526  * @param new_conn pointer where the new connection is stored
527  * @return ERR_OK if a new connection has been received or an error
528  *                code otherwise
529  */
530 err_t
netconn_accept(struct netconn * conn,struct netconn ** new_conn)531 netconn_accept(struct netconn *conn, struct netconn **new_conn)
532 {
533 #if LWIP_TCP
534   err_t err;
535   void *accept_ptr;
536   struct netconn *newconn;
537 #if TCP_LISTEN_BACKLOG
538   API_MSG_VAR_DECLARE(msg);
539 #endif /* TCP_LISTEN_BACKLOG */
540 
541   LWIP_ERROR("netconn_accept: invalid pointer",    (new_conn != NULL),                  return ERR_VAL);
542   *new_conn = NULL;
543   LWIP_ERROR("netconn_accept: invalid conn",       (conn != NULL),                      return ERR_VAL);
544 
545   /* NOTE: Although the opengroup spec says a pending error shall be returned to
546            send/recv/getsockopt(SO_ERROR) only, we return it for listening
547            connections also, to handle embedded-system errors */
548   err = netconn_err(conn);
549   if (ERR_IS_FATAL(err)) {
550     /* return pending error */
551     return err;
552   }
553   if (!NETCONN_ACCEPTMBOX_WAITABLE(conn)) {
554     /* don't accept if closed: this might block the application task
555        waiting on acceptmbox forever! */
556     return ERR_CLSD;
557   }
558 
559   API_MSG_VAR_ALLOC_ACCEPT(msg);
560 
561   NETCONN_MBOX_WAITING_INC(conn);
562   if (netconn_is_nonblocking(conn)) {
563     if (sys_arch_mbox_tryfetch(&conn->acceptmbox, &accept_ptr) == SYS_MBOX_EMPTY) {
564       API_MSG_VAR_FREE_ACCEPT(msg);
565       NETCONN_MBOX_WAITING_DEC(conn);
566       return ERR_WOULDBLOCK;
567     }
568   } else {
569 #if LWIP_SO_RCVTIMEO
570     if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
571       API_MSG_VAR_FREE_ACCEPT(msg);
572       NETCONN_MBOX_WAITING_DEC(conn);
573       return ERR_TIMEOUT;
574     }
575 #else
576     sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0);
577 #endif /* LWIP_SO_RCVTIMEO*/
578   }
579   NETCONN_MBOX_WAITING_DEC(conn);
580 #if LWIP_NETCONN_FULLDUPLEX
581   if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
582     if (lwip_netconn_is_deallocated_msg(accept_ptr)) {
583       /* the netconn has been closed from another thread */
584       API_MSG_VAR_FREE_ACCEPT(msg);
585       return ERR_CLSD;
586     }
587   }
588 #endif
589 
590   /* Register event with callback */
591   API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
592 
593   if (lwip_netconn_is_err_msg(accept_ptr, &err)) {
594     /* a connection has been aborted: e.g. out of pcbs or out of netconns during accept */
595     API_MSG_VAR_FREE_ACCEPT(msg);
596     return err;
597   }
598   if (accept_ptr == NULL) {
599     /* connection has been aborted */
600     API_MSG_VAR_FREE_ACCEPT(msg);
601     return ERR_CLSD;
602   }
603   newconn = (struct netconn *)accept_ptr;
604 
605 #if LWIP_SO_RCVBUF
606   SYS_ARCH_DEC(conn->recv_avail, 1);
607 #endif /* LWIP_SO_RCVBUF */
608 
609 #if TCP_LISTEN_BACKLOG
610   /* Let the stack know that we have accepted the connection. */
611   API_MSG_VAR_REF(msg).conn = newconn;
612   /* don't care for the return value of lwip_netconn_do_recv */
613   netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg));
614   API_MSG_VAR_FREE(msg);
615 #endif /* TCP_LISTEN_BACKLOG */
616 
617   *new_conn = newconn;
618   /* don't set conn->last_err: it's only ERR_OK, anyway */
619   return ERR_OK;
620 #else /* LWIP_TCP */
621   LWIP_UNUSED_ARG(conn);
622   LWIP_UNUSED_ARG(new_conn);
623   return ERR_ARG;
624 #endif /* LWIP_TCP */
625 }
626 
627 /**
628  * @ingroup netconn_common
629  * Receive data: actual implementation that doesn't care whether pbuf or netbuf
630  * is received (this is internal, it's just here for describing common errors)
631  *
632  * @param conn the netconn from which to receive data
633  * @param new_buf pointer where a new pbuf/netbuf is stored when received data
634  * @param apiflags flags that control function behaviour. For now only:
635  * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
636  * @return ERR_OK if data has been received, an error code otherwise (timeout,
637  *                memory error or another error)
638  *         ERR_CONN if not connected
639  *         ERR_CLSD if TCP connection has been closed
640  *         ERR_WOULDBLOCK if the netconn is nonblocking but would block to wait for data
641  *         ERR_TIMEOUT if the netconn has a receive timeout and no data was received
642  */
643 static err_t
netconn_recv_data(struct netconn * conn,void ** new_buf,u8_t apiflags)644 netconn_recv_data(struct netconn *conn, void **new_buf, u8_t apiflags)
645 {
646   void *buf = NULL;
647   u16_t len;
648 
649   LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
650   *new_buf = NULL;
651   LWIP_ERROR("netconn_recv: invalid conn",    (conn != NULL),    return ERR_ARG;);
652 
653   if (!NETCONN_RECVMBOX_WAITABLE(conn))
654   {
655 #if LWIP_TCP
656     if (NETCONN_ACCEPTMBOX_WAITABLE(conn)) {
657       return ERR_CONN;
658     }
659 #endif /* LWIP_TCP */
660     return ERR_CLSD;
661   }
662 
663   err_t err = netconn_err(conn);
664   if (ERR_IS_FATAL(err)) {
665 #if LWIP_TCP
666     u32_t fetch_ret;
667     u16_t pending_err;
668     SYS_ARCH_DECL_PROTECT(lev);
669 
670     pending_err = conn->pending_err;
671     if (pending_err) {
672       /* NETCONN_PENDING_ERR_RST: Entry state. In this state will try to fetch all data segments/FIN/RST from recvmbox.
673       If RST can be fetched from recvmbox, then will finish RST processing (pending_error = 0). Else should do:
674       If refused_data is empty, set pending_error to 0 and finish.
675       If refused_data is not empty, and the flag doesn't contains FIN, then should pass the data to user,
676         and go to NETCONN_READY_ERR_RST.
677       If refused_data is not empty, and the flag contains FIN, then should pass the data to user,
678         and go to NETCONN_PENDING_ERR_CLSD.
679       NETCONN_PENDING_ERR_CLSD: The data in refused_data contains FIN, and is already read,
680         we should return ERR_CLSD to indicate FIN.
681       NETCONN_READY_ERR_RST: The data in refused_data is processed, we should return ERR_RST.
682       */
683       switch (pending_err) {
684         case NETCONN_PENDING_ERR_FIN_RST:
685           /* fall-through */
686         case NETCONN_PENDING_ERR_RST:
687           fetch_ret = sys_arch_mbox_tryfetch(&conn->recvmbox, &buf);
688           if ((fetch_ret == SYS_MBOX_EMPTY) || (buf == &netconn_reset) ||
689               (buf == &netconn_aborted) || (buf == &netconn_closed)) {
690             /* No buffer left or race condition, reset pending_error. */
691             if ((fetch_ret == SYS_MBOX_EMPTY) && (conn->refused_data != NULL)) {
692               *new_buf = conn->refused_data;
693               SYS_ARCH_PROTECT(lev);
694               conn->pending_err = (u16_t)((conn->refused_data->flags & PBUF_FLAG_TCP_FIN) ? \
695                 NETCONN_PENDING_ERR_CLSD : NETCONN_READY_ERR_RST);
696               conn->refused_data = NULL;
697               SYS_ARCH_UNPROTECT(lev);
698               err = ERR_OK;
699             } else {
700               if (pending_err == NETCONN_PENDING_ERR_FIN_RST) {
701                 SYS_ARCH_PROTECT(lev);
702                 conn->pending_err = NETCONN_PENDING_ERR_RST;
703                 SYS_ARCH_UNPROTECT(lev);
704                 return ERR_CLSD;
705               }
706               (void)lwip_netconn_is_err_msg(buf, &err);
707               SYS_ARCH_PROTECT(lev);
708               conn->pending_err = 0;
709               SYS_ARCH_UNPROTECT(lev);
710             }
711             return err;
712           } else {
713             API_EVENT(conn, NETCONN_EVT_RCVMINUS, (buf == NULL ? (u32_t)1 : ((struct pbuf *)buf)->tot_len));
714             *new_buf = buf;
715             /* Don't have to inform stack about reading data, since it's already in RST state. */
716             return buf == NULL ? ERR_CLSD : ERR_OK;
717           }
718         case NETCONN_PENDING_ERR_CLSD:
719           SYS_ARCH_PROTECT(lev);
720           conn->pending_err = NETCONN_READY_ERR_RST;
721           SYS_ARCH_UNPROTECT(lev);
722           return ERR_CLSD;
723         case NETCONN_READY_ERR_RST:
724           SYS_ARCH_PROTECT(lev);
725           conn->pending_err = 0;
726           SYS_ARCH_UNPROTECT(lev);
727           return err;
728         default:
729           LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: unknown pending_error\n"));
730           break;
731       }
732     }
733 #endif
734     return err;
735   }
736 
737   NETCONN_MBOX_WAITING_INC(conn);
738   if (netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK) ||
739       (conn->flags & NETCONN_FLAG_MBOXCLOSED)) {
740     if (sys_arch_mbox_tryfetch(&conn->recvmbox, &buf) == SYS_MBOX_EMPTY) {
741       NETCONN_MBOX_WAITING_DEC(conn);
742       if (conn->flags & NETCONN_FLAG_MBOXCLOSED) {
743         return ERR_CONN;
744       }
745       return ERR_WOULDBLOCK;
746     }
747   } else {
748 #if LWIP_SO_RCVTIMEO
749     if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
750       NETCONN_MBOX_WAITING_DEC(conn);
751       return ERR_TIMEOUT;
752     }
753 #else
754     sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
755 #endif /* LWIP_SO_RCVTIMEO*/
756   }
757   NETCONN_MBOX_WAITING_DEC(conn);
758 #if LWIP_NETCONN_FULLDUPLEX
759   if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
760     if (lwip_netconn_is_deallocated_msg(buf)) {
761       /* the netconn has been closed from another thread */
762       return ERR_CLSD;
763     }
764   }
765 #endif
766 
767 #if LWIP_TCP
768 #if (LWIP_UDP || LWIP_RAW)
769   if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
770 #endif /* (LWIP_UDP || LWIP_RAW) */
771   {
772     /* Check if this is an error message or a pbuf */
773     if (lwip_netconn_is_err_msg(buf, &err)) {
774       /* new_buf has been zeroed above already */
775       if (err == ERR_CLSD) {
776         /* connection closed translates to ERR_OK with *new_buf == NULL */
777         return ERR_OK;
778       }
779       return err;
780     }
781     len = ((struct pbuf *)buf)->tot_len;
782   }
783 #endif /* LWIP_TCP */
784 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
785   else
786 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
787 #if (LWIP_UDP || LWIP_RAW)
788   {
789     LWIP_ASSERT("buf != NULL", buf != NULL);
790     len = netbuf_len((struct netbuf *)buf);
791   }
792 #endif /* (LWIP_UDP || LWIP_RAW) */
793 
794 #if LWIP_SO_RCVBUF
795   SYS_ARCH_DEC(conn->recv_avail, len);
796 #endif /* LWIP_SO_RCVBUF */
797   /* Register event with callback */
798   API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
799 
800   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
801 
802   *new_buf = buf;
803   /* don't set conn->last_err: it's only ERR_OK, anyway */
804   return ERR_OK;
805 }
806 
807 #if LWIP_TCP
808 static err_t
netconn_tcp_recvd_msg(struct netconn * conn,size_t len,struct api_msg * msg)809 netconn_tcp_recvd_msg(struct netconn *conn, size_t len, struct api_msg *msg)
810 {
811   LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
812              NETCONNTYPE_GROUP(NETCONN_TYPE(conn)) == NETCONN_TCP, return ERR_ARG;);
813 
814   msg->conn = conn;
815   msg->msg.r.len = len;
816 
817   return netconn_apimsg(lwip_netconn_do_recv, msg);
818 }
819 
820 err_t
netconn_tcp_recvd(struct netconn * conn,size_t len)821 netconn_tcp_recvd(struct netconn *conn, size_t len)
822 {
823   err_t err;
824   API_MSG_VAR_DECLARE(msg);
825   LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
826              NETCONNTYPE_GROUP(NETCONN_TYPE(conn)) == NETCONN_TCP, return ERR_ARG;);
827 
828   API_MSG_VAR_ALLOC(msg);
829   err = netconn_tcp_recvd_msg(conn, len, &API_VAR_REF(msg));
830   API_MSG_VAR_FREE(msg);
831   return err;
832 }
833 
834 static err_t
netconn_recv_data_tcp(struct netconn * conn,struct pbuf ** new_buf,u8_t apiflags)835 netconn_recv_data_tcp(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags)
836 {
837   err_t err;
838   struct pbuf *buf;
839   API_MSG_VAR_DECLARE(msg);
840 #if LWIP_MPU_COMPATIBLE
841   msg = NULL;
842 #endif
843 
844   if (netconn_is_flag_set(conn, NETCONN_FIN_RX_PENDING)) {
845     netconn_clear_flags(conn, NETCONN_FIN_RX_PENDING);
846     goto handle_fin;
847   }
848 
849   if (!(apiflags & NETCONN_NOAUTORCVD)) {
850     /* need to allocate API message here so empty message pool does not result in event loss
851       * see bug #47512: MPU_COMPATIBLE may fail on empty pool */
852     API_MSG_VAR_ALLOC(msg);
853   }
854 
855   err = netconn_recv_data(conn, (void **)new_buf, apiflags);
856   if (err != ERR_OK) {
857     if (!(apiflags & NETCONN_NOAUTORCVD)) {
858       API_MSG_VAR_FREE(msg);
859     }
860     return err;
861   }
862   buf = *new_buf;
863   if (!(apiflags & NETCONN_NOAUTORCVD)) {
864     /* Let the stack know that we have taken the data. */
865     u16_t len = buf ? buf->tot_len : 1;
866     /* don't care for the return value of lwip_netconn_do_recv */
867     /* @todo: this should really be fixed, e.g. by retrying in poll on error */
868     netconn_tcp_recvd_msg(conn, len,  &API_VAR_REF(msg));
869     API_MSG_VAR_FREE(msg);
870   }
871 
872   /* If we are closed, we indicate that we no longer wish to use the socket */
873   if (buf == NULL) {
874     if (apiflags & NETCONN_NOFIN) {
875       /* received a FIN but the caller cannot handle it right now:
876          re-enqueue it and return "no data" */
877       netconn_set_flags(conn, NETCONN_FIN_RX_PENDING);
878       return ERR_WOULDBLOCK;
879     } else {
880 handle_fin:
881       API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
882       if (conn->pcb.ip == NULL) {
883         /* race condition: RST during recv */
884         err = netconn_err(conn);
885         if (ERR_IS_FATAL(err)) {
886           return err;
887         }
888         return ERR_RST;
889       }
890       /* RX side is closed, so deallocate the recvmbox */
891       netconn_close_shutdown(conn, NETCONN_SHUT_RD);
892       /* Don' store ERR_CLSD as conn->err since we are only half-closed */
893       return ERR_CLSD;
894     }
895   }
896   return err;
897 }
898 
899 /**
900  * @ingroup netconn_tcp
901  * Receive data (in form of a pbuf) from a TCP netconn
902  *
903  * @param conn the netconn from which to receive data
904  * @param new_buf pointer where a new pbuf is stored when received data
905  * @return ERR_OK if data has been received, an error code otherwise (timeout,
906  *                memory error or another error, @see netconn_recv_data)
907  *         ERR_ARG if conn is not a TCP netconn
908  */
909 err_t
netconn_recv_tcp_pbuf(struct netconn * conn,struct pbuf ** new_buf)910 netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
911 {
912   LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
913              NETCONNTYPE_GROUP(NETCONN_TYPE(conn)) == NETCONN_TCP, return ERR_ARG;);
914 
915   return netconn_recv_data_tcp(conn, new_buf, 0);
916 }
917 
918 /**
919  * @ingroup netconn_tcp
920  * Receive data (in form of a pbuf) from a TCP netconn
921  *
922  * @param conn the netconn from which to receive data
923  * @param new_buf pointer where a new pbuf is stored when received data
924  * @param apiflags flags that control function behaviour. For now only:
925  * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
926  * @return ERR_OK if data has been received, an error code otherwise (timeout,
927  *                memory error or another error, @see netconn_recv_data)
928  *         ERR_ARG if conn is not a TCP netconn
929  */
930 err_t
netconn_recv_tcp_pbuf_flags(struct netconn * conn,struct pbuf ** new_buf,u8_t apiflags)931 netconn_recv_tcp_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags)
932 {
933   LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
934              NETCONNTYPE_GROUP(NETCONN_TYPE(conn)) == NETCONN_TCP, return ERR_ARG;);
935 
936   return netconn_recv_data_tcp(conn, new_buf, apiflags);
937 }
938 #endif /* LWIP_TCP */
939 
940 /**
941  * Receive data (in form of a netbuf) from a UDP or RAW netconn
942  *
943  * @param conn the netconn from which to receive data
944  * @param new_buf pointer where a new netbuf is stored when received data
945  * @return ERR_OK if data has been received, an error code otherwise (timeout,
946  *                memory error or another error)
947  *         ERR_ARG if conn is not a UDP/RAW netconn
948  */
949 err_t
netconn_recv_udp_raw_netbuf(struct netconn * conn,struct netbuf ** new_buf)950 netconn_recv_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf)
951 {
952   LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) &&
953              NETCONNTYPE_GROUP(NETCONN_TYPE(conn)) != NETCONN_TCP, return ERR_ARG;);
954 
955   return netconn_recv_data(conn, (void **)new_buf, 0);
956 }
957 
958 /**
959  * Receive data (in form of a netbuf) from a UDP or RAW netconn
960  *
961  * @param conn the netconn from which to receive data
962  * @param new_buf pointer where a new netbuf is stored when received data
963  * @param apiflags flags that control function behaviour. For now only:
964  * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
965  * @return ERR_OK if data has been received, an error code otherwise (timeout,
966  *                memory error or another error)
967  *         ERR_ARG if conn is not a UDP/RAW netconn
968  */
969 err_t
netconn_recv_udp_raw_netbuf_flags(struct netconn * conn,struct netbuf ** new_buf,u8_t apiflags)970 netconn_recv_udp_raw_netbuf_flags(struct netconn *conn, struct netbuf **new_buf, u8_t apiflags)
971 {
972   LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) &&
973              NETCONNTYPE_GROUP(NETCONN_TYPE(conn)) != NETCONN_TCP, return ERR_ARG;);
974 
975   return netconn_recv_data(conn, (void **)new_buf, apiflags);
976 }
977 
978 /**
979  * @ingroup netconn_common
980  * Receive data (in form of a netbuf containing a packet buffer) from a netconn
981  *
982  * @param conn the netconn from which to receive data
983  * @param new_buf pointer where a new netbuf is stored when received data
984  * @return ERR_OK if data has been received, an error code otherwise (timeout,
985  *                memory error or another error)
986  */
987 err_t
netconn_recv(struct netconn * conn,struct netbuf ** new_buf)988 netconn_recv(struct netconn *conn, struct netbuf **new_buf)
989 {
990 #if LWIP_TCP
991   struct netbuf *buf = NULL;
992   err_t err;
993 #endif /* LWIP_TCP */
994 
995   LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
996   *new_buf = NULL;
997   LWIP_ERROR("netconn_recv: invalid conn",    (conn != NULL),    return ERR_ARG;);
998 
999 #if LWIP_TCP
1000 #if (LWIP_UDP || LWIP_RAW)
1001   if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
1002 #endif /* (LWIP_UDP || LWIP_RAW) */
1003   {
1004     struct pbuf *p = NULL;
1005     /* This is not a listening netconn, since recvmbox is set */
1006 
1007     buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
1008     if (buf == NULL) {
1009       return ERR_MEM;
1010     }
1011 
1012     err = netconn_recv_data_tcp(conn, &p, 0);
1013     if (err != ERR_OK) {
1014       memp_free(MEMP_NETBUF, buf);
1015       return err;
1016     }
1017     LWIP_ASSERT("p != NULL", p != NULL);
1018 
1019     buf->p = p;
1020     buf->ptr = p;
1021     buf->port = 0;
1022     ip_addr_set_zero(&buf->addr);
1023     *new_buf = buf;
1024     /* don't set conn->last_err: it's only ERR_OK, anyway */
1025     return ERR_OK;
1026   }
1027 #endif /* LWIP_TCP */
1028 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
1029   else
1030 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
1031   {
1032 #if (LWIP_UDP || LWIP_RAW)
1033     return netconn_recv_data(conn, (void **)new_buf, 0);
1034 #endif /* (LWIP_UDP || LWIP_RAW) */
1035   }
1036 }
1037 
1038 /**
1039  * @ingroup netconn_udp
1040  * Send data (in form of a netbuf) to a specific remote IP address and port.
1041  * Only to be used for UDP and RAW netconns (not TCP).
1042  *
1043  * @param conn the netconn over which to send data
1044  * @param buf a netbuf containing the data to send
1045  * @param addr the remote IP address to which to send the data
1046  * @param port the remote port to which to send the data
1047  * @return ERR_OK if data was sent, any other err_t on error
1048  */
1049 err_t
netconn_sendto(struct netconn * conn,struct netbuf * buf,const ip_addr_t * addr,u16_t port)1050 netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port)
1051 {
1052   if (buf != NULL) {
1053     ip_addr_set(&buf->addr, addr);
1054     buf->port = port;
1055     return netconn_send(conn, buf);
1056   }
1057   return ERR_VAL;
1058 }
1059 
1060 /**
1061  * @ingroup netconn_udp
1062  * Send data over a UDP or RAW netconn (that is already connected).
1063  *
1064  * @param conn the UDP or RAW netconn over which to send data
1065  * @param buf a netbuf containing the data to send
1066  * @return ERR_OK if data was sent, any other err_t on error
1067  */
1068 err_t
netconn_send(struct netconn * conn,struct netbuf * buf)1069 netconn_send(struct netconn *conn, struct netbuf *buf)
1070 {
1071   API_MSG_VAR_DECLARE(msg);
1072   err_t err;
1073 
1074   LWIP_ERROR("netconn_send: invalid conn",  (conn != NULL), return ERR_ARG;);
1075 
1076   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
1077 
1078   API_MSG_VAR_ALLOC(msg);
1079   API_MSG_VAR_REF(msg).conn = conn;
1080   API_MSG_VAR_REF(msg).msg.b = buf;
1081   err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg));
1082   API_MSG_VAR_FREE(msg);
1083 
1084   return err;
1085 }
1086 
1087 /**
1088  * @ingroup netconn_tcp
1089  * Send data over a TCP netconn.
1090  *
1091  * @param conn the TCP netconn over which to send data
1092  * @param dataptr pointer to the application buffer that contains the data to send
1093  * @param size size of the application data to send
1094  * @param apiflags combination of following flags :
1095  * - NETCONN_COPY: data will be copied into memory belonging to the stack
1096  * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
1097  * - NETCONN_DONTBLOCK: only write the data if all data can be written at once
1098  * @param bytes_written pointer to a location that receives the number of written bytes
1099  * @return ERR_OK if data was sent, any other err_t on error
1100  */
1101 err_t
netconn_write_partly(struct netconn * conn,const void * dataptr,size_t size,u8_t apiflags,size_t * bytes_written)1102 netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
1103                      u8_t apiflags, size_t *bytes_written)
1104 {
1105   struct netvector vector;
1106   vector.ptr = dataptr;
1107   vector.len = size;
1108   return netconn_write_vectors_partly(conn, &vector, 1, apiflags, bytes_written);
1109 }
1110 
1111 /**
1112  * Send vectorized data atomically over a TCP netconn.
1113  *
1114  * @param conn the TCP netconn over which to send data
1115  * @param vectors array of vectors containing data to send
1116  * @param vectorcnt number of vectors in the array
1117  * @param apiflags combination of following flags :
1118  * - NETCONN_COPY: data will be copied into memory belonging to the stack
1119  * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
1120  * - NETCONN_DONTBLOCK: only write the data if all data can be written at once
1121  * @param bytes_written pointer to a location that receives the number of written bytes
1122  * @return ERR_OK if data was sent, any other err_t on error
1123  */
1124 err_t
netconn_write_vectors_partly(struct netconn * conn,struct netvector * vectors,u16_t vectorcnt,u8_t apiflags,size_t * bytes_written)1125 netconn_write_vectors_partly(struct netconn *conn, struct netvector *vectors, u16_t vectorcnt,
1126                              u8_t apiflags, size_t *bytes_written)
1127 {
1128   API_MSG_VAR_DECLARE(msg);
1129   err_t err;
1130   u8_t dontblock;
1131   size_t size;
1132   int i;
1133 
1134   LWIP_ERROR("netconn_write: invalid conn",  (conn != NULL), return ERR_ARG;);
1135   LWIP_ERROR("netconn_write: invalid conn->type",  (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP), return ERR_VAL;);
1136   dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
1137 #if LWIP_SO_SNDTIMEO
1138   if (conn->send_timeout != 0) {
1139     dontblock = 1;
1140   }
1141 #endif /* LWIP_SO_SNDTIMEO */
1142   if (dontblock && !bytes_written) {
1143     /* This implies netconn_write() cannot be used for non-blocking send, since
1144        it has no way to return the number of bytes written. */
1145     return ERR_VAL;
1146   }
1147 
1148   /* sum up the total size */
1149   size = 0;
1150   for (i = 0; i < vectorcnt; i++) {
1151     size += vectors[i].len;
1152     if (size < vectors[i].len) {
1153       /* overflow */
1154       return ERR_VAL;
1155     }
1156   }
1157   if (size == 0) {
1158     return ERR_OK;
1159   } else if (size > SSIZE_MAX) {
1160     ssize_t limited;
1161     /* this is required by the socket layer (cannot send full size_t range) */
1162     if (!bytes_written) {
1163       return ERR_VAL;
1164     }
1165     /* limit the amount of data to send */
1166     limited = SSIZE_MAX;
1167     size = (size_t)limited;
1168   }
1169 
1170   API_MSG_VAR_ALLOC(msg);
1171   /* non-blocking write sends as much  */
1172   API_MSG_VAR_REF(msg).conn = conn;
1173   API_MSG_VAR_REF(msg).msg.w.vector = vectors;
1174   API_MSG_VAR_REF(msg).msg.w.vector_cnt = vectorcnt;
1175   API_MSG_VAR_REF(msg).msg.w.vector_off = 0;
1176   API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags;
1177   API_MSG_VAR_REF(msg).msg.w.len = size;
1178   API_MSG_VAR_REF(msg).msg.w.offset = 0;
1179 #if LWIP_SO_SNDTIMEO
1180   if (conn->send_timeout != 0) {
1181     /* get the time we started, which is later compared to
1182         sys_now() + conn->send_timeout */
1183     API_MSG_VAR_REF(msg).msg.w.time_started = sys_now();
1184   } else {
1185     API_MSG_VAR_REF(msg).msg.w.time_started = 0;
1186   }
1187 #endif /* LWIP_SO_SNDTIMEO */
1188 
1189   /* For locking the core: this _can_ be delayed on low memory/low send buffer,
1190      but if it is, this is done inside api_msg.c:do_write(), so we can use the
1191      non-blocking version here. */
1192   err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg));
1193   if (err == ERR_OK) {
1194     if (bytes_written != NULL) {
1195       *bytes_written = API_MSG_VAR_REF(msg).msg.w.offset;
1196     }
1197     /* for blocking, check all requested bytes were written, NOTE: send_timeout is
1198        treated as dontblock (see dontblock assignment above) */
1199     if (!dontblock) {
1200       LWIP_ASSERT("do_write failed to write all bytes", API_MSG_VAR_REF(msg).msg.w.offset == size);
1201     }
1202   } else if (err == ERR_CLSD) {
1203     /* if connection is closed and send must return EPIPE */
1204     err = ERR_PIPE;
1205   } else {
1206     /* do nothing */
1207   }
1208 
1209   API_MSG_VAR_FREE(msg);
1210 
1211   return err;
1212 }
1213 
1214 /**
1215  * @ingroup netconn_tcp
1216  * Close or shutdown a TCP netconn (doesn't delete it).
1217  *
1218  * @param conn the TCP netconn to close or shutdown
1219  * @param how fully close or only shutdown one side?
1220  * @return ERR_OK if the netconn was closed, any other err_t on error
1221  */
1222 static err_t
netconn_close_shutdown(struct netconn * conn,u8_t how)1223 netconn_close_shutdown(struct netconn *conn, u8_t how)
1224 {
1225   API_MSG_VAR_DECLARE(msg);
1226   err_t err;
1227   LWIP_UNUSED_ARG(how);
1228 
1229   LWIP_ERROR("netconn_close: invalid conn",  (conn != NULL), return ERR_ARG;);
1230 
1231   API_MSG_VAR_ALLOC(msg);
1232   API_MSG_VAR_REF(msg).conn = conn;
1233 #if LWIP_TCP
1234   /* shutting down both ends is the same as closing */
1235   API_MSG_VAR_REF(msg).msg.sd.shut = how;
1236 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
1237   /* get the time we started, which is later compared to
1238      sys_now() + conn->send_timeout */
1239   API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
1240 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1241   API_MSG_VAR_REF(msg).msg.sd.polls_left =
1242     ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
1243 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1244 #endif /* LWIP_TCP */
1245   err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg));
1246   API_MSG_VAR_FREE(msg);
1247 
1248   return err;
1249 }
1250 
1251 /**
1252  * @ingroup netconn_tcp
1253  * Close a TCP netconn (doesn't delete it).
1254  *
1255  * @param conn the TCP netconn to close
1256  * @return ERR_OK if the netconn was closed, any other err_t on error
1257  */
1258 err_t
netconn_close(struct netconn * conn)1259 netconn_close(struct netconn *conn)
1260 {
1261   /* shutting down both ends is the same as closing */
1262   return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
1263 }
1264 
1265 /**
1266  * @ingroup netconn_common
1267  * Get and reset pending error on a netconn
1268  *
1269  * @param conn the netconn to get the error from
1270  * @return and pending error or ERR_OK if no error was pending
1271  */
1272 err_t
netconn_err(struct netconn * conn)1273 netconn_err(struct netconn *conn)
1274 {
1275   err_t err;
1276   SYS_ARCH_DECL_PROTECT(lev);
1277   if (conn == NULL) {
1278     return ERR_OK;
1279   }
1280   SYS_ARCH_PROTECT(lev);
1281   err = conn->last_err;
1282   SYS_ARCH_UNPROTECT(lev);
1283   return err;
1284 }
1285 
1286 /**
1287  * @ingroup netconn_tcp
1288  * Shut down one or both sides of a TCP netconn (doesn't delete it).
1289  *
1290  * @param conn the TCP netconn to shut down
1291  * @param shut_rx shut down the RX side (no more read possible after this)
1292  * @param shut_tx shut down the TX side (no more write possible after this)
1293  * @return ERR_OK if the netconn was closed, any other err_t on error
1294  */
1295 err_t
netconn_shutdown(struct netconn * conn,u8_t shut_rx,u8_t shut_tx)1296 netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
1297 {
1298   return netconn_close_shutdown(conn, (u8_t)((shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)));
1299 }
1300 
1301 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
1302 /**
1303  * @ingroup netconn_udp
1304  * Leave multicast groups (IGMP memberships) for UDP netconns.
1305  *
1306  * @param conn the UDP netconn  for which to change multicast addresses
1307  * @param multiaddr IP address of the multicast group to leave
1308  * @param netif_addr the IP address of the network interface on which to send
1309  *                  the igmp/MLD message
1310  * @param join_or_leave flag whether to send a join- or leave-message.
1311  *   This function is always called with NETCONN_LEAVE type
1312  * @return ERR_OK if the action was taken, any err_t on error
1313  */
1314 err_t
netconn_leave_group(struct netconn * conn,const ip_addr_t * multiaddr,const ip_addr_t * netif_addr,enum netconn_igmp join_or_leave)1315 netconn_leave_group(struct netconn *conn,
1316                     const ip_addr_t *multiaddr,
1317                     const ip_addr_t *netif_addr,
1318                     enum netconn_igmp join_or_leave)
1319 {
1320   API_MSG_VAR_DECLARE(msg);
1321   err_t err;
1322 
1323   LWIP_ERROR("netconn_leave_group: invalid conn",  (conn != NULL), return ERR_ARG);
1324 
1325   API_MSG_VAR_ALLOC(msg);
1326 
1327 #if LWIP_IPV4
1328   /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
1329   if (multiaddr == NULL) {
1330     multiaddr = IP4_ADDR_ANY;
1331   }
1332   if (netif_addr == NULL) {
1333     netif_addr = IP4_ADDR_ANY;
1334   }
1335 #endif /* LWIP_IPV4 */
1336 
1337   API_MSG_VAR_REF(msg).conn = conn;
1338   API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
1339   API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr);
1340   API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
1341   err = netconn_apimsg(lwip_netconn_do_leave_group, &API_MSG_VAR_REF(msg));
1342   API_MSG_VAR_FREE(msg);
1343 
1344   return err;
1345 }
1346 /*
1347  * @ingroup netconn_udp
1348  * Leave multicast groups (MLD memberships) for UDP netconns.
1349  *
1350  * @param conn the UDP netconn for which to change multicast addresses
1351  * @param multiaddr IP address of the multicast group to leave
1352  * @param if_idx the index of the netif
1353  * @param join_or_leave flag whether to send a join- or leave-message.
1354  *   This function is called with the NETCONN_LEAVE type.
1355  * @return ERR_OK if the action was taken, any err_t on error
1356  */
1357 err_t
netconn_leave_group_netif(struct netconn * conn,const ip_addr_t * multiaddr,u8_t if_idx,enum netconn_igmp join_or_leave)1358 netconn_leave_group_netif(struct netconn *conn,
1359                           const ip_addr_t *multiaddr,
1360                           u8_t if_idx,
1361                           enum netconn_igmp join_or_leave)
1362 {
1363   API_MSG_VAR_DECLARE(msg);
1364   err_t err;
1365 
1366   LWIP_ERROR("netconn_leave_group_netif: invalid conn",  (conn != NULL), return ERR_ARG);
1367 
1368   API_MSG_VAR_ALLOC(msg);
1369 
1370 #if LWIP_IPV4
1371   /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
1372   if (multiaddr == NULL) {
1373     multiaddr = IP4_ADDR_ANY;
1374   }
1375   if (if_idx == NETIF_NO_INDEX) {
1376     return ERR_IF;
1377   }
1378 #endif /* LWIP_IPV4 */
1379 
1380   API_MSG_VAR_REF(msg).conn = conn;
1381   API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
1382   API_MSG_VAR_REF(msg).msg.jl.if_idx = if_idx;
1383   API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
1384   err = netconn_apimsg(lwip_netconn_do_leave_group, &API_MSG_VAR_REF(msg));
1385   API_MSG_VAR_FREE(msg);
1386 
1387   return err;
1388 }
1389 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
1390 
1391 #if LWIP_DNS
1392 /**
1393  * @ingroup netconn_common
1394  * Execute a DNS query, only one IP address is returned
1395  *
1396  * @param name a string representation of the DNS host name to query
1397  * @param addr a preallocated ip_addr_t where to store the resolved IP address
1398  * @param dns_addrtype IP address type (IPv4 / IPv6)
1399  * @return ERR_OK: resolving succeeded
1400  *         ERR_MEM: memory error, try again later
1401  *         ERR_ARG: dns client not initialized or invalid hostname
1402  *         ERR_VAL: dns server response was invalid
1403  *         HOST_NOT_FOUND : Hostname not found in DNS Server.
1404  *         TRY_AGAIN : Didnt receive information from an authoritative server.
1405  *         NO_DATA : Hostname is genuine, but there are no A/AAAA records for it in the server.
1406  *         NO_RECOVERY : Some server failure occured which cant be recovered.
1407  */
1408 #if LWIP_IPV4 && LWIP_IPV6
1409 err_t
netconn_gethostbyname_addrtype(const char * name,ip_addr_t * addr,u32_t * count,u8_t dns_addrtype)1410 netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u32_t *count, u8_t dns_addrtype)
1411 #else
1412 err_t
1413 netconn_gethostbyname(const char *name, ip_addr_t *addr, u32_t *count)
1414 #endif
1415 {
1416   API_VAR_DECLARE(struct dns_api_msg, msg);
1417 #if !LWIP_MPU_COMPATIBLE
1418   sys_sem_t sem;
1419 #endif /* LWIP_MPU_COMPATIBLE */
1420   err_t err;
1421   err_t cberr;
1422 
1423 #if LWIP_IPV4 && LWIP_IPV6
1424   LWIP_ERROR("netconn_gethostbyname_addrtype: invalid name", (name != NULL), return ERR_ARG);
1425   LWIP_ERROR("netconn_gethostbyname_addrtype: invalid addr", (addr != NULL), return ERR_ARG);
1426   LWIP_ERROR("netconn_gethostbyname_addrtype: invalid count", ((count != NULL) && (*count)), return ERR_ARG);
1427 #else
1428   LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG);
1429   LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG);
1430   LWIP_ERROR("netconn_gethostbyname: invalid count", ((count != NULL) && (*count)), return ERR_ARG);
1431 #endif
1432 
1433 #if LWIP_MPU_COMPATIBLE
1434   if (strlen(name) >= DNS_MAX_NAME_LENGTH) {
1435     return ERR_ARG;
1436   }
1437 #endif
1438 
1439 #ifdef LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE
1440 #if LWIP_IPV4 && LWIP_IPV6
1441   if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, dns_addrtype, &err))
1442 #else
1443   if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, NETCONN_DNS_DEFAULT, &err))
1444 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1445   {
1446     return err;
1447   }
1448 #endif /* LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE */
1449 
1450   API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM);
1451 #if LWIP_MPU_COMPATIBLE
1452   strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH - 1);
1453   API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH - 1] = 0;
1454 #else /* LWIP_MPU_COMPATIBLE */
1455   API_VAR_REF(msg).err = API_VAR_REF(&err);
1456   API_VAR_REF(msg).sem = API_VAR_REF(&sem);
1457   API_VAR_REF(msg).count = API_VAR_REF(count);
1458   API_VAR_REF(msg).addr = API_VAR_REF(addr);
1459   API_VAR_REF(msg).name = name;
1460 #endif /* LWIP_MPU_COMPATIBLE */
1461 #if LWIP_IPV4 && LWIP_IPV6
1462   API_VAR_REF(msg).dns_addrtype = dns_addrtype;
1463 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1464 #if LWIP_NETCONN_SEM_PER_THREAD
1465   API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET();
1466 #else /* LWIP_NETCONN_SEM_PER_THREAD*/
1467   err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0);
1468   if (err != ERR_OK) {
1469     API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1470     return err;
1471   }
1472 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
1473 
1474   cberr = tcpip_send_msg_wait_sem(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg), API_EXPR_REF(API_VAR_REF(msg).sem));
1475 #if !LWIP_NETCONN_SEM_PER_THREAD
1476   sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
1477 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
1478   if (cberr != ERR_OK) {
1479     API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1480     return cberr;
1481   }
1482 
1483 #if LWIP_MPU_COMPATIBLE
1484   *addr = msg->addr;
1485   err = msg->err;
1486 #endif /* LWIP_MPU_COMPATIBLE */
1487 
1488   API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1489   return err;
1490 }
1491 
1492 #if LWIP_DNS_REVERSE
1493 err_t
netconn_getnameinfo(ip_addr_t * addr,char * hostname)1494 netconn_getnameinfo(ip_addr_t *addr, char *hostname)
1495 {
1496   API_VAR_DECLARE(struct reverse_dns_api_msg, msg);
1497 #if !LWIP_MPU_COMPATIBLE
1498   sys_sem_t sem;
1499 #endif /* LWIP_MPU_COMPATIBLE */
1500   err_t err = 0;
1501   err_t cberr;
1502 
1503   LWIP_ERROR("netconn_getnameinfo: invalid addr", (addr != NULL), return ERR_ARG);
1504   LWIP_ERROR("netconn_getnameinfo: invalid name", (hostname != NULL), return ERR_ARG);
1505 
1506   API_VAR_ALLOC(struct reverse_dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM);
1507 
1508   API_VAR_REF(msg).err = API_VAR_REF(&err);
1509   API_VAR_REF(msg).addr = API_VAR_REF(addr);
1510 
1511 #if LWIP_MPU_COMPATIBLE
1512   if (strncpy_s(API_VAR_REF(msg).hostname, hostname, NI_MAXHOST - 1) == EOK) {
1513     API_VAR_REF(msg).hostname[NI_MAXHOST - 1] = 0;
1514   } else {
1515     API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1516     return ERR_MEM;
1517   }
1518 #else
1519   API_VAR_REF(msg).hostname = hostname;
1520   API_VAR_REF(msg).sem = API_VAR_REF(&sem);
1521 #endif
1522 
1523 #if LWIP_NETCONN_SEM_PER_THREAD
1524   API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET();
1525 #else /* LWIP_NETCONN_SEM_PER_THREAD */
1526   err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0);
1527   if (err != ERR_OK) {
1528     API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1529     return err;
1530   }
1531 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
1532 
1533   cberr = tcpip_callback(lwip_netconn_do_getnamebyhost, &API_VAR_REF(msg));
1534   if (cberr != ERR_OK) {
1535 #if !LWIP_NETCONN_SEM_PER_THREAD
1536     sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
1537 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
1538     API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1539     return cberr;
1540   }
1541   (void)sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem));
1542 #if !LWIP_NETCONN_SEM_PER_THREAD
1543   sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
1544 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
1545 
1546 #if LWIP_MPU_COMPATIBLE
1547   size_t namelen = LWIP_MIN(strlen(API_VAR_REF(msg).hostname), NI_MAXHOST - 1);
1548   if (strncpy_s(hostname, API_VAR_REF(msg).hostname, namelen != EOK) {
1549     API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1550     return ERR_MEM;
1551   }
1552   hostname[namelen] = 0;
1553   err = msg->err;
1554 #endif /* LWIP_MPU_COMPATIBLE */
1555 
1556   API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1557   return err;
1558 }
1559 #endif /* LWIP_DNS_REVERSE */
1560 #endif /* LWIP_DNS*/
1561 
1562 #if LWIP_NETCONN_SEM_PER_THREAD
1563 void
1564 netconn_thread_init(void)
1565 {
1566   sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
1567   if (!sys_sem_valid(sem)) {
1568     /* call alloc only once */
1569     LWIP_NETCONN_THREAD_SEM_ALLOC();
1570     LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET()));
1571   }
1572 }
1573 
1574 void
1575 netconn_thread_cleanup(void)
1576 {
1577   sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
1578   if (sys_sem_valid(sem)) {
1579     /* call free only once */
1580     LWIP_NETCONN_THREAD_SEM_FREE();
1581   }
1582 }
1583 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
1584 
1585 /**
1586  * Get the connection information
1587  *
1588  * @param conn the netconn to query
1589  * @param conninfo a pointer to which to save the connection info
1590  * @return ERR_CONN for invalid connections
1591  *         ERR_OK if the information was retrieved
1592  */
1593 err_t netconn_getconninfo(struct netconn *conn, void *conn_info)
1594 {
1595   API_MSG_VAR_DECLARE(msg);
1596   err_t err;
1597   struct tcpip_conn *conninfo;
1598 
1599   conninfo = (struct tcpip_conn *)conn_info;
1600   LWIP_ERROR("netconn_getconninfo: invalid conn", (conn != NULL), return ERR_ARG;);
1601   LWIP_ERROR("netconn_getconninfo: invalid conninfo", (conninfo != NULL), return ERR_ARG;);
1602 
1603   API_MSG_VAR_ALLOC(msg);
1604   API_MSG_VAR_REF(msg).conn = conn;
1605   API_MSG_VAR_REF(msg).msg.conn_info = conninfo;
1606   err = netconn_apimsg(do_getconninfo, &API_MSG_VAR_REF(msg));
1607   API_MSG_VAR_FREE(msg);
1608   return err;
1609 }
1610 
1611 #endif /* LWIP_NETCONN */
1612