3 * Sockets BSD-Like API module
8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33 * This file is part of the lwIP TCP/IP stack.
35 * Author: Adam Dunkels <adam@sics.se>
37 * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
43 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
45 #include "lwip/sockets.h"
48 #include "lwip/igmp.h"
49 #include "lwip/inet.h"
53 #include "lwip/tcpip.h"
54 #include "lwip/pbuf.h"
55 #if LWIP_CHECKSUM_ON_COPY
56 #include "lwip/inet_chksum.h"
61 #define NUM_SOCKETS MEMP_NUM_NETCONN
63 /** Contains all internal pointers and states used for a socket */
65 /** sockets currently are built on netconns, each socket has one netconn */
67 /** data that was left from the previous read */
69 /** offset in the data that was left from the previous read */
71 /** number of times data was received, set by event_callback(),
72 tested by the receive and select functions */
74 /** number of times data was ACKed (free send buffer), set by event_callback(),
77 /** error happened for this socket, set by event_callback(), tested by select */
79 /** last error that occurred on this socket */
81 /** counter of how many threads are waiting for this socket using select */
85 /** Description for a task waiting in select */
86 struct lwip_select_cb {
87 /** Pointer to the next waiting task */
88 struct lwip_select_cb *next;
89 /** Pointer to the previous waiting task */
90 struct lwip_select_cb *prev;
91 /** readset passed to select */
93 /** writeset passed to select */
95 /** unimplemented: exceptset passed to select */
97 /** don't signal the same semaphore twice: set to 1 when signalled */
99 /** semaphore to wake up a task waiting for select */
103 /** This struct is used to pass data to the set/getsockopt_internal
104 * functions running in tcpip_thread context (only a void* is allowed) */
105 struct lwip_setgetsockopt_data {
106 /** socket struct for which to change options */
107 struct lwip_sock *sock;
109 /** socket index for which to change options */
111 #endif /* LWIP_DEBUG */
112 /** level of the option to process */
114 /** name of the option to process */
116 /** set: value to set the option to
117 * get: value of the option is stored here */
119 /** size of *optval */
121 /** if an error occures, it is temporarily stored here */
125 /** The global array of available sockets */
126 static struct lwip_sock sockets[NUM_SOCKETS];
127 /** The global list of tasks waiting for select */
128 static struct lwip_select_cb *select_cb_list;
129 /** This counter is increased from lwip_select when the list is chagned
130 and checked in event_callback to see if it has changed. */
131 static volatile int select_cb_ctr;
133 /** Table to quickly map an lwIP error (err_t) to a socket error
134 * by using -err as an index */
135 static const int err_to_errno_table[] = {
136 0, /* ERR_OK 0 No error, everything OK. */
137 ENOMEM, /* ERR_MEM -1 Out of memory error. */
138 ENOBUFS, /* ERR_BUF -2 Buffer error. */
139 EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
140 EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
141 EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
142 EINVAL, /* ERR_VAL -6 Illegal value. */
143 EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
144 EADDRINUSE, /* ERR_USE -8 Address in use. */
145 EALREADY, /* ERR_ISCONN -9 Already connected. */
146 ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */
147 ECONNRESET, /* ERR_RST -11 Connection reset. */
148 ENOTCONN, /* ERR_CLSD -12 Connection closed. */
149 ENOTCONN, /* ERR_CONN -13 Not connected. */
150 EIO, /* ERR_ARG -14 Illegal argument. */
151 -1, /* ERR_IF -15 Low-level netif error */
154 #define ERR_TO_ERRNO_TABLE_SIZE \
155 (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
157 #define err_to_errno(err) \
158 ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
159 err_to_errno_table[-(err)] : EIO)
163 #define set_errno(err) errno = (err)
166 #define set_errno(err)
169 #define sock_set_errno(sk, e) do { \
171 set_errno(sk->err); \
174 /* Forward delcaration of some functions */
175 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
176 static void lwip_getsockopt_internal(void *arg);
177 static void lwip_setsockopt_internal(void *arg);
180 * Initialize this module. This function has to be called before any other
181 * functions in this module!
184 lwip_socket_init(void)
189 * Map a externally used socket index to the internal socket representation.
191 * @param s externally used socket index
192 * @return struct lwip_sock for the socket or NULL if not found
194 static struct lwip_sock *
197 struct lwip_sock *sock;
199 if ((s < 0) || (s >= NUM_SOCKETS)) {
200 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
208 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
217 * Same as get_socket but doesn't set errno
219 * @param s externally used socket index
220 * @return struct lwip_sock for the socket or NULL if not found
222 static struct lwip_sock *
225 if ((s < 0) || (s >= NUM_SOCKETS)) {
228 if (!sockets[s].conn) {
235 * Allocate a new socket for a given netconn.
237 * @param newconn the netconn for which to allocate a socket
238 * @param accepted 1 if socket has been created by accept(),
239 * 0 if socket has been created by socket()
240 * @return the index of the new socket; -1 on error
243 alloc_socket(struct netconn *newconn, int accepted)
246 SYS_ARCH_DECL_PROTECT(lev);
248 /* allocate a new socket identifier */
249 for (i = 0; i < NUM_SOCKETS; ++i) {
250 /* Protect socket array */
251 SYS_ARCH_PROTECT(lev);
252 if (!sockets[i].conn) {
253 sockets[i].conn = newconn;
254 /* The socket is not yet known to anyone, so no need to protect
255 after having marked it as used. */
256 SYS_ARCH_UNPROTECT(lev);
257 sockets[i].lastdata = NULL;
258 sockets[i].lastoffset = 0;
259 sockets[i].rcvevent = 0;
260 /* TCP sendbuf is empty, but the socket is not yet writable until connected
261 * (unless it has been created by accept()). */
262 sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);
263 sockets[i].errevent = 0;
265 sockets[i].select_waiting = 0;
268 SYS_ARCH_UNPROTECT(lev);
273 /** Free a socket. The socket's netconn must have been
276 * @param sock the socket to free
277 * @param is_tcp != 0 for TCP sockets, used to free lastdata
280 free_socket(struct lwip_sock *sock, int is_tcp)
283 SYS_ARCH_DECL_PROTECT(lev);
285 lastdata = sock->lastdata;
286 sock->lastdata = NULL;
287 sock->lastoffset = 0;
290 /* Protect socket array */
291 SYS_ARCH_PROTECT(lev);
293 SYS_ARCH_UNPROTECT(lev);
294 /* don't use 'sock' after this line, as another task might have allocated it */
296 if (lastdata != NULL) {
298 pbuf_free((struct pbuf *)lastdata);
300 netbuf_delete((struct netbuf *)lastdata);
305 /* Below this, the well-known socket functions are implemented.
306 * Use google.com or opengroup.org to get a good description :-)
308 * Exceptions are documented!
312 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
314 struct lwip_sock *sock, *nsock;
315 struct netconn *newconn;
319 struct sockaddr_in sin;
321 SYS_ARCH_DECL_PROTECT(lev);
323 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
324 sock = get_socket(s);
329 if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
330 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
331 sock_set_errno(sock, EWOULDBLOCK);
335 /* wait for a new connection */
336 err = netconn_accept(sock->conn, &newconn);
338 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
339 sock_set_errno(sock, err_to_errno(err));
342 LWIP_ASSERT("newconn != NULL", newconn != NULL);
343 /* Prevent automatic window updates, we do this on our own! */
344 netconn_set_noautorecved(newconn, 1);
346 /* get the IP address and port of the remote host */
347 err = netconn_peer(newconn, &naddr, &port);
349 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
350 netconn_delete(newconn);
351 sock_set_errno(sock, err_to_errno(err));
355 /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
356 * not be NULL if addr is valid.
359 LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
360 memset(&sin, 0, sizeof(sin));
361 sin.sin_len = sizeof(sin);
362 sin.sin_family = AF_INET;
363 sin.sin_port = htons(port);
364 inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
366 if (*addrlen > sizeof(sin))
367 *addrlen = sizeof(sin);
369 MEMCPY(addr, &sin, *addrlen);
372 newsock = alloc_socket(newconn, 1);
374 netconn_delete(newconn);
375 sock_set_errno(sock, ENFILE);
378 LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));
379 LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
380 nsock = &sockets[newsock];
382 /* See event_callback: If data comes in right away after an accept, even
383 * though the server task might not have created a new socket yet.
384 * In that case, newconn->socket is counted down (newconn->socket--),
385 * so nsock->rcvevent is >= 1 here!
387 SYS_ARCH_PROTECT(lev);
388 nsock->rcvevent += (s16_t)(-1 - newconn->socket);
389 newconn->socket = newsock;
390 SYS_ARCH_UNPROTECT(lev);
392 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
393 ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
394 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
396 sock_set_errno(sock, 0);
401 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
403 struct lwip_sock *sock;
404 ip_addr_t local_addr;
407 const struct sockaddr_in *name_in;
409 sock = get_socket(s);
414 /* check size, familiy and alignment of 'name' */
415 LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
416 ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
417 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
418 name_in = (const struct sockaddr_in *)(void*)name;
420 inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);
421 local_port = name_in->sin_port;
423 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
424 ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
425 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port)));
427 err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
430 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
431 sock_set_errno(sock, err_to_errno(err));
435 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
436 sock_set_errno(sock, 0);
443 struct lwip_sock *sock;
446 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
448 sock = get_socket(s);
453 if(sock->conn != NULL) {
454 is_tcp = netconn_type(sock->conn) == NETCONN_TCP;
456 LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
459 netconn_delete(sock->conn);
461 free_socket(sock, is_tcp);
467 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
469 struct lwip_sock *sock;
471 const struct sockaddr_in *name_in;
473 sock = get_socket(s);
478 /* check size, familiy and alignment of 'name' */
479 LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
480 ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
481 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
482 name_in = (const struct sockaddr_in *)(void*)name;
484 if (name_in->sin_family == AF_UNSPEC) {
485 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
486 err = netconn_disconnect(sock->conn);
488 ip_addr_t remote_addr;
491 inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);
492 remote_port = name_in->sin_port;
494 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
495 ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
496 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port)));
498 err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
502 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
503 sock_set_errno(sock, err_to_errno(err));
507 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
508 sock_set_errno(sock, 0);
513 * Set a socket into listen mode.
514 * The socket may not have been used for another connection previously.
516 * @param s the socket to set to listening mode
517 * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
518 * @return 0 on success, non-zero on failure
521 lwip_listen(int s, int backlog)
523 struct lwip_sock *sock;
526 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
528 sock = get_socket(s);
533 /* limit the "backlog" parameter to fit in an u8_t */
534 backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
536 err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
539 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
540 sock_set_errno(sock, err_to_errno(err));
544 sock_set_errno(sock, 0);
549 lwip_recvfrom(int s, void *mem, size_t len, int flags,
550 struct sockaddr *from, socklen_t *fromlen)
552 struct lwip_sock *sock;
555 u16_t buflen, copylen;
562 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
563 sock = get_socket(s);
569 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
570 /* Check if there is data left from the last recv operation. */
571 if (sock->lastdata) {
572 buf = sock->lastdata;
574 /* If this is non-blocking call, then check first */
575 if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
576 (sock->rcvevent <= 0)) {
578 /* update receive window */
579 netconn_recved(sock->conn, (u32_t)off);
580 /* already received data, return that */
581 sock_set_errno(sock, 0);
584 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
585 sock_set_errno(sock, EWOULDBLOCK);
589 /* No data was left from the previous operation, so we try to get
590 some from the network. */
591 if (netconn_type(sock->conn) == NETCONN_TCP) {
592 err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
594 err = netconn_recv(sock->conn, (struct netbuf **)&buf);
596 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
601 /* update receive window */
602 netconn_recved(sock->conn, (u32_t)off);
603 /* already received data, return that */
604 sock_set_errno(sock, 0);
607 /* We should really do some error checking here. */
608 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
609 s, lwip_strerr(err)));
610 sock_set_errno(sock, err_to_errno(err));
611 if (err == ERR_CLSD) {
617 LWIP_ASSERT("buf != NULL", buf != NULL);
618 sock->lastdata = buf;
621 if (netconn_type(sock->conn) == NETCONN_TCP) {
622 p = (struct pbuf *)buf;
624 p = ((struct netbuf *)buf)->p;
627 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
628 buflen, len, off, sock->lastoffset));
630 buflen -= sock->lastoffset;
635 copylen = (u16_t)len;
638 /* copy the contents of the received buffer into
639 the supplied memory pointer mem */
640 pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
644 if (netconn_type(sock->conn) == NETCONN_TCP) {
645 LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
648 (p->flags & PBUF_FLAG_PUSH) ||
649 (sock->rcvevent <= 0) ||
650 ((flags & MSG_PEEK)!=0)) {
657 /* Check to see from where the data was.*/
660 if (from && fromlen) {
661 struct sockaddr_in sin;
663 if (netconn_type(sock->conn) == NETCONN_TCP) {
665 netconn_getaddr(sock->conn, addr, &port, 0);
667 addr = netbuf_fromaddr((struct netbuf *)buf);
668 port = netbuf_fromport((struct netbuf *)buf);
671 memset(&sin, 0, sizeof(sin));
672 sin.sin_len = sizeof(sin);
673 sin.sin_family = AF_INET;
674 sin.sin_port = htons(port);
675 inet_addr_from_ipaddr(&sin.sin_addr, addr);
677 if (*fromlen > sizeof(sin)) {
678 *fromlen = sizeof(sin);
681 MEMCPY(from, &sin, *fromlen);
683 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
684 ip_addr_debug_print(SOCKETS_DEBUG, addr);
685 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
688 if (netconn_type(sock->conn) == NETCONN_TCP) {
690 netconn_getaddr(sock->conn, addr, &port, 0);
692 addr = netbuf_fromaddr((struct netbuf *)buf);
693 port = netbuf_fromport((struct netbuf *)buf);
696 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
697 ip_addr_debug_print(SOCKETS_DEBUG, addr);
698 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
699 #endif /* SOCKETS_DEBUG */
703 /* If we don't peek the incoming message... */
704 if ((flags & MSG_PEEK) == 0) {
705 /* If this is a TCP socket, check if there is data left in the
706 buffer. If so, it should be saved in the sock structure for next
708 if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {
709 sock->lastdata = buf;
710 sock->lastoffset += copylen;
711 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
713 sock->lastdata = NULL;
714 sock->lastoffset = 0;
715 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
716 if (netconn_type(sock->conn) == NETCONN_TCP) {
717 pbuf_free((struct pbuf *)buf);
719 netbuf_delete((struct netbuf *)buf);
726 /* update receive window */
727 netconn_recved(sock->conn, (u32_t)off);
729 sock_set_errno(sock, 0);
734 lwip_read(int s, void *mem, size_t len)
736 return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
740 lwip_recv(int s, void *mem, size_t len, int flags)
742 return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
746 lwip_send(int s, const void *data, size_t size, int flags)
748 struct lwip_sock *sock;
752 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
753 s, data, size, flags));
755 sock = get_socket(s);
760 if (sock->conn->type != NETCONN_TCP) {
761 #if (LWIP_UDP || LWIP_RAW)
762 return lwip_sendto(s, data, size, flags, NULL, 0);
763 #else /* (LWIP_UDP || LWIP_RAW) */
764 sock_set_errno(sock, err_to_errno(ERR_ARG));
766 #endif /* (LWIP_UDP || LWIP_RAW) */
769 if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) {
770 if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) {
771 /* too much data to ever send nonblocking! */
772 sock_set_errno(sock, EMSGSIZE);
777 write_flags = NETCONN_COPY |
778 ((flags & MSG_MORE) ? NETCONN_MORE : 0) |
779 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
780 err = netconn_write(sock->conn, data, size, write_flags);
782 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size));
783 sock_set_errno(sock, err_to_errno(err));
784 return (err == ERR_OK ? (int)size : -1);
788 lwip_sendto(int s, const void *data, size_t size, int flags,
789 const struct sockaddr *to, socklen_t tolen)
791 struct lwip_sock *sock;
794 const struct sockaddr_in *to_in;
796 #if !LWIP_TCPIP_CORE_LOCKING
800 sock = get_socket(s);
805 if (sock->conn->type == NETCONN_TCP) {
807 return lwip_send(s, data, size, flags);
809 LWIP_UNUSED_ARG(flags);
810 sock_set_errno(sock, err_to_errno(ERR_ARG));
812 #endif /* LWIP_TCP */
815 /* @todo: split into multiple sendto's? */
816 LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
817 short_size = (u16_t)size;
818 LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
819 ((tolen == sizeof(struct sockaddr_in)) &&
820 ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))),
821 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
822 to_in = (const struct sockaddr_in *)(void*)to;
824 #if LWIP_TCPIP_CORE_LOCKING
825 /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */
828 ip_addr_t *remote_addr;
830 #if LWIP_NETIF_TX_SINGLE_PBUF
831 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM);
833 #if LWIP_CHECKSUM_ON_COPY
835 if (sock->conn->type != NETCONN_RAW) {
836 chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size);
838 #endif /* LWIP_CHECKSUM_ON_COPY */
839 MEMCPY(p->payload, data, size);
840 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
841 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF);
843 p->payload = (void*)data;
844 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
847 inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr);
848 remote_port = ntohs(to_in->sin_port);
850 remote_addr = &sock->conn->pcb.raw->remote_ip;
851 if (sock->conn->type == NETCONN_RAW) {
854 remote_port = sock->conn->pcb.udp->remote_port;
859 if (sock->conn->type == NETCONN_RAW) {
860 err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr);
863 #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF
864 err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,
865 remote_addr, remote_port, 1, chksum);
866 #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
867 err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p,
868 remote_addr, remote_port);
869 #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
872 #endif /* LWIP_UDP */
881 #else /* LWIP_TCPIP_CORE_LOCKING */
882 /* initialize a buffer */
883 buf.p = buf.ptr = NULL;
884 #if LWIP_CHECKSUM_ON_COPY
886 #endif /* LWIP_CHECKSUM_ON_COPY */
888 inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr);
889 remote_port = ntohs(to_in->sin_port);
890 netbuf_fromport(&buf) = remote_port;
893 ip_addr_set_any(&buf.addr);
894 netbuf_fromport(&buf) = 0;
897 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
898 s, data, short_size, flags));
899 ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
900 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
902 /* make the buffer point to the data that should be sent */
903 #if LWIP_NETIF_TX_SINGLE_PBUF
904 /* Allocate a new netbuf and copy the data into it. */
905 if (netbuf_alloc(&buf, short_size) == NULL) {
908 #if LWIP_CHECKSUM_ON_COPY
909 if (sock->conn->type != NETCONN_RAW) {
910 u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
911 netbuf_set_chksum(&buf, chksum);
914 #endif /* LWIP_CHECKSUM_ON_COPY */
916 err = netbuf_take(&buf, data, short_size);
919 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
920 err = netbuf_ref(&buf, data, short_size);
921 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
924 err = netconn_send(sock->conn, &buf);
927 /* deallocated the buffer */
929 #endif /* LWIP_TCPIP_CORE_LOCKING */
930 sock_set_errno(sock, err_to_errno(err));
931 return (err == ERR_OK ? short_size : -1);
935 lwip_socket(int domain, int type, int protocol)
937 struct netconn *conn;
940 LWIP_UNUSED_ARG(domain);
942 /* create a netconn */
945 conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
946 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
947 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
950 conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?
951 NETCONN_UDPLITE : NETCONN_UDP, event_callback);
952 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
953 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
956 conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
957 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
958 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
960 /* Prevent automatic window updates, we do this on our own! */
961 netconn_set_noautorecved(conn, 1);
965 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
966 domain, type, protocol));
972 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
977 i = alloc_socket(conn, 0);
980 netconn_delete(conn);
985 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
991 lwip_write(int s, const void *data, size_t size)
993 return lwip_send(s, data, size, 0);
997 * Go through the readset and writeset lists and see which socket of the sockets
998 * set in the sets has events. On return, readset, writeset and exceptset have
999 * the sockets enabled that had events.
1001 * exceptset is not used for now!!!
1003 * @param maxfdp1 the highest socket index in the sets
1004 * @param readset_in: set of sockets to check for read events
1005 * @param writeset_in: set of sockets to check for write events
1006 * @param exceptset_in: set of sockets to check for error events
1007 * @param readset_out: set of sockets that had read events
1008 * @param writeset_out: set of sockets that had write events
1009 * @param exceptset_out: set os sockets that had error events
1010 * @return number of sockets that had events (read/write/exception) (>= 0)
1013 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
1014 fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
1017 fd_set lreadset, lwriteset, lexceptset;
1018 struct lwip_sock *sock;
1019 SYS_ARCH_DECL_PROTECT(lev);
1022 FD_ZERO(&lwriteset);
1023 FD_ZERO(&lexceptset);
1025 /* Go through each socket in each list to count number of sockets which
1027 for(i = 0; i < maxfdp1; i++) {
1028 void* lastdata = NULL;
1030 u16_t sendevent = 0;
1032 /* First get the socket's status (protected)... */
1033 SYS_ARCH_PROTECT(lev);
1034 sock = tryget_socket(i);
1036 lastdata = sock->lastdata;
1037 rcvevent = sock->rcvevent;
1038 sendevent = sock->sendevent;
1039 errevent = sock->errevent;
1041 SYS_ARCH_UNPROTECT(lev);
1042 /* ... then examine it: */
1043 /* See if netconn of this socket is ready for read */
1044 if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
1045 FD_SET(i, &lreadset);
1046 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
1049 /* See if netconn of this socket is ready for write */
1050 if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
1051 FD_SET(i, &lwriteset);
1052 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
1055 /* See if netconn of this socket had an error */
1056 if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
1057 FD_SET(i, &lexceptset);
1058 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
1062 /* copy local sets to the ones provided as arguments */
1063 *readset_out = lreadset;
1064 *writeset_out = lwriteset;
1065 *exceptset_out = lexceptset;
1067 LWIP_ASSERT("nready >= 0", nready >= 0);
1072 * Processing exceptset is not yet implemented.
1075 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
1076 struct timeval *timeout)
1080 fd_set lreadset, lwriteset, lexceptset;
1082 struct lwip_select_cb select_cb;
1085 SYS_ARCH_DECL_PROTECT(lev);
1087 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
1088 maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
1089 timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
1090 timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
1092 /* Go through each socket in each list to count number of sockets which
1094 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1096 /* If we don't have any current events, then suspend if we are supposed to */
1098 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
1099 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
1100 /* This is OK as the local fdsets are empty and nready is zero,
1101 or we would have returned earlier. */
1102 goto return_copy_fdsets;
1105 /* None ready: add our semaphore to list:
1106 We don't actually need any dynamic memory. Our entry on the
1107 list is only valid while we are in this function, so it's ok
1108 to use local variables. */
1110 select_cb.next = NULL;
1111 select_cb.prev = NULL;
1112 select_cb.readset = readset;
1113 select_cb.writeset = writeset;
1114 select_cb.exceptset = exceptset;
1115 select_cb.sem_signalled = 0;
1116 err = sys_sem_new(&select_cb.sem, 0);
1117 if (err != ERR_OK) {
1118 /* failed to create semaphore */
1123 /* Protect the select_cb_list */
1124 SYS_ARCH_PROTECT(lev);
1126 /* Put this select_cb on top of list */
1127 select_cb.next = select_cb_list;
1128 if (select_cb_list != NULL) {
1129 select_cb_list->prev = &select_cb;
1131 select_cb_list = &select_cb;
1132 /* Increasing this counter tells even_callback that the list has changed. */
1135 /* Now we can safely unprotect */
1136 SYS_ARCH_UNPROTECT(lev);
1138 /* Increase select_waiting for each socket we are interested in */
1139 for(i = 0; i < maxfdp1; i++) {
1140 if ((readset && FD_ISSET(i, readset)) ||
1141 (writeset && FD_ISSET(i, writeset)) ||
1142 (exceptset && FD_ISSET(i, exceptset))) {
1143 struct lwip_sock *sock = tryget_socket(i);
1144 LWIP_ASSERT("sock != NULL", sock != NULL);
1145 SYS_ARCH_PROTECT(lev);
1146 sock->select_waiting++;
1147 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
1148 SYS_ARCH_UNPROTECT(lev);
1152 /* Call lwip_selscan again: there could have been events between
1153 the last scan (whithout us on the list) and putting us on the list! */
1154 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1156 /* Still none ready, just wait to be woken */
1161 msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
1162 if (msectimeout == 0) {
1163 /* Wait 1ms at least (0 means wait forever) */
1168 waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
1170 /* Increase select_waiting for each socket we are interested in */
1171 for(i = 0; i < maxfdp1; i++) {
1172 if ((readset && FD_ISSET(i, readset)) ||
1173 (writeset && FD_ISSET(i, writeset)) ||
1174 (exceptset && FD_ISSET(i, exceptset))) {
1175 struct lwip_sock *sock = tryget_socket(i);
1176 LWIP_ASSERT("sock != NULL", sock != NULL);
1177 SYS_ARCH_PROTECT(lev);
1178 sock->select_waiting--;
1179 LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0);
1180 SYS_ARCH_UNPROTECT(lev);
1183 /* Take us off the list */
1184 SYS_ARCH_PROTECT(lev);
1185 if (select_cb.next != NULL) {
1186 select_cb.next->prev = select_cb.prev;
1188 if (select_cb_list == &select_cb) {
1189 LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
1190 select_cb_list = select_cb.next;
1192 LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
1193 select_cb.prev->next = select_cb.next;
1195 /* Increasing this counter tells even_callback that the list has changed. */
1197 SYS_ARCH_UNPROTECT(lev);
1199 sys_sem_free(&select_cb.sem);
1200 if (waitres == SYS_ARCH_TIMEOUT) {
1202 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
1203 /* This is OK as the local fdsets are empty and nready is zero,
1204 or we would have returned earlier. */
1205 goto return_copy_fdsets;
1208 /* See what's set */
1209 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1212 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
1216 *readset = lreadset;
1219 *writeset = lwriteset;
1222 *exceptset = lexceptset;
1230 * Callback registered in the netconn layer for each socket-netconn.
1231 * Processes recvevent (data available) and wakes up tasks waiting for select.
1234 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
1237 struct lwip_sock *sock;
1238 struct lwip_select_cb *scb;
1239 int last_select_cb_ctr;
1240 SYS_ARCH_DECL_PROTECT(lev);
1242 LWIP_UNUSED_ARG(len);
1248 /* Data comes in right away after an accept, even though
1249 * the server task might not have created a new socket yet.
1250 * Just count down (or up) if that's the case and we
1251 * will use the data later. Note that only receive events
1252 * can happen before the new socket is set up. */
1253 SYS_ARCH_PROTECT(lev);
1254 if (conn->socket < 0) {
1255 if (evt == NETCONN_EVT_RCVPLUS) {
1258 SYS_ARCH_UNPROTECT(lev);
1262 SYS_ARCH_UNPROTECT(lev);
1265 sock = get_socket(s);
1273 SYS_ARCH_PROTECT(lev);
1274 /* Set event as required */
1276 case NETCONN_EVT_RCVPLUS:
1279 case NETCONN_EVT_RCVMINUS:
1282 case NETCONN_EVT_SENDPLUS:
1283 sock->sendevent = 1;
1285 case NETCONN_EVT_SENDMINUS:
1286 sock->sendevent = 0;
1288 case NETCONN_EVT_ERROR:
1292 LWIP_ASSERT("unknown event", 0);
1296 if (sock->select_waiting == 0) {
1297 /* noone is waiting for this socket, no need to check select_cb_list */
1298 SYS_ARCH_UNPROTECT(lev);
1302 /* Now decide if anyone is waiting for this socket */
1303 /* NOTE: This code goes through the select_cb_list list multiple times
1304 ONLY IF a select was actually waiting. We go through the list the number
1305 of waiting select calls + 1. This list is expected to be small. */
1307 /* At this point, SYS_ARCH is still protected! */
1309 for (scb = select_cb_list; scb != NULL; scb = scb->next) {
1310 if (scb->sem_signalled == 0) {
1311 /* semaphore not signalled yet */
1313 /* Test this select call for our socket */
1314 if (sock->rcvevent > 0) {
1315 if (scb->readset && FD_ISSET(s, scb->readset)) {
1319 if (sock->sendevent != 0) {
1320 if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
1324 if (sock->errevent != 0) {
1325 if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
1330 scb->sem_signalled = 1;
1331 /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
1332 lead to the select thread taking itself off the list, invalidagin the semaphore. */
1333 sys_sem_signal(&scb->sem);
1336 /* unlock interrupts with each step */
1337 last_select_cb_ctr = select_cb_ctr;
1338 SYS_ARCH_UNPROTECT(lev);
1339 /* this makes sure interrupt protection time is short */
1340 SYS_ARCH_PROTECT(lev);
1341 if (last_select_cb_ctr != select_cb_ctr) {
1342 /* someone has changed select_cb_list, restart at the beginning */
1346 SYS_ARCH_UNPROTECT(lev);
1350 * Unimplemented: Close one end of a full-duplex connection.
1351 * Currently, the full connection is closed.
1354 lwip_shutdown(int s, int how)
1356 struct lwip_sock *sock;
1358 u8_t shut_rx = 0, shut_tx = 0;
1360 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
1362 sock = get_socket(s);
1367 if (sock->conn != NULL) {
1368 if (netconn_type(sock->conn) != NETCONN_TCP) {
1369 sock_set_errno(sock, EOPNOTSUPP);
1373 sock_set_errno(sock, ENOTCONN);
1377 if (how == SHUT_RD) {
1379 } else if (how == SHUT_WR) {
1381 } else if(how == SHUT_RDWR) {
1385 sock_set_errno(sock, EINVAL);
1388 err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
1390 sock_set_errno(sock, err_to_errno(err));
1391 return (err == ERR_OK ? 0 : -1);
1395 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
1397 struct lwip_sock *sock;
1398 struct sockaddr_in sin;
1401 sock = get_socket(s);
1406 memset(&sin, 0, sizeof(sin));
1407 sin.sin_len = sizeof(sin);
1408 sin.sin_family = AF_INET;
1410 /* get the IP address and port */
1411 netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
1413 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
1414 ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
1415 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port));
1417 sin.sin_port = htons(sin.sin_port);
1418 inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
1420 if (*namelen > sizeof(sin)) {
1421 *namelen = sizeof(sin);
1424 MEMCPY(name, &sin, *namelen);
1425 sock_set_errno(sock, 0);
1430 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
1432 return lwip_getaddrname(s, name, namelen, 0);
1436 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
1438 return lwip_getaddrname(s, name, namelen, 1);
1442 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
1445 struct lwip_sock *sock = get_socket(s);
1446 struct lwip_setgetsockopt_data data;
1452 if ((NULL == optval) || (NULL == optlen)) {
1453 sock_set_errno(sock, EFAULT);
1457 /* Do length and type checks for the various options first, to keep it readable. */
1460 /* Level: SOL_SOCKET */
1466 /* UNIMPL case SO_DEBUG: */
1467 /* UNIMPL case SO_DONTROUTE: */
1470 /* UNIMPL case SO_CONTIMEO: */
1471 /* UNIMPL case SO_SNDTIMEO: */
1472 #if LWIP_SO_RCVTIMEO
1474 #endif /* LWIP_SO_RCVTIMEO */
1477 #endif /* LWIP_SO_RCVBUF */
1478 /* UNIMPL case SO_OOBINLINE: */
1479 /* UNIMPL case SO_SNDBUF: */
1480 /* UNIMPL case SO_RCVLOWAT: */
1481 /* UNIMPL case SO_SNDLOWAT: */
1485 #endif /* SO_REUSE */
1487 /* UNIMPL case SO_USELOOPBACK: */
1488 if (*optlen < sizeof(int)) {
1494 if (*optlen < sizeof(int)) {
1498 if ((sock->conn->type != NETCONN_UDP) ||
1499 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1500 /* this flag is only available for UDP, not for UDP lite */
1503 #endif /* LWIP_UDP */
1507 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1510 } /* switch (optname) */
1513 /* Level: IPPROTO_IP */
1516 /* UNIMPL case IP_HDRINCL: */
1517 /* UNIMPL case IP_RCVDSTADDR: */
1518 /* UNIMPL case IP_RCVIF: */
1521 if (*optlen < sizeof(int)) {
1526 case IP_MULTICAST_TTL:
1527 if (*optlen < sizeof(u8_t)) {
1531 case IP_MULTICAST_IF:
1532 if (*optlen < sizeof(struct in_addr)) {
1536 case IP_MULTICAST_LOOP:
1537 if (*optlen < sizeof(u8_t)) {
1540 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1544 #endif /* LWIP_IGMP */
1547 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1550 } /* switch (optname) */
1554 /* Level: IPPROTO_TCP */
1556 if (*optlen < sizeof(int)) {
1561 /* If this is no TCP socket, ignore any options. */
1562 if (sock->conn->type != NETCONN_TCP)
1568 #if LWIP_TCP_KEEPALIVE
1572 #endif /* LWIP_TCP_KEEPALIVE */
1576 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
1579 } /* switch (optname) */
1581 #endif /* LWIP_TCP */
1582 #if LWIP_UDP && LWIP_UDPLITE
1583 /* Level: IPPROTO_UDPLITE */
1584 case IPPROTO_UDPLITE:
1585 if (*optlen < sizeof(int)) {
1590 /* If this is no UDP lite socket, ignore any options. */
1591 if (sock->conn->type != NETCONN_UDPLITE) {
1596 case UDPLITE_SEND_CSCOV:
1597 case UDPLITE_RECV_CSCOV:
1601 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
1604 } /* switch (optname) */
1606 #endif /* LWIP_UDP && LWIP_UDPLITE*/
1607 /* UNDEFINED LEVEL */
1609 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
1610 s, level, optname));
1615 if (err != ERR_OK) {
1616 sock_set_errno(sock, err);
1620 /* Now do the actual option processing */
1624 #endif /* LWIP_DEBUG */
1626 data.optname = optname;
1627 data.optval = optval;
1628 data.optlen = optlen;
1630 tcpip_callback(lwip_getsockopt_internal, &data);
1631 sys_arch_sem_wait(&sock->conn->op_completed, 0);
1632 /* maybe lwip_getsockopt_internal has changed err */
1635 sock_set_errno(sock, err);
1636 return err ? -1 : 0;
1640 lwip_getsockopt_internal(void *arg)
1642 struct lwip_sock *sock;
1645 #endif /* LWIP_DEBUG */
1648 struct lwip_setgetsockopt_data *data;
1650 LWIP_ASSERT("arg != NULL", arg != NULL);
1652 data = (struct lwip_setgetsockopt_data*)arg;
1656 #endif /* LWIP_DEBUG */
1657 level = data->level;
1658 optname = data->optname;
1659 optval = data->optval;
1663 /* Level: SOL_SOCKET */
1667 /* The option flags */
1670 /* UNIMPL case SO_DEBUG: */
1671 /* UNIMPL case SO_DONTROUTE: */
1673 /* UNIMPL case SO_OOBINCLUDE: */
1677 #endif /* SO_REUSE */
1678 /*case SO_USELOOPBACK: UNIMPL */
1679 *(int*)optval = sock->conn->pcb.ip->so_options & optname;
1680 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
1681 s, optname, (*(int*)optval?"on":"off")));
1685 switch (NETCONNTYPE_GROUP(sock->conn->type)) {
1687 *(int*)optval = SOCK_RAW;
1690 *(int*)optval = SOCK_STREAM;
1693 *(int*)optval = SOCK_DGRAM;
1695 default: /* unrecognized socket type */
1696 *(int*)optval = sock->conn->type;
1697 LWIP_DEBUGF(SOCKETS_DEBUG,
1698 ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
1699 s, *(int *)optval));
1700 } /* switch (sock->conn->type) */
1701 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
1702 s, *(int *)optval));
1706 /* only overwrite ERR_OK or tempoary errors */
1707 if ((sock->err == 0) || (sock->err == EINPROGRESS)) {
1708 sock_set_errno(sock, err_to_errno(sock->conn->last_err));
1710 *(int *)optval = sock->err;
1712 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
1713 s, *(int *)optval));
1716 #if LWIP_SO_RCVTIMEO
1718 *(int *)optval = netconn_get_recvtimeout(sock->conn);
1720 #endif /* LWIP_SO_RCVTIMEO */
1723 *(int *)optval = netconn_get_recvbufsize(sock->conn);
1725 #endif /* LWIP_SO_RCVBUF */
1728 *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
1730 #endif /* LWIP_UDP*/
1732 LWIP_ASSERT("unhandled optname", 0);
1734 } /* switch (optname) */
1737 /* Level: IPPROTO_IP */
1741 *(int*)optval = sock->conn->pcb.ip->ttl;
1742 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
1743 s, *(int *)optval));
1746 *(int*)optval = sock->conn->pcb.ip->tos;
1747 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
1748 s, *(int *)optval));
1751 case IP_MULTICAST_TTL:
1752 *(u8_t*)optval = sock->conn->pcb.ip->ttl;
1753 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
1754 s, *(int *)optval));
1756 case IP_MULTICAST_IF:
1757 inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip);
1758 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
1759 s, *(u32_t *)optval));
1761 case IP_MULTICAST_LOOP:
1762 if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
1767 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
1768 s, *(int *)optval));
1770 #endif /* LWIP_IGMP */
1772 LWIP_ASSERT("unhandled optname", 0);
1774 } /* switch (optname) */
1778 /* Level: IPPROTO_TCP */
1782 *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
1783 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
1784 s, (*(int*)optval)?"on":"off") );
1787 *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
1788 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",
1789 s, *(int *)optval));
1792 #if LWIP_TCP_KEEPALIVE
1794 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
1795 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",
1796 s, *(int *)optval));
1799 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
1800 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",
1801 s, *(int *)optval));
1804 *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
1805 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",
1806 s, *(int *)optval));
1808 #endif /* LWIP_TCP_KEEPALIVE */
1810 LWIP_ASSERT("unhandled optname", 0);
1812 } /* switch (optname) */
1814 #endif /* LWIP_TCP */
1815 #if LWIP_UDP && LWIP_UDPLITE
1816 /* Level: IPPROTO_UDPLITE */
1817 case IPPROTO_UDPLITE:
1819 case UDPLITE_SEND_CSCOV:
1820 *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
1821 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
1822 s, (*(int*)optval)) );
1824 case UDPLITE_RECV_CSCOV:
1825 *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
1826 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
1827 s, (*(int*)optval)) );
1830 LWIP_ASSERT("unhandled optname", 0);
1832 } /* switch (optname) */
1834 #endif /* LWIP_UDP */
1836 LWIP_ASSERT("unhandled level", 0);
1838 } /* switch (level) */
1839 sys_sem_signal(&sock->conn->op_completed);
1843 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
1845 struct lwip_sock *sock = get_socket(s);
1847 struct lwip_setgetsockopt_data data;
1853 if (NULL == optval) {
1854 sock_set_errno(sock, EFAULT);
1858 /* Do length and type checks for the various options first, to keep it readable. */
1861 /* Level: SOL_SOCKET */
1866 /* UNIMPL case SO_DEBUG: */
1867 /* UNIMPL case SO_DONTROUTE: */
1869 /* UNIMPL case case SO_CONTIMEO: */
1870 /* UNIMPL case case SO_SNDTIMEO: */
1871 #if LWIP_SO_RCVTIMEO
1873 #endif /* LWIP_SO_RCVTIMEO */
1876 #endif /* LWIP_SO_RCVBUF */
1877 /* UNIMPL case SO_OOBINLINE: */
1878 /* UNIMPL case SO_SNDBUF: */
1879 /* UNIMPL case SO_RCVLOWAT: */
1880 /* UNIMPL case SO_SNDLOWAT: */
1884 #endif /* SO_REUSE */
1885 /* UNIMPL case SO_USELOOPBACK: */
1886 if (optlen < sizeof(int)) {
1891 if (optlen < sizeof(int)) {
1895 if ((sock->conn->type != NETCONN_UDP) ||
1896 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1897 /* this flag is only available for UDP, not for UDP lite */
1900 #endif /* LWIP_UDP */
1903 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1906 } /* switch (optname) */
1909 /* Level: IPPROTO_IP */
1912 /* UNIMPL case IP_HDRINCL: */
1913 /* UNIMPL case IP_RCVDSTADDR: */
1914 /* UNIMPL case IP_RCVIF: */
1917 if (optlen < sizeof(int)) {
1922 case IP_MULTICAST_TTL:
1923 if (optlen < sizeof(u8_t)) {
1926 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1930 case IP_MULTICAST_IF:
1931 if (optlen < sizeof(struct in_addr)) {
1934 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1938 case IP_MULTICAST_LOOP:
1939 if (optlen < sizeof(u8_t)) {
1942 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1946 case IP_ADD_MEMBERSHIP:
1947 case IP_DROP_MEMBERSHIP:
1948 if (optlen < sizeof(struct ip_mreq)) {
1951 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1955 #endif /* LWIP_IGMP */
1957 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1960 } /* switch (optname) */
1964 /* Level: IPPROTO_TCP */
1966 if (optlen < sizeof(int)) {
1971 /* If this is no TCP socket, ignore any options. */
1972 if (sock->conn->type != NETCONN_TCP)
1978 #if LWIP_TCP_KEEPALIVE
1982 #endif /* LWIP_TCP_KEEPALIVE */
1986 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
1989 } /* switch (optname) */
1991 #endif /* LWIP_TCP */
1992 #if LWIP_UDP && LWIP_UDPLITE
1993 /* Level: IPPROTO_UDPLITE */
1994 case IPPROTO_UDPLITE:
1995 if (optlen < sizeof(int)) {
2000 /* If this is no UDP lite socket, ignore any options. */
2001 if (sock->conn->type != NETCONN_UDPLITE)
2005 case UDPLITE_SEND_CSCOV:
2006 case UDPLITE_RECV_CSCOV:
2010 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
2013 } /* switch (optname) */
2015 #endif /* LWIP_UDP && LWIP_UDPLITE */
2016 /* UNDEFINED LEVEL */
2018 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2019 s, level, optname));
2021 } /* switch (level) */
2024 if (err != ERR_OK) {
2025 sock_set_errno(sock, err);
2030 /* Now do the actual option processing */
2034 #endif /* LWIP_DEBUG */
2036 data.optname = optname;
2037 data.optval = (void*)optval;
2038 data.optlen = &optlen;
2040 tcpip_callback(lwip_setsockopt_internal, &data);
2041 sys_arch_sem_wait(&sock->conn->op_completed, 0);
2042 /* maybe lwip_setsockopt_internal has changed err */
2045 sock_set_errno(sock, err);
2046 return err ? -1 : 0;
2050 lwip_setsockopt_internal(void *arg)
2052 struct lwip_sock *sock;
2055 #endif /* LWIP_DEBUG */
2058 struct lwip_setgetsockopt_data *data;
2060 LWIP_ASSERT("arg != NULL", arg != NULL);
2062 data = (struct lwip_setgetsockopt_data*)arg;
2066 #endif /* LWIP_DEBUG */
2067 level = data->level;
2068 optname = data->optname;
2069 optval = data->optval;
2073 /* Level: SOL_SOCKET */
2077 /* The option flags */
2079 /* UNIMPL case SO_DEBUG: */
2080 /* UNIMPL case SO_DONTROUTE: */
2082 /* UNIMPL case SO_OOBINCLUDE: */
2086 #endif /* SO_REUSE */
2087 /* UNIMPL case SO_USELOOPBACK: */
2088 if (*(int*)optval) {
2089 sock->conn->pcb.ip->so_options |= optname;
2091 sock->conn->pcb.ip->so_options &= ~optname;
2093 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
2094 s, optname, (*(int*)optval?"on":"off")));
2096 #if LWIP_SO_RCVTIMEO
2098 netconn_set_recvtimeout(sock->conn, *(int*)optval);
2100 #endif /* LWIP_SO_RCVTIMEO */
2103 netconn_set_recvbufsize(sock->conn, *(int*)optval);
2105 #endif /* LWIP_SO_RCVBUF */
2108 if (*(int*)optval) {
2109 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
2111 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
2114 #endif /* LWIP_UDP */
2116 LWIP_ASSERT("unhandled optname", 0);
2118 } /* switch (optname) */
2121 /* Level: IPPROTO_IP */
2125 sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
2126 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
2127 s, sock->conn->pcb.ip->ttl));
2130 sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
2131 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
2132 s, sock->conn->pcb.ip->tos));
2135 case IP_MULTICAST_TTL:
2136 sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);
2138 case IP_MULTICAST_IF:
2139 inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval);
2141 case IP_MULTICAST_LOOP:
2142 if (*(u8_t*)optval) {
2143 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
2145 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
2148 case IP_ADD_MEMBERSHIP:
2149 case IP_DROP_MEMBERSHIP:
2151 /* If this is a TCP or a RAW socket, ignore these options. */
2152 struct ip_mreq *imr = (struct ip_mreq *)optval;
2154 ip_addr_t multi_addr;
2155 inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
2156 inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
2157 if(optname == IP_ADD_MEMBERSHIP){
2158 data->err = igmp_joingroup(&if_addr, &multi_addr);
2160 data->err = igmp_leavegroup(&if_addr, &multi_addr);
2162 if(data->err != ERR_OK) {
2163 data->err = EADDRNOTAVAIL;
2167 #endif /* LWIP_IGMP */
2169 LWIP_ASSERT("unhandled optname", 0);
2171 } /* switch (optname) */
2175 /* Level: IPPROTO_TCP */
2179 if (*(int*)optval) {
2180 tcp_nagle_disable(sock->conn->pcb.tcp);
2182 tcp_nagle_enable(sock->conn->pcb.tcp);
2184 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
2185 s, (*(int *)optval)?"on":"off") );
2188 sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
2189 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
2190 s, sock->conn->pcb.tcp->keep_idle));
2193 #if LWIP_TCP_KEEPALIVE
2195 sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
2196 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
2197 s, sock->conn->pcb.tcp->keep_idle));
2200 sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
2201 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
2202 s, sock->conn->pcb.tcp->keep_intvl));
2205 sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
2206 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
2207 s, sock->conn->pcb.tcp->keep_cnt));
2209 #endif /* LWIP_TCP_KEEPALIVE */
2211 LWIP_ASSERT("unhandled optname", 0);
2213 } /* switch (optname) */
2215 #endif /* LWIP_TCP*/
2216 #if LWIP_UDP && LWIP_UDPLITE
2217 /* Level: IPPROTO_UDPLITE */
2218 case IPPROTO_UDPLITE:
2220 case UDPLITE_SEND_CSCOV:
2221 if (((*(int*)optval != 0) && ((*(int*)optval < 8)) ) || (*(int*)optval > 0xffff)) {
2222 /* don't allow illegal values! */
2223 sock->conn->pcb.udp->chksum_len_tx = 8;
2225 sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;
2227 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
2228 s, (*(int*)optval)) );
2230 case UDPLITE_RECV_CSCOV:
2231 if (((*(int*)optval != 0) && ((*(int*)optval < 8))) || (*(int*)optval > 0xffff)) {
2232 /* don't allow illegal values! */
2233 sock->conn->pcb.udp->chksum_len_rx = 8;
2235 sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;
2237 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
2238 s, (*(int*)optval)) );
2241 LWIP_ASSERT("unhandled optname", 0);
2243 } /* switch (optname) */
2245 #endif /* LWIP_UDP */
2247 LWIP_ASSERT("unhandled level", 0);
2249 } /* switch (level) */
2250 sys_sem_signal(&sock->conn->op_completed);
2254 lwip_ioctl(int s, long cmd, void *argp)
2256 struct lwip_sock *sock = get_socket(s);
2261 #endif /* LWIP_SO_RCVBUF */
2271 sock_set_errno(sock, EINVAL);
2275 SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
2276 if (recv_avail < 0) {
2279 *((u16_t*)argp) = (u16_t)recv_avail;
2281 /* Check if there is data left from the last recv operation. /maq 041215 */
2282 if (sock->lastdata) {
2283 struct pbuf *p = (struct pbuf *)sock->lastdata;
2284 if (netconn_type(sock->conn) != NETCONN_TCP) {
2285 p = ((struct netbuf *)p)->p;
2287 buflen = p->tot_len;
2288 buflen -= sock->lastoffset;
2290 *((u16_t*)argp) += buflen;
2293 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
2294 sock_set_errno(sock, 0);
2296 #endif /* LWIP_SO_RCVBUF */
2300 if (argp && *(u32_t*)argp) {
2303 netconn_set_nonblocking(sock->conn, val);
2304 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
2305 sock_set_errno(sock, 0);
2309 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
2310 sock_set_errno(sock, ENOSYS); /* not yet implemented */
2312 } /* switch (cmd) */
2315 /** A minimal implementation of fcntl.
2316 * Currently only the commands F_GETFL and F_SETFL are implemented.
2317 * Only the flag O_NONBLOCK is implemented.
2320 lwip_fcntl(int s, int cmd, int val)
2322 struct lwip_sock *sock = get_socket(s);
2325 if (!sock || !sock->conn) {
2331 ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
2334 if ((val & ~O_NONBLOCK) == 0) {
2335 /* only O_NONBLOCK, all other bits are zero */
2336 netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
2341 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
2347 #endif /* LWIP_SOCKET */