The Pedigree Project 0.1
api_lib.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
43/*
44 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
45 * All rights reserved.
46 *
47 * Redistribution and use in source and binary forms, with or without modification,
48 * are permitted provided that the following conditions are met:
49 *
50 * 1. Redistributions of source code must retain the above copyright notice,
51 * this list of conditions and the following disclaimer.
52 * 2. Redistributions in binary form must reproduce the above copyright notice,
53 * this list of conditions and the following disclaimer in the documentation
54 * and/or other materials provided with the distribution.
55 * 3. The name of the author may not be used to endorse or promote products
56 * derived from this software without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
59 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
60 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
61 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
62 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
63 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
64 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
65 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
66 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
67 * OF SUCH DAMAGE.
68 *
69 * This file is part of the lwIP TCP/IP stack.
70 *
71 * Author: Adam Dunkels <adam@sics.se>
72 */
73
74/* This is the part of the API that is linked with
75 the application */
76
77#include "lwip/opt.h"
78
79#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
80
81#include "lwip/api.h"
82#include "lwip/memp.h"
83
84#include "lwip/ip.h"
85#include "lwip/raw.h"
86#include "lwip/udp.h"
87#include "lwip/priv/api_msg.h"
88#include "lwip/priv/tcp_priv.h"
90
91#include <string.h>
92
93#define API_MSG_VAR_REF(name) API_VAR_REF(name)
94#define API_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct api_msg, name)
95#define API_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, ERR_MEM)
96#define API_MSG_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, NULL)
97#define API_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_API_MSG, name)
98
99static err_t netconn_close_shutdown(struct netconn *conn, u8_t how);
100
110static err_t
111netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg)
112{
113 err_t err;
114
115#ifdef LWIP_DEBUG
116 /* catch functions that don't set err */
117 apimsg->err = ERR_VAL;
118#endif /* LWIP_DEBUG */
119
120#if LWIP_NETCONN_SEM_PER_THREAD
121 apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
122#endif /* LWIP_NETCONN_SEM_PER_THREAD */
123
124 err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg));
125 if (err == ERR_OK) {
126 return apimsg->err;
127 }
128 return err;
129}
130
141struct netconn*
142netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
143{
144 struct netconn *conn;
145 API_MSG_VAR_DECLARE(msg);
146 API_MSG_VAR_ALLOC_RETURN_NULL(msg);
147
148 conn = netconn_alloc(t, callback);
149 if (conn != NULL) {
150 err_t err;
151
152 API_MSG_VAR_REF(msg).msg.n.proto = proto;
153 API_MSG_VAR_REF(msg).conn = conn;
154 err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg));
155 if (err != ERR_OK) {
156 LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
157 LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
158#if LWIP_TCP
159 LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
160#endif /* LWIP_TCP */
161#if !LWIP_NETCONN_SEM_PER_THREAD
162 LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
163 sys_sem_free(&conn->op_completed);
164#endif /* !LWIP_NETCONN_SEM_PER_THREAD */
165 sys_mbox_free(&conn->recvmbox);
166 memp_free(MEMP_NETCONN, conn);
167 API_MSG_VAR_FREE(msg);
168 return NULL;
169 }
170 }
171 API_MSG_VAR_FREE(msg);
172 return conn;
173}
174
184err_t
185netconn_delete(struct netconn *conn)
186{
187 err_t err;
188 API_MSG_VAR_DECLARE(msg);
189
190 /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
191 if (conn == NULL) {
192 return ERR_OK;
193 }
194
195 API_MSG_VAR_ALLOC(msg);
196 API_MSG_VAR_REF(msg).conn = conn;
197#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
198 /* get the time we started, which is later compared to
199 sys_now() + conn->send_timeout */
200 API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
201#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
202#if LWIP_TCP
203 API_MSG_VAR_REF(msg).msg.sd.polls_left =
204 ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
205#endif /* LWIP_TCP */
206#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
207 err = netconn_apimsg(lwip_netconn_do_delconn, &API_MSG_VAR_REF(msg));
208 API_MSG_VAR_FREE(msg);
209
210 if (err != ERR_OK) {
211 return err;
212 }
213
214 netconn_free(conn);
215
216 return ERR_OK;
217}
218
230err_t
231netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
232{
233 API_MSG_VAR_DECLARE(msg);
234 err_t err;
235
236 LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
237 LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
238 LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
239
240 API_MSG_VAR_ALLOC(msg);
241 API_MSG_VAR_REF(msg).conn = conn;
242 API_MSG_VAR_REF(msg).msg.ad.local = local;
243#if LWIP_MPU_COMPATIBLE
244 err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg));
245 *addr = msg->msg.ad.ipaddr;
246 *port = msg->msg.ad.port;
247#else /* LWIP_MPU_COMPATIBLE */
248 msg.msg.ad.ipaddr = addr;
249 msg.msg.ad.port = port;
250 err = netconn_apimsg(lwip_netconn_do_getaddr, &msg);
251#endif /* LWIP_MPU_COMPATIBLE */
252 API_MSG_VAR_FREE(msg);
253
254 return err;
255}
256
268err_t
269netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port)
270{
271 API_MSG_VAR_DECLARE(msg);
272 err_t err;
273
274 LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
275
276#if LWIP_IPV4
277 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
278 if (addr == NULL) {
279 addr = IP4_ADDR_ANY;
280 }
281#endif /* LWIP_IPV4 */
282
283#if LWIP_IPV4 && LWIP_IPV6
284 /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY,
285 * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind
286 */
287 if ((netconn_get_ipv6only(conn) == 0) &&
288 ip_addr_cmp(addr, IP6_ADDR_ANY)) {
289 addr = IP_ANY_TYPE;
290 }
291#endif /* LWIP_IPV4 && LWIP_IPV6 */
292
293 API_MSG_VAR_ALLOC(msg);
294 API_MSG_VAR_REF(msg).conn = conn;
295 API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
296 API_MSG_VAR_REF(msg).msg.bc.port = port;
297 err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg));
298 API_MSG_VAR_FREE(msg);
299
300 return err;
301}
302
312err_t
313netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port)
314{
315 API_MSG_VAR_DECLARE(msg);
316 err_t err;
317
318 LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
319
320#if LWIP_IPV4
321 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
322 if (addr == NULL) {
323 addr = IP4_ADDR_ANY;
324 }
325#endif /* LWIP_IPV4 */
326
327 API_MSG_VAR_ALLOC(msg);
328 API_MSG_VAR_REF(msg).conn = conn;
329 API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
330 API_MSG_VAR_REF(msg).msg.bc.port = port;
331 err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg));
332 API_MSG_VAR_FREE(msg);
333
334 return err;
335}
336
344err_t
345netconn_disconnect(struct netconn *conn)
346{
347 API_MSG_VAR_DECLARE(msg);
348 err_t err;
349
350 LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
351
352 API_MSG_VAR_ALLOC(msg);
353 API_MSG_VAR_REF(msg).conn = conn;
354 err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg));
355 API_MSG_VAR_FREE(msg);
356
357 return err;
358}
359
369err_t
370netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
371{
372#if LWIP_TCP
373 API_MSG_VAR_DECLARE(msg);
374 err_t err;
375
376 /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
377 LWIP_UNUSED_ARG(backlog);
378
379 LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
380
381 API_MSG_VAR_ALLOC(msg);
382 API_MSG_VAR_REF(msg).conn = conn;
383#if TCP_LISTEN_BACKLOG
384 API_MSG_VAR_REF(msg).msg.lb.backlog = backlog;
385#endif /* TCP_LISTEN_BACKLOG */
386 err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg));
387 API_MSG_VAR_FREE(msg);
388
389 return err;
390#else /* LWIP_TCP */
391 LWIP_UNUSED_ARG(conn);
392 LWIP_UNUSED_ARG(backlog);
393 return ERR_ARG;
394#endif /* LWIP_TCP */
395}
396
406err_t
407netconn_accept(struct netconn *conn, struct netconn **new_conn)
408{
409#if LWIP_TCP
410 void *accept_ptr;
411 struct netconn *newconn;
412#if TCP_LISTEN_BACKLOG
413 API_MSG_VAR_DECLARE(msg);
414#endif /* TCP_LISTEN_BACKLOG */
415
416 LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
417 *new_conn = NULL;
418 LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
419
420 if (ERR_IS_FATAL(conn->last_err)) {
421 /* don't recv on fatal errors: this might block the application task
422 waiting on acceptmbox forever! */
423 return conn->last_err;
424 }
425 if (!sys_mbox_valid(&conn->acceptmbox)) {
426 return ERR_CLSD;
427 }
428
429#if TCP_LISTEN_BACKLOG
430 API_MSG_VAR_ALLOC(msg);
431#endif /* TCP_LISTEN_BACKLOG */
432
433#if LWIP_SO_RCVTIMEO
434 if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
435#if TCP_LISTEN_BACKLOG
436 API_MSG_VAR_FREE(msg);
437#endif /* TCP_LISTEN_BACKLOG */
438 return ERR_TIMEOUT;
439 }
440#else
441 sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0);
442#endif /* LWIP_SO_RCVTIMEO*/
443 newconn = (struct netconn *)accept_ptr;
444 /* Register event with callback */
445 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
446
447 if (accept_ptr == &netconn_aborted) {
448 /* a connection has been aborted: out of pcbs or out of netconns during accept */
449 /* @todo: set netconn error, but this would be fatal and thus block further accepts */
450#if TCP_LISTEN_BACKLOG
451 API_MSG_VAR_FREE(msg);
452#endif /* TCP_LISTEN_BACKLOG */
453 return ERR_ABRT;
454 }
455 if (newconn == NULL) {
456 /* connection has been aborted */
457 /* in this special case, we set the netconn error from application thread, as
458 on a ready-to-accept listening netconn, there should not be anything running
459 in tcpip_thread */
460 NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
461#if TCP_LISTEN_BACKLOG
462 API_MSG_VAR_FREE(msg);
463#endif /* TCP_LISTEN_BACKLOG */
464 return ERR_CLSD;
465 }
466#if TCP_LISTEN_BACKLOG
467 /* Let the stack know that we have accepted the connection. */
468 API_MSG_VAR_REF(msg).conn = newconn;
469 /* don't care for the return value of lwip_netconn_do_recv */
470 netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg));
471 API_MSG_VAR_FREE(msg);
472#endif /* TCP_LISTEN_BACKLOG */
473
474 *new_conn = newconn;
475 /* don't set conn->last_err: it's only ERR_OK, anyway */
476 return ERR_OK;
477#else /* LWIP_TCP */
478 LWIP_UNUSED_ARG(conn);
479 LWIP_UNUSED_ARG(new_conn);
480 return ERR_ARG;
481#endif /* LWIP_TCP */
482}
483
494static err_t
495netconn_recv_data(struct netconn *conn, void **new_buf)
496{
497 void *buf = NULL;
498 u16_t len;
499#if LWIP_TCP
500 API_MSG_VAR_DECLARE(msg);
501#if LWIP_MPU_COMPATIBLE
502 msg = NULL;
503#endif
504#endif /* LWIP_TCP */
505
506 LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
507 *new_buf = NULL;
508 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
509#if LWIP_TCP
510#if (LWIP_UDP || LWIP_RAW)
511 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
512#endif /* (LWIP_UDP || LWIP_RAW) */
513 {
514 if (!sys_mbox_valid(&conn->recvmbox)) {
515 /* This happens when calling this function after receiving FIN */
516 return sys_mbox_valid(&conn->acceptmbox) ? ERR_CONN : ERR_CLSD;
517 }
518 }
519#endif /* LWIP_TCP */
520 LWIP_ERROR("netconn_recv: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
521
522 if (ERR_IS_FATAL(conn->last_err)) {
523 /* don't recv on fatal errors: this might block the application task
524 waiting on recvmbox forever! */
525 /* @todo: this does not allow us to fetch data that has been put into recvmbox
526 before the fatal error occurred - is that a problem? */
527 return conn->last_err;
528 }
529#if LWIP_TCP
530#if (LWIP_UDP || LWIP_RAW)
531 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
532#endif /* (LWIP_UDP || LWIP_RAW) */
533 {
534 API_MSG_VAR_ALLOC(msg);
535 }
536#endif /* LWIP_TCP */
537
538#if LWIP_SO_RCVTIMEO
539 if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
540#if LWIP_TCP
541#if (LWIP_UDP || LWIP_RAW)
542 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
543#endif /* (LWIP_UDP || LWIP_RAW) */
544 {
545 API_MSG_VAR_FREE(msg);
546 }
547#endif /* LWIP_TCP */
548 return ERR_TIMEOUT;
549 }
550#else
551 sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
552#endif /* LWIP_SO_RCVTIMEO*/
553
554#if LWIP_TCP
555#if (LWIP_UDP || LWIP_RAW)
556 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
557#endif /* (LWIP_UDP || LWIP_RAW) */
558 {
559 /* Let the stack know that we have taken the data. */
560 /* @todo: Speedup: Don't block and wait for the answer here
561 (to prevent multiple thread-switches). */
562 API_MSG_VAR_REF(msg).conn = conn;
563 if (buf != NULL) {
564 API_MSG_VAR_REF(msg).msg.r.len = ((struct pbuf *)buf)->tot_len;
565 } else {
566 API_MSG_VAR_REF(msg).msg.r.len = 1;
567 }
568
569 /* don't care for the return value of lwip_netconn_do_recv */
570 netconn_apimsg(lwip_netconn_do_recv, &API_MSG_VAR_REF(msg));
571 API_MSG_VAR_FREE(msg);
572
573 /* If we are closed, we indicate that we no longer wish to use the socket */
574 if (buf == NULL) {
575 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
576 if (conn->pcb.ip == NULL) {
577 /* race condition: RST during recv */
578 return conn->last_err == ERR_OK ? ERR_RST : conn->last_err;
579 }
580 /* RX side is closed, so deallocate the recvmbox */
581 netconn_close_shutdown(conn, NETCONN_SHUT_RD);
582 /* Don' store ERR_CLSD as conn->err since we are only half-closed */
583 return ERR_CLSD;
584 }
585 len = ((struct pbuf *)buf)->tot_len;
586 }
587#endif /* LWIP_TCP */
588#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
589 else
590#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
591#if (LWIP_UDP || LWIP_RAW)
592 {
593 LWIP_ASSERT("buf != NULL", buf != NULL);
594 len = netbuf_len((struct netbuf*)buf);
595 }
596#endif /* (LWIP_UDP || LWIP_RAW) */
597
598#if LWIP_SO_RCVBUF
599 SYS_ARCH_DEC(conn->recv_avail, len);
600#endif /* LWIP_SO_RCVBUF */
601 /* Register event with callback */
602 API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
603
604 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
605
606 *new_buf = buf;
607 /* don't set conn->last_err: it's only ERR_OK, anyway */
608 return ERR_OK;
609}
610
621err_t
622netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
623{
624 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
625 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
626
627 return netconn_recv_data(conn, (void **)new_buf);
628}
629
639err_t
640netconn_recv(struct netconn *conn, struct netbuf **new_buf)
641{
642#if LWIP_TCP
643 struct netbuf *buf = NULL;
644 err_t err;
645#endif /* LWIP_TCP */
646
647 LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
648 *new_buf = NULL;
649 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
650
651#if LWIP_TCP
652#if (LWIP_UDP || LWIP_RAW)
653 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
654#endif /* (LWIP_UDP || LWIP_RAW) */
655 {
656 struct pbuf *p = NULL;
657 /* This is not a listening netconn, since recvmbox is set */
658
659 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
660 if (buf == NULL) {
661 return ERR_MEM;
662 }
663
664 err = netconn_recv_data(conn, (void **)&p);
665 if (err != ERR_OK) {
666 memp_free(MEMP_NETBUF, buf);
667 return err;
668 }
669 LWIP_ASSERT("p != NULL", p != NULL);
670
671 buf->p = p;
672 buf->ptr = p;
673 buf->port = 0;
674 ip_addr_set_zero(&buf->addr);
675 *new_buf = buf;
676 /* don't set conn->last_err: it's only ERR_OK, anyway */
677 return ERR_OK;
678 }
679#endif /* LWIP_TCP */
680#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
681 else
682#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
683 {
684#if (LWIP_UDP || LWIP_RAW)
685 return netconn_recv_data(conn, (void **)new_buf);
686#endif /* (LWIP_UDP || LWIP_RAW) */
687 }
688}
689
701err_t
702netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port)
703{
704 if (buf != NULL) {
705 ip_addr_set(&buf->addr, addr);
706 buf->port = port;
707 return netconn_send(conn, buf);
708 }
709 return ERR_VAL;
710}
711
720err_t
721netconn_send(struct netconn *conn, struct netbuf *buf)
722{
723 API_MSG_VAR_DECLARE(msg);
724 err_t err;
725
726 LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
727
728 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
729
730 API_MSG_VAR_ALLOC(msg);
731 API_MSG_VAR_REF(msg).conn = conn;
732 API_MSG_VAR_REF(msg).msg.b = buf;
733 err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg));
734 API_MSG_VAR_FREE(msg);
735
736 return err;
737}
738
753err_t
754netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
755 u8_t apiflags, size_t *bytes_written)
756{
757 API_MSG_VAR_DECLARE(msg);
758 err_t err;
759 u8_t dontblock;
760
761 LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
762 LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;);
763 if (size == 0) {
764 return ERR_OK;
765 }
766 dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
767#if LWIP_SO_SNDTIMEO
768 if (conn->send_timeout != 0) {
769 dontblock = 1;
770 }
771#endif /* LWIP_SO_SNDTIMEO */
772 if (dontblock && !bytes_written) {
773 /* This implies netconn_write() cannot be used for non-blocking send, since
774 it has no way to return the number of bytes written. */
775 return ERR_VAL;
776 }
777
778 API_MSG_VAR_ALLOC(msg);
779 /* non-blocking write sends as much */
780 API_MSG_VAR_REF(msg).conn = conn;
781 API_MSG_VAR_REF(msg).msg.w.dataptr = dataptr;
782 API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags;
783 API_MSG_VAR_REF(msg).msg.w.len = size;
784#if LWIP_SO_SNDTIMEO
785 if (conn->send_timeout != 0) {
786 /* get the time we started, which is later compared to
787 sys_now() + conn->send_timeout */
788 API_MSG_VAR_REF(msg).msg.w.time_started = sys_now();
789 } else {
790 API_MSG_VAR_REF(msg).msg.w.time_started = 0;
791 }
792#endif /* LWIP_SO_SNDTIMEO */
793
794 /* For locking the core: this _can_ be delayed on low memory/low send buffer,
795 but if it is, this is done inside api_msg.c:do_write(), so we can use the
796 non-blocking version here. */
797 err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg));
798 if ((err == ERR_OK) && (bytes_written != NULL)) {
799 if (dontblock) {
800 /* nonblocking write: maybe the data has been sent partly */
801 *bytes_written = API_MSG_VAR_REF(msg).msg.w.len;
802 } else {
803 /* blocking call succeeded: all data has been sent if it */
804 *bytes_written = size;
805 }
806 }
807 API_MSG_VAR_FREE(msg);
808
809 return err;
810}
811
820static err_t
821netconn_close_shutdown(struct netconn *conn, u8_t how)
822{
823 API_MSG_VAR_DECLARE(msg);
824 err_t err;
825 LWIP_UNUSED_ARG(how);
826
827 LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
828
829 API_MSG_VAR_ALLOC(msg);
830 API_MSG_VAR_REF(msg).conn = conn;
831#if LWIP_TCP
832 /* shutting down both ends is the same as closing */
833 API_MSG_VAR_REF(msg).msg.sd.shut = how;
834#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
835 /* get the time we started, which is later compared to
836 sys_now() + conn->send_timeout */
837 API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
838#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
839 API_MSG_VAR_REF(msg).msg.sd.polls_left =
840 ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
841#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
842#endif /* LWIP_TCP */
843 err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg));
844 API_MSG_VAR_FREE(msg);
845
846 return err;
847}
848
856err_t
857netconn_close(struct netconn *conn)
858{
859 /* shutting down both ends is the same as closing */
860 return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
861}
862
872err_t
873netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
874{
875 return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
876}
877
878#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
890err_t
891netconn_join_leave_group(struct netconn *conn,
892 const ip_addr_t *multiaddr,
893 const ip_addr_t *netif_addr,
894 enum netconn_igmp join_or_leave)
895{
896 API_MSG_VAR_DECLARE(msg);
897 err_t err;
898
899 LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
900
901 API_MSG_VAR_ALLOC(msg);
902
903#if LWIP_IPV4
904 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
905 if (multiaddr == NULL) {
906 multiaddr = IP4_ADDR_ANY;
907 }
908 if (netif_addr == NULL) {
909 netif_addr = IP4_ADDR_ANY;
910 }
911#endif /* LWIP_IPV4 */
912
913 API_MSG_VAR_REF(msg).conn = conn;
914 API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
915 API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr);
916 API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
917 err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg));
918 API_MSG_VAR_FREE(msg);
919
920 return err;
921}
922#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
923
924#if LWIP_DNS
937#if LWIP_IPV4 && LWIP_IPV6
938err_t
939netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype)
940#else
941err_t
942netconn_gethostbyname(const char *name, ip_addr_t *addr)
943#endif
944{
945 API_VAR_DECLARE(struct dns_api_msg, msg);
946#if !LWIP_MPU_COMPATIBLE
947 sys_sem_t sem;
948#endif /* LWIP_MPU_COMPATIBLE */
949 err_t err;
950 err_t cberr;
951
952 LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
953 LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
954#if LWIP_MPU_COMPATIBLE
955 if (strlen(name) >= DNS_MAX_NAME_LENGTH) {
956 return ERR_ARG;
957 }
958#endif
959
960 API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM);
961#if LWIP_MPU_COMPATIBLE
962 strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH-1);
963 API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH-1] = 0;
964#else /* LWIP_MPU_COMPATIBLE */
965 msg.err = &err;
966 msg.sem = &sem;
967 API_VAR_REF(msg).addr = API_VAR_REF(addr);
968 API_VAR_REF(msg).name = name;
969#endif /* LWIP_MPU_COMPATIBLE */
970#if LWIP_IPV4 && LWIP_IPV6
971 API_VAR_REF(msg).dns_addrtype = dns_addrtype;
972#endif /* LWIP_IPV4 && LWIP_IPV6 */
973#if LWIP_NETCONN_SEM_PER_THREAD
974 API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET();
975#else /* LWIP_NETCONN_SEM_PER_THREAD*/
976 err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0);
977 if (err != ERR_OK) {
978 API_VAR_FREE(MEMP_DNS_API_MSG, msg);
979 return err;
980 }
981#endif /* LWIP_NETCONN_SEM_PER_THREAD */
982
983 cberr = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg));
984 if (cberr != ERR_OK) {
985#if !LWIP_NETCONN_SEM_PER_THREAD
986 sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
987#endif /* !LWIP_NETCONN_SEM_PER_THREAD */
988 API_VAR_FREE(MEMP_DNS_API_MSG, msg);
989 return cberr;
990 }
991 sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem));
992#if !LWIP_NETCONN_SEM_PER_THREAD
993 sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
994#endif /* !LWIP_NETCONN_SEM_PER_THREAD */
995
996#if LWIP_MPU_COMPATIBLE
997 *addr = msg->addr;
998 err = msg->err;
999#endif /* LWIP_MPU_COMPATIBLE */
1000
1001 API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1002 return err;
1003}
1004#endif /* LWIP_DNS*/
1005
1006#if LWIP_NETCONN_SEM_PER_THREAD
1007void
1008netconn_thread_init(void)
1009{
1010 sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
1011 if ((sem == NULL) || !sys_sem_valid(sem)) {
1012 /* call alloc only once */
1013 LWIP_NETCONN_THREAD_SEM_ALLOC();
1014 LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET()));
1015 }
1016}
1017
1018void
1019netconn_thread_cleanup(void)
1020{
1021 sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
1022 if ((sem != NULL) && sys_sem_valid(sem)) {
1023 /* call free only once */
1024 LWIP_NETCONN_THREAD_SEM_FREE();
1025 }
1026}
1027#endif /* LWIP_NETCONN_SEM_PER_THREAD */
1028
1029#endif /* LWIP_NETCONN */
#define LWIP_DEBUGF(debug, message)
Definition debug.h:183
#define LWIP_UNUSED_ARG(x)
Definition arch.h:327
s8_t err_t
Definition err.h:76
@ ERR_RST
Definition err.h:111
@ ERR_OK
Definition err.h:82
@ ERR_CLSD
Definition err.h:113
@ ERR_VAL
Definition err.h:94
@ ERR_MEM
Definition err.h:84
@ ERR_CONN
Definition err.h:104
@ ERR_ARG
Definition err.h:115
@ ERR_TIMEOUT
Definition err.h:88
@ ERR_ABRT
Definition err.h:109
#define API_LIB_DEBUG
Definition opt.h:2671
#define DNS_MAX_NAME_LENGTH
Definition opt.h:1040
#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT
Definition opt.h:1850
u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
Definition sys_arch.cc:298
int sys_mbox_valid(sys_mbox_t *mbox)
Definition sys_arch.cc:330
void sys_mbox_free(sys_mbox_t *mbox)
Definition sys_arch.cc:255
int sys_sem_valid(sys_sem_t *sem)
Definition sys_arch.cc:162
void sys_sem_free(sys_sem_t *sem)
Definition sys_arch.cc:152
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
Definition sys_arch.cc:138
u32_t sys_now(void)
Definition sys_arch.cc:78
void * memp_malloc(memp_t type)
Definition memp.c:404
void memp_free(memp_t type, void *mem)
Definition memp.c:488
Definition pbuf.h:161
u16_t len
Definition pbuf.h:178
#define sys_sem_wait(sem)
Definition sys.h:217
#define SYS_ARCH_TIMEOUT
Definition sys.h:106
err_t tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem)
Definition tcpip.c:482
void(* tcpip_callback_fn)(void *ctx)
Definition tcpip.h:89
#define tcpip_callback(f, ctx)
Definition tcpip.h:113