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