UbixOS V2 2.0

api_lib.c
Go to the documentation of this file.
1
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 <net/opt.h>
59
60 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
61
62 #include <net/api.h>
63 #include <net/memp.h>
64
65 #include <net/ip.h>
66 #include <net/raw.h>
67 #include <net/udp.h>
68 #include <net/priv/api_msg.h>
69 #include <net/priv/tcp_priv.h>
70 #include <net/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
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
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
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
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
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
293 err_t
294 netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port)
295 {
296 API_MSG_VAR_DECLARE(msg);
297 err_t err;
298
299 LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
300
301 #if LWIP_IPV4
302 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
303 if (addr == NULL) {
304 addr = IP4_ADDR_ANY;
305 }
306 #endif /* LWIP_IPV4 */
307
308 API_MSG_VAR_ALLOC(msg);
309 API_MSG_VAR_REF(msg).conn = conn;
310 API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
311 API_MSG_VAR_REF(msg).msg.bc.port = port;
312 err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg));
313 API_MSG_VAR_FREE(msg);
314
315 return err;
316 }
317
325 err_t
326 netconn_disconnect(struct netconn *conn)
327 {
328 API_MSG_VAR_DECLARE(msg);
329 err_t err;
330
331 LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
332
333 API_MSG_VAR_ALLOC(msg);
334 API_MSG_VAR_REF(msg).conn = conn;
335 err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg));
336 API_MSG_VAR_FREE(msg);
337
338 return err;
339 }
340
350 err_t
351 netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
352 {
353 #if LWIP_TCP
354 API_MSG_VAR_DECLARE(msg);
355 err_t err;
356
357 /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
358 LWIP_UNUSED_ARG(backlog);
359
360 LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
361
362 API_MSG_VAR_ALLOC(msg);
363 API_MSG_VAR_REF(msg).conn = conn;
364 #if TCP_LISTEN_BACKLOG
365 API_MSG_VAR_REF(msg).msg.lb.backlog = backlog;
366 #endif /* TCP_LISTEN_BACKLOG */
367 err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg));
368 API_MSG_VAR_FREE(msg);
369
370 return err;
371 #else /* LWIP_TCP */
372 LWIP_UNUSED_ARG(conn);
373 LWIP_UNUSED_ARG(backlog);
374 return ERR_ARG;
375 #endif /* LWIP_TCP */
376 }
377
387 err_t
388 netconn_accept(struct netconn *conn, struct netconn **new_conn)
389 {
390 #if LWIP_TCP
391 void *accept_ptr;
392 struct netconn *newconn;
393 #if TCP_LISTEN_BACKLOG
394 API_MSG_VAR_DECLARE(msg);
395 #endif /* TCP_LISTEN_BACKLOG */
396
397 LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
398 *new_conn = NULL;
399 LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
400
401 if (ERR_IS_FATAL(conn->last_err)) {
402 /* don't recv on fatal errors: this might block the application task
403 waiting on acceptmbox forever! */
404 return conn->last_err;
405 }
406 if (!sys_mbox_valid(&conn->acceptmbox)) {
407 return ERR_CLSD;
408 }
409
410 #if TCP_LISTEN_BACKLOG
411 API_MSG_VAR_ALLOC(msg);
412 #endif /* TCP_LISTEN_BACKLOG */
413
414 #if LWIP_SO_RCVTIMEO
415 if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
416 #if TCP_LISTEN_BACKLOG
417 API_MSG_VAR_FREE(msg);
418 #endif /* TCP_LISTEN_BACKLOG */
419 return ERR_TIMEOUT;
420 }
421 #else
422 sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0);
423 #endif /* LWIP_SO_RCVTIMEO*/
424 newconn = (struct netconn *)accept_ptr;
425 /* Register event with callback */
426 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
427
428 if (accept_ptr == &netconn_aborted) {
429 /* a connection has been aborted: out of pcbs or out of netconns during accept */
430 /* @todo: set netconn error, but this would be fatal and thus block further accepts */
431 #if TCP_LISTEN_BACKLOG
432 API_MSG_VAR_FREE(msg);
433 #endif /* TCP_LISTEN_BACKLOG */
434 return ERR_ABRT;
435 }
436 if (newconn == NULL) {
437 /* connection has been aborted */
438 /* in this special case, we set the netconn error from application thread, as
439 on a ready-to-accept listening netconn, there should not be anything running
440 in tcpip_thread */
441 NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
442 #if TCP_LISTEN_BACKLOG
443 API_MSG_VAR_FREE(msg);
444 #endif /* TCP_LISTEN_BACKLOG */
445 return ERR_CLSD;
446 }
447 #if TCP_LISTEN_BACKLOG
448 /* Let the stack know that we have accepted the connection. */
449 API_MSG_VAR_REF(msg).conn = newconn;
450 /* don't care for the return value of lwip_netconn_do_recv */
451 netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg));
452 API_MSG_VAR_FREE(msg);
453 #endif /* TCP_LISTEN_BACKLOG */
454
455 *new_conn = newconn;
456 /* don't set conn->last_err: it's only ERR_OK, anyway */
457 return ERR_OK;
458 #else /* LWIP_TCP */
459 LWIP_UNUSED_ARG(conn);
460 LWIP_UNUSED_ARG(new_conn);
461 return ERR_ARG;
462 #endif /* LWIP_TCP */
463 }
464
475 static err_t
476 netconn_recv_data(struct netconn *conn, void **new_buf)
477 {
478 void *buf = NULL;
479 u16_t len;
480 #if LWIP_TCP
481 API_MSG_VAR_DECLARE(msg);
482 #if LWIP_MPU_COMPATIBLE
483 msg = NULL;
484 #endif
485 #endif /* LWIP_TCP */
486
487 LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
488 *new_buf = NULL;
489 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
490 #if LWIP_TCP
491 #if (LWIP_UDP || LWIP_RAW)
492 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
493 #endif /* (LWIP_UDP || LWIP_RAW) */
494 {
495 if (!sys_mbox_valid(&conn->recvmbox)) {
496 /* This happens when calling this function after receiving FIN */
497 return sys_mbox_valid(&conn->acceptmbox) ? ERR_CONN : ERR_CLSD;
498 }
499 }
500 #endif /* LWIP_TCP */
501 LWIP_ERROR("netconn_recv: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
502
503 if (ERR_IS_FATAL(conn->last_err)) {
504 /* don't recv on fatal errors: this might block the application task
505 waiting on recvmbox forever! */
506 /* @todo: this does not allow us to fetch data that has been put into recvmbox
507 before the fatal error occurred - is that a problem? */
508 return conn->last_err;
509 }
510 #if LWIP_TCP
511 #if (LWIP_UDP || LWIP_RAW)
512 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
513 #endif /* (LWIP_UDP || LWIP_RAW) */
514 {
515 API_MSG_VAR_ALLOC(msg);
516 }
517 #endif /* LWIP_TCP */
518
519 #if LWIP_SO_RCVTIMEO
520 if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
521 #if LWIP_TCP
522 #if (LWIP_UDP || LWIP_RAW)
523 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
524 #endif /* (LWIP_UDP || LWIP_RAW) */
525 {
526 API_MSG_VAR_FREE(msg);
527 }
528 #endif /* LWIP_TCP */
529 return ERR_TIMEOUT;
530 }
531 #else
532 sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
533 #endif /* LWIP_SO_RCVTIMEO*/
534
535 #if LWIP_TCP
536 #if (LWIP_UDP || LWIP_RAW)
537 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
538 #endif /* (LWIP_UDP || LWIP_RAW) */
539 {
540 /* Let the stack know that we have taken the data. */
541 /* @todo: Speedup: Don't block and wait for the answer here
542 (to prevent multiple thread-switches). */
543 API_MSG_VAR_REF(msg).conn = conn;
544 if (buf != NULL) {
545 API_MSG_VAR_REF(msg).msg.r.len = ((struct pbuf *)buf)->tot_len;
546 } else {
547 API_MSG_VAR_REF(msg).msg.r.len = 1;
548 }
549
550 /* don't care for the return value of lwip_netconn_do_recv */
551 netconn_apimsg(lwip_netconn_do_recv, &API_MSG_VAR_REF(msg));
552 API_MSG_VAR_FREE(msg);
553
554 /* If we are closed, we indicate that we no longer wish to use the socket */
555 if (buf == NULL) {
556 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
557 if (conn->pcb.ip == NULL) {
558 /* race condition: RST during recv */
559 return conn->last_err == ERR_OK ? ERR_RST : conn->last_err;
560 }
561 /* RX side is closed, so deallocate the recvmbox */
562 netconn_close_shutdown(conn, NETCONN_SHUT_RD);
563 /* Don' store ERR_CLSD as conn->err since we are only half-closed */
564 return ERR_CLSD;
565 }
566 len = ((struct pbuf *)buf)->tot_len;
567 }
568 #endif /* LWIP_TCP */
569 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
570 else
571 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
572 #if (LWIP_UDP || LWIP_RAW)
573 {
574 LWIP_ASSERT("buf != NULL", buf != NULL);
575 len = netbuf_len((struct netbuf*)buf);
576 }
577 #endif /* (LWIP_UDP || LWIP_RAW) */
578
579 #if LWIP_SO_RCVBUF
580 SYS_ARCH_DEC(conn->recv_avail, len);
581 #endif /* LWIP_SO_RCVBUF */
582 /* Register event with callback */
583 API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
584
585 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
586
587 *new_buf = buf;
588 /* don't set conn->last_err: it's only ERR_OK, anyway */
589 return ERR_OK;
590 }
591
602 err_t
603 netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
604 {
605 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
606 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
607
608 return netconn_recv_data(conn, (void **)new_buf);
609 }
610
620 err_t
621 netconn_recv(struct netconn *conn, struct netbuf **new_buf)
622 {
623 #if LWIP_TCP
624 struct netbuf *buf = NULL;
625 err_t err;
626 #endif /* LWIP_TCP */
627
628 LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
629 *new_buf = NULL;
630 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
631
632 #if LWIP_TCP
633 #if (LWIP_UDP || LWIP_RAW)
634 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
635 #endif /* (LWIP_UDP || LWIP_RAW) */
636 {
637 struct pbuf *p = NULL;
638 /* This is not a listening netconn, since recvmbox is set */
639
640 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
641 if (buf == NULL) {
642 return ERR_MEM;
643 }
644
645 err = netconn_recv_data(conn, (void **)&p);
646 if (err != ERR_OK) {
647 memp_free(MEMP_NETBUF, buf);
648 return err;
649 }
650 LWIP_ASSERT("p != NULL", p != NULL);
651
652 buf->p = p;
653 buf->ptr = p;
654 buf->port = 0;
655 ip_addr_set_zero(&buf->addr);
656 *new_buf = buf;
657 /* don't set conn->last_err: it's only ERR_OK, anyway */
658 return ERR_OK;
659 }
660 #endif /* LWIP_TCP */
661 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
662 else
663 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
664 {
665 #if (LWIP_UDP || LWIP_RAW)
666 return netconn_recv_data(conn, (void **)new_buf);
667 #endif /* (LWIP_UDP || LWIP_RAW) */
668 }
669 }
670
682 err_t
683 netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port)
684 {
685 if (buf != NULL) {
686 ip_addr_set(&buf->addr, addr);
687 buf->port = port;
688 return netconn_send(conn, buf);
689 }
690 return ERR_VAL;
691 }
692
701 err_t
702 netconn_send(struct netconn *conn, struct netbuf *buf)
703 {
704 API_MSG_VAR_DECLARE(msg);
705 err_t err;
706
707 LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
708
709 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
710
711 API_MSG_VAR_ALLOC(msg);
712 API_MSG_VAR_REF(msg).conn = conn;
713 API_MSG_VAR_REF(msg).msg.b = buf;
714 err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg));
715 API_MSG_VAR_FREE(msg);
716
717 return err;
718 }
719
734 err_t
735 netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
736 u8_t apiflags, size_t *bytes_written)
737 {
738 API_MSG_VAR_DECLARE(msg);
739 err_t err;
740 u8_t dontblock;
741
742 LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
743 LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;);
744 if (size == 0) {
745 return ERR_OK;
746 }
747 dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
748 #if LWIP_SO_SNDTIMEO
749 if (conn->send_timeout != 0) {
750 dontblock = 1;
751 }
752 #endif /* LWIP_SO_SNDTIMEO */
753 if (dontblock && !bytes_written) {
754 /* This implies netconn_write() cannot be used for non-blocking send, since
755 it has no way to return the number of bytes written. */
756 return ERR_VAL;
757 }
758
759 API_MSG_VAR_ALLOC(msg);
760 /* non-blocking write sends as much */
761 API_MSG_VAR_REF(msg).conn = conn;
762 API_MSG_VAR_REF(msg).msg.w.dataptr = dataptr;
763 API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags;
764 API_MSG_VAR_REF(msg).msg.w.len = size;
765 #if LWIP_SO_SNDTIMEO
766 if (conn->send_timeout != 0) {
767 /* get the time we started, which is later compared to
768 sys_now() + conn->send_timeout */
769 API_MSG_VAR_REF(msg).msg.w.time_started = sys_now();
770 } else {
771 API_MSG_VAR_REF(msg).msg.w.time_started = 0;
772 }
773 #endif /* LWIP_SO_SNDTIMEO */
774
775 /* For locking the core: this _can_ be delayed on low memory/low send buffer,
776 but if it is, this is done inside api_msg.c:do_write(), so we can use the
777 non-blocking version here. */
778 err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg));
779 if ((err == ERR_OK) && (bytes_written != NULL)) {
780 if (dontblock) {
781 /* nonblocking write: maybe the data has been sent partly */
782 *bytes_written = API_MSG_VAR_REF(msg).msg.w.len;
783 } else {
784 /* blocking call succeeded: all data has been sent if it */
785 *bytes_written = size;
786 }
787 }
788 API_MSG_VAR_FREE(msg);
789
790 return err;
791 }
792
801 static err_t
802 netconn_close_shutdown(struct netconn *conn, u8_t how)
803 {
804 API_MSG_VAR_DECLARE(msg);
805 err_t err;
806 LWIP_UNUSED_ARG(how);
807
808 LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
809
810 API_MSG_VAR_ALLOC(msg);
811 API_MSG_VAR_REF(msg).conn = conn;
812 #if LWIP_TCP
813 /* shutting down both ends is the same as closing */
814 API_MSG_VAR_REF(msg).msg.sd.shut = how;
815 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
816 /* get the time we started, which is later compared to
817 sys_now() + conn->send_timeout */
818 API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
819 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
820 API_MSG_VAR_REF(msg).msg.sd.polls_left =
821 ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
822 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
823 #endif /* LWIP_TCP */
824 err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg));
825 API_MSG_VAR_FREE(msg);
826
827 return err;
828 }
829
837 err_t
838 netconn_close(struct netconn *conn)
839 {
840 /* shutting down both ends is the same as closing */
841 return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
842 }
843
853 err_t
854 netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
855 {
856 return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
857 }
858
859 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
860
871 err_t
872 netconn_join_leave_group(struct netconn *conn,
873 const ip_addr_t *multiaddr,
874 const ip_addr_t *netif_addr,
875 enum netconn_igmp join_or_leave)
876 {
877 API_MSG_VAR_DECLARE(msg);
878 err_t err;
879
880 LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
881
882 API_MSG_VAR_ALLOC(msg);
883
884 #if LWIP_IPV4
885 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
886 if (multiaddr == NULL) {
887 multiaddr = IP4_ADDR_ANY;
888 }
889 if (netif_addr == NULL) {
890 netif_addr = IP4_ADDR_ANY;
891 }
892 #endif /* LWIP_IPV4 */
893
894 API_MSG_VAR_REF(msg).conn = conn;
895 API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
896 API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr);
897 API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
898 err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg));
899 API_MSG_VAR_FREE(msg);
900
901 return err;
902 }
903 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
904
905 #if LWIP_DNS
906
918 #if LWIP_IPV4 && LWIP_IPV6
919 err_t
920 netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype)
921 #else
922 err_t
923 netconn_gethostbyname(const char *name, ip_addr_t *addr)
924 #endif
925 {
926 API_VAR_DECLARE(struct dns_api_msg, msg);
927 #if !LWIP_MPU_COMPATIBLE
928 sys_sem_t sem;
929 #endif /* LWIP_MPU_COMPATIBLE */
930 err_t err;
931 err_t cberr;
932
933 LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
934 LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
935 #if LWIP_MPU_COMPATIBLE
936 if (strlen(name) >= DNS_MAX_NAME_LENGTH) {
937 return ERR_ARG;
938 }
939 #endif
940
941 API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM);
942 #if LWIP_MPU_COMPATIBLE
943 strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH-1);
944 API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH-1] = 0;
945 #else /* LWIP_MPU_COMPATIBLE */
946 msg.err = &err;
947 msg.sem = &sem;
948 API_VAR_REF(msg).addr = API_VAR_REF(addr);
949 API_VAR_REF(msg).name = name;
950 #endif /* LWIP_MPU_COMPATIBLE */
951 #if LWIP_IPV4 && LWIP_IPV6
952 API_VAR_REF(msg).dns_addrtype = dns_addrtype;
953 #endif /* LWIP_IPV4 && LWIP_IPV6 */
954 #if LWIP_NETCONN_SEM_PER_THREAD
955 API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET();
956 #else /* LWIP_NETCONN_SEM_PER_THREAD*/
957 err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0);
958 if (err != ERR_OK) {
959 API_VAR_FREE(MEMP_DNS_API_MSG, msg);
960 return err;
961 }
962 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
963
964 cberr = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg));
965 if (cberr != ERR_OK) {
966 #if !LWIP_NETCONN_SEM_PER_THREAD
967 sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
968 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
969 API_VAR_FREE(MEMP_DNS_API_MSG, msg);
970 return cberr;
971 }
972 sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem));
973 #if !LWIP_NETCONN_SEM_PER_THREAD
974 sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
975 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
976
977 #if LWIP_MPU_COMPATIBLE
978 *addr = msg->addr;
979 err = msg->err;
980 #endif /* LWIP_MPU_COMPATIBLE */
981
982 API_VAR_FREE(MEMP_DNS_API_MSG, msg);
983 return err;
984 }
985 #endif /* LWIP_DNS*/
986
987 #if LWIP_NETCONN_SEM_PER_THREAD
988 void
989 netconn_thread_init(void)
990 {
991 sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
992 if ((sem == NULL) || !sys_sem_valid(sem)) {
993 /* call alloc only once */
994 LWIP_NETCONN_THREAD_SEM_ALLOC();
995 LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET()));
996 }
997 }
998
999 void
1000 netconn_thread_cleanup(void)
1001 {
1002 sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
1003 if ((sem != NULL) && sys_sem_valid(sem)) {
1004 /* call free only once */
1005 LWIP_NETCONN_THREAD_SEM_FREE();
1006 }
1007 }
1008 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
1009
1010 #endif /* LWIP_NETCONN */
tcpip_priv.h
sys_sem_wait
#define sys_sem_wait(sem)
Definition: sys.h:158
opt.h
ip_addr_cmp
#define ip_addr_cmp(addr1, addr2)
Definition: ip_addr.h:316
pbuf::len
u16_t len
Definition: pbuf.h:159
DNS_MAX_NAME_LENGTH
#define DNS_MAX_NAME_LENGTH
Definition: lwipopts.h:159
sys_mbox_free
void sys_mbox_free(struct sys_mbox **mb)
Definition: sys_arch.c:194
LWIP_ASSERT
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
ip_addr_set_zero
#define ip_addr_set_zero(ipaddr)
Definition: ip_addr.h:309
sys_sem_new
err_t sys_sem_new(sys_sem_t **sem, u8_t count)
Definition: sys_arch.c:52
ERR_ABRT
Definition: err.h:90
sys_sem_free
void sys_sem_free(sys_sem_t **sem)
Definition: sys_arch.c:75
ERR_IS_FATAL
#define ERR_IS_FATAL(e)
Definition: err.h:99
u16_t
uint16_t u16_t
Definition: arch.h:124
string.h
sys_sem_valid
int sys_sem_valid(struct sys_sem **s)
Definition: sys_arch.c:132
SYS_ARCH_DEC
#define SYS_ARCH_DEC(var, val)
Definition: sys.h:384
ip_addr_set
#define ip_addr_set(dest, src)
Definition: ip_addr.h:307
IP_ANY_TYPE
#define IP_ANY_TYPE
Definition: ip_addr.h:400
strncpy
char * strncpy(char *__restrict, const char *__restrict, size_t)
API_VAR_FREE
#define API_VAR_FREE(pool, name)
Definition: tcpip_priv.h:86
strlen
int strlen(const char *str)
Definition: strlen.c:55
memp_malloc
void * memp_malloc(memp_t type)
Definition: memp.c:385
raw.h
sys_sem
Definition: sem.h:36
memp_free
void memp_free(memp_t type, void *mem)
Definition: memp.c:469
ERR_TIMEOUT
Definition: err.h:69
ERR_MEM
Definition: err.h:65
LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT
#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT
Definition: lwipopts.h:301
sys_now
u32_t sys_now(void)
Definition: sys_arch.c:497
LWIP_ERROR
#define LWIP_ERROR(message, expression, handler)
Definition: debug.h:135
ERR_CLSD
Definition: err.h:94
API_LIB_DEBUG
#define API_LIB_DEBUG
Definition: lwipopts.h:437
u8_t
uint8_t u8_t
Definition: arch.h:122
ip_addr_t
ip6_addr_t ip_addr_t
Definition: ip_addr.h:290
ERR_CONN
Definition: err.h:85
buf
Definition: buf.h:35
tcp_priv.h
API_VAR_ALLOC
#define API_VAR_ALLOC(type, pool, name, errorval)
Definition: tcpip_priv.h:84
API_EXPR_REF
#define API_EXPR_REF(expr)
Definition: tcpip_priv.h:88
ERR_ARG
Definition: err.h:96
LWIP_UNUSED_ARG
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:315
sys_mbox_valid
int sys_mbox_valid(struct sys_mbox **mb)
Definition: sys_arch.c:367
sys_arch_mbox_fetch
uint32_t sys_arch_mbox_fetch(struct sys_mbox **mb, void **msg, uint32_t timeout)
Definition: sys_arch.c:287
U16_F
#define U16_F
Definition: arch.h:148
ERR_OK
Definition: err.h:63
API_EXPR_REF_SEM
#define API_EXPR_REF_SEM(expr)
Definition: tcpip_priv.h:89
err_t
s8_t err_t
Definition: err.h:57
tcpip_callback
#define tcpip_callback(f, ctx)
Definition: tcpip.h:85
name
const char * name
Definition: pci.c:37
API_VAR_DECLARE
#define API_VAR_DECLARE(type, name)
Definition: tcpip_priv.h:83
ip.h
ERR_RST
Definition: err.h:92
tcpip_send_msg_wait_sem
err_t tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem)
Definition: tcpip.c:322
udp.h
SYS_ARCH_TIMEOUT
#define SYS_ARCH_TIMEOUT
Definition: sys.h:47
tcpip_callback_fn
void(* tcpip_callback_fn)(void *ctx)
Definition: tcpip.h:70
memp.h
API_VAR_REF
#define API_VAR_REF(name)
Definition: tcpip_priv.h:82
ERR_VAL
Definition: err.h:75
pbuf
Definition: pbuf.h:142
LWIP_DEBUGF
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:164
api_msg.h
api.h
NULL
#define NULL
Definition: fat_string.h:17