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