Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
lwip_sockets.c
Go to the documentation of this file.
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 && (sockets[i].select_waiting == 0)) { 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 return i + LWIP_SOCKET_OFFSET; 00424 } 00425 SYS_ARCH_UNPROTECT(lev); 00426 } 00427 return -1; 00428 } 00429 00430 /** Free a socket. The socket's netconn must have been 00431 * delete before! 00432 * 00433 * @param sock the socket to free 00434 * @param is_tcp != 0 for TCP sockets, used to free lastdata 00435 */ 00436 static void 00437 free_socket(struct lwip_sock *sock, int is_tcp) 00438 { 00439 void *lastdata; 00440 00441 lastdata = sock->lastdata; 00442 sock->lastdata = NULL; 00443 sock->lastoffset = 0; 00444 sock->err = 0; 00445 00446 /* Protect socket array */ 00447 SYS_ARCH_SET(sock->conn, NULL); 00448 /* don't use 'sock' after this line, as another task might have allocated it */ 00449 00450 if (lastdata != NULL) { 00451 if (is_tcp) { 00452 pbuf_free((struct pbuf *)lastdata); 00453 } else { 00454 netbuf_delete((struct netbuf *)lastdata); 00455 } 00456 } 00457 } 00458 00459 /* Below this, the well-known socket functions are implemented. 00460 * Use google.com or opengroup.org to get a good description :-) 00461 * 00462 * Exceptions are documented! 00463 */ 00464 00465 int 00466 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) 00467 { 00468 struct lwip_sock *sock, *nsock; 00469 struct netconn *newconn; 00470 ip_addr_t naddr; 00471 u16_t port = 0; 00472 int newsock; 00473 err_t err; 00474 SYS_ARCH_DECL_PROTECT(lev); 00475 00476 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); 00477 sock = get_socket(s); 00478 if (!sock) { 00479 return -1; 00480 } 00481 00482 if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) { 00483 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); 00484 set_errno(EWOULDBLOCK); 00485 return -1; 00486 } 00487 00488 /* wait for a new connection */ 00489 err = netconn_accept(sock->conn, &newconn); 00490 if (err != ERR_OK) { 00491 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); 00492 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 00493 sock_set_errno(sock, EOPNOTSUPP); 00494 } else if (err == ERR_CLSD) { 00495 sock_set_errno(sock, EINVAL); 00496 } else { 00497 sock_set_errno(sock, err_to_errno(err)); 00498 } 00499 return -1; 00500 } 00501 LWIP_ASSERT("newconn != NULL", newconn != NULL); 00502 00503 newsock = alloc_socket(newconn, 1); 00504 if (newsock == -1) { 00505 netconn_delete(newconn); 00506 sock_set_errno(sock, ENFILE); 00507 return -1; 00508 } 00509 LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); 00510 LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback); 00511 nsock = &sockets[newsock - LWIP_SOCKET_OFFSET]; 00512 00513 /* See event_callback: If data comes in right away after an accept, even 00514 * though the server task might not have created a new socket yet. 00515 * In that case, newconn->socket is counted down (newconn->socket--), 00516 * so nsock->rcvevent is >= 1 here! 00517 */ 00518 SYS_ARCH_PROTECT(lev); 00519 nsock->rcvevent += (s16_t)(-1 - newconn->socket); 00520 newconn->socket = newsock; 00521 SYS_ARCH_UNPROTECT(lev); 00522 00523 /* Note that POSIX only requires us to check addr is non-NULL. addrlen must 00524 * not be NULL if addr is valid. 00525 */ 00526 if (addr != NULL) { 00527 union sockaddr_aligned tempaddr; 00528 /* get the IP address and port of the remote host */ 00529 err = netconn_peer(newconn, &naddr, &port); 00530 if (err != ERR_OK) { 00531 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); 00532 netconn_delete(newconn); 00533 free_socket(nsock, 1); 00534 sock_set_errno(sock, err_to_errno(err)); 00535 return -1; 00536 } 00537 LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); 00538 00539 IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port); 00540 if (*addrlen > tempaddr.sa.sa_len) { 00541 *addrlen = tempaddr.sa.sa_len; 00542 } 00543 MEMCPY(addr, &tempaddr, *addrlen); 00544 00545 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); 00546 ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); 00547 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); 00548 } else { 00549 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock)); 00550 } 00551 00552 sock_set_errno(sock, 0); 00553 return newsock; 00554 } 00555 00556 int 00557 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) 00558 { 00559 struct lwip_sock *sock; 00560 ip_addr_t local_addr; 00561 u16_t local_port; 00562 err_t err; 00563 00564 sock = get_socket(s); 00565 if (!sock) { 00566 return -1; 00567 } 00568 00569 if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { 00570 /* sockaddr does not match socket type (IPv4/IPv6) */ 00571 sock_set_errno(sock, err_to_errno(ERR_VAL)); 00572 return -1; 00573 } 00574 00575 /* check size, family and alignment of 'name' */ 00576 LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) && 00577 IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)), 00578 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 00579 LWIP_UNUSED_ARG(namelen); 00580 00581 SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port); 00582 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); 00583 ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr); 00584 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); 00585 00586 #if LWIP_IPV4 && LWIP_IPV6 00587 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ 00588 if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) { 00589 unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr)); 00590 IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4); 00591 } 00592 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 00593 00594 err = netconn_bind(sock->conn, &local_addr, local_port); 00595 00596 if (err != ERR_OK) { 00597 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); 00598 sock_set_errno(sock, err_to_errno(err)); 00599 return -1; 00600 } 00601 00602 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); 00603 sock_set_errno(sock, 0); 00604 return 0; 00605 } 00606 00607 int 00608 lwip_close(int s) 00609 { 00610 struct lwip_sock *sock; 00611 int is_tcp = 0; 00612 err_t err; 00613 00614 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); 00615 00616 sock = get_socket(s); 00617 if (!sock) { 00618 return -1; 00619 } 00620 00621 if (sock->conn != NULL) { 00622 is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; 00623 } else { 00624 LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL); 00625 } 00626 00627 #if LWIP_IGMP 00628 /* drop all possibly joined IGMP memberships */ 00629 lwip_socket_drop_registered_memberships(s); 00630 #endif /* LWIP_IGMP */ 00631 00632 err = netconn_delete(sock->conn); 00633 if (err != ERR_OK) { 00634 sock_set_errno(sock, err_to_errno(err)); 00635 return -1; 00636 } 00637 00638 free_socket(sock, is_tcp); 00639 set_errno(0); 00640 return 0; 00641 } 00642 00643 int 00644 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) 00645 { 00646 struct lwip_sock *sock; 00647 err_t err; 00648 00649 sock = get_socket(s); 00650 if (!sock) { 00651 return -1; 00652 } 00653 00654 if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { 00655 /* sockaddr does not match socket type (IPv4/IPv6) */ 00656 sock_set_errno(sock, err_to_errno(ERR_VAL)); 00657 return -1; 00658 } 00659 00660 LWIP_UNUSED_ARG(namelen); 00661 if (name->sa_family == AF_UNSPEC) { 00662 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); 00663 err = netconn_disconnect(sock->conn); 00664 } else { 00665 ip_addr_t remote_addr; 00666 u16_t remote_port; 00667 00668 /* check size, family and alignment of 'name' */ 00669 LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) && 00670 IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name), 00671 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 00672 00673 SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port); 00674 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); 00675 ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr); 00676 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port)); 00677 00678 #if LWIP_IPV4 && LWIP_IPV6 00679 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ 00680 if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) { 00681 unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr)); 00682 IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4); 00683 } 00684 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 00685 00686 err = netconn_connect(sock->conn, &remote_addr, remote_port); 00687 } 00688 00689 if (err != ERR_OK) { 00690 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); 00691 sock_set_errno(sock, err_to_errno(err)); 00692 return -1; 00693 } 00694 00695 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); 00696 sock_set_errno(sock, 0); 00697 return 0; 00698 } 00699 00700 /** 00701 * Set a socket into listen mode. 00702 * The socket may not have been used for another connection previously. 00703 * 00704 * @param s the socket to set to listening mode 00705 * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) 00706 * @return 0 on success, non-zero on failure 00707 */ 00708 int 00709 lwip_listen(int s, int backlog) 00710 { 00711 struct lwip_sock *sock; 00712 err_t err; 00713 00714 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); 00715 00716 sock = get_socket(s); 00717 if (!sock) { 00718 return -1; 00719 } 00720 00721 /* limit the "backlog" parameter to fit in an u8_t */ 00722 backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); 00723 00724 err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); 00725 00726 if (err != ERR_OK) { 00727 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); 00728 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 00729 sock_set_errno(sock, EOPNOTSUPP); 00730 return -1; 00731 } 00732 sock_set_errno(sock, err_to_errno(err)); 00733 return -1; 00734 } 00735 00736 sock_set_errno(sock, 0); 00737 return 0; 00738 } 00739 00740 int 00741 lwip_recvfrom(int s, void *mem, size_t len, int flags, 00742 struct sockaddr *from, socklen_t *fromlen) 00743 { 00744 struct lwip_sock *sock; 00745 void *buf = NULL; 00746 struct pbuf *p; 00747 u16_t buflen, copylen; 00748 int off = 0; 00749 u8_t done = 0; 00750 err_t err; 00751 00752 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); 00753 sock = get_socket(s); 00754 if (!sock) { 00755 return -1; 00756 } 00757 00758 do { 00759 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata)); 00760 /* Check if there is data left from the last recv operation. */ 00761 if (sock->lastdata) { 00762 buf = sock->lastdata; 00763 } else { 00764 /* If this is non-blocking call, then check first */ 00765 if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && 00766 (sock->rcvevent <= 0)) { 00767 if (off > 0) { 00768 /* already received data, return that */ 00769 sock_set_errno(sock, 0); 00770 return off; 00771 } 00772 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); 00773 set_errno(EWOULDBLOCK); 00774 return -1; 00775 } 00776 00777 /* No data was left from the previous operation, so we try to get 00778 some from the network. */ 00779 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 00780 err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf); 00781 } else { 00782 err = netconn_recv(sock->conn, (struct netbuf **)&buf); 00783 } 00784 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n", 00785 err, buf)); 00786 00787 if (err != ERR_OK) { 00788 if (off > 0) { 00789 if (err == ERR_CLSD) { 00790 /* closed but already received data, ensure select gets the FIN, too */ 00791 event_callback(sock->conn, NETCONN_EVT_RCVPLUS, 0); 00792 } 00793 /* already received data, return that */ 00794 sock_set_errno(sock, 0); 00795 return off; 00796 } 00797 /* We should really do some error checking here. */ 00798 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n", 00799 s, lwip_strerr(err))); 00800 sock_set_errno(sock, err_to_errno(err)); 00801 if (err == ERR_CLSD) { 00802 return 0; 00803 } else { 00804 return -1; 00805 } 00806 } 00807 LWIP_ASSERT("buf != NULL", buf != NULL); 00808 sock->lastdata = buf; 00809 } 00810 00811 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 00812 p = (struct pbuf *)buf; 00813 } else { 00814 p = ((struct netbuf *)buf)->p; 00815 } 00816 buflen = p->tot_len; 00817 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n", 00818 buflen, len, off, sock->lastoffset)); 00819 00820 buflen -= sock->lastoffset; 00821 00822 if (len > buflen) { 00823 copylen = buflen; 00824 } else { 00825 copylen = (u16_t)len; 00826 } 00827 00828 /* copy the contents of the received buffer into 00829 the supplied memory pointer mem */ 00830 pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset); 00831 00832 off += copylen; 00833 00834 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 00835 LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen); 00836 len -= copylen; 00837 if ((len <= 0) || 00838 (p->flags & PBUF_FLAG_PUSH) || 00839 (sock->rcvevent <= 0) || 00840 ((flags & MSG_PEEK) != 0)) { 00841 done = 1; 00842 } 00843 } else { 00844 done = 1; 00845 } 00846 00847 /* Check to see from where the data was.*/ 00848 if (done) { 00849 #if !SOCKETS_DEBUG 00850 if (from && fromlen) 00851 #endif /* !SOCKETS_DEBUG */ 00852 { 00853 u16_t port; 00854 ip_addr_t tmpaddr; 00855 ip_addr_t *fromaddr; 00856 union sockaddr_aligned saddr; 00857 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); 00858 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 00859 fromaddr = &tmpaddr; 00860 netconn_getaddr(sock->conn, fromaddr, &port, 0); 00861 } else { 00862 port = netbuf_fromport((struct netbuf *)buf); 00863 fromaddr = netbuf_fromaddr((struct netbuf *)buf); 00864 } 00865 00866 #if LWIP_IPV4 && LWIP_IPV6 00867 /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */ 00868 if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && IP_IS_V4(fromaddr)) { 00869 ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr)); 00870 IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6); 00871 } 00872 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 00873 00874 IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); 00875 ip_addr_debug_print(SOCKETS_DEBUG, fromaddr); 00876 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); 00877 #if SOCKETS_DEBUG 00878 if (from && fromlen) 00879 #endif /* SOCKETS_DEBUG */ 00880 { 00881 if (*fromlen > saddr.sa.sa_len) { 00882 *fromlen = saddr.sa.sa_len; 00883 } 00884 MEMCPY(from, &saddr, *fromlen); 00885 } 00886 } 00887 } 00888 00889 /* If we don't peek the incoming message... */ 00890 if ((flags & MSG_PEEK) == 0) { 00891 /* If this is a TCP socket, check if there is data left in the 00892 buffer. If so, it should be saved in the sock structure for next 00893 time around. */ 00894 if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (buflen - copylen > 0)) { 00895 sock->lastdata = buf; 00896 sock->lastoffset += copylen; 00897 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf)); 00898 } else { 00899 sock->lastdata = NULL; 00900 sock->lastoffset = 0; 00901 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf)); 00902 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 00903 pbuf_free((struct pbuf *)buf); 00904 } else { 00905 netbuf_delete((struct netbuf *)buf); 00906 } 00907 buf = NULL; 00908 } 00909 } 00910 } while (!done); 00911 00912 sock_set_errno(sock, 0); 00913 return off; 00914 } 00915 00916 int 00917 lwip_read(int s, void *mem, size_t len) 00918 { 00919 return lwip_recvfrom(s, mem, len, 0, NULL, NULL); 00920 } 00921 00922 int 00923 lwip_recv(int s, void *mem, size_t len, int flags) 00924 { 00925 return lwip_recvfrom(s, mem, len, flags, NULL, NULL); 00926 } 00927 00928 int 00929 lwip_send(int s, const void *data, size_t size, int flags) 00930 { 00931 struct lwip_sock *sock; 00932 err_t err; 00933 u8_t write_flags; 00934 size_t written; 00935 00936 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", 00937 s, data, size, flags)); 00938 00939 sock = get_socket(s); 00940 if (!sock) { 00941 return -1; 00942 } 00943 00944 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 00945 #if (LWIP_UDP || LWIP_RAW) 00946 return lwip_sendto(s, data, size, flags, NULL, 0); 00947 #else /* (LWIP_UDP || LWIP_RAW) */ 00948 sock_set_errno(sock, err_to_errno(ERR_ARG)); 00949 return -1; 00950 #endif /* (LWIP_UDP || LWIP_RAW) */ 00951 } 00952 00953 write_flags = NETCONN_COPY | 00954 ((flags & MSG_MORE) ? NETCONN_MORE : 0) | 00955 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); 00956 written = 0; 00957 err = netconn_write_partly(sock->conn, data, size, write_flags, &written); 00958 00959 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written)); 00960 sock_set_errno(sock, err_to_errno(err)); 00961 return (err == ERR_OK ? (int)written : -1); 00962 } 00963 00964 int 00965 lwip_sendmsg(int s, const struct msghdr *msg, int flags) 00966 { 00967 struct lwip_sock *sock; 00968 int i; 00969 #if LWIP_TCP 00970 u8_t write_flags; 00971 size_t written; 00972 #endif 00973 int size = 0; 00974 err_t err = ERR_OK; 00975 00976 sock = get_socket(s); 00977 if (!sock) { 00978 return -1; 00979 } 00980 00981 LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL, 00982 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 00983 00984 LWIP_UNUSED_ARG(msg->msg_control); 00985 LWIP_UNUSED_ARG(msg->msg_controllen); 00986 LWIP_UNUSED_ARG(msg->msg_flags); 00987 LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", (msg->msg_iov != NULL && msg->msg_iovlen != 0), 00988 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 00989 00990 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 00991 #if LWIP_TCP 00992 write_flags = NETCONN_COPY | 00993 ((flags & MSG_MORE) ? NETCONN_MORE : 0) | 00994 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); 00995 00996 for (i = 0; i < msg->msg_iovlen; i++) { 00997 u8_t apiflags = write_flags; 00998 if (i + 1 < msg->msg_iovlen) { 00999 apiflags |= NETCONN_MORE; 01000 } 01001 written = 0; 01002 err = netconn_write_partly(sock->conn, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len, write_flags, &written); 01003 if (err == ERR_OK) { 01004 size += written; 01005 /* check that the entire IO vector was accepected, if not return a partial write */ 01006 if (written != msg->msg_iov[i].iov_len) 01007 break; 01008 } 01009 /* none of this IO vector was accepted, but previous was, return partial write and conceal ERR_WOULDBLOCK */ 01010 else if (err == ERR_WOULDBLOCK && size > 0) { 01011 err = ERR_OK; 01012 /* let ERR_WOULDBLOCK persist on the netconn since we are returning ERR_OK */ 01013 break; 01014 } else { 01015 size = -1; 01016 break; 01017 } 01018 } 01019 sock_set_errno(sock, err_to_errno(err)); 01020 return size; 01021 #else /* LWIP_TCP */ 01022 sock_set_errno(sock, err_to_errno(ERR_ARG)); 01023 return -1; 01024 #endif /* LWIP_TCP */ 01025 } 01026 /* else, UDP and RAW NETCONNs */ 01027 #if LWIP_UDP || LWIP_RAW 01028 { 01029 struct netbuf *chain_buf; 01030 01031 LWIP_UNUSED_ARG(flags); 01032 LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) || 01033 IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)) , 01034 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 01035 01036 /* initialize chain buffer with destination */ 01037 chain_buf = netbuf_new(); 01038 if (!chain_buf) { 01039 sock_set_errno(sock, err_to_errno(ERR_MEM)); 01040 return -1; 01041 } 01042 if (msg->msg_name) { 01043 u16_t remote_port; 01044 SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf->addr, remote_port); 01045 netbuf_fromport(chain_buf) = remote_port; 01046 } 01047 #if LWIP_NETIF_TX_SINGLE_PBUF 01048 for (i = 0; i < msg->msg_iovlen; i++) { 01049 size += msg->msg_iov[i].iov_len; 01050 } 01051 /* Allocate a new netbuf and copy the data into it. */ 01052 if (netbuf_alloc(chain_buf, (u16_t)size) == NULL) { 01053 err = ERR_MEM; 01054 } else { 01055 /* flatten the IO vectors */ 01056 size_t offset = 0; 01057 for (i = 0; i < msg->msg_iovlen; i++) { 01058 MEMCPY(&((u8_t*)chain_buf->p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); 01059 offset += msg->msg_iov[i].iov_len; 01060 } 01061 #if LWIP_CHECKSUM_ON_COPY 01062 { 01063 /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */ 01064 u16_t chksum = ~inet_chksum_pbuf(chain_buf->p); 01065 netbuf_set_chksum(chain_buf, chksum); 01066 } 01067 #endif /* LWIP_CHECKSUM_ON_COPY */ 01068 err = ERR_OK; 01069 } 01070 #else /* LWIP_NETIF_TX_SINGLE_PBUF */ 01071 /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain 01072 manually to avoid having to allocate, chain, and delete a netbuf for each iov */ 01073 for (i = 0; i < msg->msg_iovlen; i++) { 01074 struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); 01075 if (p == NULL) { 01076 err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */ 01077 break; 01078 } 01079 p->payload = msg->msg_iov[i].iov_base; 01080 LWIP_ASSERT("iov_len < u16_t", msg->msg_iov[i].iov_len <= 0xFFFF); 01081 p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len; 01082 /* netbuf empty, add new pbuf */ 01083 if (chain_buf->p == NULL) { 01084 chain_buf->p = chain_buf->ptr = p; 01085 /* add pbuf to existing pbuf chain */ 01086 } else { 01087 pbuf_cat(chain_buf->p, p); 01088 } 01089 } 01090 /* save size of total chain */ 01091 if (err == ERR_OK) { 01092 size = netbuf_len(chain_buf); 01093 } 01094 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ 01095 01096 if (err == ERR_OK) { 01097 #if LWIP_IPV4 && LWIP_IPV6 01098 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ 01099 if (IP_IS_V6_VAL(chain_buf->addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf->addr))) { 01100 unmap_ipv4_mapped_ipv6(ip_2_ip4(&chain_buf->addr), ip_2_ip6(&chain_buf->addr)); 01101 IP_SET_TYPE_VAL(chain_buf->addr, IPADDR_TYPE_V4); 01102 } 01103 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 01104 01105 /* send the data */ 01106 err = netconn_send(sock->conn, chain_buf); 01107 } 01108 01109 /* deallocated the buffer */ 01110 netbuf_delete(chain_buf); 01111 01112 sock_set_errno(sock, err_to_errno(err)); 01113 return (err == ERR_OK ? size : -1); 01114 } 01115 #else /* LWIP_UDP || LWIP_RAW */ 01116 sock_set_errno(sock, err_to_errno(ERR_ARG)); 01117 return -1; 01118 #endif /* LWIP_UDP || LWIP_RAW */ 01119 } 01120 01121 int 01122 lwip_sendto(int s, const void *data, size_t size, int flags, 01123 const struct sockaddr *to, socklen_t tolen) 01124 { 01125 struct lwip_sock *sock; 01126 err_t err; 01127 u16_t short_size; 01128 u16_t remote_port; 01129 struct netbuf buf; 01130 01131 sock = get_socket(s); 01132 if (!sock) { 01133 return -1; 01134 } 01135 01136 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 01137 #if LWIP_TCP 01138 return lwip_send(s, data, size, flags); 01139 #else /* LWIP_TCP */ 01140 LWIP_UNUSED_ARG(flags); 01141 sock_set_errno(sock, err_to_errno(ERR_ARG)); 01142 return -1; 01143 #endif /* LWIP_TCP */ 01144 } 01145 01146 /* @todo: split into multiple sendto's? */ 01147 LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); 01148 short_size = (u16_t)size; 01149 LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || 01150 (IS_SOCK_ADDR_LEN_VALID(tolen) && 01151 IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))), 01152 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 01153 LWIP_UNUSED_ARG(tolen); 01154 01155 /* initialize a buffer */ 01156 buf.p = buf.ptr = NULL; 01157 #if LWIP_CHECKSUM_ON_COPY 01158 buf.flags = 0; 01159 #endif /* LWIP_CHECKSUM_ON_COPY */ 01160 if (to) { 01161 SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port); 01162 } else { 01163 remote_port = 0; 01164 ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr); 01165 } 01166 netbuf_fromport(&buf) = remote_port; 01167 01168 01169 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", 01170 s, data, short_size, flags)); 01171 ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr); 01172 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); 01173 01174 /* make the buffer point to the data that should be sent */ 01175 #if LWIP_NETIF_TX_SINGLE_PBUF 01176 /* Allocate a new netbuf and copy the data into it. */ 01177 if (netbuf_alloc(&buf, short_size) == NULL) { 01178 err = ERR_MEM; 01179 } else { 01180 #if LWIP_CHECKSUM_ON_COPY 01181 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) { 01182 u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); 01183 netbuf_set_chksum(&buf, chksum); 01184 } else 01185 #endif /* LWIP_CHECKSUM_ON_COPY */ 01186 { 01187 MEMCPY(buf.p->payload, data, short_size); 01188 } 01189 err = ERR_OK; 01190 } 01191 #else /* LWIP_NETIF_TX_SINGLE_PBUF */ 01192 err = netbuf_ref(&buf, data, short_size); 01193 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ 01194 if (err == ERR_OK) { 01195 #if LWIP_IPV4 && LWIP_IPV6 01196 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ 01197 if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) { 01198 unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr)); 01199 IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4); 01200 } 01201 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 01202 01203 /* send the data */ 01204 err = netconn_send(sock->conn, &buf); 01205 } 01206 01207 /* deallocated the buffer */ 01208 netbuf_free(&buf); 01209 01210 sock_set_errno(sock, err_to_errno(err)); 01211 return (err == ERR_OK ? short_size : -1); 01212 } 01213 01214 int 01215 lwip_socket(int domain, int type, int protocol) 01216 { 01217 struct netconn *conn; 01218 int i; 01219 01220 LWIP_UNUSED_ARG(domain); /* @todo: check this */ 01221 01222 /* create a netconn */ 01223 switch (type) { 01224 case SOCK_RAW: 01225 conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), 01226 (u8_t)protocol, event_callback); 01227 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", 01228 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 01229 break; 01230 case SOCK_DGRAM: 01231 conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, 01232 ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) , 01233 event_callback); 01234 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", 01235 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 01236 break; 01237 case SOCK_STREAM: 01238 conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), event_callback); 01239 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", 01240 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 01241 break; 01242 default: 01243 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", 01244 domain, type, protocol)); 01245 set_errno(EINVAL); 01246 return -1; 01247 } 01248 01249 if (!conn) { 01250 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); 01251 set_errno(ENOBUFS); 01252 return -1; 01253 } 01254 01255 i = alloc_socket(conn, 0); 01256 01257 if (i == -1) { 01258 netconn_delete(conn); 01259 set_errno(ENFILE); 01260 return -1; 01261 } 01262 conn->socket = i; 01263 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); 01264 set_errno(0); 01265 return i; 01266 } 01267 01268 int 01269 lwip_write(int s, const void *data, size_t size) 01270 { 01271 return lwip_send(s, data, size, 0); 01272 } 01273 01274 int 01275 lwip_writev(int s, const struct iovec *iov, int iovcnt) 01276 { 01277 struct msghdr msg; 01278 01279 msg.msg_name = NULL; 01280 msg.msg_namelen = 0; 01281 /* Hack: we have to cast via number to cast from 'const' pointer to non-const. 01282 Blame the opengroup standard for this inconsistency. */ 01283 msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov); 01284 msg.msg_iovlen = iovcnt; 01285 msg.msg_control = NULL; 01286 msg.msg_controllen = 0; 01287 msg.msg_flags = 0; 01288 return lwip_sendmsg(s, &msg, 0); 01289 } 01290 01291 /** 01292 * Go through the readset and writeset lists and see which socket of the sockets 01293 * set in the sets has events. On return, readset, writeset and exceptset have 01294 * the sockets enabled that had events. 01295 * 01296 * @param maxfdp1 the highest socket index in the sets 01297 * @param readset_in set of sockets to check for read events 01298 * @param writeset_in set of sockets to check for write events 01299 * @param exceptset_in set of sockets to check for error events 01300 * @param readset_out set of sockets that had read events 01301 * @param writeset_out set of sockets that had write events 01302 * @param exceptset_out set os sockets that had error events 01303 * @return number of sockets that had events (read/write/exception) (>= 0) 01304 */ 01305 static int 01306 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, 01307 fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) 01308 { 01309 int i, nready = 0; 01310 fd_set lreadset, lwriteset, lexceptset; 01311 struct lwip_sock *sock; 01312 SYS_ARCH_DECL_PROTECT(lev); 01313 01314 FD_ZERO(&lreadset); 01315 FD_ZERO(&lwriteset); 01316 FD_ZERO(&lexceptset); 01317 01318 /* Go through each socket in each list to count number of sockets which 01319 currently match */ 01320 for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { 01321 /* if this FD is not in the set, continue */ 01322 if (!(readset_in && FD_ISSET(i, readset_in)) && 01323 !(writeset_in && FD_ISSET(i, writeset_in)) && 01324 !(exceptset_in && FD_ISSET(i, exceptset_in))) { 01325 continue; 01326 } 01327 /* First get the socket's status (protected)... */ 01328 SYS_ARCH_PROTECT(lev); 01329 sock = tryget_socket(i); 01330 if (sock != NULL) { 01331 void* lastdata = sock->lastdata; 01332 s16_t rcvevent = sock->rcvevent; 01333 u16_t sendevent = sock->sendevent; 01334 u16_t errevent = sock->errevent; 01335 SYS_ARCH_UNPROTECT(lev); 01336 01337 /* ... then examine it: */ 01338 /* See if netconn of this socket is ready for read */ 01339 if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { 01340 FD_SET(i, &lreadset); 01341 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); 01342 nready++; 01343 } 01344 /* See if netconn of this socket is ready for write */ 01345 if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { 01346 FD_SET(i, &lwriteset); 01347 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); 01348 nready++; 01349 } 01350 /* See if netconn of this socket had an error */ 01351 if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { 01352 FD_SET(i, &lexceptset); 01353 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); 01354 nready++; 01355 } 01356 } else { 01357 SYS_ARCH_UNPROTECT(lev); 01358 /* continue on to next FD in list */ 01359 } 01360 } 01361 /* copy local sets to the ones provided as arguments */ 01362 *readset_out = lreadset; 01363 *writeset_out = lwriteset; 01364 *exceptset_out = lexceptset; 01365 01366 LWIP_ASSERT("nready >= 0", nready >= 0); 01367 return nready; 01368 } 01369 01370 int 01371 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, 01372 struct timeval *timeout) 01373 { 01374 u32_t waitres = 0; 01375 int nready; 01376 fd_set lreadset, lwriteset, lexceptset; 01377 u32_t msectimeout; 01378 struct lwip_select_cb select_cb; 01379 int i; 01380 int maxfdp2; 01381 #if LWIP_NETCONN_SEM_PER_THREAD 01382 int waited = 0; 01383 #endif 01384 SYS_ARCH_DECL_PROTECT(lev); 01385 01386 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", 01387 maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, 01388 timeout ? (s32_t)timeout->tv_sec : (s32_t)-1, 01389 timeout ? (s32_t)timeout->tv_usec : (s32_t)-1)); 01390 01391 /* Go through each socket in each list to count number of sockets which 01392 currently match */ 01393 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 01394 01395 /* If we don't have any current events, then suspend if we are supposed to */ 01396 if (!nready) { 01397 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { 01398 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); 01399 /* This is OK as the local fdsets are empty and nready is zero, 01400 or we would have returned earlier. */ 01401 goto return_copy_fdsets; 01402 } 01403 01404 /* None ready: add our semaphore to list: 01405 We don't actually need any dynamic memory. Our entry on the 01406 list is only valid while we are in this function, so it's ok 01407 to use local variables. */ 01408 01409 select_cb.next = NULL; 01410 select_cb.prev = NULL; 01411 select_cb.readset = readset; 01412 select_cb.writeset = writeset; 01413 select_cb.exceptset = exceptset; 01414 select_cb.sem_signalled = 0; 01415 #if LWIP_NETCONN_SEM_PER_THREAD 01416 select_cb.sem = LWIP_NETCONN_THREAD_SEM_GET(); 01417 #else /* LWIP_NETCONN_SEM_PER_THREAD */ 01418 if (sys_sem_new(&select_cb.sem, 0) != ERR_OK) { 01419 /* failed to create semaphore */ 01420 set_errno(ENOMEM); 01421 return -1; 01422 } 01423 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 01424 01425 /* Protect the select_cb_list */ 01426 SYS_ARCH_PROTECT(lev); 01427 01428 /* Put this select_cb on top of list */ 01429 select_cb.next = select_cb_list; 01430 if (select_cb_list != NULL) { 01431 select_cb_list->prev = &select_cb; 01432 } 01433 select_cb_list = &select_cb; 01434 /* Increasing this counter tells event_callback that the list has changed. */ 01435 select_cb_ctr++; 01436 01437 /* Now we can safely unprotect */ 01438 SYS_ARCH_UNPROTECT(lev); 01439 01440 /* Increase select_waiting for each socket we are interested in */ 01441 maxfdp2 = maxfdp1; 01442 for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { 01443 if ((readset && FD_ISSET(i, readset)) || 01444 (writeset && FD_ISSET(i, writeset)) || 01445 (exceptset && FD_ISSET(i, exceptset))) { 01446 struct lwip_sock *sock; 01447 SYS_ARCH_PROTECT(lev); 01448 sock = tryget_socket(i); 01449 if (sock != NULL) { 01450 sock->select_waiting++; 01451 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); 01452 } else { 01453 /* Not a valid socket */ 01454 nready = -1; 01455 maxfdp2 = i; 01456 SYS_ARCH_UNPROTECT(lev); 01457 break; 01458 } 01459 SYS_ARCH_UNPROTECT(lev); 01460 } 01461 } 01462 01463 if (nready >= 0) { 01464 /* Call lwip_selscan again: there could have been events between 01465 the last scan (without us on the list) and putting us on the list! */ 01466 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 01467 if (!nready) { 01468 /* Still none ready, just wait to be woken */ 01469 if (timeout == 0) { 01470 /* Wait forever */ 01471 msectimeout = 0; 01472 } else { 01473 msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); 01474 if (msectimeout == 0) { 01475 /* Wait 1ms at least (0 means wait forever) */ 01476 msectimeout = 1; 01477 } 01478 } 01479 01480 waitres = sys_arch_sem_wait(SELECT_SEM_PTR(select_cb.sem), msectimeout); 01481 #if LWIP_NETCONN_SEM_PER_THREAD 01482 waited = 1; 01483 #endif 01484 } 01485 } 01486 01487 /* Decrease select_waiting for each socket we are interested in */ 01488 for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) { 01489 if ((readset && FD_ISSET(i, readset)) || 01490 (writeset && FD_ISSET(i, writeset)) || 01491 (exceptset && FD_ISSET(i, exceptset))) { 01492 struct lwip_sock *sock; 01493 SYS_ARCH_PROTECT(lev); 01494 sock = tryget_socket(i); 01495 if (sock != NULL) { 01496 /* for now, handle select_waiting==0... */ 01497 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); 01498 if (sock->select_waiting > 0) { 01499 sock->select_waiting--; 01500 } 01501 } else { 01502 /* Not a valid socket */ 01503 nready = -1; 01504 } 01505 SYS_ARCH_UNPROTECT(lev); 01506 } 01507 } 01508 /* Take us off the list */ 01509 SYS_ARCH_PROTECT(lev); 01510 if (select_cb.next != NULL) { 01511 select_cb.next->prev = select_cb.prev; 01512 } 01513 if (select_cb_list == &select_cb) { 01514 LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL); 01515 select_cb_list = select_cb.next; 01516 } else { 01517 LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL); 01518 select_cb.prev->next = select_cb.next; 01519 } 01520 /* Increasing this counter tells event_callback that the list has changed. */ 01521 select_cb_ctr++; 01522 SYS_ARCH_UNPROTECT(lev); 01523 01524 #if LWIP_NETCONN_SEM_PER_THREAD 01525 if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { 01526 /* don't leave the thread-local semaphore signalled */ 01527 sys_arch_sem_wait(select_cb.sem, 1); 01528 } 01529 #else /* LWIP_NETCONN_SEM_PER_THREAD */ 01530 sys_sem_free(&select_cb.sem); 01531 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 01532 01533 if (nready < 0) { 01534 /* This happens when a socket got closed while waiting */ 01535 set_errno(EBADF); 01536 return -1; 01537 } 01538 01539 if (waitres == SYS_ARCH_TIMEOUT) { 01540 /* Timeout */ 01541 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); 01542 /* This is OK as the local fdsets are empty and nready is zero, 01543 or we would have returned earlier. */ 01544 goto return_copy_fdsets; 01545 } 01546 01547 /* See what's set */ 01548 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 01549 } 01550 01551 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); 01552 return_copy_fdsets: 01553 set_errno(0); 01554 if (readset) { 01555 *readset = lreadset; 01556 } 01557 if (writeset) { 01558 *writeset = lwriteset; 01559 } 01560 if (exceptset) { 01561 *exceptset = lexceptset; 01562 } 01563 return nready; 01564 } 01565 01566 /** 01567 * Callback registered in the netconn layer for each socket-netconn. 01568 * Processes recvevent (data available) and wakes up tasks waiting for select. 01569 */ 01570 static void 01571 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) 01572 { 01573 int s; 01574 struct lwip_sock *sock; 01575 struct lwip_select_cb *scb; 01576 int last_select_cb_ctr; 01577 SYS_ARCH_DECL_PROTECT(lev); 01578 01579 LWIP_UNUSED_ARG(len); 01580 01581 /* Get socket */ 01582 if (conn) { 01583 s = conn->socket; 01584 if (s < 0) { 01585 /* Data comes in right away after an accept, even though 01586 * the server task might not have created a new socket yet. 01587 * Just count down (or up) if that's the case and we 01588 * will use the data later. Note that only receive events 01589 * can happen before the new socket is set up. */ 01590 SYS_ARCH_PROTECT(lev); 01591 if (conn->socket < 0) { 01592 if (evt == NETCONN_EVT_RCVPLUS) { 01593 conn->socket--; 01594 } 01595 SYS_ARCH_UNPROTECT(lev); 01596 return; 01597 } 01598 s = conn->socket; 01599 SYS_ARCH_UNPROTECT(lev); 01600 } 01601 01602 sock = get_socket(s); 01603 if (!sock) { 01604 return; 01605 } 01606 } else { 01607 return; 01608 } 01609 01610 SYS_ARCH_PROTECT(lev); 01611 /* Set event as required */ 01612 switch (evt) { 01613 case NETCONN_EVT_RCVPLUS: 01614 sock->rcvevent++; 01615 break; 01616 case NETCONN_EVT_RCVMINUS: 01617 sock->rcvevent--; 01618 break; 01619 case NETCONN_EVT_SENDPLUS: 01620 sock->sendevent = 1; 01621 break; 01622 case NETCONN_EVT_SENDMINUS: 01623 sock->sendevent = 0; 01624 break; 01625 case NETCONN_EVT_ERROR: 01626 sock->errevent = 1; 01627 break; 01628 default: 01629 LWIP_ASSERT("unknown event", 0); 01630 break; 01631 } 01632 01633 if (sock->select_waiting == 0) { 01634 /* noone is waiting for this socket, no need to check select_cb_list */ 01635 SYS_ARCH_UNPROTECT(lev); 01636 return; 01637 } 01638 01639 /* Now decide if anyone is waiting for this socket */ 01640 /* NOTE: This code goes through the select_cb_list list multiple times 01641 ONLY IF a select was actually waiting. We go through the list the number 01642 of waiting select calls + 1. This list is expected to be small. */ 01643 01644 /* At this point, SYS_ARCH is still protected! */ 01645 again: 01646 for (scb = select_cb_list; scb != NULL; scb = scb->next) { 01647 /* remember the state of select_cb_list to detect changes */ 01648 last_select_cb_ctr = select_cb_ctr; 01649 if (scb->sem_signalled == 0) { 01650 /* semaphore not signalled yet */ 01651 int do_signal = 0; 01652 /* Test this select call for our socket */ 01653 if (sock->rcvevent > 0) { 01654 if (scb->readset && FD_ISSET(s, scb->readset)) { 01655 do_signal = 1; 01656 } 01657 } 01658 if (sock->sendevent != 0) { 01659 if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { 01660 do_signal = 1; 01661 } 01662 } 01663 if (sock->errevent != 0) { 01664 if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { 01665 do_signal = 1; 01666 } 01667 } 01668 if (do_signal) { 01669 scb->sem_signalled = 1; 01670 /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might 01671 lead to the select thread taking itself off the list, invalidating the semaphore. */ 01672 sys_sem_signal(SELECT_SEM_PTR(scb->sem)); 01673 } 01674 } 01675 /* unlock interrupts with each step */ 01676 SYS_ARCH_UNPROTECT(lev); 01677 /* this makes sure interrupt protection time is short */ 01678 SYS_ARCH_PROTECT(lev); 01679 if (last_select_cb_ctr != select_cb_ctr) { 01680 /* someone has changed select_cb_list, restart at the beginning */ 01681 goto again; 01682 } 01683 } 01684 SYS_ARCH_UNPROTECT(lev); 01685 } 01686 01687 /** 01688 * Close one end of a full-duplex connection. 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 IPv4 mapped IPv6 */ 01754 if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && 01755 IP_IS_V4_VAL(naddr)) { 01756 ip4_2_ipv4_mapped_ipv6(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 /* It should not be possible to disable the checksum generation with ICMPv6 02578 * as per RFC 3542 chapter 3.1 */ 02579 if(sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) { 02580 return EINVAL; 02581 } 02582 02583 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW); 02584 if (*(const int *)optval < 0) { 02585 sock->conn->pcb.raw->chksum_reqd = 0; 02586 } else if (*(const int *)optval & 1) { 02587 /* Per RFC3542, odd offsets are not allowed */ 02588 return EINVAL; 02589 } else { 02590 sock->conn->pcb.raw->chksum_reqd = 1; 02591 sock->conn->pcb.raw->chksum_offset = (u16_t)*(const int *)optval; 02592 } 02593 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n", 02594 s, sock->conn->pcb.raw->chksum_reqd)); 02595 break; 02596 #endif /* LWIP_IPV6 && LWIP_RAW */ 02597 default: 02598 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", 02599 s, optname)); 02600 err = ENOPROTOOPT; 02601 break; 02602 } /* switch (optname) */ 02603 break; 02604 default: 02605 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", 02606 s, level, optname)); 02607 err = ENOPROTOOPT; 02608 break; 02609 } /* switch (level) */ 02610 02611 return err; 02612 } 02613 02614 int 02615 lwip_ioctl(int s, long cmd, void *argp) 02616 { 02617 struct lwip_sock *sock = get_socket(s); 02618 u8_t val; 02619 #if LWIP_SO_RCVBUF 02620 u16_t buflen = 0; 02621 int recv_avail; 02622 #endif /* LWIP_SO_RCVBUF */ 02623 02624 if (!sock) { 02625 return -1; 02626 } 02627 02628 switch (cmd) { 02629 #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE 02630 case FIONREAD: 02631 if (!argp) { 02632 sock_set_errno(sock, EINVAL); 02633 return -1; 02634 } 02635 #if LWIP_FIONREAD_LINUXMODE 02636 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 02637 struct pbuf *p; 02638 if (sock->lastdata) { 02639 p = ((struct netbuf *)sock->lastdata)->p; 02640 *((int*)argp) = p->tot_len - sock->lastoffset; 02641 } else { 02642 struct netbuf *rxbuf; 02643 err_t err; 02644 if (sock->rcvevent <= 0) { 02645 *((int*)argp) = 0; 02646 } else { 02647 err = netconn_recv(sock->conn, &rxbuf); 02648 if (err != ERR_OK) { 02649 *((int*)argp) = 0; 02650 } else { 02651 sock->lastdata = rxbuf; 02652 sock->lastoffset = 0; 02653 *((int*)argp) = rxbuf->p->tot_len; 02654 } 02655 } 02656 } 02657 return 0; 02658 } 02659 #endif /* LWIP_FIONREAD_LINUXMODE */ 02660 02661 #if LWIP_SO_RCVBUF 02662 /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */ 02663 SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); 02664 if (recv_avail < 0) { 02665 recv_avail = 0; 02666 } 02667 *((int*)argp) = recv_avail; 02668 02669 /* Check if there is data left from the last recv operation. /maq 041215 */ 02670 if (sock->lastdata) { 02671 struct pbuf *p = (struct pbuf *)sock->lastdata; 02672 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 02673 p = ((struct netbuf *)p)->p; 02674 } 02675 buflen = p->tot_len; 02676 buflen -= sock->lastoffset; 02677 02678 *((int*)argp) += buflen; 02679 } 02680 02681 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp))); 02682 sock_set_errno(sock, 0); 02683 return 0; 02684 #else /* LWIP_SO_RCVBUF */ 02685 break; 02686 #endif /* LWIP_SO_RCVBUF */ 02687 #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ 02688 02689 case (long)FIONBIO: 02690 val = 0; 02691 if (argp && *(u32_t*)argp) { 02692 val = 1; 02693 } 02694 netconn_set_nonblocking(sock->conn, val); 02695 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); 02696 sock_set_errno(sock, 0); 02697 return 0; 02698 02699 default: 02700 break; 02701 } /* switch (cmd) */ 02702 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); 02703 sock_set_errno(sock, ENOSYS); /* not yet implemented */ 02704 return -1; 02705 } 02706 02707 /** A minimal implementation of fcntl. 02708 * Currently only the commands F_GETFL and F_SETFL are implemented. 02709 * Only the flag O_NONBLOCK is implemented. 02710 */ 02711 int 02712 lwip_fcntl(int s, int cmd, int val) 02713 { 02714 struct lwip_sock *sock = get_socket(s); 02715 int ret = -1; 02716 02717 if (!sock) { 02718 return -1; 02719 } 02720 02721 switch (cmd) { 02722 case F_GETFL: 02723 ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; 02724 sock_set_errno(sock, 0); 02725 break; 02726 case F_SETFL: 02727 if ((val & ~O_NONBLOCK) == 0) { 02728 /* only O_NONBLOCK, all other bits are zero */ 02729 netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); 02730 ret = 0; 02731 sock_set_errno(sock, 0); 02732 } else { 02733 sock_set_errno(sock, ENOSYS); /* not yet implemented */ 02734 } 02735 break; 02736 default: 02737 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); 02738 sock_set_errno(sock, ENOSYS); /* not yet implemented */ 02739 break; 02740 } 02741 return ret; 02742 } 02743 02744 #if LWIP_IGMP 02745 /** Register a new IGMP membership. On socket close, the membership is dropped automatically. 02746 * 02747 * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). 02748 * 02749 * @return 1 on success, 0 on failure 02750 */ 02751 static int 02752 lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) 02753 { 02754 struct lwip_sock *sock = get_socket(s); 02755 int i; 02756 02757 if (!sock) { 02758 return 0; 02759 } 02760 02761 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 02762 if (socket_ipv4_multicast_memberships[i].sock == NULL) { 02763 socket_ipv4_multicast_memberships[i].sock = sock; 02764 ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr); 02765 ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr); 02766 return 1; 02767 } 02768 } 02769 return 0; 02770 } 02771 02772 /** Unregister a previously registered membership. This prevents dropping the membership 02773 * on socket close. 02774 * 02775 * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). 02776 */ 02777 static void 02778 lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) 02779 { 02780 struct lwip_sock *sock = get_socket(s); 02781 int i; 02782 02783 if (!sock) { 02784 return; 02785 } 02786 02787 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 02788 if ((socket_ipv4_multicast_memberships[i].sock == sock) && 02789 ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) && 02790 ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) { 02791 socket_ipv4_multicast_memberships[i].sock = NULL; 02792 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); 02793 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); 02794 return; 02795 } 02796 } 02797 } 02798 02799 /** Drop all memberships of a socket that were not dropped explicitly via setsockopt. 02800 * 02801 * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK). 02802 */ 02803 static void 02804 lwip_socket_drop_registered_memberships(int s) 02805 { 02806 struct lwip_sock *sock = get_socket(s); 02807 int i; 02808 02809 if (!sock) { 02810 return; 02811 } 02812 02813 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 02814 if (socket_ipv4_multicast_memberships[i].sock == sock) { 02815 ip_addr_t multi_addr, if_addr; 02816 ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr); 02817 ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr); 02818 socket_ipv4_multicast_memberships[i].sock = NULL; 02819 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); 02820 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); 02821 02822 netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE); 02823 } 02824 } 02825 } 02826 #endif /* LWIP_IGMP */ 02827 #endif /* LWIP_SOCKET */
Generated on Sun Jul 17 2022 08:25:25 by 1.7.2