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