3 * Sockets BSD-Like API module
5 * @defgroup socket Socket API
6 * @ingroup sequential_api
7 * BSD-style socket API.\n
8 * Thread-safe, to be called from non-TCPIP threads only.\n
9 * Can be activated by defining @ref LWIP_SOCKET to 1.\n
10 * Header is in posix/sys/socket.h\b
14 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
15 * All rights reserved.
17 * Redistribution and use in source and binary forms, with or without modification,
18 * are permitted provided that the following conditions are met:
20 * 1. Redistributions of source code must retain the above copyright notice,
21 * this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright notice,
23 * this list of conditions and the following disclaimer in the documentation
24 * and/or other materials provided with the distribution.
25 * 3. The name of the author may not be used to endorse or promote products
26 * derived from this software without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
31 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
33 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
36 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
39 * This file is part of the lwIP TCP/IP stack.
41 * Author: Adam Dunkels <adam@sics.se>
43 * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
49 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
51 #include "lwip/sockets.h"
54 #include "lwip/igmp.h"
55 #include "lwip/inet.h"
59 #include "lwip/memp.h"
60 #include "lwip/pbuf.h"
61 #include "lwip/priv/tcpip_priv.h"
62 #if LWIP_CHECKSUM_ON_COPY
63 #include "lwip/inet_chksum.h"
68 /* If the netconn API is not required publicly, then we include the necessary
69 files here to get the implementation */
72 #define LWIP_NETCONN 1
77 #define LWIP_NETCONN 0
81 #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \
82 (sin)->sin_len = sizeof(struct sockaddr_in); \
83 (sin)->sin_family = AF_INET; \
84 (sin)->sin_port = lwip_htons((port)); \
85 inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \
86 memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0)
87 #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \
88 inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \
89 (port) = lwip_ntohs((sin)->sin_port); }while(0)
90 #endif /* LWIP_IPV4 */
93 #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \
94 (sin6)->sin6_len = sizeof(struct sockaddr_in6); \
95 (sin6)->sin6_family = AF_INET6; \
96 (sin6)->sin6_port = lwip_htons((port)); \
97 (sin6)->sin6_flowinfo = 0; \
98 inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \
99 (sin6)->sin6_scope_id = 0; }while(0)
100 #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \
101 inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \
102 (port) = lwip_ntohs((sin6)->sin6_port); }while(0)
103 #endif /* LWIP_IPV6 */
105 #if LWIP_IPV4 && LWIP_IPV6
106 static void sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* ipaddr, u16_t* port);
108 #define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \
109 ((namelen) == sizeof(struct sockaddr_in6)))
110 #define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \
111 ((name)->sa_family == AF_INET6))
112 #define SOCK_ADDR_TYPE_MATCH(name, sock) \
113 ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \
114 (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type))))
115 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \
116 if (IP_IS_V6(ipaddr)) { \
117 IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \
119 IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \
121 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port))
122 #define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \
123 (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6))
124 #elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */
125 #define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in6))
126 #define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET6)
127 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
128 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
129 IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port)
130 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
131 SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port)
132 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
133 #else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */
134 #define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in))
135 #define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET)
136 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
137 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
138 IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port)
139 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
140 SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port)
141 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
142 #endif /* LWIP_IPV6 */
144 #define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \
145 IS_SOCK_ADDR_TYPE_VALID(name))
146 #define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \
147 SOCK_ADDR_TYPE_MATCH(name, sock))
148 #define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0)
151 #define LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype) do { if ((optlen) < sizeof(opttype)) { return EINVAL; }}while(0)
152 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \
153 LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \
154 if ((sock)->conn == NULL) { return EINVAL; } }while(0)
155 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \
156 LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \
157 if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { return EINVAL; } }while(0)
158 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \
159 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \
160 if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { return ENOPROTOOPT; } }while(0)
163 #define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name) API_VAR_REF(name)
164 #define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name)
165 #define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name) API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name)
166 #if LWIP_MPU_COMPATIBLE
167 #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \
168 name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \
169 if (name == NULL) { \
170 sock_set_errno(sock, ENOMEM); \
173 #else /* LWIP_MPU_COMPATIBLE */
174 #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock)
175 #endif /* LWIP_MPU_COMPATIBLE */
177 #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
178 #define LWIP_SO_SNDRCVTIMEO_OPTTYPE int
179 #define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val))
180 #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((s32_t)*(const int*)(optval))
182 #define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval
183 #define LWIP_SO_SNDRCVTIMEO_SET(optval, val) do { \
185 ((struct timeval *)(optval))->tv_sec = (loc) / 1000U; \
186 ((struct timeval *)(optval))->tv_usec = ((loc) % 1000U) * 1000U; }while(0)
187 #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000U) + (((const struct timeval *)(optval))->tv_usec / 1000U))
190 #define NUM_SOCKETS MEMP_NUM_NETCONN
192 /** This is overridable for the rare case where more than 255 threads
193 * select on the same socket...
196 #define SELWAIT_T u8_t
199 /** Contains all internal pointers and states used for a socket */
201 /** sockets currently are built on netconns, each socket has one netconn */
202 struct netconn *conn;
203 /** data that was left from the previous read */
205 /** offset in the data that was left from the previous read */
207 /** number of times data was received, set by event_callback(),
208 tested by the receive and select functions */
210 /** number of times data was ACKed (free send buffer), set by event_callback(),
213 /** error happened for this socket, set by event_callback(), tested by select */
215 /** last error that occurred on this socket (in fact, all our errnos fit into an u8_t) */
217 /** counter of how many threads are waiting for this socket using select */
218 SELWAIT_T select_waiting;
221 #if LWIP_NETCONN_SEM_PER_THREAD
222 #define SELECT_SEM_T sys_sem_t*
223 #define SELECT_SEM_PTR(sem) (sem)
224 #else /* LWIP_NETCONN_SEM_PER_THREAD */
225 #define SELECT_SEM_T sys_sem_t
226 #define SELECT_SEM_PTR(sem) (&(sem))
227 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
229 /** Description for a task waiting in select */
230 struct lwip_select_cb {
231 /** Pointer to the next waiting task */
232 struct lwip_select_cb *next;
233 /** Pointer to the previous waiting task */
234 struct lwip_select_cb *prev;
235 /** readset passed to select */
237 /** writeset passed to select */
239 /** unimplemented: exceptset passed to select */
241 /** don't signal the same semaphore twice: set to 1 when signalled */
243 /** semaphore to wake up a task waiting for select */
247 /** A struct sockaddr replacement that has the same alignment as sockaddr_in/
248 * sockaddr_in6 if instantiated.
250 union sockaddr_aligned {
253 struct sockaddr_in6 sin6;
254 #endif /* LWIP_IPV6 */
256 struct sockaddr_in sin;
257 #endif /* LWIP_IPV4 */
261 /* Define the number of IPv4 multicast memberships, default is one per socket */
262 #ifndef LWIP_SOCKET_MAX_MEMBERSHIPS
263 #define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS
266 /* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when
267 a socket is closed */
268 struct lwip_socket_multicast_pair {
270 struct lwip_sock* sock;
271 /** the interface address */
273 /** the group address */
274 ip4_addr_t multi_addr;
277 struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS];
279 static int lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr);
280 static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr);
281 static void lwip_socket_drop_registered_memberships(int s);
282 #endif /* LWIP_IGMP */
284 /** The global array of available sockets */
285 static struct lwip_sock sockets[NUM_SOCKETS];
286 /** The global list of tasks waiting for select */
287 static struct lwip_select_cb *select_cb_list;
288 /** This counter is increased from lwip_select when the list is changed
289 and checked in event_callback to see if it has changed. */
290 static volatile int select_cb_ctr;
292 #if LWIP_SOCKET_SET_ERRNO
294 #define set_errno(err) do { if (err) { errno = (err); } } while(0)
296 #else /* LWIP_SOCKET_SET_ERRNO */
297 #define set_errno(err)
298 #endif /* LWIP_SOCKET_SET_ERRNO */
300 #define sock_set_errno(sk, e) do { \
301 const int sockerr = (e); \
302 sk->err = (u8_t)sockerr; \
303 set_errno(sockerr); \
306 /* Forward declaration of some functions */
307 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
308 #if !LWIP_TCPIP_CORE_LOCKING
309 static void lwip_getsockopt_callback(void *arg);
310 static void lwip_setsockopt_callback(void *arg);
312 static u8_t lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen);
313 static u8_t lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen);
315 #if LWIP_IPV4 && LWIP_IPV6
317 sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* ipaddr, u16_t* port)
319 if ((sockaddr->sa_family) == AF_INET6) {
320 SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, *port);
321 ipaddr->type = IPADDR_TYPE_V6;
323 SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, *port);
324 ipaddr->type = IPADDR_TYPE_V4;
327 #endif /* LWIP_IPV4 && LWIP_IPV6 */
329 /** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */
331 lwip_socket_thread_init(void)
333 netconn_thread_init();
336 /** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */
338 lwip_socket_thread_cleanup(void)
340 netconn_thread_cleanup();
344 * Map a externally used socket index to the internal socket representation.
346 * @param s externally used socket index
347 * @return struct lwip_sock for the socket or NULL if not found
349 static struct lwip_sock *
352 struct lwip_sock *sock;
354 s -= LWIP_SOCKET_OFFSET;
356 if ((s < 0) || (s >= NUM_SOCKETS)) {
357 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s + LWIP_SOCKET_OFFSET));
365 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s + LWIP_SOCKET_OFFSET));
374 * Same as get_socket but doesn't set errno
376 * @param s externally used socket index
377 * @return struct lwip_sock for the socket or NULL if not found
379 static struct lwip_sock *
382 s -= LWIP_SOCKET_OFFSET;
383 if ((s < 0) || (s >= NUM_SOCKETS)) {
386 if (!sockets[s].conn) {
393 * Allocate a new socket for a given netconn.
395 * @param newconn the netconn for which to allocate a socket
396 * @param accepted 1 if socket has been created by accept(),
397 * 0 if socket has been created by socket()
398 * @return the index of the new socket; -1 on error
401 alloc_socket(struct netconn *newconn, int accepted)
404 SYS_ARCH_DECL_PROTECT(lev);
406 /* allocate a new socket identifier */
407 for (i = 0; i < NUM_SOCKETS; ++i) {
408 /* Protect socket array */
409 SYS_ARCH_PROTECT(lev);
410 if (!sockets[i].conn && (sockets[i].select_waiting == 0)) {
411 sockets[i].conn = newconn;
412 /* The socket is not yet known to anyone, so no need to protect
413 after having marked it as used. */
414 SYS_ARCH_UNPROTECT(lev);
415 sockets[i].lastdata = NULL;
416 sockets[i].lastoffset = 0;
417 sockets[i].rcvevent = 0;
418 /* TCP sendbuf is empty, but the socket is not yet writable until connected
419 * (unless it has been created by accept()). */
420 sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
421 sockets[i].errevent = 0;
423 return i + LWIP_SOCKET_OFFSET;
425 SYS_ARCH_UNPROTECT(lev);
430 /** Free a socket. The socket's netconn must have been
433 * @param sock the socket to free
434 * @param is_tcp != 0 for TCP sockets, used to free lastdata
437 free_socket(struct lwip_sock *sock, int is_tcp)
441 lastdata = sock->lastdata;
442 sock->lastdata = NULL;
443 sock->lastoffset = 0;
446 /* Protect socket array */
447 SYS_ARCH_SET(sock->conn, NULL);
448 /* don't use 'sock' after this line, as another task might have allocated it */
450 if (lastdata != NULL) {
452 pbuf_free((struct pbuf *)lastdata);
454 netbuf_delete((struct netbuf *)lastdata);
459 /* Below this, the well-known socket functions are implemented.
460 * Use google.com or opengroup.org to get a good description :-)
462 * Exceptions are documented!
466 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
468 struct lwip_sock *sock, *nsock;
469 struct netconn *newconn;
474 SYS_ARCH_DECL_PROTECT(lev);
476 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
477 sock = get_socket(s);
482 if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
483 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
484 set_errno(EWOULDBLOCK);
488 /* wait for a new connection */
489 err = netconn_accept(sock->conn, &newconn);
491 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
492 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
493 sock_set_errno(sock, EOPNOTSUPP);
494 } else if (err == ERR_CLSD) {
495 sock_set_errno(sock, EINVAL);
497 sock_set_errno(sock, err_to_errno(err));
501 LWIP_ASSERT("newconn != NULL", newconn != NULL);
503 newsock = alloc_socket(newconn, 1);
505 netconn_delete(newconn);
506 sock_set_errno(sock, ENFILE);
509 LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET));
510 LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
511 nsock = &sockets[newsock - LWIP_SOCKET_OFFSET];
513 /* See event_callback: If data comes in right away after an accept, even
514 * though the server task might not have created a new socket yet.
515 * In that case, newconn->socket is counted down (newconn->socket--),
516 * so nsock->rcvevent is >= 1 here!
518 SYS_ARCH_PROTECT(lev);
519 nsock->rcvevent += (s16_t)(-1 - newconn->socket);
520 newconn->socket = newsock;
521 SYS_ARCH_UNPROTECT(lev);
523 /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
524 * not be NULL if addr is valid.
527 union sockaddr_aligned tempaddr;
528 /* get the IP address and port of the remote host */
529 err = netconn_peer(newconn, &naddr, &port);
531 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
532 netconn_delete(newconn);
533 free_socket(nsock, 1);
534 sock_set_errno(sock, err_to_errno(err));
537 LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
539 IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port);
540 if (*addrlen > tempaddr.sa.sa_len) {
541 *addrlen = tempaddr.sa.sa_len;
543 MEMCPY(addr, &tempaddr, *addrlen);
545 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
546 ip_addr_debug_print_val(SOCKETS_DEBUG, naddr);
547 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
549 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock));
552 sock_set_errno(sock, 0);
557 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
559 struct lwip_sock *sock;
560 ip_addr_t local_addr;
564 sock = get_socket(s);
569 if (!SOCK_ADDR_TYPE_MATCH(name, sock)) {
570 /* sockaddr does not match socket type (IPv4/IPv6) */
571 sock_set_errno(sock, err_to_errno(ERR_VAL));
575 /* check size, family and alignment of 'name' */
576 LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) &&
577 IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)),
578 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
579 LWIP_UNUSED_ARG(namelen);
581 SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port);
582 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
583 ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr);
584 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));
586 #if LWIP_IPV4 && LWIP_IPV6
587 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
588 if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) {
589 unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr));
590 IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4);
592 #endif /* LWIP_IPV4 && LWIP_IPV6 */
594 err = netconn_bind(sock->conn, &local_addr, local_port);
597 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
598 sock_set_errno(sock, err_to_errno(err));
602 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
603 sock_set_errno(sock, 0);
610 struct lwip_sock *sock;
614 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
616 sock = get_socket(s);
621 if (sock->conn != NULL) {
622 is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP;
624 LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
628 /* drop all possibly joined IGMP memberships */
629 lwip_socket_drop_registered_memberships(s);
630 #endif /* LWIP_IGMP */
632 err = netconn_delete(sock->conn);
634 sock_set_errno(sock, err_to_errno(err));
638 free_socket(sock, is_tcp);
644 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
646 struct lwip_sock *sock;
649 sock = get_socket(s);
654 if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) {
655 /* sockaddr does not match socket type (IPv4/IPv6) */
656 sock_set_errno(sock, err_to_errno(ERR_VAL));
660 LWIP_UNUSED_ARG(namelen);
661 if (name->sa_family == AF_UNSPEC) {
662 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
663 err = netconn_disconnect(sock->conn);
665 ip_addr_t remote_addr;
668 /* check size, family and alignment of 'name' */
669 LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) &&
670 IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name),
671 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
673 SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port);
674 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
675 ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr);
676 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
678 #if LWIP_IPV4 && LWIP_IPV6
679 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
680 if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) {
681 unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr));
682 IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4);
684 #endif /* LWIP_IPV4 && LWIP_IPV6 */
686 err = netconn_connect(sock->conn, &remote_addr, remote_port);
690 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
691 sock_set_errno(sock, err_to_errno(err));
695 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
696 sock_set_errno(sock, 0);
701 * Set a socket into listen mode.
702 * The socket may not have been used for another connection previously.
704 * @param s the socket to set to listening mode
705 * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
706 * @return 0 on success, non-zero on failure
709 lwip_listen(int s, int backlog)
711 struct lwip_sock *sock;
714 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
716 sock = get_socket(s);
721 /* limit the "backlog" parameter to fit in an u8_t */
722 backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
724 err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
727 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
728 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
729 sock_set_errno(sock, EOPNOTSUPP);
732 sock_set_errno(sock, err_to_errno(err));
736 sock_set_errno(sock, 0);
741 lwip_recvfrom(int s, void *mem, size_t len, int flags,
742 struct sockaddr *from, socklen_t *fromlen)
744 struct lwip_sock *sock;
747 u16_t buflen, copylen;
752 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
753 sock = get_socket(s);
759 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
760 /* Check if there is data left from the last recv operation. */
761 if (sock->lastdata) {
762 buf = sock->lastdata;
764 /* If this is non-blocking call, then check first */
765 if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
766 (sock->rcvevent <= 0)) {
768 /* already received data, return that */
769 sock_set_errno(sock, 0);
772 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
773 set_errno(EWOULDBLOCK);
777 /* No data was left from the previous operation, so we try to get
778 some from the network. */
779 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
780 err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
782 err = netconn_recv(sock->conn, (struct netbuf **)&buf);
784 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
789 if (err == ERR_CLSD) {
790 /* closed but already received data, ensure select gets the FIN, too */
791 event_callback(sock->conn, NETCONN_EVT_RCVPLUS, 0);
793 /* already received data, return that */
794 sock_set_errno(sock, 0);
797 /* We should really do some error checking here. */
798 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
799 s, lwip_strerr(err)));
800 sock_set_errno(sock, err_to_errno(err));
801 if (err == ERR_CLSD) {
807 LWIP_ASSERT("buf != NULL", buf != NULL);
808 sock->lastdata = buf;
811 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
812 p = (struct pbuf *)buf;
814 p = ((struct netbuf *)buf)->p;
817 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
818 buflen, len, off, sock->lastoffset));
820 buflen -= sock->lastoffset;
825 copylen = (u16_t)len;
828 /* copy the contents of the received buffer into
829 the supplied memory pointer mem */
830 pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
834 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
835 LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
838 (p->flags & PBUF_FLAG_PUSH) ||
839 (sock->rcvevent <= 0) ||
840 ((flags & MSG_PEEK) != 0)) {
847 /* Check to see from where the data was.*/
851 #endif /* !SOCKETS_DEBUG */
856 union sockaddr_aligned saddr;
857 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
858 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
860 netconn_getaddr(sock->conn, fromaddr, &port, 0);
862 port = netbuf_fromport((struct netbuf *)buf);
863 fromaddr = netbuf_fromaddr((struct netbuf *)buf);
866 #if LWIP_IPV4 && LWIP_IPV6
867 /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
868 if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && IP_IS_V4(fromaddr)) {
869 ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr));
870 IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6);
872 #endif /* LWIP_IPV4 && LWIP_IPV6 */
874 IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port);
875 ip_addr_debug_print(SOCKETS_DEBUG, fromaddr);
876 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
879 #endif /* SOCKETS_DEBUG */
881 if (*fromlen > saddr.sa.sa_len) {
882 *fromlen = saddr.sa.sa_len;
884 MEMCPY(from, &saddr, *fromlen);
889 /* If we don't peek the incoming message... */
890 if ((flags & MSG_PEEK) == 0) {
891 /* If this is a TCP socket, check if there is data left in the
892 buffer. If so, it should be saved in the sock structure for next
894 if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (buflen - copylen > 0)) {
895 sock->lastdata = buf;
896 sock->lastoffset += copylen;
897 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
899 sock->lastdata = NULL;
900 sock->lastoffset = 0;
901 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
902 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
903 pbuf_free((struct pbuf *)buf);
905 netbuf_delete((struct netbuf *)buf);
912 sock_set_errno(sock, 0);
917 lwip_read(int s, void *mem, size_t len)
919 return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
923 lwip_recv(int s, void *mem, size_t len, int flags)
925 return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
929 lwip_send(int s, const void *data, size_t size, int flags)
931 struct lwip_sock *sock;
936 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
937 s, data, size, flags));
939 sock = get_socket(s);
944 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
945 #if (LWIP_UDP || LWIP_RAW)
946 return lwip_sendto(s, data, size, flags, NULL, 0);
947 #else /* (LWIP_UDP || LWIP_RAW) */
948 sock_set_errno(sock, err_to_errno(ERR_ARG));
950 #endif /* (LWIP_UDP || LWIP_RAW) */
953 write_flags = NETCONN_COPY |
954 ((flags & MSG_MORE) ? NETCONN_MORE : 0) |
955 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
957 err = netconn_write_partly(sock->conn, data, size, write_flags, &written);
959 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written));
960 sock_set_errno(sock, err_to_errno(err));
961 return (err == ERR_OK ? (int)written : -1);
965 lwip_sendmsg(int s, const struct msghdr *msg, int flags)
967 struct lwip_sock *sock;
976 sock = get_socket(s);
981 LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL,
982 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
984 LWIP_UNUSED_ARG(msg->msg_control);
985 LWIP_UNUSED_ARG(msg->msg_controllen);
986 LWIP_UNUSED_ARG(msg->msg_flags);
987 LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", (msg->msg_iov != NULL && msg->msg_iovlen != 0),
988 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
990 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
992 write_flags = NETCONN_COPY |
993 ((flags & MSG_MORE) ? NETCONN_MORE : 0) |
994 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
996 for (i = 0; i < msg->msg_iovlen; i++) {
997 u8_t apiflags = write_flags;
998 if (i + 1 < msg->msg_iovlen) {
999 apiflags |= NETCONN_MORE;
1002 err = netconn_write_partly(sock->conn, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len, write_flags, &written);
1003 if (err == ERR_OK) {
1005 /* check that the entire IO vector was accepected, if not return a partial write */
1006 if (written != msg->msg_iov[i].iov_len)
1009 /* none of this IO vector was accepted, but previous was, return partial write and conceal ERR_WOULDBLOCK */
1010 else if (err == ERR_WOULDBLOCK && size > 0) {
1012 /* let ERR_WOULDBLOCK persist on the netconn since we are returning ERR_OK */
1019 sock_set_errno(sock, err_to_errno(err));
1021 #else /* LWIP_TCP */
1022 sock_set_errno(sock, err_to_errno(ERR_ARG));
1024 #endif /* LWIP_TCP */
1026 /* else, UDP and RAW NETCONNs */
1027 #if LWIP_UDP || LWIP_RAW
1029 struct netbuf *chain_buf;
1031 LWIP_UNUSED_ARG(flags);
1032 LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) ||
1033 IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)) ,
1034 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
1036 /* initialize chain buffer with destination */
1037 chain_buf = netbuf_new();
1039 sock_set_errno(sock, err_to_errno(ERR_MEM));
1042 if (msg->msg_name) {
1044 SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf->addr, remote_port);
1045 netbuf_fromport(chain_buf) = remote_port;
1047 #if LWIP_NETIF_TX_SINGLE_PBUF
1048 for (i = 0; i < msg->msg_iovlen; i++) {
1049 size += msg->msg_iov[i].iov_len;
1051 /* Allocate a new netbuf and copy the data into it. */
1052 if (netbuf_alloc(chain_buf, (u16_t)size) == NULL) {
1055 /* flatten the IO vectors */
1057 for (i = 0; i < msg->msg_iovlen; i++) {
1058 MEMCPY(&((u8_t*)chain_buf->p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
1059 offset += msg->msg_iov[i].iov_len;
1061 #if LWIP_CHECKSUM_ON_COPY
1063 /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */
1064 u16_t chksum = ~inet_chksum_pbuf(chain_buf->p);
1065 netbuf_set_chksum(chain_buf, chksum);
1067 #endif /* LWIP_CHECKSUM_ON_COPY */
1070 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
1071 /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain
1072 manually to avoid having to allocate, chain, and delete a netbuf for each iov */
1073 for (i = 0; i < msg->msg_iovlen; i++) {
1074 struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
1076 err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */
1079 p->payload = msg->msg_iov[i].iov_base;
1080 LWIP_ASSERT("iov_len < u16_t", msg->msg_iov[i].iov_len <= 0xFFFF);
1081 p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len;
1082 /* netbuf empty, add new pbuf */
1083 if (chain_buf->p == NULL) {
1084 chain_buf->p = chain_buf->ptr = p;
1085 /* add pbuf to existing pbuf chain */
1087 pbuf_cat(chain_buf->p, p);
1090 /* save size of total chain */
1091 if (err == ERR_OK) {
1092 size = netbuf_len(chain_buf);
1094 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
1096 if (err == ERR_OK) {
1097 #if LWIP_IPV4 && LWIP_IPV6
1098 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
1099 if (IP_IS_V6_VAL(chain_buf->addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf->addr))) {
1100 unmap_ipv4_mapped_ipv6(ip_2_ip4(&chain_buf->addr), ip_2_ip6(&chain_buf->addr));
1101 IP_SET_TYPE_VAL(chain_buf->addr, IPADDR_TYPE_V4);
1103 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1106 err = netconn_send(sock->conn, chain_buf);
1109 /* deallocated the buffer */
1110 netbuf_delete(chain_buf);
1112 sock_set_errno(sock, err_to_errno(err));
1113 return (err == ERR_OK ? size : -1);
1115 #else /* LWIP_UDP || LWIP_RAW */
1116 sock_set_errno(sock, err_to_errno(ERR_ARG));
1118 #endif /* LWIP_UDP || LWIP_RAW */
1122 lwip_sendto(int s, const void *data, size_t size, int flags,
1123 const struct sockaddr *to, socklen_t tolen)
1125 struct lwip_sock *sock;
1131 sock = get_socket(s);
1136 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
1138 return lwip_send(s, data, size, flags);
1139 #else /* LWIP_TCP */
1140 LWIP_UNUSED_ARG(flags);
1141 sock_set_errno(sock, err_to_errno(ERR_ARG));
1143 #endif /* LWIP_TCP */
1146 /* @todo: split into multiple sendto's? */
1147 LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
1148 short_size = (u16_t)size;
1149 LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
1150 (IS_SOCK_ADDR_LEN_VALID(tolen) &&
1151 IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))),
1152 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
1153 LWIP_UNUSED_ARG(tolen);
1155 /* initialize a buffer */
1156 buf.p = buf.ptr = NULL;
1157 #if LWIP_CHECKSUM_ON_COPY
1159 #endif /* LWIP_CHECKSUM_ON_COPY */
1161 SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port);
1164 ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr);
1166 netbuf_fromport(&buf) = remote_port;
1169 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
1170 s, data, short_size, flags));
1171 ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
1172 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
1174 /* make the buffer point to the data that should be sent */
1175 #if LWIP_NETIF_TX_SINGLE_PBUF
1176 /* Allocate a new netbuf and copy the data into it. */
1177 if (netbuf_alloc(&buf, short_size) == NULL) {
1180 #if LWIP_CHECKSUM_ON_COPY
1181 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
1182 u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
1183 netbuf_set_chksum(&buf, chksum);
1185 #endif /* LWIP_CHECKSUM_ON_COPY */
1187 MEMCPY(buf.p->payload, data, short_size);
1191 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
1192 err = netbuf_ref(&buf, data, short_size);
1193 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
1194 if (err == ERR_OK) {
1195 #if LWIP_IPV4 && LWIP_IPV6
1196 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
1197 if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) {
1198 unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr));
1199 IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4);
1201 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1204 err = netconn_send(sock->conn, &buf);
1207 /* deallocated the buffer */
1210 sock_set_errno(sock, err_to_errno(err));
1211 return (err == ERR_OK ? short_size : -1);
1215 lwip_socket(int domain, int type, int protocol)
1217 struct netconn *conn;
1220 LWIP_UNUSED_ARG(domain); /* @todo: check this */
1222 /* create a netconn */
1225 conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW),
1226 (u8_t)protocol, event_callback);
1227 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
1228 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1231 conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain,
1232 ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) ,
1234 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
1235 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1238 conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), event_callback);
1239 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
1240 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1243 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
1244 domain, type, protocol));
1250 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
1255 i = alloc_socket(conn, 0);
1258 netconn_delete(conn);
1263 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
1269 lwip_write(int s, const void *data, size_t size)
1271 return lwip_send(s, data, size, 0);
1275 lwip_writev(int s, const struct iovec *iov, int iovcnt)
1279 msg.msg_name = NULL;
1280 msg.msg_namelen = 0;
1281 /* Hack: we have to cast via number to cast from 'const' pointer to non-const.
1282 Blame the opengroup standard for this inconsistency. */
1283 msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov);
1284 msg.msg_iovlen = iovcnt;
1285 msg.msg_control = NULL;
1286 msg.msg_controllen = 0;
1288 return lwip_sendmsg(s, &msg, 0);
1292 * Go through the readset and writeset lists and see which socket of the sockets
1293 * set in the sets has events. On return, readset, writeset and exceptset have
1294 * the sockets enabled that had events.
1296 * @param maxfdp1 the highest socket index in the sets
1297 * @param readset_in set of sockets to check for read events
1298 * @param writeset_in set of sockets to check for write events
1299 * @param exceptset_in set of sockets to check for error events
1300 * @param readset_out set of sockets that had read events
1301 * @param writeset_out set of sockets that had write events
1302 * @param exceptset_out set os sockets that had error events
1303 * @return number of sockets that had events (read/write/exception) (>= 0)
1306 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
1307 fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
1310 fd_set lreadset, lwriteset, lexceptset;
1311 struct lwip_sock *sock;
1312 SYS_ARCH_DECL_PROTECT(lev);
1315 FD_ZERO(&lwriteset);
1316 FD_ZERO(&lexceptset);
1318 /* Go through each socket in each list to count number of sockets which
1320 for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) {
1321 /* if this FD is not in the set, continue */
1322 if (!(readset_in && FD_ISSET(i, readset_in)) &&
1323 !(writeset_in && FD_ISSET(i, writeset_in)) &&
1324 !(exceptset_in && FD_ISSET(i, exceptset_in))) {
1327 /* First get the socket's status (protected)... */
1328 SYS_ARCH_PROTECT(lev);
1329 sock = tryget_socket(i);
1331 void* lastdata = sock->lastdata;
1332 s16_t rcvevent = sock->rcvevent;
1333 u16_t sendevent = sock->sendevent;
1334 u16_t errevent = sock->errevent;
1335 SYS_ARCH_UNPROTECT(lev);
1337 /* ... then examine it: */
1338 /* See if netconn of this socket is ready for read */
1339 if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
1340 FD_SET(i, &lreadset);
1341 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
1344 /* See if netconn of this socket is ready for write */
1345 if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
1346 FD_SET(i, &lwriteset);
1347 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
1350 /* See if netconn of this socket had an error */
1351 if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
1352 FD_SET(i, &lexceptset);
1353 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
1357 SYS_ARCH_UNPROTECT(lev);
1358 /* continue on to next FD in list */
1361 /* copy local sets to the ones provided as arguments */
1362 *readset_out = lreadset;
1363 *writeset_out = lwriteset;
1364 *exceptset_out = lexceptset;
1366 LWIP_ASSERT("nready >= 0", nready >= 0);
1371 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
1372 struct timeval *timeout)
1376 fd_set lreadset, lwriteset, lexceptset;
1378 struct lwip_select_cb select_cb;
1381 #if LWIP_NETCONN_SEM_PER_THREAD
1384 SYS_ARCH_DECL_PROTECT(lev);
1386 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
1387 maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
1388 timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
1389 timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
1391 /* Go through each socket in each list to count number of sockets which
1393 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1395 /* If we don't have any current events, then suspend if we are supposed to */
1397 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
1398 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
1399 /* This is OK as the local fdsets are empty and nready is zero,
1400 or we would have returned earlier. */
1401 goto return_copy_fdsets;
1404 /* None ready: add our semaphore to list:
1405 We don't actually need any dynamic memory. Our entry on the
1406 list is only valid while we are in this function, so it's ok
1407 to use local variables. */
1409 select_cb.next = NULL;
1410 select_cb.prev = NULL;
1411 select_cb.readset = readset;
1412 select_cb.writeset = writeset;
1413 select_cb.exceptset = exceptset;
1414 select_cb.sem_signalled = 0;
1415 #if LWIP_NETCONN_SEM_PER_THREAD
1416 select_cb.sem = LWIP_NETCONN_THREAD_SEM_GET();
1417 #else /* LWIP_NETCONN_SEM_PER_THREAD */
1418 if (sys_sem_new(&select_cb.sem, 0) != ERR_OK) {
1419 /* failed to create semaphore */
1423 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
1425 /* Protect the select_cb_list */
1426 SYS_ARCH_PROTECT(lev);
1428 /* Put this select_cb on top of list */
1429 select_cb.next = select_cb_list;
1430 if (select_cb_list != NULL) {
1431 select_cb_list->prev = &select_cb;
1433 select_cb_list = &select_cb;
1434 /* Increasing this counter tells event_callback that the list has changed. */
1437 /* Now we can safely unprotect */
1438 SYS_ARCH_UNPROTECT(lev);
1440 /* Increase select_waiting for each socket we are interested in */
1442 for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) {
1443 if ((readset && FD_ISSET(i, readset)) ||
1444 (writeset && FD_ISSET(i, writeset)) ||
1445 (exceptset && FD_ISSET(i, exceptset))) {
1446 struct lwip_sock *sock;
1447 SYS_ARCH_PROTECT(lev);
1448 sock = tryget_socket(i);
1450 sock->select_waiting++;
1451 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
1453 /* Not a valid socket */
1456 SYS_ARCH_UNPROTECT(lev);
1459 SYS_ARCH_UNPROTECT(lev);
1464 /* Call lwip_selscan again: there could have been events between
1465 the last scan (without us on the list) and putting us on the list! */
1466 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1468 /* Still none ready, just wait to be woken */
1473 msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
1474 if (msectimeout == 0) {
1475 /* Wait 1ms at least (0 means wait forever) */
1480 waitres = sys_arch_sem_wait(SELECT_SEM_PTR(select_cb.sem), msectimeout);
1481 #if LWIP_NETCONN_SEM_PER_THREAD
1487 /* Decrease select_waiting for each socket we are interested in */
1488 for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) {
1489 if ((readset && FD_ISSET(i, readset)) ||
1490 (writeset && FD_ISSET(i, writeset)) ||
1491 (exceptset && FD_ISSET(i, exceptset))) {
1492 struct lwip_sock *sock;
1493 SYS_ARCH_PROTECT(lev);
1494 sock = tryget_socket(i);
1496 /* for now, handle select_waiting==0... */
1497 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
1498 if (sock->select_waiting > 0) {
1499 sock->select_waiting--;
1502 /* Not a valid socket */
1505 SYS_ARCH_UNPROTECT(lev);
1508 /* Take us off the list */
1509 SYS_ARCH_PROTECT(lev);
1510 if (select_cb.next != NULL) {
1511 select_cb.next->prev = select_cb.prev;
1513 if (select_cb_list == &select_cb) {
1514 LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
1515 select_cb_list = select_cb.next;
1517 LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
1518 select_cb.prev->next = select_cb.next;
1520 /* Increasing this counter tells event_callback that the list has changed. */
1522 SYS_ARCH_UNPROTECT(lev);
1524 #if LWIP_NETCONN_SEM_PER_THREAD
1525 if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) {
1526 /* don't leave the thread-local semaphore signalled */
1527 sys_arch_sem_wait(select_cb.sem, 1);
1529 #else /* LWIP_NETCONN_SEM_PER_THREAD */
1530 sys_sem_free(&select_cb.sem);
1531 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
1534 /* This happens when a socket got closed while waiting */
1539 if (waitres == SYS_ARCH_TIMEOUT) {
1541 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
1542 /* This is OK as the local fdsets are empty and nready is zero,
1543 or we would have returned earlier. */
1544 goto return_copy_fdsets;
1547 /* See what's set */
1548 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1551 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
1555 *readset = lreadset;
1558 *writeset = lwriteset;
1561 *exceptset = lexceptset;
1567 * Callback registered in the netconn layer for each socket-netconn.
1568 * Processes recvevent (data available) and wakes up tasks waiting for select.
1571 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
1574 struct lwip_sock *sock;
1575 struct lwip_select_cb *scb;
1576 int last_select_cb_ctr;
1577 SYS_ARCH_DECL_PROTECT(lev);
1579 LWIP_UNUSED_ARG(len);
1585 /* Data comes in right away after an accept, even though
1586 * the server task might not have created a new socket yet.
1587 * Just count down (or up) if that's the case and we
1588 * will use the data later. Note that only receive events
1589 * can happen before the new socket is set up. */
1590 SYS_ARCH_PROTECT(lev);
1591 if (conn->socket < 0) {
1592 if (evt == NETCONN_EVT_RCVPLUS) {
1595 SYS_ARCH_UNPROTECT(lev);
1599 SYS_ARCH_UNPROTECT(lev);
1602 sock = get_socket(s);
1610 SYS_ARCH_PROTECT(lev);
1611 /* Set event as required */
1613 case NETCONN_EVT_RCVPLUS:
1616 case NETCONN_EVT_RCVMINUS:
1619 case NETCONN_EVT_SENDPLUS:
1620 sock->sendevent = 1;
1622 case NETCONN_EVT_SENDMINUS:
1623 sock->sendevent = 0;
1625 case NETCONN_EVT_ERROR:
1629 LWIP_ASSERT("unknown event", 0);
1633 if (sock->select_waiting == 0) {
1634 /* noone is waiting for this socket, no need to check select_cb_list */
1635 SYS_ARCH_UNPROTECT(lev);
1639 /* Now decide if anyone is waiting for this socket */
1640 /* NOTE: This code goes through the select_cb_list list multiple times
1641 ONLY IF a select was actually waiting. We go through the list the number
1642 of waiting select calls + 1. This list is expected to be small. */
1644 /* At this point, SYS_ARCH is still protected! */
1646 for (scb = select_cb_list; scb != NULL; scb = scb->next) {
1647 /* remember the state of select_cb_list to detect changes */
1648 last_select_cb_ctr = select_cb_ctr;
1649 if (scb->sem_signalled == 0) {
1650 /* semaphore not signalled yet */
1652 /* Test this select call for our socket */
1653 if (sock->rcvevent > 0) {
1654 if (scb->readset && FD_ISSET(s, scb->readset)) {
1658 if (sock->sendevent != 0) {
1659 if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
1663 if (sock->errevent != 0) {
1664 if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
1669 scb->sem_signalled = 1;
1670 /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
1671 lead to the select thread taking itself off the list, invalidating the semaphore. */
1672 sys_sem_signal(SELECT_SEM_PTR(scb->sem));
1675 /* unlock interrupts with each step */
1676 SYS_ARCH_UNPROTECT(lev);
1677 /* this makes sure interrupt protection time is short */
1678 SYS_ARCH_PROTECT(lev);
1679 if (last_select_cb_ctr != select_cb_ctr) {
1680 /* someone has changed select_cb_list, restart at the beginning */
1684 SYS_ARCH_UNPROTECT(lev);
1688 * Close one end of a full-duplex connection.
1691 lwip_shutdown(int s, int how)
1693 struct lwip_sock *sock;
1695 u8_t shut_rx = 0, shut_tx = 0;
1697 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
1699 sock = get_socket(s);
1704 if (sock->conn != NULL) {
1705 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
1706 sock_set_errno(sock, EOPNOTSUPP);
1710 sock_set_errno(sock, ENOTCONN);
1714 if (how == SHUT_RD) {
1716 } else if (how == SHUT_WR) {
1718 } else if (how == SHUT_RDWR) {
1722 sock_set_errno(sock, EINVAL);
1725 err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
1727 sock_set_errno(sock, err_to_errno(err));
1728 return (err == ERR_OK ? 0 : -1);
1732 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
1734 struct lwip_sock *sock;
1735 union sockaddr_aligned saddr;
1740 sock = get_socket(s);
1745 /* get the IP address and port */
1746 err = netconn_getaddr(sock->conn, &naddr, &port, local);
1747 if (err != ERR_OK) {
1748 sock_set_errno(sock, err_to_errno(err));
1752 #if LWIP_IPV4 && LWIP_IPV6
1753 /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
1754 if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) &&
1755 IP_IS_V4_VAL(naddr)) {
1756 ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&naddr), ip_2_ip4(&naddr));
1757 IP_SET_TYPE_VAL(naddr, IPADDR_TYPE_V6);
1759 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1761 IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port);
1763 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
1764 ip_addr_debug_print_val(SOCKETS_DEBUG, naddr);
1765 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port));
1767 if (*namelen > saddr.sa.sa_len) {
1768 *namelen = saddr.sa.sa_len;
1770 MEMCPY(name, &saddr, *namelen);
1772 sock_set_errno(sock, 0);
1777 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
1779 return lwip_getaddrname(s, name, namelen, 0);
1783 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
1785 return lwip_getaddrname(s, name, namelen, 1);
1789 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
1792 struct lwip_sock *sock = get_socket(s);
1793 #if !LWIP_TCPIP_CORE_LOCKING
1794 LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data);
1795 #endif /* !LWIP_TCPIP_CORE_LOCKING */
1801 if ((NULL == optval) || (NULL == optlen)) {
1802 sock_set_errno(sock, EFAULT);
1806 #if LWIP_TCPIP_CORE_LOCKING
1807 /* core-locking can just call the -impl function */
1809 err = lwip_getsockopt_impl(s, level, optname, optval, optlen);
1810 UNLOCK_TCPIP_CORE();
1812 #else /* LWIP_TCPIP_CORE_LOCKING */
1814 #if LWIP_MPU_COMPATIBLE
1815 /* MPU_COMPATIBLE copies the optval data, so check for max size here */
1816 if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) {
1817 sock_set_errno(sock, ENOBUFS);
1820 #endif /* LWIP_MPU_COMPATIBLE */
1822 LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock);
1823 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s;
1824 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level;
1825 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
1826 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen;
1827 #if !LWIP_MPU_COMPATIBLE
1828 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval;
1829 #endif /* !LWIP_MPU_COMPATIBLE */
1830 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0;
1831 #if LWIP_NETCONN_SEM_PER_THREAD
1832 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
1834 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
1836 err = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
1837 if (err != ERR_OK) {
1838 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
1839 sock_set_errno(sock, err_to_errno(err));
1842 sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
1844 /* write back optlen and optval */
1845 *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen;
1846 #if LWIP_MPU_COMPATIBLE
1847 MEMCPY(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval,
1848 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen);
1849 #endif /* LWIP_MPU_COMPATIBLE */
1851 /* maybe lwip_getsockopt_internal has changed err */
1852 err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
1853 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
1854 #endif /* LWIP_TCPIP_CORE_LOCKING */
1856 sock_set_errno(sock, err);
1857 return err ? -1 : 0;
1860 #if !LWIP_TCPIP_CORE_LOCKING
1861 /** lwip_getsockopt_callback: only used without CORE_LOCKING
1862 * to get into the tcpip_thread
1865 lwip_getsockopt_callback(void *arg)
1867 struct lwip_setgetsockopt_data *data;
1868 LWIP_ASSERT("arg != NULL", arg != NULL);
1869 data = (struct lwip_setgetsockopt_data*)arg;
1871 data->err = lwip_getsockopt_impl(data->s, data->level, data->optname,
1872 #if LWIP_MPU_COMPATIBLE
1874 #else /* LWIP_MPU_COMPATIBLE */
1876 #endif /* LWIP_MPU_COMPATIBLE */
1879 sys_sem_signal((sys_sem_t*)(data->completed_sem));
1881 #endif /* LWIP_TCPIP_CORE_LOCKING */
1883 /** lwip_getsockopt_impl: the actual implementation of getsockopt:
1884 * same argument as lwip_getsockopt, either called directly or through callback
1887 lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen)
1890 struct lwip_sock *sock = tryget_socket(s);
1897 /* Level: SOL_SOCKET */
1903 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
1904 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) {
1907 if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) {
1913 #endif /* LWIP_TCP */
1915 /* The option flags */
1920 #endif /* SO_REUSE */
1921 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
1922 *(int*)optval = ip_get_option(sock->conn->pcb.ip, optname);
1923 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
1924 s, optname, (*(int*)optval?"on":"off")));
1928 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
1929 switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) {
1931 *(int*)optval = SOCK_RAW;
1934 *(int*)optval = SOCK_STREAM;
1937 *(int*)optval = SOCK_DGRAM;
1939 default: /* unrecognized socket type */
1940 *(int*)optval = netconn_type(sock->conn);
1941 LWIP_DEBUGF(SOCKETS_DEBUG,
1942 ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
1943 s, *(int *)optval));
1944 } /* switch (netconn_type(sock->conn)) */
1945 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
1946 s, *(int *)optval));
1950 LWIP_SOCKOPT_CHECK_OPTLEN(*optlen, int);
1951 /* only overwrite ERR_OK or temporary errors */
1952 if (((sock->err == 0) || (sock->err == EINPROGRESS)) && (sock->conn != NULL)) {
1953 sock_set_errno(sock, err_to_errno(sock->conn->last_err));
1955 *(int *)optval = (sock->err == 0xFF ? (int)-1 : (int)sock->err);
1957 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
1958 s, *(int *)optval));
1961 #if LWIP_SO_SNDTIMEO
1963 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
1964 LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn));
1966 #endif /* LWIP_SO_SNDTIMEO */
1967 #if LWIP_SO_RCVTIMEO
1969 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
1970 LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn));
1972 #endif /* LWIP_SO_RCVTIMEO */
1975 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
1976 *(int *)optval = netconn_get_recvbufsize(sock->conn);
1978 #endif /* LWIP_SO_RCVBUF */
1983 struct linger* linger = (struct linger*)optval;
1984 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger);
1985 conn_linger = sock->conn->linger;
1986 if (conn_linger >= 0) {
1987 linger->l_onoff = 1;
1988 linger->l_linger = (int)conn_linger;
1990 linger->l_onoff = 0;
1991 linger->l_linger = 0;
1995 #endif /* LWIP_SO_LINGER */
1998 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP);
2000 if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0) {
2001 /* this flag is only available for UDP, not for UDP lite */
2002 return EAFNOSUPPORT;
2004 #endif /* LWIP_UDPLITE */
2005 *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
2007 #endif /* LWIP_UDP*/
2009 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
2013 } /* switch (optname) */
2016 /* Level: IPPROTO_IP */
2020 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
2021 *(int*)optval = sock->conn->pcb.ip->ttl;
2022 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
2023 s, *(int *)optval));
2026 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
2027 *(int*)optval = sock->conn->pcb.ip->tos;
2028 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
2029 s, *(int *)optval));
2031 #if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP
2032 case IP_MULTICAST_TTL:
2033 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
2034 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2037 *(u8_t*)optval = udp_get_multicast_ttl(sock->conn->pcb.udp);
2038 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
2039 s, *(int *)optval));
2041 case IP_MULTICAST_IF:
2042 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr);
2043 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2046 inet_addr_from_ip4addr((struct in_addr*)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp));
2047 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
2048 s, *(u32_t *)optval));
2050 case IP_MULTICAST_LOOP:
2051 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
2052 if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
2057 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
2058 s, *(int *)optval));
2060 #endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */
2062 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
2066 } /* switch (optname) */
2070 /* Level: IPPROTO_TCP */
2072 /* Special case: all IPPROTO_TCP option take an int */
2073 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP);
2074 if (sock->conn->pcb.tcp->state == LISTEN) {
2079 *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
2080 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
2081 s, (*(int*)optval)?"on":"off") );
2084 *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
2085 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n",
2086 s, *(int *)optval));
2089 #if LWIP_TCP_KEEPALIVE
2091 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
2092 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n",
2093 s, *(int *)optval));
2096 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
2097 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n",
2098 s, *(int *)optval));
2101 *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
2102 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n",
2103 s, *(int *)optval));
2105 #endif /* LWIP_TCP_KEEPALIVE */
2107 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
2111 } /* switch (optname) */
2113 #endif /* LWIP_TCP */
2116 /* Level: IPPROTO_IPV6 */
2120 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
2121 *(int*)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0);
2122 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n",
2123 s, *(int *)optval));
2126 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
2130 } /* switch (optname) */
2132 #endif /* LWIP_IPV6 */
2134 #if LWIP_UDP && LWIP_UDPLITE
2135 /* Level: IPPROTO_UDPLITE */
2136 case IPPROTO_UDPLITE:
2137 /* Special case: all IPPROTO_UDPLITE option take an int */
2138 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
2139 /* If this is no UDP lite socket, ignore any options. */
2140 if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
2144 case UDPLITE_SEND_CSCOV:
2145 *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
2146 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
2147 s, (*(int*)optval)) );
2149 case UDPLITE_RECV_CSCOV:
2150 *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
2151 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
2152 s, (*(int*)optval)) );
2155 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
2159 } /* switch (optname) */
2161 #endif /* LWIP_UDP */
2162 /* Level: IPPROTO_RAW */
2165 #if LWIP_IPV6 && LWIP_RAW
2167 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW);
2168 if (sock->conn->pcb.raw->chksum_reqd == 0) {
2169 *(int *)optval = -1;
2171 *(int *)optval = sock->conn->pcb.raw->chksum_offset;
2173 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n",
2174 s, (*(int*)optval)) );
2176 #endif /* LWIP_IPV6 && LWIP_RAW */
2178 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
2182 } /* switch (optname) */
2185 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2186 s, level, optname));
2189 } /* switch (level) */
2195 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
2198 struct lwip_sock *sock = get_socket(s);
2199 #if !LWIP_TCPIP_CORE_LOCKING
2200 LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data);
2201 #endif /* !LWIP_TCPIP_CORE_LOCKING */
2207 if (NULL == optval) {
2208 sock_set_errno(sock, EFAULT);
2212 #if LWIP_TCPIP_CORE_LOCKING
2213 /* core-locking can just call the -impl function */
2215 err = lwip_setsockopt_impl(s, level, optname, optval, optlen);
2216 UNLOCK_TCPIP_CORE();
2218 #else /* LWIP_TCPIP_CORE_LOCKING */
2220 #if LWIP_MPU_COMPATIBLE
2221 /* MPU_COMPATIBLE copies the optval data, so check for max size here */
2222 if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) {
2223 sock_set_errno(sock, ENOBUFS);
2226 #endif /* LWIP_MPU_COMPATIBLE */
2228 LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock);
2229 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s;
2230 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level;
2231 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
2232 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen;
2233 #if LWIP_MPU_COMPATIBLE
2234 MEMCPY(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen);
2235 #else /* LWIP_MPU_COMPATIBLE */
2236 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void*)optval;
2237 #endif /* LWIP_MPU_COMPATIBLE */
2238 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0;
2239 #if LWIP_NETCONN_SEM_PER_THREAD
2240 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
2242 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
2244 err = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
2245 if (err != ERR_OK) {
2246 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
2247 sock_set_errno(sock, err_to_errno(err));
2250 sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
2252 /* maybe lwip_getsockopt_internal has changed err */
2253 err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
2254 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
2255 #endif /* LWIP_TCPIP_CORE_LOCKING */
2257 sock_set_errno(sock, err);
2258 return err ? -1 : 0;
2261 #if !LWIP_TCPIP_CORE_LOCKING
2262 /** lwip_setsockopt_callback: only used without CORE_LOCKING
2263 * to get into the tcpip_thread
2266 lwip_setsockopt_callback(void *arg)
2268 struct lwip_setgetsockopt_data *data;
2269 LWIP_ASSERT("arg != NULL", arg != NULL);
2270 data = (struct lwip_setgetsockopt_data*)arg;
2272 data->err = lwip_setsockopt_impl(data->s, data->level, data->optname,
2273 #if LWIP_MPU_COMPATIBLE
2275 #else /* LWIP_MPU_COMPATIBLE */
2277 #endif /* LWIP_MPU_COMPATIBLE */
2280 sys_sem_signal((sys_sem_t*)(data->completed_sem));
2282 #endif /* LWIP_TCPIP_CORE_LOCKING */
2284 /** lwip_setsockopt_impl: the actual implementation of setsockopt:
2285 * same argument as lwip_setsockopt, either called directly or through callback
2288 lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen)
2291 struct lwip_sock *sock = tryget_socket(s);
2298 /* Level: SOL_SOCKET */
2302 /* SO_ACCEPTCONN is get-only */
2304 /* The option flags */
2309 #endif /* SO_REUSE */
2310 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
2311 if (*(const int*)optval) {
2312 ip_set_option(sock->conn->pcb.ip, optname);
2314 ip_reset_option(sock->conn->pcb.ip, optname);
2316 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
2317 s, optname, (*(const int*)optval?"on":"off")));
2320 /* SO_TYPE is get-only */
2321 /* SO_ERROR is get-only */
2323 #if LWIP_SO_SNDTIMEO
2325 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
2326 netconn_set_sendtimeout(sock->conn, LWIP_SO_SNDRCVTIMEO_GET_MS(optval));
2328 #endif /* LWIP_SO_SNDTIMEO */
2329 #if LWIP_SO_RCVTIMEO
2331 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
2332 netconn_set_recvtimeout(sock->conn, (int)LWIP_SO_SNDRCVTIMEO_GET_MS(optval));
2334 #endif /* LWIP_SO_RCVTIMEO */
2337 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int);
2338 netconn_set_recvbufsize(sock->conn, *(const int*)optval);
2340 #endif /* LWIP_SO_RCVBUF */
2344 const struct linger* linger = (const struct linger*)optval;
2345 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger);
2346 if (linger->l_onoff) {
2347 int lingersec = linger->l_linger;
2348 if (lingersec < 0) {
2351 if (lingersec > 0xFFFF) {
2354 sock->conn->linger = (s16_t)lingersec;
2356 sock->conn->linger = -1;
2360 #endif /* LWIP_SO_LINGER */
2363 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP);
2365 if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0) {
2366 /* this flag is only available for UDP, not for UDP lite */
2367 return EAFNOSUPPORT;
2369 #endif /* LWIP_UDPLITE */
2370 if (*(const int*)optval) {
2371 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
2373 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
2376 #endif /* LWIP_UDP */
2378 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
2382 } /* switch (optname) */
2385 /* Level: IPPROTO_IP */
2389 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
2390 sock->conn->pcb.ip->ttl = (u8_t)(*(const int*)optval);
2391 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
2392 s, sock->conn->pcb.ip->ttl));
2395 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
2396 sock->conn->pcb.ip->tos = (u8_t)(*(const int*)optval);
2397 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
2398 s, sock->conn->pcb.ip->tos));
2400 #if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP
2401 case IP_MULTICAST_TTL:
2402 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
2403 udp_set_multicast_ttl(sock->conn->pcb.udp, (u8_t)(*(const u8_t*)optval));
2405 case IP_MULTICAST_IF:
2408 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP);
2409 inet_addr_to_ip4addr(&if_addr, (const struct in_addr*)optval);
2410 udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr);
2413 case IP_MULTICAST_LOOP:
2414 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
2415 if (*(const u8_t*)optval) {
2416 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
2418 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
2421 #endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */
2423 case IP_ADD_MEMBERSHIP:
2424 case IP_DROP_MEMBERSHIP:
2426 /* If this is a TCP or a RAW socket, ignore these options. */
2427 /* @todo: assign membership to this socket so that it is dropped when closing the socket */
2429 const struct ip_mreq *imr = (const struct ip_mreq *)optval;
2431 ip4_addr_t multi_addr;
2432 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP);
2433 inet_addr_to_ip4addr(&if_addr, &imr->imr_interface);
2434 inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr);
2435 if (optname == IP_ADD_MEMBERSHIP) {
2436 if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) {
2437 /* cannot track membership (out of memory) */
2441 igmp_err = igmp_joingroup(&if_addr, &multi_addr);
2444 igmp_err = igmp_leavegroup(&if_addr, &multi_addr);
2445 lwip_socket_unregister_membership(s, &if_addr, &multi_addr);
2447 if (igmp_err != ERR_OK) {
2448 err = EADDRNOTAVAIL;
2452 #endif /* LWIP_IGMP */
2454 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
2458 } /* switch (optname) */
2462 /* Level: IPPROTO_TCP */
2464 /* Special case: all IPPROTO_TCP option take an int */
2465 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
2466 if (sock->conn->pcb.tcp->state == LISTEN) {
2471 if (*(const int*)optval) {
2472 tcp_nagle_disable(sock->conn->pcb.tcp);
2474 tcp_nagle_enable(sock->conn->pcb.tcp);
2476 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
2477 s, (*(const int *)optval)?"on":"off") );
2480 sock->conn->pcb.tcp->keep_idle = (u32_t)(*(const int*)optval);
2481 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
2482 s, sock->conn->pcb.tcp->keep_idle));
2485 #if LWIP_TCP_KEEPALIVE
2487 sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(const int*)optval);
2488 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
2489 s, sock->conn->pcb.tcp->keep_idle));
2492 sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(const int*)optval);
2493 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
2494 s, sock->conn->pcb.tcp->keep_intvl));
2497 sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int*)optval);
2498 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
2499 s, sock->conn->pcb.tcp->keep_cnt));
2501 #endif /* LWIP_TCP_KEEPALIVE */
2503 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
2507 } /* switch (optname) */
2509 #endif /* LWIP_TCP*/
2512 /* Level: IPPROTO_IPV6 */
2516 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
2517 if (*(const int*)optval) {
2518 netconn_set_ipv6only(sock->conn, 1);
2520 netconn_set_ipv6only(sock->conn, 0);
2522 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n",
2523 s, (netconn_get_ipv6only(sock->conn) ? 1 : 0)));
2526 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
2530 } /* switch (optname) */
2532 #endif /* LWIP_IPV6 */
2534 #if LWIP_UDP && LWIP_UDPLITE
2535 /* Level: IPPROTO_UDPLITE */
2536 case IPPROTO_UDPLITE:
2537 /* Special case: all IPPROTO_UDPLITE option take an int */
2538 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
2539 /* If this is no UDP lite socket, ignore any options. */
2540 if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
2544 case UDPLITE_SEND_CSCOV:
2545 if ((*(const int*)optval != 0) && ((*(const int*)optval < 8) || (*(const int*)optval > 0xffff))) {
2546 /* don't allow illegal values! */
2547 sock->conn->pcb.udp->chksum_len_tx = 8;
2549 sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(const int*)optval;
2551 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
2552 s, (*(const int*)optval)) );
2554 case UDPLITE_RECV_CSCOV:
2555 if ((*(const int*)optval != 0) && ((*(const int*)optval < 8) || (*(const int*)optval > 0xffff))) {
2556 /* don't allow illegal values! */
2557 sock->conn->pcb.udp->chksum_len_rx = 8;
2559 sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(const int*)optval;
2561 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
2562 s, (*(const int*)optval)) );
2565 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
2569 } /* switch (optname) */
2571 #endif /* LWIP_UDP */
2572 /* Level: IPPROTO_RAW */
2575 #if LWIP_IPV6 && LWIP_RAW
2577 /* It should not be possible to disable the checksum generation with ICMPv6
2578 * as per RFC 3542 chapter 3.1 */
2579 if(sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) {
2583 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW);
2584 if (*(const int *)optval < 0) {
2585 sock->conn->pcb.raw->chksum_reqd = 0;
2586 } else if (*(const int *)optval & 1) {
2587 /* Per RFC3542, odd offsets are not allowed */
2590 sock->conn->pcb.raw->chksum_reqd = 1;
2591 sock->conn->pcb.raw->chksum_offset = (u16_t)*(const int *)optval;
2593 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n",
2594 s, sock->conn->pcb.raw->chksum_reqd));
2596 #endif /* LWIP_IPV6 && LWIP_RAW */
2598 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
2602 } /* switch (optname) */
2605 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2606 s, level, optname));
2609 } /* switch (level) */
2615 lwip_ioctl(int s, long cmd, void *argp)
2617 struct lwip_sock *sock = get_socket(s);
2622 #endif /* LWIP_SO_RCVBUF */
2629 #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE
2632 sock_set_errno(sock, EINVAL);
2635 #if LWIP_FIONREAD_LINUXMODE
2636 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
2638 if (sock->lastdata) {
2639 p = ((struct netbuf *)sock->lastdata)->p;
2640 *((int*)argp) = p->tot_len - sock->lastoffset;
2642 struct netbuf *rxbuf;
2644 if (sock->rcvevent <= 0) {
2647 err = netconn_recv(sock->conn, &rxbuf);
2648 if (err != ERR_OK) {
2651 sock->lastdata = rxbuf;
2652 sock->lastoffset = 0;
2653 *((int*)argp) = rxbuf->p->tot_len;
2659 #endif /* LWIP_FIONREAD_LINUXMODE */
2662 /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */
2663 SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
2664 if (recv_avail < 0) {
2667 *((int*)argp) = recv_avail;
2669 /* Check if there is data left from the last recv operation. /maq 041215 */
2670 if (sock->lastdata) {
2671 struct pbuf *p = (struct pbuf *)sock->lastdata;
2672 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
2673 p = ((struct netbuf *)p)->p;
2675 buflen = p->tot_len;
2676 buflen -= sock->lastoffset;
2678 *((int*)argp) += buflen;
2681 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
2682 sock_set_errno(sock, 0);
2684 #else /* LWIP_SO_RCVBUF */
2686 #endif /* LWIP_SO_RCVBUF */
2687 #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */
2691 if (argp && *(u32_t*)argp) {
2694 netconn_set_nonblocking(sock->conn, val);
2695 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
2696 sock_set_errno(sock, 0);
2701 } /* switch (cmd) */
2702 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
2703 sock_set_errno(sock, ENOSYS); /* not yet implemented */
2707 /** A minimal implementation of fcntl.
2708 * Currently only the commands F_GETFL and F_SETFL are implemented.
2709 * Only the flag O_NONBLOCK is implemented.
2712 lwip_fcntl(int s, int cmd, int val)
2714 struct lwip_sock *sock = get_socket(s);
2723 ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
2724 sock_set_errno(sock, 0);
2727 if ((val & ~O_NONBLOCK) == 0) {
2728 /* only O_NONBLOCK, all other bits are zero */
2729 netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
2731 sock_set_errno(sock, 0);
2733 sock_set_errno(sock, ENOSYS); /* not yet implemented */
2737 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
2738 sock_set_errno(sock, ENOSYS); /* not yet implemented */
2745 /** Register a new IGMP membership. On socket close, the membership is dropped automatically.
2747 * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
2749 * @return 1 on success, 0 on failure
2752 lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
2754 struct lwip_sock *sock = get_socket(s);
2761 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
2762 if (socket_ipv4_multicast_memberships[i].sock == NULL) {
2763 socket_ipv4_multicast_memberships[i].sock = sock;
2764 ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr);
2765 ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr);
2772 /** Unregister a previously registered membership. This prevents dropping the membership
2775 * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
2778 lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
2780 struct lwip_sock *sock = get_socket(s);
2787 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
2788 if ((socket_ipv4_multicast_memberships[i].sock == sock) &&
2789 ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) &&
2790 ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) {
2791 socket_ipv4_multicast_memberships[i].sock = NULL;
2792 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
2793 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
2799 /** Drop all memberships of a socket that were not dropped explicitly via setsockopt.
2801 * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK).
2804 lwip_socket_drop_registered_memberships(int s)
2806 struct lwip_sock *sock = get_socket(s);
2813 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
2814 if (socket_ipv4_multicast_memberships[i].sock == sock) {
2815 ip_addr_t multi_addr, if_addr;
2816 ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr);
2817 ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr);
2818 socket_ipv4_multicast_memberships[i].sock = NULL;
2819 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
2820 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
2822 netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE);
2826 #endif /* LWIP_IGMP */
2827 #endif /* LWIP_SOCKET */