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.
Dependents: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
lwip_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 /** 00042 * @defgroup socket Socket API 00043 * @ingroup threadsafe_api 00044 * BSD-style socket API.\n 00045 * Thread-safe, to be called from non-TCPIP threads only.\n 00046 * Can be activated by defining LWIP_SOCKET to 1.\n 00047 * Header is in posix/sys/socket.h\b 00048 */ 00049 00050 #include "lwip/opt.h" 00051 00052 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ 00053 00054 #include "lwip/sockets.h" 00055 #include "lwip/api.h" 00056 #include "lwip/sys.h" 00057 #include "lwip/igmp.h" 00058 #include "lwip/inet.h" 00059 #include "lwip/tcp.h" 00060 #include "lwip/raw.h" 00061 #include "lwip/udp.h" 00062 #include "lwip/memp.h" 00063 #include "lwip/pbuf.h" 00064 #include "lwip/priv/tcpip_priv.h" 00065 #if LWIP_CHECKSUM_ON_COPY 00066 #include "lwip/inet_chksum.h" 00067 #endif 00068 00069 #include <string.h> 00070 00071 /* If the netconn API is not required publicly, then we include the necessary 00072 files here to get the implementation */ 00073 #if !LWIP_NETCONN 00074 #undef LWIP_NETCONN 00075 #define LWIP_NETCONN 1 00076 #include "api_msg.c" 00077 #include "api_lib.c" 00078 #include "netbuf.c" 00079 #undef LWIP_NETCONN 00080 #define LWIP_NETCONN 0 00081 #endif 00082 00083 #if LWIP_IPV4 00084 #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \ 00085 (sin)->sin_len = sizeof(struct sockaddr_in); \ 00086 (sin)->sin_family = AF_INET; \ 00087 (sin)->sin_port = htons((port)); \ 00088 inet_addr_from_ipaddr(&(sin)->sin_addr, ipaddr); \ 00089 memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) 00090 #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \ 00091 inet_addr_to_ipaddr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \ 00092 (port) = ntohs((sin)->sin_port); }while(0) 00093 #endif /* LWIP_IPV4 */ 00094 00095 #if LWIP_IPV6 00096 #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \ 00097 (sin6)->sin6_len = sizeof(struct sockaddr_in6); \ 00098 (sin6)->sin6_family = AF_INET6; \ 00099 (sin6)->sin6_port = htons((port)); \ 00100 (sin6)->sin6_flowinfo = 0; \ 00101 inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \ 00102 (sin6)->sin6_scope_id = 0; }while(0) 00103 #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \ 00104 inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \ 00105 (port) = ntohs((sin6)->sin6_port); }while(0) 00106 #endif /* LWIP_IPV6 */ 00107 00108 #if LWIP_IPV4 && LWIP_IPV6 00109 static void sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* ipaddr, u16_t* port); 00110 00111 #define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \ 00112 ((namelen) == sizeof(struct sockaddr_in6))) 00113 #define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \ 00114 ((name)->sa_family == AF_INET6)) 00115 #define SOCK_ADDR_TYPE_MATCH(name, sock) \ 00116 ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \ 00117 (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type)))) 00118 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \ 00119 if (IP_IS_V6(ipaddr)) { \ 00120 IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \ 00121 } else { \ 00122 IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \ 00123 } } while(0) 00124 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port)) 00125 #define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \ 00126 (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6)) 00127 #elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ 00128 #define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in6)) 00129 #define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET6) 00130 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1 00131 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ 00132 IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port) 00133 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ 00134 SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port) 00135 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) 00136 #else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */ 00137 #define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in)) 00138 #define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET) 00139 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1 00140 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ 00141 IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port) 00142 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ 00143 SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port) 00144 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) 00145 #endif /* LWIP_IPV6 */ 00146 00147 #define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \ 00148 IS_SOCK_ADDR_TYPE_VALID(name)) 00149 #define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \ 00150 SOCK_ADDR_TYPE_MATCH(name, sock)) 00151 #define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0) 00152 00153 00154 #define LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype) do { if ((optlen) < sizeof(opttype)) { return EINVAL; }}while(0) 00155 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \ 00156 LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \ 00157 if ((sock)->conn == NULL) { return EINVAL; } }while(0) 00158 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \ 00159 LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \ 00160 if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { return EINVAL; } }while(0) 00161 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \ 00162 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \ 00163 if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { return ENOPROTOOPT; } }while(0) 00164 00165 00166 #define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name) API_VAR_REF(name) 00167 #define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name) 00168 #define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name) API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name) 00169 #if LWIP_MPU_COMPATIBLE 00170 #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \ 00171 name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \ 00172 if (name == NULL) { \ 00173 sock_set_errno(sock, ENOMEM); \ 00174 return -1; \ 00175 } }while(0) 00176 #else /* LWIP_MPU_COMPATIBLE */ 00177 #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) 00178 #endif /* LWIP_MPU_COMPATIBLE */ 00179 00180 #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD 00181 #define LWIP_SO_SNDRCVTIMEO_OPTTYPE int 00182 #define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val)) 00183 #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((s32_t)*(const int*)(optval)) 00184 #else 00185 #define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval 00186 #define LWIP_SO_SNDRCVTIMEO_SET(optval, val) do { \ 00187 s32_t loc = (val); \ 00188 ((struct timeval *)(optval))->tv_sec = (loc) / 1000U; \ 00189 ((struct timeval *)(optval))->tv_usec = ((loc) % 1000U) * 1000U; }while(0) 00190 #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000U) + (((const struct timeval *)(optval))->tv_usec / 1000U)) 00191 #endif 00192 00193 #define NUM_SOCKETS MEMP_NUM_NETCONN 00194 00195 /** This is overridable for the rare case where more than 255 threads 00196 * select on the same socket... 00197 */ 00198 #ifndef SELWAIT_T 00199 #define SELWAIT_T u8_t 00200 #endif 00201 00202 /** Contains all internal pointers and states used for a socket */ 00203 struct lwip_sock { 00204 /** sockets currently are built on netconns, each socket has one netconn */ 00205 struct netconn *conn; 00206 /** data that was left from the previous read */ 00207 void *lastdata; 00208 /** offset in the data that was left from the previous read */ 00209 u16_t lastoffset; 00210 /** number of times data was received, set by event_callback(), 00211 tested by the receive and select functions */ 00212 s16_t rcvevent; 00213 /** number of times data was ACKed (free send buffer), set by event_callback(), 00214 tested by select */ 00215 u16_t sendevent; 00216 /** error happened for this socket, set by event_callback(), tested by select */ 00217 u16_t errevent; 00218 /** last error that occurred on this socket (in fact, all our errnos fit into an u8_t) */ 00219 u8_t err; 00220 /** counter of how many threads are waiting for this socket using select */ 00221 SELWAIT_T select_waiting; 00222 }; 00223 00224 #if LWIP_NETCONN_SEM_PER_THREAD 00225 #define SELECT_SEM_T sys_sem_t* 00226 #define SELECT_SEM_PTR(sem) (sem) 00227 #else /* LWIP_NETCONN_SEM_PER_THREAD */ 00228 #define SELECT_SEM_T sys_sem_t 00229 #define SELECT_SEM_PTR(sem) (&(sem)) 00230 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 00231 00232 /** Description for a task waiting in select */ 00233 struct lwip_select_cb { 00234 /** Pointer to the next waiting task */ 00235 struct lwip_select_cb *next; 00236 /** Pointer to the previous waiting task */ 00237 struct lwip_select_cb *prev; 00238 /** readset passed to select */ 00239 fd_set *readset; 00240 /** writeset passed to select */ 00241 fd_set *writeset; 00242 /** unimplemented: exceptset passed to select */ 00243 fd_set *exceptset; 00244 /** don't signal the same semaphore twice: set to 1 when signalled */ 00245 int sem_signalled; 00246 /** semaphore to wake up a task waiting for select */ 00247 SELECT_SEM_T sem; 00248 }; 00249 00250 /** A struct sockaddr replacement that has the same alignment as sockaddr_in/ 00251 * sockaddr_in6 if instantiated. 00252 */ 00253 union sockaddr_aligned { 00254 struct sockaddr sa; 00255 #if LWIP_IPV6 00256 struct sockaddr_in6 sin6; 00257 #endif /* LWIP_IPV6 */ 00258 #if LWIP_IPV4 00259 struct sockaddr_in sin; 00260 #endif /* LWIP_IPV4 */ 00261 }; 00262 00263 #if LWIP_IGMP 00264 /* Define the number of IPv4 multicast memberships, default is one per socket */ 00265 #ifndef LWIP_SOCKET_MAX_MEMBERSHIPS 00266 #define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS 00267 #endif 00268 00269 /* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when 00270 a socket is closed */ 00271 struct lwip_socket_multicast_pair { 00272 /** the socket (+1 to not require initialization) */ 00273 int sa; 00274 /** the interface address */ 00275 ip4_addr_t if_addr; 00276 /** the group address */ 00277 ip4_addr_t multi_addr; 00278 }; 00279 00280 struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS]; 00281 00282 static int lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); 00283 static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); 00284 static void lwip_socket_drop_registered_memberships(int s); 00285 #endif /* LWIP_IGMP */ 00286 00287 /** The global array of available sockets */ 00288 static struct lwip_sock sockets[NUM_SOCKETS]; 00289 /** The global list of tasks waiting for select */ 00290 static struct lwip_select_cb *select_cb_list; 00291 /** This counter is increased from lwip_select when the list is changed 00292 and checked in event_callback to see if it has changed. */ 00293 static volatile int select_cb_ctr; 00294 00295 /** Table to quickly map an lwIP error (err_t) to a socket error 00296 * by using -err as an index */ 00297 static const int err_to_errno_table[] = { 00298 0, /* ERR_OK 0 No error, everything OK. */ 00299 ENOMEM, /* ERR_MEM -1 Out of memory error. */ 00300 ENOBUFS, /* ERR_BUF -2 Buffer error. */ 00301 EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ 00302 EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ 00303 EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ 00304 EINVAL, /* ERR_VAL -6 Illegal value. */ 00305 EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ 00306 EADDRINUSE, /* ERR_USE -8 Address in use. */ 00307 EALREADY, /* ERR_ALREADY -9 Already connecting. */ 00308 EISCONN, /* ERR_ISCONN -10 Conn already established.*/ 00309 ENOTCONN, /* ERR_CONN -11 Not connected. */ 00310 -1, /* ERR_IF -12 Low-level netif error */ 00311 ECONNABORTED, /* ERR_ABRT -13 Connection aborted. */ 00312 ECONNRESET, /* ERR_RST -14 Connection reset. */ 00313 ENOTCONN, /* ERR_CLSD -15 Connection closed. */ 00314 EIO /* ERR_ARG -16 Illegal argument. */ 00315 }; 00316 00317 #define ERR_TO_ERRNO_TABLE_SIZE LWIP_ARRAYSIZE(err_to_errno_table) 00318 00319 #define err_to_errno(err) \ 00320 ((unsigned)(-(signed)(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \ 00321 err_to_errno_table[-(signed)(err)] : EIO) 00322 00323 #if LWIP_SOCKET_SET_ERRNO 00324 #ifndef set_errno 00325 #define set_errno(err) do { if (err) { errno = (err); } } while(0) 00326 #endif 00327 #else /* LWIP_SOCKET_SET_ERRNO */ 00328 #define set_errno(err) 00329 #endif /* LWIP_SOCKET_SET_ERRNO */ 00330 00331 #define sock_set_errno(sk, e) do { \ 00332 const int sockerr = (e); \ 00333 sk->err = (u8_t)sockerr; \ 00334 set_errno(sockerr); \ 00335 } while (0) 00336 00337 /* Forward declaration of some functions */ 00338 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); 00339 #if !LWIP_TCPIP_CORE_LOCKING 00340 static void lwip_getsockopt_callback(void *arg); 00341 static void lwip_setsockopt_callback(void *arg); 00342 #endif 00343 static u8_t lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen); 00344 static u8_t lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen); 00345 00346 #if LWIP_IPV4 && LWIP_IPV6 00347 static void 00348 sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* ipaddr, u16_t* port) 00349 { 00350 if ((sockaddr->sa_family) == AF_INET6) { 00351 SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, *port); 00352 ipaddr->type = IPADDR_TYPE_V6; 00353 } else { 00354 SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, *port); 00355 ipaddr->type = IPADDR_TYPE_V4; 00356 } 00357 } 00358 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 00359 00360 /** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ 00361 void 00362 lwip_socket_thread_init(void) 00363 { 00364 netconn_thread_init(); 00365 } 00366 00367 /** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ 00368 void 00369 lwip_socket_thread_cleanup(void) 00370 { 00371 netconn_thread_cleanup(); 00372 } 00373 00374 /** 00375 * Map a externally used socket index to the internal socket representation. 00376 * 00377 * @param s externally used socket index 00378 * @return struct lwip_sock for the socket or NULL if not found 00379 */ 00380 static struct lwip_sock * 00381 get_socket(int s) 00382 { 00383 struct lwip_sock *sock; 00384 00385 s -= LWIP_SOCKET_OFFSET; 00386 00387 if ((s < 0) || (s >= NUM_SOCKETS)) { 00388 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s + LWIP_SOCKET_OFFSET)); 00389 set_errno(EBADF); 00390 return NULL; 00391 } 00392 00393 sock = &sockets[s]; 00394 00395 if (!sock->conn) { 00396 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s + LWIP_SOCKET_OFFSET)); 00397 set_errno(EBADF); 00398 return NULL; 00399 } 00400 00401 return sock; 00402 } 00403 00404 /** 00405 * Same as get_socket but doesn't set errno 00406 * 00407 * @param s externally used socket index 00408 * @return struct lwip_sock for the socket or NULL if not found 00409 */ 00410 static struct lwip_sock * 00411 tryget_socket(int s) 00412 { 00413 s -= LWIP_SOCKET_OFFSET; 00414 if ((s < 0) || (s >= NUM_SOCKETS)) { 00415 return NULL; 00416 } 00417 if (!sockets[s].conn) { 00418 return NULL; 00419 } 00420 return &sockets[s]; 00421 } 00422 00423 /** 00424 * Allocate a new socket for a given netconn. 00425 * 00426 * @param newconn the netconn for which to allocate a socket 00427 * @param accepted 1 if socket has been created by accept(), 00428 * 0 if socket has been created by socket() 00429 * @return the index of the new socket; -1 on error 00430 */ 00431 static int 00432 alloc_socket(struct netconn *newconn, int accepted) 00433 { 00434 int i; 00435 SYS_ARCH_DECL_PROTECT(lev); 00436 00437 /* allocate a new socket identifier */ 00438 for (i = 0; i < NUM_SOCKETS; ++i) { 00439 /* Protect socket array */ 00440 SYS_ARCH_PROTECT(lev); 00441 if (!sockets[i].conn) { 00442 sockets[i].conn = newconn; 00443 /* The socket is not yet known to anyone, so no need to protect 00444 after having marked it as used. */ 00445 SYS_ARCH_UNPROTECT(lev); 00446 sockets[i].lastdata = NULL; 00447 sockets[i].lastoffset = 0; 00448 sockets[i].rcvevent = 0; 00449 /* TCP sendbuf is empty, but the socket is not yet writable until connected 00450 * (unless it has been created by accept()). */ 00451 sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); 00452 sockets[i].errevent = 0; 00453 sockets[i].err = 0; 00454 sockets[i].select_waiting = 0; 00455 return i + LWIP_SOCKET_OFFSET; 00456 } 00457 SYS_ARCH_UNPROTECT(lev); 00458 } 00459 return -1; 00460 } 00461 00462 /** Free a socket. The socket's netconn must have been 00463 * delete before! 00464 * 00465 * @param sock the socket to free 00466 * @param is_tcp != 0 for TCP sockets, used to free lastdata 00467 */ 00468 static void 00469 free_socket(struct lwip_sock *sock, int is_tcp) 00470 { 00471 void *lastdata; 00472 00473 lastdata = sock->lastdata; 00474 sock->lastdata = NULL; 00475 sock->lastoffset = 0; 00476 sock->err = 0; 00477 00478 /* Protect socket array */ 00479 SYS_ARCH_SET(sock->conn, NULL); 00480 /* don't use 'sock' after this line, as another task might have allocated it */ 00481 00482 if (lastdata != NULL) { 00483 if (is_tcp) { 00484 pbuf_free((struct pbuf *)lastdata); 00485 } else { 00486 netbuf_delete((struct netbuf *)lastdata); 00487 } 00488 } 00489 } 00490 00491 /* Below this, the well-known socket functions are implemented. 00492 * Use google.com or opengroup.org to get a good description :-) 00493 * 00494 * Exceptions are documented! 00495 */ 00496 00497 int 00498 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) 00499 { 00500 struct lwip_sock *sock, *nsock; 00501 struct netconn *newconn; 00502 ip_addr_t naddr; 00503 u16_t port = 0; 00504 int newsock; 00505 err_t err; 00506 SYS_ARCH_DECL_PROTECT(lev); 00507 00508 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); 00509 sock = get_socket(s); 00510 if (!sock) { 00511 return -1; 00512 } 00513 00514 if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) { 00515 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); 00516 sock_set_errno(sock, EWOULDBLOCK); 00517 return -1; 00518 } 00519 00520 /* wait for a new connection */ 00521 err = netconn_accept(sock->conn, &newconn); 00522 if (err != ERR_OK) { 00523 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); 00524 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 00525 sock_set_errno(sock, EOPNOTSUPP); 00526 } else if (err == ERR_CLSD) { 00527 sock_set_errno(sock, EINVAL); 00528 } else { 00529 sock_set_errno(sock, err_to_errno(err)); 00530 } 00531 return -1; 00532 } 00533 LWIP_ASSERT("newconn != NULL", newconn != NULL); 00534 00535 newsock = alloc_socket(newconn, 1); 00536 if (newsock == -1) { 00537 netconn_delete(newconn); 00538 sock_set_errno(sock, ENFILE); 00539 return -1; 00540 } 00541 LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); 00542 LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback); 00543 nsock = &sockets[newsock - LWIP_SOCKET_OFFSET]; 00544 00545 /* See event_callback: If data comes in right away after an accept, even 00546 * though the server task might not have created a new socket yet. 00547 * In that case, newconn->socket is counted down (newconn->socket--), 00548 * so nsock->rcvevent is >= 1 here! 00549 */ 00550 SYS_ARCH_PROTECT(lev); 00551 nsock->rcvevent += (s16_t)(-1 - newconn->socket); 00552 newconn->socket = newsock; 00553 SYS_ARCH_UNPROTECT(lev); 00554 00555 /* Note that POSIX only requires us to check addr is non-NULL. addrlen must 00556 * not be NULL if addr is valid. 00557 */ 00558 if (addr != NULL) { 00559 union sockaddr_aligned tempaddr; 00560 /* get the IP address and port of the remote host */ 00561 err = netconn_peer(newconn, &naddr, &port); 00562 if (err != ERR_OK) { 00563 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); 00564 netconn_delete(newconn); 00565 free_socket(nsock, 1); 00566 sock_set_errno(sock, err_to_errno(err)); 00567 return -1; 00568 } 00569 LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); 00570 00571 IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port); 00572 if (*addrlen > tempaddr.sa.sa_len) { 00573 *addrlen = tempaddr.sa.sa_len; 00574 } 00575 MEMCPY(addr, &tempaddr, *addrlen); 00576 00577 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); 00578 ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); 00579 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); 00580 } else { 00581 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock)); 00582 } 00583 00584 sock_set_errno(sock, 0); 00585 return newsock; 00586 } 00587 00588 int 00589 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) 00590 { 00591 struct lwip_sock *sock; 00592 ip_addr_t local_addr; 00593 u16_t local_port; 00594 err_t err; 00595 00596 sock = get_socket(s); 00597 if (!sock) { 00598 return -1; 00599 } 00600 00601 if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { 00602 /* sockaddr does not match socket type (IPv4/IPv6) */ 00603 sock_set_errno(sock, err_to_errno(ERR_VAL)); 00604 return -1; 00605 } 00606 00607 /* check size, family and alignment of 'name' */ 00608 LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) && 00609 IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)), 00610 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 00611 LWIP_UNUSED_ARG(namelen); 00612 00613 SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port); 00614 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); 00615 ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr); 00616 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); 00617 00618 err = netconn_bind(sock->conn, &local_addr, local_port); 00619 00620 if (err != ERR_OK) { 00621 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); 00622 sock_set_errno(sock, err_to_errno(err)); 00623 return -1; 00624 } 00625 00626 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); 00627 sock_set_errno(sock, 0); 00628 return 0; 00629 } 00630 00631 int 00632 lwip_close(int s) 00633 { 00634 struct lwip_sock *sock; 00635 int is_tcp = 0; 00636 err_t err; 00637 00638 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); 00639 00640 sock = get_socket(s); 00641 if (!sock) { 00642 return -1; 00643 } 00644 00645 if (sock->conn != NULL) { 00646 is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; 00647 } else { 00648 LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL); 00649 } 00650 00651 #if LWIP_IGMP 00652 /* drop all possibly joined IGMP memberships */ 00653 lwip_socket_drop_registered_memberships(s); 00654 #endif /* LWIP_IGMP */ 00655 00656 err = netconn_delete(sock->conn); 00657 if (err != ERR_OK) { 00658 sock_set_errno(sock, err_to_errno(err)); 00659 return -1; 00660 } 00661 00662 free_socket(sock, is_tcp); 00663 set_errno(0); 00664 return 0; 00665 } 00666 00667 int 00668 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) 00669 { 00670 struct lwip_sock *sock; 00671 err_t err; 00672 00673 sock = get_socket(s); 00674 if (!sock) { 00675 return -1; 00676 } 00677 00678 if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { 00679 /* sockaddr does not match socket type (IPv4/IPv6) */ 00680 sock_set_errno(sock, err_to_errno(ERR_VAL)); 00681 return -1; 00682 } 00683 00684 LWIP_UNUSED_ARG(namelen); 00685 if (name->sa_family == AF_UNSPEC) { 00686 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); 00687 err = netconn_disconnect(sock->conn); 00688 } else { 00689 ip_addr_t remote_addr; 00690 u16_t remote_port; 00691 00692 /* check size, family and alignment of 'name' */ 00693 LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) && 00694 IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name), 00695 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 00696 00697 SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port); 00698 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); 00699 ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr); 00700 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port)); 00701 00702 err = netconn_connect(sock->conn, &remote_addr, remote_port); 00703 } 00704 00705 if (err != ERR_OK) { 00706 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); 00707 sock_set_errno(sock, err_to_errno(err)); 00708 return -1; 00709 } 00710 00711 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); 00712 sock_set_errno(sock, 0); 00713 return 0; 00714 } 00715 00716 /** 00717 * Set a socket into listen mode. 00718 * The socket may not have been used for another connection previously. 00719 * 00720 * @param s the socket to set to listening mode 00721 * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) 00722 * @return 0 on success, non-zero on failure 00723 */ 00724 int 00725 lwip_listen(int s, int backlog) 00726 { 00727 struct lwip_sock *sock; 00728 err_t err; 00729 00730 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); 00731 00732 sock = get_socket(s); 00733 if (!sock) { 00734 return -1; 00735 } 00736 00737 /* limit the "backlog" parameter to fit in an u8_t */ 00738 backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); 00739 00740 err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); 00741 00742 if (err != ERR_OK) { 00743 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); 00744 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 00745 sock_set_errno(sock, EOPNOTSUPP); 00746 return -1; 00747 } 00748 sock_set_errno(sock, err_to_errno(err)); 00749 return -1; 00750 } 00751 00752 sock_set_errno(sock, 0); 00753 return 0; 00754 } 00755 00756 int 00757 lwip_recvfrom(int s, void *mem, size_t len, int flags, 00758 struct sockaddr *from, socklen_t *fromlen) 00759 { 00760 struct lwip_sock *sock; 00761 void *buf = NULL; 00762 struct pbuf *p; 00763 u16_t buflen, copylen; 00764 int off = 0; 00765 u8_t done = 0; 00766 err_t err; 00767 00768 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); 00769 sock = get_socket(s); 00770 if (!sock) { 00771 return -1; 00772 } 00773 00774 do { 00775 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata)); 00776 /* Check if there is data left from the last recv operation. */ 00777 if (sock->lastdata) { 00778 buf = sock->lastdata; 00779 } else { 00780 /* If this is non-blocking call, then check first */ 00781 if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && 00782 (sock->rcvevent <= 0)) { 00783 if (off > 0) { 00784 /* already received data, return that */ 00785 sock_set_errno(sock, 0); 00786 return off; 00787 } 00788 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); 00789 sock_set_errno(sock, EWOULDBLOCK); 00790 return -1; 00791 } 00792 00793 /* No data was left from the previous operation, so we try to get 00794 some from the network. */ 00795 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 00796 err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf); 00797 } else { 00798 err = netconn_recv(sock->conn, (struct netbuf **)&buf); 00799 } 00800 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n", 00801 err, buf)); 00802 00803 if (err != ERR_OK) { 00804 if (off > 0) { 00805 if (err == ERR_CLSD) { 00806 /* closed but already received data, ensure select gets the FIN, too */ 00807 event_callback(sock->conn, NETCONN_EVT_RCVPLUS, 0); 00808 } 00809 /* already received data, return that */ 00810 sock_set_errno(sock, 0); 00811 return off; 00812 } 00813 /* We should really do some error checking here. */ 00814 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n", 00815 s, lwip_strerr(err))); 00816 sock_set_errno(sock, err_to_errno(err)); 00817 if (err == ERR_CLSD) { 00818 return 0; 00819 } else { 00820 return -1; 00821 } 00822 } 00823 LWIP_ASSERT("buf != NULL", buf != NULL); 00824 sock->lastdata = buf; 00825 } 00826 00827 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 00828 p = (struct pbuf *)buf; 00829 } else { 00830 p = ((struct netbuf *)buf)->p; 00831 } 00832 buflen = p->tot_len; 00833 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n", 00834 buflen, len, off, sock->lastoffset)); 00835 00836 buflen -= sock->lastoffset; 00837 00838 if (len > buflen) { 00839 copylen = buflen; 00840 } else { 00841 copylen = (u16_t)len; 00842 } 00843 00844 /* copy the contents of the received buffer into 00845 the supplied memory pointer mem */ 00846 pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset); 00847 00848 off += copylen; 00849 00850 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 00851 LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen); 00852 len -= copylen; 00853 if ((len <= 0) || 00854 (p->flags & PBUF_FLAG_PUSH) || 00855 (sock->rcvevent <= 0) || 00856 ((flags & MSG_PEEK) != 0)) { 00857 done = 1; 00858 } 00859 } else { 00860 done = 1; 00861 } 00862 00863 /* Check to see from where the data was.*/ 00864 if (done) { 00865 #if !SOCKETS_DEBUG 00866 if (from && fromlen) 00867 #endif /* !SOCKETS_DEBUG */ 00868 { 00869 u16_t port; 00870 ip_addr_t tmpaddr; 00871 ip_addr_t *fromaddr; 00872 union sockaddr_aligned saddr; 00873 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); 00874 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 00875 fromaddr = &tmpaddr; 00876 netconn_getaddr(sock->conn, fromaddr, &port, 0); 00877 } else { 00878 port = netbuf_fromport((struct netbuf *)buf); 00879 fromaddr = netbuf_fromaddr((struct netbuf *)buf); 00880 } 00881 IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); 00882 ip_addr_debug_print(SOCKETS_DEBUG, fromaddr); 00883 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); 00884 #if SOCKETS_DEBUG 00885 if (from && fromlen) 00886 #endif /* SOCKETS_DEBUG */ 00887 { 00888 if (*fromlen > saddr.sa.sa_len) { 00889 *fromlen = saddr.sa.sa_len; 00890 } 00891 MEMCPY(from, &saddr, *fromlen); 00892 } 00893 } 00894 } 00895 00896 /* If we don't peek the incoming message... */ 00897 if ((flags & MSG_PEEK) == 0) { 00898 /* If this is a TCP socket, check if there is data left in the 00899 buffer. If so, it should be saved in the sock structure for next 00900 time around. */ 00901 if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (buflen - copylen > 0)) { 00902 sock->lastdata = buf; 00903 sock->lastoffset += copylen; 00904 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf)); 00905 } else { 00906 sock->lastdata = NULL; 00907 sock->lastoffset = 0; 00908 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf)); 00909 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 00910 pbuf_free((struct pbuf *)buf); 00911 } else { 00912 netbuf_delete((struct netbuf *)buf); 00913 } 00914 buf = NULL; 00915 } 00916 } 00917 } while (!done); 00918 00919 sock_set_errno(sock, 0); 00920 return off; 00921 } 00922 00923 int 00924 lwip_read(int s, void *mem, size_t len) 00925 { 00926 return lwip_recvfrom(s, mem, len, 0, NULL, NULL); 00927 } 00928 00929 int 00930 lwip_recv(int s, void *mem, size_t len, int flags) 00931 { 00932 return lwip_recvfrom(s, mem, len, flags, NULL, NULL); 00933 } 00934 00935 int 00936 lwip_send(int s, const void *data, size_t size, int flags) 00937 { 00938 struct lwip_sock *sock; 00939 err_t err; 00940 u8_t write_flags; 00941 size_t written; 00942 00943 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", 00944 s, data, size, flags)); 00945 00946 sock = get_socket(s); 00947 if (!sock) { 00948 return -1; 00949 } 00950 00951 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 00952 #if (LWIP_UDP || LWIP_RAW) 00953 return lwip_sendto(s, data, size, flags, NULL, 0); 00954 #else /* (LWIP_UDP || LWIP_RAW) */ 00955 sock_set_errno(sock, err_to_errno(ERR_ARG)); 00956 return -1; 00957 #endif /* (LWIP_UDP || LWIP_RAW) */ 00958 } 00959 00960 write_flags = NETCONN_COPY | 00961 ((flags & MSG_MORE) ? NETCONN_MORE : 0) | 00962 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); 00963 written = 0; 00964 err = netconn_write_partly(sock->conn, data, size, write_flags, &written); 00965 00966 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written)); 00967 sock_set_errno(sock, err_to_errno(err)); 00968 return (err == ERR_OK ? (int)written : -1); 00969 } 00970 00971 int 00972 lwip_sendmsg(int s, const struct msghdr *msg, int flags) 00973 { 00974 struct lwip_sock *sock; 00975 struct netbuf *chain_buf; 00976 u16_t remote_port; 00977 int i; 00978 #if LWIP_TCP 00979 u8_t write_flags; 00980 size_t written; 00981 #endif 00982 int size = 0; 00983 err_t err = ERR_OK; 00984 00985 sock = get_socket(s); 00986 if (!sock) { 00987 return -1; 00988 } 00989 00990 LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL, 00991 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 00992 00993 LWIP_UNUSED_ARG(msg->msg_control); 00994 LWIP_UNUSED_ARG(msg->msg_controllen); 00995 LWIP_UNUSED_ARG(msg->msg_flags); 00996 LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", (msg->msg_iov != NULL && msg->msg_iovlen != 0), 00997 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 00998 00999 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 01000 #if LWIP_TCP 01001 write_flags = NETCONN_COPY | 01002 ((flags & MSG_MORE) ? NETCONN_MORE : 0) | 01003 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); 01004 01005 for (i = 0; i < msg->msg_iovlen; i++) { 01006 written = 0; 01007 err = netconn_write_partly(sock->conn, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len, write_flags, &written); 01008 if (err == ERR_OK) { 01009 size += written; 01010 /* check that the entire IO vector was accepected, if not return a partial write */ 01011 if (written != msg->msg_iov[i].iov_len) 01012 break; 01013 } 01014 /* none of this IO vector was accepted, but previous was, return partial write and conceal ERR_WOULDBLOCK */ 01015 else if (err == ERR_WOULDBLOCK && size > 0) { 01016 err = ERR_OK; 01017 /* let ERR_WOULDBLOCK persist on the netconn since we are returning ERR_OK */ 01018 break; 01019 } else { 01020 size = -1; 01021 break; 01022 } 01023 } 01024 sock_set_errno(sock, err_to_errno(err)); 01025 return size; 01026 #else /* LWIP_TCP */ 01027 sock_set_errno(sock, err_to_errno(ERR_ARG)); 01028 return -1; 01029 #endif /* LWIP_TCP */ 01030 } 01031 /* else, UDP and RAW NETCONNs */ 01032 #if LWIP_UDP || LWIP_RAW 01033 01034 LWIP_UNUSED_ARG(flags); 01035 LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) || 01036 IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)) , 01037 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 01038 01039 /* initialize chain buffer with destination */ 01040 chain_buf = netbuf_new(); 01041 if (!chain_buf) { 01042 sock_set_errno(sock, err_to_errno(ERR_MEM)); 01043 return -1; 01044 } 01045 if (msg->msg_name) { 01046 SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf->addr, remote_port); 01047 netbuf_fromport(chain_buf) = remote_port; 01048 } 01049 #if LWIP_NETIF_TX_SINGLE_PBUF 01050 for (i = 0; i < msg->msg_iovlen; i++) { 01051 size += msg->msg_iov[i].iov_len; 01052 } 01053 /* Allocate a new netbuf and copy the data into it. */ 01054 if (netbuf_alloc(chain_buf, (u16_t)size) == NULL) { 01055 err = ERR_MEM; 01056 } 01057 else { 01058 /* flatten the IO vectors */ 01059 size_t offset = 0; 01060 for (i = 0; i < msg->msg_iovlen; i++) { 01061 MEMCPY(&((u8_t*)chain_buf->p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); 01062 offset += msg->msg_iov[i].iov_len; 01063 } 01064 #if LWIP_CHECKSUM_ON_COPY 01065 { 01066 /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */ 01067 u16_t chksum = ~inet_chksum_pbuf(chain_buf->p); 01068 netbuf_set_chksum(chain_buf, chksum); 01069 } 01070 #endif /* LWIP_CHECKSUM_ON_COPY */ 01071 err = ERR_OK; 01072 } 01073 #else /* LWIP_NETIF_TX_SINGLE_PBUF */ 01074 /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain 01075 manually to avoid having to allocate, chain, and delete a netbuf for each iov */ 01076 for (i = 0; i < msg->msg_iovlen; i++) { 01077 struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); 01078 if (p == NULL) { 01079 err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */ 01080 break; 01081 } 01082 p->payload = msg->msg_iov[i].iov_base; 01083 LWIP_ASSERT("iov_len < u16_t", msg->msg_iov[i].iov_len <= 0xFFFF); 01084 p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len; 01085 /* netbuf empty, add new pbuf */ 01086 if (chain_buf->p == NULL) { 01087 chain_buf->p = chain_buf->ptr = p; 01088 /* add pbuf to existing pbuf chain */ 01089 } else { 01090 pbuf_cat(chain_buf->p, p); 01091 } 01092 } 01093 /* save size of total chain */ 01094 if (err == ERR_OK) { 01095 size = netbuf_len(chain_buf); 01096 } 01097 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ 01098 01099 if (err == ERR_OK) { 01100 /* send the data */ 01101 err = netconn_send(sock->conn, chain_buf); 01102 } 01103 01104 /* deallocated the buffer */ 01105 netbuf_delete(chain_buf); 01106 01107 sock_set_errno(sock, err_to_errno(err)); 01108 return (err == ERR_OK ? size : -1); 01109 #else /* LWIP_UDP || LWIP_RAW */ 01110 sock_set_errno(sock, err_to_errno(ERR_ARG)); 01111 return -1; 01112 #endif /* LWIP_UDP || LWIP_RAW */ 01113 } 01114 01115 int 01116 lwip_sendto(int s, const void *data, size_t size, int flags, 01117 const struct sockaddr *to, socklen_t tolen) 01118 { 01119 struct lwip_sock *sock; 01120 err_t err; 01121 u16_t short_size; 01122 u16_t remote_port; 01123 struct netbuf buf; 01124 01125 sock = get_socket(s); 01126 if (!sock) { 01127 return -1; 01128 } 01129 01130 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 01131 #if LWIP_TCP 01132 return lwip_send(s, data, size, flags); 01133 #else /* LWIP_TCP */ 01134 LWIP_UNUSED_ARG(flags); 01135 sock_set_errno(sock, err_to_errno(ERR_ARG)); 01136 return -1; 01137 #endif /* LWIP_TCP */ 01138 } 01139 01140 if ((to != NULL) && !SOCK_ADDR_TYPE_MATCH(to, sock)) { 01141 /* sockaddr does not match socket type (IPv4/IPv6) */ 01142 sock_set_errno(sock, err_to_errno(ERR_VAL)); 01143 return -1; 01144 } 01145 01146 /* @todo: split into multiple sendto's? */ 01147 LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); 01148 short_size = (u16_t)size; 01149 LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || 01150 (IS_SOCK_ADDR_LEN_VALID(tolen) && 01151 IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))), 01152 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 01153 LWIP_UNUSED_ARG(tolen); 01154 01155 /* initialize a buffer */ 01156 buf.p = buf.ptr = NULL; 01157 #if LWIP_CHECKSUM_ON_COPY 01158 buf.flags = 0; 01159 #endif /* LWIP_CHECKSUM_ON_COPY */ 01160 if (to) { 01161 SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port); 01162 } else { 01163 remote_port = 0; 01164 ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr); 01165 } 01166 netbuf_fromport(&buf) = remote_port; 01167 01168 01169 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", 01170 s, data, short_size, flags)); 01171 ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr); 01172 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); 01173 01174 /* make the buffer point to the data that should be sent */ 01175 #if LWIP_NETIF_TX_SINGLE_PBUF 01176 /* Allocate a new netbuf and copy the data into it. */ 01177 if (netbuf_alloc(&buf, short_size) == NULL) { 01178 err = ERR_MEM; 01179 } else { 01180 #if LWIP_CHECKSUM_ON_COPY 01181 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) { 01182 u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); 01183 netbuf_set_chksum(&buf, chksum); 01184 } else 01185 #endif /* LWIP_CHECKSUM_ON_COPY */ 01186 { 01187 MEMCPY(buf.p->payload, data, short_size); 01188 } 01189 err = ERR_OK; 01190 } 01191 #else /* LWIP_NETIF_TX_SINGLE_PBUF */ 01192 err = netbuf_ref(&buf, data, short_size); 01193 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ 01194 if (err == ERR_OK) { 01195 /* send the data */ 01196 err = netconn_send(sock->conn, &buf); 01197 } 01198 01199 /* deallocated the buffer */ 01200 netbuf_free(&buf); 01201 01202 sock_set_errno(sock, err_to_errno(err)); 01203 return (err == ERR_OK ? short_size : -1); 01204 } 01205 01206 int 01207 lwip_socket(int domain, int type, int protocol) 01208 { 01209 struct netconn *conn; 01210 int i; 01211 01212 #if !LWIP_IPV6 01213 LWIP_UNUSED_ARG(domain); /* @todo: check this */ 01214 #endif /* LWIP_IPV6 */ 01215 01216 /* create a netconn */ 01217 switch (type) { 01218 case SOCK_RAW: 01219 conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), 01220 (u8_t)protocol, event_callback); 01221 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", 01222 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 01223 break; 01224 case SOCK_DGRAM: 01225 conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, 01226 ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) , 01227 event_callback); 01228 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", 01229 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 01230 break; 01231 case SOCK_STREAM: 01232 conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), event_callback); 01233 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", 01234 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 01235 break; 01236 default: 01237 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", 01238 domain, type, protocol)); 01239 set_errno(EINVAL); 01240 return -1; 01241 } 01242 01243 if (!conn) { 01244 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); 01245 set_errno(ENOBUFS); 01246 return -1; 01247 } 01248 01249 i = alloc_socket(conn, 0); 01250 01251 if (i == -1) { 01252 netconn_delete(conn); 01253 set_errno(ENFILE); 01254 return -1; 01255 } 01256 conn->socket = i; 01257 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); 01258 set_errno(0); 01259 return i; 01260 } 01261 01262 int 01263 lwip_write(int s, const void *data, size_t size) 01264 { 01265 return lwip_send(s, data, size, 0); 01266 } 01267 01268 int 01269 lwip_writev(int s, const struct iovec *iov, int iovcnt) 01270 { 01271 struct msghdr msg; 01272 01273 msg.msg_name = NULL; 01274 msg.msg_namelen = 0; 01275 /* Hack: we have to cast via number to cast from 'const' pointer to non-const. 01276 Blame the opengroup standard for this inconsistency. */ 01277 msg.msg_iov = (struct iovec *)(size_t)iov; 01278 msg.msg_iovlen = iovcnt; 01279 msg.msg_control = NULL; 01280 msg.msg_controllen = 0; 01281 msg.msg_flags = 0; 01282 return lwip_sendmsg(s, &msg, 0); 01283 } 01284 01285 /** 01286 * Go through the readset and writeset lists and see which socket of the sockets 01287 * set in the sets has events. On return, readset, writeset and exceptset have 01288 * the sockets enabled that had events. 01289 * 01290 * @param maxfdp1 the highest socket index in the sets 01291 * @param readset_in: set of sockets to check for read events 01292 * @param writeset_in: set of sockets to check for write events 01293 * @param exceptset_in: set of sockets to check for error events 01294 * @param readset_out: set of sockets that had read events 01295 * @param writeset_out: set of sockets that had write events 01296 * @param exceptset_out: set os sockets that had error events 01297 * @return number of sockets that had events (read/write/exception) (>= 0) 01298 */ 01299 static int 01300 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, 01301 fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) 01302 { 01303 int i, nready = 0; 01304 fd_set lreadset, lwriteset, lexceptset; 01305 struct lwip_sock *sock; 01306 SYS_ARCH_DECL_PROTECT(lev); 01307 01308 FD_ZERO(&lreadset); 01309 FD_ZERO(&lwriteset); 01310 FD_ZERO(&lexceptset); 01311 01312 /* Go through each socket in each list to count number of sockets which 01313 currently match */ 01314 for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { 01315 /* if this FD is not in the set, continue */ 01316 if (!(readset_in && FD_ISSET(i, readset_in)) && 01317 !(writeset_in && FD_ISSET(i, writeset_in)) && 01318 !(exceptset_in && FD_ISSET(i, exceptset_in))) { 01319 continue; 01320 } 01321 /* First get the socket's status (protected)... */ 01322 SYS_ARCH_PROTECT(lev); 01323 sock = tryget_socket(i); 01324 if (sock != NULL) { 01325 void* lastdata = sock->lastdata; 01326 s16_t rcvevent = sock->rcvevent; 01327 u16_t sendevent = sock->sendevent; 01328 u16_t errevent = sock->errevent; 01329 SYS_ARCH_UNPROTECT(lev); 01330 01331 /* ... then examine it: */ 01332 /* See if netconn of this socket is ready for read */ 01333 if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { 01334 FD_SET(i, &lreadset); 01335 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); 01336 nready++; 01337 } 01338 /* See if netconn of this socket is ready for write */ 01339 if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { 01340 FD_SET(i, &lwriteset); 01341 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); 01342 nready++; 01343 } 01344 /* See if netconn of this socket had an error */ 01345 if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { 01346 FD_SET(i, &lexceptset); 01347 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); 01348 nready++; 01349 } 01350 } else { 01351 SYS_ARCH_UNPROTECT(lev); 01352 /* continue on to next FD in list */ 01353 } 01354 } 01355 /* copy local sets to the ones provided as arguments */ 01356 *readset_out = lreadset; 01357 *writeset_out = lwriteset; 01358 *exceptset_out = lexceptset; 01359 01360 LWIP_ASSERT("nready >= 0", nready >= 0); 01361 return nready; 01362 } 01363 01364 int 01365 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, 01366 struct timeval *timeout) 01367 { 01368 u32_t waitres = 0; 01369 int nready; 01370 fd_set lreadset, lwriteset, lexceptset; 01371 u32_t msectimeout; 01372 struct lwip_select_cb select_cb; 01373 int i; 01374 int maxfdp2; 01375 #if LWIP_NETCONN_SEM_PER_THREAD 01376 int waited = 0; 01377 #endif 01378 SYS_ARCH_DECL_PROTECT(lev); 01379 01380 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", 01381 maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, 01382 timeout ? (s32_t)timeout->tv_sec : (s32_t)-1, 01383 timeout ? (s32_t)timeout->tv_usec : (s32_t)-1)); 01384 01385 /* Go through each socket in each list to count number of sockets which 01386 currently match */ 01387 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 01388 01389 /* If we don't have any current events, then suspend if we are supposed to */ 01390 if (!nready) { 01391 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { 01392 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); 01393 /* This is OK as the local fdsets are empty and nready is zero, 01394 or we would have returned earlier. */ 01395 goto return_copy_fdsets; 01396 } 01397 01398 /* None ready: add our semaphore to list: 01399 We don't actually need any dynamic memory. Our entry on the 01400 list is only valid while we are in this function, so it's ok 01401 to use local variables. */ 01402 01403 select_cb.next = NULL; 01404 select_cb.prev = NULL; 01405 select_cb.readset = readset; 01406 select_cb.writeset = writeset; 01407 select_cb.exceptset = exceptset; 01408 select_cb.sem_signalled = 0; 01409 #if LWIP_NETCONN_SEM_PER_THREAD 01410 select_cb.sem = LWIP_NETCONN_THREAD_SEM_GET(); 01411 #else /* LWIP_NETCONN_SEM_PER_THREAD */ 01412 if (sys_sem_new(&select_cb.sem, 0) != ERR_OK) { 01413 /* failed to create semaphore */ 01414 set_errno(ENOMEM); 01415 return -1; 01416 } 01417 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 01418 01419 /* Protect the select_cb_list */ 01420 SYS_ARCH_PROTECT(lev); 01421 01422 /* Put this select_cb on top of list */ 01423 select_cb.next = select_cb_list; 01424 if (select_cb_list != NULL) { 01425 select_cb_list->prev = &select_cb; 01426 } 01427 select_cb_list = &select_cb; 01428 /* Increasing this counter tells event_callback that the list has changed. */ 01429 select_cb_ctr++; 01430 01431 /* Now we can safely unprotect */ 01432 SYS_ARCH_UNPROTECT(lev); 01433 01434 /* Increase select_waiting for each socket we are interested in */ 01435 maxfdp2 = maxfdp1; 01436 for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { 01437 if ((readset && FD_ISSET(i, readset)) || 01438 (writeset && FD_ISSET(i, writeset)) || 01439 (exceptset && FD_ISSET(i, exceptset))) { 01440 struct lwip_sock *sock; 01441 SYS_ARCH_PROTECT(lev); 01442 sock = tryget_socket(i); 01443 if (sock != NULL) { 01444 sock->select_waiting++; 01445 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); 01446 } else { 01447 /* Not a valid socket */ 01448 nready = -1; 01449 maxfdp2 = i; 01450 SYS_ARCH_UNPROTECT(lev); 01451 break; 01452 } 01453 SYS_ARCH_UNPROTECT(lev); 01454 } 01455 } 01456 01457 if (nready >= 0) { 01458 /* Call lwip_selscan again: there could have been events between 01459 the last scan (without us on the list) and putting us on the list! */ 01460 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 01461 if (!nready) { 01462 /* Still none ready, just wait to be woken */ 01463 if (timeout == 0) { 01464 /* Wait forever */ 01465 msectimeout = 0; 01466 } else { 01467 msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); 01468 if (msectimeout == 0) { 01469 /* Wait 1ms at least (0 means wait forever) */ 01470 msectimeout = 1; 01471 } 01472 } 01473 01474 waitres = sys_arch_sem_wait(SELECT_SEM_PTR(select_cb.sem), msectimeout); 01475 #if LWIP_NETCONN_SEM_PER_THREAD 01476 waited = 1; 01477 #endif 01478 } 01479 } 01480 01481 /* Decrease select_waiting for each socket we are interested in */ 01482 for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) { 01483 if ((readset && FD_ISSET(i, readset)) || 01484 (writeset && FD_ISSET(i, writeset)) || 01485 (exceptset && FD_ISSET(i, exceptset))) { 01486 struct lwip_sock *sock; 01487 SYS_ARCH_PROTECT(lev); 01488 sock = tryget_socket(i); 01489 if (sock != NULL) { 01490 /* @todo: what if this is a new socket (reallocated?) in this case, 01491 select_waiting-- would be wrong (a global 'sockalloc' counter, 01492 stored per socket could help) */ 01493 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); 01494 if (sock->select_waiting > 0) { 01495 sock->select_waiting--; 01496 } 01497 } else { 01498 /* Not a valid socket */ 01499 nready = -1; 01500 } 01501 SYS_ARCH_UNPROTECT(lev); 01502 } 01503 } 01504 /* Take us off the list */ 01505 SYS_ARCH_PROTECT(lev); 01506 if (select_cb.next != NULL) { 01507 select_cb.next->prev = select_cb.prev; 01508 } 01509 if (select_cb_list == &select_cb) { 01510 LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL); 01511 select_cb_list = select_cb.next; 01512 } else { 01513 LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL); 01514 select_cb.prev->next = select_cb.next; 01515 } 01516 /* Increasing this counter tells event_callback that the list has changed. */ 01517 select_cb_ctr++; 01518 SYS_ARCH_UNPROTECT(lev); 01519 01520 #if LWIP_NETCONN_SEM_PER_THREAD 01521 if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { 01522 /* don't leave the thread-local semaphore signalled */ 01523 sys_arch_sem_wait(select_cb.sem, 1); 01524 } 01525 #else /* LWIP_NETCONN_SEM_PER_THREAD */ 01526 sys_sem_free(&select_cb.sem); 01527 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 01528 01529 if (nready < 0) { 01530 /* This happens when a socket got closed while waiting */ 01531 set_errno(EBADF); 01532 return -1; 01533 } 01534 01535 if (waitres == SYS_ARCH_TIMEOUT) { 01536 /* Timeout */ 01537 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); 01538 /* This is OK as the local fdsets are empty and nready is zero, 01539 or we would have returned earlier. */ 01540 goto return_copy_fdsets; 01541 } 01542 01543 /* See what's set */ 01544 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 01545 } 01546 01547 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); 01548 return_copy_fdsets: 01549 set_errno(0); 01550 if (readset) { 01551 *readset = lreadset; 01552 } 01553 if (writeset) { 01554 *writeset = lwriteset; 01555 } 01556 if (exceptset) { 01557 *exceptset = lexceptset; 01558 } 01559 return nready; 01560 } 01561 01562 /** 01563 * Callback registered in the netconn layer for each socket-netconn. 01564 * Processes recvevent (data available) and wakes up tasks waiting for select. 01565 */ 01566 static void 01567 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) 01568 { 01569 int s; 01570 struct lwip_sock *sock; 01571 struct lwip_select_cb *scb; 01572 int last_select_cb_ctr; 01573 SYS_ARCH_DECL_PROTECT(lev); 01574 01575 LWIP_UNUSED_ARG(len); 01576 01577 /* Get socket */ 01578 if (conn) { 01579 s = conn->socket; 01580 if (s < 0) { 01581 /* Data comes in right away after an accept, even though 01582 * the server task might not have created a new socket yet. 01583 * Just count down (or up) if that's the case and we 01584 * will use the data later. Note that only receive events 01585 * can happen before the new socket is set up. */ 01586 SYS_ARCH_PROTECT(lev); 01587 if (conn->socket < 0) { 01588 if (evt == NETCONN_EVT_RCVPLUS) { 01589 conn->socket--; 01590 } 01591 SYS_ARCH_UNPROTECT(lev); 01592 return; 01593 } 01594 s = conn->socket; 01595 SYS_ARCH_UNPROTECT(lev); 01596 } 01597 01598 sock = get_socket(s); 01599 if (!sock) { 01600 return; 01601 } 01602 } else { 01603 return; 01604 } 01605 01606 SYS_ARCH_PROTECT(lev); 01607 /* Set event as required */ 01608 switch (evt) { 01609 case NETCONN_EVT_RCVPLUS: 01610 sock->rcvevent++; 01611 break; 01612 case NETCONN_EVT_RCVMINUS: 01613 sock->rcvevent--; 01614 break; 01615 case NETCONN_EVT_SENDPLUS: 01616 sock->sendevent = 1; 01617 break; 01618 case NETCONN_EVT_SENDMINUS: 01619 sock->sendevent = 0; 01620 break; 01621 case NETCONN_EVT_ERROR: 01622 sock->errevent = 1; 01623 break; 01624 default: 01625 LWIP_ASSERT("unknown event", 0); 01626 break; 01627 } 01628 01629 if (sock->select_waiting == 0) { 01630 /* noone is waiting for this socket, no need to check select_cb_list */ 01631 SYS_ARCH_UNPROTECT(lev); 01632 return; 01633 } 01634 01635 /* Now decide if anyone is waiting for this socket */ 01636 /* NOTE: This code goes through the select_cb_list list multiple times 01637 ONLY IF a select was actually waiting. We go through the list the number 01638 of waiting select calls + 1. This list is expected to be small. */ 01639 01640 /* At this point, SYS_ARCH is still protected! */ 01641 again: 01642 for (scb = select_cb_list; scb != NULL; scb = scb->next) { 01643 /* remember the state of select_cb_list to detect changes */ 01644 last_select_cb_ctr = select_cb_ctr; 01645 if (scb->sem_signalled == 0) { 01646 /* semaphore not signalled yet */ 01647 int do_signal = 0; 01648 /* Test this select call for our socket */ 01649 if (sock->rcvevent > 0) { 01650 if (scb->readset && FD_ISSET(s, scb->readset)) { 01651 do_signal = 1; 01652 } 01653 } 01654 if (sock->sendevent != 0) { 01655 if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { 01656 do_signal = 1; 01657 } 01658 } 01659 if (sock->errevent != 0) { 01660 if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { 01661 do_signal = 1; 01662 } 01663 } 01664 if (do_signal) { 01665 scb->sem_signalled = 1; 01666 /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might 01667 lead to the select thread taking itself off the list, invalidating the semaphore. */ 01668 sys_sem_signal(SELECT_SEM_PTR(scb->sem)); 01669 } 01670 } 01671 /* unlock interrupts with each step */ 01672 SYS_ARCH_UNPROTECT(lev); 01673 /* this makes sure interrupt protection time is short */ 01674 SYS_ARCH_PROTECT(lev); 01675 if (last_select_cb_ctr != select_cb_ctr) { 01676 /* someone has changed select_cb_list, restart at the beginning */ 01677 goto again; 01678 } 01679 } 01680 SYS_ARCH_UNPROTECT(lev); 01681 } 01682 01683 /** 01684 * Unimplemented: Close one end of a full-duplex connection. 01685 * Currently, the full connection is closed. 01686 */ 01687 int 01688 lwip_shutdown(int s, int how) 01689 { 01690 struct lwip_sock *sock; 01691 err_t err; 01692 u8_t shut_rx = 0, shut_tx = 0; 01693 01694 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); 01695 01696 sock = get_socket(s); 01697 if (!sock) { 01698 return -1; 01699 } 01700 01701 if (sock->conn != NULL) { 01702 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 01703 sock_set_errno(sock, EOPNOTSUPP); 01704 return -1; 01705 } 01706 } else { 01707 sock_set_errno(sock, ENOTCONN); 01708 return -1; 01709 } 01710 01711 if (how == SHUT_RD) { 01712 shut_rx = 1; 01713 } else if (how == SHUT_WR) { 01714 shut_tx = 1; 01715 } else if (how == SHUT_RDWR) { 01716 shut_rx = 1; 01717 shut_tx = 1; 01718 } else { 01719 sock_set_errno(sock, EINVAL); 01720 return -1; 01721 } 01722 err = netconn_shutdown(sock->conn, shut_rx, shut_tx); 01723 01724 sock_set_errno(sock, err_to_errno(err)); 01725 return (err == ERR_OK ? 0 : -1); 01726 } 01727 01728 static int 01729 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) 01730 { 01731 struct lwip_sock *sock; 01732 union sockaddr_aligned saddr; 01733 ip_addr_t naddr; 01734 u16_t port; 01735 err_t err; 01736 01737 sock = get_socket(s); 01738 if (!sock) { 01739 return -1; 01740 } 01741 01742 /* get the IP address and port */ 01743 /* @todo: this does not work for IPv6, yet */ 01744 err = netconn_getaddr(sock->conn, &naddr, &port, local); 01745 if (err != ERR_OK) { 01746 sock_set_errno(sock, err_to_errno(err)); 01747 return -1; 01748 } 01749 IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port); 01750 01751 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); 01752 ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); 01753 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); 01754 01755 if (*namelen > saddr.sa.sa_len) { 01756 *namelen = saddr.sa.sa_len; 01757 } 01758 MEMCPY(name, &saddr, *namelen); 01759 01760 sock_set_errno(sock, 0); 01761 return 0; 01762 } 01763 01764 int 01765 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) 01766 { 01767 return lwip_getaddrname(s, name, namelen, 0); 01768 } 01769 01770 int 01771 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) 01772 { 01773 return lwip_getaddrname(s, name, namelen, 1); 01774 } 01775 01776 int 01777 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) 01778 { 01779 u8_t err; 01780 struct lwip_sock *sock = get_socket(s); 01781 #if !LWIP_TCPIP_CORE_LOCKING 01782 LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); 01783 #endif /* !LWIP_TCPIP_CORE_LOCKING */ 01784 01785 if (!sock) { 01786 return -1; 01787 } 01788 01789 if ((NULL == optval) || (NULL == optlen)) { 01790 sock_set_errno(sock, EFAULT); 01791 return -1; 01792 } 01793 01794 #if LWIP_TCPIP_CORE_LOCKING 01795 /* core-locking can just call the -impl function */ 01796 LOCK_TCPIP_CORE(); 01797 err = lwip_getsockopt_impl(s, level, optname, optval, optlen); 01798 UNLOCK_TCPIP_CORE(); 01799 01800 #else /* LWIP_TCPIP_CORE_LOCKING */ 01801 01802 #if LWIP_MPU_COMPATIBLE 01803 /* MPU_COMPATIBLE copies the optval data, so check for max size here */ 01804 if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { 01805 sock_set_errno(sock, ENOBUFS); 01806 return -1; 01807 } 01808 #endif /* LWIP_MPU_COMPATIBLE */ 01809 01810 LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); 01811 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; 01812 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; 01813 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; 01814 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen; 01815 #if !LWIP_MPU_COMPATIBLE 01816 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval; 01817 #endif /* !LWIP_MPU_COMPATIBLE */ 01818 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; 01819 #if LWIP_NETCONN_SEM_PER_THREAD 01820 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); 01821 #else 01822 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; 01823 #endif 01824 err = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); 01825 if (err != ERR_OK) { 01826 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); 01827 sock_set_errno(sock, err_to_errno(err)); 01828 return -1; 01829 } 01830 sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); 01831 01832 /* write back optlen and optval */ 01833 *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen; 01834 #if LWIP_MPU_COMPATIBLE 01835 memcpy(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, 01836 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen); 01837 #endif /* LWIP_MPU_COMPATIBLE */ 01838 01839 /* maybe lwip_getsockopt_internal has changed err */ 01840 err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; 01841 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); 01842 #endif /* LWIP_TCPIP_CORE_LOCKING */ 01843 01844 sock_set_errno(sock, err); 01845 return err ? -1 : 0; 01846 } 01847 01848 #if !LWIP_TCPIP_CORE_LOCKING 01849 /** lwip_getsockopt_callback: only used without CORE_LOCKING 01850 * to get into the tcpip_thread 01851 */ 01852 static void 01853 lwip_getsockopt_callback(void *arg) 01854 { 01855 struct lwip_setgetsockopt_data *data; 01856 LWIP_ASSERT("arg != NULL", arg != NULL); 01857 data = (struct lwip_setgetsockopt_data*)arg; 01858 01859 data->err = lwip_getsockopt_impl(data->s, data->level, data->optname, 01860 #if LWIP_MPU_COMPATIBLE 01861 data->optval, 01862 #else /* LWIP_MPU_COMPATIBLE */ 01863 data->optval.p, 01864 #endif /* LWIP_MPU_COMPATIBLE */ 01865 &data->optlen); 01866 01867 sys_sem_signal((sys_sem_t*)(data->completed_sem)); 01868 } 01869 #endif /* LWIP_TCPIP_CORE_LOCKING */ 01870 01871 /** lwip_getsockopt_impl: the actual implementation of getsockopt: 01872 * same argument as lwip_getsockopt, either called directly or through callback 01873 */ 01874 static u8_t 01875 lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen) 01876 { 01877 u8_t err = 0; 01878 struct lwip_sock *sock = tryget_socket(s); 01879 if (!sock) { 01880 return EBADF; 01881 } 01882 01883 switch (level) { 01884 01885 /* Level: SOL_SOCKET */ 01886 case SOL_SOCKET: 01887 switch (optname) { 01888 01889 #if LWIP_TCP 01890 case SO_ACCEPTCONN: 01891 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 01892 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) { 01893 return ENOPROTOOPT; 01894 } 01895 if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) { 01896 *(int*)optval = 1; 01897 } else { 01898 *(int*)optval = 0; 01899 } 01900 break; 01901 #endif /* LWIP_TCP */ 01902 01903 /* The option flags */ 01904 case SO_BROADCAST: 01905 case SO_KEEPALIVE: 01906 #if SO_REUSE 01907 case SO_REUSEADDR: 01908 #endif /* SO_REUSE */ 01909 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 01910 *(int*)optval = ip_get_option(sock->conn->pcb.ip, optname); 01911 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", 01912 s, optname, (*(int*)optval?"on":"off"))); 01913 break; 01914 01915 case SO_TYPE: 01916 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); 01917 switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { 01918 case NETCONN_RAW: 01919 *(int*)optval = SOCK_RAW; 01920 break; 01921 case NETCONN_TCP: 01922 *(int*)optval = SOCK_STREAM; 01923 break; 01924 case NETCONN_UDP: 01925 *(int*)optval = SOCK_DGRAM; 01926 break; 01927 default: /* unrecognized socket type */ 01928 *(int*)optval = netconn_type(sock->conn); 01929 LWIP_DEBUGF(SOCKETS_DEBUG, 01930 ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", 01931 s, *(int *)optval)); 01932 } /* switch (netconn_type(sock->conn)) */ 01933 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", 01934 s, *(int *)optval)); 01935 break; 01936 01937 case SO_ERROR: 01938 LWIP_SOCKOPT_CHECK_OPTLEN(*optlen, int); 01939 /* only overwrite ERR_OK or temporary errors */ 01940 if (((sock->err == 0) || (sock->err == EINPROGRESS)) && (sock->conn != NULL)) { 01941 sock_set_errno(sock, err_to_errno(sock->conn->last_err)); 01942 } 01943 *(int *)optval = (sock->err == 0xFF ? (int)-1 : (int)sock->err); 01944 sock->err = 0; 01945 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", 01946 s, *(int *)optval)); 01947 break; 01948 01949 #if LWIP_SO_SNDTIMEO 01950 case SO_SNDTIMEO: 01951 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); 01952 LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn)); 01953 break; 01954 #endif /* LWIP_SO_SNDTIMEO */ 01955 #if LWIP_SO_RCVTIMEO 01956 case SO_RCVTIMEO: 01957 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); 01958 LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn)); 01959 break; 01960 #endif /* LWIP_SO_RCVTIMEO */ 01961 #if LWIP_SO_RCVBUF 01962 case SO_RCVBUF: 01963 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); 01964 *(int *)optval = netconn_get_recvbufsize(sock->conn); 01965 break; 01966 #endif /* LWIP_SO_RCVBUF */ 01967 #if LWIP_SO_LINGER 01968 case SO_LINGER: 01969 { 01970 s16_t conn_linger; 01971 struct linger* linger = (struct linger*)optval; 01972 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger); 01973 conn_linger = sock->conn->linger; 01974 if (conn_linger >= 0) { 01975 linger->l_onoff = 1; 01976 linger->l_linger = (int)conn_linger; 01977 } else { 01978 linger->l_onoff = 0; 01979 linger->l_linger = 0; 01980 } 01981 } 01982 break; 01983 #endif /* LWIP_SO_LINGER */ 01984 #if LWIP_UDP 01985 case SO_NO_CHECK: 01986 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP); 01987 #if LWIP_UDPLITE 01988 if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0) { 01989 /* this flag is only available for UDP, not for UDP lite */ 01990 return EAFNOSUPPORT; 01991 } 01992 #endif /* LWIP_UDPLITE */ 01993 *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0; 01994 break; 01995 #endif /* LWIP_UDP*/ 01996 default: 01997 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", 01998 s, optname)); 01999 err = ENOPROTOOPT; 02000 break; 02001 } /* switch (optname) */ 02002 break; 02003 02004 /* Level: IPPROTO_IP */ 02005 case IPPROTO_IP: 02006 switch (optname) { 02007 case IP_TTL: 02008 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 02009 *(int*)optval = sock->conn->pcb.ip->ttl; 02010 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", 02011 s, *(int *)optval)); 02012 break; 02013 case IP_TOS: 02014 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 02015 *(int*)optval = sock->conn->pcb.ip->tos; 02016 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", 02017 s, *(int *)optval)); 02018 break; 02019 #if LWIP_MULTICAST_TX_OPTIONS 02020 case IP_MULTICAST_TTL: 02021 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); 02022 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { 02023 return ENOPROTOOPT; 02024 } 02025 *(u8_t*)optval = sock->conn->pcb.udp->mcast_ttl; 02026 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", 02027 s, *(int *)optval)); 02028 break; 02029 case IP_MULTICAST_IF: 02030 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr); 02031 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { 02032 return ENOPROTOOPT; 02033 } 02034 inet_addr_from_ipaddr((struct in_addr*)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp)); 02035 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", 02036 s, *(u32_t *)optval)); 02037 break; 02038 case IP_MULTICAST_LOOP: 02039 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); 02040 if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { 02041 *(u8_t*)optval = 1; 02042 } else { 02043 *(u8_t*)optval = 0; 02044 } 02045 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", 02046 s, *(int *)optval)); 02047 break; 02048 #endif /* LWIP_MULTICAST_TX_OPTIONS */ 02049 default: 02050 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", 02051 s, optname)); 02052 err = ENOPROTOOPT; 02053 break; 02054 } /* switch (optname) */ 02055 break; 02056 02057 #if LWIP_TCP 02058 /* Level: IPPROTO_TCP */ 02059 case IPPROTO_TCP: 02060 /* Special case: all IPPROTO_TCP option take an int */ 02061 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP); 02062 switch (optname) { 02063 case TCP_NODELAY: 02064 *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp); 02065 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", 02066 s, (*(int*)optval)?"on":"off") ); 02067 break; 02068 case TCP_KEEPALIVE: 02069 *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle; 02070 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n", 02071 s, *(int *)optval)); 02072 break; 02073 02074 #if LWIP_TCP_KEEPALIVE 02075 case TCP_KEEPIDLE: 02076 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000); 02077 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n", 02078 s, *(int *)optval)); 02079 break; 02080 case TCP_KEEPINTVL: 02081 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000); 02082 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n", 02083 s, *(int *)optval)); 02084 break; 02085 case TCP_KEEPCNT: 02086 *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt; 02087 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n", 02088 s, *(int *)optval)); 02089 break; 02090 #endif /* LWIP_TCP_KEEPALIVE */ 02091 default: 02092 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", 02093 s, optname)); 02094 err = ENOPROTOOPT; 02095 break; 02096 } /* switch (optname) */ 02097 break; 02098 #endif /* LWIP_TCP */ 02099 02100 #if LWIP_IPV6 02101 /* Level: IPPROTO_IPV6 */ 02102 case IPPROTO_IPV6: 02103 switch (optname) { 02104 case IPV6_V6ONLY: 02105 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); 02106 /* @todo: this does not work for datagram sockets, yet */ 02107 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 02108 return ENOPROTOOPT; 02109 } 02110 *(int*)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0); 02111 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n", 02112 s, *(int *)optval)); 02113 break; 02114 default: 02115 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", 02116 s, optname)); 02117 err = ENOPROTOOPT; 02118 break; 02119 } /* switch (optname) */ 02120 break; 02121 #endif /* LWIP_IPV6 */ 02122 02123 #if LWIP_UDP && LWIP_UDPLITE 02124 /* Level: IPPROTO_UDPLITE */ 02125 case IPPROTO_UDPLITE: 02126 /* Special case: all IPPROTO_UDPLITE option take an int */ 02127 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 02128 /* If this is no UDP lite socket, ignore any options. */ 02129 if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { 02130 return ENOPROTOOPT; 02131 } 02132 switch (optname) { 02133 case UDPLITE_SEND_CSCOV: 02134 *(int*)optval = sock->conn->pcb.udp->chksum_len_tx; 02135 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", 02136 s, (*(int*)optval)) ); 02137 break; 02138 case UDPLITE_RECV_CSCOV: 02139 *(int*)optval = sock->conn->pcb.udp->chksum_len_rx; 02140 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", 02141 s, (*(int*)optval)) ); 02142 break; 02143 default: 02144 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", 02145 s, optname)); 02146 err = ENOPROTOOPT; 02147 break; 02148 } /* switch (optname) */ 02149 break; 02150 #endif /* LWIP_UDP */ 02151 /* Level: IPPROTO_RAW */ 02152 case IPPROTO_RAW: 02153 switch (optname) { 02154 #if LWIP_IPV6 && LWIP_RAW 02155 case IPV6_CHECKSUM: 02156 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW); 02157 if (sock->conn->pcb.raw->chksum_reqd == 0) { 02158 *(int *)optval = -1; 02159 } else { 02160 *(int *)optval = sock->conn->pcb.raw->chksum_offset; 02161 } 02162 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n", 02163 s, (*(int*)optval)) ); 02164 break; 02165 #endif /* LWIP_IPV6 && LWIP_RAW */ 02166 default: 02167 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", 02168 s, optname)); 02169 err = ENOPROTOOPT; 02170 break; 02171 } /* switch (optname) */ 02172 break; 02173 default: 02174 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", 02175 s, level, optname)); 02176 err = ENOPROTOOPT; 02177 break; 02178 } /* switch (level) */ 02179 02180 return err; 02181 } 02182 02183 int 02184 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) 02185 { 02186 u8_t err = 0; 02187 struct lwip_sock *sock = get_socket(s); 02188 #if !LWIP_TCPIP_CORE_LOCKING 02189 LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); 02190 #endif /* !LWIP_TCPIP_CORE_LOCKING */ 02191 02192 if (!sock) { 02193 return -1; 02194 } 02195 02196 if (NULL == optval) { 02197 sock_set_errno(sock, EFAULT); 02198 return -1; 02199 } 02200 02201 #if LWIP_TCPIP_CORE_LOCKING 02202 /* core-locking can just call the -impl function */ 02203 LOCK_TCPIP_CORE(); 02204 err = lwip_setsockopt_impl(s, level, optname, optval, optlen); 02205 UNLOCK_TCPIP_CORE(); 02206 02207 #else /* LWIP_TCPIP_CORE_LOCKING */ 02208 02209 #if LWIP_MPU_COMPATIBLE 02210 /* MPU_COMPATIBLE copies the optval data, so check for max size here */ 02211 if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { 02212 sock_set_errno(sock, ENOBUFS); 02213 return -1; 02214 } 02215 #endif /* LWIP_MPU_COMPATIBLE */ 02216 02217 LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); 02218 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; 02219 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; 02220 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; 02221 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen; 02222 #if LWIP_MPU_COMPATIBLE 02223 memcpy(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen); 02224 #else /* LWIP_MPU_COMPATIBLE */ 02225 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void*)optval; 02226 #endif /* LWIP_MPU_COMPATIBLE */ 02227 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; 02228 #if LWIP_NETCONN_SEM_PER_THREAD 02229 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); 02230 #else 02231 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; 02232 #endif 02233 err = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); 02234 if (err != ERR_OK) { 02235 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); 02236 sock_set_errno(sock, err_to_errno(err)); 02237 return -1; 02238 } 02239 sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); 02240 02241 /* maybe lwip_getsockopt_internal has changed err */ 02242 err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; 02243 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); 02244 #endif /* LWIP_TCPIP_CORE_LOCKING */ 02245 02246 sock_set_errno(sock, err); 02247 return err ? -1 : 0; 02248 } 02249 02250 #if !LWIP_TCPIP_CORE_LOCKING 02251 /** lwip_setsockopt_callback: only used without CORE_LOCKING 02252 * to get into the tcpip_thread 02253 */ 02254 static void 02255 lwip_setsockopt_callback(void *arg) 02256 { 02257 struct lwip_setgetsockopt_data *data; 02258 LWIP_ASSERT("arg != NULL", arg != NULL); 02259 data = (struct lwip_setgetsockopt_data*)arg; 02260 02261 data->err = lwip_setsockopt_impl(data->s, data->level, data->optname, 02262 #if LWIP_MPU_COMPATIBLE 02263 data->optval, 02264 #else /* LWIP_MPU_COMPATIBLE */ 02265 data->optval.pc, 02266 #endif /* LWIP_MPU_COMPATIBLE */ 02267 data->optlen); 02268 02269 sys_sem_signal((sys_sem_t*)(data->completed_sem)); 02270 } 02271 #endif /* LWIP_TCPIP_CORE_LOCKING */ 02272 02273 /** lwip_setsockopt_impl: the actual implementation of setsockopt: 02274 * same argument as lwip_setsockopt, either called directly or through callback 02275 */ 02276 static u8_t 02277 lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen) 02278 { 02279 u8_t err = 0; 02280 struct lwip_sock *sock = tryget_socket(s); 02281 if (!sock) { 02282 return EBADF; 02283 } 02284 02285 switch (level) { 02286 02287 /* Level: SOL_SOCKET */ 02288 case SOL_SOCKET: 02289 switch (optname) { 02290 02291 /* SO_ACCEPTCONN is get-only */ 02292 02293 /* The option flags */ 02294 case SO_BROADCAST: 02295 case SO_KEEPALIVE: 02296 #if SO_REUSE 02297 case SO_REUSEADDR: 02298 #endif /* SO_REUSE */ 02299 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); 02300 if (*(const int*)optval) { 02301 ip_set_option(sock->conn->pcb.ip, optname); 02302 } else { 02303 ip_reset_option(sock->conn->pcb.ip, optname); 02304 } 02305 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", 02306 s, optname, (*(const int*)optval?"on":"off"))); 02307 break; 02308 02309 /* SO_TYPE is get-only */ 02310 /* SO_ERROR is get-only */ 02311 02312 #if LWIP_SO_SNDTIMEO 02313 case SO_SNDTIMEO: 02314 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); 02315 netconn_set_sendtimeout(sock->conn, LWIP_SO_SNDRCVTIMEO_GET_MS(optval)); 02316 break; 02317 #endif /* LWIP_SO_SNDTIMEO */ 02318 #if LWIP_SO_RCVTIMEO 02319 case SO_RCVTIMEO: 02320 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); 02321 netconn_set_recvtimeout(sock->conn, (int)LWIP_SO_SNDRCVTIMEO_GET_MS(optval)); 02322 break; 02323 #endif /* LWIP_SO_RCVTIMEO */ 02324 #if LWIP_SO_RCVBUF 02325 case SO_RCVBUF: 02326 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int); 02327 netconn_set_recvbufsize(sock->conn, *(const int*)optval); 02328 break; 02329 #endif /* LWIP_SO_RCVBUF */ 02330 #if LWIP_SO_LINGER 02331 case SO_LINGER: 02332 { 02333 const struct linger* linger = (const struct linger*)optval; 02334 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger); 02335 if (linger->l_onoff) { 02336 int lingersec = linger->l_linger; 02337 if (lingersec < 0) { 02338 return EINVAL; 02339 } 02340 if (lingersec > 0xFFFF) { 02341 lingersec = 0xFFFF; 02342 } 02343 sock->conn->linger = (s16_t)lingersec; 02344 } else { 02345 sock->conn->linger = -1; 02346 } 02347 } 02348 break; 02349 #endif /* LWIP_SO_LINGER */ 02350 #if LWIP_UDP 02351 case SO_NO_CHECK: 02352 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); 02353 #if LWIP_UDPLITE 02354 if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0) { 02355 /* this flag is only available for UDP, not for UDP lite */ 02356 return EAFNOSUPPORT; 02357 } 02358 #endif /* LWIP_UDPLITE */ 02359 if (*(const int*)optval) { 02360 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM); 02361 } else { 02362 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM); 02363 } 02364 break; 02365 #endif /* LWIP_UDP */ 02366 default: 02367 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", 02368 s, optname)); 02369 err = ENOPROTOOPT; 02370 break; 02371 } /* switch (optname) */ 02372 break; 02373 02374 /* Level: IPPROTO_IP */ 02375 case IPPROTO_IP: 02376 switch (optname) { 02377 case IP_TTL: 02378 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); 02379 sock->conn->pcb.ip->ttl = (u8_t)(*(const int*)optval); 02380 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", 02381 s, sock->conn->pcb.ip->ttl)); 02382 break; 02383 case IP_TOS: 02384 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); 02385 sock->conn->pcb.ip->tos = (u8_t)(*(const int*)optval); 02386 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", 02387 s, sock->conn->pcb.ip->tos)); 02388 break; 02389 #if LWIP_MULTICAST_TX_OPTIONS 02390 case IP_MULTICAST_TTL: 02391 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); 02392 sock->conn->pcb.udp->mcast_ttl = (u8_t)(*(const u8_t*)optval); 02393 break; 02394 case IP_MULTICAST_IF: 02395 { 02396 ip4_addr_t if_addr; 02397 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP); 02398 inet_addr_to_ipaddr(&if_addr, (const struct in_addr*)optval); 02399 udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr); 02400 } 02401 break; 02402 case IP_MULTICAST_LOOP: 02403 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); 02404 if (*(const u8_t*)optval) { 02405 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP); 02406 } else { 02407 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP); 02408 } 02409 break; 02410 #endif /* LWIP_MULTICAST_TX_OPTIONS */ 02411 #if LWIP_IGMP 02412 case IP_ADD_MEMBERSHIP: 02413 case IP_DROP_MEMBERSHIP: 02414 { 02415 /* If this is a TCP or a RAW socket, ignore these options. */ 02416 /* @todo: assign membership to this socket so that it is dropped when closing the socket */ 02417 err_t igmp_err; 02418 const struct ip_mreq *imr = (const struct ip_mreq *)optval; 02419 ip4_addr_t if_addr; 02420 ip4_addr_t multi_addr; 02421 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP); 02422 inet_addr_to_ipaddr(&if_addr, &imr->imr_interface); 02423 inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr); 02424 if (optname == IP_ADD_MEMBERSHIP) { 02425 if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) { 02426 /* cannot track membership (out of memory) */ 02427 err = ENOMEM; 02428 igmp_err = ERR_OK; 02429 } else { 02430 igmp_err = igmp_joingroup(&if_addr, &multi_addr); 02431 } 02432 } else { 02433 igmp_err = igmp_leavegroup(&if_addr, &multi_addr); 02434 lwip_socket_unregister_membership(s, &if_addr, &multi_addr); 02435 } 02436 if (igmp_err != ERR_OK) { 02437 err = EADDRNOTAVAIL; 02438 } 02439 } 02440 break; 02441 #endif /* LWIP_IGMP */ 02442 default: 02443 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", 02444 s, optname)); 02445 err = ENOPROTOOPT; 02446 break; 02447 } /* switch (optname) */ 02448 break; 02449 02450 #if LWIP_TCP 02451 /* Level: IPPROTO_TCP */ 02452 case IPPROTO_TCP: 02453 /* Special case: all IPPROTO_TCP option take an int */ 02454 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP); 02455 switch (optname) { 02456 case TCP_NODELAY: 02457 if (*(const int*)optval) { 02458 tcp_nagle_disable(sock->conn->pcb.tcp); 02459 } else { 02460 tcp_nagle_enable(sock->conn->pcb.tcp); 02461 } 02462 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", 02463 s, (*(const int *)optval)?"on":"off") ); 02464 break; 02465 case TCP_KEEPALIVE: 02466 sock->conn->pcb.tcp->keep_idle = (u32_t)(*(const int*)optval); 02467 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", 02468 s, sock->conn->pcb.tcp->keep_idle)); 02469 break; 02470 02471 #if LWIP_TCP_KEEPALIVE 02472 case TCP_KEEPIDLE: 02473 sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(const int*)optval); 02474 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", 02475 s, sock->conn->pcb.tcp->keep_idle)); 02476 break; 02477 case TCP_KEEPINTVL: 02478 sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(const int*)optval); 02479 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", 02480 s, sock->conn->pcb.tcp->keep_intvl)); 02481 break; 02482 case TCP_KEEPCNT: 02483 sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int*)optval); 02484 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", 02485 s, sock->conn->pcb.tcp->keep_cnt)); 02486 break; 02487 #endif /* LWIP_TCP_KEEPALIVE */ 02488 default: 02489 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", 02490 s, optname)); 02491 err = ENOPROTOOPT; 02492 break; 02493 } /* switch (optname) */ 02494 break; 02495 #endif /* LWIP_TCP*/ 02496 02497 #if LWIP_IPV6 02498 /* Level: IPPROTO_IPV6 */ 02499 case IPPROTO_IPV6: 02500 switch (optname) { 02501 case IPV6_V6ONLY: 02502 /* @todo: this does not work for datagram sockets, yet */ 02503 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP); 02504 if (*(const int*)optval) { 02505 netconn_set_ipv6only(sock->conn, 1); 02506 } else { 02507 netconn_set_ipv6only(sock->conn, 0); 02508 } 02509 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n", 02510 s, (netconn_get_ipv6only(sock->conn) ? 1 : 0))); 02511 break; 02512 default: 02513 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", 02514 s, optname)); 02515 err = ENOPROTOOPT; 02516 break; 02517 } /* switch (optname) */ 02518 break; 02519 #endif /* LWIP_IPV6 */ 02520 02521 #if LWIP_UDP && LWIP_UDPLITE 02522 /* Level: IPPROTO_UDPLITE */ 02523 case IPPROTO_UDPLITE: 02524 /* Special case: all IPPROTO_UDPLITE option take an int */ 02525 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); 02526 /* If this is no UDP lite socket, ignore any options. */ 02527 if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { 02528 return ENOPROTOOPT; 02529 } 02530 switch (optname) { 02531 case UDPLITE_SEND_CSCOV: 02532 if ((*(const int*)optval != 0) && ((*(const int*)optval < 8) || (*(const int*)optval > 0xffff))) { 02533 /* don't allow illegal values! */ 02534 sock->conn->pcb.udp->chksum_len_tx = 8; 02535 } else { 02536 sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(const int*)optval; 02537 } 02538 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", 02539 s, (*(const int*)optval)) ); 02540 break; 02541 case UDPLITE_RECV_CSCOV: 02542 if ((*(const int*)optval != 0) && ((*(const int*)optval < 8) || (*(const int*)optval > 0xffff))) { 02543 /* don't allow illegal values! */ 02544 sock->conn->pcb.udp->chksum_len_rx = 8; 02545 } else { 02546 sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(const int*)optval; 02547 } 02548 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", 02549 s, (*(const int*)optval)) ); 02550 break; 02551 default: 02552 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", 02553 s, optname)); 02554 err = ENOPROTOOPT; 02555 break; 02556 } /* switch (optname) */ 02557 break; 02558 #endif /* LWIP_UDP */ 02559 /* Level: IPPROTO_RAW */ 02560 case IPPROTO_RAW: 02561 switch (optname) { 02562 #if LWIP_IPV6 && LWIP_RAW 02563 case IPV6_CHECKSUM: 02564 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW); 02565 if (*(const int *)optval < 0) { 02566 sock->conn->pcb.raw->chksum_reqd = 0; 02567 } else if (*(const int *)optval & 1) { 02568 /* Per RFC3542, odd offsets are not allowed */ 02569 return EINVAL; 02570 } else { 02571 sock->conn->pcb.raw->chksum_reqd = 1; 02572 sock->conn->pcb.raw->chksum_offset = (u16_t)*(const int *)optval; 02573 } 02574 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n", 02575 s, sock->conn->pcb.raw->chksum_reqd)); 02576 break; 02577 #endif /* LWIP_IPV6 && LWIP_RAW */ 02578 default: 02579 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", 02580 s, optname)); 02581 err = ENOPROTOOPT; 02582 break; 02583 } /* switch (optname) */ 02584 break; 02585 default: 02586 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", 02587 s, level, optname)); 02588 err = ENOPROTOOPT; 02589 break; 02590 } /* switch (level) */ 02591 02592 return err; 02593 } 02594 02595 int 02596 lwip_ioctl(int s, long cmd, void *argp) 02597 { 02598 struct lwip_sock *sock = get_socket(s); 02599 u8_t val; 02600 #if LWIP_SO_RCVBUF 02601 u16_t buflen = 0; 02602 int recv_avail; 02603 #endif /* LWIP_SO_RCVBUF */ 02604 02605 if (!sock) { 02606 return -1; 02607 } 02608 02609 switch (cmd) { 02610 #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE 02611 case FIONREAD: 02612 if (!argp) { 02613 sock_set_errno(sock, EINVAL); 02614 return -1; 02615 } 02616 #if LWIP_FIONREAD_LINUXMODE 02617 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 02618 struct pbuf *p; 02619 if (sock->lastdata) { 02620 p = ((struct netbuf *)sock->lastdata)->p; 02621 *((int*)argp) = p->tot_len - sock->lastoffset; 02622 } else { 02623 struct netbuf *rxbuf; 02624 err_t err; 02625 if (sock->rcvevent <= 0) { 02626 *((int*)argp) = 0; 02627 } else { 02628 err = netconn_recv(sock->conn, &rxbuf); 02629 if (err != ERR_OK) { 02630 *((int*)argp) = 0; 02631 } else { 02632 sock->lastdata = rxbuf; 02633 sock->lastoffset = 0; 02634 *((int*)argp) = rxbuf->p->tot_len; 02635 } 02636 } 02637 } 02638 return 0; 02639 } 02640 #endif /* LWIP_FIONREAD_LINUXMODE */ 02641 02642 #if LWIP_SO_RCVBUF 02643 /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */ 02644 SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); 02645 if (recv_avail < 0) { 02646 recv_avail = 0; 02647 } 02648 *((int*)argp) = recv_avail; 02649 02650 /* Check if there is data left from the last recv operation. /maq 041215 */ 02651 if (sock->lastdata) { 02652 struct pbuf *p = (struct pbuf *)sock->lastdata; 02653 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 02654 p = ((struct netbuf *)p)->p; 02655 } 02656 buflen = p->tot_len; 02657 buflen -= sock->lastoffset; 02658 02659 *((int*)argp) += buflen; 02660 } 02661 02662 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp))); 02663 sock_set_errno(sock, 0); 02664 return 0; 02665 #else /* LWIP_SO_RCVBUF */ 02666 break; 02667 #endif /* LWIP_SO_RCVBUF */ 02668 #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ 02669 02670 case (long)FIONBIO: 02671 val = 0; 02672 if (argp && *(u32_t*)argp) { 02673 val = 1; 02674 } 02675 netconn_set_nonblocking(sock->conn, val); 02676 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); 02677 sock_set_errno(sock, 0); 02678 return 0; 02679 02680 default: 02681 break; 02682 } /* switch (cmd) */ 02683 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); 02684 sock_set_errno(sock, ENOSYS); /* not yet implemented */ 02685 return -1; 02686 } 02687 02688 /** A minimal implementation of fcntl. 02689 * Currently only the commands F_GETFL and F_SETFL are implemented. 02690 * Only the flag O_NONBLOCK is implemented. 02691 */ 02692 int 02693 lwip_fcntl(int s, int cmd, int val) 02694 { 02695 struct lwip_sock *sock = get_socket(s); 02696 int ret = -1; 02697 02698 if (!sock) { 02699 return -1; 02700 } 02701 02702 switch (cmd) { 02703 case F_GETFL: 02704 ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; 02705 sock_set_errno(sock, 0); 02706 break; 02707 case F_SETFL: 02708 if ((val & ~O_NONBLOCK) == 0) { 02709 /* only O_NONBLOCK, all other bits are zero */ 02710 netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); 02711 ret = 0; 02712 sock_set_errno(sock, 0); 02713 } else { 02714 sock_set_errno(sock, ENOSYS); /* not yet implemented */ 02715 } 02716 break; 02717 default: 02718 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); 02719 sock_set_errno(sock, ENOSYS); /* not yet implemented */ 02720 break; 02721 } 02722 return ret; 02723 } 02724 02725 #if LWIP_IGMP 02726 /** Register a new IGMP membership. On socket close, the membership is dropped automatically. 02727 * 02728 * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). 02729 * 02730 * @return 1 on success, 0 on failure 02731 */ 02732 static int 02733 lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) 02734 { 02735 /* s+1 is stored in the array to prevent having to initialize the array 02736 (default initialization is to 0) */ 02737 int sa = s + 1; 02738 int i; 02739 02740 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 02741 if (socket_ipv4_multicast_memberships[i].sa == 0) { 02742 socket_ipv4_multicast_memberships[i].sa = sa; 02743 ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr); 02744 ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr); 02745 return 1; 02746 } 02747 } 02748 return 0; 02749 } 02750 02751 /** Unregister a previously registered membership. This prevents dropping the membership 02752 * on socket close. 02753 * 02754 * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). 02755 */ 02756 static void 02757 lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) 02758 { 02759 /* s+1 is stored in the array to prevent having to initialize the array 02760 (default initialization is to 0) */ 02761 int sa = s + 1; 02762 int i; 02763 02764 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 02765 if ((socket_ipv4_multicast_memberships[i].sa == sa) && 02766 ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) && 02767 ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) { 02768 socket_ipv4_multicast_memberships[i].sa = 0; 02769 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); 02770 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); 02771 return; 02772 } 02773 } 02774 } 02775 02776 /** Drop all memberships of a socket that were not dropped explicitly via setsockopt. 02777 * 02778 * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK). 02779 */ 02780 static void lwip_socket_drop_registered_memberships(int s) 02781 { 02782 /* s+1 is stored in the array to prevent having to initialize the array 02783 (default initialization is to 0) */ 02784 int sa = s + 1; 02785 int i; 02786 02787 LWIP_ASSERT("socket has no netconn", sockets[s].conn != NULL); 02788 02789 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 02790 if (socket_ipv4_multicast_memberships[i].sa == sa) { 02791 ip_addr_t multi_addr, if_addr; 02792 ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr); 02793 ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr); 02794 socket_ipv4_multicast_memberships[i].sa = 0; 02795 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); 02796 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); 02797 02798 netconn_join_leave_group(sockets[s].conn, &multi_addr, &if_addr, NETCONN_LEAVE); 02799 } 02800 } 02801 } 02802 #endif /* LWIP_IGMP */ 02803 #endif /* LWIP_SOCKET */
Generated on Tue Jul 12 2022 11:02:42 by
