V1

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