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"
52 #include "lwip/priv/sockets_priv.h"
55 #include "lwip/igmp.h"
56 #include "lwip/inet.h"
60 #include "lwip/memp.h"
61 #include "lwip/pbuf.h"
62 #include "lwip/priv/tcpip_priv.h"
63 #if LWIP_CHECKSUM_ON_COPY
64 #include "lwip/inet_chksum.h"
69 /* If the netconn API is not required publicly, then we include the necessary
70 files here to get the implementation */
73 #define LWIP_NETCONN 1
78 #define LWIP_NETCONN 0
82 #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \
83 (sin)->sin_len = sizeof(struct sockaddr_in); \
84 (sin)->sin_family = AF_INET; \
85 (sin)->sin_port = lwip_htons((port)); \
86 inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \
87 memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0)
88 #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \
89 inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \
90 (port) = lwip_ntohs((sin)->sin_port); }while(0)
91 #endif /* LWIP_IPV4 */
94 #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \
95 (sin6)->sin6_len = sizeof(struct sockaddr_in6); \
96 (sin6)->sin6_family = AF_INET6; \
97 (sin6)->sin6_port = lwip_htons((port)); \
98 (sin6)->sin6_flowinfo = 0; \
99 inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \
100 (sin6)->sin6_scope_id = ip6_addr_zone(ipaddr); }while(0)
101 #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \
102 inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \
103 if (ip6_addr_has_scope(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { \
104 ip6_addr_set_zone(ip_2_ip6(ipaddr), (u8_t)((sin6)->sin6_scope_id)); \
106 (port) = lwip_ntohs((sin6)->sin6_port); }while(0)
107 #endif /* LWIP_IPV6 */
109 #if LWIP_IPV4 && LWIP_IPV6
110 static void sockaddr_to_ipaddr_port(const struct sockaddr
* sockaddr
, ip_addr_t
* ipaddr
, u16_t
* port
);
112 #define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \
113 ((namelen) == sizeof(struct sockaddr_in6)))
114 #define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \
115 ((name)->sa_family == AF_INET6))
116 #define SOCK_ADDR_TYPE_MATCH(name, sock) \
117 ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \
118 (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type))))
119 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \
120 if (IP_IS_V6(ipaddr)) { \
121 IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \
123 IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \
125 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port))
126 #define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \
127 (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6))
128 #elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */
129 #define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in6))
130 #define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET6)
131 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
132 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
133 IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port)
134 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
135 SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port)
136 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
137 #else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */
138 #define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in))
139 #define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET)
140 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
141 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
142 IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port)
143 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
144 SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port)
145 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
146 #endif /* LWIP_IPV6 */
148 #define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \
149 IS_SOCK_ADDR_TYPE_VALID(name))
150 #define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \
151 SOCK_ADDR_TYPE_MATCH(name, sock))
152 #define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0)
155 #define LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype) do { if ((optlen) < sizeof(opttype)) { return EINVAL; }}while(0)
156 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \
157 LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \
158 if ((sock)->conn == NULL) { return EINVAL; } }while(0)
159 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \
160 LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \
161 if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { return EINVAL; } }while(0)
162 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \
163 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \
164 if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { return ENOPROTOOPT; } }while(0)
167 #define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name) API_VAR_REF(name)
168 #define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name)
169 #define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name) API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name)
170 #if LWIP_MPU_COMPATIBLE
171 #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \
172 name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \
173 if (name == NULL) { \
174 sock_set_errno(sock, ENOMEM); \
177 #else /* LWIP_MPU_COMPATIBLE */
178 #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock)
179 #endif /* LWIP_MPU_COMPATIBLE */
181 #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
182 #define LWIP_SO_SNDRCVTIMEO_OPTTYPE int
183 #define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val))
184 #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((s32_t)*(const int*)(optval))
186 #define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval
187 #define LWIP_SO_SNDRCVTIMEO_SET(optval, val) do { \
189 ((struct timeval *)(optval))->tv_sec = (loc) / 1000U; \
190 ((struct timeval *)(optval))->tv_usec = ((loc) % 1000U) * 1000U; }while(0)
191 #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000U) + (((const struct timeval *)(optval))->tv_usec / 1000U))
194 #define NUM_SOCKETS MEMP_NUM_NETCONN
196 /** This is overridable for the rare case where more than 255 threads
197 * select on the same socket...
200 #define SELWAIT_T u8_t
203 union lwip_sock_lastdata
{
204 struct netbuf
*netbuf
;
208 /** Contains all internal pointers and states used for a socket */
210 /** sockets currently are built on netconns, each socket has one netconn */
211 struct netconn
*conn
;
212 /** last error that occurred on this socket */
214 /** data that was left from the previous read */
215 union lwip_sock_lastdata lastdata
;
216 #if LWIP_SOCKET_SELECT
217 /** number of times data was received, set by event_callback(),
218 tested by the receive and select functions */
220 /** number of times data was ACKed (free send buffer), set by event_callback(),
223 /** error happened for this socket, set by event_callback(), tested by select */
225 /** counter of how many threads are waiting for this socket using select */
226 SELWAIT_T select_waiting
;
227 #endif /* LWIP_SOCKET_SELECT */
228 #if LWIP_NETCONN_FULLDUPLEX
229 /* counter of how many threads are using a struct lwip_sock (not the 'int') */
231 /* status of pending close/delete actions */
232 u8_t fd_free_pending
;
233 #define LWIP_SOCK_FD_FREE_TCP 1
234 #define LWIP_SOCK_FD_FREE_FREE 2
238 #if LWIP_NETCONN_SEM_PER_THREAD
239 #define SELECT_SEM_T sys_sem_t*
240 #define SELECT_SEM_PTR(sem) (sem)
241 #else /* LWIP_NETCONN_SEM_PER_THREAD */
242 #define SELECT_SEM_T sys_sem_t
243 #define SELECT_SEM_PTR(sem) (&(sem))
244 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
246 /** Description for a task waiting in select */
247 struct lwip_select_cb
{
248 /** Pointer to the next waiting task */
249 struct lwip_select_cb
*next
;
250 /** Pointer to the previous waiting task */
251 struct lwip_select_cb
*prev
;
252 /** readset passed to select */
254 /** writeset passed to select */
256 /** unimplemented: exceptset passed to select */
258 /** don't signal the same semaphore twice: set to 1 when signalled */
260 /** semaphore to wake up a task waiting for select */
264 /** A struct sockaddr replacement that has the same alignment as sockaddr_in/
265 * sockaddr_in6 if instantiated.
267 union sockaddr_aligned
{
270 struct sockaddr_in6 sin6
;
271 #endif /* LWIP_IPV6 */
273 struct sockaddr_in sin
;
274 #endif /* LWIP_IPV4 */
278 /* Define the number of IPv4 multicast memberships, default is one per socket */
279 #ifndef LWIP_SOCKET_MAX_MEMBERSHIPS
280 #define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS
283 /* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when
284 a socket is closed */
285 struct lwip_socket_multicast_pair
{
287 struct lwip_sock
* sock
;
288 /** the interface address */
290 /** the group address */
291 ip4_addr_t multi_addr
;
294 struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships
[LWIP_SOCKET_MAX_MEMBERSHIPS
];
296 static int lwip_socket_register_membership(int s
, const ip4_addr_t
*if_addr
, const ip4_addr_t
*multi_addr
);
297 static void lwip_socket_unregister_membership(int s
, const ip4_addr_t
*if_addr
, const ip4_addr_t
*multi_addr
);
298 static void lwip_socket_drop_registered_memberships(int s
);
299 #endif /* LWIP_IGMP */
301 /** The global array of available sockets */
302 static struct lwip_sock sockets
[NUM_SOCKETS
];
303 /** The global list of tasks waiting for select */
304 static struct lwip_select_cb
*select_cb_list
;
305 /** This counter is increased from lwip_select when the list is changed
306 and checked in event_callback to see if it has changed. */
307 static volatile int select_cb_ctr
;
309 #define sock_set_errno(sk, e) do { \
310 const int sockerr = (e); \
312 set_errno(sockerr); \
315 /* Forward declaration of some functions */
316 #if LWIP_SOCKET_SELECT
317 static void event_callback(struct netconn
*conn
, enum netconn_evt evt
, u16_t len
);
318 #define DEFAULT_SOCKET_EVENTCB event_callback
320 #define DEFAULT_SOCKET_EVENTCB NULL
322 #if !LWIP_TCPIP_CORE_LOCKING
323 static void lwip_getsockopt_callback(void *arg
);
324 static void lwip_setsockopt_callback(void *arg
);
326 static int lwip_getsockopt_impl(int s
, int level
, int optname
, void *optval
, socklen_t
*optlen
);
327 static int lwip_setsockopt_impl(int s
, int level
, int optname
, const void *optval
, socklen_t optlen
);
328 static void free_socket(struct lwip_sock
*sock
, int is_tcp
);
330 #if LWIP_IPV4 && LWIP_IPV6
332 sockaddr_to_ipaddr_port(const struct sockaddr
* sockaddr
, ip_addr_t
* ipaddr
, u16_t
* port
)
334 if ((sockaddr
->sa_family
) == AF_INET6
) {
335 SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6
*)(const void*)(sockaddr
), ipaddr
, *port
);
336 ipaddr
->type
= IPADDR_TYPE_V6
;
338 SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in
*)(const void*)(sockaddr
), ipaddr
, *port
);
339 ipaddr
->type
= IPADDR_TYPE_V4
;
342 #endif /* LWIP_IPV4 && LWIP_IPV6 */
344 /** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */
346 lwip_socket_thread_init(void)
348 netconn_thread_init();
351 /** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */
353 lwip_socket_thread_cleanup(void)
355 netconn_thread_cleanup();
358 #if LWIP_NETCONN_FULLDUPLEX
359 /* Thread-safe increment of sock->fd_used, with overflow check */
361 sock_inc_used(struct lwip_sock
*sock
)
363 LWIP_ASSERT("sock != NULL", sock
!= NULL
);
364 SYS_ARCH_INC(sock
->fd_used
, 1);
365 LWIP_ASSERT("sock->fd_used != 0", sock
->fd_used
!= 0);
368 /* In full-duplex mode,sock->fd_used != 0 prevents a socket descriptor from being
369 * released (and possibly reused) when used from more than one thread
370 * (e.g. read-while-write or close-while-write, etc)
371 * This function is called at the end of functions using (try)get_socket*().
374 done_socket(struct lwip_sock
*sock
)
376 SYS_ARCH_DECL_PROTECT(lev
);
378 LWIP_ASSERT("sock != NULL", sock
!= NULL
);
380 SYS_ARCH_PROTECT(lev
);
381 LWIP_ASSERT("sock->fd_used > 0", sock
->fd_used
> 0);
382 if (--sock
->fd_used
== 0) {
383 if (sock
->fd_free_pending
) {
384 /* free the socket */
386 free_socket(sock
, sock
->fd_free_pending
& LWIP_SOCK_FD_FREE_TCP
);
389 SYS_ARCH_UNPROTECT(lev
);
391 #else /* LWIP_NETCONN_FULLDUPLEX */
392 #define sock_inc_used(sock)
393 #define done_socket(sock)
394 #endif /* LWIP_NETCONN_FULLDUPLEX */
396 /* Translate a socket 'int' into a pointer (only fails if the index is invalid) */
397 static struct lwip_sock
*
398 tryget_socket_unconn(int fd
)
400 int s
= fd
- LWIP_SOCKET_OFFSET
;
401 if ((s
< 0) || (s
>= NUM_SOCKETS
)) {
402 LWIP_DEBUGF(SOCKETS_DEBUG
, ("tryget_socket_unconn(%d): invalid\n", fd
));
405 sock_inc_used(&sockets
[s
]);
410 * Same as get_socket but doesn't set errno
412 * @param fd externally used socket index
413 * @return struct lwip_sock for the socket or NULL if not found
415 static struct lwip_sock
*
416 tryget_socket(int fd
)
418 struct lwip_sock
*sock
= tryget_socket_unconn(fd
);
429 * Map a externally used socket index to the internal socket representation.
431 * @param fd externally used socket index
432 * @return struct lwip_sock for the socket or NULL if not found
434 static struct lwip_sock
*
437 struct lwip_sock
*sock
= tryget_socket(fd
);
439 if ((fd
< LWIP_SOCKET_OFFSET
) || (fd
>= (LWIP_SOCKET_OFFSET
+ NUM_SOCKETS
))) {
440 LWIP_DEBUGF(SOCKETS_DEBUG
, ("get_socket(%d): invalid\n", fd
));
449 * Allocate a new socket for a given netconn.
451 * @param newconn the netconn for which to allocate a socket
452 * @param accepted 1 if socket has been created by accept(),
453 * 0 if socket has been created by socket()
454 * @return the index of the new socket; -1 on error
457 alloc_socket(struct netconn
*newconn
, int accepted
)
460 SYS_ARCH_DECL_PROTECT(lev
);
461 LWIP_UNUSED_ARG(accepted
);
463 /* allocate a new socket identifier */
464 for (i
= 0; i
< NUM_SOCKETS
; ++i
) {
465 /* Protect socket array */
466 SYS_ARCH_PROTECT(lev
);
467 if (!sockets
[i
].conn
) {
468 #if LWIP_NETCONN_FULLDUPLEX
469 if (sockets
[i
].fd_used
) {
472 sockets
[i
].fd_used
= 1;
473 sockets
[i
].fd_free_pending
= 0;
475 sockets
[i
].conn
= newconn
;
476 /* The socket is not yet known to anyone, so no need to protect
477 after having marked it as used. */
478 SYS_ARCH_UNPROTECT(lev
);
479 sockets
[i
].lastdata
.pbuf
= NULL
;
480 #if LWIP_SOCKET_SELECT
481 LWIP_ASSERT("sockets[i].select_waiting == 0", sockets
[i
].select_waiting
== 0);
482 sockets
[i
].rcvevent
= 0;
483 /* TCP sendbuf is empty, but the socket is not yet writable until connected
484 * (unless it has been created by accept()). */
485 sockets
[i
].sendevent
= (NETCONNTYPE_GROUP(newconn
->type
) == NETCONN_TCP
? (accepted
!= 0) : 1);
486 sockets
[i
].errevent
= 0;
487 #endif /* LWIP_SOCKET_SELECT */
489 return i
+ LWIP_SOCKET_OFFSET
;
491 SYS_ARCH_UNPROTECT(lev
);
496 /** Free a socket. The socket's netconn must have been
499 * @param sock the socket to free
500 * @param is_tcp != 0 for TCP sockets, used to free lastdata
503 free_socket(struct lwip_sock
*sock
, int is_tcp
)
505 union lwip_sock_lastdata lastdata
;
506 SYS_ARCH_DECL_PROTECT(lev
);
508 /* Protect socket array */
509 SYS_ARCH_PROTECT(lev
);
511 #if LWIP_NETCONN_FULLDUPLEX
512 LWIP_ASSERT("sock->fd_used > 0", sock
->fd_used
> 0);
513 if (--sock
->fd_used
> 0) {
514 sock
->fd_free_pending
= LWIP_SOCK_FD_FREE_FREE
| is_tcp
? LWIP_SOCK_FD_FREE_TCP
: 0;
515 SYS_ARCH_UNPROTECT(lev
);
520 lastdata
= sock
->lastdata
;
521 sock
->lastdata
.pbuf
= NULL
;
524 SYS_ARCH_UNPROTECT(lev
);
525 /* don't use 'sock' after this line, as another task might have allocated it */
527 if (lastdata
.pbuf
!= NULL
) {
529 pbuf_free(lastdata
.pbuf
);
531 netbuf_delete(lastdata
.netbuf
);
536 /* Below this, the well-known socket functions are implemented.
537 * Use google.com or opengroup.org to get a good description :-)
539 * Exceptions are documented!
543 lwip_accept(int s
, struct sockaddr
*addr
, socklen_t
*addrlen
)
545 struct lwip_sock
*sock
, *nsock
;
546 struct netconn
*newconn
;
552 SYS_ARCH_DECL_PROTECT(lev
);
554 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_accept(%d)...\n", s
));
555 sock
= get_socket(s
);
560 /* wait for a new connection */
561 err
= netconn_accept(sock
->conn
, &newconn
);
563 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s
, err
));
564 if (NETCONNTYPE_GROUP(netconn_type(sock
->conn
)) != NETCONN_TCP
) {
565 sock_set_errno(sock
, EOPNOTSUPP
);
566 } else if (err
== ERR_CLSD
) {
567 sock_set_errno(sock
, EINVAL
);
569 sock_set_errno(sock
, err_to_errno(err
));
574 LWIP_ASSERT("newconn != NULL", newconn
!= NULL
);
576 newsock
= alloc_socket(newconn
, 1);
578 netconn_delete(newconn
);
579 sock_set_errno(sock
, ENFILE
);
583 LWIP_ASSERT("invalid socket index", (newsock
>= LWIP_SOCKET_OFFSET
) && (newsock
< NUM_SOCKETS
+ LWIP_SOCKET_OFFSET
));
584 nsock
= &sockets
[newsock
- LWIP_SOCKET_OFFSET
];
586 /* See event_callback: If data comes in right away after an accept, even
587 * though the server task might not have created a new socket yet.
588 * In that case, newconn->socket is counted down (newconn->socket--),
589 * so nsock->rcvevent is >= 1 here!
591 SYS_ARCH_PROTECT(lev
);
592 recvevent
= (s16_t
)(-1 - newconn
->socket
);
593 newconn
->socket
= newsock
;
594 SYS_ARCH_UNPROTECT(lev
);
596 if (newconn
->callback
) {
597 while(recvevent
> 0) {
599 newconn
->callback(newconn
, NETCONN_EVT_RCVPLUS
, 0);
603 /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
604 * not be NULL if addr is valid.
606 if ((addr
!= NULL
) && (addrlen
!= NULL
)) {
607 union sockaddr_aligned tempaddr
;
608 /* get the IP address and port of the remote host */
609 err
= netconn_peer(newconn
, &naddr
, &port
);
611 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s
, err
));
612 netconn_delete(newconn
);
613 free_socket(nsock
, 1);
614 sock_set_errno(sock
, err_to_errno(err
));
619 IPADDR_PORT_TO_SOCKADDR(&tempaddr
, &naddr
, port
);
620 if (*addrlen
> tempaddr
.sa
.sa_len
) {
621 *addrlen
= tempaddr
.sa
.sa_len
;
623 MEMCPY(addr
, &tempaddr
, *addrlen
);
625 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_accept(%d) returning new sock=%d addr=", s
, newsock
));
626 ip_addr_debug_print_val(SOCKETS_DEBUG
, naddr
);
627 LWIP_DEBUGF(SOCKETS_DEBUG
, (" port=%"U16_F
"\n", port
));
629 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_accept(%d) returning new sock=%d", s
, newsock
));
632 sock_set_errno(sock
, 0);
639 lwip_bind(int s
, const struct sockaddr
*name
, socklen_t namelen
)
641 struct lwip_sock
*sock
;
642 ip_addr_t local_addr
;
646 sock
= get_socket(s
);
651 if (!SOCK_ADDR_TYPE_MATCH(name
, sock
)) {
652 /* sockaddr does not match socket type (IPv4/IPv6) */
653 sock_set_errno(sock
, err_to_errno(ERR_VAL
));
658 /* check size, family and alignment of 'name' */
659 LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen
) &&
660 IS_SOCK_ADDR_TYPE_VALID(name
) && IS_SOCK_ADDR_ALIGNED(name
)),
661 sock_set_errno(sock
, err_to_errno(ERR_ARG
)); return -1;);
662 LWIP_UNUSED_ARG(namelen
);
664 SOCKADDR_TO_IPADDR_PORT(name
, &local_addr
, local_port
);
665 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_bind(%d, addr=", s
));
666 ip_addr_debug_print_val(SOCKETS_DEBUG
, local_addr
);
667 LWIP_DEBUGF(SOCKETS_DEBUG
, (" port=%"U16_F
")\n", local_port
));
669 #if LWIP_IPV4 && LWIP_IPV6
670 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
671 if (IP_IS_V6_VAL(local_addr
) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr
))) {
672 unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr
), ip_2_ip6(&local_addr
));
673 IP_SET_TYPE_VAL(local_addr
, IPADDR_TYPE_V4
);
675 #endif /* LWIP_IPV4 && LWIP_IPV6 */
677 err
= netconn_bind(sock
->conn
, &local_addr
, local_port
);
680 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_bind(%d) failed, err=%d\n", s
, err
));
681 sock_set_errno(sock
, err_to_errno(err
));
686 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_bind(%d) succeeded\n", s
));
687 sock_set_errno(sock
, 0);
695 struct lwip_sock
*sock
;
699 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_close(%d)\n", s
));
701 sock
= get_socket(s
);
706 if (sock
->conn
!= NULL
) {
707 is_tcp
= NETCONNTYPE_GROUP(netconn_type(sock
->conn
)) == NETCONN_TCP
;
709 LWIP_ASSERT("sock->lastdata == NULL", sock
->lastdata
.pbuf
== NULL
);
713 /* drop all possibly joined IGMP memberships */
714 lwip_socket_drop_registered_memberships(s
);
715 #endif /* LWIP_IGMP */
717 err
= netconn_delete(sock
->conn
);
719 sock_set_errno(sock
, err_to_errno(err
));
724 free_socket(sock
, is_tcp
);
730 lwip_connect(int s
, const struct sockaddr
*name
, socklen_t namelen
)
732 struct lwip_sock
*sock
;
735 sock
= get_socket(s
);
740 if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name
, sock
)) {
741 /* sockaddr does not match socket type (IPv4/IPv6) */
742 sock_set_errno(sock
, err_to_errno(ERR_VAL
));
747 LWIP_UNUSED_ARG(namelen
);
748 if (name
->sa_family
== AF_UNSPEC
) {
749 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_connect(%d, AF_UNSPEC)\n", s
));
750 err
= netconn_disconnect(sock
->conn
);
752 ip_addr_t remote_addr
;
755 /* check size, family and alignment of 'name' */
756 LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen
) &&
757 IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name
) && IS_SOCK_ADDR_ALIGNED(name
),
758 sock_set_errno(sock
, err_to_errno(ERR_ARG
)); return -1;);
760 SOCKADDR_TO_IPADDR_PORT(name
, &remote_addr
, remote_port
);
761 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_connect(%d, addr=", s
));
762 ip_addr_debug_print_val(SOCKETS_DEBUG
, remote_addr
);
763 LWIP_DEBUGF(SOCKETS_DEBUG
, (" port=%"U16_F
")\n", remote_port
));
765 #if LWIP_IPV4 && LWIP_IPV6
766 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
767 if (IP_IS_V6_VAL(remote_addr
) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr
))) {
768 unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr
), ip_2_ip6(&remote_addr
));
769 IP_SET_TYPE_VAL(remote_addr
, IPADDR_TYPE_V4
);
771 #endif /* LWIP_IPV4 && LWIP_IPV6 */
773 err
= netconn_connect(sock
->conn
, &remote_addr
, remote_port
);
777 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_connect(%d) failed, err=%d\n", s
, err
));
778 sock_set_errno(sock
, err_to_errno(err
));
783 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_connect(%d) succeeded\n", s
));
784 sock_set_errno(sock
, 0);
790 * Set a socket into listen mode.
791 * The socket may not have been used for another connection previously.
793 * @param s the socket to set to listening mode
794 * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
795 * @return 0 on success, non-zero on failure
798 lwip_listen(int s
, int backlog
)
800 struct lwip_sock
*sock
;
803 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_listen(%d, backlog=%d)\n", s
, backlog
));
805 sock
= get_socket(s
);
810 /* limit the "backlog" parameter to fit in an u8_t */
811 backlog
= LWIP_MIN(LWIP_MAX(backlog
, 0), 0xff);
813 err
= netconn_listen_with_backlog(sock
->conn
, (u8_t
)backlog
);
816 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_listen(%d) failed, err=%d\n", s
, err
));
817 if (NETCONNTYPE_GROUP(netconn_type(sock
->conn
)) != NETCONN_TCP
) {
818 sock_set_errno(sock
, EOPNOTSUPP
);
820 sock_set_errno(sock
, err_to_errno(err
));
826 sock_set_errno(sock
, 0);
831 /* Helper function to loop over receiving pbufs from netconn
832 * until "len" bytes are received or we're otherwise done.
835 lwip_recv_tcp(struct lwip_sock
*sock
, void *mem
, size_t len
, int flags
)
837 u8_t apiflags
= NETCONN_NOAUTORCVD
;
841 LWIP_ASSERT("no socket given", sock
!= NULL
);
842 LWIP_ASSERT("this should be checked internally", NETCONNTYPE_GROUP(netconn_type(sock
->conn
)) == NETCONN_TCP
);
844 if (flags
& MSG_DONTWAIT
) {
845 apiflags
= NETCONN_DONTBLOCK
;
855 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_recv_tcp: top while sock->lastdata=%p\n", (void*)sock
->lastdata
.pbuf
));
856 /* Check if there is data left from the last recv operation. */
857 if (sock
->lastdata
.pbuf
) {
858 p
= sock
->lastdata
.pbuf
;
860 /* No data was left from the previous operation, so we try to get
861 some from the network. */
862 err
= netconn_recv_tcp_pbuf_flags(sock
->conn
, &p
, apiflags
);
863 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_recv_tcp: netconn_recv err=%d, pbuf=%p\n",
868 /* already received data, return that (this trusts in getting the same error from
869 netconn layer again next time netconn_recv is called) */
870 if (err
== ERR_CLSD
) {
871 /* closed but already received data, ensure select gets the FIN, too */
872 if (sock
->conn
->callback
!= NULL
) {
873 sock
->conn
->callback(sock
->conn
, NETCONN_EVT_RCVPLUS
, 0);
876 goto lwip_recv_tcp_done
;
878 /* We should really do some error checking here. */
879 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_recv_tcp: p == NULL, error is \"%s\"!\n",
881 sock_set_errno(sock
, err_to_errno(err
));
882 if (err
== ERR_CLSD
) {
888 LWIP_ASSERT("p != NULL", p
!= NULL
);
889 sock
->lastdata
.pbuf
= p
;
892 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_recv_tcp: buflen=%"U16_F
" recv_left=%d off=%d\n",
893 p
->tot_len
, recv_left
, recvd
));
895 if (recv_left
> p
->tot_len
) {
896 copylen
= p
->tot_len
;
898 copylen
= (u16_t
)recv_left
;
901 /* copy the contents of the received buffer into
902 the supplied memory pointer mem */
903 pbuf_copy_partial(p
, (u8_t
*)mem
+ recvd
, copylen
, 0);
907 /* TCP combines multiple pbufs for one recv */
908 LWIP_ASSERT("invalid copylen, len would underflow", recv_left
>= copylen
);
909 recv_left
-= copylen
;
911 /* Unless we peek the incoming message... */
912 if ((flags
& MSG_PEEK
) == 0) {
913 /* ... check if there is data left in the pbuf */
914 LWIP_ASSERT("invalid copylen", p
->tot_len
>= copylen
);
915 if (p
->tot_len
- copylen
> 0) {
916 /* If so, it should be saved in the sock structure for the next recv call.
917 We store the pbuf but hide/free the consumed data: */
918 sock
->lastdata
.pbuf
= pbuf_free_header(p
, copylen
);
919 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_recv_tcp: lastdata now pbuf=%p\n", (void*)sock
->lastdata
.pbuf
));
921 sock
->lastdata
.pbuf
= NULL
;
922 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_recv_tcp: deleting pbuf=%p\n", (void*)p
));
926 /* once we have some data to return, only add more if we don't need to wait */
927 apiflags
|= NETCONN_DONTBLOCK
;
928 /* @todo: do we need to support peeking more than one pbuf? */
929 } while ((recv_left
> 0) || (flags
& MSG_PEEK
));
932 /* ensure window update after copying all data */
933 netconn_tcp_recvd(sock
->conn
, recvd
);
935 sock_set_errno(sock
, 0);
939 /* Convert a netbuf's address data to struct sockaddr */
941 lwip_sock_make_addr(struct netconn
*conn
, ip_addr_t
*fromaddr
, u16_t port
,
942 struct sockaddr
*from
, socklen_t
*fromlen
)
944 union sockaddr_aligned saddr
;
946 LWIP_UNUSED_ARG(conn
);
948 #if LWIP_IPV4 && LWIP_IPV6
949 /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
950 if (NETCONNTYPE_ISIPV6(netconn_type(conn
)) && IP_IS_V4(fromaddr
)) {
951 ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr
), ip_2_ip4(fromaddr
));
952 IP_SET_TYPE(fromaddr
, IPADDR_TYPE_V6
);
954 #endif /* LWIP_IPV4 && LWIP_IPV6 */
956 LWIP_DEBUGF(SOCKETS_DEBUG
, (" addr="));
957 IPADDR_PORT_TO_SOCKADDR(&saddr
, fromaddr
, port
);
958 ip_addr_debug_print(SOCKETS_DEBUG
, fromaddr
);
959 LWIP_DEBUGF(SOCKETS_DEBUG
, (" port=%"U16_F
"", port
));
962 if (*fromlen
> saddr
.sa
.sa_len
) {
963 *fromlen
= saddr
.sa
.sa_len
;
965 MEMCPY(from
, &saddr
, *fromlen
);
970 lwip_recvfrom(int s
, void *mem
, size_t len
, int flags
,
971 struct sockaddr
*from
, socklen_t
*fromlen
)
973 struct lwip_sock
*sock
;
976 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_recvfrom(%d, %p, %"SZT_F
", 0x%x, ..)\n", s
, mem
, len
, flags
));
977 sock
= get_socket(s
);
981 if (NETCONNTYPE_GROUP(netconn_type(sock
->conn
)) == NETCONN_TCP
) {
982 ret
= lwip_recv_tcp(sock
, mem
, len
, flags
);
985 #endif /* !SOCKETS_DEBUG */
987 /* get remote addr/port from tcp_pcb */
990 netconn_getaddr(sock
->conn
, &tmpaddr
, &port
, 0);
991 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_recvfrom(%d):", s
));
992 lwip_sock_make_addr(sock
->conn
, &tmpaddr
, port
, from
, fromlen
);
993 LWIP_DEBUGF(SOCKETS_DEBUG
, (" len=%d\n", ret
));
999 u16_t buflen
, copylen
;
1003 if (flags
& MSG_DONTWAIT
) {
1004 apiflags
= NETCONN_DONTBLOCK
;
1009 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_recvfrom[UDP/RAW]: top sock->lastdata=%p\n", (void*)sock
->lastdata
.netbuf
));
1010 /* Check if there is data left from the last recv operation. */
1011 buf
= sock
->lastdata
.netbuf
;
1013 /* No data was left from the previous operation, so we try to get
1014 some from the network. */
1015 err
= netconn_recv_udp_raw_netbuf_flags(sock
->conn
, &buf
, apiflags
);
1016 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_recvfrom[UDP/RAW]: netconn_recv err=%d, netbuf=%p\n",
1019 if (err
!= ERR_OK
) {
1020 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_recvfrom[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n",
1021 s
, lwip_strerr(err
)));
1022 sock_set_errno(sock
, err_to_errno(err
));
1026 LWIP_ASSERT("buf != NULL", buf
!= NULL
);
1027 sock
->lastdata
.netbuf
= buf
;
1030 buflen
= buf
->p
->tot_len
;
1031 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_recvfrom: buflen=%"U16_F
" len=%"SZT_F
"\n",
1037 copylen
= (u16_t
)len
;
1040 /* copy the contents of the received buffer into
1041 the supplied memory pointer mem */
1042 pbuf_copy_partial(buf
->p
, (u8_t
*)mem
, copylen
, 0);
1045 /* Check to see from where the data was.*/
1047 if (from
&& fromlen
)
1048 #endif /* !SOCKETS_DEBUG */
1050 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_recvfrom(%d):", s
));
1051 lwip_sock_make_addr(sock
->conn
, netbuf_fromaddr(buf
), netbuf_fromport(buf
), from
, fromlen
);
1052 LWIP_DEBUGF(SOCKETS_DEBUG
, (" len=%d\n", ret
));
1055 /* If we don't peek the incoming message: zero lastdata pointer and free the netbuf */
1056 if ((flags
& MSG_PEEK
) == 0) {
1057 sock
->lastdata
.netbuf
= NULL
;
1062 sock_set_errno(sock
, 0);
1068 lwip_read(int s
, void *mem
, size_t len
)
1070 return lwip_recvfrom(s
, mem
, len
, 0, NULL
, NULL
);
1074 lwip_recv(int s
, void *mem
, size_t len
, int flags
)
1076 return lwip_recvfrom(s
, mem
, len
, flags
, NULL
, NULL
);
1080 lwip_send(int s
, const void *data
, size_t size
, int flags
)
1082 struct lwip_sock
*sock
;
1087 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_send(%d, data=%p, size=%"SZT_F
", flags=0x%x)\n",
1088 s
, data
, size
, flags
));
1090 sock
= get_socket(s
);
1095 if (NETCONNTYPE_GROUP(netconn_type(sock
->conn
)) != NETCONN_TCP
) {
1096 #if (LWIP_UDP || LWIP_RAW)
1098 return lwip_sendto(s
, data
, size
, flags
, NULL
, 0);
1099 #else /* (LWIP_UDP || LWIP_RAW) */
1100 sock_set_errno(sock
, err_to_errno(ERR_ARG
));
1103 #endif /* (LWIP_UDP || LWIP_RAW) */
1106 write_flags
= NETCONN_COPY
|
1107 ((flags
& MSG_MORE
) ? NETCONN_MORE
: 0) |
1108 ((flags
& MSG_DONTWAIT
) ? NETCONN_DONTBLOCK
: 0);
1110 err
= netconn_write_partly(sock
->conn
, data
, size
, write_flags
, &written
);
1112 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_send(%d) err=%d written=%"SZT_F
"\n", s
, err
, written
));
1113 sock_set_errno(sock
, err_to_errno(err
));
1115 return (err
== ERR_OK
? (int)written
: -1);
1119 lwip_sendmsg(int s
, const struct msghdr
*msg
, int flags
)
1121 struct lwip_sock
*sock
;
1130 sock
= get_socket(s
);
1135 LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg
!= NULL
,
1136 sock_set_errno(sock
, err_to_errno(ERR_ARG
)); return -1;);
1137 LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", msg
->msg_iov
!= NULL
,
1138 sock_set_errno(sock
, err_to_errno(ERR_ARG
)); return -1;);
1139 LWIP_ERROR("lwip_sendmsg: maximum iovs exceeded", (msg
->msg_iovlen
> 0) && (msg
->msg_iovlen
<= IOV_MAX
),
1140 sock_set_errno(sock
, EMSGSIZE
); return -1;);
1141 LWIP_ERROR("lwip_sendmsg: unsupported flags", ((flags
== 0) || (flags
== MSG_NOSIGNAL
)),
1142 sock_set_errno(sock
, EOPNOTSUPP
); return -1;);
1144 LWIP_UNUSED_ARG(msg
->msg_control
);
1145 LWIP_UNUSED_ARG(msg
->msg_controllen
);
1146 LWIP_UNUSED_ARG(msg
->msg_flags
);
1148 if (NETCONNTYPE_GROUP(netconn_type(sock
->conn
)) == NETCONN_TCP
) {
1150 write_flags
= NETCONN_COPY
|
1151 ((flags
& MSG_MORE
) ? NETCONN_MORE
: 0) |
1152 ((flags
& MSG_DONTWAIT
) ? NETCONN_DONTBLOCK
: 0);
1155 err
= netconn_write_vectors_partly(sock
->conn
, (struct netvector
*)msg
->msg_iov
, (u16_t
)msg
->msg_iovlen
, write_flags
, &written
);
1156 sock_set_errno(sock
, err_to_errno(err
));
1158 return (err
== ERR_OK
? (int)written
: -1);
1159 #else /* LWIP_TCP */
1160 sock_set_errno(sock
, err_to_errno(ERR_ARG
));
1163 #endif /* LWIP_TCP */
1165 /* else, UDP and RAW NETCONNs */
1166 #if LWIP_UDP || LWIP_RAW
1168 struct netbuf chain_buf
;
1170 LWIP_UNUSED_ARG(flags
);
1171 LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg
->msg_name
== NULL
) && (msg
->msg_namelen
== 0)) ||
1172 IS_SOCK_ADDR_LEN_VALID(msg
->msg_namelen
)) ,
1173 sock_set_errno(sock
, err_to_errno(ERR_ARG
)); return -1;);
1175 /* initialize chain buffer with destination */
1176 memset(&chain_buf
, 0, sizeof(struct netbuf
));
1177 if (msg
->msg_name
) {
1179 SOCKADDR_TO_IPADDR_PORT((const struct sockaddr
*)msg
->msg_name
, &chain_buf
.addr
, remote_port
);
1180 netbuf_fromport(&chain_buf
) = remote_port
;
1182 #if LWIP_NETIF_TX_SINGLE_PBUF
1183 for (i
= 0; i
< msg
->msg_iovlen
; i
++) {
1184 size
+= msg
->msg_iov
[i
].iov_len
;
1185 if ((msg
->msg_iov
[i
].iov_len
> INT_MAX
) || (size
< (int)msg
->msg_iov
[i
].iov_len
)) {
1187 goto sendmsg_emsgsize
;
1190 if (size
> 0xFFFF) {
1192 goto sendmsg_emsgsize
;
1194 /* Allocate a new netbuf and copy the data into it. */
1195 if (netbuf_alloc(&chain_buf
, (u16_t
)size
) == NULL
) {
1198 /* flatten the IO vectors */
1200 for (i
= 0; i
< msg
->msg_iovlen
; i
++) {
1201 MEMCPY(&((u8_t
*)chain_buf
.p
->payload
)[offset
], msg
->msg_iov
[i
].iov_base
, msg
->msg_iov
[i
].iov_len
);
1202 offset
+= msg
->msg_iov
[i
].iov_len
;
1204 #if LWIP_CHECKSUM_ON_COPY
1206 /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */
1207 u16_t chksum
= ~inet_chksum_pbuf(chain_buf
.p
);
1208 netbuf_set_chksum(&chain_buf
, chksum
);
1210 #endif /* LWIP_CHECKSUM_ON_COPY */
1213 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
1214 /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain
1215 manually to avoid having to allocate, chain, and delete a netbuf for each iov */
1216 for (i
= 0; i
< msg
->msg_iovlen
; i
++) {
1218 if (msg
->msg_iov
[i
].iov_len
> 0xFFFF) {
1220 goto sendmsg_emsgsize
;
1222 p
= pbuf_alloc(PBUF_TRANSPORT
, 0, PBUF_REF
);
1224 err
= ERR_MEM
; /* let netbuf_delete() cleanup chain_buf */
1227 p
->payload
= msg
->msg_iov
[i
].iov_base
;
1228 p
->len
= p
->tot_len
= (u16_t
)msg
->msg_iov
[i
].iov_len
;
1229 /* netbuf empty, add new pbuf */
1230 if (chain_buf
.p
== NULL
) {
1231 chain_buf
.p
= chain_buf
.ptr
= p
;
1232 /* add pbuf to existing pbuf chain */
1234 if (chain_buf
.p
->tot_len
+ p
->len
> 0xffff) {
1237 goto sendmsg_emsgsize
;
1239 pbuf_cat(chain_buf
.p
, p
);
1242 /* save size of total chain */
1243 if (err
== ERR_OK
) {
1244 size
= netbuf_len(&chain_buf
);
1246 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
1248 if (err
== ERR_OK
) {
1249 #if LWIP_IPV4 && LWIP_IPV6
1250 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
1251 if (IP_IS_V6_VAL(chain_buf
.addr
) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf
.addr
))) {
1252 unmap_ipv4_mapped_ipv6(ip_2_ip4(&chain_buf
.addr
), ip_2_ip6(&chain_buf
.addr
));
1253 IP_SET_TYPE_VAL(chain_buf
.addr
, IPADDR_TYPE_V4
);
1255 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1258 err
= netconn_send(sock
->conn
, &chain_buf
);
1261 /* deallocated the buffer */
1262 netbuf_free(&chain_buf
);
1264 sock_set_errno(sock
, err_to_errno(err
));
1266 return (err
== ERR_OK
? size
: -1);
1268 sock_set_errno(sock
, EMSGSIZE
);
1269 netbuf_free(&chain_buf
);
1273 #else /* LWIP_UDP || LWIP_RAW */
1274 sock_set_errno(sock
, err_to_errno(ERR_ARG
));
1277 #endif /* LWIP_UDP || LWIP_RAW */
1281 lwip_sendto(int s
, const void *data
, size_t size
, int flags
,
1282 const struct sockaddr
*to
, socklen_t tolen
)
1284 struct lwip_sock
*sock
;
1290 sock
= get_socket(s
);
1295 if (NETCONNTYPE_GROUP(netconn_type(sock
->conn
)) == NETCONN_TCP
) {
1298 return lwip_send(s
, data
, size
, flags
);
1299 #else /* LWIP_TCP */
1300 LWIP_UNUSED_ARG(flags
);
1301 sock_set_errno(sock
, err_to_errno(ERR_ARG
));
1304 #endif /* LWIP_TCP */
1307 if (size
> 0xFFFF) {
1308 /* cannot fit into one datagram (at least for us) */
1309 sock_set_errno(sock
, EMSGSIZE
);
1313 short_size
= (u16_t
)size
;
1314 LWIP_ERROR("lwip_sendto: invalid address", (((to
== NULL
) && (tolen
== 0)) ||
1315 (IS_SOCK_ADDR_LEN_VALID(tolen
) &&
1316 IS_SOCK_ADDR_TYPE_VALID(to
) && IS_SOCK_ADDR_ALIGNED(to
))),
1317 sock_set_errno(sock
, err_to_errno(ERR_ARG
)); return -1;);
1318 LWIP_UNUSED_ARG(tolen
);
1320 /* initialize a buffer */
1321 buf
.p
= buf
.ptr
= NULL
;
1322 #if LWIP_CHECKSUM_ON_COPY
1324 #endif /* LWIP_CHECKSUM_ON_COPY */
1326 SOCKADDR_TO_IPADDR_PORT(to
, &buf
.addr
, remote_port
);
1329 ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock
->conn
)), &buf
.addr
);
1331 netbuf_fromport(&buf
) = remote_port
;
1334 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_sendto(%d, data=%p, short_size=%"U16_F
", flags=0x%x to=",
1335 s
, data
, short_size
, flags
));
1336 ip_addr_debug_print(SOCKETS_DEBUG
, &buf
.addr
);
1337 LWIP_DEBUGF(SOCKETS_DEBUG
, (" port=%"U16_F
"\n", remote_port
));
1339 /* make the buffer point to the data that should be sent */
1340 #if LWIP_NETIF_TX_SINGLE_PBUF
1341 /* Allocate a new netbuf and copy the data into it. */
1342 if (netbuf_alloc(&buf
, short_size
) == NULL
) {
1345 #if LWIP_CHECKSUM_ON_COPY
1346 if (NETCONNTYPE_GROUP(netconn_type(sock
->conn
)) != NETCONN_RAW
) {
1347 u16_t chksum
= LWIP_CHKSUM_COPY(buf
.p
->payload
, data
, short_size
);
1348 netbuf_set_chksum(&buf
, chksum
);
1350 #endif /* LWIP_CHECKSUM_ON_COPY */
1352 MEMCPY(buf
.p
->payload
, data
, short_size
);
1356 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
1357 err
= netbuf_ref(&buf
, data
, short_size
);
1358 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
1359 if (err
== ERR_OK
) {
1360 #if LWIP_IPV4 && LWIP_IPV6
1361 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
1362 if (IP_IS_V6_VAL(buf
.addr
) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf
.addr
))) {
1363 unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf
.addr
), ip_2_ip6(&buf
.addr
));
1364 IP_SET_TYPE_VAL(buf
.addr
, IPADDR_TYPE_V4
);
1366 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1369 err
= netconn_send(sock
->conn
, &buf
);
1372 /* deallocated the buffer */
1375 sock_set_errno(sock
, err_to_errno(err
));
1377 return (err
== ERR_OK
? short_size
: -1);
1381 lwip_socket(int domain
, int type
, int protocol
)
1383 struct netconn
*conn
;
1386 LWIP_UNUSED_ARG(domain
); /* @todo: check this */
1388 /* create a netconn */
1391 conn
= netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain
, NETCONN_RAW
),
1392 (u8_t
)protocol
, DEFAULT_SOCKET_EVENTCB
);
1393 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_socket(%s, SOCK_RAW, %d) = ",
1394 domain
== PF_INET
? "PF_INET" : "UNKNOWN", protocol
));
1397 conn
= netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain
,
1398 ((protocol
== IPPROTO_UDPLITE
) ? NETCONN_UDPLITE
: NETCONN_UDP
)) ,
1399 DEFAULT_SOCKET_EVENTCB
);
1400 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
1401 domain
== PF_INET
? "PF_INET" : "UNKNOWN", protocol
));
1404 conn
= netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain
, NETCONN_TCP
), DEFAULT_SOCKET_EVENTCB
);
1405 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
1406 domain
== PF_INET
? "PF_INET" : "UNKNOWN", protocol
));
1409 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
1410 domain
, type
, protocol
));
1416 LWIP_DEBUGF(SOCKETS_DEBUG
, ("-1 / ENOBUFS (could not create netconn)\n"));
1421 i
= alloc_socket(conn
, 0);
1424 netconn_delete(conn
);
1429 done_socket(&sockets
[i
- LWIP_SOCKET_OFFSET
]);
1430 LWIP_DEBUGF(SOCKETS_DEBUG
, ("%d\n", i
));
1436 lwip_write(int s
, const void *data
, size_t size
)
1438 return lwip_send(s
, data
, size
, 0);
1442 lwip_writev(int s
, const struct iovec
*iov
, int iovcnt
)
1446 msg
.msg_name
= NULL
;
1447 msg
.msg_namelen
= 0;
1448 /* Hack: we have to cast via number to cast from 'const' pointer to non-const.
1449 Blame the opengroup standard for this inconsistency. */
1450 msg
.msg_iov
= LWIP_CONST_CAST(struct iovec
*, iov
);
1451 msg
.msg_iovlen
= iovcnt
;
1452 msg
.msg_control
= NULL
;
1453 msg
.msg_controllen
= 0;
1455 return lwip_sendmsg(s
, &msg
, 0);
1458 #if LWIP_SOCKET_SELECT
1460 * Go through the readset and writeset lists and see which socket of the sockets
1461 * set in the sets has events. On return, readset, writeset and exceptset have
1462 * the sockets enabled that had events.
1464 * @param maxfdp1 the highest socket index in the sets
1465 * @param readset_in set of sockets to check for read events
1466 * @param writeset_in set of sockets to check for write events
1467 * @param exceptset_in set of sockets to check for error events
1468 * @param readset_out set of sockets that had read events
1469 * @param writeset_out set of sockets that had write events
1470 * @param exceptset_out set os sockets that had error events
1471 * @return number of sockets that had events (read/write/exception) (>= 0)
1474 lwip_selscan(int maxfdp1
, fd_set
*readset_in
, fd_set
*writeset_in
, fd_set
*exceptset_in
,
1475 fd_set
*readset_out
, fd_set
*writeset_out
, fd_set
*exceptset_out
)
1478 fd_set lreadset
, lwriteset
, lexceptset
;
1479 struct lwip_sock
*sock
;
1480 SYS_ARCH_DECL_PROTECT(lev
);
1483 FD_ZERO(&lwriteset
);
1484 FD_ZERO(&lexceptset
);
1486 /* Go through each socket in each list to count number of sockets which
1488 for (i
= LWIP_SOCKET_OFFSET
; i
< maxfdp1
; i
++) {
1489 /* if this FD is not in the set, continue */
1490 if (!(readset_in
&& FD_ISSET(i
, readset_in
)) &&
1491 !(writeset_in
&& FD_ISSET(i
, writeset_in
)) &&
1492 !(exceptset_in
&& FD_ISSET(i
, exceptset_in
))) {
1495 /* First get the socket's status (protected)... */
1496 SYS_ARCH_PROTECT(lev
);
1497 sock
= tryget_socket_unconn(i
);
1499 void* lastdata
= sock
->lastdata
.pbuf
;
1500 s16_t rcvevent
= sock
->rcvevent
;
1501 u16_t sendevent
= sock
->sendevent
;
1502 u16_t errevent
= sock
->errevent
;
1503 SYS_ARCH_UNPROTECT(lev
);
1505 /* ... then examine it: */
1506 /* See if netconn of this socket is ready for read */
1507 if (readset_in
&& FD_ISSET(i
, readset_in
) && ((lastdata
!= NULL
) || (rcvevent
> 0))) {
1508 FD_SET(i
, &lreadset
);
1509 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_selscan: fd=%d ready for reading\n", i
));
1512 /* See if netconn of this socket is ready for write */
1513 if (writeset_in
&& FD_ISSET(i
, writeset_in
) && (sendevent
!= 0)) {
1514 FD_SET(i
, &lwriteset
);
1515 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_selscan: fd=%d ready for writing\n", i
));
1518 /* See if netconn of this socket had an error */
1519 if (exceptset_in
&& FD_ISSET(i
, exceptset_in
) && (errevent
!= 0)) {
1520 FD_SET(i
, &lexceptset
);
1521 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_selscan: fd=%d ready for exception\n", i
));
1526 SYS_ARCH_UNPROTECT(lev
);
1527 /* no a valid open socket */
1531 /* copy local sets to the ones provided as arguments */
1532 *readset_out
= lreadset
;
1533 *writeset_out
= lwriteset
;
1534 *exceptset_out
= lexceptset
;
1536 LWIP_ASSERT("nready >= 0", nready
>= 0);
1540 #if LWIP_NETCONN_FULLDUPLEX
1541 /* Mark all of the set sockets in one of the three fdsets passed to select as used.
1542 * All sockets are marked (and later unmarked), whether they are open or not.
1543 * This is OK as lwip_selscan aborts select when non-open sockets are found.
1546 lwip_select_inc_sockets_used_set(int maxfdp
, fd_set
*fdset
, fd_set
*used_sockets
)
1548 SYS_ARCH_DECL_PROTECT(lev
);
1551 for (i
= LWIP_SOCKET_OFFSET
; i
< maxfdp
; i
++) {
1552 /* if this FD is in the set, lock it (unless already done) */
1553 if (FD_ISSET(i
, fdset
) && !FD_ISSET(i
, used_sockets
)) {
1554 struct lwip_sock
*sock
;
1555 SYS_ARCH_PROTECT(lev
);
1556 sock
= tryget_socket_unconn(i
);
1558 sock_inc_used(sock
);
1559 FD_SET(i
, used_sockets
);
1561 SYS_ARCH_UNPROTECT(lev
);
1567 /* Mark all sockets passed to select as used to prevent them from being freed
1568 * from other threads while select is running.
1569 * Marked sockets are added to 'used_sockets' to mark them only once an be able
1570 * to unmark them correctly.
1573 lwip_select_inc_sockets_used(int maxfdp
, fd_set
*fdset1
, fd_set
*fdset2
, fd_set
*fdset3
, fd_set
*used_sockets
)
1575 FD_ZERO(used_sockets
);
1576 lwip_select_inc_sockets_used_set(maxfdp
, fdset1
, used_sockets
);
1577 lwip_select_inc_sockets_used_set(maxfdp
, fdset2
, used_sockets
);
1578 lwip_select_inc_sockets_used_set(maxfdp
, fdset3
, used_sockets
);
1581 /* Let go all sockets that were marked as used when starting select */
1583 lwip_select_dec_sockets_used(int maxfdp
, fd_set
*used_sockets
)
1586 for (i
= LWIP_SOCKET_OFFSET
; i
< maxfdp
; i
++) {
1587 /* if this FD is not in the set, continue */
1588 if (FD_ISSET(i
, used_sockets
)) {
1589 struct lwip_sock
*sock
= tryget_socket_unconn(i
);
1590 LWIP_ASSERT("socket gone at the end of select", sock
!= NULL
);
1597 #else /* LWIP_NETCONN_FULLDUPLEX */
1598 #define lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, used_sockets)
1599 #define lwip_select_dec_sockets_used(maxfdp1, used_sockets)
1600 #endif /* LWIP_NETCONN_FULLDUPLEX */
1603 lwip_select(int maxfdp1
, fd_set
*readset
, fd_set
*writeset
, fd_set
*exceptset
,
1604 struct timeval
*timeout
)
1608 fd_set lreadset
, lwriteset
, lexceptset
;
1610 struct lwip_select_cb select_cb
;
1613 #if LWIP_NETCONN_SEM_PER_THREAD
1616 #if LWIP_NETCONN_FULLDUPLEX
1617 fd_set used_sockets
;
1619 SYS_ARCH_DECL_PROTECT(lev
);
1621 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F
" tvusec=%"S32_F
")\n",
1622 maxfdp1
, (void *)readset
, (void *) writeset
, (void *) exceptset
,
1623 timeout
? (s32_t
)timeout
->tv_sec
: (s32_t
)-1,
1624 timeout
? (s32_t
)timeout
->tv_usec
: (s32_t
)-1));
1626 if ((maxfdp1
< 0) || (maxfdp1
> (FD_SETSIZE
+ LWIP_SOCKET_OFFSET
))) {
1631 lwip_select_inc_sockets_used(maxfdp1
, readset
, writeset
, exceptset
, &used_sockets
);
1633 /* Go through each socket in each list to count number of sockets which
1635 nready
= lwip_selscan(maxfdp1
, readset
, writeset
, exceptset
, &lreadset
, &lwriteset
, &lexceptset
);
1642 /* If we don't have any current events, then suspend if we are supposed to */
1644 if (timeout
&& timeout
->tv_sec
== 0 && timeout
->tv_usec
== 0) {
1645 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_select: no timeout, returning 0\n"));
1646 /* This is OK as the local fdsets are empty and nready is zero,
1647 or we would have returned earlier. */
1648 goto return_copy_fdsets
;
1651 /* None ready: add our semaphore to list:
1652 We don't actually need any dynamic memory. Our entry on the
1653 list is only valid while we are in this function, so it's ok
1654 to use local variables. */
1656 select_cb
.next
= NULL
;
1657 select_cb
.prev
= NULL
;
1658 select_cb
.readset
= readset
;
1659 select_cb
.writeset
= writeset
;
1660 select_cb
.exceptset
= exceptset
;
1661 select_cb
.sem_signalled
= 0;
1662 #if LWIP_NETCONN_SEM_PER_THREAD
1663 select_cb
.sem
= LWIP_NETCONN_THREAD_SEM_GET();
1664 #else /* LWIP_NETCONN_SEM_PER_THREAD */
1665 if (sys_sem_new(&select_cb
.sem
, 0) != ERR_OK
) {
1666 /* failed to create semaphore */
1668 lwip_select_dec_sockets_used(maxfdp1
, &used_sockets
);
1671 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
1673 /* Protect the select_cb_list */
1674 SYS_ARCH_PROTECT(lev
);
1676 /* Put this select_cb on top of list */
1677 select_cb
.next
= select_cb_list
;
1678 if (select_cb_list
!= NULL
) {
1679 select_cb_list
->prev
= &select_cb
;
1681 select_cb_list
= &select_cb
;
1682 /* Increasing this counter tells event_callback that the list has changed. */
1685 /* Now we can safely unprotect */
1686 SYS_ARCH_UNPROTECT(lev
);
1688 /* Increase select_waiting for each socket we are interested in */
1690 for (i
= LWIP_SOCKET_OFFSET
; i
< maxfdp1
; i
++) {
1691 if ((readset
&& FD_ISSET(i
, readset
)) ||
1692 (writeset
&& FD_ISSET(i
, writeset
)) ||
1693 (exceptset
&& FD_ISSET(i
, exceptset
))) {
1694 struct lwip_sock
*sock
;
1695 SYS_ARCH_PROTECT(lev
);
1696 sock
= tryget_socket_unconn(i
);
1698 sock
->select_waiting
++;
1699 LWIP_ASSERT("sock->select_waiting > 0", sock
->select_waiting
> 0);
1702 /* Not a valid socket */
1705 SYS_ARCH_UNPROTECT(lev
);
1708 SYS_ARCH_UNPROTECT(lev
);
1713 /* Call lwip_selscan again: there could have been events between
1714 the last scan (without us on the list) and putting us on the list! */
1715 nready
= lwip_selscan(maxfdp1
, readset
, writeset
, exceptset
, &lreadset
, &lwriteset
, &lexceptset
);
1717 /* Still none ready, just wait to be woken */
1722 msectimeout
= ((timeout
->tv_sec
* 1000) + ((timeout
->tv_usec
+ 500)/1000));
1723 if (msectimeout
== 0) {
1724 /* Wait 1ms at least (0 means wait forever) */
1729 waitres
= sys_arch_sem_wait(SELECT_SEM_PTR(select_cb
.sem
), msectimeout
);
1730 #if LWIP_NETCONN_SEM_PER_THREAD
1736 /* Decrease select_waiting for each socket we are interested in */
1737 for (i
= LWIP_SOCKET_OFFSET
; i
< maxfdp2
; i
++) {
1738 if ((readset
&& FD_ISSET(i
, readset
)) ||
1739 (writeset
&& FD_ISSET(i
, writeset
)) ||
1740 (exceptset
&& FD_ISSET(i
, exceptset
))) {
1741 struct lwip_sock
*sock
;
1742 SYS_ARCH_PROTECT(lev
);
1743 sock
= tryget_socket_unconn(i
);
1745 /* for now, handle select_waiting==0... */
1746 LWIP_ASSERT("sock->select_waiting > 0", sock
->select_waiting
> 0);
1747 if (sock
->select_waiting
> 0) {
1748 sock
->select_waiting
--;
1752 /* Not a valid socket */
1755 SYS_ARCH_UNPROTECT(lev
);
1758 /* Take us off the list */
1759 SYS_ARCH_PROTECT(lev
);
1760 if (select_cb
.next
!= NULL
) {
1761 select_cb
.next
->prev
= select_cb
.prev
;
1763 if (select_cb_list
== &select_cb
) {
1764 LWIP_ASSERT("select_cb.prev == NULL", select_cb
.prev
== NULL
);
1765 select_cb_list
= select_cb
.next
;
1767 LWIP_ASSERT("select_cb.prev != NULL", select_cb
.prev
!= NULL
);
1768 select_cb
.prev
->next
= select_cb
.next
;
1770 /* Increasing this counter tells event_callback that the list has changed. */
1772 SYS_ARCH_UNPROTECT(lev
);
1774 #if LWIP_NETCONN_SEM_PER_THREAD
1775 if (select_cb
.sem_signalled
&& (!waited
|| (waitres
== SYS_ARCH_TIMEOUT
))) {
1776 /* don't leave the thread-local semaphore signalled */
1777 sys_arch_sem_wait(select_cb
.sem
, 1);
1779 #else /* LWIP_NETCONN_SEM_PER_THREAD */
1780 sys_sem_free(&select_cb
.sem
);
1781 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
1784 /* This happens when a socket got closed while waiting */
1786 lwip_select_dec_sockets_used(maxfdp1
, &used_sockets
);
1790 if (waitres
== SYS_ARCH_TIMEOUT
) {
1792 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_select: timeout expired\n"));
1793 /* This is OK as the local fdsets are empty and nready is zero,
1794 or we would have returned earlier. */
1795 goto return_copy_fdsets
;
1798 /* See what's set */
1799 nready
= lwip_selscan(maxfdp1
, readset
, writeset
, exceptset
, &lreadset
, &lwriteset
, &lexceptset
);
1802 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_select: nready=%d\n", nready
));
1804 lwip_select_dec_sockets_used(maxfdp1
, &used_sockets
);
1807 *readset
= lreadset
;
1810 *writeset
= lwriteset
;
1813 *exceptset
= lexceptset
;
1819 * Callback registered in the netconn layer for each socket-netconn.
1820 * Processes recvevent (data available) and wakes up tasks waiting for select.
1823 event_callback(struct netconn
*conn
, enum netconn_evt evt
, u16_t len
)
1826 struct lwip_sock
*sock
;
1827 struct lwip_select_cb
*scb
;
1828 int last_select_cb_ctr
;
1829 SYS_ARCH_DECL_PROTECT(lev
);
1831 LWIP_UNUSED_ARG(len
);
1837 /* Data comes in right away after an accept, even though
1838 * the server task might not have created a new socket yet.
1839 * Just count down (or up) if that's the case and we
1840 * will use the data later. Note that only receive events
1841 * can happen before the new socket is set up. */
1842 SYS_ARCH_PROTECT(lev
);
1843 if (conn
->socket
< 0) {
1844 if (evt
== NETCONN_EVT_RCVPLUS
) {
1845 /* conn->socket is -1 on initialization
1846 lwip_accept adjusts sock->recvevent if conn->socket < -1 */
1849 SYS_ARCH_UNPROTECT(lev
);
1853 SYS_ARCH_UNPROTECT(lev
);
1856 sock
= get_socket(s
);
1864 SYS_ARCH_PROTECT(lev
);
1865 /* Set event as required */
1867 case NETCONN_EVT_RCVPLUS
:
1870 case NETCONN_EVT_RCVMINUS
:
1873 case NETCONN_EVT_SENDPLUS
:
1874 sock
->sendevent
= 1;
1876 case NETCONN_EVT_SENDMINUS
:
1877 sock
->sendevent
= 0;
1879 case NETCONN_EVT_ERROR
:
1883 LWIP_ASSERT("unknown event", 0);
1887 if (sock
->select_waiting
== 0) {
1888 /* noone is waiting for this socket, no need to check select_cb_list */
1889 SYS_ARCH_UNPROTECT(lev
);
1894 /* Now decide if anyone is waiting for this socket */
1895 /* NOTE: This code goes through the select_cb_list list multiple times
1896 ONLY IF a select was actually waiting. We go through the list the number
1897 of waiting select calls + 1. This list is expected to be small. */
1899 /* At this point, SYS_ARCH is still protected! */
1901 for (scb
= select_cb_list
; scb
!= NULL
; scb
= scb
->next
) {
1902 /* remember the state of select_cb_list to detect changes */
1903 last_select_cb_ctr
= select_cb_ctr
;
1904 if (scb
->sem_signalled
== 0) {
1905 /* semaphore not signalled yet */
1907 /* Test this select call for our socket */
1908 if (sock
->rcvevent
> 0) {
1909 if (scb
->readset
&& FD_ISSET(s
, scb
->readset
)) {
1913 if (sock
->sendevent
!= 0) {
1914 if (!do_signal
&& scb
->writeset
&& FD_ISSET(s
, scb
->writeset
)) {
1918 if (sock
->errevent
!= 0) {
1919 if (!do_signal
&& scb
->exceptset
&& FD_ISSET(s
, scb
->exceptset
)) {
1924 scb
->sem_signalled
= 1;
1925 /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
1926 lead to the select thread taking itself off the list, invalidating the semaphore. */
1927 sys_sem_signal(SELECT_SEM_PTR(scb
->sem
));
1930 /* unlock interrupts with each step */
1931 SYS_ARCH_UNPROTECT(lev
);
1932 /* this makes sure interrupt protection time is short */
1933 SYS_ARCH_PROTECT(lev
);
1934 if (last_select_cb_ctr
!= select_cb_ctr
) {
1935 /* someone has changed select_cb_list, restart at the beginning */
1939 SYS_ARCH_UNPROTECT(lev
);
1942 #endif /* LWIP_SOCKET_SELECT */
1945 * Close one end of a full-duplex connection.
1948 lwip_shutdown(int s
, int how
)
1950 struct lwip_sock
*sock
;
1952 u8_t shut_rx
= 0, shut_tx
= 0;
1954 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_shutdown(%d, how=%d)\n", s
, how
));
1956 sock
= get_socket(s
);
1961 if (sock
->conn
!= NULL
) {
1962 if (NETCONNTYPE_GROUP(netconn_type(sock
->conn
)) != NETCONN_TCP
) {
1963 sock_set_errno(sock
, EOPNOTSUPP
);
1968 sock_set_errno(sock
, ENOTCONN
);
1973 if (how
== SHUT_RD
) {
1975 } else if (how
== SHUT_WR
) {
1977 } else if (how
== SHUT_RDWR
) {
1981 sock_set_errno(sock
, EINVAL
);
1985 err
= netconn_shutdown(sock
->conn
, shut_rx
, shut_tx
);
1987 sock_set_errno(sock
, err_to_errno(err
));
1989 return (err
== ERR_OK
? 0 : -1);
1993 lwip_getaddrname(int s
, struct sockaddr
*name
, socklen_t
*namelen
, u8_t local
)
1995 struct lwip_sock
*sock
;
1996 union sockaddr_aligned saddr
;
2001 sock
= get_socket(s
);
2006 /* get the IP address and port */
2007 err
= netconn_getaddr(sock
->conn
, &naddr
, &port
, local
);
2008 if (err
!= ERR_OK
) {
2009 sock_set_errno(sock
, err_to_errno(err
));
2014 #if LWIP_IPV4 && LWIP_IPV6
2015 /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
2016 if (NETCONNTYPE_ISIPV6(netconn_type(sock
->conn
)) &&
2017 IP_IS_V4_VAL(naddr
)) {
2018 ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&naddr
), ip_2_ip4(&naddr
));
2019 IP_SET_TYPE_VAL(naddr
, IPADDR_TYPE_V6
);
2021 #endif /* LWIP_IPV4 && LWIP_IPV6 */
2023 IPADDR_PORT_TO_SOCKADDR(&saddr
, &naddr
, port
);
2025 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getaddrname(%d, addr=", s
));
2026 ip_addr_debug_print_val(SOCKETS_DEBUG
, naddr
);
2027 LWIP_DEBUGF(SOCKETS_DEBUG
, (" port=%"U16_F
")\n", port
));
2029 if (*namelen
> saddr
.sa
.sa_len
) {
2030 *namelen
= saddr
.sa
.sa_len
;
2032 MEMCPY(name
, &saddr
, *namelen
);
2034 sock_set_errno(sock
, 0);
2040 lwip_getpeername(int s
, struct sockaddr
*name
, socklen_t
*namelen
)
2042 return lwip_getaddrname(s
, name
, namelen
, 0);
2046 lwip_getsockname(int s
, struct sockaddr
*name
, socklen_t
*namelen
)
2048 return lwip_getaddrname(s
, name
, namelen
, 1);
2052 lwip_getsockopt(int s
, int level
, int optname
, void *optval
, socklen_t
*optlen
)
2055 struct lwip_sock
*sock
= get_socket(s
);
2056 #if !LWIP_TCPIP_CORE_LOCKING
2058 LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data
);
2059 #endif /* !LWIP_TCPIP_CORE_LOCKING */
2065 if ((NULL
== optval
) || (NULL
== optlen
)) {
2066 sock_set_errno(sock
, EFAULT
);
2071 #if LWIP_TCPIP_CORE_LOCKING
2072 /* core-locking can just call the -impl function */
2074 err
= lwip_getsockopt_impl(s
, level
, optname
, optval
, optlen
);
2075 UNLOCK_TCPIP_CORE();
2077 #else /* LWIP_TCPIP_CORE_LOCKING */
2079 #if LWIP_MPU_COMPATIBLE
2080 /* MPU_COMPATIBLE copies the optval data, so check for max size here */
2081 if (*optlen
> LWIP_SETGETSOCKOPT_MAXOPTLEN
) {
2082 sock_set_errno(sock
, ENOBUFS
);
2086 #endif /* LWIP_MPU_COMPATIBLE */
2088 LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data
, sock
);
2089 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).s
= s
;
2090 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).level
= level
;
2091 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).optname
= optname
;
2092 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).optlen
= *optlen
;
2093 #if !LWIP_MPU_COMPATIBLE
2094 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).optval
.p
= optval
;
2095 #endif /* !LWIP_MPU_COMPATIBLE */
2096 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).err
= 0;
2097 #if LWIP_NETCONN_SEM_PER_THREAD
2098 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).completed_sem
= LWIP_NETCONN_THREAD_SEM_GET();
2100 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).completed_sem
= &sock
->conn
->op_completed
;
2102 cberr
= tcpip_callback(lwip_getsockopt_callback
, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
));
2103 if (cberr
!= ERR_OK
) {
2104 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data
);
2105 sock_set_errno(sock
, err_to_errno(cberr
));
2109 sys_arch_sem_wait((sys_sem_t
*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).completed_sem
), 0);
2111 /* write back optlen and optval */
2112 *optlen
= LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).optlen
;
2113 #if LWIP_MPU_COMPATIBLE
2114 MEMCPY(optval
, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).optval
,
2115 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).optlen
);
2116 #endif /* LWIP_MPU_COMPATIBLE */
2118 /* maybe lwip_getsockopt_internal has changed err */
2119 err
= LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).err
;
2120 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data
);
2121 #endif /* LWIP_TCPIP_CORE_LOCKING */
2123 sock_set_errno(sock
, err
);
2125 return err
? -1 : 0;
2128 #if !LWIP_TCPIP_CORE_LOCKING
2129 /** lwip_getsockopt_callback: only used without CORE_LOCKING
2130 * to get into the tcpip_thread
2133 lwip_getsockopt_callback(void *arg
)
2135 struct lwip_setgetsockopt_data
*data
;
2136 LWIP_ASSERT("arg != NULL", arg
!= NULL
);
2137 data
= (struct lwip_setgetsockopt_data
*)arg
;
2139 data
->err
= lwip_getsockopt_impl(data
->s
, data
->level
, data
->optname
,
2140 #if LWIP_MPU_COMPATIBLE
2142 #else /* LWIP_MPU_COMPATIBLE */
2144 #endif /* LWIP_MPU_COMPATIBLE */
2147 sys_sem_signal((sys_sem_t
*)(data
->completed_sem
));
2149 #endif /* LWIP_TCPIP_CORE_LOCKING */
2151 /** lwip_getsockopt_impl: the actual implementation of getsockopt:
2152 * same argument as lwip_getsockopt, either called directly or through callback
2155 lwip_getsockopt_impl(int s
, int level
, int optname
, void *optval
, socklen_t
*optlen
)
2158 struct lwip_sock
*sock
= tryget_socket(s
);
2165 /* Level: SOL_SOCKET */
2171 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock
, *optlen
, int);
2172 if (NETCONNTYPE_GROUP(sock
->conn
->type
) != NETCONN_TCP
) {
2176 if ((sock
->conn
->pcb
.tcp
!= NULL
) && (sock
->conn
->pcb
.tcp
->state
== LISTEN
)) {
2182 #endif /* LWIP_TCP */
2184 /* The option flags */
2189 #endif /* SO_REUSE */
2190 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock
, *optlen
, int);
2191 *(int*)optval
= ip_get_option(sock
->conn
->pcb
.ip
, optname
);
2192 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
2193 s
, optname
, (*(int*)optval
?"on":"off")));
2197 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock
, *optlen
, int);
2198 switch (NETCONNTYPE_GROUP(netconn_type(sock
->conn
))) {
2200 *(int*)optval
= SOCK_RAW
;
2203 *(int*)optval
= SOCK_STREAM
;
2206 *(int*)optval
= SOCK_DGRAM
;
2208 default: /* unrecognized socket type */
2209 *(int*)optval
= netconn_type(sock
->conn
);
2210 LWIP_DEBUGF(SOCKETS_DEBUG
,
2211 ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
2212 s
, *(int *)optval
));
2213 } /* switch (netconn_type(sock->conn)) */
2214 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
2215 s
, *(int *)optval
));
2219 LWIP_SOCKOPT_CHECK_OPTLEN(*optlen
, int);
2220 /* only overwrite ERR_OK or temporary errors */
2221 if (((sock
->err
== 0) || (sock
->err
== EINPROGRESS
)) && (sock
->conn
!= NULL
)) {
2222 sock_set_errno(sock
, err_to_errno(sock
->conn
->last_err
));
2224 *(int *)optval
= sock
->err
;
2226 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
2227 s
, *(int *)optval
));
2230 #if LWIP_SO_SNDTIMEO
2232 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock
, *optlen
, LWIP_SO_SNDRCVTIMEO_OPTTYPE
);
2233 LWIP_SO_SNDRCVTIMEO_SET(optval
, netconn_get_sendtimeout(sock
->conn
));
2235 #endif /* LWIP_SO_SNDTIMEO */
2236 #if LWIP_SO_RCVTIMEO
2238 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock
, *optlen
, LWIP_SO_SNDRCVTIMEO_OPTTYPE
);
2239 LWIP_SO_SNDRCVTIMEO_SET(optval
, netconn_get_recvtimeout(sock
->conn
));
2241 #endif /* LWIP_SO_RCVTIMEO */
2244 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock
, *optlen
, int);
2245 *(int *)optval
= netconn_get_recvbufsize(sock
->conn
);
2247 #endif /* LWIP_SO_RCVBUF */
2252 struct linger
* linger
= (struct linger
*)optval
;
2253 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock
, *optlen
, struct linger
);
2254 conn_linger
= sock
->conn
->linger
;
2255 if (conn_linger
>= 0) {
2256 linger
->l_onoff
= 1;
2257 linger
->l_linger
= (int)conn_linger
;
2259 linger
->l_onoff
= 0;
2260 linger
->l_linger
= 0;
2264 #endif /* LWIP_SO_LINGER */
2267 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock
, *optlen
, int, NETCONN_UDP
);
2269 if ((udp_flags(sock
->conn
->pcb
.udp
) & UDP_FLAGS_UDPLITE
) != 0) {
2270 /* this flag is only available for UDP, not for UDP lite */
2272 return EAFNOSUPPORT
;
2274 #endif /* LWIP_UDPLITE */
2275 *(int*)optval
= (udp_flags(sock
->conn
->pcb
.udp
) & UDP_FLAGS_NOCHKSUM
) ? 1 : 0;
2277 #endif /* LWIP_UDP*/
2279 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
2283 } /* switch (optname) */
2286 /* Level: IPPROTO_IP */
2290 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock
, *optlen
, int);
2291 *(int*)optval
= sock
->conn
->pcb
.ip
->ttl
;
2292 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
2293 s
, *(int *)optval
));
2296 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock
, *optlen
, int);
2297 *(int*)optval
= sock
->conn
->pcb
.ip
->tos
;
2298 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
2299 s
, *(int *)optval
));
2301 #if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS
2302 case IP_MULTICAST_TTL
:
2303 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock
, *optlen
, u8_t
);
2304 if (NETCONNTYPE_GROUP(netconn_type(sock
->conn
)) != NETCONN_UDP
) {
2308 *(u8_t
*)optval
= udp_get_multicast_ttl(sock
->conn
->pcb
.udp
);
2309 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
2310 s
, *(int *)optval
));
2312 case IP_MULTICAST_IF
:
2313 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock
, *optlen
, struct in_addr
);
2314 if (NETCONNTYPE_GROUP(netconn_type(sock
->conn
)) != NETCONN_UDP
) {
2318 inet_addr_from_ip4addr((struct in_addr
*)optval
, udp_get_multicast_netif_addr(sock
->conn
->pcb
.udp
));
2319 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F
"\n",
2320 s
, *(u32_t
*)optval
));
2322 case IP_MULTICAST_LOOP
:
2323 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock
, *optlen
, u8_t
);
2324 if ((sock
->conn
->pcb
.udp
->flags
& UDP_FLAGS_MULTICAST_LOOP
) != 0) {
2329 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
2330 s
, *(int *)optval
));
2332 #endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS */
2334 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
2338 } /* switch (optname) */
2342 /* Level: IPPROTO_TCP */
2344 /* Special case: all IPPROTO_TCP option take an int */
2345 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock
, *optlen
, int, NETCONN_TCP
);
2346 if (sock
->conn
->pcb
.tcp
->state
== LISTEN
) {
2352 *(int*)optval
= tcp_nagle_disabled(sock
->conn
->pcb
.tcp
);
2353 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
2354 s
, (*(int*)optval
)?"on":"off") );
2357 *(int*)optval
= (int)sock
->conn
->pcb
.tcp
->keep_idle
;
2358 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n",
2359 s
, *(int *)optval
));
2362 #if LWIP_TCP_KEEPALIVE
2364 *(int*)optval
= (int)(sock
->conn
->pcb
.tcp
->keep_idle
/1000);
2365 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n",
2366 s
, *(int *)optval
));
2369 *(int*)optval
= (int)(sock
->conn
->pcb
.tcp
->keep_intvl
/1000);
2370 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n",
2371 s
, *(int *)optval
));
2374 *(int*)optval
= (int)sock
->conn
->pcb
.tcp
->keep_cnt
;
2375 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n",
2376 s
, *(int *)optval
));
2378 #endif /* LWIP_TCP_KEEPALIVE */
2380 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
2384 } /* switch (optname) */
2386 #endif /* LWIP_TCP */
2389 /* Level: IPPROTO_IPV6 */
2393 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock
, *optlen
, int);
2394 *(int*)optval
= (netconn_get_ipv6only(sock
->conn
) ? 1 : 0);
2395 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n",
2396 s
, *(int *)optval
));
2399 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
2403 } /* switch (optname) */
2405 #endif /* LWIP_IPV6 */
2407 #if LWIP_UDP && LWIP_UDPLITE
2408 /* Level: IPPROTO_UDPLITE */
2409 case IPPROTO_UDPLITE
:
2410 /* Special case: all IPPROTO_UDPLITE option take an int */
2411 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock
, *optlen
, int);
2412 /* If this is no UDP lite socket, ignore any options. */
2413 if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock
->conn
))) {
2418 case UDPLITE_SEND_CSCOV
:
2419 *(int*)optval
= sock
->conn
->pcb
.udp
->chksum_len_tx
;
2420 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
2421 s
, (*(int*)optval
)) );
2423 case UDPLITE_RECV_CSCOV
:
2424 *(int*)optval
= sock
->conn
->pcb
.udp
->chksum_len_rx
;
2425 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
2426 s
, (*(int*)optval
)) );
2429 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
2433 } /* switch (optname) */
2435 #endif /* LWIP_UDP */
2436 /* Level: IPPROTO_RAW */
2439 #if LWIP_IPV6 && LWIP_RAW
2441 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock
, *optlen
, int, NETCONN_RAW
);
2442 if (sock
->conn
->pcb
.raw
->chksum_reqd
== 0) {
2443 *(int *)optval
= -1;
2445 *(int *)optval
= sock
->conn
->pcb
.raw
->chksum_offset
;
2447 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n",
2448 s
, (*(int*)optval
)) );
2450 #endif /* LWIP_IPV6 && LWIP_RAW */
2452 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
2456 } /* switch (optname) */
2459 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2460 s
, level
, optname
));
2463 } /* switch (level) */
2470 lwip_setsockopt(int s
, int level
, int optname
, const void *optval
, socklen_t optlen
)
2473 struct lwip_sock
*sock
= get_socket(s
);
2474 #if !LWIP_TCPIP_CORE_LOCKING
2476 LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data
);
2477 #endif /* !LWIP_TCPIP_CORE_LOCKING */
2483 if (NULL
== optval
) {
2484 sock_set_errno(sock
, EFAULT
);
2489 #if LWIP_TCPIP_CORE_LOCKING
2490 /* core-locking can just call the -impl function */
2492 err
= lwip_setsockopt_impl(s
, level
, optname
, optval
, optlen
);
2493 UNLOCK_TCPIP_CORE();
2495 #else /* LWIP_TCPIP_CORE_LOCKING */
2497 #if LWIP_MPU_COMPATIBLE
2498 /* MPU_COMPATIBLE copies the optval data, so check for max size here */
2499 if (optlen
> LWIP_SETGETSOCKOPT_MAXOPTLEN
) {
2500 sock_set_errno(sock
, ENOBUFS
);
2504 #endif /* LWIP_MPU_COMPATIBLE */
2506 LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data
, sock
);
2507 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).s
= s
;
2508 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).level
= level
;
2509 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).optname
= optname
;
2510 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).optlen
= optlen
;
2511 #if LWIP_MPU_COMPATIBLE
2512 MEMCPY(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).optval
, optval
, optlen
);
2513 #else /* LWIP_MPU_COMPATIBLE */
2514 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).optval
.pc
= (const void*)optval
;
2515 #endif /* LWIP_MPU_COMPATIBLE */
2516 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).err
= 0;
2517 #if LWIP_NETCONN_SEM_PER_THREAD
2518 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).completed_sem
= LWIP_NETCONN_THREAD_SEM_GET();
2520 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).completed_sem
= &sock
->conn
->op_completed
;
2522 cberr
= tcpip_callback(lwip_setsockopt_callback
, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
));
2523 if (cberr
!= ERR_OK
) {
2524 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data
);
2525 sock_set_errno(sock
, err_to_errno(cberr
));
2529 sys_arch_sem_wait((sys_sem_t
*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).completed_sem
), 0);
2531 /* maybe lwip_getsockopt_internal has changed err */
2532 err
= LWIP_SETGETSOCKOPT_DATA_VAR_REF(data
).err
;
2533 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data
);
2534 #endif /* LWIP_TCPIP_CORE_LOCKING */
2536 sock_set_errno(sock
, err
);
2538 return err
? -1 : 0;
2541 #if !LWIP_TCPIP_CORE_LOCKING
2542 /** lwip_setsockopt_callback: only used without CORE_LOCKING
2543 * to get into the tcpip_thread
2546 lwip_setsockopt_callback(void *arg
)
2548 struct lwip_setgetsockopt_data
*data
;
2549 LWIP_ASSERT("arg != NULL", arg
!= NULL
);
2550 data
= (struct lwip_setgetsockopt_data
*)arg
;
2552 data
->err
= lwip_setsockopt_impl(data
->s
, data
->level
, data
->optname
,
2553 #if LWIP_MPU_COMPATIBLE
2555 #else /* LWIP_MPU_COMPATIBLE */
2557 #endif /* LWIP_MPU_COMPATIBLE */
2560 sys_sem_signal((sys_sem_t
*)(data
->completed_sem
));
2562 #endif /* LWIP_TCPIP_CORE_LOCKING */
2564 /** lwip_setsockopt_impl: the actual implementation of setsockopt:
2565 * same argument as lwip_setsockopt, either called directly or through callback
2568 lwip_setsockopt_impl(int s
, int level
, int optname
, const void *optval
, socklen_t optlen
)
2571 struct lwip_sock
*sock
= tryget_socket(s
);
2578 /* Level: SOL_SOCKET */
2582 /* SO_ACCEPTCONN is get-only */
2584 /* The option flags */
2589 #endif /* SO_REUSE */
2590 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock
, optlen
, int);
2591 if (*(const int*)optval
) {
2592 ip_set_option(sock
->conn
->pcb
.ip
, optname
);
2594 ip_reset_option(sock
->conn
->pcb
.ip
, optname
);
2596 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
2597 s
, optname
, (*(const int*)optval
?"on":"off")));
2600 /* SO_TYPE is get-only */
2601 /* SO_ERROR is get-only */
2603 #if LWIP_SO_SNDTIMEO
2605 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock
, optlen
, LWIP_SO_SNDRCVTIMEO_OPTTYPE
);
2606 netconn_set_sendtimeout(sock
->conn
, LWIP_SO_SNDRCVTIMEO_GET_MS(optval
));
2608 #endif /* LWIP_SO_SNDTIMEO */
2609 #if LWIP_SO_RCVTIMEO
2611 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock
, optlen
, LWIP_SO_SNDRCVTIMEO_OPTTYPE
);
2612 netconn_set_recvtimeout(sock
->conn
, (int)LWIP_SO_SNDRCVTIMEO_GET_MS(optval
));
2614 #endif /* LWIP_SO_RCVTIMEO */
2617 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock
, optlen
, int);
2618 netconn_set_recvbufsize(sock
->conn
, *(const int*)optval
);
2620 #endif /* LWIP_SO_RCVBUF */
2624 const struct linger
* linger
= (const struct linger
*)optval
;
2625 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock
, optlen
, struct linger
);
2626 if (linger
->l_onoff
) {
2627 int lingersec
= linger
->l_linger
;
2628 if (lingersec
< 0) {
2632 if (lingersec
> 0xFFFF) {
2635 sock
->conn
->linger
= (s16_t
)lingersec
;
2637 sock
->conn
->linger
= -1;
2641 #endif /* LWIP_SO_LINGER */
2644 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock
, optlen
, int, NETCONN_UDP
);
2646 if ((udp_flags(sock
->conn
->pcb
.udp
) & UDP_FLAGS_UDPLITE
) != 0) {
2647 /* this flag is only available for UDP, not for UDP lite */
2649 return EAFNOSUPPORT
;
2651 #endif /* LWIP_UDPLITE */
2652 if (*(const int*)optval
) {
2653 udp_setflags(sock
->conn
->pcb
.udp
, udp_flags(sock
->conn
->pcb
.udp
) | UDP_FLAGS_NOCHKSUM
);
2655 udp_setflags(sock
->conn
->pcb
.udp
, udp_flags(sock
->conn
->pcb
.udp
) & ~UDP_FLAGS_NOCHKSUM
);
2658 #endif /* LWIP_UDP */
2660 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
2664 } /* switch (optname) */
2667 /* Level: IPPROTO_IP */
2671 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock
, optlen
, int);
2672 sock
->conn
->pcb
.ip
->ttl
= (u8_t
)(*(const int*)optval
);
2673 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
2674 s
, sock
->conn
->pcb
.ip
->ttl
));
2677 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock
, optlen
, int);
2678 sock
->conn
->pcb
.ip
->tos
= (u8_t
)(*(const int*)optval
);
2679 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
2680 s
, sock
->conn
->pcb
.ip
->tos
));
2682 #if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS
2683 case IP_MULTICAST_TTL
:
2684 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock
, optlen
, u8_t
, NETCONN_UDP
);
2685 udp_set_multicast_ttl(sock
->conn
->pcb
.udp
, (u8_t
)(*(const u8_t
*)optval
));
2687 case IP_MULTICAST_IF
:
2690 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock
, optlen
, struct in_addr
, NETCONN_UDP
);
2691 inet_addr_to_ip4addr(&if_addr
, (const struct in_addr
*)optval
);
2692 udp_set_multicast_netif_addr(sock
->conn
->pcb
.udp
, &if_addr
);
2695 case IP_MULTICAST_LOOP
:
2696 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock
, optlen
, u8_t
, NETCONN_UDP
);
2697 if (*(const u8_t
*)optval
) {
2698 udp_setflags(sock
->conn
->pcb
.udp
, udp_flags(sock
->conn
->pcb
.udp
) | UDP_FLAGS_MULTICAST_LOOP
);
2700 udp_setflags(sock
->conn
->pcb
.udp
, udp_flags(sock
->conn
->pcb
.udp
) & ~UDP_FLAGS_MULTICAST_LOOP
);
2703 #endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS */
2705 case IP_ADD_MEMBERSHIP
:
2706 case IP_DROP_MEMBERSHIP
:
2708 /* If this is a TCP or a RAW socket, ignore these options. */
2709 /* @todo: assign membership to this socket so that it is dropped when closing the socket */
2711 const struct ip_mreq
*imr
= (const struct ip_mreq
*)optval
;
2713 ip4_addr_t multi_addr
;
2714 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock
, optlen
, struct ip_mreq
, NETCONN_UDP
);
2715 inet_addr_to_ip4addr(&if_addr
, &imr
->imr_interface
);
2716 inet_addr_to_ip4addr(&multi_addr
, &imr
->imr_multiaddr
);
2717 if (optname
== IP_ADD_MEMBERSHIP
) {
2718 if (!lwip_socket_register_membership(s
, &if_addr
, &multi_addr
)) {
2719 /* cannot track membership (out of memory) */
2723 igmp_err
= igmp_joingroup(&if_addr
, &multi_addr
);
2726 igmp_err
= igmp_leavegroup(&if_addr
, &multi_addr
);
2727 lwip_socket_unregister_membership(s
, &if_addr
, &multi_addr
);
2729 if (igmp_err
!= ERR_OK
) {
2730 err
= EADDRNOTAVAIL
;
2734 #endif /* LWIP_IGMP */
2736 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
2740 } /* switch (optname) */
2744 /* Level: IPPROTO_TCP */
2746 /* Special case: all IPPROTO_TCP option take an int */
2747 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock
, optlen
, int, NETCONN_TCP
);
2748 if (sock
->conn
->pcb
.tcp
->state
== LISTEN
) {
2754 if (*(const int*)optval
) {
2755 tcp_nagle_disable(sock
->conn
->pcb
.tcp
);
2757 tcp_nagle_enable(sock
->conn
->pcb
.tcp
);
2759 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
2760 s
, (*(const int *)optval
)?"on":"off") );
2763 sock
->conn
->pcb
.tcp
->keep_idle
= (u32_t
)(*(const int*)optval
);
2764 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F
"\n",
2765 s
, sock
->conn
->pcb
.tcp
->keep_idle
));
2768 #if LWIP_TCP_KEEPALIVE
2770 sock
->conn
->pcb
.tcp
->keep_idle
= 1000*(u32_t
)(*(const int*)optval
);
2771 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F
"\n",
2772 s
, sock
->conn
->pcb
.tcp
->keep_idle
));
2775 sock
->conn
->pcb
.tcp
->keep_intvl
= 1000*(u32_t
)(*(const int*)optval
);
2776 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F
"\n",
2777 s
, sock
->conn
->pcb
.tcp
->keep_intvl
));
2780 sock
->conn
->pcb
.tcp
->keep_cnt
= (u32_t
)(*(const int*)optval
);
2781 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F
"\n",
2782 s
, sock
->conn
->pcb
.tcp
->keep_cnt
));
2784 #endif /* LWIP_TCP_KEEPALIVE */
2786 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
2790 } /* switch (optname) */
2792 #endif /* LWIP_TCP*/
2795 /* Level: IPPROTO_IPV6 */
2799 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock
, optlen
, int, NETCONN_TCP
);
2800 if (*(const int*)optval
) {
2801 netconn_set_ipv6only(sock
->conn
, 1);
2803 netconn_set_ipv6only(sock
->conn
, 0);
2805 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n",
2806 s
, (netconn_get_ipv6only(sock
->conn
) ? 1 : 0)));
2809 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
2813 } /* switch (optname) */
2815 #endif /* LWIP_IPV6 */
2817 #if LWIP_UDP && LWIP_UDPLITE
2818 /* Level: IPPROTO_UDPLITE */
2819 case IPPROTO_UDPLITE
:
2820 /* Special case: all IPPROTO_UDPLITE option take an int */
2821 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock
, optlen
, int);
2822 /* If this is no UDP lite socket, ignore any options. */
2823 if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock
->conn
))) {
2828 case UDPLITE_SEND_CSCOV
:
2829 if ((*(const int*)optval
!= 0) && ((*(const int*)optval
< 8) || (*(const int*)optval
> 0xffff))) {
2830 /* don't allow illegal values! */
2831 sock
->conn
->pcb
.udp
->chksum_len_tx
= 8;
2833 sock
->conn
->pcb
.udp
->chksum_len_tx
= (u16_t
)*(const int*)optval
;
2835 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
2836 s
, (*(const int*)optval
)) );
2838 case UDPLITE_RECV_CSCOV
:
2839 if ((*(const int*)optval
!= 0) && ((*(const int*)optval
< 8) || (*(const int*)optval
> 0xffff))) {
2840 /* don't allow illegal values! */
2841 sock
->conn
->pcb
.udp
->chksum_len_rx
= 8;
2843 sock
->conn
->pcb
.udp
->chksum_len_rx
= (u16_t
)*(const int*)optval
;
2845 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
2846 s
, (*(const int*)optval
)) );
2849 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
2853 } /* switch (optname) */
2855 #endif /* LWIP_UDP */
2856 /* Level: IPPROTO_RAW */
2859 #if LWIP_IPV6 && LWIP_RAW
2861 /* It should not be possible to disable the checksum generation with ICMPv6
2862 * as per RFC 3542 chapter 3.1 */
2863 if(sock
->conn
->pcb
.raw
->protocol
== IPPROTO_ICMPV6
) {
2868 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock
, optlen
, int, NETCONN_RAW
);
2869 if (*(const int *)optval
< 0) {
2870 sock
->conn
->pcb
.raw
->chksum_reqd
= 0;
2871 } else if (*(const int *)optval
& 1) {
2872 /* Per RFC3542, odd offsets are not allowed */
2876 sock
->conn
->pcb
.raw
->chksum_reqd
= 1;
2877 sock
->conn
->pcb
.raw
->chksum_offset
= (u16_t
)*(const int *)optval
;
2879 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n",
2880 s
, sock
->conn
->pcb
.raw
->chksum_reqd
));
2882 #endif /* LWIP_IPV6 && LWIP_RAW */
2884 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
2888 } /* switch (optname) */
2891 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2892 s
, level
, optname
));
2895 } /* switch (level) */
2902 lwip_ioctl(int s
, long cmd
, void *argp
)
2904 struct lwip_sock
*sock
= get_socket(s
);
2908 #endif /* LWIP_SO_RCVBUF */
2915 #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE
2918 sock_set_errno(sock
, EINVAL
);
2922 #if LWIP_FIONREAD_LINUXMODE
2923 if (NETCONNTYPE_GROUP(netconn_type(sock
->conn
)) != NETCONN_TCP
) {
2925 if (sock
->lastdata
.netbuf
) {
2926 nb
= sock
->lastdata
.netbuf
;
2927 *((int*)argp
) = nb
->p
->tot_len
;
2929 struct netbuf
*rxbuf
;
2930 err_t err
= netconn_recv_udp_raw_netbuf_flags(sock
->conn
, &rxbuf
, NETCONN_DONTBLOCK
);
2931 if (err
!= ERR_OK
) {
2934 sock
->lastdata
.netbuf
= rxbuf
;
2935 *((int*)argp
) = rxbuf
->p
->tot_len
;
2941 #endif /* LWIP_FIONREAD_LINUXMODE */
2944 /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */
2945 SYS_ARCH_GET(sock
->conn
->recv_avail
, recv_avail
);
2946 if (recv_avail
< 0) {
2950 /* Check if there is data left from the last recv operation. /maq 041215 */
2951 if (sock
->lastdata
.netbuf
) {
2952 if (NETCONNTYPE_GROUP(netconn_type(sock
->conn
)) != NETCONN_TCP
) {
2953 recv_avail
+= sock
->lastdata
.pbuf
->tot_len
;
2955 recv_avail
+= sock
->lastdata
.netbuf
->p
->tot_len
;
2958 *((int*)argp
) = recv_avail
;
2960 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F
"\n", s
, argp
, *((u16_t
*)argp
)));
2961 sock_set_errno(sock
, 0);
2964 #else /* LWIP_SO_RCVBUF */
2966 #endif /* LWIP_SO_RCVBUF */
2967 #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */
2971 if (argp
&& *(u32_t
*)argp
) {
2974 netconn_set_nonblocking(sock
->conn
, val
);
2975 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_ioctl(%d, FIONBIO, %d)\n", s
, val
));
2976 sock_set_errno(sock
, 0);
2982 } /* switch (cmd) */
2983 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s
, cmd
, argp
));
2984 sock_set_errno(sock
, ENOSYS
); /* not yet implemented */
2989 /** A minimal implementation of fcntl.
2990 * Currently only the commands F_GETFL and F_SETFL are implemented.
2991 * Only the flag O_NONBLOCK is implemented.
2994 lwip_fcntl(int s
, int cmd
, int val
)
2996 struct lwip_sock
*sock
= get_socket(s
);
3005 ret
= netconn_is_nonblocking(sock
->conn
) ? O_NONBLOCK
: 0;
3006 sock_set_errno(sock
, 0);
3009 if ((val
& ~O_NONBLOCK
) == 0) {
3010 /* only O_NONBLOCK, all other bits are zero */
3011 netconn_set_nonblocking(sock
->conn
, val
& O_NONBLOCK
);
3013 sock_set_errno(sock
, 0);
3015 sock_set_errno(sock
, ENOSYS
); /* not yet implemented */
3019 LWIP_DEBUGF(SOCKETS_DEBUG
, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s
, cmd
, val
));
3020 sock_set_errno(sock
, ENOSYS
); /* not yet implemented */
3028 /** Register a new IGMP membership. On socket close, the membership is dropped automatically.
3030 * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
3032 * @return 1 on success, 0 on failure
3035 lwip_socket_register_membership(int s
, const ip4_addr_t
*if_addr
, const ip4_addr_t
*multi_addr
)
3037 struct lwip_sock
*sock
= get_socket(s
);
3044 for (i
= 0; i
< LWIP_SOCKET_MAX_MEMBERSHIPS
; i
++) {
3045 if (socket_ipv4_multicast_memberships
[i
].sock
== NULL
) {
3046 socket_ipv4_multicast_memberships
[i
].sock
= sock
;
3047 ip4_addr_copy(socket_ipv4_multicast_memberships
[i
].if_addr
, *if_addr
);
3048 ip4_addr_copy(socket_ipv4_multicast_memberships
[i
].multi_addr
, *multi_addr
);
3057 /** Unregister a previously registered membership. This prevents dropping the membership
3060 * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
3063 lwip_socket_unregister_membership(int s
, const ip4_addr_t
*if_addr
, const ip4_addr_t
*multi_addr
)
3065 struct lwip_sock
*sock
= get_socket(s
);
3072 for (i
= 0; i
< LWIP_SOCKET_MAX_MEMBERSHIPS
; i
++) {
3073 if ((socket_ipv4_multicast_memberships
[i
].sock
== sock
) &&
3074 ip4_addr_cmp(&socket_ipv4_multicast_memberships
[i
].if_addr
, if_addr
) &&
3075 ip4_addr_cmp(&socket_ipv4_multicast_memberships
[i
].multi_addr
, multi_addr
)) {
3076 socket_ipv4_multicast_memberships
[i
].sock
= NULL
;
3077 ip4_addr_set_zero(&socket_ipv4_multicast_memberships
[i
].if_addr
);
3078 ip4_addr_set_zero(&socket_ipv4_multicast_memberships
[i
].multi_addr
);
3085 /** Drop all memberships of a socket that were not dropped explicitly via setsockopt.
3087 * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK).
3090 lwip_socket_drop_registered_memberships(int s
)
3092 struct lwip_sock
*sock
= get_socket(s
);
3099 for (i
= 0; i
< LWIP_SOCKET_MAX_MEMBERSHIPS
; i
++) {
3100 if (socket_ipv4_multicast_memberships
[i
].sock
== sock
) {
3101 ip_addr_t multi_addr
, if_addr
;
3102 ip_addr_copy_from_ip4(multi_addr
, socket_ipv4_multicast_memberships
[i
].multi_addr
);
3103 ip_addr_copy_from_ip4(if_addr
, socket_ipv4_multicast_memberships
[i
].if_addr
);
3104 socket_ipv4_multicast_memberships
[i
].sock
= NULL
;
3105 ip4_addr_set_zero(&socket_ipv4_multicast_memberships
[i
].if_addr
);
3106 ip4_addr_set_zero(&socket_ipv4_multicast_memberships
[i
].multi_addr
);
3108 netconn_join_leave_group(sock
->conn
, &multi_addr
, &if_addr
, NETCONN_LEAVE
);
3113 #endif /* LWIP_IGMP */
3114 #endif /* LWIP_SOCKET */