VM: simplify slab allocator
[minix.git] / lib / liblwip / api / sockets.c
blob9919b6112e0291c3c9b09ed46550b38dc6b50767
1 /**
2 * @file
3 * Sockets BSD-Like API module
5 */
7 /*
8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9 * All rights reserved.
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
31 * OF SUCH DAMAGE.
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>
41 #include "lwip/opt.h"
43 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
45 #include "lwip/sockets.h"
46 #include "lwip/api.h"
47 #include "lwip/sys.h"
48 #include "lwip/igmp.h"
49 #include "lwip/inet.h"
50 #include "lwip/tcp.h"
51 #include "lwip/raw.h"
52 #include "lwip/udp.h"
53 #include "lwip/tcpip.h"
54 #include "lwip/pbuf.h"
55 #if LWIP_CHECKSUM_ON_COPY
56 #include "lwip/inet_chksum.h"
57 #endif
59 #include <string.h>
61 #define NUM_SOCKETS MEMP_NUM_NETCONN
63 /** Contains all internal pointers and states used for a socket */
64 struct lwip_sock {
65 /** sockets currently are built on netconns, each socket has one netconn */
66 struct netconn *conn;
67 /** data that was left from the previous read */
68 void *lastdata;
69 /** offset in the data that was left from the previous read */
70 u16_t lastoffset;
71 /** number of times data was received, set by event_callback(),
72 tested by the receive and select functions */
73 s16_t rcvevent;
74 /** number of times data was ACKed (free send buffer), set by event_callback(),
75 tested by select */
76 u16_t sendevent;
77 /** error happened for this socket, set by event_callback(), tested by select */
78 u16_t errevent;
79 /** last error that occurred on this socket */
80 int err;
81 /** counter of how many threads are waiting for this socket using select */
82 int select_waiting;
85 /** Description for a task waiting in select */
86 struct lwip_select_cb {
87 /** Pointer to the next waiting task */
88 struct lwip_select_cb *next;
89 /** Pointer to the previous waiting task */
90 struct lwip_select_cb *prev;
91 /** readset passed to select */
92 fd_set *readset;
93 /** writeset passed to select */
94 fd_set *writeset;
95 /** unimplemented: exceptset passed to select */
96 fd_set *exceptset;
97 /** don't signal the same semaphore twice: set to 1 when signalled */
98 int sem_signalled;
99 /** semaphore to wake up a task waiting for select */
100 sys_sem_t sem;
103 /** This struct is used to pass data to the set/getsockopt_internal
104 * functions running in tcpip_thread context (only a void* is allowed) */
105 struct lwip_setgetsockopt_data {
106 /** socket struct for which to change options */
107 struct lwip_sock *sock;
108 /** socket index for which to change options */
109 int s;
110 /** level of the option to process */
111 int level;
112 /** name of the option to process */
113 int optname;
114 /** set: value to set the option to
115 * get: value of the option is stored here */
116 void *optval;
117 /** size of *optval */
118 socklen_t *optlen;
119 /** if an error occures, it is temporarily stored here */
120 err_t err;
123 /** The global array of available sockets */
124 static struct lwip_sock sockets[NUM_SOCKETS];
125 /** The global list of tasks waiting for select */
126 static struct lwip_select_cb *select_cb_list;
127 /** This counter is increased from lwip_select when the list is chagned
128 and checked in event_callback to see if it has changed. */
129 static volatile int select_cb_ctr;
131 /** Table to quickly map an lwIP error (err_t) to a socket error
132 * by using -err as an index */
133 static const int err_to_errno_table[] = {
134 0, /* ERR_OK 0 No error, everything OK. */
135 ENOMEM, /* ERR_MEM -1 Out of memory error. */
136 ENOBUFS, /* ERR_BUF -2 Buffer error. */
137 EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
138 EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
139 EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
140 EINVAL, /* ERR_VAL -6 Illegal value. */
141 EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
142 ECONNABORTED, /* ERR_ABRT -8 Connection aborted. */
143 ECONNRESET, /* ERR_RST -9 Connection reset. */
144 ESHUTDOWN, /* ERR_CLSD -10 Connection closed. */
145 ENOTCONN, /* ERR_CONN -11 Not connected. */
146 EIO, /* ERR_ARG -12 Illegal argument. */
147 EADDRINUSE, /* ERR_USE -13 Address in use. */
148 -1, /* ERR_IF -14 Low-level netif error */
149 -1, /* ERR_ISCONN -15 Already connected. */
152 #define ERR_TO_ERRNO_TABLE_SIZE \
153 (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
155 #define err_to_errno(err) \
156 ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
157 err_to_errno_table[-(err)] : EIO)
159 #ifdef ERRNO
160 #ifndef set_errno
161 #define set_errno(err) errno = (err)
162 #endif
163 #else /* ERRNO */
164 #define set_errno(err)
165 #endif /* ERRNO */
167 #define sock_set_errno(sk, e) do { \
168 sk->err = (e); \
169 set_errno(sk->err); \
170 } while (0)
172 /* Forward delcaration of some functions */
173 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
174 static void lwip_getsockopt_internal(void *arg);
175 static void lwip_setsockopt_internal(void *arg);
178 * Initialize this module. This function has to be called before any other
179 * functions in this module!
181 void
182 lwip_socket_init(void)
187 * Map a externally used socket index to the internal socket representation.
189 * @param s externally used socket index
190 * @return struct lwip_sock for the socket or NULL if not found
192 static struct lwip_sock *
193 get_socket(int s)
195 struct lwip_sock *sock;
197 if ((s < 0) || (s >= NUM_SOCKETS)) {
198 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
199 set_errno(EBADF);
200 return NULL;
203 sock = &sockets[s];
205 if (!sock->conn) {
206 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
207 set_errno(EBADF);
208 return NULL;
211 return sock;
215 * Same as get_socket but doesn't set errno
217 * @param s externally used socket index
218 * @return struct lwip_sock for the socket or NULL if not found
220 static struct lwip_sock *
221 tryget_socket(int s)
223 if ((s < 0) || (s >= NUM_SOCKETS)) {
224 return NULL;
226 if (!sockets[s].conn) {
227 return NULL;
229 return &sockets[s];
233 * Allocate a new socket for a given netconn.
235 * @param newconn the netconn for which to allocate a socket
236 * @param accepted 1 if socket has been created by accept(),
237 * 0 if socket has been created by socket()
238 * @return the index of the new socket; -1 on error
240 static int
241 alloc_socket(struct netconn *newconn, int accepted)
243 int i;
244 SYS_ARCH_DECL_PROTECT(lev);
246 /* allocate a new socket identifier */
247 for (i = 0; i < NUM_SOCKETS; ++i) {
248 /* Protect socket array */
249 SYS_ARCH_PROTECT(lev);
250 if (!sockets[i].conn) {
251 sockets[i].conn = newconn;
252 /* The socket is not yet known to anyone, so no need to protect
253 after having marked it as used. */
254 SYS_ARCH_UNPROTECT(lev);
255 sockets[i].lastdata = NULL;
256 sockets[i].lastoffset = 0;
257 sockets[i].rcvevent = 0;
258 /* TCP sendbuf is empty, but the socket is not yet writable until connected
259 * (unless it has been created by accept()). */
260 sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);
261 sockets[i].errevent = 0;
262 sockets[i].err = 0;
263 sockets[i].select_waiting = 0;
264 return i;
266 SYS_ARCH_UNPROTECT(lev);
268 return -1;
271 /** Free a socket. The socket's netconn must have been
272 * delete before!
274 * @param sock the socket to free
275 * @param is_tcp != 0 for TCP sockets, used to free lastdata
277 static void
278 free_socket(struct lwip_sock *sock, int is_tcp)
280 void *lastdata;
281 SYS_ARCH_DECL_PROTECT(lev);
283 lastdata = sock->lastdata;
284 sock->lastdata = NULL;
285 sock->lastoffset = 0;
286 sock->err = 0;
288 /* Protect socket array */
289 SYS_ARCH_PROTECT(lev);
290 sock->conn = NULL;
291 SYS_ARCH_UNPROTECT(lev);
292 /* don't use 'sock' after this line, as another task might have allocated it */
294 if (lastdata != NULL) {
295 if (is_tcp) {
296 pbuf_free((struct pbuf *)lastdata);
297 } else {
298 netbuf_delete((struct netbuf *)lastdata);
303 /* Below this, the well-known socket functions are implemented.
304 * Use google.com or opengroup.org to get a good description :-)
306 * Exceptions are documented!
310 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
312 struct lwip_sock *sock, *nsock;
313 struct netconn *newconn;
314 ip_addr_t naddr;
315 u16_t port;
316 int newsock;
317 struct sockaddr_in sin;
318 err_t err;
319 SYS_ARCH_DECL_PROTECT(lev);
321 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
322 sock = get_socket(s);
323 if (!sock) {
324 return -1;
327 if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
328 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
329 sock_set_errno(sock, EWOULDBLOCK);
330 return -1;
333 /* wait for a new connection */
334 err = netconn_accept(sock->conn, &newconn);
335 if (err != ERR_OK) {
336 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
337 sock_set_errno(sock, err_to_errno(err));
338 return -1;
340 LWIP_ASSERT("newconn != NULL", newconn != NULL);
341 /* Prevent automatic window updates, we do this on our own! */
342 netconn_set_noautorecved(newconn, 1);
344 /* get the IP address and port of the remote host */
345 err = netconn_peer(newconn, &naddr, &port);
346 if (err != ERR_OK) {
347 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
348 netconn_delete(newconn);
349 sock_set_errno(sock, err_to_errno(err));
350 return -1;
353 /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
354 * not be NULL if addr is valid.
356 if (NULL != addr) {
357 LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
358 memset(&sin, 0, sizeof(sin));
359 sin.sin_len = sizeof(sin);
360 sin.sin_family = AF_INET;
361 sin.sin_port = htons(port);
362 inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
364 if (*addrlen > sizeof(sin))
365 *addrlen = sizeof(sin);
367 MEMCPY(addr, &sin, *addrlen);
370 newsock = alloc_socket(newconn, 1);
371 if (newsock == -1) {
372 netconn_delete(newconn);
373 sock_set_errno(sock, ENFILE);
374 return -1;
376 LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));
377 LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
378 nsock = &sockets[newsock];
380 /* See event_callback: If data comes in right away after an accept, even
381 * though the server task might not have created a new socket yet.
382 * In that case, newconn->socket is counted down (newconn->socket--),
383 * so nsock->rcvevent is >= 1 here!
385 SYS_ARCH_PROTECT(lev);
386 nsock->rcvevent += (s16_t)(-1 - newconn->socket);
387 newconn->socket = newsock;
388 SYS_ARCH_UNPROTECT(lev);
390 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
391 ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
392 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
394 sock_set_errno(sock, 0);
395 return newsock;
399 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
401 struct lwip_sock *sock;
402 ip_addr_t local_addr;
403 u16_t local_port;
404 err_t err;
405 const struct sockaddr_in *name_in;
407 sock = get_socket(s);
408 if (!sock) {
409 return -1;
412 /* check size, familiy and alignment of 'name' */
413 LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
414 ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
415 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
416 name_in = (const struct sockaddr_in *)(void*)name;
418 inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);
419 local_port = name_in->sin_port;
421 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
422 ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
423 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port)));
425 err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
427 if (err != ERR_OK) {
428 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
429 sock_set_errno(sock, err_to_errno(err));
430 return -1;
433 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
434 sock_set_errno(sock, 0);
435 return 0;
439 lwip_close(int s)
441 struct lwip_sock *sock;
442 int is_tcp = 0;
444 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
446 sock = get_socket(s);
447 if (!sock) {
448 return -1;
451 if(sock->conn != NULL) {
452 is_tcp = netconn_type(sock->conn) == NETCONN_TCP;
453 } else {
454 LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
457 netconn_delete(sock->conn);
459 free_socket(sock, is_tcp);
460 set_errno(0);
461 return 0;
465 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
467 struct lwip_sock *sock;
468 err_t err;
469 const struct sockaddr_in *name_in;
471 sock = get_socket(s);
472 if (!sock) {
473 return -1;
476 /* check size, familiy and alignment of 'name' */
477 LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
478 ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
479 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
480 name_in = (const struct sockaddr_in *)(void*)name;
482 if (name_in->sin_family == AF_UNSPEC) {
483 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
484 err = netconn_disconnect(sock->conn);
485 } else {
486 ip_addr_t remote_addr;
487 u16_t remote_port;
489 inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);
490 remote_port = name_in->sin_port;
492 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
493 ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
494 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port)));
496 err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
499 if (err != ERR_OK) {
500 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
501 sock_set_errno(sock, err_to_errno(err));
502 return -1;
505 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
506 sock_set_errno(sock, 0);
507 return 0;
511 * Set a socket into listen mode.
512 * The socket may not have been used for another connection previously.
514 * @param s the socket to set to listening mode
515 * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
516 * @return 0 on success, non-zero on failure
519 lwip_listen(int s, int backlog)
521 struct lwip_sock *sock;
522 err_t err;
524 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
526 sock = get_socket(s);
527 if (!sock) {
528 return -1;
531 /* limit the "backlog" parameter to fit in an u8_t */
532 backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
534 err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
536 if (err != ERR_OK) {
537 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
538 sock_set_errno(sock, err_to_errno(err));
539 return -1;
542 sock_set_errno(sock, 0);
543 return 0;
547 lwip_recvfrom(int s, void *mem, size_t len, int flags,
548 struct sockaddr *from, socklen_t *fromlen)
550 struct lwip_sock *sock;
551 void *buf = NULL;
552 struct pbuf *p;
553 u16_t buflen, copylen;
554 int off = 0;
555 ip_addr_t *addr;
556 u16_t port;
557 u8_t done = 0;
558 err_t err;
560 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
561 sock = get_socket(s);
562 if (!sock) {
563 return -1;
566 do {
567 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
568 /* Check if there is data left from the last recv operation. */
569 if (sock->lastdata) {
570 buf = sock->lastdata;
571 } else {
572 /* If this is non-blocking call, then check first */
573 if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
574 (sock->rcvevent <= 0)) {
575 if (off > 0) {
576 /* update receive window */
577 netconn_recved(sock->conn, (u32_t)off);
578 /* already received data, return that */
579 sock_set_errno(sock, 0);
580 return off;
582 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
583 sock_set_errno(sock, EWOULDBLOCK);
584 return -1;
587 /* No data was left from the previous operation, so we try to get
588 some from the network. */
589 if (netconn_type(sock->conn) == NETCONN_TCP) {
590 err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
591 } else {
592 err = netconn_recv(sock->conn, (struct netbuf **)&buf);
594 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
595 err, buf));
597 if (err != ERR_OK) {
598 if (off > 0) {
599 /* update receive window */
600 netconn_recved(sock->conn, (u32_t)off);
601 /* already received data, return that */
602 sock_set_errno(sock, 0);
603 return off;
605 /* We should really do some error checking here. */
606 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
607 s, lwip_strerr(err)));
608 sock_set_errno(sock, err_to_errno(err));
609 if (err == ERR_CLSD) {
610 return 0;
611 } else {
612 return -1;
615 LWIP_ASSERT("buf != NULL", buf != NULL);
616 sock->lastdata = buf;
619 if (netconn_type(sock->conn) == NETCONN_TCP) {
620 p = (struct pbuf *)buf;
621 } else {
622 p = ((struct netbuf *)buf)->p;
624 buflen = p->tot_len;
625 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
626 buflen, len, off, sock->lastoffset));
628 buflen -= sock->lastoffset;
630 if (len > buflen) {
631 copylen = buflen;
632 } else {
633 copylen = (u16_t)len;
636 /* copy the contents of the received buffer into
637 the supplied memory pointer mem */
638 pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
640 off += copylen;
642 if (netconn_type(sock->conn) == NETCONN_TCP) {
643 LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
644 len -= copylen;
645 if ( (len <= 0) ||
646 (p->flags & PBUF_FLAG_PUSH) ||
647 (sock->rcvevent <= 0) ||
648 ((flags & MSG_PEEK)!=0)) {
649 done = 1;
651 } else {
652 done = 1;
655 /* Check to see from where the data was.*/
656 if (done) {
657 ip_addr_t fromaddr;
658 if (from && fromlen) {
659 struct sockaddr_in sin;
661 if (netconn_type(sock->conn) == NETCONN_TCP) {
662 addr = &fromaddr;
663 netconn_getaddr(sock->conn, addr, &port, 0);
664 } else {
665 addr = netbuf_fromaddr((struct netbuf *)buf);
666 port = netbuf_fromport((struct netbuf *)buf);
669 memset(&sin, 0, sizeof(sin));
670 sin.sin_len = sizeof(sin);
671 sin.sin_family = AF_INET;
672 sin.sin_port = htons(port);
673 inet_addr_from_ipaddr(&sin.sin_addr, addr);
675 if (*fromlen > sizeof(sin)) {
676 *fromlen = sizeof(sin);
679 MEMCPY(from, &sin, *fromlen);
681 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
682 ip_addr_debug_print(SOCKETS_DEBUG, addr);
683 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
684 } else {
685 #if SOCKETS_DEBUG
686 if (netconn_type(sock->conn) == NETCONN_TCP) {
687 addr = &fromaddr;
688 netconn_getaddr(sock->conn, addr, &port, 0);
689 } else {
690 addr = netbuf_fromaddr((struct netbuf *)buf);
691 port = netbuf_fromport((struct netbuf *)buf);
694 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
695 ip_addr_debug_print(SOCKETS_DEBUG, addr);
696 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
697 #endif /* SOCKETS_DEBUG */
701 /* If we don't peek the incoming message... */
702 if ((flags & MSG_PEEK) == 0) {
703 /* If this is a TCP socket, check if there is data left in the
704 buffer. If so, it should be saved in the sock structure for next
705 time around. */
706 if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {
707 sock->lastdata = buf;
708 sock->lastoffset += copylen;
709 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
710 } else {
711 sock->lastdata = NULL;
712 sock->lastoffset = 0;
713 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
714 if (netconn_type(sock->conn) == NETCONN_TCP) {
715 pbuf_free((struct pbuf *)buf);
716 } else {
717 netbuf_delete((struct netbuf *)buf);
721 } while (!done);
723 if (off > 0) {
724 /* update receive window */
725 netconn_recved(sock->conn, (u32_t)off);
727 sock_set_errno(sock, 0);
728 return off;
732 lwip_read(int s, void *mem, size_t len)
734 return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
738 lwip_recv(int s, void *mem, size_t len, int flags)
740 return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
744 lwip_send(int s, const void *data, size_t size, int flags)
746 struct lwip_sock *sock;
747 err_t err;
748 u8_t write_flags;
750 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
751 s, data, size, flags));
753 sock = get_socket(s);
754 if (!sock) {
755 return -1;
758 if (sock->conn->type != NETCONN_TCP) {
759 #if (LWIP_UDP || LWIP_RAW)
760 return lwip_sendto(s, data, size, flags, NULL, 0);
761 #else /* (LWIP_UDP || LWIP_RAW) */
762 sock_set_errno(sock, err_to_errno(ERR_ARG));
763 return -1;
764 #endif /* (LWIP_UDP || LWIP_RAW) */
767 if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) {
768 if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) {
769 /* too much data to ever send nonblocking! */
770 sock_set_errno(sock, EMSGSIZE);
771 return -1;
775 write_flags = NETCONN_COPY |
776 ((flags & MSG_MORE) ? NETCONN_MORE : 0) |
777 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
778 err = netconn_write(sock->conn, data, size, write_flags);
780 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size));
781 sock_set_errno(sock, err_to_errno(err));
782 return (err == ERR_OK ? (int)size : -1);
786 lwip_sendto(int s, const void *data, size_t size, int flags,
787 const struct sockaddr *to, socklen_t tolen)
789 struct lwip_sock *sock;
790 err_t err;
791 u16_t short_size;
792 const struct sockaddr_in *to_in;
793 u16_t remote_port;
794 #if !LWIP_TCPIP_CORE_LOCKING
795 struct netbuf buf;
796 #endif
798 sock = get_socket(s);
799 if (!sock) {
800 return -1;
803 if (sock->conn->type == NETCONN_TCP) {
804 #if LWIP_TCP
805 return lwip_send(s, data, size, flags);
806 #else /* LWIP_TCP */
807 sock_set_errno(sock, err_to_errno(ERR_ARG));
808 return -1;
809 #endif /* LWIP_TCP */
812 /* @todo: split into multiple sendto's? */
813 LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
814 short_size = (u16_t)size;
815 LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
816 ((tolen == sizeof(struct sockaddr_in)) &&
817 ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))),
818 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
819 to_in = (const struct sockaddr_in *)(void*)to;
821 #if LWIP_TCPIP_CORE_LOCKING
822 /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */
824 struct pbuf* p;
825 ip_addr_t *remote_addr;
827 #if LWIP_NETIF_TX_SINGLE_PBUF
828 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM);
829 if (p != NULL) {
830 #if LWIP_CHECKSUM_ON_COPY
831 u16_t chksum = 0;
832 if (sock->conn->type != NETCONN_RAW) {
833 chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size);
834 } else
835 #endif /* LWIP_CHECKSUM_ON_COPY */
836 MEMCPY(p->payload, data, size);
837 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
838 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF);
839 if (p != NULL) {
840 p->payload = (void*)data;
841 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
843 if (to_in != NULL) {
844 inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr);
845 remote_port = ntohs(to_in->sin_port);
846 } else {
847 remote_addr = IP_ADDR_ANY;
848 remote_port = 0;
851 LOCK_TCPIP_CORE();
852 if (sock->conn->type == NETCONN_RAW) {
853 err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr);
854 } else {
855 #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF
856 err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,
857 remote_addr, remote_port, 1, chksum);
858 #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
859 err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p,
860 remote_addr, remote_port);
861 #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
863 UNLOCK_TCPIP_CORE();
865 pbuf_free(p);
866 } else {
867 err = ERR_MEM;
870 #else /* LWIP_TCPIP_CORE_LOCKING */
871 /* initialize a buffer */
872 buf.p = buf.ptr = NULL;
873 #if LWIP_CHECKSUM_ON_COPY
874 buf.flags = 0;
875 #endif /* LWIP_CHECKSUM_ON_COPY */
876 if (to) {
877 inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr);
878 remote_port = ntohs(to_in->sin_port);
879 netbuf_fromport(&buf) = remote_port;
880 } else {
881 remote_port = 0;
882 ip_addr_set_any(&buf.addr);
883 netbuf_fromport(&buf) = 0;
886 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%d"U16_F", flags=0x%x to=",
887 s, data, short_size, flags));
888 ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
889 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
891 /* make the buffer point to the data that should be sent */
892 #if LWIP_NETIF_TX_SINGLE_PBUF
893 /* Allocate a new netbuf and copy the data into it. */
894 if (netbuf_alloc(&buf, short_size) == NULL) {
895 err = ERR_MEM;
896 } else {
897 #if LWIP_CHECKSUM_ON_COPY
898 if (sock->conn->type != NETCONN_RAW) {
899 u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
900 netbuf_set_chksum(&buf, chksum);
901 err = ERR_OK;
902 } else
903 #endif /* LWIP_CHECKSUM_ON_COPY */
905 err = netbuf_take(&buf, data, short_size);
908 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
909 err = netbuf_ref(&buf, data, short_size);
910 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
911 if (err == ERR_OK) {
912 /* send the data */
913 err = netconn_send(sock->conn, &buf);
916 /* deallocated the buffer */
917 netbuf_free(&buf);
918 #endif /* LWIP_TCPIP_CORE_LOCKING */
919 sock_set_errno(sock, err_to_errno(err));
920 return (err == ERR_OK ? short_size : -1);
924 lwip_socket(int domain, int type, int protocol)
926 struct netconn *conn;
927 int i;
929 LWIP_UNUSED_ARG(domain);
931 /* create a netconn */
932 switch (type) {
933 case SOCK_RAW:
934 conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
935 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
936 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
937 break;
938 case SOCK_DGRAM:
939 conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?
940 NETCONN_UDPLITE : NETCONN_UDP, event_callback);
941 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
942 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
943 break;
944 case SOCK_STREAM:
945 conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
946 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
947 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
948 if (conn != NULL) {
949 /* Prevent automatic window updates, we do this on our own! */
950 netconn_set_noautorecved(conn, 1);
952 break;
953 default:
954 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
955 domain, type, protocol));
956 set_errno(EINVAL);
957 return -1;
960 if (!conn) {
961 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
962 set_errno(ENOBUFS);
963 return -1;
966 i = alloc_socket(conn, 0);
968 if (i == -1) {
969 netconn_delete(conn);
970 set_errno(ENFILE);
971 return -1;
973 conn->socket = i;
974 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
975 set_errno(0);
976 return i;
980 lwip_write(int s, const void *data, size_t size)
982 return lwip_send(s, data, size, 0);
986 * Go through the readset and writeset lists and see which socket of the sockets
987 * set in the sets has events. On return, readset, writeset and exceptset have
988 * the sockets enabled that had events.
990 * exceptset is not used for now!!!
992 * @param maxfdp1 the highest socket index in the sets
993 * @param readset_in: set of sockets to check for read events
994 * @param writeset_in: set of sockets to check for write events
995 * @param exceptset_in: set of sockets to check for error events
996 * @param readset_out: set of sockets that had read events
997 * @param writeset_out: set of sockets that had write events
998 * @param exceptset_out: set os sockets that had error events
999 * @return number of sockets that had events (read/write/exception) (>= 0)
1001 static int
1002 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
1003 fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
1005 int i, nready = 0;
1006 fd_set lreadset, lwriteset, lexceptset;
1007 struct lwip_sock *sock;
1008 SYS_ARCH_DECL_PROTECT(lev);
1010 FD_ZERO(&lreadset);
1011 FD_ZERO(&lwriteset);
1012 FD_ZERO(&lexceptset);
1014 /* Go through each socket in each list to count number of sockets which
1015 currently match */
1016 for(i = 0; i < maxfdp1; i++) {
1017 void* lastdata = NULL;
1018 s16_t rcvevent = 0;
1019 u16_t sendevent = 0;
1020 u16_t errevent = 0;
1021 /* First get the socket's status (protected)... */
1022 SYS_ARCH_PROTECT(lev);
1023 sock = tryget_socket(i);
1024 if (sock != NULL) {
1025 lastdata = sock->lastdata;
1026 rcvevent = sock->rcvevent;
1027 sendevent = sock->sendevent;
1028 errevent = sock->errevent;
1030 SYS_ARCH_UNPROTECT(lev);
1031 /* ... then examine it: */
1032 /* See if netconn of this socket is ready for read */
1033 if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
1034 FD_SET(i, &lreadset);
1035 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
1036 nready++;
1038 /* See if netconn of this socket is ready for write */
1039 if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
1040 FD_SET(i, &lwriteset);
1041 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
1042 nready++;
1044 /* See if netconn of this socket had an error */
1045 if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
1046 FD_SET(i, &lexceptset);
1047 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
1048 nready++;
1051 /* copy local sets to the ones provided as arguments */
1052 *readset_out = lreadset;
1053 *writeset_out = lwriteset;
1054 *exceptset_out = lexceptset;
1056 LWIP_ASSERT("nready >= 0", nready >= 0);
1057 return nready;
1061 * Processing exceptset is not yet implemented.
1064 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
1065 struct timeval *timeout)
1067 u32_t waitres = 0;
1068 int nready;
1069 fd_set lreadset, lwriteset, lexceptset;
1070 u32_t msectimeout;
1071 struct lwip_select_cb select_cb;
1072 err_t err;
1073 int i;
1074 SYS_ARCH_DECL_PROTECT(lev);
1076 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
1077 maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
1078 timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
1079 timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
1081 /* Go through each socket in each list to count number of sockets which
1082 currently match */
1083 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1085 /* If we don't have any current events, then suspend if we are supposed to */
1086 if (!nready) {
1087 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
1088 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
1089 /* This is OK as the local fdsets are empty and nready is zero,
1090 or we would have returned earlier. */
1091 goto return_copy_fdsets;
1094 /* None ready: add our semaphore to list:
1095 We don't actually need any dynamic memory. Our entry on the
1096 list is only valid while we are in this function, so it's ok
1097 to use local variables. */
1099 select_cb.next = NULL;
1100 select_cb.prev = NULL;
1101 select_cb.readset = readset;
1102 select_cb.writeset = writeset;
1103 select_cb.exceptset = exceptset;
1104 select_cb.sem_signalled = 0;
1105 err = sys_sem_new(&select_cb.sem, 0);
1106 if (err != ERR_OK) {
1107 /* failed to create semaphore */
1108 set_errno(ENOMEM);
1109 return -1;
1112 /* Protect the select_cb_list */
1113 SYS_ARCH_PROTECT(lev);
1115 /* Put this select_cb on top of list */
1116 select_cb.next = select_cb_list;
1117 if (select_cb_list != NULL) {
1118 select_cb_list->prev = &select_cb;
1120 select_cb_list = &select_cb;
1121 /* Increasing this counter tells even_callback that the list has changed. */
1122 select_cb_ctr++;
1124 /* Now we can safely unprotect */
1125 SYS_ARCH_UNPROTECT(lev);
1127 /* Increase select_waiting for each socket we are interested in */
1128 for(i = 0; i < maxfdp1; i++) {
1129 if ((readset && FD_ISSET(i, readset)) ||
1130 (writeset && FD_ISSET(i, writeset)) ||
1131 (exceptset && FD_ISSET(i, exceptset))) {
1132 struct lwip_sock *sock = tryget_socket(i);
1133 LWIP_ASSERT("sock != NULL", sock != NULL);
1134 SYS_ARCH_PROTECT(lev);
1135 sock->select_waiting++;
1136 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
1137 SYS_ARCH_UNPROTECT(lev);
1141 /* Call lwip_selscan again: there could have been events between
1142 the last scan (whithout us on the list) and putting us on the list! */
1143 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1144 if (!nready) {
1145 /* Still none ready, just wait to be woken */
1146 if (timeout == 0) {
1147 /* Wait forever */
1148 msectimeout = 0;
1149 } else {
1150 msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
1151 if (msectimeout == 0) {
1152 /* Wait 1ms at least (0 means wait forever) */
1153 msectimeout = 1;
1157 waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
1159 /* Increase select_waiting for each socket we are interested in */
1160 for(i = 0; i < maxfdp1; i++) {
1161 if ((readset && FD_ISSET(i, readset)) ||
1162 (writeset && FD_ISSET(i, writeset)) ||
1163 (exceptset && FD_ISSET(i, exceptset))) {
1164 struct lwip_sock *sock = tryget_socket(i);
1165 LWIP_ASSERT("sock != NULL", sock != NULL);
1166 SYS_ARCH_PROTECT(lev);
1167 sock->select_waiting--;
1168 LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0);
1169 SYS_ARCH_UNPROTECT(lev);
1172 /* Take us off the list */
1173 SYS_ARCH_PROTECT(lev);
1174 if (select_cb.next != NULL) {
1175 select_cb.next->prev = select_cb.prev;
1177 if (select_cb_list == &select_cb) {
1178 LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
1179 select_cb_list = select_cb.next;
1180 } else {
1181 LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
1182 select_cb.prev->next = select_cb.next;
1184 SYS_ARCH_UNPROTECT(lev);
1186 sys_sem_free(&select_cb.sem);
1187 if (waitres == SYS_ARCH_TIMEOUT) {
1188 /* Timeout */
1189 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
1190 /* This is OK as the local fdsets are empty and nready is zero,
1191 or we would have returned earlier. */
1192 goto return_copy_fdsets;
1195 /* See what's set */
1196 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1199 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
1200 return_copy_fdsets:
1201 set_errno(0);
1202 if (readset) {
1203 *readset = lreadset;
1205 if (writeset) {
1206 *writeset = lwriteset;
1208 if (exceptset) {
1209 *exceptset = lexceptset;
1213 return nready;
1217 * Callback registered in the netconn layer for each socket-netconn.
1218 * Processes recvevent (data available) and wakes up tasks waiting for select.
1220 static void
1221 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
1223 int s;
1224 struct lwip_sock *sock;
1225 struct lwip_select_cb *scb;
1226 SYS_ARCH_DECL_PROTECT(lev);
1228 LWIP_UNUSED_ARG(len);
1230 /* Get socket */
1231 if (conn) {
1232 s = conn->socket;
1233 if (s < 0) {
1234 /* Data comes in right away after an accept, even though
1235 * the server task might not have created a new socket yet.
1236 * Just count down (or up) if that's the case and we
1237 * will use the data later. Note that only receive events
1238 * can happen before the new socket is set up. */
1239 SYS_ARCH_PROTECT(lev);
1240 if (conn->socket < 0) {
1241 if (evt == NETCONN_EVT_RCVPLUS) {
1242 conn->socket--;
1244 SYS_ARCH_UNPROTECT(lev);
1245 return;
1247 s = conn->socket;
1248 SYS_ARCH_UNPROTECT(lev);
1251 sock = get_socket(s);
1252 if (!sock) {
1253 return;
1255 } else {
1256 return;
1259 SYS_ARCH_PROTECT(lev);
1260 /* Set event as required */
1261 switch (evt) {
1262 case NETCONN_EVT_RCVPLUS:
1263 sock->rcvevent++;
1264 break;
1265 case NETCONN_EVT_RCVMINUS:
1266 sock->rcvevent--;
1267 break;
1268 case NETCONN_EVT_SENDPLUS:
1269 sock->sendevent = 1;
1270 break;
1271 case NETCONN_EVT_SENDMINUS:
1272 sock->sendevent = 0;
1273 break;
1274 case NETCONN_EVT_ERROR:
1275 sock->errevent = 1;
1276 break;
1277 default:
1278 LWIP_ASSERT("unknown event", 0);
1279 break;
1282 if (sock->select_waiting == 0) {
1283 /* noone is waiting for this socket, no need to check select_cb_list */
1284 SYS_ARCH_UNPROTECT(lev);
1285 return;
1288 SYS_ARCH_UNPROTECT(lev);
1290 /* Now decide if anyone is waiting for this socket */
1291 /* NOTE: This code is written this way to protect the select link list
1292 but to avoid a deadlock situation by releasing select_lock before
1293 signalling for the select. This means we need to go through the list
1294 multiple times ONLY IF a select was actually waiting. We go through
1295 the list the number of waiting select calls + 1. This list is
1296 expected to be small. */
1297 while (1) {
1298 int last_select_cb_ctr;
1299 SYS_ARCH_PROTECT(lev);
1300 for (scb = select_cb_list; scb; scb = scb->next) {
1301 /* @todo: unprotect with each loop and check for changes? */
1302 if (scb->sem_signalled == 0) {
1303 /* Test this select call for our socket */
1304 if (scb->readset && FD_ISSET(s, scb->readset)) {
1305 if (sock->rcvevent > 0) {
1306 break;
1309 if (scb->writeset && FD_ISSET(s, scb->writeset)) {
1310 if (sock->sendevent != 0) {
1311 break;
1314 if (scb->exceptset && FD_ISSET(s, scb->exceptset)) {
1315 if (sock->errevent != 0) {
1316 break;
1320 /* unlock interrupts with each step */
1321 last_select_cb_ctr = select_cb_ctr;
1322 SYS_ARCH_UNPROTECT(lev);
1323 SYS_ARCH_PROTECT(lev);
1324 if (last_select_cb_ctr != select_cb_ctr) {
1325 /* someone has changed select_cb_list, restart at the beginning */
1326 scb = select_cb_list;
1329 if (scb) {
1330 scb->sem_signalled = 1;
1331 sys_sem_signal(&scb->sem);
1332 SYS_ARCH_UNPROTECT(lev);
1333 } else {
1334 SYS_ARCH_UNPROTECT(lev);
1335 break;
1341 * Unimplemented: Close one end of a full-duplex connection.
1342 * Currently, the full connection is closed.
1345 lwip_shutdown(int s, int how)
1347 struct lwip_sock *sock;
1348 err_t err;
1349 u8_t shut_rx = 0, shut_tx = 0;
1351 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
1353 sock = get_socket(s);
1354 if (!sock) {
1355 return -1;
1358 if (sock->conn != NULL) {
1359 if (netconn_type(sock->conn) != NETCONN_TCP) {
1360 sock_set_errno(sock, EOPNOTSUPP);
1361 return EOPNOTSUPP;
1363 } else {
1364 sock_set_errno(sock, ENOTCONN);
1365 return ENOTCONN;
1368 if (how == SHUT_RD) {
1369 shut_rx = 1;
1370 } else if (how == SHUT_WR) {
1371 shut_tx = 1;
1372 } else if(how == SHUT_RDWR) {
1373 shut_rx = 1;
1374 shut_tx = 1;
1375 } else {
1376 sock_set_errno(sock, EINVAL);
1377 return EINVAL;
1379 err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
1381 sock_set_errno(sock, err_to_errno(err));
1382 return (err == ERR_OK ? 0 : -1);
1385 static int
1386 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
1388 struct lwip_sock *sock;
1389 struct sockaddr_in sin;
1390 ip_addr_t naddr;
1392 sock = get_socket(s);
1393 if (!sock) {
1394 return -1;
1397 memset(&sin, 0, sizeof(sin));
1398 sin.sin_len = sizeof(sin);
1399 sin.sin_family = AF_INET;
1401 /* get the IP address and port */
1402 netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
1404 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
1405 ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
1406 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port));
1408 sin.sin_port = htons(sin.sin_port);
1409 inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
1411 if (*namelen > sizeof(sin)) {
1412 *namelen = sizeof(sin);
1415 MEMCPY(name, &sin, *namelen);
1416 sock_set_errno(sock, 0);
1417 return 0;
1421 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
1423 return lwip_getaddrname(s, name, namelen, 0);
1427 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
1429 return lwip_getaddrname(s, name, namelen, 1);
1433 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
1435 err_t err = ERR_OK;
1436 struct lwip_sock *sock = get_socket(s);
1437 struct lwip_setgetsockopt_data data;
1439 if (!sock) {
1440 return -1;
1443 if ((NULL == optval) || (NULL == optlen)) {
1444 sock_set_errno(sock, EFAULT);
1445 return -1;
1448 /* Do length and type checks for the various options first, to keep it readable. */
1449 switch (level) {
1451 /* Level: SOL_SOCKET */
1452 case SOL_SOCKET:
1453 switch (optname) {
1455 case SO_ACCEPTCONN:
1456 case SO_BROADCAST:
1457 /* UNIMPL case SO_DEBUG: */
1458 /* UNIMPL case SO_DONTROUTE: */
1459 case SO_ERROR:
1460 case SO_KEEPALIVE:
1461 /* UNIMPL case SO_CONTIMEO: */
1462 /* UNIMPL case SO_SNDTIMEO: */
1463 #if LWIP_SO_RCVTIMEO
1464 case SO_RCVTIMEO:
1465 #endif /* LWIP_SO_RCVTIMEO */
1466 #if LWIP_SO_RCVBUF
1467 case SO_RCVBUF:
1468 #endif /* LWIP_SO_RCVBUF */
1469 /* UNIMPL case SO_OOBINLINE: */
1470 /* UNIMPL case SO_SNDBUF: */
1471 /* UNIMPL case SO_RCVLOWAT: */
1472 /* UNIMPL case SO_SNDLOWAT: */
1473 #if SO_REUSE
1474 case SO_REUSEADDR:
1475 case SO_REUSEPORT:
1476 #endif /* SO_REUSE */
1477 case SO_TYPE:
1478 /* UNIMPL case SO_USELOOPBACK: */
1479 if (*optlen < sizeof(int)) {
1480 err = EINVAL;
1482 break;
1484 case SO_NO_CHECK:
1485 if (*optlen < sizeof(int)) {
1486 err = EINVAL;
1488 #if LWIP_UDP
1489 if ((sock->conn->type != NETCONN_UDP) ||
1490 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1491 /* this flag is only available for UDP, not for UDP lite */
1492 err = EAFNOSUPPORT;
1494 #endif /* LWIP_UDP */
1495 break;
1497 default:
1498 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1499 s, optname));
1500 err = ENOPROTOOPT;
1501 } /* switch (optname) */
1502 break;
1504 /* Level: IPPROTO_IP */
1505 case IPPROTO_IP:
1506 switch (optname) {
1507 /* UNIMPL case IP_HDRINCL: */
1508 /* UNIMPL case IP_RCVDSTADDR: */
1509 /* UNIMPL case IP_RCVIF: */
1510 case IP_TTL:
1511 case IP_TOS:
1512 if (*optlen < sizeof(int)) {
1513 err = EINVAL;
1515 break;
1516 #if LWIP_IGMP
1517 case IP_MULTICAST_TTL:
1518 if (*optlen < sizeof(u8_t)) {
1519 err = EINVAL;
1521 break;
1522 case IP_MULTICAST_IF:
1523 if (*optlen < sizeof(struct in_addr)) {
1524 err = EINVAL;
1526 break;
1527 case IP_MULTICAST_LOOP:
1528 if (*optlen < sizeof(u8_t)) {
1529 err = EINVAL;
1531 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1532 err = EAFNOSUPPORT;
1534 break;
1535 #endif /* LWIP_IGMP */
1537 default:
1538 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1539 s, optname));
1540 err = ENOPROTOOPT;
1541 } /* switch (optname) */
1542 break;
1544 #if LWIP_TCP
1545 /* Level: IPPROTO_TCP */
1546 case IPPROTO_TCP:
1547 if (*optlen < sizeof(int)) {
1548 err = EINVAL;
1549 break;
1552 /* If this is no TCP socket, ignore any options. */
1553 if (sock->conn->type != NETCONN_TCP)
1554 return 0;
1556 switch (optname) {
1557 case TCP_NODELAY:
1558 case TCP_KEEPALIVE:
1559 #if LWIP_TCP_KEEPALIVE
1560 case TCP_KEEPIDLE:
1561 case TCP_KEEPINTVL:
1562 case TCP_KEEPCNT:
1563 #endif /* LWIP_TCP_KEEPALIVE */
1564 break;
1566 default:
1567 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
1568 s, optname));
1569 err = ENOPROTOOPT;
1570 } /* switch (optname) */
1571 break;
1572 #endif /* LWIP_TCP */
1573 #if LWIP_UDP && LWIP_UDPLITE
1574 /* Level: IPPROTO_UDPLITE */
1575 case IPPROTO_UDPLITE:
1576 if (*optlen < sizeof(int)) {
1577 err = EINVAL;
1578 break;
1581 /* If this is no UDP lite socket, ignore any options. */
1582 if (sock->conn->type != NETCONN_UDPLITE) {
1583 return 0;
1586 switch (optname) {
1587 case UDPLITE_SEND_CSCOV:
1588 case UDPLITE_RECV_CSCOV:
1589 break;
1591 default:
1592 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
1593 s, optname));
1594 err = ENOPROTOOPT;
1595 } /* switch (optname) */
1596 break;
1597 #endif /* LWIP_UDP && LWIP_UDPLITE*/
1598 /* UNDEFINED LEVEL */
1599 default:
1600 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
1601 s, level, optname));
1602 err = ENOPROTOOPT;
1603 } /* switch */
1606 if (err != ERR_OK) {
1607 sock_set_errno(sock, err);
1608 return -1;
1611 /* Now do the actual option processing */
1612 data.sock = sock;
1613 data.level = level;
1614 data.optname = optname;
1615 data.optval = optval;
1616 data.optlen = optlen;
1617 data.err = err;
1618 tcpip_callback(lwip_getsockopt_internal, &data);
1619 sys_arch_sem_wait(&sock->conn->op_completed, 0);
1620 /* maybe lwip_getsockopt_internal has changed err */
1621 err = data.err;
1623 sock_set_errno(sock, err);
1624 return err ? -1 : 0;
1627 static void
1628 lwip_getsockopt_internal(void *arg)
1630 struct lwip_sock *sock;
1631 #ifdef LWIP_DEBUG
1632 int s;
1633 #endif /* LWIP_DEBUG */
1634 int level, optname;
1635 void *optval;
1636 struct lwip_setgetsockopt_data *data;
1638 LWIP_ASSERT("arg != NULL", arg != NULL);
1640 data = (struct lwip_setgetsockopt_data*)arg;
1641 sock = data->sock;
1642 #ifdef LWIP_DEBUG
1643 s = data->s;
1644 #endif /* LWIP_DEBUG */
1645 level = data->level;
1646 optname = data->optname;
1647 optval = data->optval;
1649 switch (level) {
1651 /* Level: SOL_SOCKET */
1652 case SOL_SOCKET:
1653 switch (optname) {
1655 /* The option flags */
1656 case SO_ACCEPTCONN:
1657 case SO_BROADCAST:
1658 /* UNIMPL case SO_DEBUG: */
1659 /* UNIMPL case SO_DONTROUTE: */
1660 case SO_KEEPALIVE:
1661 /* UNIMPL case SO_OOBINCLUDE: */
1662 #if SO_REUSE
1663 case SO_REUSEADDR:
1664 case SO_REUSEPORT:
1665 #endif /* SO_REUSE */
1666 /*case SO_USELOOPBACK: UNIMPL */
1667 *(int*)optval = sock->conn->pcb.ip->so_options & optname;
1668 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
1669 s, optname, (*(int*)optval?"on":"off")));
1670 break;
1672 case SO_TYPE:
1673 switch (NETCONNTYPE_GROUP(sock->conn->type)) {
1674 case NETCONN_RAW:
1675 *(int*)optval = SOCK_RAW;
1676 break;
1677 case NETCONN_TCP:
1678 *(int*)optval = SOCK_STREAM;
1679 break;
1680 case NETCONN_UDP:
1681 *(int*)optval = SOCK_DGRAM;
1682 break;
1683 default: /* unrecognized socket type */
1684 *(int*)optval = sock->conn->type;
1685 LWIP_DEBUGF(SOCKETS_DEBUG,
1686 ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
1687 s, *(int *)optval));
1688 } /* switch (sock->conn->type) */
1689 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
1690 s, *(int *)optval));
1691 break;
1693 case SO_ERROR:
1694 /* only overwrite if ERR_OK before */
1695 if (sock->err == 0) {
1696 sock_set_errno(sock, err_to_errno(sock->conn->last_err));
1698 *(int *)optval = sock->err;
1699 sock->err = 0;
1700 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
1701 s, *(int *)optval));
1702 break;
1704 #if LWIP_SO_RCVTIMEO
1705 case SO_RCVTIMEO:
1706 *(int *)optval = netconn_get_recvtimeout(sock->conn);
1707 break;
1708 #endif /* LWIP_SO_RCVTIMEO */
1709 #if LWIP_SO_RCVBUF
1710 case SO_RCVBUF:
1711 *(int *)optval = netconn_get_recvbufsize(sock->conn);
1712 break;
1713 #endif /* LWIP_SO_RCVBUF */
1714 #if LWIP_UDP
1715 case SO_NO_CHECK:
1716 *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
1717 break;
1718 #endif /* LWIP_UDP*/
1719 default:
1720 LWIP_ASSERT("unhandled optname", 0);
1721 break;
1722 } /* switch (optname) */
1723 break;
1725 /* Level: IPPROTO_IP */
1726 case IPPROTO_IP:
1727 switch (optname) {
1728 case IP_TTL:
1729 *(int*)optval = sock->conn->pcb.ip->ttl;
1730 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
1731 s, *(int *)optval));
1732 break;
1733 case IP_TOS:
1734 *(int*)optval = sock->conn->pcb.ip->tos;
1735 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
1736 s, *(int *)optval));
1737 break;
1738 #if LWIP_IGMP
1739 case IP_MULTICAST_TTL:
1740 *(u8_t*)optval = sock->conn->pcb.ip->ttl;
1741 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
1742 s, *(int *)optval));
1743 break;
1744 case IP_MULTICAST_IF:
1745 inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip);
1746 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
1747 s, *(u32_t *)optval));
1748 break;
1749 case IP_MULTICAST_LOOP:
1750 if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
1751 *(u8_t*)optval = 1;
1752 } else {
1753 *(u8_t*)optval = 0;
1755 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
1756 s, *(int *)optval));
1757 break;
1758 #endif /* LWIP_IGMP */
1759 default:
1760 LWIP_ASSERT("unhandled optname", 0);
1761 break;
1762 } /* switch (optname) */
1763 break;
1765 #if LWIP_TCP
1766 /* Level: IPPROTO_TCP */
1767 case IPPROTO_TCP:
1768 switch (optname) {
1769 case TCP_NODELAY:
1770 *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
1771 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
1772 s, (*(int*)optval)?"on":"off") );
1773 break;
1774 case TCP_KEEPALIVE:
1775 *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
1776 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",
1777 s, *(int *)optval));
1778 break;
1780 #if LWIP_TCP_KEEPALIVE
1781 case TCP_KEEPIDLE:
1782 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
1783 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",
1784 s, *(int *)optval));
1785 break;
1786 case TCP_KEEPINTVL:
1787 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
1788 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",
1789 s, *(int *)optval));
1790 break;
1791 case TCP_KEEPCNT:
1792 *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
1793 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",
1794 s, *(int *)optval));
1795 break;
1796 #endif /* LWIP_TCP_KEEPALIVE */
1797 default:
1798 LWIP_ASSERT("unhandled optname", 0);
1799 break;
1800 } /* switch (optname) */
1801 break;
1802 #endif /* LWIP_TCP */
1803 #if LWIP_UDP && LWIP_UDPLITE
1804 /* Level: IPPROTO_UDPLITE */
1805 case IPPROTO_UDPLITE:
1806 switch (optname) {
1807 case UDPLITE_SEND_CSCOV:
1808 *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
1809 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
1810 s, (*(int*)optval)) );
1811 break;
1812 case UDPLITE_RECV_CSCOV:
1813 *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
1814 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
1815 s, (*(int*)optval)) );
1816 break;
1817 default:
1818 LWIP_ASSERT("unhandled optname", 0);
1819 break;
1820 } /* switch (optname) */
1821 break;
1822 #endif /* LWIP_UDP */
1823 default:
1824 LWIP_ASSERT("unhandled level", 0);
1825 break;
1826 } /* switch (level) */
1827 sys_sem_signal(&sock->conn->op_completed);
1831 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
1833 struct lwip_sock *sock = get_socket(s);
1834 err_t err = ERR_OK;
1835 struct lwip_setgetsockopt_data data;
1837 if (!sock) {
1838 return -1;
1841 if (NULL == optval) {
1842 sock_set_errno(sock, EFAULT);
1843 return -1;
1846 /* Do length and type checks for the various options first, to keep it readable. */
1847 switch (level) {
1849 /* Level: SOL_SOCKET */
1850 case SOL_SOCKET:
1851 switch (optname) {
1853 case SO_BROADCAST:
1854 /* UNIMPL case SO_DEBUG: */
1855 /* UNIMPL case SO_DONTROUTE: */
1856 case SO_KEEPALIVE:
1857 /* UNIMPL case case SO_CONTIMEO: */
1858 /* UNIMPL case case SO_SNDTIMEO: */
1859 #if LWIP_SO_RCVTIMEO
1860 case SO_RCVTIMEO:
1861 #endif /* LWIP_SO_RCVTIMEO */
1862 #if LWIP_SO_RCVBUF
1863 case SO_RCVBUF:
1864 #endif /* LWIP_SO_RCVBUF */
1865 /* UNIMPL case SO_OOBINLINE: */
1866 /* UNIMPL case SO_SNDBUF: */
1867 /* UNIMPL case SO_RCVLOWAT: */
1868 /* UNIMPL case SO_SNDLOWAT: */
1869 #if SO_REUSE
1870 case SO_REUSEADDR:
1871 case SO_REUSEPORT:
1872 #endif /* SO_REUSE */
1873 /* UNIMPL case SO_USELOOPBACK: */
1874 if (optlen < sizeof(int)) {
1875 err = EINVAL;
1877 break;
1878 case SO_NO_CHECK:
1879 if (optlen < sizeof(int)) {
1880 err = EINVAL;
1882 #if LWIP_UDP
1883 if ((sock->conn->type != NETCONN_UDP) ||
1884 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1885 /* this flag is only available for UDP, not for UDP lite */
1886 err = EAFNOSUPPORT;
1888 #endif /* LWIP_UDP */
1889 break;
1890 default:
1891 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1892 s, optname));
1893 err = ENOPROTOOPT;
1894 } /* switch (optname) */
1895 break;
1897 /* Level: IPPROTO_IP */
1898 case IPPROTO_IP:
1899 switch (optname) {
1900 /* UNIMPL case IP_HDRINCL: */
1901 /* UNIMPL case IP_RCVDSTADDR: */
1902 /* UNIMPL case IP_RCVIF: */
1903 case IP_TTL:
1904 case IP_TOS:
1905 if (optlen < sizeof(int)) {
1906 err = EINVAL;
1908 break;
1909 #if LWIP_IGMP
1910 case IP_MULTICAST_TTL:
1911 if (optlen < sizeof(u8_t)) {
1912 err = EINVAL;
1914 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1915 err = EAFNOSUPPORT;
1917 break;
1918 case IP_MULTICAST_IF:
1919 if (optlen < sizeof(struct in_addr)) {
1920 err = EINVAL;
1922 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1923 err = EAFNOSUPPORT;
1925 break;
1926 case IP_MULTICAST_LOOP:
1927 if (optlen < sizeof(u8_t)) {
1928 err = EINVAL;
1930 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1931 err = EAFNOSUPPORT;
1933 break;
1934 case IP_ADD_MEMBERSHIP:
1935 case IP_DROP_MEMBERSHIP:
1936 if (optlen < sizeof(struct ip_mreq)) {
1937 err = EINVAL;
1939 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1940 err = EAFNOSUPPORT;
1942 break;
1943 #endif /* LWIP_IGMP */
1944 default:
1945 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1946 s, optname));
1947 err = ENOPROTOOPT;
1948 } /* switch (optname) */
1949 break;
1951 #if LWIP_TCP
1952 /* Level: IPPROTO_TCP */
1953 case IPPROTO_TCP:
1954 if (optlen < sizeof(int)) {
1955 err = EINVAL;
1956 break;
1959 /* If this is no TCP socket, ignore any options. */
1960 if (sock->conn->type != NETCONN_TCP)
1961 return 0;
1963 switch (optname) {
1964 case TCP_NODELAY:
1965 case TCP_KEEPALIVE:
1966 #if LWIP_TCP_KEEPALIVE
1967 case TCP_KEEPIDLE:
1968 case TCP_KEEPINTVL:
1969 case TCP_KEEPCNT:
1970 #endif /* LWIP_TCP_KEEPALIVE */
1971 break;
1973 default:
1974 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
1975 s, optname));
1976 err = ENOPROTOOPT;
1977 } /* switch (optname) */
1978 break;
1979 #endif /* LWIP_TCP */
1980 #if LWIP_UDP && LWIP_UDPLITE
1981 /* Level: IPPROTO_UDPLITE */
1982 case IPPROTO_UDPLITE:
1983 if (optlen < sizeof(int)) {
1984 err = EINVAL;
1985 break;
1988 /* If this is no UDP lite socket, ignore any options. */
1989 if (sock->conn->type != NETCONN_UDPLITE)
1990 return 0;
1992 switch (optname) {
1993 case UDPLITE_SEND_CSCOV:
1994 case UDPLITE_RECV_CSCOV:
1995 break;
1997 default:
1998 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
1999 s, optname));
2000 err = ENOPROTOOPT;
2001 } /* switch (optname) */
2002 break;
2003 #endif /* LWIP_UDP && LWIP_UDPLITE */
2004 /* UNDEFINED LEVEL */
2005 default:
2006 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2007 s, level, optname));
2008 err = ENOPROTOOPT;
2009 } /* switch (level) */
2012 if (err != ERR_OK) {
2013 sock_set_errno(sock, err);
2014 return -1;
2018 /* Now do the actual option processing */
2019 data.sock = sock;
2020 data.level = level;
2021 data.optname = optname;
2022 data.optval = (void*)optval;
2023 data.optlen = &optlen;
2024 data.err = err;
2025 tcpip_callback(lwip_setsockopt_internal, &data);
2026 sys_arch_sem_wait(&sock->conn->op_completed, 0);
2027 /* maybe lwip_setsockopt_internal has changed err */
2028 err = data.err;
2030 sock_set_errno(sock, err);
2031 return err ? -1 : 0;
2034 static void
2035 lwip_setsockopt_internal(void *arg)
2037 struct lwip_sock *sock;
2038 #ifdef LWIP_DEBUG
2039 int s;
2040 #endif /* LWIP_DEBUG */
2041 int level, optname;
2042 const void *optval;
2043 struct lwip_setgetsockopt_data *data;
2045 LWIP_ASSERT("arg != NULL", arg != NULL);
2047 data = (struct lwip_setgetsockopt_data*)arg;
2048 sock = data->sock;
2049 #ifdef LWIP_DEBUG
2050 s = data->s;
2051 #endif /* LWIP_DEBUG */
2052 level = data->level;
2053 optname = data->optname;
2054 optval = data->optval;
2056 switch (level) {
2058 /* Level: SOL_SOCKET */
2059 case SOL_SOCKET:
2060 switch (optname) {
2062 /* The option flags */
2063 case SO_BROADCAST:
2064 /* UNIMPL case SO_DEBUG: */
2065 /* UNIMPL case SO_DONTROUTE: */
2066 case SO_KEEPALIVE:
2067 /* UNIMPL case SO_OOBINCLUDE: */
2068 #if SO_REUSE
2069 case SO_REUSEADDR:
2070 case SO_REUSEPORT:
2071 #endif /* SO_REUSE */
2072 /* UNIMPL case SO_USELOOPBACK: */
2073 if (*(int*)optval) {
2074 sock->conn->pcb.ip->so_options |= optname;
2075 } else {
2076 sock->conn->pcb.ip->so_options &= ~optname;
2078 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
2079 s, optname, (*(int*)optval?"on":"off")));
2080 break;
2081 #if LWIP_SO_RCVTIMEO
2082 case SO_RCVTIMEO:
2083 netconn_set_recvtimeout(sock->conn, *(int*)optval);
2084 break;
2085 #endif /* LWIP_SO_RCVTIMEO */
2086 #if LWIP_SO_RCVBUF
2087 case SO_RCVBUF:
2088 netconn_set_recvbufsize(sock->conn, *(int*)optval);
2089 break;
2090 #endif /* LWIP_SO_RCVBUF */
2091 #if LWIP_UDP
2092 case SO_NO_CHECK:
2093 if (*(int*)optval) {
2094 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
2095 } else {
2096 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
2098 break;
2099 #endif /* LWIP_UDP */
2100 default:
2101 LWIP_ASSERT("unhandled optname", 0);
2102 break;
2103 } /* switch (optname) */
2104 break;
2106 /* Level: IPPROTO_IP */
2107 case IPPROTO_IP:
2108 switch (optname) {
2109 case IP_TTL:
2110 sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
2111 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
2112 s, sock->conn->pcb.ip->ttl));
2113 break;
2114 case IP_TOS:
2115 sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
2116 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
2117 s, sock->conn->pcb.ip->tos));
2118 break;
2119 #if LWIP_IGMP
2120 case IP_MULTICAST_TTL:
2121 sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);
2122 break;
2123 case IP_MULTICAST_IF:
2124 inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval);
2125 break;
2126 case IP_MULTICAST_LOOP:
2127 if (*(u8_t*)optval) {
2128 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
2129 } else {
2130 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
2132 break;
2133 case IP_ADD_MEMBERSHIP:
2134 case IP_DROP_MEMBERSHIP:
2136 /* If this is a TCP or a RAW socket, ignore these options. */
2137 struct ip_mreq *imr = (struct ip_mreq *)optval;
2138 ip_addr_t if_addr;
2139 ip_addr_t multi_addr;
2140 inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
2141 inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
2142 if(optname == IP_ADD_MEMBERSHIP){
2143 data->err = igmp_joingroup(&if_addr, &multi_addr);
2144 } else {
2145 data->err = igmp_leavegroup(&if_addr, &multi_addr);
2147 if(data->err != ERR_OK) {
2148 data->err = EADDRNOTAVAIL;
2151 break;
2152 #endif /* LWIP_IGMP */
2153 default:
2154 LWIP_ASSERT("unhandled optname", 0);
2155 break;
2156 } /* switch (optname) */
2157 break;
2159 #if LWIP_TCP
2160 /* Level: IPPROTO_TCP */
2161 case IPPROTO_TCP:
2162 switch (optname) {
2163 case TCP_NODELAY:
2164 if (*(int*)optval) {
2165 tcp_nagle_disable(sock->conn->pcb.tcp);
2166 } else {
2167 tcp_nagle_enable(sock->conn->pcb.tcp);
2169 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
2170 s, (*(int *)optval)?"on":"off") );
2171 break;
2172 case TCP_KEEPALIVE:
2173 sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
2174 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
2175 s, sock->conn->pcb.tcp->keep_idle));
2176 break;
2178 #if LWIP_TCP_KEEPALIVE
2179 case TCP_KEEPIDLE:
2180 sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
2181 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
2182 s, sock->conn->pcb.tcp->keep_idle));
2183 break;
2184 case TCP_KEEPINTVL:
2185 sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
2186 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
2187 s, sock->conn->pcb.tcp->keep_intvl));
2188 break;
2189 case TCP_KEEPCNT:
2190 sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
2191 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
2192 s, sock->conn->pcb.tcp->keep_cnt));
2193 break;
2194 #endif /* LWIP_TCP_KEEPALIVE */
2195 default:
2196 LWIP_ASSERT("unhandled optname", 0);
2197 break;
2198 } /* switch (optname) */
2199 break;
2200 #endif /* LWIP_TCP*/
2201 #if LWIP_UDP && LWIP_UDPLITE
2202 /* Level: IPPROTO_UDPLITE */
2203 case IPPROTO_UDPLITE:
2204 switch (optname) {
2205 case UDPLITE_SEND_CSCOV:
2206 if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
2207 /* don't allow illegal values! */
2208 sock->conn->pcb.udp->chksum_len_tx = 8;
2209 } else {
2210 sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;
2212 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
2213 s, (*(int*)optval)) );
2214 break;
2215 case UDPLITE_RECV_CSCOV:
2216 if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
2217 /* don't allow illegal values! */
2218 sock->conn->pcb.udp->chksum_len_rx = 8;
2219 } else {
2220 sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;
2222 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
2223 s, (*(int*)optval)) );
2224 break;
2225 default:
2226 LWIP_ASSERT("unhandled optname", 0);
2227 break;
2228 } /* switch (optname) */
2229 break;
2230 #endif /* LWIP_UDP */
2231 default:
2232 LWIP_ASSERT("unhandled level", 0);
2233 break;
2234 } /* switch (level) */
2235 sys_sem_signal(&sock->conn->op_completed);
2239 lwip_ioctl(int s, long cmd, void *argp)
2241 struct lwip_sock *sock = get_socket(s);
2242 u16_t buflen = 0;
2243 s16_t recv_avail;
2244 u8_t val;
2246 if (!sock) {
2247 return -1;
2250 switch (cmd) {
2251 case FIONREAD:
2252 if (!argp) {
2253 sock_set_errno(sock, EINVAL);
2254 return -1;
2257 SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
2258 if (recv_avail < 0) {
2259 recv_avail = 0;
2261 *((u16_t*)argp) = (u16_t)recv_avail;
2263 /* Check if there is data left from the last recv operation. /maq 041215 */
2264 if (sock->lastdata) {
2265 struct pbuf *p = (struct pbuf *)sock->lastdata;
2266 if (netconn_type(sock->conn) != NETCONN_TCP) {
2267 p = ((struct netbuf *)p)->p;
2269 buflen = p->tot_len;
2270 buflen -= sock->lastoffset;
2272 *((u16_t*)argp) += buflen;
2275 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
2276 sock_set_errno(sock, 0);
2277 return 0;
2279 case FIONBIO:
2280 val = 0;
2281 if (argp && *(u32_t*)argp) {
2282 val = 1;
2284 netconn_set_nonblocking(sock->conn, val);
2285 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
2286 sock_set_errno(sock, 0);
2287 return 0;
2289 default:
2290 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
2291 sock_set_errno(sock, ENOSYS); /* not yet implemented */
2292 return -1;
2293 } /* switch (cmd) */
2296 /** A minimal implementation of fcntl.
2297 * Currently only the commands F_GETFL and F_SETFL are implemented.
2298 * Only the flag O_NONBLOCK is implemented.
2301 lwip_fcntl(int s, int cmd, int val)
2303 struct lwip_sock *sock = get_socket(s);
2304 int ret = -1;
2306 if (!sock || !sock->conn) {
2307 return -1;
2310 switch (cmd) {
2311 case F_GETFL:
2312 ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
2313 break;
2314 case F_SETFL:
2315 if ((val & ~O_NONBLOCK) == 0) {
2316 /* only O_NONBLOCK, all other bits are zero */
2317 netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
2318 ret = 0;
2320 break;
2321 default:
2322 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
2323 break;
2325 return ret;
2328 #endif /* LWIP_SOCKET */