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 IP4ADDR_PORT_TO_SOCKADDR(sin, ipXaddr, port) do { \
62 (sin)->sin_len = sizeof(struct sockaddr_in); \
63 (sin)->sin_family = AF_INET; \
64 (sin)->sin_port = htons((port)); \
65 inet_addr_from_ipaddr(&(sin)->sin_addr, ipX_2_ip(ipXaddr)); \
66 memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0)
67 #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipXaddr, port) do { \
68 inet_addr_to_ipaddr(ipX_2_ip(ipXaddr), &((sin)->sin_addr)); \
69 (port) = ntohs((sin)->sin_port); }while(0)
72 #define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \
73 ((namelen) == sizeof(struct sockaddr_in6)))
74 #define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \
75 ((name)->sa_family == AF_INET6))
76 #define SOCK_ADDR_TYPE_MATCH(name, sock) \
77 ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \
78 (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type))))
79 #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipXaddr, port) do { \
80 (sin6)->sin6_len = sizeof(struct sockaddr_in6); \
81 (sin6)->sin6_family = AF_INET6; \
82 (sin6)->sin6_port = htons((port)); \
83 (sin6)->sin6_flowinfo = 0; \
84 inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipX_2_ip6(ipXaddr)); }while(0)
85 #define IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) do { \
87 IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ipXaddr, port); \
89 IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port); \
91 #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipXaddr, port) do { \
92 inet6_addr_to_ip6addr(ipX_2_ip6(ipXaddr), &((sin6)->sin6_addr)); \
93 (port) = ntohs((sin6)->sin6_port); }while(0)
94 #define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) do { \
96 SOCKADDR6_TO_IP6ADDR_PORT((struct sockaddr_in6*)(void*)(sockaddr), ipXaddr, port); \
98 SOCKADDR4_TO_IP4ADDR_PORT((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port); \
100 #define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \
101 (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6))
102 #else /* LWIP_IPV6 */
103 #define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in))
104 #define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET)
105 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
106 #define IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) \
107 IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port)
108 #define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) \
109 SOCKADDR4_TO_IP4ADDR_PORT((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port)
110 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
111 #endif /* LWIP_IPV6 */
113 #define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \
114 IS_SOCK_ADDR_TYPE_VALID(name))
115 #define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \
116 SOCK_ADDR_TYPE_MATCH(name, sock))
117 #define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0)
121 #define NUM_SOCKETS MEMP_NUM_NETCONN
123 /** Contains all internal pointers and states used for a socket */
125 /** sockets currently are built on netconns, each socket has one netconn */
126 struct netconn *conn;
127 /** data that was left from the previous read */
129 /** offset in the data that was left from the previous read */
131 /** number of times data was received, set by event_callback(),
132 tested by the receive and select functions */
134 /** number of times data was ACKed (free send buffer), set by event_callback(),
137 /** error happened for this socket, set by event_callback(), tested by select */
139 /** last error that occurred on this socket */
141 /** counter of how many threads are waiting for this socket using select */
145 /** Description for a task waiting in select */
146 struct lwip_select_cb {
147 /** Pointer to the next waiting task */
148 struct lwip_select_cb *next;
149 /** Pointer to the previous waiting task */
150 struct lwip_select_cb *prev;
151 /** readset passed to select */
153 /** writeset passed to select */
155 /** unimplemented: exceptset passed to select */
157 /** don't signal the same semaphore twice: set to 1 when signalled */
159 /** semaphore to wake up a task waiting for select */
163 /** This struct is used to pass data to the set/getsockopt_internal
164 * functions running in tcpip_thread context (only a void* is allowed) */
165 struct lwip_setgetsockopt_data {
166 /** socket struct for which to change options */
167 struct lwip_sock *sock;
169 /** socket index for which to change options */
171 #endif /* LWIP_DEBUG */
172 /** level of the option to process */
174 /** name of the option to process */
176 /** set: value to set the option to
177 * get: value of the option is stored here */
179 /** size of *optval */
181 /** if an error occures, it is temporarily stored here */
185 /** A struct sockaddr replacement that has the same alignment as sockaddr_in/
186 * sockaddr_in6 if instantiated.
188 union sockaddr_aligned {
191 struct sockaddr_in6 sin6;
192 #endif /* LWIP_IPV6 */
193 struct sockaddr_in sin;
197 /** The global array of available sockets */
198 static struct lwip_sock sockets[NUM_SOCKETS];
199 /** The global list of tasks waiting for select */
200 static struct lwip_select_cb *select_cb_list;
201 /** This counter is increased from lwip_select when the list is chagned
202 and checked in event_callback to see if it has changed. */
203 static volatile int select_cb_ctr;
205 /** Table to quickly map an lwIP error (err_t) to a socket error
206 * by using -err as an index */
207 static const int err_to_errno_table[] = {
208 0, /* ERR_OK 0 No error, everything OK. */
209 ENOMEM, /* ERR_MEM -1 Out of memory error. */
210 ENOBUFS, /* ERR_BUF -2 Buffer error. */
211 EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
212 EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
213 EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
214 EINVAL, /* ERR_VAL -6 Illegal value. */
215 EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
216 EADDRINUSE, /* ERR_USE -8 Address in use. */
217 EALREADY, /* ERR_ISCONN -9 Already connected. */
218 ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */
219 ECONNRESET, /* ERR_RST -11 Connection reset. */
220 ENOTCONN, /* ERR_CLSD -12 Connection closed. */
221 ENOTCONN, /* ERR_CONN -13 Not connected. */
222 EIO, /* ERR_ARG -14 Illegal argument. */
223 -1, /* ERR_IF -15 Low-level netif error */
226 #define ERR_TO_ERRNO_TABLE_SIZE \
227 (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
229 #define err_to_errno(err) \
230 ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
231 err_to_errno_table[-(err)] : EIO)
235 #define set_errno(err) errno = (err)
238 #define set_errno(err)
241 #define sock_set_errno(sk, e) do { \
243 set_errno(sk->err); \
246 /* Forward delcaration of some functions */
247 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
248 static void lwip_getsockopt_internal(void *arg);
249 static void lwip_setsockopt_internal(void *arg);
252 * Initialize this module. This function has to be called before any other
253 * functions in this module!
256 lwip_socket_init(void)
261 * Map a externally used socket index to the internal socket representation.
263 * @param s externally used socket index
264 * @return struct lwip_sock for the socket or NULL if not found
266 static struct lwip_sock *
269 struct lwip_sock *sock;
271 if ((s < 0) || (s >= NUM_SOCKETS)) {
272 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
280 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
289 * Same as get_socket but doesn't set errno
291 * @param s externally used socket index
292 * @return struct lwip_sock for the socket or NULL if not found
294 static struct lwip_sock *
297 if ((s < 0) || (s >= NUM_SOCKETS)) {
300 if (!sockets[s].conn) {
307 * Allocate a new socket for a given netconn.
309 * @param newconn the netconn for which to allocate a socket
310 * @param accepted 1 if socket has been created by accept(),
311 * 0 if socket has been created by socket()
312 * @return the index of the new socket; -1 on error
315 alloc_socket(struct netconn *newconn, int accepted)
318 SYS_ARCH_DECL_PROTECT(lev);
320 /* allocate a new socket identifier */
321 for (i = 0; i < NUM_SOCKETS; ++i) {
322 /* Protect socket array */
323 SYS_ARCH_PROTECT(lev);
324 if (!sockets[i].conn) {
325 sockets[i].conn = newconn;
326 /* The socket is not yet known to anyone, so no need to protect
327 after having marked it as used. */
328 SYS_ARCH_UNPROTECT(lev);
329 sockets[i].lastdata = NULL;
330 sockets[i].lastoffset = 0;
331 sockets[i].rcvevent = 0;
332 /* TCP sendbuf is empty, but the socket is not yet writable until connected
333 * (unless it has been created by accept()). */
334 sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
335 sockets[i].errevent = 0;
337 sockets[i].select_waiting = 0;
340 SYS_ARCH_UNPROTECT(lev);
345 /** Free a socket. The socket's netconn must have been
348 * @param sock the socket to free
349 * @param is_tcp != 0 for TCP sockets, used to free lastdata
352 free_socket(struct lwip_sock *sock, int is_tcp)
355 SYS_ARCH_DECL_PROTECT(lev);
357 lastdata = sock->lastdata;
358 sock->lastdata = NULL;
359 sock->lastoffset = 0;
362 /* Protect socket array */
363 SYS_ARCH_PROTECT(lev);
365 SYS_ARCH_UNPROTECT(lev);
366 /* don't use 'sock' after this line, as another task might have allocated it */
368 if (lastdata != NULL) {
370 pbuf_free((struct pbuf *)lastdata);
372 netbuf_delete((struct netbuf *)lastdata);
377 /* Below this, the well-known socket functions are implemented.
378 * Use google.com or opengroup.org to get a good description :-)
380 * Exceptions are documented!
384 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
386 struct lwip_sock *sock, *nsock;
387 struct netconn *newconn;
392 SYS_ARCH_DECL_PROTECT(lev);
394 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
395 sock = get_socket(s);
400 if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
401 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
402 sock_set_errno(sock, EWOULDBLOCK);
406 /* wait for a new connection */
407 err = netconn_accept(sock->conn, &newconn);
409 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
410 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
411 sock_set_errno(sock, EOPNOTSUPP);
414 sock_set_errno(sock, err_to_errno(err));
417 LWIP_ASSERT("newconn != NULL", newconn != NULL);
418 /* Prevent automatic window updates, we do this on our own! */
419 netconn_set_noautorecved(newconn, 1);
421 /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
422 * not be NULL if addr is valid.
425 union sockaddr_aligned tempaddr;
426 /* get the IP address and port of the remote host */
427 err = netconn_peer(newconn, ipX_2_ip(&naddr), &port);
429 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
430 netconn_delete(newconn);
431 sock_set_errno(sock, err_to_errno(err));
434 LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
436 IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(newconn->type), &tempaddr, &naddr, port);
437 if (*addrlen > tempaddr.sa.sa_len) {
438 *addrlen = tempaddr.sa.sa_len;
440 MEMCPY(addr, &tempaddr, *addrlen);
443 newsock = alloc_socket(newconn, 1);
445 netconn_delete(newconn);
446 sock_set_errno(sock, ENFILE);
449 LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));
450 LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
451 nsock = &sockets[newsock];
453 /* See event_callback: If data comes in right away after an accept, even
454 * though the server task might not have created a new socket yet.
455 * In that case, newconn->socket is counted down (newconn->socket--),
456 * so nsock->rcvevent is >= 1 here!
458 SYS_ARCH_PROTECT(lev);
459 nsock->rcvevent += (s16_t)(-1 - newconn->socket);
460 newconn->socket = newsock;
461 SYS_ARCH_UNPROTECT(lev);
463 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock));
465 LWIP_DEBUGF(SOCKETS_DEBUG, (" addr="));
466 ipX_addr_debug_print(NETCONNTYPE_ISIPV6(newconn->type), SOCKETS_DEBUG, &naddr);
467 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
470 sock_set_errno(sock, 0);
475 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
477 struct lwip_sock *sock;
478 ipX_addr_t local_addr;
482 sock = get_socket(s);
487 if (!SOCK_ADDR_TYPE_MATCH(name, sock)) {
488 /* sockaddr does not match socket type (IPv4/IPv6) */
489 sock_set_errno(sock, err_to_errno(ERR_VAL));
493 /* check size, familiy and alignment of 'name' */
494 LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) &&
495 IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)),
496 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
497 LWIP_UNUSED_ARG(namelen);
499 SOCKADDR_TO_IPXADDR_PORT((name->sa_family == AF_INET6), name, &local_addr, local_port);
500 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
501 ipX_addr_debug_print(name->sa_family == AF_INET6, SOCKETS_DEBUG, &local_addr);
502 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));
504 err = netconn_bind(sock->conn, ipX_2_ip(&local_addr), local_port);
507 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
508 sock_set_errno(sock, err_to_errno(err));
512 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
513 sock_set_errno(sock, 0);
520 struct lwip_sock *sock;
523 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
525 sock = get_socket(s);
530 if(sock->conn != NULL) {
531 is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP;
533 LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
536 netconn_delete(sock->conn);
538 free_socket(sock, is_tcp);
544 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
546 struct lwip_sock *sock;
549 sock = get_socket(s);
554 if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) {
555 /* sockaddr does not match socket type (IPv4/IPv6) */
556 sock_set_errno(sock, err_to_errno(ERR_VAL));
560 /* check size, familiy and alignment of 'name' */
561 LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) &&
562 IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name),
563 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
564 LWIP_UNUSED_ARG(namelen);
565 if (name->sa_family == AF_UNSPEC) {
566 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
567 err = netconn_disconnect(sock->conn);
569 ipX_addr_t remote_addr;
571 SOCKADDR_TO_IPXADDR_PORT((name->sa_family == AF_INET6), name, &remote_addr, remote_port);
572 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
573 ipX_addr_debug_print(name->sa_family == AF_INET6, SOCKETS_DEBUG, &remote_addr);
574 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
576 err = netconn_connect(sock->conn, ipX_2_ip(&remote_addr), remote_port);
580 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
581 sock_set_errno(sock, err_to_errno(err));
585 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
586 sock_set_errno(sock, 0);
591 * Set a socket into listen mode.
592 * The socket may not have been used for another connection previously.
594 * @param s the socket to set to listening mode
595 * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
596 * @return 0 on success, non-zero on failure
599 lwip_listen(int s, int backlog)
601 struct lwip_sock *sock;
604 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
606 sock = get_socket(s);
611 /* limit the "backlog" parameter to fit in an u8_t */
612 backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
614 err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
617 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
618 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
619 sock_set_errno(sock, EOPNOTSUPP);
622 sock_set_errno(sock, err_to_errno(err));
626 sock_set_errno(sock, 0);
631 lwip_recvfrom(int s, void *mem, size_t len, int flags,
632 struct sockaddr *from, socklen_t *fromlen)
634 struct lwip_sock *sock;
637 u16_t buflen, copylen;
642 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
643 sock = get_socket(s);
649 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
650 /* Check if there is data left from the last recv operation. */
651 if (sock->lastdata) {
652 buf = sock->lastdata;
654 /* If this is non-blocking call, then check first */
655 if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
656 (sock->rcvevent <= 0)) {
658 /* update receive window */
659 netconn_recved(sock->conn, (u32_t)off);
660 /* already received data, return that */
661 sock_set_errno(sock, 0);
664 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
665 sock_set_errno(sock, EWOULDBLOCK);
669 /* No data was left from the previous operation, so we try to get
670 some from the network. */
671 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
672 err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
674 err = netconn_recv(sock->conn, (struct netbuf **)&buf);
676 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
681 /* update receive window */
682 netconn_recved(sock->conn, (u32_t)off);
683 /* already received data, return that */
684 sock_set_errno(sock, 0);
687 /* We should really do some error checking here. */
688 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
689 s, lwip_strerr(err)));
690 sock_set_errno(sock, err_to_errno(err));
691 if (err == ERR_CLSD) {
697 LWIP_ASSERT("buf != NULL", buf != NULL);
698 sock->lastdata = buf;
701 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
702 p = (struct pbuf *)buf;
704 p = ((struct netbuf *)buf)->p;
707 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
708 buflen, len, off, sock->lastoffset));
710 buflen -= sock->lastoffset;
715 copylen = (u16_t)len;
718 /* copy the contents of the received buffer into
719 the supplied memory pointer mem */
720 pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
724 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
725 LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
728 (p->flags & PBUF_FLAG_PUSH) ||
729 (sock->rcvevent <= 0) ||
730 ((flags & MSG_PEEK)!=0)) {
737 /* Check to see from where the data was.*/
741 #endif /* !SOCKETS_DEBUG */
745 ipX_addr_t *fromaddr;
746 union sockaddr_aligned saddr;
747 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
748 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
750 /* @todo: this does not work for IPv6, yet */
751 netconn_getaddr(sock->conn, ipX_2_ip(fromaddr), &port, 0);
753 port = netbuf_fromport((struct netbuf *)buf);
754 fromaddr = netbuf_fromaddr_ipX((struct netbuf *)buf);
756 IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
757 &saddr, fromaddr, port);
758 ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
759 SOCKETS_DEBUG, fromaddr);
760 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
761 if (*fromlen > saddr.sa.sa_len) {
762 *fromlen = saddr.sa.sa_len;
764 MEMCPY(from, &saddr, *fromlen);
768 /* If we don't peek the incoming message... */
769 if ((flags & MSG_PEEK) == 0) {
770 /* If this is a TCP socket, check if there is data left in the
771 buffer. If so, it should be saved in the sock structure for next
773 if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (buflen - copylen > 0)) {
774 sock->lastdata = buf;
775 sock->lastoffset += copylen;
776 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
778 sock->lastdata = NULL;
779 sock->lastoffset = 0;
780 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
781 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
782 pbuf_free((struct pbuf *)buf);
784 netbuf_delete((struct netbuf *)buf);
790 if ((off > 0) && (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP)) {
791 /* update receive window */
792 netconn_recved(sock->conn, (u32_t)off);
794 sock_set_errno(sock, 0);
799 lwip_read(int s, void *mem, size_t len)
801 return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
805 lwip_recv(int s, void *mem, size_t len, int flags)
807 return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
811 lwip_send(int s, const void *data, size_t size, int flags)
813 struct lwip_sock *sock;
818 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
819 s, data, size, flags));
821 sock = get_socket(s);
826 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
827 #if (LWIP_UDP || LWIP_RAW)
828 return lwip_sendto(s, data, size, flags, NULL, 0);
829 #else /* (LWIP_UDP || LWIP_RAW) */
830 sock_set_errno(sock, err_to_errno(ERR_ARG));
832 #endif /* (LWIP_UDP || LWIP_RAW) */
835 write_flags = NETCONN_COPY |
836 ((flags & MSG_MORE) ? NETCONN_MORE : 0) |
837 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
839 err = netconn_write_partly(sock->conn, data, size, write_flags, &written);
841 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written));
842 sock_set_errno(sock, err_to_errno(err));
843 return (err == ERR_OK ? (int)written : -1);
847 lwip_sendto(int s, const void *data, size_t size, int flags,
848 const struct sockaddr *to, socklen_t tolen)
850 struct lwip_sock *sock;
854 #if !LWIP_TCPIP_CORE_LOCKING
858 sock = get_socket(s);
863 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
865 return lwip_send(s, data, size, flags);
867 LWIP_UNUSED_ARG(flags);
868 sock_set_errno(sock, err_to_errno(ERR_ARG));
870 #endif /* LWIP_TCP */
873 if ((to != NULL) && !SOCK_ADDR_TYPE_MATCH(to, sock)) {
874 /* sockaddr does not match socket type (IPv4/IPv6) */
875 sock_set_errno(sock, err_to_errno(ERR_VAL));
879 /* @todo: split into multiple sendto's? */
880 LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
881 short_size = (u16_t)size;
882 LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
883 (IS_SOCK_ADDR_LEN_VALID(tolen) &&
884 IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))),
885 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
886 LWIP_UNUSED_ARG(tolen);
888 #if LWIP_TCPIP_CORE_LOCKING
889 /* Special speedup for fast UDP/RAW sending: call the raw API directly
890 instead of using the netconn functions. */
893 ipX_addr_t *remote_addr;
894 ipX_addr_t remote_addr_tmp;
896 #if LWIP_NETIF_TX_SINGLE_PBUF
897 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM);
899 #if LWIP_CHECKSUM_ON_COPY
901 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
902 chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size);
904 #endif /* LWIP_CHECKSUM_ON_COPY */
905 MEMCPY(p->payload, data, size);
906 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
907 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF);
909 p->payload = (void*)data;
910 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
913 SOCKADDR_TO_IPXADDR_PORT(to->sa_family == AF_INET6,
914 to, &remote_addr_tmp, remote_port);
915 remote_addr = &remote_addr_tmp;
917 remote_addr = &sock->conn->pcb.raw->remote_ip;
918 if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_RAW) {
921 remote_port = sock->conn->pcb.udp->remote_port;
926 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_RAW) {
927 err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, ipX_2_ip(remote_addr));
930 #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF
931 err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,
932 ipX_2_ip(remote_addr), remote_port, 1, chksum);
933 #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
934 err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p,
935 ipX_2_ip(remote_addr), remote_port);
936 #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
939 #endif /* LWIP_UDP */
948 #else /* LWIP_TCPIP_CORE_LOCKING */
949 /* initialize a buffer */
950 buf.p = buf.ptr = NULL;
951 #if LWIP_CHECKSUM_ON_COPY
953 #endif /* LWIP_CHECKSUM_ON_COPY */
955 SOCKADDR_TO_IPXADDR_PORT((to->sa_family) == AF_INET6, to, &buf.addr, remote_port);
958 ipX_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr);
960 netbuf_fromport(&buf) = remote_port;
963 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
964 s, data, short_size, flags));
965 ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
966 SOCKETS_DEBUG, &buf.addr);
967 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
969 /* make the buffer point to the data that should be sent */
970 #if LWIP_NETIF_TX_SINGLE_PBUF
971 /* Allocate a new netbuf and copy the data into it. */
972 if (netbuf_alloc(&buf, short_size) == NULL) {
975 #if LWIP_CHECKSUM_ON_COPY
976 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
977 u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
978 netbuf_set_chksum(&buf, chksum);
981 #endif /* LWIP_CHECKSUM_ON_COPY */
983 err = netbuf_take(&buf, data, short_size);
986 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
987 err = netbuf_ref(&buf, data, short_size);
988 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
991 err = netconn_send(sock->conn, &buf);
994 /* deallocated the buffer */
996 #endif /* LWIP_TCPIP_CORE_LOCKING */
997 sock_set_errno(sock, err_to_errno(err));
998 return (err == ERR_OK ? short_size : -1);
1002 lwip_socket(int domain, int type, int protocol)
1004 struct netconn *conn;
1008 LWIP_UNUSED_ARG(domain); /* @todo: check this */
1009 #endif /* LWIP_IPV6 */
1011 /* create a netconn */
1014 conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW),
1015 (u8_t)protocol, event_callback);
1016 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
1017 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1020 conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain,
1021 ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) ,
1023 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
1024 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1027 conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), event_callback);
1028 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
1029 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1031 /* Prevent automatic window updates, we do this on our own! */
1032 netconn_set_noautorecved(conn, 1);
1036 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
1037 domain, type, protocol));
1043 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
1048 i = alloc_socket(conn, 0);
1051 netconn_delete(conn);
1056 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
1062 lwip_write(int s, const void *data, size_t size)
1064 return lwip_send(s, data, size, 0);
1068 * Go through the readset and writeset lists and see which socket of the sockets
1069 * set in the sets has events. On return, readset, writeset and exceptset have
1070 * the sockets enabled that had events.
1072 * exceptset is not used for now!!!
1074 * @param maxfdp1 the highest socket index in the sets
1075 * @param readset_in: set of sockets to check for read events
1076 * @param writeset_in: set of sockets to check for write events
1077 * @param exceptset_in: set of sockets to check for error events
1078 * @param readset_out: set of sockets that had read events
1079 * @param writeset_out: set of sockets that had write events
1080 * @param exceptset_out: set os sockets that had error events
1081 * @return number of sockets that had events (read/write/exception) (>= 0)
1084 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
1085 fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
1088 fd_set lreadset, lwriteset, lexceptset;
1089 struct lwip_sock *sock;
1090 SYS_ARCH_DECL_PROTECT(lev);
1093 FD_ZERO(&lwriteset);
1094 FD_ZERO(&lexceptset);
1096 /* Go through each socket in each list to count number of sockets which
1098 for(i = 0; i < maxfdp1; i++) {
1099 void* lastdata = NULL;
1101 u16_t sendevent = 0;
1103 /* First get the socket's status (protected)... */
1104 SYS_ARCH_PROTECT(lev);
1105 sock = tryget_socket(i);
1107 lastdata = sock->lastdata;
1108 rcvevent = sock->rcvevent;
1109 sendevent = sock->sendevent;
1110 errevent = sock->errevent;
1112 SYS_ARCH_UNPROTECT(lev);
1113 /* ... then examine it: */
1114 /* See if netconn of this socket is ready for read */
1115 if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
1116 FD_SET(i, &lreadset);
1117 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
1120 /* See if netconn of this socket is ready for write */
1121 if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
1122 FD_SET(i, &lwriteset);
1123 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
1126 /* See if netconn of this socket had an error */
1127 if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
1128 FD_SET(i, &lexceptset);
1129 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
1133 /* copy local sets to the ones provided as arguments */
1134 *readset_out = lreadset;
1135 *writeset_out = lwriteset;
1136 *exceptset_out = lexceptset;
1138 LWIP_ASSERT("nready >= 0", nready >= 0);
1143 * Processing exceptset is not yet implemented.
1146 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
1147 struct timeval *timeout)
1151 fd_set lreadset, lwriteset, lexceptset;
1153 struct lwip_select_cb select_cb;
1156 SYS_ARCH_DECL_PROTECT(lev);
1158 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
1159 maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
1160 timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
1161 timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
1163 /* Go through each socket in each list to count number of sockets which
1165 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1167 /* If we don't have any current events, then suspend if we are supposed to */
1169 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
1170 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
1171 /* This is OK as the local fdsets are empty and nready is zero,
1172 or we would have returned earlier. */
1173 goto return_copy_fdsets;
1176 /* None ready: add our semaphore to list:
1177 We don't actually need any dynamic memory. Our entry on the
1178 list is only valid while we are in this function, so it's ok
1179 to use local variables. */
1181 select_cb.next = NULL;
1182 select_cb.prev = NULL;
1183 select_cb.readset = readset;
1184 select_cb.writeset = writeset;
1185 select_cb.exceptset = exceptset;
1186 select_cb.sem_signalled = 0;
1187 err = sys_sem_new(&select_cb.sem, 0);
1188 if (err != ERR_OK) {
1189 /* failed to create semaphore */
1194 /* Protect the select_cb_list */
1195 SYS_ARCH_PROTECT(lev);
1197 /* Put this select_cb on top of list */
1198 select_cb.next = select_cb_list;
1199 if (select_cb_list != NULL) {
1200 select_cb_list->prev = &select_cb;
1202 select_cb_list = &select_cb;
1203 /* Increasing this counter tells even_callback that the list has changed. */
1206 /* Now we can safely unprotect */
1207 SYS_ARCH_UNPROTECT(lev);
1209 /* Increase select_waiting for each socket we are interested in */
1210 for(i = 0; i < maxfdp1; i++) {
1211 if ((readset && FD_ISSET(i, readset)) ||
1212 (writeset && FD_ISSET(i, writeset)) ||
1213 (exceptset && FD_ISSET(i, exceptset))) {
1214 struct lwip_sock *sock = tryget_socket(i);
1215 LWIP_ASSERT("sock != NULL", sock != NULL);
1216 SYS_ARCH_PROTECT(lev);
1217 sock->select_waiting++;
1218 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
1219 SYS_ARCH_UNPROTECT(lev);
1223 /* Call lwip_selscan again: there could have been events between
1224 the last scan (whithout us on the list) and putting us on the list! */
1225 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1227 /* Still none ready, just wait to be woken */
1232 msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
1233 if (msectimeout == 0) {
1234 /* Wait 1ms at least (0 means wait forever) */
1239 waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
1241 /* Increase select_waiting for each socket we are interested in */
1242 for(i = 0; i < maxfdp1; i++) {
1243 if ((readset && FD_ISSET(i, readset)) ||
1244 (writeset && FD_ISSET(i, writeset)) ||
1245 (exceptset && FD_ISSET(i, exceptset))) {
1246 struct lwip_sock *sock = tryget_socket(i);
1247 LWIP_ASSERT("sock != NULL", sock != NULL);
1248 SYS_ARCH_PROTECT(lev);
1249 sock->select_waiting--;
1250 LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0);
1251 SYS_ARCH_UNPROTECT(lev);
1254 /* Take us off the list */
1255 SYS_ARCH_PROTECT(lev);
1256 if (select_cb.next != NULL) {
1257 select_cb.next->prev = select_cb.prev;
1259 if (select_cb_list == &select_cb) {
1260 LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
1261 select_cb_list = select_cb.next;
1263 LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
1264 select_cb.prev->next = select_cb.next;
1266 /* Increasing this counter tells even_callback that the list has changed. */
1268 SYS_ARCH_UNPROTECT(lev);
1270 sys_sem_free(&select_cb.sem);
1271 if (waitres == SYS_ARCH_TIMEOUT) {
1273 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
1274 /* This is OK as the local fdsets are empty and nready is zero,
1275 or we would have returned earlier. */
1276 goto return_copy_fdsets;
1279 /* See what's set */
1280 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1283 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
1287 *readset = lreadset;
1290 *writeset = lwriteset;
1293 *exceptset = lexceptset;
1299 * Callback registered in the netconn layer for each socket-netconn.
1300 * Processes recvevent (data available) and wakes up tasks waiting for select.
1303 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
1306 struct lwip_sock *sock;
1307 struct lwip_select_cb *scb;
1308 int last_select_cb_ctr;
1309 SYS_ARCH_DECL_PROTECT(lev);
1311 LWIP_UNUSED_ARG(len);
1317 /* Data comes in right away after an accept, even though
1318 * the server task might not have created a new socket yet.
1319 * Just count down (or up) if that's the case and we
1320 * will use the data later. Note that only receive events
1321 * can happen before the new socket is set up. */
1322 SYS_ARCH_PROTECT(lev);
1323 if (conn->socket < 0) {
1324 if (evt == NETCONN_EVT_RCVPLUS) {
1327 SYS_ARCH_UNPROTECT(lev);
1331 SYS_ARCH_UNPROTECT(lev);
1334 sock = get_socket(s);
1342 SYS_ARCH_PROTECT(lev);
1343 /* Set event as required */
1345 case NETCONN_EVT_RCVPLUS:
1348 case NETCONN_EVT_RCVMINUS:
1351 case NETCONN_EVT_SENDPLUS:
1352 sock->sendevent = 1;
1354 case NETCONN_EVT_SENDMINUS:
1355 sock->sendevent = 0;
1357 case NETCONN_EVT_ERROR:
1361 LWIP_ASSERT("unknown event", 0);
1365 if (sock->select_waiting == 0) {
1366 /* noone is waiting for this socket, no need to check select_cb_list */
1367 SYS_ARCH_UNPROTECT(lev);
1371 /* Now decide if anyone is waiting for this socket */
1372 /* NOTE: This code goes through the select_cb_list list multiple times
1373 ONLY IF a select was actually waiting. We go through the list the number
1374 of waiting select calls + 1. This list is expected to be small. */
1376 /* At this point, SYS_ARCH is still protected! */
1378 for (scb = select_cb_list; scb != NULL; scb = scb->next) {
1379 if (scb->sem_signalled == 0) {
1380 /* semaphore not signalled yet */
1382 /* Test this select call for our socket */
1383 if (sock->rcvevent > 0) {
1384 if (scb->readset && FD_ISSET(s, scb->readset)) {
1388 if (sock->sendevent != 0) {
1389 if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
1393 if (sock->errevent != 0) {
1394 if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
1399 scb->sem_signalled = 1;
1400 /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
1401 lead to the select thread taking itself off the list, invalidagin the semaphore. */
1402 sys_sem_signal(&scb->sem);
1405 /* unlock interrupts with each step */
1406 last_select_cb_ctr = select_cb_ctr;
1407 SYS_ARCH_UNPROTECT(lev);
1408 /* this makes sure interrupt protection time is short */
1409 SYS_ARCH_PROTECT(lev);
1410 if (last_select_cb_ctr != select_cb_ctr) {
1411 /* someone has changed select_cb_list, restart at the beginning */
1415 SYS_ARCH_UNPROTECT(lev);
1419 * Unimplemented: Close one end of a full-duplex connection.
1420 * Currently, the full connection is closed.
1423 lwip_shutdown(int s, int how)
1425 struct lwip_sock *sock;
1427 u8_t shut_rx = 0, shut_tx = 0;
1429 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
1431 sock = get_socket(s);
1436 if (sock->conn != NULL) {
1437 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
1438 sock_set_errno(sock, EOPNOTSUPP);
1442 sock_set_errno(sock, ENOTCONN);
1446 if (how == SHUT_RD) {
1448 } else if (how == SHUT_WR) {
1450 } else if(how == SHUT_RDWR) {
1454 sock_set_errno(sock, EINVAL);
1457 err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
1459 sock_set_errno(sock, err_to_errno(err));
1460 return (err == ERR_OK ? 0 : -1);
1464 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
1466 struct lwip_sock *sock;
1467 union sockaddr_aligned saddr;
1471 sock = get_socket(s);
1476 /* get the IP address and port */
1477 /* @todo: this does not work for IPv6, yet */
1478 netconn_getaddr(sock->conn, ipX_2_ip(&naddr), &port, local);
1479 IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
1480 &saddr, &naddr, port);
1482 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
1483 ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
1484 SOCKETS_DEBUG, &naddr);
1485 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port));
1487 if (*namelen > saddr.sa.sa_len) {
1488 *namelen = saddr.sa.sa_len;
1490 MEMCPY(name, &saddr, *namelen);
1492 sock_set_errno(sock, 0);
1497 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
1499 return lwip_getaddrname(s, name, namelen, 0);
1503 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
1505 return lwip_getaddrname(s, name, namelen, 1);
1509 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
1512 struct lwip_sock *sock = get_socket(s);
1513 struct lwip_setgetsockopt_data data;
1519 if ((NULL == optval) || (NULL == optlen)) {
1520 sock_set_errno(sock, EFAULT);
1524 /* Do length and type checks for the various options first, to keep it readable. */
1527 /* Level: SOL_SOCKET */
1533 /* UNIMPL case SO_DEBUG: */
1534 /* UNIMPL case SO_DONTROUTE: */
1537 /* UNIMPL case SO_CONTIMEO: */
1538 /* UNIMPL case SO_SNDTIMEO: */
1539 #if LWIP_SO_RCVTIMEO
1541 #endif /* LWIP_SO_RCVTIMEO */
1544 #endif /* LWIP_SO_RCVBUF */
1545 /* UNIMPL case SO_OOBINLINE: */
1546 /* UNIMPL case SO_SNDBUF: */
1547 /* UNIMPL case SO_RCVLOWAT: */
1548 /* UNIMPL case SO_SNDLOWAT: */
1552 #endif /* SO_REUSE */
1554 /* UNIMPL case SO_USELOOPBACK: */
1555 if (*optlen < sizeof(int)) {
1561 if (*optlen < sizeof(int)) {
1565 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP ||
1566 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1567 /* this flag is only available for UDP, not for UDP lite */
1570 #endif /* LWIP_UDP */
1574 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1577 } /* switch (optname) */
1580 /* Level: IPPROTO_IP */
1583 /* UNIMPL case IP_HDRINCL: */
1584 /* UNIMPL case IP_RCVDSTADDR: */
1585 /* UNIMPL case IP_RCVIF: */
1588 if (*optlen < sizeof(int)) {
1593 case IP_MULTICAST_TTL:
1594 if (*optlen < sizeof(u8_t)) {
1598 case IP_MULTICAST_IF:
1599 if (*optlen < sizeof(struct in_addr)) {
1603 case IP_MULTICAST_LOOP:
1604 if (*optlen < sizeof(u8_t)) {
1607 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
1611 #endif /* LWIP_IGMP */
1614 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1617 } /* switch (optname) */
1621 /* Level: IPPROTO_TCP */
1623 if (*optlen < sizeof(int)) {
1628 /* If this is no TCP socket, ignore any options. */
1629 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP)
1635 #if LWIP_TCP_KEEPALIVE
1639 #endif /* LWIP_TCP_KEEPALIVE */
1643 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
1646 } /* switch (optname) */
1648 #endif /* LWIP_TCP */
1649 #if LWIP_UDP && LWIP_UDPLITE
1650 /* Level: IPPROTO_UDPLITE */
1651 case IPPROTO_UDPLITE:
1652 if (*optlen < sizeof(int)) {
1657 /* If this is no UDP lite socket, ignore any options. */
1658 if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
1663 case UDPLITE_SEND_CSCOV:
1664 case UDPLITE_RECV_CSCOV:
1668 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
1671 } /* switch (optname) */
1673 #endif /* LWIP_UDP && LWIP_UDPLITE*/
1674 /* UNDEFINED LEVEL */
1676 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
1677 s, level, optname));
1682 if (err != ERR_OK) {
1683 sock_set_errno(sock, err);
1687 /* Now do the actual option processing */
1691 #endif /* LWIP_DEBUG */
1693 data.optname = optname;
1694 data.optval = optval;
1695 data.optlen = optlen;
1697 tcpip_callback(lwip_getsockopt_internal, &data);
1698 sys_arch_sem_wait(&sock->conn->op_completed, 0);
1699 /* maybe lwip_getsockopt_internal has changed err */
1702 sock_set_errno(sock, err);
1703 return err ? -1 : 0;
1707 lwip_getsockopt_internal(void *arg)
1709 struct lwip_sock *sock;
1712 #endif /* LWIP_DEBUG */
1715 struct lwip_setgetsockopt_data *data;
1717 LWIP_ASSERT("arg != NULL", arg != NULL);
1719 data = (struct lwip_setgetsockopt_data*)arg;
1723 #endif /* LWIP_DEBUG */
1724 level = data->level;
1725 optname = data->optname;
1726 optval = data->optval;
1730 /* Level: SOL_SOCKET */
1734 /* The option flags */
1737 /* UNIMPL case SO_DEBUG: */
1738 /* UNIMPL case SO_DONTROUTE: */
1740 /* UNIMPL case SO_OOBINCLUDE: */
1744 #endif /* SO_REUSE */
1745 /*case SO_USELOOPBACK: UNIMPL */
1746 *(int*)optval = sock->conn->pcb.ip->so_options & optname;
1747 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
1748 s, optname, (*(int*)optval?"on":"off")));
1752 switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) {
1754 *(int*)optval = SOCK_RAW;
1757 *(int*)optval = SOCK_STREAM;
1760 *(int*)optval = SOCK_DGRAM;
1762 default: /* unrecognized socket type */
1763 *(int*)optval = netconn_type(sock->conn);
1764 LWIP_DEBUGF(SOCKETS_DEBUG,
1765 ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
1766 s, *(int *)optval));
1767 } /* switch (netconn_type(sock->conn)) */
1768 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
1769 s, *(int *)optval));
1773 /* only overwrite ERR_OK or tempoary errors */
1774 if ((sock->err == 0) || (sock->err == EINPROGRESS)) {
1775 sock_set_errno(sock, err_to_errno(sock->conn->last_err));
1777 *(int *)optval = sock->err;
1779 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
1780 s, *(int *)optval));
1783 #if LWIP_SO_RCVTIMEO
1785 *(int *)optval = netconn_get_recvtimeout(sock->conn);
1787 #endif /* LWIP_SO_RCVTIMEO */
1790 *(int *)optval = netconn_get_recvbufsize(sock->conn);
1792 #endif /* LWIP_SO_RCVBUF */
1795 *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
1797 #endif /* LWIP_UDP*/
1799 LWIP_ASSERT("unhandled optname", 0);
1801 } /* switch (optname) */
1804 /* Level: IPPROTO_IP */
1808 *(int*)optval = sock->conn->pcb.ip->ttl;
1809 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
1810 s, *(int *)optval));
1813 *(int*)optval = sock->conn->pcb.ip->tos;
1814 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
1815 s, *(int *)optval));
1818 case IP_MULTICAST_TTL:
1819 *(u8_t*)optval = sock->conn->pcb.ip->ttl;
1820 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
1821 s, *(int *)optval));
1823 case IP_MULTICAST_IF:
1824 inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip);
1825 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
1826 s, *(u32_t *)optval));
1828 case IP_MULTICAST_LOOP:
1829 if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
1834 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
1835 s, *(int *)optval));
1837 #endif /* LWIP_IGMP */
1839 LWIP_ASSERT("unhandled optname", 0);
1841 } /* switch (optname) */
1845 /* Level: IPPROTO_TCP */
1849 *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
1850 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
1851 s, (*(int*)optval)?"on":"off") );
1854 *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
1855 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",
1856 s, *(int *)optval));
1859 #if LWIP_TCP_KEEPALIVE
1861 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
1862 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",
1863 s, *(int *)optval));
1866 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
1867 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",
1868 s, *(int *)optval));
1871 *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
1872 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",
1873 s, *(int *)optval));
1875 #endif /* LWIP_TCP_KEEPALIVE */
1877 LWIP_ASSERT("unhandled optname", 0);
1879 } /* switch (optname) */
1881 #endif /* LWIP_TCP */
1882 #if LWIP_UDP && LWIP_UDPLITE
1883 /* Level: IPPROTO_UDPLITE */
1884 case IPPROTO_UDPLITE:
1886 case UDPLITE_SEND_CSCOV:
1887 *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
1888 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
1889 s, (*(int*)optval)) );
1891 case UDPLITE_RECV_CSCOV:
1892 *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
1893 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
1894 s, (*(int*)optval)) );
1897 LWIP_ASSERT("unhandled optname", 0);
1899 } /* switch (optname) */
1901 #endif /* LWIP_UDP */
1903 LWIP_ASSERT("unhandled level", 0);
1905 } /* switch (level) */
1906 sys_sem_signal(&sock->conn->op_completed);
1910 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
1912 struct lwip_sock *sock = get_socket(s);
1914 struct lwip_setgetsockopt_data data;
1920 if (NULL == optval) {
1921 sock_set_errno(sock, EFAULT);
1925 /* Do length and type checks for the various options first, to keep it readable. */
1928 /* Level: SOL_SOCKET */
1933 /* UNIMPL case SO_DEBUG: */
1934 /* UNIMPL case SO_DONTROUTE: */
1936 /* UNIMPL case case SO_CONTIMEO: */
1937 /* UNIMPL case case SO_SNDTIMEO: */
1938 #if LWIP_SO_RCVTIMEO
1940 #endif /* LWIP_SO_RCVTIMEO */
1943 #endif /* LWIP_SO_RCVBUF */
1944 /* UNIMPL case SO_OOBINLINE: */
1945 /* UNIMPL case SO_SNDBUF: */
1946 /* UNIMPL case SO_RCVLOWAT: */
1947 /* UNIMPL case SO_SNDLOWAT: */
1951 #endif /* SO_REUSE */
1952 /* UNIMPL case SO_USELOOPBACK: */
1953 if (optlen < sizeof(int)) {
1958 if (optlen < sizeof(int)) {
1962 if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) ||
1963 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1964 /* this flag is only available for UDP, not for UDP lite */
1967 #endif /* LWIP_UDP */
1970 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1973 } /* switch (optname) */
1976 /* Level: IPPROTO_IP */
1979 /* UNIMPL case IP_HDRINCL: */
1980 /* UNIMPL case IP_RCVDSTADDR: */
1981 /* UNIMPL case IP_RCVIF: */
1984 if (optlen < sizeof(int)) {
1989 case IP_MULTICAST_TTL:
1990 if (optlen < sizeof(u8_t)) {
1993 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
1997 case IP_MULTICAST_IF:
1998 if (optlen < sizeof(struct in_addr)) {
2001 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2005 case IP_MULTICAST_LOOP:
2006 if (optlen < sizeof(u8_t)) {
2009 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2013 case IP_ADD_MEMBERSHIP:
2014 case IP_DROP_MEMBERSHIP:
2015 if (optlen < sizeof(struct ip_mreq)) {
2018 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2022 #endif /* LWIP_IGMP */
2024 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
2027 } /* switch (optname) */
2031 /* Level: IPPROTO_TCP */
2033 if (optlen < sizeof(int)) {
2038 /* If this is no TCP socket, ignore any options. */
2039 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP)
2045 #if LWIP_TCP_KEEPALIVE
2049 #endif /* LWIP_TCP_KEEPALIVE */
2053 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
2056 } /* switch (optname) */
2058 #endif /* LWIP_TCP */
2059 #if LWIP_UDP && LWIP_UDPLITE
2060 /* Level: IPPROTO_UDPLITE */
2061 case IPPROTO_UDPLITE:
2062 if (optlen < sizeof(int)) {
2067 /* If this is no UDP lite socket, ignore any options. */
2068 if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn)))
2072 case UDPLITE_SEND_CSCOV:
2073 case UDPLITE_RECV_CSCOV:
2077 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
2080 } /* switch (optname) */
2082 #endif /* LWIP_UDP && LWIP_UDPLITE */
2083 /* UNDEFINED LEVEL */
2085 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2086 s, level, optname));
2088 } /* switch (level) */
2091 if (err != ERR_OK) {
2092 sock_set_errno(sock, err);
2097 /* Now do the actual option processing */
2101 #endif /* LWIP_DEBUG */
2103 data.optname = optname;
2104 data.optval = (void*)optval;
2105 data.optlen = &optlen;
2107 tcpip_callback(lwip_setsockopt_internal, &data);
2108 sys_arch_sem_wait(&sock->conn->op_completed, 0);
2109 /* maybe lwip_setsockopt_internal has changed err */
2112 sock_set_errno(sock, err);
2113 return err ? -1 : 0;
2117 lwip_setsockopt_internal(void *arg)
2119 struct lwip_sock *sock;
2122 #endif /* LWIP_DEBUG */
2125 struct lwip_setgetsockopt_data *data;
2127 LWIP_ASSERT("arg != NULL", arg != NULL);
2129 data = (struct lwip_setgetsockopt_data*)arg;
2133 #endif /* LWIP_DEBUG */
2134 level = data->level;
2135 optname = data->optname;
2136 optval = data->optval;
2140 /* Level: SOL_SOCKET */
2144 /* The option flags */
2146 /* UNIMPL case SO_DEBUG: */
2147 /* UNIMPL case SO_DONTROUTE: */
2149 /* UNIMPL case SO_OOBINCLUDE: */
2153 #endif /* SO_REUSE */
2154 /* UNIMPL case SO_USELOOPBACK: */
2155 if (*(int*)optval) {
2156 sock->conn->pcb.ip->so_options |= optname;
2158 sock->conn->pcb.ip->so_options &= ~optname;
2160 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
2161 s, optname, (*(int*)optval?"on":"off")));
2163 #if LWIP_SO_RCVTIMEO
2165 netconn_set_recvtimeout(sock->conn, *(int*)optval);
2167 #endif /* LWIP_SO_RCVTIMEO */
2170 netconn_set_recvbufsize(sock->conn, *(int*)optval);
2172 #endif /* LWIP_SO_RCVBUF */
2175 if (*(int*)optval) {
2176 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
2178 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
2181 #endif /* LWIP_UDP */
2183 LWIP_ASSERT("unhandled optname", 0);
2185 } /* switch (optname) */
2188 /* Level: IPPROTO_IP */
2192 sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
2193 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
2194 s, sock->conn->pcb.ip->ttl));
2197 sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
2198 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
2199 s, sock->conn->pcb.ip->tos));
2202 case IP_MULTICAST_TTL:
2203 sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);
2205 case IP_MULTICAST_IF:
2206 inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval);
2208 case IP_MULTICAST_LOOP:
2209 if (*(u8_t*)optval) {
2210 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
2212 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
2215 case IP_ADD_MEMBERSHIP:
2216 case IP_DROP_MEMBERSHIP:
2218 /* If this is a TCP or a RAW socket, ignore these options. */
2219 struct ip_mreq *imr = (struct ip_mreq *)optval;
2221 ip_addr_t multi_addr;
2222 inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
2223 inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
2224 if(optname == IP_ADD_MEMBERSHIP){
2225 data->err = igmp_joingroup(&if_addr, &multi_addr);
2227 data->err = igmp_leavegroup(&if_addr, &multi_addr);
2229 if(data->err != ERR_OK) {
2230 data->err = EADDRNOTAVAIL;
2234 #endif /* LWIP_IGMP */
2236 LWIP_ASSERT("unhandled optname", 0);
2238 } /* switch (optname) */
2242 /* Level: IPPROTO_TCP */
2246 if (*(int*)optval) {
2247 tcp_nagle_disable(sock->conn->pcb.tcp);
2249 tcp_nagle_enable(sock->conn->pcb.tcp);
2251 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
2252 s, (*(int *)optval)?"on":"off") );
2255 sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
2256 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
2257 s, sock->conn->pcb.tcp->keep_idle));
2260 #if LWIP_TCP_KEEPALIVE
2262 sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
2263 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
2264 s, sock->conn->pcb.tcp->keep_idle));
2267 sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
2268 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
2269 s, sock->conn->pcb.tcp->keep_intvl));
2272 sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
2273 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
2274 s, sock->conn->pcb.tcp->keep_cnt));
2276 #endif /* LWIP_TCP_KEEPALIVE */
2278 LWIP_ASSERT("unhandled optname", 0);
2280 } /* switch (optname) */
2282 #endif /* LWIP_TCP*/
2283 #if LWIP_UDP && LWIP_UDPLITE
2284 /* Level: IPPROTO_UDPLITE */
2285 case IPPROTO_UDPLITE:
2287 case UDPLITE_SEND_CSCOV:
2288 if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
2289 /* don't allow illegal values! */
2290 sock->conn->pcb.udp->chksum_len_tx = 8;
2292 sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;
2294 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
2295 s, (*(int*)optval)) );
2297 case UDPLITE_RECV_CSCOV:
2298 if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
2299 /* don't allow illegal values! */
2300 sock->conn->pcb.udp->chksum_len_rx = 8;
2302 sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;
2304 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
2305 s, (*(int*)optval)) );
2308 LWIP_ASSERT("unhandled optname", 0);
2310 } /* switch (optname) */
2312 #endif /* LWIP_UDP */
2314 LWIP_ASSERT("unhandled level", 0);
2316 } /* switch (level) */
2317 sys_sem_signal(&sock->conn->op_completed);
2321 lwip_ioctl(int s, long cmd, void *argp)
2323 struct lwip_sock *sock = get_socket(s);
2328 #endif /* LWIP_SO_RCVBUF */
2335 #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE
2338 sock_set_errno(sock, EINVAL);
2341 #if LWIP_FIONREAD_LINUXMODE
2342 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
2344 if (sock->lastdata) {
2345 p = ((struct netbuf *)sock->lastdata)->p;
2347 struct netbuf *rxbuf;
2349 if (sock->rcvevent <= 0) {
2350 *((u16_t*)argp) = 0;
2352 err = netconn_recv(sock->conn, &rxbuf);
2353 if (err != ERR_OK) {
2354 *((u16_t*)argp) = 0;
2356 sock->lastdata = rxbuf;
2357 *((u16_t*)argp) = rxbuf->p->tot_len;
2363 #endif /* LWIP_FIONREAD_LINUXMODE */
2366 /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */
2367 SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
2368 if (recv_avail < 0) {
2371 *((u16_t*)argp) = (u16_t)recv_avail;
2373 /* Check if there is data left from the last recv operation. /maq 041215 */
2374 if (sock->lastdata) {
2375 struct pbuf *p = (struct pbuf *)sock->lastdata;
2376 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
2377 p = ((struct netbuf *)p)->p;
2379 buflen = p->tot_len;
2380 buflen -= sock->lastoffset;
2382 *((u16_t*)argp) += buflen;
2385 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
2386 sock_set_errno(sock, 0);
2388 #else /* LWIP_SO_RCVBUF */
2390 #endif /* LWIP_SO_RCVBUF */
2391 #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */
2395 if (argp && *(u32_t*)argp) {
2398 netconn_set_nonblocking(sock->conn, val);
2399 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
2400 sock_set_errno(sock, 0);
2405 } /* switch (cmd) */
2406 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
2407 sock_set_errno(sock, ENOSYS); /* not yet implemented */
2411 /** A minimal implementation of fcntl.
2412 * Currently only the commands F_GETFL and F_SETFL are implemented.
2413 * Only the flag O_NONBLOCK is implemented.
2416 lwip_fcntl(int s, int cmd, int val)
2418 struct lwip_sock *sock = get_socket(s);
2421 if (!sock || !sock->conn) {
2427 ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
2430 if ((val & ~O_NONBLOCK) == 0) {
2431 /* only O_NONBLOCK, all other bits are zero */
2432 netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
2437 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
2443 #endif /* LWIP_SOCKET */