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