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"
89 #include "lwip/priv/tcpip_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 
99 static err_t netconn_close_shutdown(struct netconn *conn, u8_t how);
100 
110 static err_t
111 netconn_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 
141 struct netconn*
142 netconn_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 
184 err_t
185 netconn_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 
230 err_t
231 netconn_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 
268 err_t
269 netconn_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 
312 err_t
313 netconn_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 
344 err_t
345 netconn_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 
369 err_t
370 netconn_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 
406 err_t
407 netconn_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 
494 static err_t
495 netconn_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 
621 err_t
622 netconn_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 
639 err_t
640 netconn_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 
701 err_t
702 netconn_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 
720 err_t
721 netconn_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 
753 err_t
754 netconn_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 
820 static err_t
821 netconn_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 
856 err_t
857 netconn_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 
872 err_t
873 netconn_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)
879 
890 err_t
891 netconn_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
925 
937 #if LWIP_IPV4 && LWIP_IPV6
938 err_t
939 netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype)
940 #else
941 err_t
942 netconn_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
1007 void
1008 netconn_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 
1018 void
1019 netconn_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 */
void sys_sem_free(sys_sem_t *sem)
Definition: sys_arch.cc:113
#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT
Definition: opt.h:1850
Definition: err.h:109
void(* tcpip_callback_fn)(void *ctx)
Definition: tcpip.h:89
u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
Definition: sys_arch.cc:248
#define SYS_ARCH_TIMEOUT
Definition: sys.h:106
void memp_free(memp_t type, void *mem)
Definition: memp.c:488
#define sys_sem_wait(sem)
Definition: sys.h:217
void sys_mbox_free(sys_mbox_t *mbox)
Definition: sys_arch.cc:226
int sys_mbox_valid(sys_mbox_t *mbox)
Definition: sys_arch.cc:284
Definition: err.h:84
Definition: err.h:113
#define tcpip_callback(f, ctx)
Definition: tcpip.h:104
u32_t sys_now(void)
Definition: sys_arch.cc:57
Definition: err.h:115
#define DNS_MAX_NAME_LENGTH
Definition: opt.h:1040
Definition: pbuf.h:161
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
Definition: sys_arch.cc:95
s8_t err_t
Definition: err.h:76
err_t tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem)
Definition: tcpip.c:348
Definition: err.h:104
#define LWIP_DEBUGF(debug, message)
#define API_LIB_DEBUG
Definition: opt.h:2671
Definition: err.h:111
Definition: err.h:94
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:327
Definition: err.h:82
void * memp_malloc(memp_t type)
Definition: memp.c:404
int sys_sem_valid(sys_sem_t *sem)
Definition: sys_arch.cc:124