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