Marcelo Rebonatto / lwip

Dependents:   EthernetInterface

Fork of lwip by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sockets.c Source File

sockets.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Sockets BSD-Like API module
00004  *
00005  */
00006 
00007 /*
00008  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00009  * All rights reserved.
00010  *
00011  * Redistribution and use in source and binary forms, with or without modification,
00012  * are permitted provided that the following conditions are met:
00013  *
00014  * 1. Redistributions of source code must retain the above copyright notice,
00015  *    this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright notice,
00017  *    this list of conditions and the following disclaimer in the documentation
00018  *    and/or other materials provided with the distribution.
00019  * 3. The name of the author may not be used to endorse or promote products
00020  *    derived from this software without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00023  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00025  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00027  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00030  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00031  * OF SUCH DAMAGE.
00032  *
00033  * This file is part of the lwIP TCP/IP stack.
00034  *
00035  * Author: Adam Dunkels <adam@sics.se>
00036  *
00037  * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
00038  *
00039  */
00040 
00041 #include "lwip/opt.h"
00042 
00043 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
00044 
00045 #include "lwip/sockets.h"
00046 #include "lwip/api.h"
00047 #include "lwip/sys.h"
00048 #include "lwip/igmp.h"
00049 #include "lwip/inet.h"
00050 #include "lwip/tcp.h"
00051 #include "lwip/raw.h"
00052 #include "lwip/udp.h"
00053 #include "lwip/tcpip.h"
00054 #include "lwip/pbuf.h"
00055 #if LWIP_CHECKSUM_ON_COPY
00056 #include "lwip/inet_chksum.h"
00057 #endif
00058 
00059 #include <string.h>
00060 #include <stdio.h>
00061 
00062 #define NUM_SOCKETS MEMP_NUM_NETCONN
00063 
00064 /** Contains all internal pointers and states used for a socket */
00065 struct lwip_sock {
00066   /** sockets currently are built on netconns, each socket has one netconn */
00067   struct netconn *conn;
00068   /** data that was left from the previous read */
00069   void *lastdata;
00070   /** offset in the data that was left from the previous read */
00071   u16_t lastoffset;
00072   /** number of times data was received, set by event_callback(),
00073       tested by the receive and select functions */
00074   s16_t rcvevent;
00075   /** number of times data was ACKed (free send buffer), set by event_callback(),
00076       tested by select */
00077   u16_t sendevent;
00078   /** error happened for this socket, set by event_callback(), tested by select */
00079   u16_t errevent; 
00080   /** last error that occurred on this socket */
00081   int err;
00082   /** counter of how many threads are waiting for this socket using select */
00083   int select_waiting;
00084 };
00085 
00086 /** Description for a task waiting in select */
00087 struct lwip_select_cb {
00088   /** Pointer to the next waiting task */
00089   struct lwip_select_cb *next;
00090   /** Pointer to the previous waiting task */
00091   struct lwip_select_cb *prev;
00092   /** readset passed to select */
00093   fd_set *readset;
00094   /** writeset passed to select */
00095   fd_set *writeset;
00096   /** unimplemented: exceptset passed to select */
00097   fd_set *exceptset;
00098   /** don't signal the same semaphore twice: set to 1 when signalled */
00099   int sem_signalled;
00100   /** semaphore to wake up a task waiting for select */
00101   sys_sem_t sem;
00102 };
00103 
00104 /** This struct is used to pass data to the set/getsockopt_internal
00105  * functions running in tcpip_thread context (only a void* is allowed) */
00106 struct lwip_setgetsockopt_data {
00107   /** socket struct for which to change options */
00108   struct lwip_sock *sock;
00109 #ifdef LWIP_DEBUG
00110   /** socket index for which to change options */
00111   int s;
00112 #endif /* LWIP_DEBUG */
00113   /** level of the option to process */
00114   int level;
00115   /** name of the option to process */
00116   int optname;
00117   /** set: value to set the option to
00118     * get: value of the option is stored here */
00119   void *optval;
00120   /** size of *optval */
00121   socklen_t *optlen;
00122   /** if an error occures, it is temporarily stored here */
00123   err_t err;
00124 };
00125 
00126 /** The global array of available sockets */
00127 static struct lwip_sock sockets[NUM_SOCKETS];
00128 /** The global list of tasks waiting for select */
00129 static struct lwip_select_cb *select_cb_list;
00130 /** This counter is increased from lwip_select when the list is chagned
00131     and checked in event_callback to see if it has changed. */
00132 static volatile int select_cb_ctr;
00133 
00134 /** Table to quickly map an lwIP error (err_t) to a socket error
00135   * by using -err as an index */
00136 static const int err_to_errno_table[] = {
00137   0,             /* ERR_OK          0      No error, everything OK. */
00138   ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */
00139   ENOBUFS,       /* ERR_BUF        -2      Buffer error.            */
00140   EWOULDBLOCK,   /* ERR_TIMEOUT    -3      Timeout                  */
00141   EHOSTUNREACH,  /* ERR_RTE        -4      Routing problem.         */
00142   EINPROGRESS,   /* ERR_INPROGRESS -5      Operation in progress    */
00143   EINVAL,        /* ERR_VAL        -6      Illegal value.           */
00144   EWOULDBLOCK,   /* ERR_WOULDBLOCK -7      Operation would block.   */
00145   EADDRINUSE,    /* ERR_USE        -8      Address in use.          */
00146   EALREADY,      /* ERR_ISCONN     -9      Already connected.       */
00147   ECONNABORTED,  /* ERR_ABRT       -10     Connection aborted.      */
00148   ECONNRESET,    /* ERR_RST        -11     Connection reset.        */
00149   ENOTCONN,      /* ERR_CLSD       -12     Connection closed.       */
00150   ENOTCONN,      /* ERR_CONN       -13     Not connected.           */
00151   EIO,           /* ERR_ARG        -14     Illegal argument.        */
00152   -1,            /* ERR_IF         -15     Low-level netif error    */
00153 };
00154 
00155 #define ERR_TO_ERRNO_TABLE_SIZE \
00156   (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
00157 
00158 #define err_to_errno(err) \
00159   ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
00160     err_to_errno_table[-(err)] : EIO)
00161 
00162 #ifdef ERRNO
00163 #ifndef set_errno
00164 #define set_errno(err) errno = (err)
00165 #endif
00166 #else /* ERRNO */
00167 #define set_errno(err)
00168 #endif /* ERRNO */
00169 
00170 #define sock_set_errno(sk, e) do { \
00171   sk->err = (e); \
00172   set_errno(sk->err); \
00173 } while (0)
00174 
00175 /* Forward delcaration of some functions */
00176 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
00177 static void lwip_getsockopt_internal(void *arg);
00178 static void lwip_setsockopt_internal(void *arg);
00179 
00180 /**
00181  * Initialize this module. This function has to be called before any other
00182  * functions in this module!
00183  */
00184 void
00185 lwip_socket_init(void)
00186 {
00187 }
00188 
00189 /**
00190  * Map a externally used socket index to the internal socket representation.
00191  *
00192  * @param s externally used socket index
00193  * @return struct lwip_sock for the socket or NULL if not found
00194  */
00195 static struct lwip_sock *
00196 get_socket(int s)
00197 {
00198   struct lwip_sock *sock;
00199 
00200   if ((s < 0) || (s >= NUM_SOCKETS)) {
00201     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
00202     set_errno(EBADF);
00203     return NULL;
00204   }
00205 
00206   sock = &sockets[s];
00207 
00208   if (!sock->conn) {
00209     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
00210     set_errno(EBADF);
00211     return NULL;
00212   }
00213 
00214   return sock;
00215 }
00216 
00217 /**
00218  * Same as get_socket but doesn't set errno
00219  *
00220  * @param s externally used socket index
00221  * @return struct lwip_sock for the socket or NULL if not found
00222  */
00223 static struct lwip_sock *
00224 tryget_socket(int s)
00225 {
00226   if ((s < 0) || (s >= NUM_SOCKETS)) {
00227     return NULL;
00228   }
00229   if (!sockets[s].conn) {
00230     return NULL;
00231   }
00232   return &sockets[s];
00233 }
00234 
00235 /**
00236  * Allocate a new socket for a given netconn.
00237  *
00238  * @param newconn the netconn for which to allocate a socket
00239  * @param accepted 1 if socket has been created by accept(),
00240  *                 0 if socket has been created by socket()
00241  * @return the index of the new socket; -1 on error
00242  */
00243 static int
00244 alloc_socket(struct netconn *newconn, int accepted)
00245 {
00246   int i;
00247   SYS_ARCH_DECL_PROTECT(lev);
00248 
00249   /* allocate a new socket identifier */
00250   for (i = 0; i < NUM_SOCKETS; ++i) {
00251     /* Protect socket array */
00252     SYS_ARCH_PROTECT(lev);
00253     if (!sockets[i].conn) {
00254       sockets[i].conn       = newconn;
00255       /* The socket is not yet known to anyone, so no need to protect
00256          after having marked it as used. */
00257       SYS_ARCH_UNPROTECT(lev);
00258       sockets[i].lastdata   = NULL;
00259       sockets[i].lastoffset = 0;
00260       sockets[i].rcvevent   = 0;
00261       /* TCP sendbuf is empty, but the socket is not yet writable until connected
00262        * (unless it has been created by accept()). */
00263       sockets[i].sendevent  = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);
00264       sockets[i].errevent   = 0;
00265       sockets[i].err        = 0;
00266       sockets[i].select_waiting = 0;
00267       return i;
00268     }
00269     SYS_ARCH_UNPROTECT(lev);
00270   }
00271   return -1;
00272 }
00273 
00274 /** Free a socket. The socket's netconn must have been
00275  * delete before!
00276  *
00277  * @param sock the socket to free
00278  * @param is_tcp != 0 for TCP sockets, used to free lastdata
00279  */
00280 static void
00281 free_socket(struct lwip_sock *sock, int is_tcp)
00282 {
00283   void *lastdata;
00284   SYS_ARCH_DECL_PROTECT(lev);
00285 
00286   lastdata         = sock->lastdata;
00287   sock->lastdata   = NULL;
00288   sock->lastoffset = 0;
00289   sock->err        = 0;
00290 
00291   /* Protect socket array */
00292   SYS_ARCH_PROTECT(lev);
00293   sock->conn       = NULL;
00294   SYS_ARCH_UNPROTECT(lev);
00295   /* don't use 'sock' after this line, as another task might have allocated it */
00296 
00297   if (lastdata != NULL) {
00298     if (is_tcp) {
00299       pbuf_free((struct pbuf *)lastdata);
00300     } else {
00301       netbuf_delete((struct netbuf *)lastdata);
00302     }
00303   }
00304 }
00305 
00306 /* Below this, the well-known socket functions are implemented.
00307  * Use google.com or opengroup.org to get a good description :-)
00308  *
00309  * Exceptions are documented!
00310  */
00311 
00312 int
00313 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
00314 {
00315   struct lwip_sock *sock, *nsock;
00316   struct netconn *newconn;
00317   ip_addr_t naddr;
00318   u16_t port;
00319   int newsock;
00320   struct sockaddr_in sin;
00321   err_t err;
00322   SYS_ARCH_DECL_PROTECT(lev);
00323 
00324   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
00325   sock = get_socket(s);
00326   if (!sock) {
00327     return -1;
00328   }
00329 
00330   if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
00331     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
00332     sock_set_errno(sock, EWOULDBLOCK);
00333     return -1;
00334   }
00335 
00336   /* wait for a new connection */
00337   err = netconn_accept(sock->conn, &newconn);
00338   if (err != ERR_OK) {
00339     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
00340     sock_set_errno(sock, err_to_errno(err));
00341     return -1;
00342   }
00343   LWIP_ASSERT("newconn != NULL", newconn != NULL);
00344   /* Prevent automatic window updates, we do this on our own! */
00345   netconn_set_noautorecved(newconn, 1);
00346 
00347   /* get the IP address and port of the remote host */
00348   err = netconn_peer(newconn, &naddr, &port);
00349   if (err != ERR_OK) {
00350     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
00351     netconn_delete(newconn);
00352     sock_set_errno(sock, err_to_errno(err));
00353     return -1;
00354   }
00355 
00356   /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
00357    * not be NULL if addr is valid.
00358    */
00359   if (NULL != addr) {
00360     LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
00361     memset(&sin, 0, sizeof(sin));
00362     sin.sin_len = sizeof(sin);
00363     sin.sin_family = AF_INET;
00364     sin.sin_port = htons(port);
00365     inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
00366 
00367     if (*addrlen > sizeof(sin))
00368       *addrlen = sizeof(sin);
00369 
00370     MEMCPY(addr, &sin, *addrlen);
00371   }
00372 
00373   newsock = alloc_socket(newconn, 1);
00374   if (newsock == -1) {
00375     netconn_delete(newconn);
00376     sock_set_errno(sock, ENFILE);
00377     return -1;
00378   }
00379   LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));
00380   LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
00381   nsock = &sockets[newsock];
00382 
00383   /* See event_callback: If data comes in right away after an accept, even
00384    * though the server task might not have created a new socket yet.
00385    * In that case, newconn->socket is counted down (newconn->socket--),
00386    * so nsock->rcvevent is >= 1 here!
00387    */
00388   SYS_ARCH_PROTECT(lev);
00389   nsock->rcvevent += (s16_t)(-1 - newconn->socket);
00390   newconn->socket = newsock;
00391   SYS_ARCH_UNPROTECT(lev);
00392 
00393   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
00394   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
00395   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
00396 
00397   sock_set_errno(sock, 0);
00398   return newsock;
00399 }
00400 
00401 int
00402 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
00403 {
00404   struct lwip_sock *sock;
00405   ip_addr_t local_addr;
00406   u16_t local_port;
00407   err_t err;
00408   const struct sockaddr_in *name_in;
00409 
00410   sock = get_socket(s);
00411   if (!sock) {
00412     return -1;
00413   }
00414 
00415   /* check size, familiy and alignment of 'name' */
00416   LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
00417              ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
00418              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
00419   name_in = (const struct sockaddr_in *)(void*)name;
00420 
00421   inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);
00422   local_port = name_in->sin_port;
00423 
00424   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
00425   ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
00426   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port)));
00427 
00428   err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
00429 
00430   if (err != ERR_OK) {
00431     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
00432     sock_set_errno(sock, err_to_errno(err));
00433     return -1;
00434   }
00435 
00436   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
00437   sock_set_errno(sock, 0);
00438   return 0;
00439 }
00440 
00441 int
00442 lwip_close(int s)
00443 {
00444   struct lwip_sock *sock;
00445   int is_tcp = 0;
00446 
00447   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
00448 
00449   sock = get_socket(s);
00450   if (!sock) {
00451     return -1;
00452   }
00453 
00454   if(sock->conn != NULL) {
00455     is_tcp = netconn_type(sock->conn) == NETCONN_TCP;
00456   } else {
00457     LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
00458   }
00459 
00460   netconn_delete(sock->conn);
00461 
00462   free_socket(sock, is_tcp);
00463   set_errno(0);
00464   return 0;
00465 }
00466 
00467 int
00468 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
00469 {
00470   struct lwip_sock *sock;
00471   err_t err;
00472   const struct sockaddr_in *name_in;
00473 
00474   sock = get_socket(s);
00475   if (!sock) {
00476     printf("Erro get_socket\n");
00477     return -1;
00478   }
00479 
00480   /* check size, familiy and alignment of 'name' */
00481   LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
00482              ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
00483              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
00484   name_in = (const struct sockaddr_in *)(void*)name;
00485 
00486   if (name_in->sin_family == AF_UNSPEC) {
00487     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
00488     printf("1->lwip_connect(%d, AF_UNSPEC)\n", s);
00489     err = netconn_disconnect(sock->conn);
00490   } else {
00491     ip_addr_t remote_addr;
00492     u16_t remote_port;
00493 
00494     inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);
00495     remote_port = name_in->sin_port;
00496 
00497     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
00498     //printf("2->lwip_connect(%d, addr=", s);
00499     
00500     ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
00501     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port)));
00502     //printf(" port=%d\n", ntohs(remote_port));
00503 
00504     err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
00505   }
00506 
00507   if (err != ERR_OK) {
00508     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
00509     //printf("4->lwip_connect(%d) failed, err=%d\n", s, err);
00510     sock_set_errno(sock, err_to_errno(err));
00511     return -1;
00512   }
00513 
00514   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
00515   sock_set_errno(sock, 0);
00516   return 0;
00517 }
00518 
00519 /**
00520  * Set a socket into listen mode.
00521  * The socket may not have been used for another connection previously.
00522  *
00523  * @param s the socket to set to listening mode
00524  * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
00525  * @return 0 on success, non-zero on failure
00526  */
00527 int
00528 lwip_listen(int s, int backlog)
00529 {
00530   struct lwip_sock *sock;
00531   err_t err;
00532 
00533   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
00534 
00535   sock = get_socket(s);
00536   if (!sock) {
00537     return -1;
00538   }
00539 
00540   /* limit the "backlog" parameter to fit in an u8_t */
00541   backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
00542 
00543   err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
00544 
00545   if (err != ERR_OK) {
00546     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
00547     sock_set_errno(sock, err_to_errno(err));
00548     return -1;
00549   }
00550 
00551   sock_set_errno(sock, 0);
00552   return 0;
00553 }
00554 
00555 int
00556 lwip_recvfrom(int s, void *mem, size_t len, int flags,
00557         struct sockaddr *from, socklen_t *fromlen)
00558 {
00559   struct lwip_sock *sock;
00560   void             *buf = NULL;
00561   struct pbuf      *p;
00562   u16_t            buflen, copylen;
00563   int              off = 0;
00564   ip_addr_t        *addr;
00565   u16_t            port;
00566   u8_t             done = 0;
00567   err_t            err;
00568 
00569   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
00570   sock = get_socket(s);
00571   if (!sock) {
00572     return -1;
00573   }
00574 
00575   do {
00576     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
00577     /* Check if there is data left from the last recv operation. */
00578     if (sock->lastdata) {
00579       buf = sock->lastdata;
00580     } else {
00581       /* If this is non-blocking call, then check first */
00582       if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && 
00583           (sock->rcvevent <= 0)) {
00584         if (off > 0) {
00585           /* update receive window */
00586           netconn_recved(sock->conn, (u32_t)off);
00587           /* already received data, return that */
00588           sock_set_errno(sock, 0);
00589           return off;
00590         }
00591         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
00592         sock_set_errno(sock, EWOULDBLOCK);
00593         return -1;
00594       }
00595 
00596       /* No data was left from the previous operation, so we try to get
00597          some from the network. */
00598       if (netconn_type(sock->conn) == NETCONN_TCP) {
00599         err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
00600       } else {
00601         err = netconn_recv(sock->conn, (struct netbuf **)&buf);
00602       }
00603       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
00604         err, buf));
00605 
00606       if (err != ERR_OK) {
00607         if (off > 0) {
00608           /* update receive window */
00609           netconn_recved(sock->conn, (u32_t)off);
00610           /* already received data, return that */
00611           sock_set_errno(sock, 0);
00612           return off;
00613         }
00614         /* We should really do some error checking here. */
00615         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
00616           s, lwip_strerr(err)));
00617         sock_set_errno(sock, err_to_errno(err));
00618         if (err == ERR_CLSD) {
00619           return 0;
00620         } else {
00621           return -1;
00622         }
00623       }
00624       LWIP_ASSERT("buf != NULL", buf != NULL);
00625       sock->lastdata = buf;
00626     }
00627 
00628     if (netconn_type(sock->conn) == NETCONN_TCP) {
00629       p = (struct pbuf *)buf;
00630     } else {
00631       p = ((struct netbuf *)buf)->p;
00632     }
00633     buflen = p->tot_len;
00634     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
00635       buflen, len, off, sock->lastoffset));
00636 
00637     buflen -= sock->lastoffset;
00638 
00639     if (len > buflen) {
00640       copylen = buflen;
00641     } else {
00642       copylen = (u16_t)len;
00643     }
00644 
00645     /* copy the contents of the received buffer into
00646     the supplied memory pointer mem */
00647     pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
00648 
00649     off += copylen;
00650 
00651     if (netconn_type(sock->conn) == NETCONN_TCP) {
00652       LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
00653       len -= copylen;
00654       if ( (len <= 0) || 
00655            (p->flags & PBUF_FLAG_PUSH) || 
00656            (sock->rcvevent <= 0) || 
00657            ((flags & MSG_PEEK)!=0)) {
00658         done = 1;
00659       }
00660     } else {
00661       done = 1;
00662     }
00663 
00664     /* Check to see from where the data was.*/
00665     if (done) {
00666       ip_addr_t fromaddr;
00667       if (from && fromlen) {
00668         struct sockaddr_in sin;
00669 
00670         if (netconn_type(sock->conn) == NETCONN_TCP) {
00671           addr = &fromaddr;
00672           netconn_getaddr(sock->conn, addr, &port, 0);
00673         } else {
00674           addr = netbuf_fromaddr((struct netbuf *)buf);
00675           port = netbuf_fromport((struct netbuf *)buf);
00676         }
00677 
00678         memset(&sin, 0, sizeof(sin));
00679         sin.sin_len = sizeof(sin);
00680         sin.sin_family = AF_INET;
00681         sin.sin_port = htons(port);
00682         inet_addr_from_ipaddr(&sin.sin_addr, addr);
00683 
00684         if (*fromlen > sizeof(sin)) {
00685           *fromlen = sizeof(sin);
00686         }
00687 
00688         MEMCPY(from, &sin, *fromlen);
00689 
00690         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
00691         ip_addr_debug_print(SOCKETS_DEBUG, addr);
00692         LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
00693       } else {
00694 #if SOCKETS_DEBUG
00695         if (netconn_type(sock->conn) == NETCONN_TCP) {
00696           addr = &fromaddr;
00697           netconn_getaddr(sock->conn, addr, &port, 0);
00698         } else {
00699           addr = netbuf_fromaddr((struct netbuf *)buf);
00700           port = netbuf_fromport((struct netbuf *)buf);
00701         }
00702 
00703         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
00704         ip_addr_debug_print(SOCKETS_DEBUG, addr);
00705         LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
00706 #endif /*  SOCKETS_DEBUG */
00707       }
00708     }
00709 
00710     /* If we don't peek the incoming message... */
00711     if ((flags & MSG_PEEK) == 0) {
00712       /* If this is a TCP socket, check if there is data left in the
00713          buffer. If so, it should be saved in the sock structure for next
00714          time around. */
00715       if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {
00716         sock->lastdata = buf;
00717         sock->lastoffset += copylen;
00718         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
00719       } else {
00720         sock->lastdata = NULL;
00721         sock->lastoffset = 0;
00722         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
00723         if (netconn_type(sock->conn) == NETCONN_TCP) {
00724           pbuf_free((struct pbuf *)buf);
00725         } else {
00726           netbuf_delete((struct netbuf *)buf);
00727         }
00728       }
00729     }
00730   } while (!done);
00731 
00732   if (off > 0) {
00733     /* update receive window */
00734     netconn_recved(sock->conn, (u32_t)off);
00735   }
00736   sock_set_errno(sock, 0);
00737   return off;
00738 }
00739 
00740 int
00741 lwip_read(int s, void *mem, size_t len)
00742 {
00743   return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
00744 }
00745 
00746 int
00747 lwip_recv(int s, void *mem, size_t len, int flags)
00748 {
00749   return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
00750 }
00751 
00752 int
00753 lwip_send(int s, const void *data, size_t size, int flags)
00754 {
00755   struct lwip_sock *sock;
00756   err_t err;
00757   u8_t write_flags;
00758 
00759   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
00760                               s, data, size, flags));
00761 
00762   sock = get_socket(s);
00763   if (!sock) {
00764     return -1;
00765   }
00766 
00767   if (sock->conn->type != NETCONN_TCP) {
00768 #if (LWIP_UDP || LWIP_RAW)
00769     return lwip_sendto (s, data, size, flags, NULL, 0);
00770 #else /* (LWIP_UDP || LWIP_RAW) */
00771     sock_set_errno(sock, err_to_errno(ERR_ARG));
00772     return -1;
00773 #endif /* (LWIP_UDP || LWIP_RAW) */
00774   }
00775 
00776   if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) {
00777     if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) {
00778       /* too much data to ever send nonblocking! */
00779       sock_set_errno(sock, EMSGSIZE);
00780       return -1;
00781     }
00782   }
00783 
00784   write_flags = NETCONN_COPY |
00785     ((flags & MSG_MORE)     ? NETCONN_MORE      : 0) |
00786     ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
00787   err = netconn_write(sock->conn, data, size, write_flags);
00788 
00789   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size));
00790   sock_set_errno(sock, err_to_errno(err));
00791   return (err == ERR_OK ? (int)size : -1);
00792 }
00793 
00794 int
00795 lwip_sendto (int s, const void *data, size_t size, int flags,
00796        const struct sockaddr *to, socklen_t tolen)
00797 {
00798   struct lwip_sock *sock;
00799   err_t err;
00800   u16_t short_size;
00801   const struct sockaddr_in *to_in;
00802   u16_t remote_port;
00803 #if !LWIP_TCPIP_CORE_LOCKING
00804   struct netbuf buf;
00805 #endif
00806 
00807   sock = get_socket(s);
00808   if (!sock) {
00809     return -1;
00810   }
00811 
00812   if (sock->conn->type == NETCONN_TCP) {
00813 #if LWIP_TCP
00814     return lwip_send(s, data, size, flags);
00815 #else /* LWIP_TCP */
00816     LWIP_UNUSED_ARG(flags);
00817     sock_set_errno(sock, err_to_errno(ERR_ARG));
00818     return -1;
00819 #endif /* LWIP_TCP */
00820   }
00821 
00822   /* @todo: split into multiple sendto's? */
00823   LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
00824   short_size = (u16_t)size;
00825   LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
00826              ((tolen == sizeof(struct sockaddr_in)) &&
00827              ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))),
00828              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
00829   to_in = (const struct sockaddr_in *)(void*)to;
00830 
00831 #if LWIP_TCPIP_CORE_LOCKING
00832   /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */
00833   {
00834     struct pbuf* p;
00835     ip_addr_t *remote_addr;
00836 
00837 #if LWIP_NETIF_TX_SINGLE_PBUF
00838     p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM);
00839     if (p != NULL) {
00840 #if LWIP_CHECKSUM_ON_COPY
00841       u16_t chksum = 0;
00842       if (sock->conn->type != NETCONN_RAW) {
00843         chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size);
00844       } else
00845 #endif /* LWIP_CHECKSUM_ON_COPY */
00846       MEMCPY(p->payload, data, size);
00847 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
00848     p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF);
00849     if (p != NULL) {
00850       p->payload = (void*)data;
00851 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
00852 
00853       if (to_in != NULL) {
00854         inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr);
00855         remote_port = ntohs(to_in->sin_port);
00856       } else {
00857         remote_addr = &sock->conn->pcb.raw->remote_ip;
00858         if (sock->conn->type == NETCONN_RAW) {
00859           remote_port = 0;
00860         } else {
00861           remote_port = sock->conn->pcb.udp->remote_port;
00862         }
00863       }
00864 
00865       LOCK_TCPIP_CORE();
00866       if (sock->conn->type == NETCONN_RAW) {
00867         err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr);
00868       } else {
00869 #if LWIP_UDP
00870 #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF
00871         err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,
00872           remote_addr, remote_port, 1, chksum);
00873 #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
00874         err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p,
00875           remote_addr, remote_port);
00876 #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
00877 #else /* LWIP_UDP */
00878         err = ERR_ARG;
00879 #endif /* LWIP_UDP */
00880       }
00881       UNLOCK_TCPIP_CORE();
00882       
00883       pbuf_free(p);
00884     } else {
00885       err = ERR_MEM;
00886     }
00887   }
00888 #else /* LWIP_TCPIP_CORE_LOCKING */
00889   /* initialize a buffer */
00890   buf.p = buf.ptr = NULL;
00891 #if LWIP_CHECKSUM_ON_COPY
00892   buf.flags = 0;
00893 #endif /* LWIP_CHECKSUM_ON_COPY */
00894   if (to) {
00895     inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr);
00896     remote_port           = ntohs(to_in->sin_port);
00897     netbuf_fromport(&buf) = remote_port;
00898   } else {
00899     remote_port           = 0;
00900     ip_addr_set_any(&buf.addr);
00901     netbuf_fromport(&buf) = 0;
00902   }
00903 
00904   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
00905               s, data, short_size, flags));
00906   ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
00907   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
00908 
00909   /* make the buffer point to the data that should be sent */
00910 #if LWIP_NETIF_TX_SINGLE_PBUF
00911   /* Allocate a new netbuf and copy the data into it. */
00912   if (netbuf_alloc(&buf, short_size) == NULL) {
00913     err = ERR_MEM;
00914   } else {
00915 #if LWIP_CHECKSUM_ON_COPY
00916     if (sock->conn->type != NETCONN_RAW) {
00917       u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
00918       netbuf_set_chksum(&buf, chksum);
00919       err = ERR_OK;
00920     } else
00921 #endif /* LWIP_CHECKSUM_ON_COPY */
00922     {
00923       err = netbuf_take(&buf, data, short_size);
00924     }
00925   }
00926 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
00927   err = netbuf_ref(&buf, data, short_size);
00928 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
00929   if (err == ERR_OK) {
00930     /* send the data */
00931     err = netconn_send(sock->conn, &buf);
00932   }
00933 
00934   /* deallocated the buffer */
00935   netbuf_free(&buf);
00936 #endif /* LWIP_TCPIP_CORE_LOCKING */
00937   sock_set_errno(sock, err_to_errno(err));
00938   return (err == ERR_OK ? short_size : -1);
00939 }
00940 
00941 int
00942 lwip_socket(int domain, int type, int protocol)
00943 {
00944   struct netconn *conn;
00945   int i;
00946 
00947   LWIP_UNUSED_ARG(domain);
00948 
00949   /* create a netconn */
00950   switch (type) {
00951   case SOCK_RAW:
00952     conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
00953     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
00954                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
00955     break;
00956   case SOCK_DGRAM:
00957     conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?
00958                  NETCONN_UDPLITE : NETCONN_UDP, event_callback);
00959     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
00960                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
00961     break;
00962   case SOCK_STREAM:
00963     conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
00964     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
00965                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
00966     if (conn != NULL) {
00967       /* Prevent automatic window updates, we do this on our own! */
00968       netconn_set_noautorecved(conn, 1);
00969     }
00970     break;
00971   default:
00972     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
00973                                  domain, type, protocol));
00974     set_errno(EINVAL);
00975     return -1;
00976   }
00977 
00978   if (!conn) {
00979     LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
00980     set_errno(ENOBUFS);
00981     return -1;
00982   }
00983 
00984   i = alloc_socket(conn, 0);
00985 
00986   if (i == -1) {
00987     netconn_delete(conn);
00988     set_errno(ENFILE);
00989     return -1;
00990   }
00991   conn->socket = i;
00992   LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
00993   set_errno(0);
00994   return i;
00995 }
00996 
00997 int
00998 lwip_write(int s, const void *data, size_t size)
00999 {
01000   return lwip_send(s, data, size, 0);
01001 }
01002 
01003 /**
01004  * Go through the readset and writeset lists and see which socket of the sockets
01005  * set in the sets has events. On return, readset, writeset and exceptset have
01006  * the sockets enabled that had events.
01007  *
01008  * exceptset is not used for now!!!
01009  *
01010  * @param maxfdp1 the highest socket index in the sets
01011  * @param readset_in:    set of sockets to check for read events
01012  * @param writeset_in:   set of sockets to check for write events
01013  * @param exceptset_in:  set of sockets to check for error events
01014  * @param readset_out:   set of sockets that had read events
01015  * @param writeset_out:  set of sockets that had write events
01016  * @param exceptset_out: set os sockets that had error events
01017  * @return number of sockets that had events (read/write/exception) (>= 0)
01018  */
01019 static int
01020 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
01021              fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
01022 {
01023   int i, nready = 0;
01024   fd_set lreadset, lwriteset, lexceptset;
01025   struct lwip_sock *sock;
01026   SYS_ARCH_DECL_PROTECT(lev);
01027 
01028   FD_ZERO(&lreadset);
01029   FD_ZERO(&lwriteset);
01030   FD_ZERO(&lexceptset);
01031 
01032   /* Go through each socket in each list to count number of sockets which
01033      currently match */
01034   for(i = 0; i < maxfdp1; i++) {
01035     void* lastdata = NULL;
01036     s16_t rcvevent = 0;
01037     u16_t sendevent = 0;
01038     u16_t errevent = 0;
01039     /* First get the socket's status (protected)... */
01040     SYS_ARCH_PROTECT(lev);
01041     sock = tryget_socket(i);
01042     if (sock != NULL) {
01043       lastdata = sock->lastdata;
01044       rcvevent = sock->rcvevent;
01045       sendevent = sock->sendevent;
01046       errevent = sock->errevent;
01047     }
01048     SYS_ARCH_UNPROTECT(lev);
01049     /* ... then examine it: */
01050     /* See if netconn of this socket is ready for read */
01051     if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
01052       FD_SET(i, &lreadset);
01053       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
01054       nready++;
01055     }
01056     /* See if netconn of this socket is ready for write */
01057     if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
01058       FD_SET(i, &lwriteset);
01059       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
01060       nready++;
01061     }
01062     /* See if netconn of this socket had an error */
01063     if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
01064       FD_SET(i, &lexceptset);
01065       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
01066       nready++;
01067     }
01068   }
01069   /* copy local sets to the ones provided as arguments */
01070   *readset_out = lreadset;
01071   *writeset_out = lwriteset;
01072   *exceptset_out = lexceptset;
01073 
01074   LWIP_ASSERT("nready >= 0", nready >= 0);
01075   return nready;
01076 }
01077 
01078 /**
01079  * Processing exceptset is not yet implemented.
01080  */
01081 int
01082 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
01083             struct timeval *timeout)
01084 {
01085   u32_t waitres = 0;
01086   int nready;
01087   fd_set lreadset, lwriteset, lexceptset;
01088   u32_t msectimeout;
01089   struct lwip_select_cb select_cb;
01090   err_t err;
01091   int i;
01092   SYS_ARCH_DECL_PROTECT(lev);
01093 
01094   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
01095                   maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
01096                   timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
01097                   timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
01098 
01099   /* Go through each socket in each list to count number of sockets which
01100      currently match */
01101   nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
01102 
01103   /* If we don't have any current events, then suspend if we are supposed to */
01104   if (!nready) {
01105     if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
01106       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
01107       /* This is OK as the local fdsets are empty and nready is zero,
01108          or we would have returned earlier. */
01109       goto return_copy_fdsets;
01110     }
01111 
01112     /* None ready: add our semaphore to list:
01113        We don't actually need any dynamic memory. Our entry on the
01114        list is only valid while we are in this function, so it's ok
01115        to use local variables. */
01116 
01117     select_cb.next = NULL;
01118     select_cb.prev = NULL;
01119     select_cb.readset = readset;
01120     select_cb.writeset = writeset;
01121     select_cb.exceptset = exceptset;
01122     select_cb.sem_signalled = 0;
01123     err = sys_sem_new(&select_cb.sem, 0);
01124     if (err != ERR_OK) {
01125       /* failed to create semaphore */
01126       set_errno(ENOMEM);
01127       return -1;
01128     }
01129 
01130     /* Protect the select_cb_list */
01131     SYS_ARCH_PROTECT(lev);
01132 
01133     /* Put this select_cb on top of list */
01134     select_cb.next = select_cb_list;
01135     if (select_cb_list != NULL) {
01136       select_cb_list->prev = &select_cb;
01137     }
01138     select_cb_list = &select_cb;
01139     /* Increasing this counter tells even_callback that the list has changed. */
01140     select_cb_ctr++;
01141 
01142     /* Now we can safely unprotect */
01143     SYS_ARCH_UNPROTECT(lev);
01144 
01145     /* Increase select_waiting for each socket we are interested in */
01146     for(i = 0; i < maxfdp1; i++) {
01147       if ((readset && FD_ISSET(i, readset)) ||
01148           (writeset && FD_ISSET(i, writeset)) ||
01149           (exceptset && FD_ISSET(i, exceptset))) {
01150         struct lwip_sock *sock = tryget_socket(i);
01151         LWIP_ASSERT("sock != NULL", sock != NULL);
01152         SYS_ARCH_PROTECT(lev);
01153         sock->select_waiting++;
01154         LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
01155         SYS_ARCH_UNPROTECT(lev);
01156       }
01157     }
01158 
01159     /* Call lwip_selscan again: there could have been events between
01160        the last scan (whithout us on the list) and putting us on the list! */
01161     nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
01162     if (!nready) {
01163       /* Still none ready, just wait to be woken */
01164       if (timeout == 0) {
01165         /* Wait forever */
01166         msectimeout = 0;
01167       } else {
01168         msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
01169         if (msectimeout == 0) {
01170           /* Wait 1ms at least (0 means wait forever) */
01171           msectimeout = 1;
01172         }
01173       }
01174 
01175       waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
01176     }
01177     /* Increase select_waiting for each socket we are interested in */
01178     for(i = 0; i < maxfdp1; i++) {
01179       if ((readset && FD_ISSET(i, readset)) ||
01180           (writeset && FD_ISSET(i, writeset)) ||
01181           (exceptset && FD_ISSET(i, exceptset))) {
01182         struct lwip_sock *sock = tryget_socket(i);
01183         LWIP_ASSERT("sock != NULL", sock != NULL);
01184         SYS_ARCH_PROTECT(lev);
01185         sock->select_waiting--;
01186         LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0);
01187         SYS_ARCH_UNPROTECT(lev);
01188       }
01189     }
01190     /* Take us off the list */
01191     SYS_ARCH_PROTECT(lev);
01192     if (select_cb.next != NULL) {
01193       select_cb.next->prev = select_cb.prev;
01194     }
01195     if (select_cb_list == &select_cb) {
01196       LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
01197       select_cb_list = select_cb.next;
01198     } else {
01199       LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
01200       select_cb.prev->next = select_cb.next;
01201     }
01202     /* Increasing this counter tells even_callback that the list has changed. */
01203     select_cb_ctr++;
01204     SYS_ARCH_UNPROTECT(lev);
01205 
01206     sys_sem_free(&select_cb.sem);
01207     if (waitres == SYS_ARCH_TIMEOUT)  {
01208       /* Timeout */
01209       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
01210       /* This is OK as the local fdsets are empty and nready is zero,
01211          or we would have returned earlier. */
01212       goto return_copy_fdsets;
01213     }
01214 
01215     /* See what's set */
01216     nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
01217   }
01218 
01219   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
01220 return_copy_fdsets:
01221   set_errno(0);
01222   if (readset) {
01223     *readset = lreadset;
01224   }
01225   if (writeset) {
01226     *writeset = lwriteset;
01227   }
01228   if (exceptset) {
01229     *exceptset = lexceptset;
01230   }
01231 
01232 
01233   return nready;
01234 }
01235 
01236 /**
01237  * Callback registered in the netconn layer for each socket-netconn.
01238  * Processes recvevent (data available) and wakes up tasks waiting for select.
01239  */
01240 static void
01241 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
01242 {
01243   int s;
01244   struct lwip_sock *sock;
01245   struct lwip_select_cb *scb;
01246   int last_select_cb_ctr;
01247   SYS_ARCH_DECL_PROTECT(lev);
01248 
01249   LWIP_UNUSED_ARG(len);
01250 
01251   /* Get socket */
01252   if (conn) {
01253     s = conn->socket;
01254     if (s < 0) {
01255       /* Data comes in right away after an accept, even though
01256        * the server task might not have created a new socket yet.
01257        * Just count down (or up) if that's the case and we
01258        * will use the data later. Note that only receive events
01259        * can happen before the new socket is set up. */
01260       SYS_ARCH_PROTECT(lev);
01261       if (conn->socket < 0) {
01262         if (evt == NETCONN_EVT_RCVPLUS) {
01263           conn->socket--;
01264         }
01265         SYS_ARCH_UNPROTECT(lev);
01266         return;
01267       }
01268       s = conn->socket;
01269       SYS_ARCH_UNPROTECT(lev);
01270     }
01271 
01272     sock = get_socket(s);
01273     if (!sock) {
01274       return;
01275     }
01276   } else {
01277     return;
01278   }
01279 
01280   SYS_ARCH_PROTECT(lev);
01281   /* Set event as required */
01282   switch (evt) {
01283     case NETCONN_EVT_RCVPLUS:
01284       sock->rcvevent++;
01285       break;
01286     case NETCONN_EVT_RCVMINUS:
01287       sock->rcvevent--;
01288       break;
01289     case NETCONN_EVT_SENDPLUS:
01290       sock->sendevent = 1;
01291       break;
01292     case NETCONN_EVT_SENDMINUS:
01293       sock->sendevent = 0;
01294       break;
01295     case NETCONN_EVT_ERROR:
01296       sock->errevent = 1;
01297       break;
01298     default:
01299       LWIP_ASSERT("unknown event", 0);
01300       break;
01301   }
01302 
01303   if (sock->select_waiting == 0) {
01304     /* noone is waiting for this socket, no need to check select_cb_list */
01305     SYS_ARCH_UNPROTECT(lev);
01306     return;
01307   }
01308 
01309   /* Now decide if anyone is waiting for this socket */
01310   /* NOTE: This code goes through the select_cb_list list multiple times
01311      ONLY IF a select was actually waiting. We go through the list the number
01312      of waiting select calls + 1. This list is expected to be small. */
01313 
01314   /* At this point, SYS_ARCH is still protected! */
01315 again:
01316   for (scb = select_cb_list; scb != NULL; scb = scb->next) {
01317     if (scb->sem_signalled == 0) {
01318       /* semaphore not signalled yet */
01319       int do_signal = 0;
01320       /* Test this select call for our socket */
01321       if (sock->rcvevent > 0) {
01322         if (scb->readset && FD_ISSET(s, scb->readset)) {
01323           do_signal = 1;
01324         }
01325       }
01326       if (sock->sendevent != 0) {
01327         if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
01328           do_signal = 1;
01329         }
01330       }
01331       if (sock->errevent != 0) {
01332         if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
01333           do_signal = 1;
01334         }
01335       }
01336       if (do_signal) {
01337         scb->sem_signalled = 1;
01338         /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
01339            lead to the select thread taking itself off the list, invalidagin the semaphore. */
01340         sys_sem_signal(&scb->sem);
01341       }
01342     }
01343     /* unlock interrupts with each step */
01344     last_select_cb_ctr = select_cb_ctr;
01345     SYS_ARCH_UNPROTECT(lev);
01346     /* this makes sure interrupt protection time is short */
01347     SYS_ARCH_PROTECT(lev);
01348     if (last_select_cb_ctr != select_cb_ctr) {
01349       /* someone has changed select_cb_list, restart at the beginning */
01350       goto again;
01351     }
01352   }
01353   SYS_ARCH_UNPROTECT(lev);
01354 }
01355 
01356 /**
01357  * Unimplemented: Close one end of a full-duplex connection.
01358  * Currently, the full connection is closed.
01359  */
01360 int
01361 lwip_shutdown(int s, int how)
01362 {
01363   struct lwip_sock *sock;
01364   err_t err;
01365   u8_t shut_rx = 0, shut_tx = 0;
01366 
01367   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
01368 
01369   sock = get_socket(s);
01370   if (!sock) {
01371     return -1;
01372   }
01373 
01374   if (sock->conn != NULL) {
01375     if (netconn_type(sock->conn) != NETCONN_TCP) {
01376       sock_set_errno(sock, EOPNOTSUPP);
01377       return EOPNOTSUPP;
01378     }
01379   } else {
01380     sock_set_errno(sock, ENOTCONN);
01381     return ENOTCONN;
01382   }
01383 
01384   if (how == SHUT_RD) {
01385     shut_rx = 1;
01386   } else if (how == SHUT_WR) {
01387     shut_tx = 1;
01388   } else if(how == SHUT_RDWR) {
01389     shut_rx = 1;
01390     shut_tx = 1;
01391   } else {
01392     sock_set_errno(sock, EINVAL);
01393     return EINVAL;
01394   }
01395   err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
01396 
01397   sock_set_errno(sock, err_to_errno(err));
01398   return (err == ERR_OK ? 0 : -1);
01399 }
01400 
01401 static int
01402 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
01403 {
01404   struct lwip_sock *sock;
01405   struct sockaddr_in sin;
01406   ip_addr_t naddr;
01407 
01408   sock = get_socket(s);
01409   if (!sock) {
01410     return -1;
01411   }
01412 
01413   memset(&sin, 0, sizeof(sin));
01414   sin.sin_len = sizeof(sin);
01415   sin.sin_family = AF_INET;
01416 
01417   /* get the IP address and port */
01418   netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
01419 
01420   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
01421   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
01422   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port));
01423 
01424   sin.sin_port = htons(sin.sin_port);
01425   inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
01426 
01427   if (*namelen > sizeof(sin)) {
01428     *namelen = sizeof(sin);
01429   }
01430 
01431   MEMCPY(name, &sin, *namelen);
01432   sock_set_errno(sock, 0);
01433   return 0;
01434 }
01435 
01436 int
01437 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
01438 {
01439   return lwip_getaddrname(s, name, namelen, 0);
01440 }
01441 
01442 int
01443 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
01444 {
01445   return lwip_getaddrname(s, name, namelen, 1);
01446 }
01447 
01448 int
01449 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
01450 {
01451   err_t err = ERR_OK;
01452   struct lwip_sock *sock = get_socket(s);
01453   struct lwip_setgetsockopt_data data;
01454 
01455   if (!sock) {
01456     return -1;
01457   }
01458 
01459   if ((NULL == optval) || (NULL == optlen)) {
01460     sock_set_errno(sock, EFAULT);
01461     return -1;
01462   }
01463 
01464   /* Do length and type checks for the various options first, to keep it readable. */
01465   switch (level) {
01466    
01467 /* Level: SOL_SOCKET */
01468   case SOL_SOCKET:
01469     switch (optname) {
01470        
01471     case SO_ACCEPTCONN:
01472     case SO_BROADCAST:
01473     /* UNIMPL case SO_DEBUG: */
01474     /* UNIMPL case SO_DONTROUTE: */
01475     case SO_ERROR:
01476     case SO_KEEPALIVE:
01477     /* UNIMPL case SO_CONTIMEO: */
01478     /* UNIMPL case SO_SNDTIMEO: */
01479 #if LWIP_SO_RCVTIMEO
01480     case SO_RCVTIMEO:
01481 #endif /* LWIP_SO_RCVTIMEO */
01482 #if LWIP_SO_RCVBUF
01483     case SO_RCVBUF:
01484 #endif /* LWIP_SO_RCVBUF */
01485     /* UNIMPL case SO_OOBINLINE: */
01486     /* UNIMPL case SO_SNDBUF: */
01487     /* UNIMPL case SO_RCVLOWAT: */
01488     /* UNIMPL case SO_SNDLOWAT: */
01489 #if SO_REUSE
01490     case SO_REUSEADDR:
01491     case SO_REUSEPORT:
01492 #endif /* SO_REUSE */
01493     case SO_TYPE:
01494     /* UNIMPL case SO_USELOOPBACK: */
01495       if (*optlen < sizeof(int)) {
01496         err = EINVAL;
01497       }
01498       break;
01499 
01500     case SO_NO_CHECK:
01501       if (*optlen < sizeof(int)) {
01502         err = EINVAL;
01503       }
01504 #if LWIP_UDP
01505       if ((sock->conn->type != NETCONN_UDP) ||
01506           ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
01507         /* this flag is only available for UDP, not for UDP lite */
01508         err = EAFNOSUPPORT;
01509       }
01510 #endif /* LWIP_UDP */
01511       break;
01512 
01513     default:
01514       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
01515                                   s, optname));
01516       err = ENOPROTOOPT;
01517     }  /* switch (optname) */
01518     break;
01519                      
01520 /* Level: IPPROTO_IP */
01521   case IPPROTO_IP:
01522     switch (optname) {
01523     /* UNIMPL case IP_HDRINCL: */
01524     /* UNIMPL case IP_RCVDSTADDR: */
01525     /* UNIMPL case IP_RCVIF: */
01526     case IP_TTL:
01527     case IP_TOS:
01528       if (*optlen < sizeof(int)) {
01529         err = EINVAL;
01530       }
01531       break;
01532 #if LWIP_IGMP
01533     case IP_MULTICAST_TTL:
01534       if (*optlen < sizeof(u8_t)) {
01535         err = EINVAL;
01536       }
01537       break;
01538     case IP_MULTICAST_IF:
01539       if (*optlen < sizeof(struct in_addr)) {
01540         err = EINVAL;
01541       }
01542       break;
01543     case IP_MULTICAST_LOOP:
01544       if (*optlen < sizeof(u8_t)) {
01545         err = EINVAL;
01546       }
01547       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
01548         err = EAFNOSUPPORT;
01549       }
01550       break;
01551 #endif /* LWIP_IGMP */
01552 
01553     default:
01554       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
01555                                   s, optname));
01556       err = ENOPROTOOPT;
01557     }  /* switch (optname) */
01558     break;
01559          
01560 #if LWIP_TCP
01561 /* Level: IPPROTO_TCP */
01562   case IPPROTO_TCP:
01563     if (*optlen < sizeof(int)) {
01564       err = EINVAL;
01565       break;
01566     }
01567     
01568     /* If this is no TCP socket, ignore any options. */
01569     if (sock->conn->type != NETCONN_TCP)
01570       return 0;
01571 
01572     switch (optname) {
01573     case TCP_NODELAY:
01574     case TCP_KEEPALIVE:
01575 #if LWIP_TCP_KEEPALIVE
01576     case TCP_KEEPIDLE:
01577     case TCP_KEEPINTVL:
01578     case TCP_KEEPCNT:
01579 #endif /* LWIP_TCP_KEEPALIVE */
01580       break;
01581        
01582     default:
01583       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
01584                                   s, optname));
01585       err = ENOPROTOOPT;
01586     }  /* switch (optname) */
01587     break;
01588 #endif /* LWIP_TCP */
01589 #if LWIP_UDP && LWIP_UDPLITE
01590 /* Level: IPPROTO_UDPLITE */
01591   case IPPROTO_UDPLITE:
01592     if (*optlen < sizeof(int)) {
01593       err = EINVAL;
01594       break;
01595     }
01596     
01597     /* If this is no UDP lite socket, ignore any options. */
01598     if (sock->conn->type != NETCONN_UDPLITE) {
01599       return 0;
01600     }
01601 
01602     switch (optname) {
01603     case UDPLITE_SEND_CSCOV:
01604     case UDPLITE_RECV_CSCOV:
01605       break;
01606        
01607     default:
01608       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
01609                                   s, optname));
01610       err = ENOPROTOOPT;
01611     }  /* switch (optname) */
01612     break;
01613 #endif /* LWIP_UDP && LWIP_UDPLITE*/
01614 /* UNDEFINED LEVEL */
01615   default:
01616       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
01617                                   s, level, optname));
01618       err = ENOPROTOOPT;
01619   }  /* switch */
01620 
01621    
01622   if (err != ERR_OK) {
01623     sock_set_errno(sock, err);
01624     return -1;
01625   }
01626 
01627   /* Now do the actual option processing */
01628   data.sock = sock;
01629 #ifdef LWIP_DEBUG
01630   data.s = s;
01631 #endif /* LWIP_DEBUG */
01632   data.level = level;
01633   data.optname = optname;
01634   data.optval = optval;
01635   data.optlen = optlen;
01636   data.err = err;
01637   tcpip_callback(lwip_getsockopt_internal, &data);
01638   sys_arch_sem_wait(&sock->conn->op_completed, 0);
01639   /* maybe lwip_getsockopt_internal has changed err */
01640   err = data.err;
01641 
01642   sock_set_errno(sock, err);
01643   return err ? -1 : 0;
01644 }
01645 
01646 static void
01647 lwip_getsockopt_internal(void *arg)
01648 {
01649   struct lwip_sock *sock;
01650 #ifdef LWIP_DEBUG
01651   int s;
01652 #endif /* LWIP_DEBUG */
01653   int level, optname;
01654   void *optval;
01655   struct lwip_setgetsockopt_data *data;
01656 
01657   LWIP_ASSERT("arg != NULL", arg != NULL);
01658 
01659   data = (struct lwip_setgetsockopt_data*)arg;
01660   sock = data->sock;
01661 #ifdef LWIP_DEBUG
01662   s = data->s;
01663 #endif /* LWIP_DEBUG */
01664   level = data->level;
01665   optname = data->optname;
01666   optval = data->optval;
01667 
01668   switch (level) {
01669 
01670 /* Level: SOL_SOCKET */
01671   case SOL_SOCKET:
01672     switch (optname) {
01673 
01674     /* The option flags */
01675     case SO_ACCEPTCONN:
01676     case SO_BROADCAST:
01677     /* UNIMPL case SO_DEBUG: */
01678     /* UNIMPL case SO_DONTROUTE: */
01679     case SO_KEEPALIVE:
01680     /* UNIMPL case SO_OOBINCLUDE: */
01681 #if SO_REUSE
01682     case SO_REUSEADDR:
01683     case SO_REUSEPORT:
01684 #endif /* SO_REUSE */
01685     /*case SO_USELOOPBACK: UNIMPL */
01686       *(int*)optval = sock->conn->pcb.ip->so_options & optname;
01687       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
01688                                   s, optname, (*(int*)optval?"on":"off")));
01689       break;
01690 
01691     case SO_TYPE:
01692       switch (NETCONNTYPE_GROUP(sock->conn->type)) {
01693       case NETCONN_RAW:
01694         *(int*)optval = SOCK_RAW;
01695         break;
01696       case NETCONN_TCP:
01697         *(int*)optval = SOCK_STREAM;
01698         break;
01699       case NETCONN_UDP:
01700         *(int*)optval = SOCK_DGRAM;
01701         break;
01702       default: /* unrecognized socket type */
01703         *(int*)optval = sock->conn->type;
01704         LWIP_DEBUGF(SOCKETS_DEBUG,
01705                     ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
01706                     s, *(int *)optval));
01707       }  /* switch (sock->conn->type) */
01708       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
01709                   s, *(int *)optval));
01710       break;
01711 
01712     case SO_ERROR:
01713       /* only overwrite ERR_OK or tempoary errors */
01714       if ((sock->err == 0) || (sock->err == EINPROGRESS)) {
01715         sock_set_errno(sock, err_to_errno(sock->conn->last_err));
01716       } 
01717       *(int *)optval = sock->err;
01718       sock->err = 0;
01719       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
01720                   s, *(int *)optval));
01721       break;
01722 
01723 #if LWIP_SO_RCVTIMEO
01724     case SO_RCVTIMEO:
01725       *(int *)optval = netconn_get_recvtimeout(sock->conn);
01726       break;
01727 #endif /* LWIP_SO_RCVTIMEO */
01728 #if LWIP_SO_RCVBUF
01729     case SO_RCVBUF:
01730       *(int *)optval = netconn_get_recvbufsize(sock->conn);
01731       break;
01732 #endif /* LWIP_SO_RCVBUF */
01733 #if LWIP_UDP
01734     case SO_NO_CHECK:
01735       *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
01736       break;
01737 #endif /* LWIP_UDP*/
01738     default:
01739       LWIP_ASSERT("unhandled optname", 0);
01740       break;
01741     }  /* switch (optname) */
01742     break;
01743 
01744 /* Level: IPPROTO_IP */
01745   case IPPROTO_IP:
01746     switch (optname) {
01747     case IP_TTL:
01748       *(int*)optval = sock->conn->pcb.ip->ttl;
01749       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
01750                   s, *(int *)optval));
01751       break;
01752     case IP_TOS:
01753       *(int*)optval = sock->conn->pcb.ip->tos;
01754       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
01755                   s, *(int *)optval));
01756       break;
01757 #if LWIP_IGMP
01758     case IP_MULTICAST_TTL:
01759       *(u8_t*)optval = sock->conn->pcb.ip->ttl;
01760       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
01761                   s, *(int *)optval));
01762       break;
01763     case IP_MULTICAST_IF:
01764       inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip);
01765       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
01766                   s, *(u32_t *)optval));
01767       break;
01768     case IP_MULTICAST_LOOP:
01769       if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
01770         *(u8_t*)optval = 1;
01771       } else {
01772         *(u8_t*)optval = 0;
01773       }
01774       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
01775                   s, *(int *)optval));
01776       break;
01777 #endif /* LWIP_IGMP */
01778     default:
01779       LWIP_ASSERT("unhandled optname", 0);
01780       break;
01781     }  /* switch (optname) */
01782     break;
01783 
01784 #if LWIP_TCP
01785 /* Level: IPPROTO_TCP */
01786   case IPPROTO_TCP:
01787     switch (optname) {
01788     case TCP_NODELAY:
01789       *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
01790       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
01791                   s, (*(int*)optval)?"on":"off") );
01792       break;
01793     case TCP_KEEPALIVE:
01794       *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
01795       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",
01796                   s, *(int *)optval));
01797       break;
01798 
01799 #if LWIP_TCP_KEEPALIVE
01800     case TCP_KEEPIDLE:
01801       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
01802       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",
01803                   s, *(int *)optval));
01804       break;
01805     case TCP_KEEPINTVL:
01806       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
01807       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",
01808                   s, *(int *)optval));
01809       break;
01810     case TCP_KEEPCNT:
01811       *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
01812       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",
01813                   s, *(int *)optval));
01814       break;
01815 #endif /* LWIP_TCP_KEEPALIVE */
01816     default:
01817       LWIP_ASSERT("unhandled optname", 0);
01818       break;
01819     }  /* switch (optname) */
01820     break;
01821 #endif /* LWIP_TCP */
01822 #if LWIP_UDP && LWIP_UDPLITE
01823   /* Level: IPPROTO_UDPLITE */
01824   case IPPROTO_UDPLITE:
01825     switch (optname) {
01826     case UDPLITE_SEND_CSCOV:
01827       *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
01828       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
01829                   s, (*(int*)optval)) );
01830       break;
01831     case UDPLITE_RECV_CSCOV:
01832       *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
01833       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
01834                   s, (*(int*)optval)) );
01835       break;
01836     default:
01837       LWIP_ASSERT("unhandled optname", 0);
01838       break;
01839     }  /* switch (optname) */
01840     break;
01841 #endif /* LWIP_UDP */
01842   default:
01843     LWIP_ASSERT("unhandled level", 0);
01844     break;
01845   } /* switch (level) */
01846   sys_sem_signal(&sock->conn->op_completed);
01847 }
01848 
01849 int
01850 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
01851 {
01852   struct lwip_sock *sock = get_socket(s);
01853   err_t err = ERR_OK;
01854   struct lwip_setgetsockopt_data data;
01855 
01856   if (!sock) {
01857     return -1;
01858   }
01859 
01860   if (NULL == optval) {
01861     sock_set_errno(sock, EFAULT);
01862     return -1;
01863   }
01864 
01865   /* Do length and type checks for the various options first, to keep it readable. */
01866   switch (level) {
01867 
01868 /* Level: SOL_SOCKET */
01869   case SOL_SOCKET:
01870     switch (optname) {
01871 
01872     case SO_BROADCAST:
01873     /* UNIMPL case SO_DEBUG: */
01874     /* UNIMPL case SO_DONTROUTE: */
01875     case SO_KEEPALIVE:
01876     /* UNIMPL case case SO_CONTIMEO: */
01877     /* UNIMPL case case SO_SNDTIMEO: */
01878 #if LWIP_SO_RCVTIMEO
01879     case SO_RCVTIMEO:
01880 #endif /* LWIP_SO_RCVTIMEO */
01881 #if LWIP_SO_RCVBUF
01882     case SO_RCVBUF:
01883 #endif /* LWIP_SO_RCVBUF */
01884     /* UNIMPL case SO_OOBINLINE: */
01885     /* UNIMPL case SO_SNDBUF: */
01886     /* UNIMPL case SO_RCVLOWAT: */
01887     /* UNIMPL case SO_SNDLOWAT: */
01888 #if SO_REUSE
01889     case SO_REUSEADDR:
01890     case SO_REUSEPORT:
01891 #endif /* SO_REUSE */
01892     /* UNIMPL case SO_USELOOPBACK: */
01893       if (optlen < sizeof(int)) {
01894         err = EINVAL;
01895       }
01896       break;
01897     case SO_NO_CHECK:
01898       if (optlen < sizeof(int)) {
01899         err = EINVAL;
01900       }
01901 #if LWIP_UDP
01902       if ((sock->conn->type != NETCONN_UDP) ||
01903           ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
01904         /* this flag is only available for UDP, not for UDP lite */
01905         err = EAFNOSUPPORT;
01906       }
01907 #endif /* LWIP_UDP */
01908       break;
01909     default:
01910       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
01911                   s, optname));
01912       err = ENOPROTOOPT;
01913     }  /* switch (optname) */
01914     break;
01915 
01916 /* Level: IPPROTO_IP */
01917   case IPPROTO_IP:
01918     switch (optname) {
01919     /* UNIMPL case IP_HDRINCL: */
01920     /* UNIMPL case IP_RCVDSTADDR: */
01921     /* UNIMPL case IP_RCVIF: */
01922     case IP_TTL:
01923     case IP_TOS:
01924       if (optlen < sizeof(int)) {
01925         err = EINVAL;
01926       }
01927       break;
01928 #if LWIP_IGMP
01929     case IP_MULTICAST_TTL:
01930       if (optlen < sizeof(u8_t)) {
01931         err = EINVAL;
01932       }
01933       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
01934         err = EAFNOSUPPORT;
01935       }
01936       break;
01937     case IP_MULTICAST_IF:
01938       if (optlen < sizeof(struct in_addr)) {
01939         err = EINVAL;
01940       }
01941       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
01942         err = EAFNOSUPPORT;
01943       }
01944       break;
01945     case IP_MULTICAST_LOOP:
01946       if (optlen < sizeof(u8_t)) {
01947         err = EINVAL;
01948       }
01949       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
01950         err = EAFNOSUPPORT;
01951       }
01952       break;
01953     case IP_ADD_MEMBERSHIP:
01954     case IP_DROP_MEMBERSHIP:
01955       if (optlen < sizeof(struct ip_mreq)) {
01956         err = EINVAL;
01957       }
01958       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
01959         err = EAFNOSUPPORT;
01960       }
01961       break;
01962 #endif /* LWIP_IGMP */
01963       default:
01964         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
01965                     s, optname));
01966         err = ENOPROTOOPT;
01967     }  /* switch (optname) */
01968     break;
01969 
01970 #if LWIP_TCP
01971 /* Level: IPPROTO_TCP */
01972   case IPPROTO_TCP:
01973     if (optlen < sizeof(int)) {
01974       err = EINVAL;
01975       break;
01976     }
01977 
01978     /* If this is no TCP socket, ignore any options. */
01979     if (sock->conn->type != NETCONN_TCP)
01980       return 0;
01981 
01982     switch (optname) {
01983     case TCP_NODELAY:
01984     case TCP_KEEPALIVE:
01985 #if LWIP_TCP_KEEPALIVE
01986     case TCP_KEEPIDLE:
01987     case TCP_KEEPINTVL:
01988     case TCP_KEEPCNT:
01989 #endif /* LWIP_TCP_KEEPALIVE */
01990       break;
01991 
01992     default:
01993       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
01994                   s, optname));
01995       err = ENOPROTOOPT;
01996     }  /* switch (optname) */
01997     break;
01998 #endif /* LWIP_TCP */
01999 #if LWIP_UDP && LWIP_UDPLITE
02000 /* Level: IPPROTO_UDPLITE */
02001   case IPPROTO_UDPLITE:
02002     if (optlen < sizeof(int)) {
02003       err = EINVAL;
02004       break;
02005     }
02006 
02007     /* If this is no UDP lite socket, ignore any options. */
02008     if (sock->conn->type != NETCONN_UDPLITE)
02009       return 0;
02010 
02011     switch (optname) {
02012     case UDPLITE_SEND_CSCOV:
02013     case UDPLITE_RECV_CSCOV:
02014       break;
02015 
02016     default:
02017       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
02018                   s, optname));
02019       err = ENOPROTOOPT;
02020     }  /* switch (optname) */
02021     break;
02022 #endif /* LWIP_UDP && LWIP_UDPLITE */
02023 /* UNDEFINED LEVEL */
02024   default:
02025     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
02026                 s, level, optname));
02027     err = ENOPROTOOPT;
02028   }  /* switch (level) */
02029 
02030 
02031   if (err != ERR_OK) {
02032     sock_set_errno(sock, err);
02033     return -1;
02034   }
02035 
02036 
02037   /* Now do the actual option processing */
02038   data.sock = sock;
02039 #ifdef LWIP_DEBUG
02040   data.s = s;
02041 #endif /* LWIP_DEBUG */
02042   data.level = level;
02043   data.optname = optname;
02044   data.optval = (void*)optval;
02045   data.optlen = &optlen;
02046   data.err = err;
02047   tcpip_callback(lwip_setsockopt_internal, &data);
02048   sys_arch_sem_wait(&sock->conn->op_completed, 0);
02049   /* maybe lwip_setsockopt_internal has changed err */
02050   err = data.err;
02051 
02052   sock_set_errno(sock, err);
02053   return err ? -1 : 0;
02054 }
02055 
02056 static void
02057 lwip_setsockopt_internal(void *arg)
02058 {
02059   struct lwip_sock *sock;
02060 #ifdef LWIP_DEBUG
02061   int s;
02062 #endif /* LWIP_DEBUG */
02063   int level, optname;
02064   const void *optval;
02065   struct lwip_setgetsockopt_data *data;
02066 
02067   LWIP_ASSERT("arg != NULL", arg != NULL);
02068 
02069   data = (struct lwip_setgetsockopt_data*)arg;
02070   sock = data->sock;
02071 #ifdef LWIP_DEBUG
02072   s = data->s;
02073 #endif /* LWIP_DEBUG */
02074   level = data->level;
02075   optname = data->optname;
02076   optval = data->optval;
02077 
02078   switch (level) {
02079 
02080 /* Level: SOL_SOCKET */
02081   case SOL_SOCKET:
02082     switch (optname) {
02083 
02084     /* The option flags */
02085     case SO_BROADCAST:
02086     /* UNIMPL case SO_DEBUG: */
02087     /* UNIMPL case SO_DONTROUTE: */
02088     case SO_KEEPALIVE:
02089     /* UNIMPL case SO_OOBINCLUDE: */
02090 #if SO_REUSE
02091     case SO_REUSEADDR:
02092     case SO_REUSEPORT:
02093 #endif /* SO_REUSE */
02094     /* UNIMPL case SO_USELOOPBACK: */
02095       if (*(int*)optval) {
02096         sock->conn->pcb.ip->so_options |= optname;
02097       } else {
02098         sock->conn->pcb.ip->so_options &= ~optname;
02099       }
02100       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
02101                   s, optname, (*(int*)optval?"on":"off")));
02102       break;
02103 #if LWIP_SO_RCVTIMEO
02104     case SO_RCVTIMEO:
02105       netconn_set_recvtimeout(sock->conn, *(int*)optval);
02106       break;
02107 #endif /* LWIP_SO_RCVTIMEO */
02108 #if LWIP_SO_RCVBUF
02109     case SO_RCVBUF:
02110       netconn_set_recvbufsize(sock->conn, *(int*)optval);
02111       break;
02112 #endif /* LWIP_SO_RCVBUF */
02113 #if LWIP_UDP
02114     case SO_NO_CHECK:
02115       if (*(int*)optval) {
02116         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
02117       } else {
02118         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
02119       }
02120       break;
02121 #endif /* LWIP_UDP */
02122     default:
02123       LWIP_ASSERT("unhandled optname", 0);
02124       break;
02125     }  /* switch (optname) */
02126     break;
02127 
02128 /* Level: IPPROTO_IP */
02129   case IPPROTO_IP:
02130     switch (optname) {
02131     case IP_TTL:
02132       sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
02133       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
02134                   s, sock->conn->pcb.ip->ttl));
02135       break;
02136     case IP_TOS:
02137       sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
02138       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
02139                   s, sock->conn->pcb.ip->tos));
02140       break;
02141 #if LWIP_IGMP
02142     case IP_MULTICAST_TTL:
02143       sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);
02144       break;
02145     case IP_MULTICAST_IF:
02146       inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval);
02147       break;
02148     case IP_MULTICAST_LOOP:
02149       if (*(u8_t*)optval) {
02150         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
02151       } else {
02152         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
02153       }
02154       break;
02155     case IP_ADD_MEMBERSHIP:
02156     case IP_DROP_MEMBERSHIP:
02157       {
02158         /* If this is a TCP or a RAW socket, ignore these options. */
02159         struct ip_mreq *imr = (struct ip_mreq *)optval;
02160         ip_addr_t if_addr;
02161         ip_addr_t multi_addr;
02162         inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
02163         inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
02164         if(optname == IP_ADD_MEMBERSHIP){
02165           data->err = igmp_joingroup(&if_addr, &multi_addr);
02166         } else {
02167           data->err = igmp_leavegroup(&if_addr, &multi_addr);
02168         }
02169         if(data->err != ERR_OK) {
02170           data->err = EADDRNOTAVAIL;
02171         }
02172       }
02173       break;
02174 #endif /* LWIP_IGMP */
02175     default:
02176       LWIP_ASSERT("unhandled optname", 0);
02177       break;
02178     }  /* switch (optname) */
02179     break;
02180 
02181 #if LWIP_TCP
02182 /* Level: IPPROTO_TCP */
02183   case IPPROTO_TCP:
02184     switch (optname) {
02185     case TCP_NODELAY:
02186       if (*(int*)optval) {
02187         tcp_nagle_disable(sock->conn->pcb.tcp);
02188       } else {
02189         tcp_nagle_enable(sock->conn->pcb.tcp);
02190       }
02191       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
02192                   s, (*(int *)optval)?"on":"off") );
02193       break;
02194     case TCP_KEEPALIVE:
02195       sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
02196       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
02197                   s, sock->conn->pcb.tcp->keep_idle));
02198       break;
02199 
02200 #if LWIP_TCP_KEEPALIVE
02201     case TCP_KEEPIDLE:
02202       sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
02203       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
02204                   s, sock->conn->pcb.tcp->keep_idle));
02205       break;
02206     case TCP_KEEPINTVL:
02207       sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
02208       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
02209                   s, sock->conn->pcb.tcp->keep_intvl));
02210       break;
02211     case TCP_KEEPCNT:
02212       sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
02213       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
02214                   s, sock->conn->pcb.tcp->keep_cnt));
02215       break;
02216 #endif /* LWIP_TCP_KEEPALIVE */
02217     default:
02218       LWIP_ASSERT("unhandled optname", 0);
02219       break;
02220     }  /* switch (optname) */
02221     break;
02222 #endif /* LWIP_TCP*/
02223 #if LWIP_UDP && LWIP_UDPLITE
02224   /* Level: IPPROTO_UDPLITE */
02225   case IPPROTO_UDPLITE:
02226     switch (optname) {
02227     case UDPLITE_SEND_CSCOV:
02228       if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
02229         /* don't allow illegal values! */
02230         sock->conn->pcb.udp->chksum_len_tx = 8;
02231       } else {
02232         sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;
02233       }
02234       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
02235                   s, (*(int*)optval)) );
02236       break;
02237     case UDPLITE_RECV_CSCOV:
02238       if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
02239         /* don't allow illegal values! */
02240         sock->conn->pcb.udp->chksum_len_rx = 8;
02241       } else {
02242         sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;
02243       }
02244       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
02245                   s, (*(int*)optval)) );
02246       break;
02247     default:
02248       LWIP_ASSERT("unhandled optname", 0);
02249       break;
02250     }  /* switch (optname) */
02251     break;
02252 #endif /* LWIP_UDP */
02253   default:
02254     LWIP_ASSERT("unhandled level", 0);
02255     break;
02256   }  /* switch (level) */
02257   sys_sem_signal(&sock->conn->op_completed);
02258 }
02259 
02260 int
02261 lwip_ioctl(int s, long cmd, void *argp)
02262 {
02263   struct lwip_sock *sock = get_socket(s);
02264   u8_t val;
02265 #if LWIP_SO_RCVBUF
02266   u16_t buflen = 0;
02267   s16_t recv_avail;
02268 #endif /* LWIP_SO_RCVBUF */
02269 
02270   if (!sock) {
02271     return -1;
02272   }
02273 
02274   switch (cmd) {
02275 #if LWIP_SO_RCVBUF
02276   case FIONREAD:
02277     if (!argp) {
02278       sock_set_errno(sock, EINVAL);
02279       return -1;
02280     }
02281 
02282     SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
02283     if (recv_avail < 0) {
02284       recv_avail = 0;
02285     }
02286     *((u16_t*)argp) = (u16_t)recv_avail;
02287 
02288     /* Check if there is data left from the last recv operation. /maq 041215 */
02289     if (sock->lastdata) {
02290       struct pbuf *p = (struct pbuf *)sock->lastdata;
02291       if (netconn_type(sock->conn) != NETCONN_TCP) {
02292         p = ((struct netbuf *)p)->p;
02293       }
02294       buflen = p->tot_len;
02295       buflen -= sock->lastoffset;
02296 
02297       *((u16_t*)argp) += buflen;
02298     }
02299 
02300     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
02301     sock_set_errno(sock, 0);
02302     return 0;
02303 #endif /* LWIP_SO_RCVBUF */
02304 
02305   case FIONBIO:
02306     val = 0;
02307     if (argp && *(u32_t*)argp) {
02308       val = 1;
02309     }
02310     netconn_set_nonblocking(sock->conn, val);
02311     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
02312     sock_set_errno(sock, 0);
02313     return 0;
02314 
02315   default:
02316     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
02317     sock_set_errno(sock, ENOSYS); /* not yet implemented */
02318     return -1;
02319   } /* switch (cmd) */
02320 }
02321 
02322 /** A minimal implementation of fcntl.
02323  * Currently only the commands F_GETFL and F_SETFL are implemented.
02324  * Only the flag O_NONBLOCK is implemented.
02325  */
02326 int
02327 lwip_fcntl(int s, int cmd, int val)
02328 {
02329   struct lwip_sock *sock = get_socket(s);
02330   int ret = -1;
02331 
02332   if (!sock || !sock->conn) {
02333     return -1;
02334   }
02335 
02336   switch (cmd) {
02337   case F_GETFL:
02338     ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
02339     break;
02340   case F_SETFL:
02341     if ((val & ~O_NONBLOCK) == 0) {
02342       /* only O_NONBLOCK, all other bits are zero */
02343       netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
02344       ret = 0;
02345     }
02346     break;
02347   default:
02348     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
02349     break;
02350   }
02351   return ret;
02352 }
02353 
02354 #endif /* LWIP_SOCKET */