3 * Sockets BSD-Like API module
8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33 * This file is part of the lwIP TCP/IP stack.
35 * Author: Adam Dunkels <adam@sics.se>
37 * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
43 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
45 #include "lwip/sockets.h"
48 #include "lwip/igmp.h"
49 #include "lwip/inet.h"
53 #include "lwip/tcpip.h"
54 #include "lwip/pbuf.h"
55 #if LWIP_CHECKSUM_ON_COPY
56 #include "lwip/inet_chksum.h"
61 #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipXaddr, port) do { \
62 (sin)->sin_len = sizeof(struct sockaddr_in); \
63 (sin)->sin_family = AF_INET; \
64 (sin)->sin_port = htons((port)); \
65 inet_addr_from_ipaddr(&(sin)->sin_addr, ipX_2_ip(ipXaddr)); \
66 memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0)
67 #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipXaddr, port) do { \
68 inet_addr_to_ipaddr(ipX_2_ip(ipXaddr), &((sin)->sin_addr)); \
69 (port) = ntohs((sin)->sin_port); }while(0)
72 #define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \
73 ((namelen) == sizeof(struct sockaddr_in6)))
74 #define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \
75 ((name)->sa_family == AF_INET6))
76 #define SOCK_ADDR_TYPE_MATCH(name, sock) \
77 ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \
78 (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type))))
79 #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipXaddr, port) do { \
80 (sin6)->sin6_len = sizeof(struct sockaddr_in6); \
81 (sin6)->sin6_family = AF_INET6; \
82 (sin6)->sin6_port = htons((port)); \
83 (sin6)->sin6_flowinfo = 0; \
84 inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipX_2_ip6(ipXaddr)); }while(0)
85 #define IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) do { \
87 IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ipXaddr, port); \
89 IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port); \
91 #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipXaddr, port) do { \
92 inet6_addr_to_ip6addr(ipX_2_ip6(ipXaddr), &((sin6)->sin6_addr)); \
93 (port) = ntohs((sin6)->sin6_port); }while(0)
94 #define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) do { \
96 SOCKADDR6_TO_IP6ADDR_PORT((struct sockaddr_in6*)(void*)(sockaddr), ipXaddr, port); \
98 SOCKADDR4_TO_IP4ADDR_PORT((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port); \
100 #define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \
101 (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6))
102 #else /* LWIP_IPV6 */
103 #define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in))
104 #define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET)
105 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
106 #define IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) \
107 IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port)
108 #define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) \
109 SOCKADDR4_TO_IP4ADDR_PORT((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port)
110 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
111 #endif /* LWIP_IPV6 */
113 #define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \
114 IS_SOCK_ADDR_TYPE_VALID(name))
115 #define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \
116 SOCK_ADDR_TYPE_MATCH(name, sock))
117 #define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0)
121 #define NUM_SOCKETS MEMP_NUM_NETCONN
123 /** Contains all internal pointers and states used for a socket */
125 /** sockets currently are built on netconns, each socket has one netconn */
126 struct netconn *conn;
127 /** data that was left from the previous read */
129 /** offset in the data that was left from the previous read */
131 /** number of times data was received, set by event_callback(),
132 tested by the receive and select functions */
134 /** number of times data was ACKed (free send buffer), set by event_callback(),
137 /** error happened for this socket, set by event_callback(), tested by select */
139 /** last error that occurred on this socket */
141 /** counter of how many threads are waiting for this socket using select */
145 /** Description for a task waiting in select */
146 struct lwip_select_cb {
147 /** Pointer to the next waiting task */
148 struct lwip_select_cb *next;
149 /** Pointer to the previous waiting task */
150 struct lwip_select_cb *prev;
151 /** readset passed to select */
153 /** writeset passed to select */
155 /** unimplemented: exceptset passed to select */
157 /** don't signal the same semaphore twice: set to 1 when signalled */
159 /** semaphore to wake up a task waiting for select */
163 /** This struct is used to pass data to the set/getsockopt_internal
164 * functions running in tcpip_thread context (only a void* is allowed) */
165 struct lwip_setgetsockopt_data {
166 /** socket struct for which to change options */
167 struct lwip_sock *sock;
169 /** socket index for which to change options */
171 #endif /* LWIP_DEBUG */
172 /** level of the option to process */
174 /** name of the option to process */
176 /** set: value to set the option to
177 * get: value of the option is stored here */
179 /** size of *optval */
181 /** if an error occures, it is temporarily stored here */
185 /** A struct sockaddr replacement that has the same alignment as sockaddr_in/
186 * sockaddr_in6 if instantiated.
188 union sockaddr_aligned {
191 struct sockaddr_in6 sin6;
192 #endif /* LWIP_IPV6 */
193 struct sockaddr_in sin;
197 /** The global array of available sockets */
198 static struct lwip_sock sockets[NUM_SOCKETS];
199 /** The global list of tasks waiting for select */
200 static struct lwip_select_cb *select_cb_list;
201 /** This counter is increased from lwip_select when the list is chagned
202 and checked in event_callback to see if it has changed. */
203 static volatile int select_cb_ctr;
205 /** Table to quickly map an lwIP error (err_t) to a socket error
206 * by using -err as an index */
207 static const int err_to_errno_table[] = {
208 0, /* ERR_OK 0 No error, everything OK. */
209 ENOMEM, /* ERR_MEM -1 Out of memory error. */
210 ENOBUFS, /* ERR_BUF -2 Buffer error. */
211 EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
212 EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
213 EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
214 EINVAL, /* ERR_VAL -6 Illegal value. */
215 EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
216 EADDRINUSE, /* ERR_USE -8 Address in use. */
217 EALREADY, /* ERR_ISCONN -9 Already connected. */
218 ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */
219 ECONNRESET, /* ERR_RST -11 Connection reset. */
220 ENOTCONN, /* ERR_CLSD -12 Connection closed. */
221 ENOTCONN, /* ERR_CONN -13 Not connected. */
222 EIO, /* ERR_ARG -14 Illegal argument. */
223 -1, /* ERR_IF -15 Low-level netif error */
226 #define ERR_TO_ERRNO_TABLE_SIZE \
227 (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
229 #define err_to_errno(err) \
230 ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
231 err_to_errno_table[-(err)] : EIO)
235 #define set_errno(err) errno = (err)
238 #define set_errno(err)
241 #define sock_set_errno(sk, e) do { \
243 set_errno(sk->err); \
246 /* Forward delcaration of some functions */
247 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
248 static void lwip_getsockopt_internal(void *arg);
249 static void lwip_setsockopt_internal(void *arg);
252 * Initialize this module. This function has to be called before any other
253 * functions in this module!
256 lwip_socket_init(void)
261 * Map a externally used socket index to the internal socket representation.
263 * @param s externally used socket index
264 * @return struct lwip_sock for the socket or NULL if not found
266 static struct lwip_sock *
269 struct lwip_sock *sock;
271 if ((s < 0) || (s >= NUM_SOCKETS)) {
272 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
280 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
289 * Same as get_socket but doesn't set errno
291 * @param s externally used socket index
292 * @return struct lwip_sock for the socket or NULL if not found
294 static struct lwip_sock *
297 if ((s < 0) || (s >= NUM_SOCKETS)) {
300 if (!sockets[s].conn) {
307 * Allocate a new socket for a given netconn.
309 * @param newconn the netconn for which to allocate a socket
310 * @param accepted 1 if socket has been created by accept(),
311 * 0 if socket has been created by socket()
312 * @return the index of the new socket; -1 on error
315 alloc_socket(struct netconn *newconn, int accepted)
318 SYS_ARCH_DECL_PROTECT(lev);
320 /* allocate a new socket identifier */
321 for (i = 0; i < NUM_SOCKETS; ++i) {
322 /* Protect socket array */
323 SYS_ARCH_PROTECT(lev);
324 if (!sockets[i].conn) {
325 sockets[i].conn = newconn;
326 /* The socket is not yet known to anyone, so no need to protect
327 after having marked it as used. */
328 SYS_ARCH_UNPROTECT(lev);
329 sockets[i].lastdata = NULL;
330 sockets[i].lastoffset = 0;
331 sockets[i].rcvevent = 0;
332 /* TCP sendbuf is empty, but the socket is not yet writable until connected
333 * (unless it has been created by accept()). */
334 sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
335 sockets[i].errevent = 0;
337 sockets[i].select_waiting = 0;
340 SYS_ARCH_UNPROTECT(lev);
345 /** Free a socket. The socket's netconn must have been
348 * @param sock the socket to free
349 * @param is_tcp != 0 for TCP sockets, used to free lastdata
352 free_socket(struct lwip_sock *sock, int is_tcp)
355 SYS_ARCH_DECL_PROTECT(lev);
357 lastdata = sock->lastdata;
358 sock->lastdata = NULL;
359 sock->lastoffset = 0;
362 /* Protect socket array */
363 SYS_ARCH_PROTECT(lev);
365 SYS_ARCH_UNPROTECT(lev);
366 /* don't use 'sock' after this line, as another task might have allocated it */
368 if (lastdata != NULL) {
370 pbuf_free((struct pbuf *)lastdata);
372 netbuf_delete((struct netbuf *)lastdata);
377 /* Below this, the well-known socket functions are implemented.
378 * Use google.com or opengroup.org to get a good description :-)
380 * Exceptions are documented!
384 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
386 struct lwip_sock *sock, *nsock;
387 struct netconn *newconn;
392 SYS_ARCH_DECL_PROTECT(lev);
394 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
395 sock = get_socket(s);
400 if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
401 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
402 sock_set_errno(sock, EWOULDBLOCK);
406 /* wait for a new connection */
407 err = netconn_accept(sock->conn, &newconn);
409 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
410 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
411 sock_set_errno(sock, EOPNOTSUPP);
414 sock_set_errno(sock, err_to_errno(err));
417 LWIP_ASSERT("newconn != NULL", newconn != NULL);
418 /* Prevent automatic window updates, we do this on our own! */
419 netconn_set_noautorecved(newconn, 1);
421 /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
422 * not be NULL if addr is valid.
425 union sockaddr_aligned tempaddr;
426 /* get the IP address and port of the remote host */
427 err = netconn_peer(newconn, ipX_2_ip(&naddr), &port);
429 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
430 netconn_delete(newconn);
431 sock_set_errno(sock, err_to_errno(err));
434 LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
436 IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(newconn->type), &tempaddr, &naddr, port);
437 if (*addrlen > tempaddr.sa.sa_len) {
438 *addrlen = tempaddr.sa.sa_len;
440 MEMCPY(addr, &tempaddr, *addrlen);
443 newsock = alloc_socket(newconn, 1);
445 netconn_delete(newconn);
446 sock_set_errno(sock, ENFILE);
449 LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));
450 LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
451 nsock = &sockets[newsock];
453 /* See event_callback: If data comes in right away after an accept, even
454 * though the server task might not have created a new socket yet.
455 * In that case, newconn->socket is counted down (newconn->socket--),
456 * so nsock->rcvevent is >= 1 here!
458 SYS_ARCH_PROTECT(lev);
459 nsock->rcvevent += (s16_t)(-1 - newconn->socket);
460 newconn->socket = newsock;
461 SYS_ARCH_UNPROTECT(lev);
463 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock));
465 LWIP_DEBUGF(SOCKETS_DEBUG, (" addr="));
466 ipX_addr_debug_print(NETCONNTYPE_ISIPV6(newconn->type), SOCKETS_DEBUG, &naddr);
467 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
470 sock_set_errno(sock, 0);
475 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
477 struct lwip_sock *sock;
478 ipX_addr_t local_addr;
482 sock = get_socket(s);
487 if (!SOCK_ADDR_TYPE_MATCH(name, sock)) {
488 /* sockaddr does not match socket type (IPv4/IPv6) */
489 sock_set_errno(sock, err_to_errno(ERR_VAL));
493 /* check size, familiy and alignment of 'name' */
494 LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) &&
495 IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)),
496 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
497 LWIP_UNUSED_ARG(namelen);
499 SOCKADDR_TO_IPXADDR_PORT((name->sa_family == AF_INET6), name, &local_addr, local_port);
500 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
501 ipX_addr_debug_print(name->sa_family == AF_INET6, SOCKETS_DEBUG, &local_addr);
502 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));
504 err = netconn_bind(sock->conn, ipX_2_ip(&local_addr), local_port);
507 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
508 sock_set_errno(sock, err_to_errno(err));
512 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
513 sock_set_errno(sock, 0);
520 struct lwip_sock *sock;
523 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
525 sock = get_socket(s);
530 if(sock->conn != NULL) {
531 is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP;
533 LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
536 netconn_delete(sock->conn);
538 free_socket(sock, is_tcp);
544 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
546 struct lwip_sock *sock;
549 sock = get_socket(s);
554 if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) {
555 /* sockaddr does not match socket type (IPv4/IPv6) */
556 sock_set_errno(sock, err_to_errno(ERR_VAL));
560 /* check size, familiy and alignment of 'name' */
561 LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) &&
562 IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name),
563 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
564 LWIP_UNUSED_ARG(namelen);
565 if (name->sa_family == AF_UNSPEC) {
566 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
567 err = netconn_disconnect(sock->conn);
569 ipX_addr_t remote_addr;
571 SOCKADDR_TO_IPXADDR_PORT((name->sa_family == AF_INET6), name, &remote_addr, remote_port);
572 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
573 ipX_addr_debug_print(name->sa_family == AF_INET6, SOCKETS_DEBUG, &remote_addr);
574 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
576 err = netconn_connect(sock->conn, ipX_2_ip(&remote_addr), remote_port);
580 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
581 sock_set_errno(sock, err_to_errno(err));
585 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
586 sock_set_errno(sock, 0);
591 * Set a socket into listen mode.
592 * The socket may not have been used for another connection previously.
594 * @param s the socket to set to listening mode
595 * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
596 * @return 0 on success, non-zero on failure
599 lwip_listen(int s, int backlog)
601 struct lwip_sock *sock;
604 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
606 sock = get_socket(s);
611 /* limit the "backlog" parameter to fit in an u8_t */
612 backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
614 err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
617 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
618 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
619 sock_set_errno(sock, EOPNOTSUPP);
622 sock_set_errno(sock, err_to_errno(err));
626 sock_set_errno(sock, 0);
631 lwip_recvfrom(int s, void *mem, size_t len, int flags,
632 struct sockaddr *from, socklen_t *fromlen)
634 struct lwip_sock *sock;
637 u16_t buflen, copylen;
642 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
643 sock = get_socket(s);
649 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
650 /* Check if there is data left from the last recv operation. */
651 if (sock->lastdata) {
652 buf = sock->lastdata;
654 /* If this is non-blocking call, then check first */
655 if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
656 (sock->rcvevent <= 0)) {
658 /* update receive window */
659 netconn_recved(sock->conn, (u32_t)off);
660 /* already received data, return that */
661 sock_set_errno(sock, 0);
664 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
665 sock_set_errno(sock, EWOULDBLOCK);
669 /* No data was left from the previous operation, so we try to get
670 some from the network. */
671 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
672 err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
674 err = netconn_recv(sock->conn, (struct netbuf **)&buf);
676 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
681 /* update receive window */
682 netconn_recved(sock->conn, (u32_t)off);
683 /* already received data, return that */
684 sock_set_errno(sock, 0);
687 /* We should really do some error checking here. */
688 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
689 s, lwip_strerr(err)));
690 sock_set_errno(sock, err_to_errno(err));
691 if (err == ERR_CLSD) {
697 LWIP_ASSERT("buf != NULL", buf != NULL);
698 sock->lastdata = buf;
701 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
702 p = (struct pbuf *)buf;
704 p = ((struct netbuf *)buf)->p;
707 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
708 buflen, len, off, sock->lastoffset));
710 buflen -= sock->lastoffset;
715 copylen = (u16_t)len;
718 /* copy the contents of the received buffer into
719 the supplied memory pointer mem */
720 pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
724 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
725 LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
728 (p->flags & PBUF_FLAG_PUSH) ||
729 (sock->rcvevent <= 0) ||
730 ((flags & MSG_PEEK)!=0)) {
737 /* Check to see from where the data was.*/
741 #endif /* !SOCKETS_DEBUG */
745 ipX_addr_t *fromaddr;
746 union sockaddr_aligned saddr;
747 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
748 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
750 /* @todo: this does not work for IPv6, yet */
751 netconn_getaddr(sock->conn, ipX_2_ip(fromaddr), &port, 0);
753 port = netbuf_fromport((struct netbuf *)buf);
754 fromaddr = netbuf_fromaddr_ipX((struct netbuf *)buf);
756 IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
757 &saddr, fromaddr, port);
758 ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
759 SOCKETS_DEBUG, fromaddr);
760 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
761 if (*fromlen > saddr.sa.sa_len) {
762 *fromlen = saddr.sa.sa_len;
764 MEMCPY(from, &saddr, *fromlen);
768 /* If we don't peek the incoming message... */
769 if ((flags & MSG_PEEK) == 0) {
770 /* If this is a TCP socket, check if there is data left in the
771 buffer. If so, it should be saved in the sock structure for next
773 if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (buflen - copylen > 0)) {
774 sock->lastdata = buf;
775 sock->lastoffset += copylen;
776 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
778 sock->lastdata = NULL;
779 sock->lastoffset = 0;
780 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
781 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
782 pbuf_free((struct pbuf *)buf);
784 netbuf_delete((struct netbuf *)buf);
790 if ((off > 0) && (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP)) {
791 /* update receive window */
792 netconn_recved(sock->conn, (u32_t)off);
794 sock_set_errno(sock, 0);
799 lwip_read(int s, void *mem, size_t len)
801 return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
805 lwip_recv(int s, void *mem, size_t len, int flags)
807 return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
811 lwip_send(int s, const void *data, size_t size, int flags)
813 struct lwip_sock *sock;
818 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
819 s, data, size, flags));
821 sock = get_socket(s);
826 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
827 #if (LWIP_UDP || LWIP_RAW)
828 return lwip_sendto(s, data, size, flags, NULL, 0);
829 #else /* (LWIP_UDP || LWIP_RAW) */
830 sock_set_errno(sock, err_to_errno(ERR_ARG));
832 #endif /* (LWIP_UDP || LWIP_RAW) */
835 write_flags = NETCONN_COPY |
836 ((flags & MSG_MORE) ? NETCONN_MORE : 0) |
837 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
839 err = netconn_write_partly(sock->conn, data, size, write_flags, &written);
841 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written));
842 sock_set_errno(sock, err_to_errno(err));
843 return (err == ERR_OK ? (int)written : -1);
847 lwip_sendto(int s, const void *data, size_t size, int flags,
848 const struct sockaddr *to, socklen_t tolen)
850 struct lwip_sock *sock;
854 #if !LWIP_TCPIP_CORE_LOCKING
858 sock = get_socket(s);
863 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
865 return lwip_send(s, data, size, flags);
867 LWIP_UNUSED_ARG(flags);
868 sock_set_errno(sock, err_to_errno(ERR_ARG));
870 #endif /* LWIP_TCP */
873 if ((to != NULL) && !SOCK_ADDR_TYPE_MATCH(to, sock)) {
874 /* sockaddr does not match socket type (IPv4/IPv6) */
875 sock_set_errno(sock, err_to_errno(ERR_VAL));
879 /* @todo: split into multiple sendto's? */
880 LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
881 short_size = (u16_t)size;
882 LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
883 (IS_SOCK_ADDR_LEN_VALID(tolen) &&
884 IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))),
885 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
886 LWIP_UNUSED_ARG(tolen);
888 #if LWIP_TCPIP_CORE_LOCKING
889 /* Special speedup for fast UDP/RAW sending: call the raw API directly
890 instead of using the netconn functions. */
893 ipX_addr_t *remote_addr;
894 ipX_addr_t remote_addr_tmp;
896 #if LWIP_NETIF_TX_SINGLE_PBUF
897 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM);
899 #if LWIP_CHECKSUM_ON_COPY
901 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
902 chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size);
904 #endif /* LWIP_CHECKSUM_ON_COPY */
905 MEMCPY(p->payload, data, size);
906 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
907 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF);
909 p->payload = (void*)data;
910 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
913 SOCKADDR_TO_IPXADDR_PORT(to->sa_family == AF_INET6,
914 to, &remote_addr_tmp, remote_port);
915 remote_addr = &remote_addr_tmp;
917 remote_addr = &sock->conn->pcb.ip->remote_ip;
919 if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_UDP) {
920 remote_port = sock->conn->pcb.udp->remote_port;
922 #endif /* LWIP_UDP */
929 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_RAW) {
931 err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, ipX_2_ip(remote_addr));
934 #endif /* LWIP_RAW */
936 #if LWIP_UDP && LWIP_RAW
938 #endif /* LWIP_UDP && LWIP_RAW */
941 #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF
942 err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,
943 ipX_2_ip(remote_addr), remote_port, 1, chksum);
944 #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
945 err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p,
946 ipX_2_ip(remote_addr), remote_port);
947 #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
950 #endif /* LWIP_UDP */
959 #else /* LWIP_TCPIP_CORE_LOCKING */
960 /* initialize a buffer */
961 buf.p = buf.ptr = NULL;
962 #if LWIP_CHECKSUM_ON_COPY
964 #endif /* LWIP_CHECKSUM_ON_COPY */
966 SOCKADDR_TO_IPXADDR_PORT((to->sa_family) == AF_INET6, to, &buf.addr, remote_port);
969 ipX_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr);
971 netbuf_fromport(&buf) = remote_port;
974 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
975 s, data, short_size, flags));
976 ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
977 SOCKETS_DEBUG, &buf.addr);
978 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
980 /* make the buffer point to the data that should be sent */
981 #if LWIP_NETIF_TX_SINGLE_PBUF
982 /* Allocate a new netbuf and copy the data into it. */
983 if (netbuf_alloc(&buf, short_size) == NULL) {
986 #if LWIP_CHECKSUM_ON_COPY
987 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
988 u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
989 netbuf_set_chksum(&buf, chksum);
992 #endif /* LWIP_CHECKSUM_ON_COPY */
994 err = netbuf_take(&buf, data, short_size);
997 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
998 err = netbuf_ref(&buf, data, short_size);
999 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
1000 if (err == ERR_OK) {
1002 err = netconn_send(sock->conn, &buf);
1005 /* deallocated the buffer */
1007 #endif /* LWIP_TCPIP_CORE_LOCKING */
1008 sock_set_errno(sock, err_to_errno(err));
1009 return (err == ERR_OK ? short_size : -1);
1013 lwip_socket(int domain, int type, int protocol)
1015 struct netconn *conn;
1019 LWIP_UNUSED_ARG(domain); /* @todo: check this */
1020 #endif /* LWIP_IPV6 */
1022 /* create a netconn */
1025 conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW),
1026 (u8_t)protocol, event_callback);
1027 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
1028 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1031 conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain,
1032 ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) ,
1034 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
1035 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1038 conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), event_callback);
1039 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
1040 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1042 /* Prevent automatic window updates, we do this on our own! */
1043 netconn_set_noautorecved(conn, 1);
1047 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
1048 domain, type, protocol));
1054 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
1059 i = alloc_socket(conn, 0);
1062 netconn_delete(conn);
1067 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
1073 lwip_write(int s, const void *data, size_t size)
1075 return lwip_send(s, data, size, 0);
1079 * Go through the readset and writeset lists and see which socket of the sockets
1080 * set in the sets has events. On return, readset, writeset and exceptset have
1081 * the sockets enabled that had events.
1083 * exceptset is not used for now!!!
1085 * @param maxfdp1 the highest socket index in the sets
1086 * @param readset_in: set of sockets to check for read events
1087 * @param writeset_in: set of sockets to check for write events
1088 * @param exceptset_in: set of sockets to check for error events
1089 * @param readset_out: set of sockets that had read events
1090 * @param writeset_out: set of sockets that had write events
1091 * @param exceptset_out: set os sockets that had error events
1092 * @return number of sockets that had events (read/write/exception) (>= 0)
1095 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
1096 fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
1099 fd_set lreadset, lwriteset, lexceptset;
1100 struct lwip_sock *sock;
1101 SYS_ARCH_DECL_PROTECT(lev);
1104 FD_ZERO(&lwriteset);
1105 FD_ZERO(&lexceptset);
1107 /* Go through each socket in each list to count number of sockets which
1109 for(i = 0; i < maxfdp1; i++) {
1110 void* lastdata = NULL;
1112 u16_t sendevent = 0;
1114 /* First get the socket's status (protected)... */
1115 SYS_ARCH_PROTECT(lev);
1116 sock = tryget_socket(i);
1118 lastdata = sock->lastdata;
1119 rcvevent = sock->rcvevent;
1120 sendevent = sock->sendevent;
1121 errevent = sock->errevent;
1123 SYS_ARCH_UNPROTECT(lev);
1124 /* ... then examine it: */
1125 /* See if netconn of this socket is ready for read */
1126 if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
1127 FD_SET(i, &lreadset);
1128 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
1131 /* See if netconn of this socket is ready for write */
1132 if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
1133 FD_SET(i, &lwriteset);
1134 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
1137 /* See if netconn of this socket had an error */
1138 if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
1139 FD_SET(i, &lexceptset);
1140 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
1144 /* copy local sets to the ones provided as arguments */
1145 *readset_out = lreadset;
1146 *writeset_out = lwriteset;
1147 *exceptset_out = lexceptset;
1149 LWIP_ASSERT("nready >= 0", nready >= 0);
1154 * Processing exceptset is not yet implemented.
1157 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
1158 struct timeval *timeout)
1162 fd_set lreadset, lwriteset, lexceptset;
1164 struct lwip_select_cb select_cb;
1167 SYS_ARCH_DECL_PROTECT(lev);
1169 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
1170 maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
1171 timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
1172 timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
1174 /* Go through each socket in each list to count number of sockets which
1176 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1178 /* If we don't have any current events, then suspend if we are supposed to */
1180 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
1181 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
1182 /* This is OK as the local fdsets are empty and nready is zero,
1183 or we would have returned earlier. */
1184 goto return_copy_fdsets;
1187 /* None ready: add our semaphore to list:
1188 We don't actually need any dynamic memory. Our entry on the
1189 list is only valid while we are in this function, so it's ok
1190 to use local variables. */
1192 select_cb.next = NULL;
1193 select_cb.prev = NULL;
1194 select_cb.readset = readset;
1195 select_cb.writeset = writeset;
1196 select_cb.exceptset = exceptset;
1197 select_cb.sem_signalled = 0;
1198 err = sys_sem_new(&select_cb.sem, 0);
1199 if (err != ERR_OK) {
1200 /* failed to create semaphore */
1205 /* Protect the select_cb_list */
1206 SYS_ARCH_PROTECT(lev);
1208 /* Put this select_cb on top of list */
1209 select_cb.next = select_cb_list;
1210 if (select_cb_list != NULL) {
1211 select_cb_list->prev = &select_cb;
1213 select_cb_list = &select_cb;
1214 /* Increasing this counter tells even_callback that the list has changed. */
1217 /* Now we can safely unprotect */
1218 SYS_ARCH_UNPROTECT(lev);
1220 /* Increase select_waiting for each socket we are interested in */
1221 for(i = 0; i < maxfdp1; i++) {
1222 if ((readset && FD_ISSET(i, readset)) ||
1223 (writeset && FD_ISSET(i, writeset)) ||
1224 (exceptset && FD_ISSET(i, exceptset))) {
1225 struct lwip_sock *sock = tryget_socket(i);
1226 LWIP_ASSERT("sock != NULL", sock != NULL);
1227 SYS_ARCH_PROTECT(lev);
1228 sock->select_waiting++;
1229 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
1230 SYS_ARCH_UNPROTECT(lev);
1234 /* Call lwip_selscan again: there could have been events between
1235 the last scan (whithout us on the list) and putting us on the list! */
1236 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1238 /* Still none ready, just wait to be woken */
1243 msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
1244 if (msectimeout == 0) {
1245 /* Wait 1ms at least (0 means wait forever) */
1250 waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
1252 /* Increase select_waiting for each socket we are interested in */
1253 for(i = 0; i < maxfdp1; i++) {
1254 if ((readset && FD_ISSET(i, readset)) ||
1255 (writeset && FD_ISSET(i, writeset)) ||
1256 (exceptset && FD_ISSET(i, exceptset))) {
1257 struct lwip_sock *sock = tryget_socket(i);
1258 LWIP_ASSERT("sock != NULL", sock != NULL);
1259 SYS_ARCH_PROTECT(lev);
1260 sock->select_waiting--;
1261 LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0);
1262 SYS_ARCH_UNPROTECT(lev);
1265 /* Take us off the list */
1266 SYS_ARCH_PROTECT(lev);
1267 if (select_cb.next != NULL) {
1268 select_cb.next->prev = select_cb.prev;
1270 if (select_cb_list == &select_cb) {
1271 LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
1272 select_cb_list = select_cb.next;
1274 LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
1275 select_cb.prev->next = select_cb.next;
1277 /* Increasing this counter tells even_callback that the list has changed. */
1279 SYS_ARCH_UNPROTECT(lev);
1281 sys_sem_free(&select_cb.sem);
1282 if (waitres == SYS_ARCH_TIMEOUT) {
1284 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
1285 /* This is OK as the local fdsets are empty and nready is zero,
1286 or we would have returned earlier. */
1287 goto return_copy_fdsets;
1290 /* See what's set */
1291 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1294 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
1298 *readset = lreadset;
1301 *writeset = lwriteset;
1304 *exceptset = lexceptset;
1310 * Callback registered in the netconn layer for each socket-netconn.
1311 * Processes recvevent (data available) and wakes up tasks waiting for select.
1314 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
1317 struct lwip_sock *sock;
1318 struct lwip_select_cb *scb;
1319 int last_select_cb_ctr;
1320 SYS_ARCH_DECL_PROTECT(lev);
1322 LWIP_UNUSED_ARG(len);
1328 /* Data comes in right away after an accept, even though
1329 * the server task might not have created a new socket yet.
1330 * Just count down (or up) if that's the case and we
1331 * will use the data later. Note that only receive events
1332 * can happen before the new socket is set up. */
1333 SYS_ARCH_PROTECT(lev);
1334 if (conn->socket < 0) {
1335 if (evt == NETCONN_EVT_RCVPLUS) {
1338 SYS_ARCH_UNPROTECT(lev);
1342 SYS_ARCH_UNPROTECT(lev);
1345 sock = get_socket(s);
1353 SYS_ARCH_PROTECT(lev);
1354 /* Set event as required */
1356 case NETCONN_EVT_RCVPLUS:
1359 case NETCONN_EVT_RCVMINUS:
1362 case NETCONN_EVT_SENDPLUS:
1363 sock->sendevent = 1;
1365 case NETCONN_EVT_SENDMINUS:
1366 sock->sendevent = 0;
1368 case NETCONN_EVT_ERROR:
1372 LWIP_ASSERT("unknown event", 0);
1376 if (sock->select_waiting == 0) {
1377 /* noone is waiting for this socket, no need to check select_cb_list */
1378 SYS_ARCH_UNPROTECT(lev);
1382 /* Now decide if anyone is waiting for this socket */
1383 /* NOTE: This code goes through the select_cb_list list multiple times
1384 ONLY IF a select was actually waiting. We go through the list the number
1385 of waiting select calls + 1. This list is expected to be small. */
1387 /* At this point, SYS_ARCH is still protected! */
1389 for (scb = select_cb_list; scb != NULL; scb = scb->next) {
1390 if (scb->sem_signalled == 0) {
1391 /* semaphore not signalled yet */
1393 /* Test this select call for our socket */
1394 if (sock->rcvevent > 0) {
1395 if (scb->readset && FD_ISSET(s, scb->readset)) {
1399 if (sock->sendevent != 0) {
1400 if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
1404 if (sock->errevent != 0) {
1405 if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
1410 scb->sem_signalled = 1;
1411 /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
1412 lead to the select thread taking itself off the list, invalidagin the semaphore. */
1413 sys_sem_signal(&scb->sem);
1416 /* unlock interrupts with each step */
1417 last_select_cb_ctr = select_cb_ctr;
1418 SYS_ARCH_UNPROTECT(lev);
1419 /* this makes sure interrupt protection time is short */
1420 SYS_ARCH_PROTECT(lev);
1421 if (last_select_cb_ctr != select_cb_ctr) {
1422 /* someone has changed select_cb_list, restart at the beginning */
1426 SYS_ARCH_UNPROTECT(lev);
1430 * Unimplemented: Close one end of a full-duplex connection.
1431 * Currently, the full connection is closed.
1434 lwip_shutdown(int s, int how)
1436 struct lwip_sock *sock;
1438 u8_t shut_rx = 0, shut_tx = 0;
1440 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
1442 sock = get_socket(s);
1447 if (sock->conn != NULL) {
1448 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
1449 sock_set_errno(sock, EOPNOTSUPP);
1453 sock_set_errno(sock, ENOTCONN);
1457 if (how == SHUT_RD) {
1459 } else if (how == SHUT_WR) {
1461 } else if(how == SHUT_RDWR) {
1465 sock_set_errno(sock, EINVAL);
1468 err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
1470 sock_set_errno(sock, err_to_errno(err));
1471 return (err == ERR_OK ? 0 : -1);
1475 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
1477 struct lwip_sock *sock;
1478 union sockaddr_aligned saddr;
1482 sock = get_socket(s);
1487 /* get the IP address and port */
1488 /* @todo: this does not work for IPv6, yet */
1489 netconn_getaddr(sock->conn, ipX_2_ip(&naddr), &port, local);
1490 IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
1491 &saddr, &naddr, port);
1493 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
1494 ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
1495 SOCKETS_DEBUG, &naddr);
1496 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port));
1498 if (*namelen > saddr.sa.sa_len) {
1499 *namelen = saddr.sa.sa_len;
1501 MEMCPY(name, &saddr, *namelen);
1503 sock_set_errno(sock, 0);
1508 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
1510 return lwip_getaddrname(s, name, namelen, 0);
1514 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
1516 return lwip_getaddrname(s, name, namelen, 1);
1520 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
1523 struct lwip_sock *sock = get_socket(s);
1524 struct lwip_setgetsockopt_data data;
1530 if ((NULL == optval) || (NULL == optlen)) {
1531 sock_set_errno(sock, EFAULT);
1535 /* Do length and type checks for the various options first, to keep it readable. */
1538 /* Level: SOL_SOCKET */
1544 /* UNIMPL case SO_DEBUG: */
1545 /* UNIMPL case SO_DONTROUTE: */
1548 /* UNIMPL case SO_CONTIMEO: */
1549 #if LWIP_SO_SNDTIMEO
1551 #endif /* LWIP_SO_SNDTIMEO */
1552 #if LWIP_SO_RCVTIMEO
1554 #endif /* LWIP_SO_RCVTIMEO */
1557 #endif /* LWIP_SO_RCVBUF */
1558 /* UNIMPL case SO_OOBINLINE: */
1559 /* UNIMPL case SO_SNDBUF: */
1560 /* UNIMPL case SO_RCVLOWAT: */
1561 /* UNIMPL case SO_SNDLOWAT: */
1565 #endif /* SO_REUSE */
1567 /* UNIMPL case SO_USELOOPBACK: */
1568 if (*optlen < sizeof(int)) {
1574 if (*optlen < sizeof(int)) {
1578 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP ||
1579 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1580 /* this flag is only available for UDP, not for UDP lite */
1583 #endif /* LWIP_UDP */
1587 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1590 } /* switch (optname) */
1593 /* Level: IPPROTO_IP */
1596 /* UNIMPL case IP_HDRINCL: */
1597 /* UNIMPL case IP_RCVDSTADDR: */
1598 /* UNIMPL case IP_RCVIF: */
1601 if (*optlen < sizeof(int)) {
1606 case IP_MULTICAST_TTL:
1607 if (*optlen < sizeof(u8_t)) {
1611 case IP_MULTICAST_IF:
1612 if (*optlen < sizeof(struct in_addr)) {
1616 case IP_MULTICAST_LOOP:
1617 if (*optlen < sizeof(u8_t)) {
1620 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
1624 #endif /* LWIP_IGMP */
1627 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1630 } /* switch (optname) */
1634 /* Level: IPPROTO_TCP */
1636 if (*optlen < sizeof(int)) {
1641 /* If this is no TCP socket, ignore any options. */
1642 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP)
1648 #if LWIP_TCP_KEEPALIVE
1652 #endif /* LWIP_TCP_KEEPALIVE */
1656 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
1659 } /* switch (optname) */
1661 #endif /* LWIP_TCP */
1662 #if LWIP_UDP && LWIP_UDPLITE
1663 /* Level: IPPROTO_UDPLITE */
1664 case IPPROTO_UDPLITE:
1665 if (*optlen < sizeof(int)) {
1670 /* If this is no UDP lite socket, ignore any options. */
1671 if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
1676 case UDPLITE_SEND_CSCOV:
1677 case UDPLITE_RECV_CSCOV:
1681 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
1684 } /* switch (optname) */
1686 #endif /* LWIP_UDP && LWIP_UDPLITE*/
1687 /* UNDEFINED LEVEL */
1689 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
1690 s, level, optname));
1695 if (err != ERR_OK) {
1696 sock_set_errno(sock, err);
1700 /* Now do the actual option processing */
1704 #endif /* LWIP_DEBUG */
1706 data.optname = optname;
1707 data.optval = optval;
1708 data.optlen = optlen;
1710 tcpip_callback(lwip_getsockopt_internal, &data);
1711 sys_arch_sem_wait(&sock->conn->op_completed, 0);
1712 /* maybe lwip_getsockopt_internal has changed err */
1715 sock_set_errno(sock, err);
1716 return err ? -1 : 0;
1720 lwip_getsockopt_internal(void *arg)
1722 struct lwip_sock *sock;
1725 #endif /* LWIP_DEBUG */
1728 struct lwip_setgetsockopt_data *data;
1730 LWIP_ASSERT("arg != NULL", arg != NULL);
1732 data = (struct lwip_setgetsockopt_data*)arg;
1736 #endif /* LWIP_DEBUG */
1737 level = data->level;
1738 optname = data->optname;
1739 optval = data->optval;
1743 /* Level: SOL_SOCKET */
1747 /* The option flags */
1750 /* UNIMPL case SO_DEBUG: */
1751 /* UNIMPL case SO_DONTROUTE: */
1753 /* UNIMPL case SO_OOBINCLUDE: */
1757 #endif /* SO_REUSE */
1758 /*case SO_USELOOPBACK: UNIMPL */
1759 *(int*)optval = sock->conn->pcb.ip->so_options & optname;
1760 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
1761 s, optname, (*(int*)optval?"on":"off")));
1765 switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) {
1767 *(int*)optval = SOCK_RAW;
1770 *(int*)optval = SOCK_STREAM;
1773 *(int*)optval = SOCK_DGRAM;
1775 default: /* unrecognized socket type */
1776 *(int*)optval = netconn_type(sock->conn);
1777 LWIP_DEBUGF(SOCKETS_DEBUG,
1778 ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
1779 s, *(int *)optval));
1780 } /* switch (netconn_type(sock->conn)) */
1781 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
1782 s, *(int *)optval));
1786 /* only overwrite ERR_OK or tempoary errors */
1787 if ((sock->err == 0) || (sock->err == EINPROGRESS)) {
1788 sock_set_errno(sock, err_to_errno(sock->conn->last_err));
1790 *(int *)optval = sock->err;
1792 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
1793 s, *(int *)optval));
1796 #if LWIP_SO_SNDTIMEO
1798 *(int *)optval = netconn_get_sendtimeout(sock->conn);
1800 #endif /* LWIP_SO_SNDTIMEO */
1801 #if LWIP_SO_RCVTIMEO
1803 *(int *)optval = netconn_get_recvtimeout(sock->conn);
1805 #endif /* LWIP_SO_RCVTIMEO */
1808 *(int *)optval = netconn_get_recvbufsize(sock->conn);
1810 #endif /* LWIP_SO_RCVBUF */
1813 *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
1815 #endif /* LWIP_UDP*/
1817 LWIP_ASSERT("unhandled optname", 0);
1819 } /* switch (optname) */
1822 /* Level: IPPROTO_IP */
1826 *(int*)optval = sock->conn->pcb.ip->ttl;
1827 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
1828 s, *(int *)optval));
1831 *(int*)optval = sock->conn->pcb.ip->tos;
1832 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
1833 s, *(int *)optval));
1836 case IP_MULTICAST_TTL:
1837 *(u8_t*)optval = sock->conn->pcb.ip->ttl;
1838 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
1839 s, *(int *)optval));
1841 case IP_MULTICAST_IF:
1842 inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip);
1843 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
1844 s, *(u32_t *)optval));
1846 case IP_MULTICAST_LOOP:
1847 if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
1852 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
1853 s, *(int *)optval));
1855 #endif /* LWIP_IGMP */
1857 LWIP_ASSERT("unhandled optname", 0);
1859 } /* switch (optname) */
1863 /* Level: IPPROTO_TCP */
1867 *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
1868 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
1869 s, (*(int*)optval)?"on":"off") );
1872 *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
1873 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",
1874 s, *(int *)optval));
1877 #if LWIP_TCP_KEEPALIVE
1879 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
1880 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",
1881 s, *(int *)optval));
1884 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
1885 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",
1886 s, *(int *)optval));
1889 *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
1890 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",
1891 s, *(int *)optval));
1893 #endif /* LWIP_TCP_KEEPALIVE */
1895 LWIP_ASSERT("unhandled optname", 0);
1897 } /* switch (optname) */
1899 #endif /* LWIP_TCP */
1900 #if LWIP_UDP && LWIP_UDPLITE
1901 /* Level: IPPROTO_UDPLITE */
1902 case IPPROTO_UDPLITE:
1904 case UDPLITE_SEND_CSCOV:
1905 *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
1906 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
1907 s, (*(int*)optval)) );
1909 case UDPLITE_RECV_CSCOV:
1910 *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
1911 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
1912 s, (*(int*)optval)) );
1915 LWIP_ASSERT("unhandled optname", 0);
1917 } /* switch (optname) */
1919 #endif /* LWIP_UDP */
1921 LWIP_ASSERT("unhandled level", 0);
1923 } /* switch (level) */
1924 sys_sem_signal(&sock->conn->op_completed);
1928 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
1930 struct lwip_sock *sock = get_socket(s);
1932 struct lwip_setgetsockopt_data data;
1938 if (NULL == optval) {
1939 sock_set_errno(sock, EFAULT);
1943 /* Do length and type checks for the various options first, to keep it readable. */
1946 /* Level: SOL_SOCKET */
1951 /* UNIMPL case SO_DEBUG: */
1952 /* UNIMPL case SO_DONTROUTE: */
1954 /* UNIMPL case case SO_CONTIMEO: */
1955 #if LWIP_SO_SNDTIMEO
1957 #endif /* LWIP_SO_SNDTIMEO */
1958 #if LWIP_SO_RCVTIMEO
1960 #endif /* LWIP_SO_RCVTIMEO */
1963 #endif /* LWIP_SO_RCVBUF */
1964 /* UNIMPL case SO_OOBINLINE: */
1965 /* UNIMPL case SO_SNDBUF: */
1966 /* UNIMPL case SO_RCVLOWAT: */
1967 /* UNIMPL case SO_SNDLOWAT: */
1971 #endif /* SO_REUSE */
1972 /* UNIMPL case SO_USELOOPBACK: */
1973 if (optlen < sizeof(int)) {
1978 if (optlen < sizeof(int)) {
1982 if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) ||
1983 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1984 /* this flag is only available for UDP, not for UDP lite */
1987 #endif /* LWIP_UDP */
1990 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1993 } /* switch (optname) */
1996 /* Level: IPPROTO_IP */
1999 /* UNIMPL case IP_HDRINCL: */
2000 /* UNIMPL case IP_RCVDSTADDR: */
2001 /* UNIMPL case IP_RCVIF: */
2004 if (optlen < sizeof(int)) {
2009 case IP_MULTICAST_TTL:
2010 if (optlen < sizeof(u8_t)) {
2013 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2017 case IP_MULTICAST_IF:
2018 if (optlen < sizeof(struct in_addr)) {
2021 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2025 case IP_MULTICAST_LOOP:
2026 if (optlen < sizeof(u8_t)) {
2029 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2033 case IP_ADD_MEMBERSHIP:
2034 case IP_DROP_MEMBERSHIP:
2035 if (optlen < sizeof(struct ip_mreq)) {
2038 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2042 #endif /* LWIP_IGMP */
2044 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
2047 } /* switch (optname) */
2051 /* Level: IPPROTO_TCP */
2053 if (optlen < sizeof(int)) {
2058 /* If this is no TCP socket, ignore any options. */
2059 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP)
2065 #if LWIP_TCP_KEEPALIVE
2069 #endif /* LWIP_TCP_KEEPALIVE */
2073 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
2076 } /* switch (optname) */
2078 #endif /* LWIP_TCP */
2079 #if LWIP_UDP && LWIP_UDPLITE
2080 /* Level: IPPROTO_UDPLITE */
2081 case IPPROTO_UDPLITE:
2082 if (optlen < sizeof(int)) {
2087 /* If this is no UDP lite socket, ignore any options. */
2088 if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn)))
2092 case UDPLITE_SEND_CSCOV:
2093 case UDPLITE_RECV_CSCOV:
2097 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
2100 } /* switch (optname) */
2102 #endif /* LWIP_UDP && LWIP_UDPLITE */
2103 /* UNDEFINED LEVEL */
2105 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2106 s, level, optname));
2108 } /* switch (level) */
2111 if (err != ERR_OK) {
2112 sock_set_errno(sock, err);
2117 /* Now do the actual option processing */
2121 #endif /* LWIP_DEBUG */
2123 data.optname = optname;
2124 data.optval = (void*)optval;
2125 data.optlen = &optlen;
2127 tcpip_callback(lwip_setsockopt_internal, &data);
2128 sys_arch_sem_wait(&sock->conn->op_completed, 0);
2129 /* maybe lwip_setsockopt_internal has changed err */
2132 sock_set_errno(sock, err);
2133 return err ? -1 : 0;
2137 lwip_setsockopt_internal(void *arg)
2139 struct lwip_sock *sock;
2142 #endif /* LWIP_DEBUG */
2145 struct lwip_setgetsockopt_data *data;
2147 LWIP_ASSERT("arg != NULL", arg != NULL);
2149 data = (struct lwip_setgetsockopt_data*)arg;
2153 #endif /* LWIP_DEBUG */
2154 level = data->level;
2155 optname = data->optname;
2156 optval = data->optval;
2160 /* Level: SOL_SOCKET */
2164 /* The option flags */
2166 /* UNIMPL case SO_DEBUG: */
2167 /* UNIMPL case SO_DONTROUTE: */
2169 /* UNIMPL case SO_OOBINCLUDE: */
2173 #endif /* SO_REUSE */
2174 /* UNIMPL case SO_USELOOPBACK: */
2175 if (*(int*)optval) {
2176 sock->conn->pcb.ip->so_options |= optname;
2178 sock->conn->pcb.ip->so_options &= ~optname;
2180 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
2181 s, optname, (*(int*)optval?"on":"off")));
2183 #if LWIP_SO_SNDTIMEO
2185 netconn_set_sendtimeout(sock->conn, (s32_t)*(int*)optval);
2187 #endif /* LWIP_SO_SNDTIMEO */
2188 #if LWIP_SO_RCVTIMEO
2190 netconn_set_recvtimeout(sock->conn, *(int*)optval);
2192 #endif /* LWIP_SO_RCVTIMEO */
2195 netconn_set_recvbufsize(sock->conn, *(int*)optval);
2197 #endif /* LWIP_SO_RCVBUF */
2200 if (*(int*)optval) {
2201 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
2203 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
2206 #endif /* LWIP_UDP */
2208 LWIP_ASSERT("unhandled optname", 0);
2210 } /* switch (optname) */
2213 /* Level: IPPROTO_IP */
2217 sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
2218 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
2219 s, sock->conn->pcb.ip->ttl));
2222 sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
2223 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
2224 s, sock->conn->pcb.ip->tos));
2227 case IP_MULTICAST_TTL:
2228 sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);
2230 case IP_MULTICAST_IF:
2231 inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval);
2233 case IP_MULTICAST_LOOP:
2234 if (*(u8_t*)optval) {
2235 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
2237 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
2240 case IP_ADD_MEMBERSHIP:
2241 case IP_DROP_MEMBERSHIP:
2243 /* If this is a TCP or a RAW socket, ignore these options. */
2244 struct ip_mreq *imr = (struct ip_mreq *)optval;
2246 ip_addr_t multi_addr;
2247 inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
2248 inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
2249 if(optname == IP_ADD_MEMBERSHIP){
2250 data->err = igmp_joingroup(&if_addr, &multi_addr);
2252 data->err = igmp_leavegroup(&if_addr, &multi_addr);
2254 if(data->err != ERR_OK) {
2255 data->err = EADDRNOTAVAIL;
2259 #endif /* LWIP_IGMP */
2261 LWIP_ASSERT("unhandled optname", 0);
2263 } /* switch (optname) */
2267 /* Level: IPPROTO_TCP */
2271 if (*(int*)optval) {
2272 tcp_nagle_disable(sock->conn->pcb.tcp);
2274 tcp_nagle_enable(sock->conn->pcb.tcp);
2276 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
2277 s, (*(int *)optval)?"on":"off") );
2280 sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
2281 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
2282 s, sock->conn->pcb.tcp->keep_idle));
2285 #if LWIP_TCP_KEEPALIVE
2287 sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
2288 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
2289 s, sock->conn->pcb.tcp->keep_idle));
2292 sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
2293 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
2294 s, sock->conn->pcb.tcp->keep_intvl));
2297 sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
2298 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
2299 s, sock->conn->pcb.tcp->keep_cnt));
2301 #endif /* LWIP_TCP_KEEPALIVE */
2303 LWIP_ASSERT("unhandled optname", 0);
2305 } /* switch (optname) */
2307 #endif /* LWIP_TCP*/
2308 #if LWIP_UDP && LWIP_UDPLITE
2309 /* Level: IPPROTO_UDPLITE */
2310 case IPPROTO_UDPLITE:
2312 case UDPLITE_SEND_CSCOV:
2313 if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
2314 /* don't allow illegal values! */
2315 sock->conn->pcb.udp->chksum_len_tx = 8;
2317 sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;
2319 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
2320 s, (*(int*)optval)) );
2322 case UDPLITE_RECV_CSCOV:
2323 if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
2324 /* don't allow illegal values! */
2325 sock->conn->pcb.udp->chksum_len_rx = 8;
2327 sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;
2329 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
2330 s, (*(int*)optval)) );
2333 LWIP_ASSERT("unhandled optname", 0);
2335 } /* switch (optname) */
2337 #endif /* LWIP_UDP */
2339 LWIP_ASSERT("unhandled level", 0);
2341 } /* switch (level) */
2342 sys_sem_signal(&sock->conn->op_completed);
2346 lwip_ioctl(int s, long cmd, void *argp)
2348 struct lwip_sock *sock = get_socket(s);
2353 #endif /* LWIP_SO_RCVBUF */
2360 #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE
2363 sock_set_errno(sock, EINVAL);
2366 #if LWIP_FIONREAD_LINUXMODE
2367 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
2369 if (sock->lastdata) {
2370 p = ((struct netbuf *)sock->lastdata)->p;
2372 struct netbuf *rxbuf;
2374 if (sock->rcvevent <= 0) {
2375 *((u16_t*)argp) = 0;
2377 err = netconn_recv(sock->conn, &rxbuf);
2378 if (err != ERR_OK) {
2379 *((u16_t*)argp) = 0;
2381 sock->lastdata = rxbuf;
2382 *((u16_t*)argp) = rxbuf->p->tot_len;
2388 #endif /* LWIP_FIONREAD_LINUXMODE */
2391 /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */
2392 SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
2393 if (recv_avail < 0) {
2396 *((u16_t*)argp) = (u16_t)recv_avail;
2398 /* Check if there is data left from the last recv operation. /maq 041215 */
2399 if (sock->lastdata) {
2400 struct pbuf *p = (struct pbuf *)sock->lastdata;
2401 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
2402 p = ((struct netbuf *)p)->p;
2404 buflen = p->tot_len;
2405 buflen -= sock->lastoffset;
2407 *((u16_t*)argp) += buflen;
2410 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
2411 sock_set_errno(sock, 0);
2413 #else /* LWIP_SO_RCVBUF */
2415 #endif /* LWIP_SO_RCVBUF */
2416 #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */
2420 if (argp && *(u32_t*)argp) {
2423 netconn_set_nonblocking(sock->conn, val);
2424 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
2425 sock_set_errno(sock, 0);
2430 } /* switch (cmd) */
2431 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
2432 sock_set_errno(sock, ENOSYS); /* not yet implemented */
2436 /** A minimal implementation of fcntl.
2437 * Currently only the commands F_GETFL and F_SETFL are implemented.
2438 * Only the flag O_NONBLOCK is implemented.
2441 lwip_fcntl(int s, int cmd, int val)
2443 struct lwip_sock *sock = get_socket(s);
2446 if (!sock || !sock->conn) {
2452 ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
2455 if ((val & ~O_NONBLOCK) == 0) {
2456 /* only O_NONBLOCK, all other bits are zero */
2457 netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
2462 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
2468 #endif /* LWIP_SOCKET */