SAMV71 Xplained Ultra Software Package 1.0

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