BadVPN – Blame information for rev 1

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