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
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
968 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
969  API_VAR_FREE(MEMP_DNS_API_MSG, msg);
970  return cberr;
971  }
973 #if !LWIP_NETCONN_SEM_PER_THREAD
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