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