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