Disabling auto-refresh of game list by default, as it is causing bugs sometimes
[open-ps2-loader.git] / modules / network / SMSTCPIP / sockets.c
blobee1b6c5c14b343fba2211451f14a1b75e909d87e
1 /*
2 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
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.
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.
27 * This file is part of the lwIP TCP/IP stack.
29 * Author: Adam Dunkels <adam@sics.se>
31 * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
35 #include "lwip/opt.h"
36 #include "lwip/api.h"
37 #include "lwip/arch.h"
38 #include "lwip/sys.h"
40 #include "lwip/sockets.h"
42 #include <thsemap.h>
43 #include <sysclib.h>
44 #include <errno.h>
46 #include "smsutils.h"
48 #define NUM_SOCKETS MEMP_NUM_NETCONN
50 struct lwip_socket {
51 struct netconn *conn;
52 struct netbuf *lastdata;
53 u16_t lastoffset;
54 u16_t rcvevent;
55 u16_t sendevent;
56 u16_t flags;
57 int err;
60 struct lwip_select_cb
62 struct lwip_select_cb *next;
63 fd_set *readset;
64 fd_set *writeset;
65 fd_set *exceptset;
66 int sem_signalled;
67 sys_sem_t sem;
70 static struct lwip_socket sockets[NUM_SOCKETS];
71 static struct lwip_select_cb *select_cb_list = 0;
73 static sys_sem_t socksem = 0;
74 static sys_sem_t selectsem = 0;
76 static void
77 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
79 static int err_to_errno_table[11] = {
80 0, /* ERR_OK 0 No error, everything OK. */
81 ENOMEM, /* ERR_MEM -1 Out of memory error. */
82 ENOBUFS, /* ERR_BUF -2 Buffer error. */
83 ECONNABORTED, /* ERR_ABRT -3 Connection aborted. */
84 ECONNRESET, /* ERR_RST -4 Connection reset. */
85 ESHUTDOWN, /* ERR_CLSD -5 Connection closed. */
86 ENOTCONN, /* ERR_CONN -6 Not connected. */
87 EINVAL, /* ERR_VAL -7 Illegal value. */
88 EIO, /* ERR_ARG -8 Illegal argument. */
89 EHOSTUNREACH, /* ERR_RTE -9 Routing problem. */
90 EADDRINUSE /* ERR_USE -10 Address in use. */
93 #define err_to_errno(err) \
94 ((err) < (sizeof(err_to_errno_table)/sizeof(int))) ? \
95 err_to_errno_table[-(err)] : EIO
97 #ifdef ERRNO
98 #define set_errno(err) errno = (err)
99 #else
100 #define set_errno(err)
101 #endif
103 #define sock_set_errno(sk, e) do { \
104 sk->err = (e); \
105 set_errno(sk->err); \
106 } while (0)
109 static struct lwip_socket *
110 get_socket(int s)
112 struct lwip_socket *sock;
114 if ((s < 0) || (s > NUM_SOCKETS)) {
115 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
116 set_errno(EBADF);
117 return NULL;
120 sock = &sockets[s];
122 if (!sock->conn) {
123 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
124 set_errno(EBADF);
125 return NULL;
128 return sock;
131 static int
132 alloc_socket(struct netconn *newconn)
134 int i;
136 if (!socksem)
137 socksem = sys_sem_new(1);
139 /* Protect socket array */
140 sys_sem_wait(socksem);
142 /* allocate a new socket identifier */
143 for(i = 0; i < NUM_SOCKETS; ++i) {
144 if (!sockets[i].conn) {
145 sockets[i].conn = newconn;
146 sockets[i].lastdata = NULL;
147 sockets[i].lastoffset = 0;
148 sockets[i].rcvevent = 0;
149 sockets[i].sendevent = 1; /* TCP send buf is empty */
150 sockets[i].flags = 0;
151 sockets[i].err = 0;
152 sys_sem_signal(socksem);
153 return i;
156 sys_sem_signal(socksem);
157 return -1;
161 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
163 struct lwip_socket *sock;
164 struct netconn *newconn;
165 struct ip_addr naddr;
166 u16_t port;
167 int newsock;
168 struct sockaddr_in sin;
170 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
171 sock = get_socket(s);
172 if (!sock) {
173 set_errno(EBADF);
174 return -1;
177 newconn = netconn_accept(sock->conn);
179 /* get the IP address and port of the remote host */
180 netconn_peer(newconn, &naddr, &port);
182 mips_memset(&sin, 0, sizeof(sin));
183 sin.sin_len = sizeof(sin);
184 sin.sin_family = AF_INET;
185 sin.sin_port = htons(port);
186 sin.sin_addr.s_addr = naddr.addr;
188 if (*addrlen > sizeof(sin))
189 *addrlen = sizeof(sin);
191 mips_memcpy(addr, &sin, *addrlen);
193 newsock = alloc_socket(newconn);
194 if (newsock == -1) {
195 netconn_delete(newconn);
196 sock_set_errno(sock, ENOBUFS);
197 return -1;
199 newconn->callback = event_callback;
200 sock = get_socket(newsock);
202 sys_sem_wait(socksem);
203 sock->rcvevent += -1 - newconn->socket;
204 newconn->socket = newsock;
205 sys_sem_signal(socksem);
207 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
208 ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
209 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", port));
211 sock_set_errno(sock, 0);
212 return newsock;
216 lwip_bind(int s, struct sockaddr *name, socklen_t namelen)
218 struct lwip_socket *sock;
219 struct ip_addr local_addr;
220 u16_t local_port;
221 err_t err;
223 sock = get_socket(s);
224 if (!sock) {
225 set_errno(EBADF);
226 return -1;
229 local_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
230 local_port = ((struct sockaddr_in *)name)->sin_port;
232 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
233 ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
234 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(local_port)));
236 err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
238 if (err != ERR_OK) {
239 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
240 sock_set_errno(sock, err_to_errno(err));
241 return -1;
244 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
245 sock_set_errno(sock, 0);
246 return 0;
250 lwip_close(int s)
252 struct lwip_socket *sock;
254 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
255 if (!socksem)
256 socksem = sys_sem_new(1);
258 /* We cannot allow multiple closes of the same socket. */
259 sys_sem_wait(socksem);
261 sock = get_socket(s);
262 if (!sock) {
263 sys_sem_signal(socksem);
264 set_errno(EBADF);
265 return -1;
268 netconn_delete(sock->conn);
269 if (sock->lastdata) {
270 netbuf_delete(sock->lastdata);
272 sock->lastdata = NULL;
273 sock->lastoffset = 0;
274 sock->conn = NULL;
275 sys_sem_signal(socksem);
276 sock_set_errno(sock, 0);
277 return 0;
281 lwip_connect(int s, struct sockaddr *name, socklen_t namelen)
283 struct lwip_socket *sock;
284 err_t err;
286 sock = get_socket(s);
287 if (!sock) {
288 set_errno(EBADF);
289 return -1;
292 if (((struct sockaddr_in *)name)->sin_family == AF_UNSPEC) {
293 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
294 err = netconn_disconnect(sock->conn);
295 } else {
296 struct ip_addr remote_addr;
297 u16_t remote_port;
299 remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
300 remote_port = ((struct sockaddr_in *)name)->sin_port;
302 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
303 ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
304 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port)));
306 err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
309 if (err != ERR_OK) {
310 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
311 sock_set_errno(sock, err_to_errno(err));
312 return -1;
315 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
316 sock_set_errno(sock, 0);
317 return 0;
321 lwip_listen(int s, int backlog)
323 struct lwip_socket *sock;
324 err_t err;
326 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
327 sock = get_socket(s);
328 if (!sock) {
329 set_errno(EBADF);
330 return -1;
333 err = netconn_listen(sock->conn);
335 if (err != ERR_OK) {
336 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
337 sock_set_errno(sock, err_to_errno(err));
338 return -1;
341 sock_set_errno(sock, 0);
342 return 0;
346 lwip_recvfrom(int s, void *header, int index, void *payload, int plen, unsigned int flags,
347 struct sockaddr *from, socklen_t *fromlen)
349 struct lwip_socket *sock;
350 struct netbuf *buf;
351 u16_t avail_len, copylen = 0;
352 struct ip_addr *addr;
353 u16_t port;
356 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, payload, plen, flags));
357 sock = get_socket(s);
358 if (!sock) {
359 set_errno(EBADF);
360 return -1;
363 /* Check if there is data left from the last recv operation. */
364 if (sock->lastdata) {
365 buf = sock->lastdata;
366 } else {
367 /* If this is non-blocking call, then check first */
368 if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK))
369 && !sock->rcvevent)
371 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
372 sock_set_errno(sock, EWOULDBLOCK);
373 return -1;
376 /* No data was left from the previous operation, so we try to get
377 some from the network. */
378 buf = netconn_recv(sock->conn);
380 if (!buf) {
381 /* We should really do some error checking here. */
382 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s));
383 sock_set_errno(sock, 0);
384 return 0;
388 avail_len = netbuf_len(buf);
390 avail_len -= sock->lastoffset;
392 /* copy the contents of the received buffer into
393 the supplied memory pointer mem */
394 if (index) {
395 if (avail_len >= 63) { // header of READ ANDX RESPONSE is 63 + padding bytes, which are "0x00" thus useless
396 netbuf_copy_partial(buf, header, 63, sock->lastoffset);
397 index = ((u8_t*)header)[index] + 4;
398 copylen = index;
399 avail_len -= index;
400 } else {
401 netbuf_copy_partial(buf, header, avail_len, sock->lastoffset);
402 copylen = avail_len;
403 avail_len = 0;
407 if (avail_len) {
408 if (plen > avail_len)
409 plen = avail_len;
411 netbuf_copy_partial(buf, payload, plen, sock->lastoffset + index);
412 copylen += plen;
413 avail_len -= plen;
416 /* Check to see from where the data was. */
417 if (from && fromlen) {
418 struct sockaddr_in sin;
420 addr = netbuf_fromaddr(buf);
421 port = netbuf_fromport(buf);
423 mips_memset(&sin, 0, sizeof(sin));
424 sin.sin_len = sizeof(sin);
425 sin.sin_family = AF_INET;
426 sin.sin_port = htons(port);
427 sin.sin_addr.s_addr = addr->addr;
429 if (*fromlen > sizeof(sin))
430 *fromlen = sizeof(sin);
432 mips_memcpy(from, &sin, *fromlen);
434 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
435 ip_addr_debug_print(SOCKETS_DEBUG, addr);
436 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));
437 } else {
438 #if SOCKETS_DEBUG > 0
439 addr = netbuf_fromaddr(buf);
440 port = netbuf_fromport(buf);
442 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
443 ip_addr_debug_print(SOCKETS_DEBUG, addr);
444 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));
445 #endif
448 /* If this is a TCP socket, check if there is data left in the
449 buffer. If so, it should be saved in the sock structure for next
450 time around. */
451 if (netconn_type(sock->conn) == NETCONN_TCP && avail_len > 0) {
452 sock->lastdata = buf;
453 sock->lastoffset += copylen;
454 } else {
455 sock->lastdata = NULL;
456 sock->lastoffset = 0;
457 netbuf_delete(buf);
460 sock_set_errno(sock, 0);
461 return copylen;
465 lwip_read(int s, void *mem, int len)
467 return lwip_recvfrom(s, NULL, 0, mem, len, 0, NULL, NULL);
471 lwip_recv(int s, void *mem, int len, unsigned int flags)
473 return lwip_recvfrom(s, NULL, 0, mem, len, flags, NULL, NULL);
477 lwip_send(int s, void *data, int size, unsigned int flags)
479 struct lwip_socket *sock;
480 struct netbuf *buf;
481 err_t err;
483 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%d, flags=0x%x)\n", s, data, size, flags));
485 sock = get_socket(s);
486 if (!sock) {
487 set_errno(EBADF);
488 return -1;
491 switch (netconn_type(sock->conn)) {
492 case NETCONN_RAW:
493 case NETCONN_UDP:
494 case NETCONN_UDPLITE:
495 case NETCONN_UDPNOCHKSUM:
496 /* create a buffer */
497 buf = netbuf_new();
499 if (!buf) {
500 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) ENOBUFS\n", s));
501 sock_set_errno(sock, ENOBUFS);
502 return -1;
505 /* make the buffer point to the data that should
506 be sent */
507 netbuf_ref(buf, data, size);
509 /* send the data */
510 err = netconn_send(sock->conn, buf);
512 /* deallocated the buffer */
513 netbuf_delete(buf);
514 break;
515 case NETCONN_TCP:
516 err = netconn_write(sock->conn, data, size, NETCONN_COPY);
517 break;
518 default:
519 err = ERR_ARG;
520 break;
522 if (err != ERR_OK) {
523 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d\n", s, err));
524 sock_set_errno(sock, err_to_errno(err));
525 return -1;
528 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) ok size=%d\n", s, size));
529 sock_set_errno(sock, 0);
530 return size;
534 lwip_sendto(int s, void *data, int size, unsigned int flags,
535 struct sockaddr *to, socklen_t tolen)
537 struct lwip_socket *sock;
538 struct ip_addr remote_addr, addr;
539 u16_t remote_port, port;
540 int ret,connected;
542 sock = get_socket(s);
543 if (!sock) {
544 set_errno(EBADF);
545 return -1;
548 /* get the peer if currently connected */
549 connected = (netconn_peer(sock->conn, &addr, &port) == ERR_OK);
551 remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;
552 remote_port = ((struct sockaddr_in *)to)->sin_port;
554 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=", s, data, size, flags));
555 ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
556 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", ntohs(remote_port)));
558 netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
560 ret = lwip_send(s, data, size, flags);
562 /* reset the remote address and port number
563 of the connection */
564 if (connected)
565 netconn_connect(sock->conn, &addr, port);
566 else
567 netconn_disconnect(sock->conn);
568 return ret;
572 lwip_socket(int domain, int type, int protocol)
574 struct netconn *conn;
575 int i;
577 /* create a netconn */
578 switch (type) {
579 case SOCK_RAW:
580 conn = netconn_new_with_proto_and_callback(NETCONN_RAW, protocol, event_callback);
581 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
582 break;
583 case SOCK_DGRAM:
584 conn = netconn_new_with_callback(NETCONN_UDP, event_callback);
585 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
586 break;
587 case SOCK_STREAM:
588 conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
589 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
590 break;
591 default:
592 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", domain, type, protocol));
593 set_errno(EINVAL);
594 return -1;
597 if (!conn) {
598 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
599 set_errno(ENOBUFS);
600 return -1;
603 i = alloc_socket(conn);
605 if (i == -1) {
606 netconn_delete(conn);
607 set_errno(ENOBUFS);
608 return -1;
610 conn->socket = i;
611 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
612 set_errno(0);
613 return i;
617 lwip_write(int s, void *data, int size)
619 return lwip_send(s, data, size, 0);
623 static int
624 lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset)
626 int i, nready = 0;
627 fd_set lreadset, lwriteset, lexceptset;
628 struct lwip_socket *p_sock;
630 FD_ZERO(&lreadset);
631 FD_ZERO(&lwriteset);
632 FD_ZERO(&lexceptset);
634 /* Go through each socket in each list to count number of sockets which
635 currently match */
636 for(i = 0; i < maxfdp1; i++)
638 if (FD_ISSET(i, readset))
640 /* See if netconn of this socket is ready for read */
641 p_sock = get_socket(i);
642 if (p_sock && (p_sock->lastdata || p_sock->rcvevent))
644 FD_SET(i, &lreadset);
645 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
646 nready++;
649 if (FD_ISSET(i, writeset))
651 /* See if netconn of this socket is ready for write */
652 p_sock = get_socket(i);
653 if (p_sock && p_sock->sendevent)
655 FD_SET(i, &lwriteset);
656 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
657 nready++;
661 *readset = lreadset;
662 *writeset = lwriteset;
663 FD_ZERO(exceptset);
665 return nready;
669 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
670 struct timeval *timeout)
672 int i;
673 int nready;
674 fd_set lreadset, lwriteset, lexceptset;
675 u32_t msectimeout;
676 struct lwip_select_cb select_cb;
677 struct lwip_select_cb *p_selcb;
679 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));
681 select_cb.next = 0;
682 select_cb.readset = readset;
683 select_cb.writeset = writeset;
684 select_cb.exceptset = exceptset;
685 select_cb.sem_signalled = 0;
687 /* Protect ourselves searching through the list */
688 if (!selectsem)
689 selectsem = sys_sem_new(1);
690 sys_sem_wait(selectsem);
692 if (readset)
693 lreadset = *readset;
694 else
695 FD_ZERO(&lreadset);
696 if (writeset)
697 lwriteset = *writeset;
698 else
699 FD_ZERO(&lwriteset);
700 if (exceptset)
701 lexceptset = *exceptset;
702 else
703 FD_ZERO(&lexceptset);
705 /* Go through each socket in each list to count number of sockets which
706 currently match */
707 nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
709 /* If we don't have any current events, then suspend if we are supposed to */
710 if (!nready)
712 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
714 sys_sem_signal(selectsem);
715 if (readset)
716 FD_ZERO(readset);
717 if (writeset)
718 FD_ZERO(writeset);
719 if (exceptset)
720 FD_ZERO(exceptset);
722 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
723 set_errno(0);
725 return 0;
728 /* add our semaphore to list */
729 /* We don't actually need any dynamic memory. Our entry on the
730 * list is only valid while we are in this function, so it's ok
731 * to use local variables */
733 select_cb.sem = sys_sem_new(0);
734 /* Note that we are still protected */
735 /* Put this select_cb on top of list */
736 select_cb.next = select_cb_list;
737 select_cb_list = &select_cb;
739 /* Now we can safely unprotect */
740 sys_sem_signal(selectsem);
742 /* Now just wait to be woken */
743 if (timeout == 0)
744 /* Wait forever */
745 msectimeout = 0;
746 else
747 msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
749 i = sys_sem_wait_timeout(select_cb.sem, msectimeout);
751 /* Take us off the list */
752 sys_sem_wait(selectsem);
753 if (select_cb_list == &select_cb)
754 select_cb_list = select_cb.next;
755 else
756 for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next)
757 if (p_selcb->next == &select_cb)
759 p_selcb->next = select_cb.next;
760 break;
763 sys_sem_signal(selectsem);
765 sys_sem_free(select_cb.sem);
766 if (i == 0) /* Timeout */
768 if (readset)
769 FD_ZERO(readset);
770 if (writeset)
771 FD_ZERO(writeset);
772 if (exceptset)
773 FD_ZERO(exceptset);
775 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
776 set_errno(0);
778 return 0;
781 if (readset)
782 lreadset = *readset;
783 else
784 FD_ZERO(&lreadset);
785 if (writeset)
786 lwriteset = *writeset;
787 else
788 FD_ZERO(&lwriteset);
789 if (exceptset)
790 lexceptset = *exceptset;
791 else
792 FD_ZERO(&lexceptset);
794 /* See what's set */
795 nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
797 else
798 sys_sem_signal(selectsem);
800 if (readset)
801 *readset = lreadset;
802 if (writeset)
803 *writeset = lwriteset;
804 if (exceptset)
805 *exceptset = lexceptset;
807 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
808 set_errno(0);
810 return nready;
814 static void
815 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
817 int s;
818 struct lwip_socket *sock;
819 struct lwip_select_cb *scb;
821 /* Get socket */
822 if (conn)
824 s = conn->socket;
825 if (s < 0)
827 /* Data comes in right away after an accept, even though
828 * the server task might not have created a new socket yet.
829 * Just count down (or up) if that's the case and we
830 * will use the data later. Note that only receive events
831 * can happen before the new socket is set up. */
832 if (evt == NETCONN_EVT_RCVPLUS)
833 conn->socket--;
834 return;
837 sock = get_socket(s);
838 if (!sock)
839 return;
841 else
842 return;
844 if (!selectsem)
845 selectsem = sys_sem_new(1);
847 sys_sem_wait(selectsem);
848 /* Set event as required */
849 switch (evt)
851 case NETCONN_EVT_RCVPLUS:
852 sock->rcvevent++;
853 break;
854 case NETCONN_EVT_RCVMINUS:
855 sock->rcvevent--;
856 break;
857 case NETCONN_EVT_SENDPLUS:
858 sock->sendevent = 1;
859 break;
860 case NETCONN_EVT_SENDMINUS:
861 sock->sendevent = 0;
862 break;
864 sys_sem_signal(selectsem);
866 /* Now decide if anyone is waiting for this socket */
867 /* NOTE: This code is written this way to protect the select link list
868 but to avoid a deadlock situation by releasing socksem before
869 signalling for the select. This means we need to go through the list
870 multiple times ONLY IF a select was actually waiting. We go through
871 the list the number of waiting select calls + 1. This list is
872 expected to be small. */
873 while (1)
875 sys_sem_wait(selectsem);
876 for (scb = select_cb_list; scb; scb = scb->next)
878 if (scb->sem_signalled == 0)
880 /* Test this select call for our socket */
881 if (scb->readset && FD_ISSET(s, scb->readset))
882 if (sock->rcvevent)
883 break;
884 if (scb->writeset && FD_ISSET(s, scb->writeset))
885 if (sock->sendevent)
886 break;
889 if (scb)
891 scb->sem_signalled = 1;
892 sys_sem_signal(selectsem);
893 sys_sem_signal(scb->sem);
894 } else {
895 sys_sem_signal(selectsem);
896 break;
905 int lwip_shutdown(int s, int how)
907 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
908 return lwip_close(s); /* XXX temporary hack until proper implementation */
911 int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen)
913 struct lwip_socket *sock;
914 struct sockaddr_in sin;
915 struct ip_addr naddr;
917 sock = get_socket(s);
918 if (!sock) {
919 set_errno(EBADF);
920 return -1;
923 mips_memset(&sin, 0, sizeof(sin));
924 sin.sin_len = sizeof(sin);
925 sin.sin_family = AF_INET;
927 /* get the IP address and port of the remote host */
928 netconn_peer(sock->conn, &naddr, &sin.sin_port);
930 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getpeername(%d, addr=", s));
931 ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
932 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));
934 sin.sin_port = htons(sin.sin_port);
935 sin.sin_addr.s_addr = naddr.addr;
937 if (*namelen > sizeof(sin))
938 *namelen = sizeof(sin);
940 mips_memcpy(name, &sin, *namelen);
941 sock_set_errno(sock, 0);
942 return 0;
945 int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen)
947 struct lwip_socket *sock;
948 struct sockaddr_in sin;
949 struct ip_addr *naddr;
951 sock = get_socket(s);
952 if (!sock) {
953 set_errno(EBADF);
954 return -1;
957 mips_memset(&sin, 0, sizeof(sin));
958 sin.sin_len = sizeof(sin);
959 sin.sin_family = AF_INET;
961 /* get the IP address and port of the remote host */
962 netconn_addr(sock->conn, &naddr, &sin.sin_port);
964 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockname(%d, addr=", s));
965 ip_addr_debug_print(SOCKETS_DEBUG, naddr);
966 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));
968 sin.sin_port = htons(sin.sin_port);
969 sin.sin_addr.s_addr = naddr->addr;
971 if (*namelen > sizeof(sin))
972 *namelen = sizeof(sin);
974 mips_memcpy(name, &sin, *namelen);
975 sock_set_errno(sock, 0);
976 return 0;
979 int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen)
981 int err = 0;
982 struct lwip_socket *sock = get_socket(s);
984 if(!sock) {
985 set_errno(EBADF);
986 return -1;
989 if( NULL == optval || NULL == optlen ) {
990 sock_set_errno( sock, EFAULT );
991 return -1;
994 /* Do length and type checks for the various options first, to keep it readable. */
995 switch( level ) {
997 /* Level: SOL_SOCKET */
998 case SOL_SOCKET:
999 switch(optname) {
1001 case SO_ACCEPTCONN:
1002 case SO_BROADCAST:
1003 /* UNIMPL case SO_DEBUG: */
1004 /* UNIMPL case SO_DONTROUTE: */
1005 case SO_ERROR:
1006 case SO_KEEPALIVE:
1007 /* UNIMPL case SO_OOBINLINE: */
1008 /* UNIMPL case SO_RCVBUF: */
1009 /* UNIMPL case SO_SNDBUF: */
1010 /* UNIMPL case SO_RCVLOWAT: */
1011 /* UNIMPL case SO_SNDLOWAT: */
1012 #ifdef SO_REUSE
1013 case SO_REUSEADDR:
1014 case SO_REUSEPORT:
1015 #endif /* SO_REUSE */
1016 case SO_TYPE:
1017 /* UNIMPL case SO_USELOOPBACK: */
1018 if( *optlen < sizeof(int) ) {
1019 err = EINVAL;
1021 break;
1023 default:
1024 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname));
1025 err = ENOPROTOOPT;
1026 } /* switch */
1027 break;
1029 /* Level: IPPROTO_IP */
1030 case IPPROTO_IP:
1031 switch(optname) {
1032 /* UNIMPL case IP_HDRINCL: */
1033 /* UNIMPL case IP_RCVDSTADDR: */
1034 /* UNIMPL case IP_RCVIF: */
1035 case IP_TTL:
1036 case IP_TOS:
1037 if( *optlen < sizeof(int) ) {
1038 err = EINVAL;
1040 break;
1042 default:
1043 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname));
1044 err = ENOPROTOOPT;
1045 } /* switch */
1046 break;
1048 /* Level: IPPROTO_TCP */
1049 case IPPROTO_TCP:
1050 if( *optlen < sizeof(int) ) {
1051 err = EINVAL;
1052 break;
1055 /* If this is no TCP socket, ignore any options. */
1056 if ( sock->conn->type != NETCONN_TCP ) return 0;
1058 switch( optname ) {
1059 case TCP_NODELAY:
1060 case TCP_KEEPALIVE:
1061 case TCP_ACKNODELAY:
1062 case TCP_EVENSEG:
1063 break;
1065 default:
1066 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname));
1067 err = ENOPROTOOPT;
1068 } /* switch */
1069 break;
1071 /* UNDEFINED LEVEL */
1072 default:
1073 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname));
1074 err = ENOPROTOOPT;
1075 } /* switch */
1078 if( 0 != err ) {
1079 sock_set_errno(sock, err);
1080 return -1;
1085 /* Now do the actual option processing */
1087 switch(level) {
1089 /* Level: SOL_SOCKET */
1090 case SOL_SOCKET:
1091 switch( optname ) {
1093 /* The option flags */
1094 case SO_ACCEPTCONN:
1095 case SO_BROADCAST:
1096 /* UNIMPL case SO_DEBUG: */
1097 /* UNIMPL case SO_DONTROUTE: */
1098 case SO_KEEPALIVE:
1099 /* UNIMPL case SO_OOBINCLUDE: */
1100 #ifdef SO_REUSE
1101 case SO_REUSEADDR:
1102 case SO_REUSEPORT:
1103 #endif /* SO_REUSE */
1104 /*case SO_USELOOPBACK: UNIMPL */
1105 *(int*)optval = sock->conn->pcb.tcp->so_options & optname;
1106 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", s, optname, (*(int*)optval?"on":"off")));
1107 break;
1109 case SO_TYPE:
1110 switch (sock->conn->type) {
1111 case NETCONN_RAW:
1112 *(int*)optval = SOCK_RAW;
1113 break;
1114 case NETCONN_TCP:
1115 *(int*)optval = SOCK_STREAM;
1116 break;
1117 case NETCONN_UDP:
1118 case NETCONN_UDPLITE:
1119 case NETCONN_UDPNOCHKSUM:
1120 *(int*)optval = SOCK_DGRAM;
1121 break;
1122 default: /* unrecognized socket type */
1123 *(int*)optval = sock->conn->type;
1124 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", s, *(int *)optval));
1125 } /* switch */
1126 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", s, *(int *)optval));
1127 break;
1129 case SO_ERROR:
1130 *(int *)optval = sock->err;
1131 sock->err = 0;
1132 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", s, *(int *)optval));
1133 break;
1134 } /* switch */
1135 break;
1137 /* Level: IPPROTO_IP */
1138 case IPPROTO_IP:
1139 switch( optname ) {
1140 case IP_TTL:
1141 *(int*)optval = sock->conn->pcb.tcp->ttl;
1142 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", s, *(int *)optval));
1143 break;
1144 case IP_TOS:
1145 *(int*)optval = sock->conn->pcb.tcp->tos;
1146 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", s, *(int *)optval));
1147 break;
1148 } /* switch */
1149 break;
1151 /* Level: IPPROTO_TCP */
1152 case IPPROTO_TCP:
1153 switch( optname ) {
1154 case TCP_NODELAY:
1155 *(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY);
1156 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", s, (*(int*)optval)?"on":"off") );
1157 break;
1158 case TCP_KEEPALIVE:
1159 *(int*)optval = sock->conn->pcb.tcp->keepalive;
1160 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", s, *(int *)optval));
1161 break;
1162 case TCP_ACKNODELAY:
1163 *(int*)optval = sock->conn->pcb.tcp->flags & TF_ACKNODELAY;
1164 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_ACKNODELAY) = %s\n", s, (*(int *)optval)?"on":"off") );
1165 break;
1166 case TCP_EVENSEG:
1167 *(int*)optval = sock->conn->pcb.tcp->flags & TF_EVENSEG;
1168 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_EVENSEG) = %s\n", s, (*(int *)optval)?"on":"off") );
1169 break;
1170 } /* switch */
1171 break;
1175 sock_set_errno(sock, err);
1176 return err ? -1 : 0;
1179 int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen)
1181 struct lwip_socket *sock = get_socket(s);
1182 int err = 0;
1184 if(!sock) {
1185 set_errno(EBADF);
1186 return -1;
1189 if( NULL == optval ) {
1190 sock_set_errno( sock, EFAULT );
1191 return -1;
1195 /* Do length and type checks for the various options first, to keep it readable. */
1196 switch( level ) {
1198 /* Level: SOL_SOCKET */
1199 case SOL_SOCKET:
1200 switch(optname) {
1202 case SO_BROADCAST:
1203 /* UNIMPL case SO_DEBUG: */
1204 /* UNIMPL case SO_DONTROUTE: */
1205 case SO_KEEPALIVE:
1206 /* UNIMPL case SO_OOBINLINE: */
1207 /* UNIMPL case SO_RCVBUF: */
1208 /* UNIMPL case SO_SNDBUF: */
1209 /* UNIMPL case SO_RCVLOWAT: */
1210 /* UNIMPL case SO_SNDLOWAT: */
1211 #ifdef SO_REUSE
1212 case SO_REUSEADDR:
1213 case SO_REUSEPORT:
1214 #endif /* SO_REUSE */
1215 /* UNIMPL case SO_USELOOPBACK: */
1216 if( optlen < sizeof(int) ) {
1217 err = EINVAL;
1219 break;
1220 default:
1221 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname));
1222 err = ENOPROTOOPT;
1223 } /* switch */
1224 break;
1226 /* Level: IPPROTO_IP */
1227 case IPPROTO_IP:
1228 switch(optname) {
1229 /* UNIMPL case IP_HDRINCL: */
1230 /* UNIMPL case IP_RCVDSTADDR: */
1231 /* UNIMPL case IP_RCVIF: */
1232 case IP_TTL:
1233 case IP_TOS:
1234 if( optlen < sizeof(int) ) {
1235 err = EINVAL;
1237 break;
1238 default:
1239 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname));
1240 err = ENOPROTOOPT;
1241 } /* switch */
1242 break;
1244 /* Level: IPPROTO_TCP */
1245 case IPPROTO_TCP:
1246 if( optlen < sizeof(int) ) {
1247 err = EINVAL;
1248 break;
1251 /* If this is no TCP socket, ignore any options. */
1252 if ( sock->conn->type != NETCONN_TCP ) return 0;
1254 switch( optname ) {
1255 case TCP_NODELAY:
1256 case TCP_KEEPALIVE:
1257 case TCP_ACKNODELAY:
1258 case TCP_EVENSEG:
1259 break;
1261 default:
1262 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname));
1263 err = ENOPROTOOPT;
1264 } /* switch */
1265 break;
1267 /* UNDEFINED LEVEL */
1268 default:
1269 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname));
1270 err = ENOPROTOOPT;
1271 } /* switch */
1274 if( 0 != err ) {
1275 sock_set_errno(sock, err);
1276 return -1;
1281 /* Now do the actual option processing */
1283 switch(level) {
1285 /* Level: SOL_SOCKET */
1286 case SOL_SOCKET:
1287 switch(optname) {
1289 /* The option flags */
1290 case SO_BROADCAST:
1291 /* UNIMPL case SO_DEBUG: */
1292 /* UNIMPL case SO_DONTROUTE: */
1293 case SO_KEEPALIVE:
1294 /* UNIMPL case SO_OOBINCLUDE: */
1295 #ifdef SO_REUSE
1296 case SO_REUSEADDR:
1297 case SO_REUSEPORT:
1298 #endif /* SO_REUSE */
1299 /* UNIMPL case SO_USELOOPBACK: */
1300 if ( *(int*)optval ) {
1301 sock->conn->pcb.tcp->so_options |= optname;
1302 } else {
1303 sock->conn->pcb.tcp->so_options &= ~optname;
1305 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", s, optname, (*(int*)optval?"on":"off")));
1306 break;
1307 } /* switch */
1308 break;
1310 /* Level: IPPROTO_IP */
1311 case IPPROTO_IP:
1312 switch( optname ) {
1313 case IP_TTL:
1314 sock->conn->pcb.tcp->ttl = (u8_t)(*(int*)optval);
1315 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %u\n", s, sock->conn->pcb.tcp->ttl));
1316 break;
1317 case IP_TOS:
1318 sock->conn->pcb.tcp->tos = (u8_t)(*(int*)optval);
1319 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n", s, sock->conn->pcb.tcp->tos));
1320 break;
1321 } /* switch */
1322 break;
1324 /* Level: IPPROTO_TCP */
1325 case IPPROTO_TCP:
1326 switch( optname ) {
1327 case TCP_NODELAY:
1328 if ( *(int*)optval ) {
1329 sock->conn->pcb.tcp->flags |= TF_NODELAY;
1330 } else {
1331 sock->conn->pcb.tcp->flags &= ~TF_NODELAY;
1333 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", s, (*(int *)optval)?"on":"off") );
1334 break;
1335 case TCP_KEEPALIVE:
1336 sock->conn->pcb.tcp->keepalive = (u32_t)(*(int*)optval);
1337 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %u\n", s, sock->conn->pcb.tcp->keepalive));
1338 break;
1339 case TCP_ACKNODELAY:
1340 if ( *(int*)optval ) {
1341 sock->conn->pcb.tcp->flags |= TF_ACKNODELAY;
1342 } else {
1343 sock->conn->pcb.tcp->flags &= ~TF_ACKNODELAY;
1345 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_ACKNODELAY) -> %s\n", s, (*(int *)optval)?"on":"off") );
1346 break;
1347 case TCP_EVENSEG:
1348 if ( *(int*)optval ) {
1349 sock->conn->pcb.tcp->flags |= TF_EVENSEG;
1350 } else {
1351 sock->conn->pcb.tcp->flags &= ~TF_EVENSEG;
1353 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_EVENSEG) -> %s\n", s, (*(int *)optval)?"on":"off") );
1354 break;
1355 } /* switch */
1356 break;
1357 } /* switch */
1359 sock_set_errno(sock, err);
1360 return err ? -1 : 0;
1363 int lwip_ioctl(int s, long cmd, void *argp)
1365 struct lwip_socket *sock = get_socket(s);
1367 if(!sock) {
1368 set_errno(EBADF);
1369 return -1;
1372 switch (cmd) {
1373 case FIONREAD:
1374 if (!argp) {
1375 sock_set_errno(sock, EINVAL);
1376 return -1;
1379 *((u16_t*)argp) = sock->conn->recv_avail;
1381 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16_t*)argp)));
1382 sock_set_errno(sock, 0);
1383 return 0;
1385 case FIONBIO:
1386 if (argp && *(u32_t*)argp)
1387 sock->flags |= O_NONBLOCK;
1388 else
1389 sock->flags &= ~O_NONBLOCK;
1390 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK)));
1391 sock_set_errno(sock, 0);
1392 return 0;
1394 default:
1395 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
1396 sock_set_errno(sock, ENOSYS); /* not yet implemented */
1397 return -1;