source: UsbWattMeter/trunk/lwip-1.4.1/src/api/sockets.c@ 164

Last change on this file since 164 was 164, checked in by coas-nagasima, 6 years ago

TOPPERS/ECNLサンプルアプリ「USB充電器電力計」を追加

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