]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/blob - src/api/sockets.c
Merged from DEVEL into main tree.
[pes-rpp/rpp-lwip.git] / src / api / sockets.c
1 /*
2  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25  * OF SUCH DAMAGE.
26  *
27  * This file is part of the lwIP TCP/IP stack.
28  *
29  * Author: Adam Dunkels <adam@sics.se>
30  *
31  * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
32  *
33  */
34
35 #include "lwip/opt.h"
36 #include "lwip/api.h"
37 #include "lwip/arch.h"
38 #include "lwip/sys.h"
39
40 #include "lwip/sockets.h"
41
42 #define NUM_SOCKETS MEMP_NUM_NETCONN
43
44 struct lwip_socket {
45   struct netconn *conn;
46   struct netbuf *lastdata;
47   u16_t lastoffset;
48   u16_t rcvevent;
49   u16_t sendevent;
50   u16_t  flags;
51   int err;
52 };
53
54 struct lwip_select_cb
55 {
56     struct lwip_select_cb *next;
57     fd_set *readset;
58     fd_set *writeset;
59     fd_set *exceptset;
60     int sem_signalled;
61     sys_sem_t sem;
62 };
63
64 static struct lwip_socket sockets[NUM_SOCKETS];
65 static struct lwip_select_cb *select_cb_list = 0;
66
67 static sys_sem_t socksem = 0;
68 static sys_sem_t selectsem = 0;
69
70 static void
71 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
72
73 static int err_to_errno_table[11] = {
74     0,      /* ERR_OK    0      No error, everything OK. */
75     ENOMEM,    /* ERR_MEM  -1      Out of memory error.     */
76     ENOBUFS,    /* ERR_BUF  -2      Buffer error.            */
77     ECONNABORTED,  /* ERR_ABRT -3      Connection aborted.      */
78     ECONNRESET,    /* ERR_RST  -4      Connection reset.        */
79     ESHUTDOWN,    /* ERR_CLSD -5      Connection closed.       */
80     ENOTCONN,    /* ERR_CONN -6      Not connected.           */
81     EINVAL,    /* ERR_VAL  -7      Illegal value.           */
82     EIO,    /* ERR_ARG  -8      Illegal argument.        */
83     EHOSTUNREACH,  /* ERR_RTE  -9      Routing problem.         */
84     EADDRINUSE    /* ERR_USE  -10     Address in use.          */
85 };
86
87 #define err_to_errno(err) \
88   ((err) < (sizeof(err_to_errno_table)/sizeof(int))) ? \
89     err_to_errno_table[-(err)] : EIO
90
91 #ifdef ERRNO
92 #define set_errno(err) errno = (err)
93 #else
94 #define set_errno(err)
95 #endif
96
97 #define sock_set_errno(sk, e) do { \
98       sk->err = (e); \
99       set_errno(sk->err); \
100 } while (0)
101
102
103 static struct lwip_socket *
104 get_socket(int s)
105 {
106   struct lwip_socket *sock;
107
108   if ((s < 0) || (s > NUM_SOCKETS)) {
109     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
110     set_errno(EBADF);
111     return NULL;
112   }
113
114   sock = &sockets[s];
115
116   if (!sock->conn) {
117     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
118     set_errno(EBADF);
119     return NULL;
120   }
121
122   return sock;
123 }
124
125 static int
126 alloc_socket(struct netconn *newconn)
127 {
128   int i;
129
130   if (!socksem)
131       socksem = sys_sem_new(1);
132
133   /* Protect socket array */
134   sys_sem_wait(socksem);
135
136   /* allocate a new socket identifier */
137   for(i = 0; i < NUM_SOCKETS; ++i) {
138     if (!sockets[i].conn) {
139       sockets[i].conn = newconn;
140       sockets[i].lastdata = NULL;
141       sockets[i].lastoffset = 0;
142       sockets[i].rcvevent = 0;
143       sockets[i].sendevent = 1; /* TCP send buf is empty */
144       sockets[i].flags = 0;
145       sockets[i].err = 0;
146       sys_sem_signal(socksem);
147       return i;
148     }
149   }
150   sys_sem_signal(socksem);
151   return -1;
152 }
153
154 int
155 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
156 {
157   struct lwip_socket *sock;
158   struct netconn *newconn;
159   struct ip_addr naddr;
160   u16_t port;
161   int newsock;
162   struct sockaddr_in sin;
163
164   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
165   sock = get_socket(s);
166   if (!sock) {
167     set_errno(EBADF);
168     return -1;
169   }
170
171   newconn = netconn_accept(sock->conn);
172
173   /* get the IP address and port of the remote host */
174   netconn_peer(newconn, &naddr, &port);
175
176   memset(&sin, 0, sizeof(sin));
177   sin.sin_len = sizeof(sin);
178   sin.sin_family = AF_INET;
179   sin.sin_port = htons(port);
180   sin.sin_addr.s_addr = naddr.addr;
181
182   if (*addrlen > sizeof(sin))
183       *addrlen = sizeof(sin);
184
185   memcpy(addr, &sin, *addrlen);
186
187   newsock = alloc_socket(newconn);
188   if (newsock == -1) {
189     netconn_delete(newconn);
190   sock_set_errno(sock, ENOBUFS);
191   return -1;
192   }
193   newconn->callback = event_callback;
194   sock = get_socket(newsock);
195
196   sys_sem_wait(socksem);
197   sock->rcvevent += -1 - newconn->socket;
198   newconn->socket = newsock;
199   sys_sem_signal(socksem);
200
201   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
202   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
203   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", port));
204
205   sock_set_errno(sock, 0);
206   return newsock;
207 }
208
209 int
210 lwip_bind(int s, struct sockaddr *name, socklen_t namelen)
211 {
212   struct lwip_socket *sock;
213   struct ip_addr local_addr;
214   u16_t local_port;
215   err_t err;
216
217   sock = get_socket(s);
218   if (!sock) {
219     set_errno(EBADF);
220     return -1;
221   }
222
223   local_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
224   local_port = ((struct sockaddr_in *)name)->sin_port;
225
226   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
227   ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
228   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(local_port)));
229
230   err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
231
232   if (err != ERR_OK) {
233     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
234     sock_set_errno(sock, err_to_errno(err));
235     return -1;
236   }
237
238   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
239   sock_set_errno(sock, 0);
240   return 0;
241 }
242
243 int
244 lwip_close(int s)
245 {
246   struct lwip_socket *sock;
247
248   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
249   if (!socksem)
250       socksem = sys_sem_new(1);
251
252   /* We cannot allow multiple closes of the same socket. */
253   sys_sem_wait(socksem);
254
255   sock = get_socket(s);
256   if (!sock) {
257       sys_sem_signal(socksem);
258       set_errno(EBADF);
259       return -1;
260   }
261
262   netconn_delete(sock->conn);
263   if (sock->lastdata) {
264     netbuf_delete(sock->lastdata);
265   }
266   sock->lastdata = NULL;
267   sock->lastoffset = 0;
268   sock->conn = NULL;
269   sys_sem_signal(socksem);
270   sock_set_errno(sock, 0);
271   return 0;
272 }
273
274 int
275 lwip_connect(int s, struct sockaddr *name, socklen_t namelen)
276 {
277   struct lwip_socket *sock;
278   err_t err;
279
280   sock = get_socket(s);
281   if (!sock) {
282     set_errno(EBADF);
283     return -1;
284   }
285
286   if (((struct sockaddr_in *)name)->sin_family == AF_UNSPEC) {
287     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
288     err = netconn_disconnect(sock->conn);
289   } else {
290     struct ip_addr remote_addr;
291     u16_t remote_port;
292
293     remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
294     remote_port = ((struct sockaddr_in *)name)->sin_port;
295
296     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
297     ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
298     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port)));
299
300     err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
301    }
302
303   if (err != ERR_OK) {
304     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
305     sock_set_errno(sock, err_to_errno(err));
306     return -1;
307   }
308
309   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
310   sock_set_errno(sock, 0);
311   return 0;
312 }
313
314 int
315 lwip_listen(int s, int backlog)
316 {
317   struct lwip_socket *sock;
318   err_t err;
319
320   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
321   sock = get_socket(s);
322   if (!sock) {
323     set_errno(EBADF);
324     return -1;
325   }
326
327   err = netconn_listen(sock->conn);
328
329   if (err != ERR_OK) {
330     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
331     sock_set_errno(sock, err_to_errno(err));
332     return -1;
333   }
334
335   sock_set_errno(sock, 0);
336   return 0;
337 }
338
339 int
340 lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
341         struct sockaddr *from, socklen_t *fromlen)
342 {
343   struct lwip_socket *sock;
344   struct netbuf *buf;
345   u16_t buflen, copylen;
346   struct ip_addr *addr;
347   u16_t port;
348
349
350   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags));
351   sock = get_socket(s);
352   if (!sock) {
353     set_errno(EBADF);
354     return -1;
355   }
356
357   /* Check if there is data left from the last recv operation. */
358   if (sock->lastdata) {
359     buf = sock->lastdata;
360   } else {
361     /* If this is non-blocking call, then check first */
362     if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK))
363   && !sock->rcvevent)
364     {
365       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
366       sock_set_errno(sock, EWOULDBLOCK);
367       return -1;
368     }
369
370     /* No data was left from the previous operation, so we try to get
371        some from the network. */
372     buf = netconn_recv(sock->conn);
373
374     if (!buf) {
375       /* We should really do some error checking here. */
376       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s));
377       sock_set_errno(sock, 0);
378       return 0;
379     }
380   }
381
382   buflen = netbuf_len(buf);
383
384   buflen -= sock->lastoffset;
385
386   if (len > buflen) {
387     copylen = buflen;
388   } else {
389     copylen = len;
390   }
391
392   /* copy the contents of the received buffer into
393      the supplied memory pointer mem */
394   netbuf_copy_partial(buf, mem, copylen, sock->lastoffset);
395
396   /* Check to see from where the data was. */
397   if (from && fromlen) {
398     struct sockaddr_in sin;
399
400     addr = netbuf_fromaddr(buf);
401     port = netbuf_fromport(buf);
402
403     memset(&sin, 0, sizeof(sin));
404     sin.sin_len = sizeof(sin);
405     sin.sin_family = AF_INET;
406     sin.sin_port = htons(port);
407     sin.sin_addr.s_addr = addr->addr;
408
409     if (*fromlen > sizeof(sin))
410       *fromlen = sizeof(sin);
411
412     memcpy(from, &sin, *fromlen);
413
414     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
415     ip_addr_debug_print(SOCKETS_DEBUG, addr);
416     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));
417   } else {
418 #if SOCKETS_DEBUG > 0
419     addr = netbuf_fromaddr(buf);
420     port = netbuf_fromport(buf);
421
422     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
423     ip_addr_debug_print(SOCKETS_DEBUG, addr);
424     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));
425 #endif
426
427   }
428
429   /* If this is a TCP socket, check if there is data left in the
430      buffer. If so, it should be saved in the sock structure for next
431      time around. */
432   if (netconn_type(sock->conn) == NETCONN_TCP && buflen - copylen > 0) {
433     sock->lastdata = buf;
434     sock->lastoffset += copylen;
435   } else {
436     sock->lastdata = NULL;
437     sock->lastoffset = 0;
438     netbuf_delete(buf);
439   }
440
441
442   sock_set_errno(sock, 0);
443   return copylen;
444 }
445
446 int
447 lwip_read(int s, void *mem, int len)
448 {
449   return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
450 }
451
452 int
453 lwip_recv(int s, void *mem, int len, unsigned int flags)
454 {
455   return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
456 }
457
458 int
459 lwip_send(int s, void *data, int size, unsigned int flags)
460 {
461   struct lwip_socket *sock;
462   struct netbuf *buf;
463   err_t err;
464
465   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%d, flags=0x%x)\n", s, data, size, flags));
466
467   sock = get_socket(s);
468   if (!sock) {
469     set_errno(EBADF);
470     return -1;
471   }
472
473   switch (netconn_type(sock->conn)) {
474   case NETCONN_RAW:
475   case NETCONN_UDP:
476   case NETCONN_UDPLITE:
477   case NETCONN_UDPNOCHKSUM:
478     /* create a buffer */
479     buf = netbuf_new();
480
481     if (!buf) {
482       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) ENOBUFS\n", s));
483       sock_set_errno(sock, ENOBUFS);
484       return -1;
485     }
486
487     /* make the buffer point to the data that should
488        be sent */
489     netbuf_ref(buf, data, size);
490
491     /* send the data */
492     err = netconn_send(sock->conn, buf);
493
494     /* deallocated the buffer */
495     netbuf_delete(buf);
496     break;
497   case NETCONN_TCP:
498     err = netconn_write(sock->conn, data, size, NETCONN_COPY);
499     break;
500   default:
501     err = ERR_ARG;
502     break;
503   }
504   if (err != ERR_OK) {
505     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d\n", s, err));
506     sock_set_errno(sock, err_to_errno(err));
507     return -1;
508   }
509
510   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) ok size=%d\n", s, size));
511   sock_set_errno(sock, 0);
512   return size;
513 }
514
515 int
516 lwip_sendto(int s, void *data, int size, unsigned int flags,
517        struct sockaddr *to, socklen_t tolen)
518 {
519   struct lwip_socket *sock;
520   struct ip_addr remote_addr, addr;
521   u16_t remote_port, port;
522   int ret,connected;
523
524   sock = get_socket(s);
525   if (!sock) {
526     set_errno(EBADF);
527     return -1;
528   }
529
530   /* get the peer if currently connected */
531   connected = (netconn_peer(sock->conn, &addr, &port) == ERR_OK);
532
533   remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;
534   remote_port = ((struct sockaddr_in *)to)->sin_port;
535
536   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=", s, data, size, flags));
537   ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
538   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", ntohs(remote_port)));
539
540   netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
541
542   ret = lwip_send(s, data, size, flags);
543
544   /* reset the remote address and port number
545      of the connection */
546   if (connected)
547     netconn_connect(sock->conn, &addr, port);
548   else
549   netconn_disconnect(sock->conn);
550   return ret;
551 }
552
553 int
554 lwip_socket(int domain, int type, int protocol)
555 {
556   struct netconn *conn;
557   int i;
558
559   /* create a netconn */
560   switch (type) {
561   case SOCK_RAW:
562     conn = netconn_new_with_proto_and_callback(NETCONN_RAW, protocol, event_callback);
563     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
564     break;
565   case SOCK_DGRAM:
566     conn = netconn_new_with_callback(NETCONN_UDP, event_callback);
567     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
568     break;
569   case SOCK_STREAM:
570     conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
571     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
572     break;
573   default:
574     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", domain, type, protocol));
575     set_errno(EINVAL);
576     return -1;
577   }
578
579   if (!conn) {
580     LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
581     set_errno(ENOBUFS);
582     return -1;
583   }
584
585   i = alloc_socket(conn);
586
587   if (i == -1) {
588     netconn_delete(conn);
589   set_errno(ENOBUFS);
590   return -1;
591   }
592   conn->socket = i;
593   LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
594   set_errno(0);
595   return i;
596 }
597
598 int
599 lwip_write(int s, void *data, int size)
600 {
601    return lwip_send(s, data, size, 0);
602 }
603
604
605 static int
606 lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset)
607 {
608     int i, nready = 0;
609     fd_set lreadset, lwriteset, lexceptset;
610     struct lwip_socket *p_sock;
611
612     FD_ZERO(&lreadset);
613     FD_ZERO(&lwriteset);
614     FD_ZERO(&lexceptset);
615
616     /* Go through each socket in each list to count number of sockets which
617        currently match */
618     for(i = 0; i < maxfdp1; i++)
619     {
620         if (FD_ISSET(i, readset))
621         {
622             /* See if netconn of this socket is ready for read */
623             p_sock = get_socket(i);
624             if (p_sock && (p_sock->lastdata || p_sock->rcvevent))
625             {
626                 FD_SET(i, &lreadset);
627                 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
628                 nready++;
629             }
630         }
631         if (FD_ISSET(i, writeset))
632         {
633             /* See if netconn of this socket is ready for write */
634             p_sock = get_socket(i);
635             if (p_sock && p_sock->sendevent)
636             {
637                 FD_SET(i, &lwriteset);
638                 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
639                 nready++;
640             }
641         }
642     }
643     *readset = lreadset;
644     *writeset = lwriteset;
645     FD_ZERO(exceptset);
646
647     return nready;
648 }
649
650
651
652 int
653 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
654                struct timeval *timeout)
655 {
656     int i;
657     int nready;
658     fd_set lreadset, lwriteset, lexceptset;
659     u32_t msectimeout;
660     struct lwip_select_cb select_cb;
661     struct lwip_select_cb *p_selcb;
662
663     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n", maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, timeout ? timeout->tv_sec : -1L, timeout ? timeout->tv_usec : -1L));
664
665     select_cb.next = 0;
666     select_cb.readset = readset;
667     select_cb.writeset = writeset;
668     select_cb.exceptset = exceptset;
669     select_cb.sem_signalled = 0;
670
671     /* Protect ourselves searching through the list */
672     if (!selectsem)
673         selectsem = sys_sem_new(1);
674     sys_sem_wait(selectsem);
675
676     if (readset)
677         lreadset = *readset;
678     else
679         FD_ZERO(&lreadset);
680     if (writeset)
681         lwriteset = *writeset;
682     else
683         FD_ZERO(&lwriteset);
684     if (exceptset)
685         lexceptset = *exceptset;
686     else
687         FD_ZERO(&lexceptset);
688
689     /* Go through each socket in each list to count number of sockets which
690        currently match */
691     nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
692
693     /* If we don't have any current events, then suspend if we are supposed to */
694     if (!nready)
695     {
696         if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
697         {
698             sys_sem_signal(selectsem);
699             if (readset)
700                 FD_ZERO(readset);
701             if (writeset)
702                 FD_ZERO(writeset);
703             if (exceptset)
704                 FD_ZERO(exceptset);
705
706             LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
707             set_errno(0);
708
709             return 0;
710         }
711
712         /* add our semaphore to list */
713         /* We don't actually need any dynamic memory. Our entry on the
714          * list is only valid while we are in this function, so it's ok
715          * to use local variables */
716
717         select_cb.sem = sys_sem_new(0);
718         /* Note that we are still protected */
719         /* Put this select_cb on top of list */
720         select_cb.next = select_cb_list;
721         select_cb_list = &select_cb;
722
723         /* Now we can safely unprotect */
724         sys_sem_signal(selectsem);
725
726         /* Now just wait to be woken */
727         if (timeout == 0)
728             /* Wait forever */
729             msectimeout = 0;
730         else
731             msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
732
733         i = sys_sem_wait_timeout(select_cb.sem, msectimeout);
734
735         /* Take us off the list */
736         sys_sem_wait(selectsem);
737         if (select_cb_list == &select_cb)
738             select_cb_list = select_cb.next;
739         else
740             for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next)
741                 if (p_selcb->next == &select_cb)
742                 {
743                     p_selcb->next = select_cb.next;
744                     break;
745                 }
746
747         sys_sem_signal(selectsem);
748
749         sys_sem_free(select_cb.sem);
750         if (i == 0)             /* Timeout */
751         {
752             if (readset)
753                 FD_ZERO(readset);
754             if (writeset)
755                 FD_ZERO(writeset);
756             if (exceptset)
757                 FD_ZERO(exceptset);
758
759             LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
760             set_errno(0);
761
762             return 0;
763         }
764
765         if (readset)
766             lreadset = *readset;
767         else
768             FD_ZERO(&lreadset);
769         if (writeset)
770             lwriteset = *writeset;
771         else
772             FD_ZERO(&lwriteset);
773         if (exceptset)
774             lexceptset = *exceptset;
775         else
776             FD_ZERO(&lexceptset);
777
778         /* See what's set */
779         nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
780     }
781     else
782         sys_sem_signal(selectsem);
783
784     if (readset)
785         *readset = lreadset;
786     if (writeset)
787         *writeset = lwriteset;
788     if (exceptset)
789         *exceptset = lexceptset;
790
791     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
792     set_errno(0);
793
794     return nready;
795 }
796
797
798 static void
799 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
800 {
801     int s;
802     struct lwip_socket *sock;
803     struct lwip_select_cb *scb;
804
805     /* Get socket */
806     if (conn)
807     {
808         s = conn->socket;
809         if (s < 0)
810         {
811             /* Data comes in right away after an accept, even though
812              * the server task might not have created a new socket yet.
813              * Just count down (or up) if that's the case and we
814              * will use the data later. Note that only receive events
815              * can happen before the new socket is set up. */
816             if (evt == NETCONN_EVT_RCVPLUS)
817                 conn->socket--;
818             return;
819         }
820
821         sock = get_socket(s);
822         if (!sock)
823             return;
824     }
825     else
826         return;
827
828     if (!selectsem)
829         selectsem = sys_sem_new(1);
830
831     sys_sem_wait(selectsem);
832     /* Set event as required */
833     switch (evt)
834     {
835       case NETCONN_EVT_RCVPLUS:
836         sock->rcvevent++;
837         break;
838       case NETCONN_EVT_RCVMINUS:
839         sock->rcvevent--;
840         break;
841       case NETCONN_EVT_SENDPLUS:
842         sock->sendevent = 1;
843         break;
844       case NETCONN_EVT_SENDMINUS:
845         sock->sendevent = 0;
846         break;
847     }
848     sys_sem_signal(selectsem);
849
850     /* Now decide if anyone is waiting for this socket */
851     /* NOTE: This code is written this way to protect the select link list
852        but to avoid a deadlock situation by releasing socksem before
853        signalling for the select. This means we need to go through the list
854        multiple times ONLY IF a select was actually waiting. We go through
855        the list the number of waiting select calls + 1. This list is
856        expected to be small. */
857     while (1)
858     {
859         sys_sem_wait(selectsem);
860         for (scb = select_cb_list; scb; scb = scb->next)
861         {
862             if (scb->sem_signalled == 0)
863             {
864                 /* Test this select call for our socket */
865                 if (scb->readset && FD_ISSET(s, scb->readset))
866                     if (sock->rcvevent)
867                         break;
868                 if (scb->writeset && FD_ISSET(s, scb->writeset))
869                     if (sock->sendevent)
870                         break;
871             }
872         }
873         if (scb)
874         {
875             scb->sem_signalled = 1;
876             sys_sem_signal(selectsem);
877             sys_sem_signal(scb->sem);
878         } else {
879             sys_sem_signal(selectsem);
880             break;
881         }
882     }
883
884 }
885
886
887
888
889 int lwip_shutdown(int s, int how)
890 {
891   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
892   return lwip_close(s); /* XXX temporary hack until proper implementation */
893 }
894
895 int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen)
896 {
897   struct lwip_socket *sock;
898   struct sockaddr_in sin;
899   struct ip_addr naddr;
900
901   sock = get_socket(s);
902   if (!sock) {
903     set_errno(EBADF);
904     return -1;
905   }
906
907   memset(&sin, 0, sizeof(sin));
908   sin.sin_len = sizeof(sin);
909   sin.sin_family = AF_INET;
910
911   /* get the IP address and port of the remote host */
912   netconn_peer(sock->conn, &naddr, &sin.sin_port);
913
914   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getpeername(%d, addr=", s));
915   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
916   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));
917
918   sin.sin_port = htons(sin.sin_port);
919   sin.sin_addr.s_addr = naddr.addr;
920
921   if (*namelen > sizeof(sin))
922       *namelen = sizeof(sin);
923
924   memcpy(name, &sin, *namelen);
925   sock_set_errno(sock, 0);
926   return 0;
927 }
928
929 int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen)
930 {
931   struct lwip_socket *sock;
932   struct sockaddr_in sin;
933   struct ip_addr *naddr;
934
935   sock = get_socket(s);
936   if (!sock) {
937     set_errno(EBADF);
938     return -1;
939   }
940
941   memset(&sin, 0, sizeof(sin));
942   sin.sin_len = sizeof(sin);
943   sin.sin_family = AF_INET;
944
945   /* get the IP address and port of the remote host */
946   netconn_addr(sock->conn, &naddr, &sin.sin_port);
947
948   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockname(%d, addr=", s));
949   ip_addr_debug_print(SOCKETS_DEBUG, naddr);
950   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));
951
952   sin.sin_port = htons(sin.sin_port);
953   sin.sin_addr.s_addr = naddr->addr;
954
955   if (*namelen > sizeof(sin))
956       *namelen = sizeof(sin);
957
958   memcpy(name, &sin, *namelen);
959   sock_set_errno(sock, 0);
960   return 0;
961 }
962
963 int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen)
964 {
965   int err = 0;
966   struct lwip_socket *sock = get_socket(s);
967
968   if(!sock) {
969         set_errno(EBADF);
970     return -1;
971   }
972
973   if( NULL == optval || NULL == optlen ) {
974     sock_set_errno( sock, EFAULT );
975     return -1;
976   }
977
978   /* Do length and type checks for the various options first, to keep it readable. */
979   switch( level ) {
980    
981 /* Level: SOL_SOCKET */
982   case SOL_SOCKET:
983       switch(optname) {
984          
985       case SO_ACCEPTCONN:
986       case SO_BROADCAST:
987       /* UNIMPL case SO_DEBUG: */
988       /* UNIMPL case SO_DONTROUTE: */
989       case SO_ERROR:
990       case SO_KEEPALIVE:
991       /* UNIMPL case SO_OOBINLINE: */
992       /* UNIMPL case SO_RCVBUF: */
993       /* UNIMPL case SO_SNDBUF: */
994       /* UNIMPL case SO_RCVLOWAT: */
995       /* UNIMPL case SO_SNDLOWAT: */
996 #ifdef SO_REUSE
997       case SO_REUSEADDR:
998       case SO_REUSEPORT:
999 #endif /* SO_REUSE */
1000       case SO_TYPE:
1001       /* UNIMPL case SO_USELOOPBACK: */
1002         if( *optlen < sizeof(int) ) {
1003           err = EINVAL;
1004         }
1005           break;
1006
1007       default:
1008         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname));
1009         err = ENOPROTOOPT;
1010       }  /* switch */
1011       break;
1012                      
1013 /* Level: IPPROTO_IP */
1014   case IPPROTO_IP:
1015       switch(optname) {
1016       /* UNIMPL case IP_HDRINCL: */
1017       /* UNIMPL case IP_RCVDSTADDR: */
1018       /* UNIMPL case IP_RCVIF: */
1019       case IP_TTL:
1020       case IP_TOS:
1021         if( *optlen < sizeof(int) ) {
1022           err = EINVAL;
1023         }
1024         break;
1025
1026       default:
1027         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname));
1028         err = ENOPROTOOPT;
1029       }  /* switch */
1030       break;
1031          
1032 /* Level: IPPROTO_TCP */
1033   case IPPROTO_TCP:
1034       if( *optlen < sizeof(int) ) {
1035         err = EINVAL;
1036         break;
1037     }
1038       
1039       /* If this is no TCP socket, ignore any options. */
1040       if ( sock->conn->type != NETCONN_TCP ) return 0;
1041
1042       switch( optname ) {
1043       case TCP_NODELAY:
1044       case TCP_KEEPALIVE:
1045         break;
1046          
1047       default:
1048         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname));
1049         err = ENOPROTOOPT;
1050       }  /* switch */
1051       break;
1052
1053 /* UNDEFINED LEVEL */
1054   default:
1055       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname));
1056       err = ENOPROTOOPT;
1057   }  /* switch */
1058
1059    
1060   if( 0 != err ) {
1061     sock_set_errno(sock, err);
1062     return -1;
1063   }
1064    
1065
1066
1067   /* Now do the actual option processing */
1068
1069   switch(level) {
1070    
1071 /* Level: SOL_SOCKET */
1072   case SOL_SOCKET:
1073     switch( optname ) {
1074
1075     /* The option flags */
1076     case SO_ACCEPTCONN:
1077     case SO_BROADCAST:
1078     /* UNIMPL case SO_DEBUG: */
1079     /* UNIMPL case SO_DONTROUTE: */
1080     case SO_KEEPALIVE:
1081     /* UNIMPL case SO_OOBINCLUDE: */
1082 #ifdef SO_REUSE
1083     case SO_REUSEADDR:
1084     case SO_REUSEPORT:
1085 #endif /* SO_REUSE */
1086     /*case SO_USELOOPBACK: UNIMPL */
1087       *(int*)optval = sock->conn->pcb.tcp->so_options & optname;
1088       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", s, optname, (*(int*)optval?"on":"off")));
1089       break;
1090
1091     case SO_TYPE:
1092       switch (sock->conn->type) {
1093       case NETCONN_RAW:
1094         *(int*)optval = SOCK_RAW;
1095         break;
1096       case NETCONN_TCP:
1097         *(int*)optval = SOCK_STREAM;
1098         break;
1099       case NETCONN_UDP:
1100       case NETCONN_UDPLITE:
1101       case NETCONN_UDPNOCHKSUM:
1102         *(int*)optval = SOCK_DGRAM;
1103         break;
1104       default: /* unrecognized socket type */
1105         *(int*)optval = sock->conn->type;
1106         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", s, *(int *)optval));
1107       }  /* switch */
1108       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", s, *(int *)optval));
1109       break;
1110
1111     case SO_ERROR:
1112       *(int *)optval = sock->err;
1113       sock->err = 0;
1114       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", s, *(int *)optval));
1115       break;
1116     }  /* switch */
1117     break;
1118
1119 /* Level: IPPROTO_IP */
1120   case IPPROTO_IP:
1121     switch( optname ) {
1122     case IP_TTL:
1123       *(int*)optval = sock->conn->pcb.tcp->ttl;
1124       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", s, *(int *)optval));
1125       break;
1126     case IP_TOS:
1127       *(int*)optval = sock->conn->pcb.tcp->tos;
1128       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", s, *(int *)optval));
1129       break;
1130     }  /* switch */
1131     break;
1132
1133 /* Level: IPPROTO_TCP */
1134   case IPPROTO_TCP:
1135     switch( optname ) {
1136     case TCP_NODELAY:
1137       *(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY);
1138       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", s, (*(int*)optval)?"on":"off") );
1139       break;
1140     case TCP_KEEPALIVE:
1141       *(int*)optval = sock->conn->pcb.tcp->keepalive;
1142       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", s, *(int *)optval));
1143       break;
1144     }  /* switch */
1145     break;
1146   }
1147
1148
1149   sock_set_errno(sock, err);
1150   return err ? -1 : 0;
1151 }
1152
1153 int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen)
1154 {
1155   struct lwip_socket *sock = get_socket(s);
1156   int err = 0;
1157
1158   if(!sock) {
1159         set_errno(EBADF);
1160     return -1;
1161   }
1162
1163   if( NULL == optval ) {
1164     sock_set_errno( sock, EFAULT );
1165     return -1;
1166   }
1167
1168
1169   /* Do length and type checks for the various options first, to keep it readable. */
1170   switch( level ) {
1171
1172 /* Level: SOL_SOCKET */
1173   case SOL_SOCKET:
1174     switch(optname) {
1175
1176     case SO_BROADCAST:
1177     /* UNIMPL case SO_DEBUG: */
1178     /* UNIMPL case SO_DONTROUTE: */
1179     case SO_KEEPALIVE:
1180     /* UNIMPL case SO_OOBINLINE: */
1181     /* UNIMPL case SO_RCVBUF: */
1182     /* UNIMPL case SO_SNDBUF: */
1183     /* UNIMPL case SO_RCVLOWAT: */
1184     /* UNIMPL case SO_SNDLOWAT: */
1185 #ifdef SO_REUSE
1186     case SO_REUSEADDR:
1187     case SO_REUSEPORT:
1188 #endif /* SO_REUSE */
1189     /* UNIMPL case SO_USELOOPBACK: */
1190       if( optlen < sizeof(int) ) {
1191         err = EINVAL;
1192       }
1193       break;
1194     default:
1195       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname));
1196       err = ENOPROTOOPT;
1197     }  /* switch */
1198     break;
1199
1200 /* Level: IPPROTO_IP */
1201   case IPPROTO_IP:
1202     switch(optname) {
1203     /* UNIMPL case IP_HDRINCL: */
1204     /* UNIMPL case IP_RCVDSTADDR: */
1205     /* UNIMPL case IP_RCVIF: */
1206     case IP_TTL:
1207     case IP_TOS:
1208       if( optlen < sizeof(int) ) {
1209         err = EINVAL;
1210       }
1211         break;
1212       default:
1213       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname));
1214       err = ENOPROTOOPT;
1215     }  /* switch */
1216     break;
1217
1218 /* Level: IPPROTO_TCP */
1219   case IPPROTO_TCP:
1220     if( optlen < sizeof(int) ) {
1221       err = EINVAL;
1222         break;
1223     }
1224
1225     /* If this is no TCP socket, ignore any options. */
1226     if ( sock->conn->type != NETCONN_TCP ) return 0;
1227
1228     switch( optname ) {
1229     case TCP_NODELAY:
1230     case TCP_KEEPALIVE:
1231       break;
1232
1233     default:
1234       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname));
1235       err = ENOPROTOOPT;
1236     }  /* switch */
1237     break;
1238
1239 /* UNDEFINED LEVEL */      
1240   default:
1241     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname));
1242     err = ENOPROTOOPT;
1243   }  /* switch */
1244
1245
1246   if( 0 != err ) {
1247     sock_set_errno(sock, err);
1248     return -1;
1249   }
1250
1251
1252
1253   /* Now do the actual option processing */
1254
1255   switch(level) {
1256
1257 /* Level: SOL_SOCKET */
1258   case SOL_SOCKET:
1259     switch(optname) {
1260
1261     /* The option flags */
1262     case SO_BROADCAST:
1263     /* UNIMPL case SO_DEBUG: */
1264     /* UNIMPL case SO_DONTROUTE: */
1265     case SO_KEEPALIVE:
1266     /* UNIMPL case SO_OOBINCLUDE: */
1267 #ifdef SO_REUSE
1268     case SO_REUSEADDR:
1269     case SO_REUSEPORT:
1270 #endif /* SO_REUSE */
1271     /* UNIMPL case SO_USELOOPBACK: */
1272       if ( *(int*)optval ) {
1273         sock->conn->pcb.tcp->so_options |= optname;
1274       } else {
1275         sock->conn->pcb.tcp->so_options &= ~optname;
1276       }
1277       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", s, optname, (*(int*)optval?"on":"off")));
1278       break;
1279     }  /* switch */
1280     break;
1281
1282 /* Level: IPPROTO_IP */
1283   case IPPROTO_IP:
1284     switch( optname ) {
1285     case IP_TTL:
1286       sock->conn->pcb.tcp->ttl = (u8_t)(*(int*)optval);
1287       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %u\n", s, sock->conn->pcb.tcp->ttl));
1288       break;
1289     case IP_TOS:
1290       sock->conn->pcb.tcp->tos = (u8_t)(*(int*)optval);
1291       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n", s, sock->conn->pcb.tcp->tos));
1292       break;
1293     }  /* switch */
1294     break;
1295
1296 /* Level: IPPROTO_TCP */
1297   case IPPROTO_TCP:
1298     switch( optname ) {
1299     case TCP_NODELAY:
1300       if ( *(int*)optval ) {
1301         sock->conn->pcb.tcp->flags |= TF_NODELAY;
1302       } else {
1303         sock->conn->pcb.tcp->flags &= ~TF_NODELAY;
1304       }
1305       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", s, (*(int *)optval)?"on":"off") );
1306       break;
1307     case TCP_KEEPALIVE:
1308       sock->conn->pcb.tcp->keepalive = (u32_t)(*(int*)optval);
1309       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %u\n", s, sock->conn->pcb.tcp->keepalive));
1310       break;
1311     }  /* switch */
1312     break;
1313   }  /* switch */
1314
1315   sock_set_errno(sock, err);
1316   return err ? -1 : 0;
1317 }
1318
1319 int lwip_ioctl(int s, long cmd, void *argp)
1320 {
1321   struct lwip_socket *sock = get_socket(s);
1322
1323   if(!sock) {
1324         set_errno(EBADF);
1325     return -1;
1326   }
1327
1328   switch (cmd) {
1329   case FIONREAD:
1330     if (!argp) {
1331       sock_set_errno(sock, EINVAL);
1332       return -1;
1333     }
1334
1335     *((u16_t*)argp) = sock->conn->recv_avail;
1336
1337     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16_t*)argp)));
1338     sock_set_errno(sock, 0);
1339     return 0;
1340
1341   case FIONBIO:
1342     if (argp && *(u32_t*)argp)
1343       sock->flags |= O_NONBLOCK;
1344     else
1345       sock->flags &= ~O_NONBLOCK;
1346     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK)));
1347     sock_set_errno(sock, 0);
1348     return 0;
1349
1350   default:
1351     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
1352     sock_set_errno(sock, ENOSYS); /* not yet implemented */
1353     return -1;
1354   }
1355 }
1356