1 /**
2 * @file
3 * Sockets BSD-Like API module
4 *
5 */
6
7 /*
8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
13 *
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.
21 *
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.
32 *
33 * This file is part of the lwIP TCP/IP stack.
34 *
35 * Author: Adam Dunkels <adam@sics.se>
36 *
37 * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
38 *
39 */
40
41 #include "lwip/opt.h"
42
43 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
44
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
58
59 #include <string.h>
60
61 #define NUM_SOCKETS MEMP_NUM_NETCONN
62
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;
83 };
84
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;
101 };
102
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 #ifdef LWIP_DEBUG
109 /** socket index for which to change options */
110 int s;
111 #endif /* LWIP_DEBUG */
112 /** level of the option to process */
113 int level;
114 /** name of the option to process */
115 int optname;
116 /** set: value to set the option to
117 * get: value of the option is stored here */
118 void *optval;
119 /** size of *optval */
120 socklen_t *optlen;
121 /** if an error occures, it is temporarily stored here */
122 err_t err;
123 };
124
125 /** The global array of available sockets */
126 static struct lwip_sock sockets[NUM_SOCKETS];
127 /** The global list of tasks waiting for select */
128 static struct lwip_select_cb *select_cb_list;
129 /** This counter is increased from lwip_select when the list is chagned
130 and checked in event_callback to see if it has changed. */
131 static volatile int select_cb_ctr;
132
133 /** Table to quickly map an lwIP error (err_t) to a socket error
134 * by using -err as an index */
135 static const int err_to_errno_table[] = {
136 0, /* ERR_OK 0 No error, everything OK. */
137 ENOMEM, /* ERR_MEM -1 Out of memory error. */
138 ENOBUFS, /* ERR_BUF -2 Buffer error. */
139 EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
140 EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
141 EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
142 EINVAL, /* ERR_VAL -6 Illegal value. */
143 EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
144 EADDRINUSE, /* ERR_USE -8 Address in use. */
145 EALREADY, /* ERR_ISCONN -9 Already connected. */
146 ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */
147 ECONNRESET, /* ERR_RST -11 Connection reset. */
148 ENOTCONN, /* ERR_CLSD -12 Connection closed. */
149 ENOTCONN, /* ERR_CONN -13 Not connected. */
150 EIO, /* ERR_ARG -14 Illegal argument. */
151 -1, /* ERR_IF -15 Low-level netif error */
152 };
153
154 #define ERR_TO_ERRNO_TABLE_SIZE \
155 (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
156
157 #define err_to_errno(err) \
158 ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
159 err_to_errno_table[-(err)] : EIO)
160
161 #ifdef ERRNO
162 #ifndef set_errno
163 #define set_errno(err) errno = (err)
164 #endif
165 #else /* ERRNO */
166 #define set_errno(err)
167 #endif /* ERRNO */
168
169 #define sock_set_errno(sk, e) do { \
170 sk->err = (e); \
171 set_errno(sk->err); \
172 } while (0)
173
174 /* Forward delcaration of some functions */
175 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
176 static void lwip_getsockopt_internal(void *arg);
177 static void lwip_setsockopt_internal(void *arg);
178
179 /**
180 * Initialize this module. This function has to be called before any other
181 * functions in this module!
182 */
183 void
lwip_socket_init(void)184 lwip_socket_init(void)
185 {
186 }
187
188 /**
189 * Map a externally used socket index to the internal socket representation.
190 *
191 * @param s externally used socket index
192 * @return struct lwip_sock for the socket or NULL if not found
193 */
194 static struct lwip_sock *
get_socket(int s)195 get_socket(int s)
196 {
197 struct lwip_sock *sock;
198
199 if ((s < 0) || (s >= NUM_SOCKETS)) {
200 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
201 set_errno(EBADF);
202 return NULL;
203 }
204
205 sock = &sockets[s];
206
207 if (!sock->conn) {
208 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
209 set_errno(EBADF);
210 return NULL;
211 }
212
213 return sock;
214 }
215
216 /**
217 * Same as get_socket but doesn't set errno
218 *
219 * @param s externally used socket index
220 * @return struct lwip_sock for the socket or NULL if not found
221 */
222 static struct lwip_sock *
tryget_socket(int s)223 tryget_socket(int s)
224 {
225 if ((s < 0) || (s >= NUM_SOCKETS)) {
226 return NULL;
227 }
228 if (!sockets[s].conn) {
229 return NULL;
230 }
231 return &sockets[s];
232 }
233
234 /**
235 * Allocate a new socket for a given netconn.
236 *
237 * @param newconn the netconn for which to allocate a socket
238 * @param accepted 1 if socket has been created by accept(),
239 * 0 if socket has been created by socket()
240 * @return the index of the new socket; -1 on error
241 */
242 static int
alloc_socket(struct netconn * newconn,int accepted)243 alloc_socket(struct netconn *newconn, int accepted)
244 {
245 int i;
246 SYS_ARCH_DECL_PROTECT(lev);
247
248 /* allocate a new socket identifier */
249 for (i = 0; i < NUM_SOCKETS; ++i) {
250 /* Protect socket array */
251 SYS_ARCH_PROTECT(lev);
252 if (!sockets[i].conn) {
253 sockets[i].conn = newconn;
254 /* The socket is not yet known to anyone, so no need to protect
255 after having marked it as used. */
256 SYS_ARCH_UNPROTECT(lev);
257 sockets[i].lastdata = NULL;
258 sockets[i].lastoffset = 0;
259 sockets[i].rcvevent = 0;
260 /* TCP sendbuf is empty, but the socket is not yet writable until connected
261 * (unless it has been created by accept()). */
262 sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);
263 sockets[i].errevent = 0;
264 sockets[i].err = 0;
265 sockets[i].select_waiting = 0;
266 return i;
267 }
268 SYS_ARCH_UNPROTECT(lev);
269 }
270 return -1;
271 }
272
273 /** Free a socket. The socket's netconn must have been
274 * delete before!
275 *
276 * @param sock the socket to free
277 * @param is_tcp != 0 for TCP sockets, used to free lastdata
278 */
279 static void
free_socket(struct lwip_sock * sock,int is_tcp)280 free_socket(struct lwip_sock *sock, int is_tcp)
281 {
282 void *lastdata;
283 SYS_ARCH_DECL_PROTECT(lev);
284
285 lastdata = sock->lastdata;
286 sock->lastdata = NULL;
287 sock->lastoffset = 0;
288 sock->err = 0;
289
290 /* Protect socket array */
291 SYS_ARCH_PROTECT(lev);
292 sock->conn = NULL;
293 SYS_ARCH_UNPROTECT(lev);
294 /* don't use 'sock' after this line, as another task might have allocated it */
295
296 if (lastdata != NULL) {
297 if (is_tcp) {
298 pbuf_free((struct pbuf *)lastdata);
299 } else {
300 netbuf_delete((struct netbuf *)lastdata);
301 }
302 }
303 }
304
305 /* Below this, the well-known socket functions are implemented.
306 * Use google.com or opengroup.org to get a good description :-)
307 *
308 * Exceptions are documented!
309 */
310
311 int
lwip_accept(int s,struct sockaddr * addr,socklen_t * addrlen)312 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
313 {
314 struct lwip_sock *sock, *nsock;
315 struct netconn *newconn;
316 ip_addr_t naddr;
317 u16_t port;
318 int newsock;
319 struct sockaddr_in sin;
320 err_t err;
321 SYS_ARCH_DECL_PROTECT(lev);
322
323 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
324 sock = get_socket(s);
325 if (!sock) {
326 return -1;
327 }
328
329 if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
330 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
331 sock_set_errno(sock, EWOULDBLOCK);
332 return -1;
333 }
334
335 /* wait for a new connection */
336 err = netconn_accept(sock->conn, &newconn);
337 if (err != ERR_OK) {
338 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
339 sock_set_errno(sock, err_to_errno(err));
340 return -1;
341 }
342 LWIP_ASSERT("newconn != NULL", newconn != NULL);
343 /* Prevent automatic window updates, we do this on our own! */
344 netconn_set_noautorecved(newconn, 1);
345
346 /* get the IP address and port of the remote host */
347 err = netconn_peer(newconn, &naddr, &port);
348 if (err != ERR_OK) {
349 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
350 netconn_delete(newconn);
351 sock_set_errno(sock, err_to_errno(err));
352 return -1;
353 }
354
355 /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
356 * not be NULL if addr is valid.
357 */
358 if (NULL != addr) {
359 LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
360 memset(&sin, 0, sizeof(sin));
361 sin.sin_len = sizeof(sin);
362 sin.sin_family = AF_INET;
363 sin.sin_port = htons(port);
364 inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
365
366 if (*addrlen > sizeof(sin))
367 *addrlen = sizeof(sin);
368
369 MEMCPY(addr, &sin, *addrlen);
370 }
371
372 newsock = alloc_socket(newconn, 1);
373 if (newsock == -1) {
374 netconn_delete(newconn);
375 sock_set_errno(sock, ENFILE);
376 return -1;
377 }
378 LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));
379 LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
380 nsock = &sockets[newsock];
381
382 /* See event_callback: If data comes in right away after an accept, even
383 * though the server task might not have created a new socket yet.
384 * In that case, newconn->socket is counted down (newconn->socket--),
385 * so nsock->rcvevent is >= 1 here!
386 */
387 SYS_ARCH_PROTECT(lev);
388 nsock->rcvevent += (s16_t)(-1 - newconn->socket);
389 newconn->socket = newsock;
390 SYS_ARCH_UNPROTECT(lev);
391
392 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
393 ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
394 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
395
396 sock_set_errno(sock, 0);
397 return newsock;
398 }
399
400 int
lwip_bind(int s,const struct sockaddr * name,socklen_t namelen)401 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
402 {
403 struct lwip_sock *sock;
404 ip_addr_t local_addr;
405 u16_t local_port;
406 err_t err;
407 const struct sockaddr_in *name_in;
408
409 sock = get_socket(s);
410 if (!sock) {
411 return -1;
412 }
413
414 /* check size, familiy and alignment of 'name' */
415 LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
416 ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
417 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
418 name_in = (const struct sockaddr_in *)(void*)name;
419
420 inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);
421 local_port = name_in->sin_port;
422
423 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
424 ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
425 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port)));
426
427 err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
428
429 if (err != ERR_OK) {
430 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
431 sock_set_errno(sock, err_to_errno(err));
432 return -1;
433 }
434
435 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
436 sock_set_errno(sock, 0);
437 return 0;
438 }
439
440 int
lwip_close(int s)441 lwip_close(int s)
442 {
443 struct lwip_sock *sock;
444 int is_tcp = 0;
445
446 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
447
448 sock = get_socket(s);
449 if (!sock) {
450 return -1;
451 }
452
453 if(sock->conn != NULL) {
454 is_tcp = netconn_type(sock->conn) == NETCONN_TCP;
455 } else {
456 LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
457 }
458
459 netconn_delete(sock->conn);
460
461 free_socket(sock, is_tcp);
462 set_errno(0);
463 return 0;
464 }
465
466 int
lwip_connect(int s,const struct sockaddr * name,socklen_t namelen)467 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
468 {
469 struct lwip_sock *sock;
470 err_t err;
471 const struct sockaddr_in *name_in;
472
473 sock = get_socket(s);
474 if (!sock) {
475 return -1;
476 }
477
478 /* check size, familiy and alignment of 'name' */
479 LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
480 ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
481 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
482 name_in = (const struct sockaddr_in *)(void*)name;
483
484 if (name_in->sin_family == AF_UNSPEC) {
485 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
486 err = netconn_disconnect(sock->conn);
487 } else {
488 ip_addr_t remote_addr;
489 u16_t remote_port;
490
491 inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);
492 remote_port = name_in->sin_port;
493
494 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
495 ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
496 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port)));
497
498 err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
499 }
500
501 if (err != ERR_OK) {
502 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
503 sock_set_errno(sock, err_to_errno(err));
504 return -1;
505 }
506
507 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
508 sock_set_errno(sock, 0);
509 return 0;
510 }
511
512 /**
513 * Set a socket into listen mode.
514 * The socket may not have been used for another connection previously.
515 *
516 * @param s the socket to set to listening mode
517 * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
518 * @return 0 on success, non-zero on failure
519 */
520 int
lwip_listen(int s,int backlog)521 lwip_listen(int s, int backlog)
522 {
523 struct lwip_sock *sock;
524 err_t err;
525
526 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
527
528 sock = get_socket(s);
529 if (!sock) {
530 return -1;
531 }
532
533 /* limit the "backlog" parameter to fit in an u8_t */
534 backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
535
536 err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
537
538 if (err != ERR_OK) {
539 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
540 sock_set_errno(sock, err_to_errno(err));
541 return -1;
542 }
543
544 sock_set_errno(sock, 0);
545 return 0;
546 }
547
548 int
lwip_recvfrom(int s,void * mem,size_t len,int flags,struct sockaddr * from,socklen_t * fromlen)549 lwip_recvfrom(int s, void *mem, size_t len, int flags,
550 struct sockaddr *from, socklen_t *fromlen)
551 {
552 struct lwip_sock *sock;
553 void *buf = NULL;
554 struct pbuf *p;
555 u16_t buflen, copylen;
556 int off = 0;
557 ip_addr_t *addr;
558 u16_t port;
559 u8_t done = 0;
560 err_t err;
561
562 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
563 sock = get_socket(s);
564 if (!sock) {
565 return -1;
566 }
567
568 do {
569 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
570 /* Check if there is data left from the last recv operation. */
571 if (sock->lastdata) {
572 buf = sock->lastdata;
573 } else {
574 /* If this is non-blocking call, then check first */
575 if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
576 (sock->rcvevent <= 0)) {
577 if (off > 0) {
578 /* update receive window */
579 netconn_recved(sock->conn, (u32_t)off);
580 /* already received data, return that */
581 sock_set_errno(sock, 0);
582 return off;
583 }
584 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
585 sock_set_errno(sock, EWOULDBLOCK);
586 return -1;
587 }
588
589 /* No data was left from the previous operation, so we try to get
590 some from the network. */
591 if (netconn_type(sock->conn) == NETCONN_TCP) {
592 err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
593 } else {
594 err = netconn_recv(sock->conn, (struct netbuf **)&buf);
595 }
596 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
597 err, buf));
598
599 if (err != ERR_OK) {
600 if (off > 0) {
601 /* update receive window */
602 netconn_recved(sock->conn, (u32_t)off);
603 /* already received data, return that */
604 sock_set_errno(sock, 0);
605 return off;
606 }
607 /* We should really do some error checking here. */
608 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
609 s, lwip_strerr(err)));
610 sock_set_errno(sock, err_to_errno(err));
611 if (err == ERR_CLSD) {
612 return 0;
613 } else {
614 return -1;
615 }
616 }
617 LWIP_ASSERT("buf != NULL", buf != NULL);
618 sock->lastdata = buf;
619 }
620
621 if (netconn_type(sock->conn) == NETCONN_TCP) {
622 p = (struct pbuf *)buf;
623 } else {
624 p = ((struct netbuf *)buf)->p;
625 }
626 buflen = p->tot_len;
627 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
628 buflen, len, off, sock->lastoffset));
629
630 buflen -= sock->lastoffset;
631
632 if (len > buflen) {
633 copylen = buflen;
634 } else {
635 copylen = (u16_t)len;
636 }
637
638 /* copy the contents of the received buffer into
639 the supplied memory pointer mem */
640 pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
641
642 off += copylen;
643
644 if (netconn_type(sock->conn) == NETCONN_TCP) {
645 LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
646 len -= copylen;
647 if ( (len <= 0) ||
648 (p->flags & PBUF_FLAG_PUSH) ||
649 (sock->rcvevent <= 0) ||
650 ((flags & MSG_PEEK)!=0)) {
651 done = 1;
652 }
653 } else {
654 done = 1;
655 }
656
657 /* Check to see from where the data was.*/
658 if (done) {
659 ip_addr_t fromaddr;
660 if (from && fromlen) {
661 struct sockaddr_in sin;
662
663 if (netconn_type(sock->conn) == NETCONN_TCP) {
664 addr = &fromaddr;
665 netconn_getaddr(sock->conn, addr, &port, 0);
666 } else {
667 addr = netbuf_fromaddr((struct netbuf *)buf);
668 port = netbuf_fromport((struct netbuf *)buf);
669 }
670
671 memset(&sin, 0, sizeof(sin));
672 sin.sin_len = sizeof(sin);
673 sin.sin_family = AF_INET;
674 sin.sin_port = htons(port);
675 inet_addr_from_ipaddr(&sin.sin_addr, addr);
676
677 if (*fromlen > sizeof(sin)) {
678 *fromlen = sizeof(sin);
679 }
680
681 MEMCPY(from, &sin, *fromlen);
682
683 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
684 ip_addr_debug_print(SOCKETS_DEBUG, addr);
685 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
686 } else {
687 #if SOCKETS_DEBUG
688 if (netconn_type(sock->conn) == NETCONN_TCP) {
689 addr = &fromaddr;
690 netconn_getaddr(sock->conn, addr, &port, 0);
691 } else {
692 addr = netbuf_fromaddr((struct netbuf *)buf);
693 port = netbuf_fromport((struct netbuf *)buf);
694 }
695
696 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
697 ip_addr_debug_print(SOCKETS_DEBUG, addr);
698 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
699 #endif /* SOCKETS_DEBUG */
700 }
701 }
702
703 /* If we don't peek the incoming message... */
704 if ((flags & MSG_PEEK) == 0) {
705 /* If this is a TCP socket, check if there is data left in the
706 buffer. If so, it should be saved in the sock structure for next
707 time around. */
708 if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {
709 sock->lastdata = buf;
710 sock->lastoffset += copylen;
711 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
712 } else {
713 sock->lastdata = NULL;
714 sock->lastoffset = 0;
715 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
716 if (netconn_type(sock->conn) == NETCONN_TCP) {
717 pbuf_free((struct pbuf *)buf);
718 } else {
719 netbuf_delete((struct netbuf *)buf);
720 }
721 }
722 }
723 } while (!done);
724
725 if (off > 0) {
726 /* update receive window */
727 netconn_recved(sock->conn, (u32_t)off);
728 }
729 sock_set_errno(sock, 0);
730 return off;
731 }
732
733 int
lwip_read(int s,void * mem,size_t len)734 lwip_read(int s, void *mem, size_t len)
735 {
736 return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
737 }
738
739 int
lwip_recv(int s,void * mem,size_t len,int flags)740 lwip_recv(int s, void *mem, size_t len, int flags)
741 {
742 return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
743 }
744
745 int
lwip_send(int s,const void * data,size_t size,int flags)746 lwip_send(int s, const void *data, size_t size, int flags)
747 {
748 struct lwip_sock *sock;
749 err_t err;
750 u8_t write_flags;
751
752 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
753 s, data, size, flags));
754
755 sock = get_socket(s);
756 if (!sock) {
757 return -1;
758 }
759
760 if (sock->conn->type != NETCONN_TCP) {
761 #if (LWIP_UDP || LWIP_RAW)
762 return lwip_sendto(s, data, size, flags, NULL, 0);
763 #else /* (LWIP_UDP || LWIP_RAW) */
764 sock_set_errno(sock, err_to_errno(ERR_ARG));
765 return -1;
766 #endif /* (LWIP_UDP || LWIP_RAW) */
767 }
768
769 if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) {
770 if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) {
771 /* too much data to ever send nonblocking! */
772 sock_set_errno(sock, EMSGSIZE);
773 return -1;
774 }
775 }
776
777 write_flags = NETCONN_COPY |
778 ((flags & MSG_MORE) ? NETCONN_MORE : 0) |
779 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
780 err = netconn_write(sock->conn, data, size, write_flags);
781
782 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size));
783 sock_set_errno(sock, err_to_errno(err));
784 return (err == ERR_OK ? (int)size : -1);
785 }
786
787 int
lwip_sendto(int s,const void * data,size_t size,int flags,const struct sockaddr * to,socklen_t tolen)788 lwip_sendto(int s, const void *data, size_t size, int flags,
789 const struct sockaddr *to, socklen_t tolen)
790 {
791 struct lwip_sock *sock;
792 err_t err;
793 u16_t short_size;
794 const struct sockaddr_in *to_in;
795 u16_t remote_port;
796 #if !LWIP_TCPIP_CORE_LOCKING
797 struct netbuf buf;
798 #endif
799
800 sock = get_socket(s);
801 if (!sock) {
802 return -1;
803 }
804
805 if (sock->conn->type == NETCONN_TCP) {
806 #if LWIP_TCP
807 return lwip_send(s, data, size, flags);
808 #else /* LWIP_TCP */
809 LWIP_UNUSED_ARG(flags);
810 sock_set_errno(sock, err_to_errno(ERR_ARG));
811 return -1;
812 #endif /* LWIP_TCP */
813 }
814
815 /* @todo: split into multiple sendto's? */
816 LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
817 short_size = (u16_t)size;
818 LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
819 ((tolen == sizeof(struct sockaddr_in)) &&
820 ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))),
821 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
822 to_in = (const struct sockaddr_in *)(void*)to;
823
824 #if LWIP_TCPIP_CORE_LOCKING
825 /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */
826 {
827 struct pbuf* p;
828 ip_addr_t *remote_addr;
829
830 #if LWIP_NETIF_TX_SINGLE_PBUF
831 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM);
832 if (p != NULL) {
833 #if LWIP_CHECKSUM_ON_COPY
834 u16_t chksum = 0;
835 if (sock->conn->type != NETCONN_RAW) {
836 chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size);
837 } else
838 #endif /* LWIP_CHECKSUM_ON_COPY */
839 MEMCPY(p->payload, data, size);
840 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
841 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF);
842 if (p != NULL) {
843 p->payload = (void*)data;
844 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
845
846 if (to_in != NULL) {
847 inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr);
848 remote_port = ntohs(to_in->sin_port);
849 } else {
850 remote_addr = &sock->conn->pcb.raw->remote_ip;
851 if (sock->conn->type == NETCONN_RAW) {
852 remote_port = 0;
853 } else {
854 remote_port = sock->conn->pcb.udp->remote_port;
855 }
856 }
857
858 LOCK_TCPIP_CORE();
859 if (sock->conn->type == NETCONN_RAW) {
860 err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr);
861 } else {
862 #if LWIP_UDP
863 #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF
864 err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,
865 remote_addr, remote_port, 1, chksum);
866 #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
867 err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p,
868 remote_addr, remote_port);
869 #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
870 #else /* LWIP_UDP */
871 err = ERR_ARG;
872 #endif /* LWIP_UDP */
873 }
874 UNLOCK_TCPIP_CORE();
875
876 pbuf_free(p);
877 } else {
878 err = ERR_MEM;
879 }
880 }
881 #else /* LWIP_TCPIP_CORE_LOCKING */
882 /* initialize a buffer */
883 buf.p = buf.ptr = NULL;
884 #if LWIP_CHECKSUM_ON_COPY
885 buf.flags = 0;
886 #endif /* LWIP_CHECKSUM_ON_COPY */
887 if (to) {
888 inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr);
889 remote_port = ntohs(to_in->sin_port);
890 netbuf_fromport(&buf) = remote_port;
891 } else {
892 remote_port = 0;
893 ip_addr_set_any(&buf.addr);
894 netbuf_fromport(&buf) = 0;
895 }
896
897 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
898 s, data, short_size, flags));
899 ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
900 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
901
902 /* make the buffer point to the data that should be sent */
903 #if LWIP_NETIF_TX_SINGLE_PBUF
904 /* Allocate a new netbuf and copy the data into it. */
905 if (netbuf_alloc(&buf, short_size) == NULL) {
906 err = ERR_MEM;
907 } else {
908 #if LWIP_CHECKSUM_ON_COPY
909 if (sock->conn->type != NETCONN_RAW) {
910 u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
911 netbuf_set_chksum(&buf, chksum);
912 err = ERR_OK;
913 } else
914 #endif /* LWIP_CHECKSUM_ON_COPY */
915 {
916 err = netbuf_take(&buf, data, short_size);
917 }
918 }
919 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
920 err = netbuf_ref(&buf, data, short_size);
921 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
922 if (err == ERR_OK) {
923 /* send the data */
924 err = netconn_send(sock->conn, &buf);
925 }
926
927 /* deallocated the buffer */
928 netbuf_free(&buf);
929 #endif /* LWIP_TCPIP_CORE_LOCKING */
930 sock_set_errno(sock, err_to_errno(err));
931 return (err == ERR_OK ? short_size : -1);
932 }
933
934 int
935 lwip_socket(int domain, int type, int protocol)
936 {
937 struct netconn *conn;
938 int i;
939
940 LWIP_UNUSED_ARG(domain);
941
942 /* create a netconn */
943 switch (type) {
944 case SOCK_RAW:
945 conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
946 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
947 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
948 break;
949 case SOCK_DGRAM:
950 conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?
951 NETCONN_UDPLITE : NETCONN_UDP, event_callback);
952 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
953 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
954 break;
955 case SOCK_STREAM:
956 conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
957 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
958 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
959 if (conn != NULL) {
960 /* Prevent automatic window updates, we do this on our own! */
961 netconn_set_noautorecved(conn, 1);
962 }
963 break;
964 default:
965 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
966 domain, type, protocol));
967 set_errno(EINVAL);
968 return -1;
969 }
970
971 if (!conn) {
972 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
973 set_errno(ENOBUFS);
974 return -1;
975 }
976
977 i = alloc_socket(conn, 0);
978
979 if (i == -1) {
980 netconn_delete(conn);
981 set_errno(ENFILE);
982 return -1;
983 }
984 conn->socket = i;
985 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
986 set_errno(0);
987 return i;
988 }
989
990 int
991 lwip_write(int s, const void *data, size_t size)
992 {
993 return lwip_send(s, data, size, 0);
994 }
995
996 /**
997 * Go through the readset and writeset lists and see which socket of the sockets
998 * set in the sets has events. On return, readset, writeset and exceptset have
999 * the sockets enabled that had events.
1000 *
1001 * exceptset is not used for now!!!
1002 *
1003 * @param maxfdp1 the highest socket index in the sets
1004 * @param readset_in: set of sockets to check for read events
1005 * @param writeset_in: set of sockets to check for write events
1006 * @param exceptset_in: set of sockets to check for error events
1007 * @param readset_out: set of sockets that had read events
1008 * @param writeset_out: set of sockets that had write events
1009 * @param exceptset_out: set os sockets that had error events
1010 * @return number of sockets that had events (read/write/exception) (>= 0)
1011 */
1012 static int
1013 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
1014 fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
1015 {
1016 int i, nready = 0;
1017 fd_set lreadset, lwriteset, lexceptset;
1018 struct lwip_sock *sock;
1019 SYS_ARCH_DECL_PROTECT(lev);
1020
1021 FD_ZERO(&lreadset);
1022 FD_ZERO(&lwriteset);
1023 FD_ZERO(&lexceptset);
1024
1025 /* Go through each socket in each list to count number of sockets which
1026 currently match */
1027 for(i = 0; i < maxfdp1; i++) {
1028 void* lastdata = NULL;
1029 s16_t rcvevent = 0;
1030 u16_t sendevent = 0;
1031 u16_t errevent = 0;
1032 /* First get the socket's status (protected)... */
1033 SYS_ARCH_PROTECT(lev);
1034 sock = tryget_socket(i);
1035 if (sock != NULL) {
1036 lastdata = sock->lastdata;
1037 rcvevent = sock->rcvevent;
1038 sendevent = sock->sendevent;
1039 errevent = sock->errevent;
1040 }
1041 SYS_ARCH_UNPROTECT(lev);
1042 /* ... then examine it: */
1043 /* See if netconn of this socket is ready for read */
1044 if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
1045 FD_SET(i, &lreadset);
1046 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
1047 nready++;
1048 }
1049 /* See if netconn of this socket is ready for write */
1050 if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
1051 FD_SET(i, &lwriteset);
1052 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
1053 nready++;
1054 }
1055 /* See if netconn of this socket had an error */
1056 if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
1057 FD_SET(i, &lexceptset);
1058 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
1059 nready++;
1060 }
1061 }
1062 /* copy local sets to the ones provided as arguments */
1063 *readset_out = lreadset;
1064 *writeset_out = lwriteset;
1065 *exceptset_out = lexceptset;
1066
1067 LWIP_ASSERT("nready >= 0", nready >= 0);
1068 return nready;
1069 }
1070
1071 /**
1072 * Processing exceptset is not yet implemented.
1073 */
1074 int
1075 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
1076 struct timeval *timeout)
1077 {
1078 u32_t waitres = 0;
1079 int nready;
1080 fd_set lreadset, lwriteset, lexceptset;
1081 u32_t msectimeout;
1082 struct lwip_select_cb select_cb;
1083 err_t err;
1084 int i;
1085 SYS_ARCH_DECL_PROTECT(lev);
1086
1087 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
1088 maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
1089 timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
1090 timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
1091
1092 /* Go through each socket in each list to count number of sockets which
1093 currently match */
1094 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1095
1096 /* If we don't have any current events, then suspend if we are supposed to */
1097 if (!nready) {
1098 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
1099 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
1100 /* This is OK as the local fdsets are empty and nready is zero,
1101 or we would have returned earlier. */
1102 goto return_copy_fdsets;
1103 }
1104
1105 /* None ready: add our semaphore to list:
1106 We don't actually need any dynamic memory. Our entry on the
1107 list is only valid while we are in this function, so it's ok
1108 to use local variables. */
1109
1110 select_cb.next = NULL;
1111 select_cb.prev = NULL;
1112 select_cb.readset = readset;
1113 select_cb.writeset = writeset;
1114 select_cb.exceptset = exceptset;
1115 select_cb.sem_signalled = 0;
1116 err = sys_sem_new(&select_cb.sem, 0);
1117 if (err != ERR_OK) {
1118 /* failed to create semaphore */
1119 set_errno(ENOMEM);
1120 return -1;
1121 }
1122
1123 /* Protect the select_cb_list */
1124 SYS_ARCH_PROTECT(lev);
1125
1126 /* Put this select_cb on top of list */
1127 select_cb.next = select_cb_list;
1128 if (select_cb_list != NULL) {
1129 select_cb_list->prev = &select_cb;
1130 }
1131 select_cb_list = &select_cb;
1132 /* Increasing this counter tells even_callback that the list has changed. */
1133 select_cb_ctr++;
1134
1135 /* Now we can safely unprotect */
1136 SYS_ARCH_UNPROTECT(lev);
1137
1138 /* Increase select_waiting for each socket we are interested in */
1139 for(i = 0; i < maxfdp1; i++) {
1140 if ((readset && FD_ISSET(i, readset)) ||
1141 (writeset && FD_ISSET(i, writeset)) ||
1142 (exceptset && FD_ISSET(i, exceptset))) {
1143 struct lwip_sock *sock = tryget_socket(i);
1144 LWIP_ASSERT("sock != NULL", sock != NULL);
1145 SYS_ARCH_PROTECT(lev);
1146 sock->select_waiting++;
1147 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
1148 SYS_ARCH_UNPROTECT(lev);
1149 }
1150 }
1151
1152 /* Call lwip_selscan again: there could have been events between
1153 the last scan (whithout us on the list) and putting us on the list! */
1154 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1155 if (!nready) {
1156 /* Still none ready, just wait to be woken */
1157 if (timeout == 0) {
1158 /* Wait forever */
1159 msectimeout = 0;
1160 } else {
1161 msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
1162 if (msectimeout == 0) {
1163 /* Wait 1ms at least (0 means wait forever) */
1164 msectimeout = 1;
1165 }
1166 }
1167
1168 waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
1169 }
1170 /* Increase select_waiting for each socket we are interested in */
1171 for(i = 0; i < maxfdp1; i++) {
1172 if ((readset && FD_ISSET(i, readset)) ||
1173 (writeset && FD_ISSET(i, writeset)) ||
1174 (exceptset && FD_ISSET(i, exceptset))) {
1175 struct lwip_sock *sock = tryget_socket(i);
1176 LWIP_ASSERT("sock != NULL", sock != NULL);
1177 SYS_ARCH_PROTECT(lev);
1178 sock->select_waiting--;
1179 LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0);
1180 SYS_ARCH_UNPROTECT(lev);
1181 }
1182 }
1183 /* Take us off the list */
1184 SYS_ARCH_PROTECT(lev);
1185 if (select_cb.next != NULL) {
1186 select_cb.next->prev = select_cb.prev;
1187 }
1188 if (select_cb_list == &select_cb) {
1189 LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
1190 select_cb_list = select_cb.next;
1191 } else {
1192 LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
1193 select_cb.prev->next = select_cb.next;
1194 }
1195 /* Increasing this counter tells even_callback that the list has changed. */
1196 select_cb_ctr++;
1197 SYS_ARCH_UNPROTECT(lev);
1198
1199 sys_sem_free(&select_cb.sem);
1200 if (waitres == SYS_ARCH_TIMEOUT) {
1201 /* Timeout */
1202 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
1203 /* This is OK as the local fdsets are empty and nready is zero,
1204 or we would have returned earlier. */
1205 goto return_copy_fdsets;
1206 }
1207
1208 /* See what's set */
1209 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1210 }
1211
1212 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
1213 return_copy_fdsets:
1214 set_errno(0);
1215 if (readset) {
1216 *readset = lreadset;
1217 }
1218 if (writeset) {
1219 *writeset = lwriteset;
1220 }
1221 if (exceptset) {
1222 *exceptset = lexceptset;
1223 }
1224
1225
1226 return nready;
1227 }
1228
1229 /**
1230 * Callback registered in the netconn layer for each socket-netconn.
1231 * Processes recvevent (data available) and wakes up tasks waiting for select.
1232 */
1233 static void
1234 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
1235 {
1236 int s;
1237 struct lwip_sock *sock;
1238 struct lwip_select_cb *scb;
1239 int last_select_cb_ctr;
1240 SYS_ARCH_DECL_PROTECT(lev);
1241
1242 LWIP_UNUSED_ARG(len);
1243
1244 /* Get socket */
1245 if (conn) {
1246 s = conn->socket;
1247 if (s < 0) {
1248 /* Data comes in right away after an accept, even though
1249 * the server task might not have created a new socket yet.
1250 * Just count down (or up) if that's the case and we
1251 * will use the data later. Note that only receive events
1252 * can happen before the new socket is set up. */
1253 SYS_ARCH_PROTECT(lev);
1254 if (conn->socket < 0) {
1255 if (evt == NETCONN_EVT_RCVPLUS) {
1256 conn->socket--;
1257 }
1258 SYS_ARCH_UNPROTECT(lev);
1259 return;
1260 }
1261 s = conn->socket;
1262 SYS_ARCH_UNPROTECT(lev);
1263 }
1264
1265 sock = get_socket(s);
1266 if (!sock) {
1267 return;
1268 }
1269 } else {
1270 return;
1271 }
1272
1273 SYS_ARCH_PROTECT(lev);
1274 /* Set event as required */
1275 switch (evt) {
1276 case NETCONN_EVT_RCVPLUS:
1277 sock->rcvevent++;
1278 break;
1279 case NETCONN_EVT_RCVMINUS:
1280 sock->rcvevent--;
1281 break;
1282 case NETCONN_EVT_SENDPLUS:
1283 sock->sendevent = 1;
1284 break;
1285 case NETCONN_EVT_SENDMINUS:
1286 sock->sendevent = 0;
1287 break;
1288 case NETCONN_EVT_ERROR:
1289 sock->errevent = 1;
1290 break;
1291 default:
1292 LWIP_ASSERT("unknown event", 0);
1293 break;
1294 }
1295
1296 if (sock->select_waiting == 0) {
1297 /* noone is waiting for this socket, no need to check select_cb_list */
1298 SYS_ARCH_UNPROTECT(lev);
1299 return;
1300 }
1301
1302 /* Now decide if anyone is waiting for this socket */
1303 /* NOTE: This code goes through the select_cb_list list multiple times
1304 ONLY IF a select was actually waiting. We go through the list the number
1305 of waiting select calls + 1. This list is expected to be small. */
1306
1307 /* At this point, SYS_ARCH is still protected! */
1308 again:
1309 for (scb = select_cb_list; scb != NULL; scb = scb->next) {
1310 if (scb->sem_signalled == 0) {
1311 /* semaphore not signalled yet */
1312 int do_signal = 0;
1313 /* Test this select call for our socket */
1314 if (sock->rcvevent > 0) {
1315 if (scb->readset && FD_ISSET(s, scb->readset)) {
1316 do_signal = 1;
1317 }
1318 }
1319 if (sock->sendevent != 0) {
1320 if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
1321 do_signal = 1;
1322 }
1323 }
1324 if (sock->errevent != 0) {
1325 if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
1326 do_signal = 1;
1327 }
1328 }
1329 if (do_signal) {
1330 scb->sem_signalled = 1;
1331 /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
1332 lead to the select thread taking itself off the list, invalidagin the semaphore. */
1333 sys_sem_signal(&scb->sem);
1334 }
1335 }
1336 /* unlock interrupts with each step */
1337 last_select_cb_ctr = select_cb_ctr;
1338 SYS_ARCH_UNPROTECT(lev);
1339 /* this makes sure interrupt protection time is short */
1340 SYS_ARCH_PROTECT(lev);
1341 if (last_select_cb_ctr != select_cb_ctr) {
1342 /* someone has changed select_cb_list, restart at the beginning */
1343 goto again;
1344 }
1345 }
1346 SYS_ARCH_UNPROTECT(lev);
1347 }
1348
1349 /**
1350 * Unimplemented: Close one end of a full-duplex connection.
1351 * Currently, the full connection is closed.
1352 */
1353 int
1354 lwip_shutdown(int s, int how)
1355 {
1356 struct lwip_sock *sock;
1357 err_t err;
1358 u8_t shut_rx = 0, shut_tx = 0;
1359
1360 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
1361
1362 sock = get_socket(s);
1363 if (!sock) {
1364 return -1;
1365 }
1366
1367 if (sock->conn != NULL) {
1368 if (netconn_type(sock->conn) != NETCONN_TCP) {
1369 sock_set_errno(sock, EOPNOTSUPP);
1370 return EOPNOTSUPP;
1371 }
1372 } else {
1373 sock_set_errno(sock, ENOTCONN);
1374 return ENOTCONN;
1375 }
1376
1377 if (how == SHUT_RD) {
1378 shut_rx = 1;
1379 } else if (how == SHUT_WR) {
1380 shut_tx = 1;
1381 } else if(how == SHUT_RDWR) {
1382 shut_rx = 1;
1383 shut_tx = 1;
1384 } else {
1385 sock_set_errno(sock, EINVAL);
1386 return EINVAL;
1387 }
1388 err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
1389
1390 sock_set_errno(sock, err_to_errno(err));
1391 return (err == ERR_OK ? 0 : -1);
1392 }
1393
1394 static int
1395 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
1396 {
1397 struct lwip_sock *sock;
1398 struct sockaddr_in sin;
1399 ip_addr_t naddr;
1400
1401 sock = get_socket(s);
1402 if (!sock) {
1403 return -1;
1404 }
1405
1406 memset(&sin, 0, sizeof(sin));
1407 sin.sin_len = sizeof(sin);
1408 sin.sin_family = AF_INET;
1409
1410 /* get the IP address and port */
1411 netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
1412
1413 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
1414 ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
1415 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port));
1416
1417 sin.sin_port = htons(sin.sin_port);
1418 inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
1419
1420 if (*namelen > sizeof(sin)) {
1421 *namelen = sizeof(sin);
1422 }
1423
1424 MEMCPY(name, &sin, *namelen);
1425 sock_set_errno(sock, 0);
1426 return 0;
1427 }
1428
1429 int
1430 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
1431 {
1432 return lwip_getaddrname(s, name, namelen, 0);
1433 }
1434
1435 int
1436 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
1437 {
1438 return lwip_getaddrname(s, name, namelen, 1);
1439 }
1440
1441 int
1442 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
1443 {
1444 err_t err = ERR_OK;
1445 struct lwip_sock *sock = get_socket(s);
1446 struct lwip_setgetsockopt_data data;
1447
1448 if (!sock) {
1449 return -1;
1450 }
1451
1452 if ((NULL == optval) || (NULL == optlen)) {
1453 sock_set_errno(sock, EFAULT);
1454 return -1;
1455 }
1456
1457 /* Do length and type checks for the various options first, to keep it readable. */
1458 switch (level) {
1459
1460 /* Level: SOL_SOCKET */
1461 case SOL_SOCKET:
1462 switch (optname) {
1463
1464 case SO_ACCEPTCONN:
1465 case SO_BROADCAST:
1466 /* UNIMPL case SO_DEBUG: */
1467 /* UNIMPL case SO_DONTROUTE: */
1468 case SO_ERROR:
1469 case SO_KEEPALIVE:
1470 /* UNIMPL case SO_CONTIMEO: */
1471 /* UNIMPL case SO_SNDTIMEO: */
1472 #if LWIP_SO_RCVTIMEO
1473 case SO_RCVTIMEO:
1474 #endif /* LWIP_SO_RCVTIMEO */
1475 #if LWIP_SO_RCVBUF
1476 case SO_RCVBUF:
1477 #endif /* LWIP_SO_RCVBUF */
1478 /* UNIMPL case SO_OOBINLINE: */
1479 /* UNIMPL case SO_SNDBUF: */
1480 /* UNIMPL case SO_RCVLOWAT: */
1481 /* UNIMPL case SO_SNDLOWAT: */
1482 #if SO_REUSE
1483 case SO_REUSEADDR:
1484 case SO_REUSEPORT:
1485 #endif /* SO_REUSE */
1486 case SO_TYPE:
1487 /* UNIMPL case SO_USELOOPBACK: */
1488 if (*optlen < sizeof(int)) {
1489 err = EINVAL;
1490 }
1491 break;
1492
1493 case SO_NO_CHECK:
1494 if (*optlen < sizeof(int)) {
1495 err = EINVAL;
1496 }
1497 #if LWIP_UDP
1498 if ((sock->conn->type != NETCONN_UDP) ||
1499 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1500 /* this flag is only available for UDP, not for UDP lite */
1501 err = EAFNOSUPPORT;
1502 }
1503 #endif /* LWIP_UDP */
1504 break;
1505
1506 default:
1507 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1508 s, optname));
1509 err = ENOPROTOOPT;
1510 } /* switch (optname) */
1511 break;
1512
1513 /* Level: IPPROTO_IP */
1514 case IPPROTO_IP:
1515 switch (optname) {
1516 /* UNIMPL case IP_HDRINCL: */
1517 /* UNIMPL case IP_RCVDSTADDR: */
1518 /* UNIMPL case IP_RCVIF: */
1519 case IP_TTL:
1520 case IP_TOS:
1521 if (*optlen < sizeof(int)) {
1522 err = EINVAL;
1523 }
1524 break;
1525 #if LWIP_IGMP
1526 case IP_MULTICAST_TTL:
1527 if (*optlen < sizeof(u8_t)) {
1528 err = EINVAL;
1529 }
1530 break;
1531 case IP_MULTICAST_IF:
1532 if (*optlen < sizeof(struct in_addr)) {
1533 err = EINVAL;
1534 }
1535 break;
1536 case IP_MULTICAST_LOOP:
1537 if (*optlen < sizeof(u8_t)) {
1538 err = EINVAL;
1539 }
1540 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1541 err = EAFNOSUPPORT;
1542 }
1543 break;
1544 #endif /* LWIP_IGMP */
1545
1546 default:
1547 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1548 s, optname));
1549 err = ENOPROTOOPT;
1550 } /* switch (optname) */
1551 break;
1552
1553 #if LWIP_TCP
1554 /* Level: IPPROTO_TCP */
1555 case IPPROTO_TCP:
1556 if (*optlen < sizeof(int)) {
1557 err = EINVAL;
1558 break;
1559 }
1560
1561 /* If this is no TCP socket, ignore any options. */
1562 if (sock->conn->type != NETCONN_TCP)
1563 return 0;
1564
1565 switch (optname) {
1566 case TCP_NODELAY:
1567 case TCP_KEEPALIVE:
1568 #if LWIP_TCP_KEEPALIVE
1569 case TCP_KEEPIDLE:
1570 case TCP_KEEPINTVL:
1571 case TCP_KEEPCNT:
1572 #endif /* LWIP_TCP_KEEPALIVE */
1573 break;
1574
1575 default:
1576 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
1577 s, optname));
1578 err = ENOPROTOOPT;
1579 } /* switch (optname) */
1580 break;
1581 #endif /* LWIP_TCP */
1582 #if LWIP_UDP && LWIP_UDPLITE
1583 /* Level: IPPROTO_UDPLITE */
1584 case IPPROTO_UDPLITE:
1585 if (*optlen < sizeof(int)) {
1586 err = EINVAL;
1587 break;
1588 }
1589
1590 /* If this is no UDP lite socket, ignore any options. */
1591 if (sock->conn->type != NETCONN_UDPLITE) {
1592 return 0;
1593 }
1594
1595 switch (optname) {
1596 case UDPLITE_SEND_CSCOV:
1597 case UDPLITE_RECV_CSCOV:
1598 break;
1599
1600 default:
1601 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
1602 s, optname));
1603 err = ENOPROTOOPT;
1604 } /* switch (optname) */
1605 break;
1606 #endif /* LWIP_UDP && LWIP_UDPLITE*/
1607 /* UNDEFINED LEVEL */
1608 default:
1609 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
1610 s, level, optname));
1611 err = ENOPROTOOPT;
1612 } /* switch */
1613
1614
1615 if (err != ERR_OK) {
1616 sock_set_errno(sock, err);
1617 return -1;
1618 }
1619
1620 /* Now do the actual option processing */
1621 data.sock = sock;
1622 #ifdef LWIP_DEBUG
1623 data.s = s;
1624 #endif /* LWIP_DEBUG */
1625 data.level = level;
1626 data.optname = optname;
1627 data.optval = optval;
1628 data.optlen = optlen;
1629 data.err = err;
1630 tcpip_callback(lwip_getsockopt_internal, &data);
1631 sys_arch_sem_wait(&sock->conn->op_completed, 0);
1632 /* maybe lwip_getsockopt_internal has changed err */
1633 err = data.err;
1634
1635 sock_set_errno(sock, err);
1636 return err ? -1 : 0;
1637 }
1638
1639 static void
1640 lwip_getsockopt_internal(void *arg)
1641 {
1642 struct lwip_sock *sock;
1643 #ifdef LWIP_DEBUG
1644 int s;
1645 #endif /* LWIP_DEBUG */
1646 int level, optname;
1647 void *optval;
1648 struct lwip_setgetsockopt_data *data;
1649
1650 LWIP_ASSERT("arg != NULL", arg != NULL);
1651
1652 data = (struct lwip_setgetsockopt_data*)arg;
1653 sock = data->sock;
1654 #ifdef LWIP_DEBUG
1655 s = data->s;
1656 #endif /* LWIP_DEBUG */
1657 level = data->level;
1658 optname = data->optname;
1659 optval = data->optval;
1660
1661 switch (level) {
1662
1663 /* Level: SOL_SOCKET */
1664 case SOL_SOCKET:
1665 switch (optname) {
1666
1667 /* The option flags */
1668 case SO_ACCEPTCONN:
1669 case SO_BROADCAST:
1670 /* UNIMPL case SO_DEBUG: */
1671 /* UNIMPL case SO_DONTROUTE: */
1672 case SO_KEEPALIVE:
1673 /* UNIMPL case SO_OOBINCLUDE: */
1674 #if SO_REUSE
1675 case SO_REUSEADDR:
1676 case SO_REUSEPORT:
1677 #endif /* SO_REUSE */
1678 /*case SO_USELOOPBACK: UNIMPL */
1679 *(int*)optval = sock->conn->pcb.ip->so_options & optname;
1680 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
1681 s, optname, (*(int*)optval?"on":"off")));
1682 break;
1683
1684 case SO_TYPE:
1685 switch (NETCONNTYPE_GROUP(sock->conn->type)) {
1686 case NETCONN_RAW:
1687 *(int*)optval = SOCK_RAW;
1688 break;
1689 case NETCONN_TCP:
1690 *(int*)optval = SOCK_STREAM;
1691 break;
1692 case NETCONN_UDP:
1693 *(int*)optval = SOCK_DGRAM;
1694 break;
1695 default: /* unrecognized socket type */
1696 *(int*)optval = sock->conn->type;
1697 LWIP_DEBUGF(SOCKETS_DEBUG,
1698 ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
1699 s, *(int *)optval));
1700 } /* switch (sock->conn->type) */
1701 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
1702 s, *(int *)optval));
1703 break;
1704
1705 case SO_ERROR:
1706 /* only overwrite ERR_OK or tempoary errors */
1707 if ((sock->err == 0) || (sock->err == EINPROGRESS)) {
1708 sock_set_errno(sock, err_to_errno(sock->conn->last_err));
1709 }
1710 *(int *)optval = sock->err;
1711 sock->err = 0;
1712 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
1713 s, *(int *)optval));
1714 break;
1715
1716 #if LWIP_SO_RCVTIMEO
1717 case SO_RCVTIMEO:
1718 *(int *)optval = netconn_get_recvtimeout(sock->conn);
1719 break;
1720 #endif /* LWIP_SO_RCVTIMEO */
1721 #if LWIP_SO_RCVBUF
1722 case SO_RCVBUF:
1723 *(int *)optval = netconn_get_recvbufsize(sock->conn);
1724 break;
1725 #endif /* LWIP_SO_RCVBUF */
1726 #if LWIP_UDP
1727 case SO_NO_CHECK:
1728 *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
1729 break;
1730 #endif /* LWIP_UDP*/
1731 default:
1732 LWIP_ASSERT("unhandled optname", 0);
1733 break;
1734 } /* switch (optname) */
1735 break;
1736
1737 /* Level: IPPROTO_IP */
1738 case IPPROTO_IP:
1739 switch (optname) {
1740 case IP_TTL:
1741 *(int*)optval = sock->conn->pcb.ip->ttl;
1742 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
1743 s, *(int *)optval));
1744 break;
1745 case IP_TOS:
1746 *(int*)optval = sock->conn->pcb.ip->tos;
1747 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
1748 s, *(int *)optval));
1749 break;
1750 #if LWIP_IGMP
1751 case IP_MULTICAST_TTL:
1752 *(u8_t*)optval = sock->conn->pcb.ip->ttl;
1753 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
1754 s, *(int *)optval));
1755 break;
1756 case IP_MULTICAST_IF:
1757 inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip);
1758 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
1759 s, *(u32_t *)optval));
1760 break;
1761 case IP_MULTICAST_LOOP:
1762 if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
1763 *(u8_t*)optval = 1;
1764 } else {
1765 *(u8_t*)optval = 0;
1766 }
1767 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
1768 s, *(int *)optval));
1769 break;
1770 #endif /* LWIP_IGMP */
1771 default:
1772 LWIP_ASSERT("unhandled optname", 0);
1773 break;
1774 } /* switch (optname) */
1775 break;
1776
1777 #if LWIP_TCP
1778 /* Level: IPPROTO_TCP */
1779 case IPPROTO_TCP:
1780 switch (optname) {
1781 case TCP_NODELAY:
1782 *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
1783 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
1784 s, (*(int*)optval)?"on":"off") );
1785 break;
1786 case TCP_KEEPALIVE:
1787 *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
1788 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",
1789 s, *(int *)optval));
1790 break;
1791
1792 #if LWIP_TCP_KEEPALIVE
1793 case TCP_KEEPIDLE:
1794 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
1795 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",
1796 s, *(int *)optval));
1797 break;
1798 case TCP_KEEPINTVL:
1799 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
1800 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",
1801 s, *(int *)optval));
1802 break;
1803 case TCP_KEEPCNT:
1804 *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
1805 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",
1806 s, *(int *)optval));
1807 break;
1808 #endif /* LWIP_TCP_KEEPALIVE */
1809 default:
1810 LWIP_ASSERT("unhandled optname", 0);
1811 break;
1812 } /* switch (optname) */
1813 break;
1814 #endif /* LWIP_TCP */
1815 #if LWIP_UDP && LWIP_UDPLITE
1816 /* Level: IPPROTO_UDPLITE */
1817 case IPPROTO_UDPLITE:
1818 switch (optname) {
1819 case UDPLITE_SEND_CSCOV:
1820 *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
1821 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
1822 s, (*(int*)optval)) );
1823 break;
1824 case UDPLITE_RECV_CSCOV:
1825 *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
1826 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
1827 s, (*(int*)optval)) );
1828 break;
1829 default:
1830 LWIP_ASSERT("unhandled optname", 0);
1831 break;
1832 } /* switch (optname) */
1833 break;
1834 #endif /* LWIP_UDP */
1835 default:
1836 LWIP_ASSERT("unhandled level", 0);
1837 break;
1838 } /* switch (level) */
1839 sys_sem_signal(&sock->conn->op_completed);
1840 }
1841
1842 int
1843 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
1844 {
1845 struct lwip_sock *sock = get_socket(s);
1846 err_t err = ERR_OK;
1847 struct lwip_setgetsockopt_data data;
1848
1849 if (!sock) {
1850 return -1;
1851 }
1852
1853 if (NULL == optval) {
1854 sock_set_errno(sock, EFAULT);
1855 return -1;
1856 }
1857
1858 /* Do length and type checks for the various options first, to keep it readable. */
1859 switch (level) {
1860
1861 /* Level: SOL_SOCKET */
1862 case SOL_SOCKET:
1863 switch (optname) {
1864
1865 case SO_BROADCAST:
1866 /* UNIMPL case SO_DEBUG: */
1867 /* UNIMPL case SO_DONTROUTE: */
1868 case SO_KEEPALIVE:
1869 /* UNIMPL case case SO_CONTIMEO: */
1870 /* UNIMPL case case SO_SNDTIMEO: */
1871 #if LWIP_SO_RCVTIMEO
1872 case SO_RCVTIMEO:
1873 #endif /* LWIP_SO_RCVTIMEO */
1874 #if LWIP_SO_RCVBUF
1875 case SO_RCVBUF:
1876 #endif /* LWIP_SO_RCVBUF */
1877 /* UNIMPL case SO_OOBINLINE: */
1878 /* UNIMPL case SO_SNDBUF: */
1879 /* UNIMPL case SO_RCVLOWAT: */
1880 /* UNIMPL case SO_SNDLOWAT: */
1881 #if SO_REUSE
1882 case SO_REUSEADDR:
1883 case SO_REUSEPORT:
1884 #endif /* SO_REUSE */
1885 /* UNIMPL case SO_USELOOPBACK: */
1886 if (optlen < sizeof(int)) {
1887 err = EINVAL;
1888 }
1889 break;
1890 case SO_NO_CHECK:
1891 if (optlen < sizeof(int)) {
1892 err = EINVAL;
1893 }
1894 #if LWIP_UDP
1895 if ((sock->conn->type != NETCONN_UDP) ||
1896 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1897 /* this flag is only available for UDP, not for UDP lite */
1898 err = EAFNOSUPPORT;
1899 }
1900 #endif /* LWIP_UDP */
1901 break;
1902 default:
1903 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1904 s, optname));
1905 err = ENOPROTOOPT;
1906 } /* switch (optname) */
1907 break;
1908
1909 /* Level: IPPROTO_IP */
1910 case IPPROTO_IP:
1911 switch (optname) {
1912 /* UNIMPL case IP_HDRINCL: */
1913 /* UNIMPL case IP_RCVDSTADDR: */
1914 /* UNIMPL case IP_RCVIF: */
1915 case IP_TTL:
1916 case IP_TOS:
1917 if (optlen < sizeof(int)) {
1918 err = EINVAL;
1919 }
1920 break;
1921 #if LWIP_IGMP
1922 case IP_MULTICAST_TTL:
1923 if (optlen < sizeof(u8_t)) {
1924 err = EINVAL;
1925 }
1926 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1927 err = EAFNOSUPPORT;
1928 }
1929 break;
1930 case IP_MULTICAST_IF:
1931 if (optlen < sizeof(struct in_addr)) {
1932 err = EINVAL;
1933 }
1934 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1935 err = EAFNOSUPPORT;
1936 }
1937 break;
1938 case IP_MULTICAST_LOOP:
1939 if (optlen < sizeof(u8_t)) {
1940 err = EINVAL;
1941 }
1942 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1943 err = EAFNOSUPPORT;
1944 }
1945 break;
1946 case IP_ADD_MEMBERSHIP:
1947 case IP_DROP_MEMBERSHIP:
1948 if (optlen < sizeof(struct ip_mreq)) {
1949 err = EINVAL;
1950 }
1951 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1952 err = EAFNOSUPPORT;
1953 }
1954 break;
1955 #endif /* LWIP_IGMP */
1956 default:
1957 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1958 s, optname));
1959 err = ENOPROTOOPT;
1960 } /* switch (optname) */
1961 break;
1962
1963 #if LWIP_TCP
1964 /* Level: IPPROTO_TCP */
1965 case IPPROTO_TCP:
1966 if (optlen < sizeof(int)) {
1967 err = EINVAL;
1968 break;
1969 }
1970
1971 /* If this is no TCP socket, ignore any options. */
1972 if (sock->conn->type != NETCONN_TCP)
1973 return 0;
1974
1975 switch (optname) {
1976 case TCP_NODELAY:
1977 case TCP_KEEPALIVE:
1978 #if LWIP_TCP_KEEPALIVE
1979 case TCP_KEEPIDLE:
1980 case TCP_KEEPINTVL:
1981 case TCP_KEEPCNT:
1982 #endif /* LWIP_TCP_KEEPALIVE */
1983 break;
1984
1985 default:
1986 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
1987 s, optname));
1988 err = ENOPROTOOPT;
1989 } /* switch (optname) */
1990 break;
1991 #endif /* LWIP_TCP */
1992 #if LWIP_UDP && LWIP_UDPLITE
1993 /* Level: IPPROTO_UDPLITE */
1994 case IPPROTO_UDPLITE:
1995 if (optlen < sizeof(int)) {
1996 err = EINVAL;
1997 break;
1998 }
1999
2000 /* If this is no UDP lite socket, ignore any options. */
2001 if (sock->conn->type != NETCONN_UDPLITE)
2002 return 0;
2003
2004 switch (optname) {
2005 case UDPLITE_SEND_CSCOV:
2006 case UDPLITE_RECV_CSCOV:
2007 break;
2008
2009 default:
2010 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
2011 s, optname));
2012 err = ENOPROTOOPT;
2013 } /* switch (optname) */
2014 break;
2015 #endif /* LWIP_UDP && LWIP_UDPLITE */
2016 /* UNDEFINED LEVEL */
2017 default:
2018 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2019 s, level, optname));
2020 err = ENOPROTOOPT;
2021 } /* switch (level) */
2022
2023
2024 if (err != ERR_OK) {
2025 sock_set_errno(sock, err);
2026 return -1;
2027 }
2028
2029
2030 /* Now do the actual option processing */
2031 data.sock = sock;
2032 #ifdef LWIP_DEBUG
2033 data.s = s;
2034 #endif /* LWIP_DEBUG */
2035 data.level = level;
2036 data.optname = optname;
2037 data.optval = (void*)optval;
2038 data.optlen = &optlen;
2039 data.err = err;
2040 tcpip_callback(lwip_setsockopt_internal, &data);
2041 sys_arch_sem_wait(&sock->conn->op_completed, 0);
2042 /* maybe lwip_setsockopt_internal has changed err */
2043 err = data.err;
2044
2045 sock_set_errno(sock, err);
2046 return err ? -1 : 0;
2047 }
2048
2049 static void
2050 lwip_setsockopt_internal(void *arg)
2051 {
2052 struct lwip_sock *sock;
2053 #ifdef LWIP_DEBUG
2054 int s;
2055 #endif /* LWIP_DEBUG */
2056 int level, optname;
2057 const void *optval;
2058 struct lwip_setgetsockopt_data *data;
2059
2060 LWIP_ASSERT("arg != NULL", arg != NULL);
2061
2062 data = (struct lwip_setgetsockopt_data*)arg;
2063 sock = data->sock;
2064 #ifdef LWIP_DEBUG
2065 s = data->s;
2066 #endif /* LWIP_DEBUG */
2067 level = data->level;
2068 optname = data->optname;
2069 optval = data->optval;
2070
2071 switch (level) {
2072
2073 /* Level: SOL_SOCKET */
2074 case SOL_SOCKET:
2075 switch (optname) {
2076
2077 /* The option flags */
2078 case SO_BROADCAST:
2079 /* UNIMPL case SO_DEBUG: */
2080 /* UNIMPL case SO_DONTROUTE: */
2081 case SO_KEEPALIVE:
2082 /* UNIMPL case SO_OOBINCLUDE: */
2083 #if SO_REUSE
2084 case SO_REUSEADDR:
2085 case SO_REUSEPORT:
2086 #endif /* SO_REUSE */
2087 /* UNIMPL case SO_USELOOPBACK: */
2088 if (*(int*)optval) {
2089 sock->conn->pcb.ip->so_options |= optname;
2090 } else {
2091 sock->conn->pcb.ip->so_options &= ~optname;
2092 }
2093 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
2094 s, optname, (*(int*)optval?"on":"off")));
2095 break;
2096 #if LWIP_SO_RCVTIMEO
2097 case SO_RCVTIMEO:
2098 netconn_set_recvtimeout(sock->conn, *(int*)optval);
2099 break;
2100 #endif /* LWIP_SO_RCVTIMEO */
2101 #if LWIP_SO_RCVBUF
2102 case SO_RCVBUF:
2103 netconn_set_recvbufsize(sock->conn, *(int*)optval);
2104 break;
2105 #endif /* LWIP_SO_RCVBUF */
2106 #if LWIP_UDP
2107 case SO_NO_CHECK:
2108 if (*(int*)optval) {
2109 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
2110 } else {
2111 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
2112 }
2113 break;
2114 #endif /* LWIP_UDP */
2115 default:
2116 LWIP_ASSERT("unhandled optname", 0);
2117 break;
2118 } /* switch (optname) */
2119 break;
2120
2121 /* Level: IPPROTO_IP */
2122 case IPPROTO_IP:
2123 switch (optname) {
2124 case IP_TTL:
2125 sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
2126 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
2127 s, sock->conn->pcb.ip->ttl));
2128 break;
2129 case IP_TOS:
2130 sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
2131 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
2132 s, sock->conn->pcb.ip->tos));
2133 break;
2134 #if LWIP_IGMP
2135 case IP_MULTICAST_TTL:
2136 sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);
2137 break;
2138 case IP_MULTICAST_IF:
2139 inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval);
2140 break;
2141 case IP_MULTICAST_LOOP:
2142 if (*(u8_t*)optval) {
2143 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
2144 } else {
2145 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
2146 }
2147 break;
2148 case IP_ADD_MEMBERSHIP:
2149 case IP_DROP_MEMBERSHIP:
2150 {
2151 /* If this is a TCP or a RAW socket, ignore these options. */
2152 struct ip_mreq *imr = (struct ip_mreq *)optval;
2153 ip_addr_t if_addr;
2154 ip_addr_t multi_addr;
2155 inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
2156 inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
2157 if(optname == IP_ADD_MEMBERSHIP){
2158 data->err = igmp_joingroup(&if_addr, &multi_addr);
2159 } else {
2160 data->err = igmp_leavegroup(&if_addr, &multi_addr);
2161 }
2162 if(data->err != ERR_OK) {
2163 data->err = EADDRNOTAVAIL;
2164 }
2165 }
2166 break;
2167 #endif /* LWIP_IGMP */
2168 default:
2169 LWIP_ASSERT("unhandled optname", 0);
2170 break;
2171 } /* switch (optname) */
2172 break;
2173
2174 #if LWIP_TCP
2175 /* Level: IPPROTO_TCP */
2176 case IPPROTO_TCP:
2177 switch (optname) {
2178 case TCP_NODELAY:
2179 if (*(int*)optval) {
2180 tcp_nagle_disable(sock->conn->pcb.tcp);
2181 } else {
2182 tcp_nagle_enable(sock->conn->pcb.tcp);
2183 }
2184 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
2185 s, (*(int *)optval)?"on":"off") );
2186 break;
2187 case TCP_KEEPALIVE:
2188 sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
2189 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
2190 s, sock->conn->pcb.tcp->keep_idle));
2191 break;
2192
2193 #if LWIP_TCP_KEEPALIVE
2194 case TCP_KEEPIDLE:
2195 sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
2196 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
2197 s, sock->conn->pcb.tcp->keep_idle));
2198 break;
2199 case TCP_KEEPINTVL:
2200 sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
2201 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
2202 s, sock->conn->pcb.tcp->keep_intvl));
2203 break;
2204 case TCP_KEEPCNT:
2205 sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
2206 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
2207 s, sock->conn->pcb.tcp->keep_cnt));
2208 break;
2209 #endif /* LWIP_TCP_KEEPALIVE */
2210 default:
2211 LWIP_ASSERT("unhandled optname", 0);
2212 break;
2213 } /* switch (optname) */
2214 break;
2215 #endif /* LWIP_TCP*/
2216 #if LWIP_UDP && LWIP_UDPLITE
2217 /* Level: IPPROTO_UDPLITE */
2218 case IPPROTO_UDPLITE:
2219 switch (optname) {
2220 case UDPLITE_SEND_CSCOV:
2221 if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
2222 /* don't allow illegal values! */
2223 sock->conn->pcb.udp->chksum_len_tx = 8;
2224 } else {
2225 sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;
2226 }
2227 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
2228 s, (*(int*)optval)) );
2229 break;
2230 case UDPLITE_RECV_CSCOV:
2231 if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
2232 /* don't allow illegal values! */
2233 sock->conn->pcb.udp->chksum_len_rx = 8;
2234 } else {
2235 sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;
2236 }
2237 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
2238 s, (*(int*)optval)) );
2239 break;
2240 default:
2241 LWIP_ASSERT("unhandled optname", 0);
2242 break;
2243 } /* switch (optname) */
2244 break;
2245 #endif /* LWIP_UDP */
2246 default:
2247 LWIP_ASSERT("unhandled level", 0);
2248 break;
2249 } /* switch (level) */
2250 sys_sem_signal(&sock->conn->op_completed);
2251 }
2252
2253 int
2254 lwip_ioctl(int s, long cmd, void *argp)
2255 {
2256 struct lwip_sock *sock = get_socket(s);
2257 u8_t val;
2258 #if LWIP_SO_RCVBUF
2259 u16_t buflen = 0;
2260 s16_t recv_avail;
2261 #endif /* LWIP_SO_RCVBUF */
2262
2263 if (!sock) {
2264 return -1;
2265 }
2266
2267 switch (cmd) {
2268 #if LWIP_SO_RCVBUF
2269 case FIONREAD:
2270 if (!argp) {
2271 sock_set_errno(sock, EINVAL);
2272 return -1;
2273 }
2274
2275 SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
2276 if (recv_avail < 0) {
2277 recv_avail = 0;
2278 }
2279 *((u16_t*)argp) = (u16_t)recv_avail;
2280
2281 /* Check if there is data left from the last recv operation. /maq 041215 */
2282 if (sock->lastdata) {
2283 struct pbuf *p = (struct pbuf *)sock->lastdata;
2284 if (netconn_type(sock->conn) != NETCONN_TCP) {
2285 p = ((struct netbuf *)p)->p;
2286 }
2287 buflen = p->tot_len;
2288 buflen -= sock->lastoffset;
2289
2290 *((u16_t*)argp) += buflen;
2291 }
2292
2293 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
2294 sock_set_errno(sock, 0);
2295 return 0;
2296 #endif /* LWIP_SO_RCVBUF */
2297
2298 case FIONBIO:
2299 val = 0;
2300 if (argp && *(u32_t*)argp) {
2301 val = 1;
2302 }
2303 netconn_set_nonblocking(sock->conn, val);
2304 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
2305 sock_set_errno(sock, 0);
2306 return 0;
2307
2308 default:
2309 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
2310 sock_set_errno(sock, ENOSYS); /* not yet implemented */
2311 return -1;
2312 } /* switch (cmd) */
2313 }
2314
2315 /** A minimal implementation of fcntl.
2316 * Currently only the commands F_GETFL and F_SETFL are implemented.
2317 * Only the flag O_NONBLOCK is implemented.
2318 */
2319 int
2320 lwip_fcntl(int s, int cmd, int val)
2321 {
2322 struct lwip_sock *sock = get_socket(s);
2323 int ret = -1;
2324
2325 if (!sock || !sock->conn) {
2326 return -1;
2327 }
2328
2329 switch (cmd) {
2330 case F_GETFL:
2331 ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
2332 break;
2333 case F_SETFL:
2334 if ((val & ~O_NONBLOCK) == 0) {
2335 /* only O_NONBLOCK, all other bits are zero */
2336 netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
2337 ret = 0;
2338 }
2339 break;
2340 default:
2341 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
2342 break;
2343 }
2344 return ret;
2345 }
2346
2347 #endif /* LWIP_SOCKET */
2348