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