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