[457] | 1 | /**
|
---|
| 2 | * @file
|
---|
| 3 | * Sockets BSD-Like API module
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
| 7 | * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
---|
| 8 | * All rights reserved.
|
---|
| 9 | *
|
---|
| 10 | * Redistribution and use in source and binary forms, with or without modification,
|
---|
| 11 | * are permitted provided that the following conditions are met:
|
---|
| 12 | *
|
---|
| 13 | * 1. Redistributions of source code must retain the above copyright notice,
|
---|
| 14 | * this list of conditions and the following disclaimer.
|
---|
| 15 | * 2. Redistributions in binary form must reproduce the above copyright notice,
|
---|
| 16 | * this list of conditions and the following disclaimer in the documentation
|
---|
| 17 | * and/or other materials provided with the distribution.
|
---|
| 18 | * 3. The name of the author may not be used to endorse or promote products
|
---|
| 19 | * derived from this software without specific prior written permission.
|
---|
| 20 | *
|
---|
| 21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
---|
| 22 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
---|
| 23 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
---|
| 24 | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
---|
| 25 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
---|
| 26 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
---|
| 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
---|
| 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
---|
| 29 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
---|
| 30 | * OF SUCH DAMAGE.
|
---|
| 31 | *
|
---|
| 32 | * This file is part of the lwIP TCP/IP stack.
|
---|
| 33 | *
|
---|
| 34 | * Author: Adam Dunkels <adam@sics.se>
|
---|
| 35 | *
|
---|
| 36 | * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
|
---|
| 37 | *
|
---|
| 38 | */
|
---|
| 39 |
|
---|
| 40 | #include "lwip/opt.h"
|
---|
| 41 |
|
---|
| 42 | #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
|
---|
| 43 |
|
---|
| 44 | #include "lwip/sockets.h"
|
---|
| 45 | #include "lwip/priv/sockets_priv.h"
|
---|
| 46 | #include "lwip/api.h"
|
---|
| 47 | #include "lwip/igmp.h"
|
---|
| 48 | #include "lwip/inet.h"
|
---|
| 49 | #include "lwip/tcp.h"
|
---|
| 50 | #include "lwip/raw.h"
|
---|
| 51 | #include "lwip/udp.h"
|
---|
| 52 | #include "lwip/memp.h"
|
---|
| 53 | #include "lwip/pbuf.h"
|
---|
| 54 | #include "lwip/netif.h"
|
---|
| 55 | #include "lwip/priv/tcpip_priv.h"
|
---|
| 56 | #include "lwip/mld6.h"
|
---|
| 57 | #if LWIP_CHECKSUM_ON_COPY
|
---|
| 58 | #include "lwip/inet_chksum.h"
|
---|
| 59 | #endif
|
---|
| 60 |
|
---|
| 61 | #if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES
|
---|
| 62 | #include <stdarg.h>
|
---|
| 63 | #endif
|
---|
| 64 |
|
---|
| 65 | #include <string.h>
|
---|
| 66 |
|
---|
| 67 | #ifdef LWIP_HOOK_FILENAME
|
---|
| 68 | #include LWIP_HOOK_FILENAME
|
---|
| 69 | #endif
|
---|
| 70 |
|
---|
| 71 | /* If the netconn API is not required publicly, then we include the necessary
|
---|
| 72 | files here to get the implementation */
|
---|
| 73 | #if !LWIP_NETCONN
|
---|
| 74 | #undef LWIP_NETCONN
|
---|
| 75 | #define LWIP_NETCONN 1
|
---|
| 76 | #include "api_msg.c"
|
---|
| 77 | #include "api_lib.c"
|
---|
| 78 | #include "netbuf.c"
|
---|
| 79 | #undef LWIP_NETCONN
|
---|
| 80 | #define LWIP_NETCONN 0
|
---|
| 81 | #endif
|
---|
| 82 |
|
---|
| 83 | #define API_SELECT_CB_VAR_REF(name) API_VAR_REF(name)
|
---|
| 84 | #define API_SELECT_CB_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_select_cb, name)
|
---|
| 85 | #define API_SELECT_CB_VAR_ALLOC(name, retblock) API_VAR_ALLOC_EXT(struct lwip_select_cb, MEMP_SELECT_CB, name, retblock)
|
---|
| 86 | #define API_SELECT_CB_VAR_FREE(name) API_VAR_FREE(MEMP_SELECT_CB, name)
|
---|
| 87 |
|
---|
| 88 | #if LWIP_IPV4
|
---|
| 89 | #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \
|
---|
| 90 | (sin)->sin_len = sizeof(struct sockaddr_in); \
|
---|
| 91 | (sin)->sin_family = AF_INET; \
|
---|
| 92 | (sin)->sin_port = lwip_htons((port)); \
|
---|
| 93 | inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \
|
---|
| 94 | memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0)
|
---|
| 95 | #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \
|
---|
| 96 | inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \
|
---|
| 97 | (port) = lwip_ntohs((sin)->sin_port); }while(0)
|
---|
| 98 | #endif /* LWIP_IPV4 */
|
---|
| 99 |
|
---|
| 100 | #if LWIP_IPV6
|
---|
| 101 | #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \
|
---|
| 102 | (sin6)->sin6_len = sizeof(struct sockaddr_in6); \
|
---|
| 103 | (sin6)->sin6_family = AF_INET6; \
|
---|
| 104 | (sin6)->sin6_port = lwip_htons((port)); \
|
---|
| 105 | (sin6)->sin6_flowinfo = 0; \
|
---|
| 106 | inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \
|
---|
| 107 | (sin6)->sin6_scope_id = ip6_addr_zone(ipaddr); }while(0)
|
---|
| 108 | #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \
|
---|
| 109 | inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \
|
---|
| 110 | if (ip6_addr_has_scope(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { \
|
---|
| 111 | ip6_addr_set_zone(ip_2_ip6(ipaddr), (u8_t)((sin6)->sin6_scope_id)); \
|
---|
| 112 | } \
|
---|
| 113 | (port) = lwip_ntohs((sin6)->sin6_port); }while(0)
|
---|
| 114 | #endif /* LWIP_IPV6 */
|
---|
| 115 |
|
---|
| 116 | #if LWIP_IPV4 && LWIP_IPV6
|
---|
| 117 | static void sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port);
|
---|
| 118 |
|
---|
| 119 | #define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \
|
---|
| 120 | ((namelen) == sizeof(struct sockaddr_in6)))
|
---|
| 121 | #define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \
|
---|
| 122 | ((name)->sa_family == AF_INET6))
|
---|
| 123 | #define SOCK_ADDR_TYPE_MATCH(name, sock) \
|
---|
| 124 | ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \
|
---|
| 125 | (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type))))
|
---|
| 126 | #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \
|
---|
| 127 | if (IP_IS_ANY_TYPE_VAL(*ipaddr) || IP_IS_V6_VAL(*ipaddr)) { \
|
---|
| 128 | IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \
|
---|
| 129 | } else { \
|
---|
| 130 | IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \
|
---|
| 131 | } } while(0)
|
---|
| 132 | #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port))
|
---|
| 133 | #define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \
|
---|
| 134 | (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6))
|
---|
| 135 | #elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */
|
---|
| 136 | #define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in6))
|
---|
| 137 | #define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET6)
|
---|
| 138 | #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
|
---|
| 139 | #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
|
---|
| 140 | IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port)
|
---|
| 141 | #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
|
---|
| 142 | SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port)
|
---|
| 143 | #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
|
---|
| 144 | #else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */
|
---|
| 145 | #define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in))
|
---|
| 146 | #define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET)
|
---|
| 147 | #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
|
---|
| 148 | #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
|
---|
| 149 | IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port)
|
---|
| 150 | #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
|
---|
| 151 | SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port)
|
---|
| 152 | #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
|
---|
| 153 | #endif /* LWIP_IPV6 */
|
---|
| 154 |
|
---|
| 155 | #define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \
|
---|
| 156 | IS_SOCK_ADDR_TYPE_VALID(name))
|
---|
| 157 | #define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \
|
---|
| 158 | SOCK_ADDR_TYPE_MATCH(name, sock))
|
---|
| 159 | #define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0)
|
---|
| 160 |
|
---|
| 161 |
|
---|
| 162 | #define LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype) do { if ((optlen) < sizeof(opttype)) { done_socket(sock); return EINVAL; }}while(0)
|
---|
| 163 | #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \
|
---|
| 164 | LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \
|
---|
| 165 | if ((sock)->conn == NULL) { done_socket(sock); return EINVAL; } }while(0)
|
---|
| 166 | #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \
|
---|
| 167 | LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \
|
---|
| 168 | if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { done_socket(sock); return EINVAL; } }while(0)
|
---|
| 169 | #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \
|
---|
| 170 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \
|
---|
| 171 | if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { done_socket(sock); return ENOPROTOOPT; } }while(0)
|
---|
| 172 |
|
---|
| 173 |
|
---|
| 174 | #define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name) API_VAR_REF(name)
|
---|
| 175 | #define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name)
|
---|
| 176 | #define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name) API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name)
|
---|
| 177 | #if LWIP_MPU_COMPATIBLE
|
---|
| 178 | #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \
|
---|
| 179 | name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \
|
---|
| 180 | if (name == NULL) { \
|
---|
| 181 | sock_set_errno(sock, ENOMEM); \
|
---|
| 182 | done_socket(sock); \
|
---|
| 183 | return -1; \
|
---|
| 184 | } }while(0)
|
---|
| 185 | #else /* LWIP_MPU_COMPATIBLE */
|
---|
| 186 | #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock)
|
---|
| 187 | #endif /* LWIP_MPU_COMPATIBLE */
|
---|
| 188 |
|
---|
| 189 | #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
|
---|
| 190 | #define LWIP_SO_SNDRCVTIMEO_OPTTYPE int
|
---|
| 191 | #define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val))
|
---|
| 192 | #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((long)*(const int*)(optval))
|
---|
| 193 | #else
|
---|
| 194 | #define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval
|
---|
| 195 | #define LWIP_SO_SNDRCVTIMEO_SET(optval, val) do { \
|
---|
| 196 | u32_t loc = (val); \
|
---|
| 197 | ((struct timeval *)(optval))->tv_sec = (long)((loc) / 1000U); \
|
---|
| 198 | ((struct timeval *)(optval))->tv_usec = (long)(((loc) % 1000U) * 1000U); }while(0)
|
---|
| 199 | #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000) + (((const struct timeval *)(optval))->tv_usec / 1000))
|
---|
| 200 | #endif
|
---|
| 201 |
|
---|
| 202 |
|
---|
| 203 | /** A struct sockaddr replacement that has the same alignment as sockaddr_in/
|
---|
| 204 | * sockaddr_in6 if instantiated.
|
---|
| 205 | */
|
---|
| 206 | union sockaddr_aligned {
|
---|
| 207 | struct sockaddr sa;
|
---|
| 208 | #if LWIP_IPV6
|
---|
| 209 | struct sockaddr_in6 sin6;
|
---|
| 210 | #endif /* LWIP_IPV6 */
|
---|
| 211 | #if LWIP_IPV4
|
---|
| 212 | struct sockaddr_in sin;
|
---|
| 213 | #endif /* LWIP_IPV4 */
|
---|
| 214 | };
|
---|
| 215 |
|
---|
| 216 | /* Define the number of IPv4 multicast memberships, default is one per socket */
|
---|
| 217 | #ifndef LWIP_SOCKET_MAX_MEMBERSHIPS
|
---|
| 218 | #define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS
|
---|
| 219 | #endif
|
---|
| 220 |
|
---|
| 221 | #if LWIP_IGMP
|
---|
| 222 | /* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when
|
---|
| 223 | a socket is closed */
|
---|
| 224 | struct lwip_socket_multicast_pair {
|
---|
| 225 | /** the socket */
|
---|
| 226 | struct lwip_sock *sock;
|
---|
| 227 | /** the interface address */
|
---|
| 228 | ip4_addr_t if_addr;
|
---|
| 229 | /** the group address */
|
---|
| 230 | ip4_addr_t multi_addr;
|
---|
| 231 | };
|
---|
| 232 |
|
---|
| 233 | static struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS];
|
---|
| 234 |
|
---|
| 235 | static int lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr);
|
---|
| 236 | static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr);
|
---|
| 237 | static void lwip_socket_drop_registered_memberships(int s);
|
---|
| 238 | #endif /* LWIP_IGMP */
|
---|
| 239 |
|
---|
| 240 | #if LWIP_IPV6_MLD
|
---|
| 241 | /* This is to keep track of IP_JOIN_GROUP calls to drop the membership when
|
---|
| 242 | a socket is closed */
|
---|
| 243 | struct lwip_socket_multicast_mld6_pair {
|
---|
| 244 | /** the socket */
|
---|
| 245 | struct lwip_sock *sock;
|
---|
| 246 | /** the interface index */
|
---|
| 247 | u8_t if_idx;
|
---|
| 248 | /** the group address */
|
---|
| 249 | ip6_addr_t multi_addr;
|
---|
| 250 | };
|
---|
| 251 |
|
---|
| 252 | static struct lwip_socket_multicast_mld6_pair socket_ipv6_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS];
|
---|
| 253 |
|
---|
| 254 | static int lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr);
|
---|
| 255 | static void lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr);
|
---|
| 256 | static void lwip_socket_drop_registered_mld6_memberships(int s);
|
---|
| 257 | #endif /* LWIP_IPV6_MLD */
|
---|
| 258 |
|
---|
| 259 | /** The global array of available sockets */
|
---|
| 260 | static struct lwip_sock sockets[NUM_SOCKETS];
|
---|
| 261 |
|
---|
| 262 | #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
|
---|
| 263 | #if LWIP_TCPIP_CORE_LOCKING
|
---|
| 264 | /* protect the select_cb_list using core lock */
|
---|
| 265 | #define LWIP_SOCKET_SELECT_DECL_PROTECT(lev)
|
---|
| 266 | #define LWIP_SOCKET_SELECT_PROTECT(lev) LOCK_TCPIP_CORE()
|
---|
| 267 | #define LWIP_SOCKET_SELECT_UNPROTECT(lev) UNLOCK_TCPIP_CORE()
|
---|
| 268 | #else /* LWIP_TCPIP_CORE_LOCKING */
|
---|
| 269 | /* protect the select_cb_list using SYS_LIGHTWEIGHT_PROT */
|
---|
| 270 | #define LWIP_SOCKET_SELECT_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev)
|
---|
| 271 | #define LWIP_SOCKET_SELECT_PROTECT(lev) SYS_ARCH_PROTECT(lev)
|
---|
| 272 | #define LWIP_SOCKET_SELECT_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev)
|
---|
| 273 | /** This counter is increased from lwip_select when the list is changed
|
---|
| 274 | and checked in select_check_waiters to see if it has changed. */
|
---|
| 275 | static volatile int select_cb_ctr;
|
---|
| 276 | #endif /* LWIP_TCPIP_CORE_LOCKING */
|
---|
| 277 | /** The global list of tasks waiting for select */
|
---|
| 278 | static struct lwip_select_cb *select_cb_list;
|
---|
| 279 | #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */
|
---|
| 280 |
|
---|
| 281 | #define sock_set_errno(sk, e) do { \
|
---|
| 282 | const int sockerr = (e); \
|
---|
| 283 | set_errno(sockerr); \
|
---|
| 284 | } while (0)
|
---|
| 285 |
|
---|
| 286 | /* Forward declaration of some functions */
|
---|
| 287 | #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
|
---|
| 288 | static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
|
---|
| 289 | #define DEFAULT_SOCKET_EVENTCB event_callback
|
---|
| 290 | static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent);
|
---|
| 291 | #else
|
---|
| 292 | #define DEFAULT_SOCKET_EVENTCB NULL
|
---|
| 293 | #endif
|
---|
| 294 | #if !LWIP_TCPIP_CORE_LOCKING
|
---|
| 295 | static void lwip_getsockopt_callback(void *arg);
|
---|
| 296 | static void lwip_setsockopt_callback(void *arg);
|
---|
| 297 | #endif
|
---|
| 298 | static int lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen);
|
---|
| 299 | static int lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen);
|
---|
| 300 | static int free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn,
|
---|
| 301 | union lwip_sock_lastdata *lastdata);
|
---|
| 302 | static void free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata);
|
---|
| 303 |
|
---|
| 304 | #if LWIP_IPV4 && LWIP_IPV6
|
---|
| 305 | static void
|
---|
| 306 | sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port)
|
---|
| 307 | {
|
---|
| 308 | if ((sockaddr->sa_family) == AF_INET6) {
|
---|
| 309 | SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6 *)(const void *)(sockaddr), ipaddr, *port);
|
---|
| 310 | ipaddr->type = IPADDR_TYPE_V6;
|
---|
| 311 | } else {
|
---|
| 312 | SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in *)(const void *)(sockaddr), ipaddr, *port);
|
---|
| 313 | ipaddr->type = IPADDR_TYPE_V4;
|
---|
| 314 | }
|
---|
| 315 | }
|
---|
| 316 | #endif /* LWIP_IPV4 && LWIP_IPV6 */
|
---|
| 317 |
|
---|
| 318 | /** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */
|
---|
| 319 | void
|
---|
| 320 | lwip_socket_thread_init(void)
|
---|
| 321 | {
|
---|
| 322 | netconn_thread_init();
|
---|
| 323 | }
|
---|
| 324 |
|
---|
| 325 | /** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */
|
---|
| 326 | void
|
---|
| 327 | lwip_socket_thread_cleanup(void)
|
---|
| 328 | {
|
---|
| 329 | netconn_thread_cleanup();
|
---|
| 330 | }
|
---|
| 331 |
|
---|
| 332 | #if LWIP_NETCONN_FULLDUPLEX
|
---|
| 333 | /* Thread-safe increment of sock->fd_used, with overflow check */
|
---|
| 334 | static int
|
---|
| 335 | sock_inc_used(struct lwip_sock *sock)
|
---|
| 336 | {
|
---|
| 337 | int ret;
|
---|
| 338 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 339 |
|
---|
| 340 | LWIP_ASSERT("sock != NULL", sock != NULL);
|
---|
| 341 |
|
---|
| 342 | SYS_ARCH_PROTECT(lev);
|
---|
| 343 | if (sock->fd_free_pending) {
|
---|
| 344 | /* prevent new usage of this socket if free is pending */
|
---|
| 345 | ret = 0;
|
---|
| 346 | } else {
|
---|
| 347 | ++sock->fd_used;
|
---|
| 348 | ret = 1;
|
---|
| 349 | LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0);
|
---|
| 350 | }
|
---|
| 351 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 352 | return ret;
|
---|
| 353 | }
|
---|
| 354 |
|
---|
| 355 | /* Like sock_inc_used(), but called under SYS_ARCH_PROTECT lock. */
|
---|
| 356 | static int
|
---|
| 357 | sock_inc_used_locked(struct lwip_sock *sock)
|
---|
| 358 | {
|
---|
| 359 | LWIP_ASSERT("sock != NULL", sock != NULL);
|
---|
| 360 |
|
---|
| 361 | if (sock->fd_free_pending) {
|
---|
| 362 | LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0);
|
---|
| 363 | return 0;
|
---|
| 364 | }
|
---|
| 365 |
|
---|
| 366 | ++sock->fd_used;
|
---|
| 367 | LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0);
|
---|
| 368 | return 1;
|
---|
| 369 | }
|
---|
| 370 |
|
---|
| 371 | /* In full-duplex mode,sock->fd_used != 0 prevents a socket descriptor from being
|
---|
| 372 | * released (and possibly reused) when used from more than one thread
|
---|
| 373 | * (e.g. read-while-write or close-while-write, etc)
|
---|
| 374 | * This function is called at the end of functions using (try)get_socket*().
|
---|
| 375 | */
|
---|
| 376 | static void
|
---|
| 377 | done_socket(struct lwip_sock *sock)
|
---|
| 378 | {
|
---|
| 379 | int freed = 0;
|
---|
| 380 | int is_tcp = 0;
|
---|
| 381 | struct netconn *conn = NULL;
|
---|
| 382 | union lwip_sock_lastdata lastdata;
|
---|
| 383 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 384 | LWIP_ASSERT("sock != NULL", sock != NULL);
|
---|
| 385 |
|
---|
| 386 | SYS_ARCH_PROTECT(lev);
|
---|
| 387 | LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0);
|
---|
| 388 | if (--sock->fd_used == 0) {
|
---|
| 389 | if (sock->fd_free_pending) {
|
---|
| 390 | /* free the socket */
|
---|
| 391 | sock->fd_used = 1;
|
---|
| 392 | is_tcp = sock->fd_free_pending & LWIP_SOCK_FD_FREE_TCP;
|
---|
| 393 | freed = free_socket_locked(sock, is_tcp, &conn, &lastdata);
|
---|
| 394 | }
|
---|
| 395 | }
|
---|
| 396 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 397 |
|
---|
| 398 | if (freed) {
|
---|
| 399 | free_socket_free_elements(is_tcp, conn, &lastdata);
|
---|
| 400 | }
|
---|
| 401 | }
|
---|
| 402 |
|
---|
| 403 | #else /* LWIP_NETCONN_FULLDUPLEX */
|
---|
| 404 | #define sock_inc_used(sock) 1
|
---|
| 405 | #define sock_inc_used_locked(sock) 1
|
---|
| 406 | #define done_socket(sock)
|
---|
| 407 | #endif /* LWIP_NETCONN_FULLDUPLEX */
|
---|
| 408 |
|
---|
| 409 | /* Translate a socket 'int' into a pointer (only fails if the index is invalid) */
|
---|
| 410 | static struct lwip_sock *
|
---|
| 411 | tryget_socket_unconn_nouse(int fd)
|
---|
| 412 | {
|
---|
| 413 | int s = fd - LWIP_SOCKET_OFFSET;
|
---|
| 414 | if ((s < 0) || (s >= NUM_SOCKETS)) {
|
---|
| 415 | LWIP_DEBUGF(SOCKETS_DEBUG, ("tryget_socket_unconn(%d): invalid\n", fd));
|
---|
| 416 | return NULL;
|
---|
| 417 | }
|
---|
| 418 | return &sockets[s];
|
---|
| 419 | }
|
---|
| 420 |
|
---|
| 421 | struct lwip_sock *
|
---|
| 422 | lwip_socket_dbg_get_socket(int fd)
|
---|
| 423 | {
|
---|
| 424 | return tryget_socket_unconn_nouse(fd);
|
---|
| 425 | }
|
---|
| 426 |
|
---|
| 427 | /* Translate a socket 'int' into a pointer (only fails if the index is invalid) */
|
---|
| 428 | static struct lwip_sock *
|
---|
| 429 | tryget_socket_unconn(int fd)
|
---|
| 430 | {
|
---|
| 431 | struct lwip_sock *ret = tryget_socket_unconn_nouse(fd);
|
---|
| 432 | if (ret != NULL) {
|
---|
| 433 | if (!sock_inc_used(ret)) {
|
---|
| 434 | return NULL;
|
---|
| 435 | }
|
---|
| 436 | }
|
---|
| 437 | return ret;
|
---|
| 438 | }
|
---|
| 439 |
|
---|
| 440 | /* Like tryget_socket_unconn(), but called under SYS_ARCH_PROTECT lock. */
|
---|
| 441 | static struct lwip_sock *
|
---|
| 442 | tryget_socket_unconn_locked(int fd)
|
---|
| 443 | {
|
---|
| 444 | struct lwip_sock *ret = tryget_socket_unconn_nouse(fd);
|
---|
| 445 | if (ret != NULL) {
|
---|
| 446 | if (!sock_inc_used_locked(ret)) {
|
---|
| 447 | return NULL;
|
---|
| 448 | }
|
---|
| 449 | }
|
---|
| 450 | return ret;
|
---|
| 451 | }
|
---|
| 452 |
|
---|
| 453 | /**
|
---|
| 454 | * Same as get_socket but doesn't set errno
|
---|
| 455 | *
|
---|
| 456 | * @param fd externally used socket index
|
---|
| 457 | * @return struct lwip_sock for the socket or NULL if not found
|
---|
| 458 | */
|
---|
| 459 | static struct lwip_sock *
|
---|
| 460 | tryget_socket(int fd)
|
---|
| 461 | {
|
---|
| 462 | struct lwip_sock *sock = tryget_socket_unconn(fd);
|
---|
| 463 | if (sock != NULL) {
|
---|
| 464 | if (sock->conn) {
|
---|
| 465 | return sock;
|
---|
| 466 | }
|
---|
| 467 | done_socket(sock);
|
---|
| 468 | }
|
---|
| 469 | return NULL;
|
---|
| 470 | }
|
---|
| 471 |
|
---|
| 472 | /**
|
---|
| 473 | * Map a externally used socket index to the internal socket representation.
|
---|
| 474 | *
|
---|
| 475 | * @param fd externally used socket index
|
---|
| 476 | * @return struct lwip_sock for the socket or NULL if not found
|
---|
| 477 | */
|
---|
| 478 | static struct lwip_sock *
|
---|
| 479 | get_socket(int fd)
|
---|
| 480 | {
|
---|
| 481 | struct lwip_sock *sock = tryget_socket(fd);
|
---|
| 482 | if (!sock) {
|
---|
| 483 | if ((fd < LWIP_SOCKET_OFFSET) || (fd >= (LWIP_SOCKET_OFFSET + NUM_SOCKETS))) {
|
---|
| 484 | LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", fd));
|
---|
| 485 | }
|
---|
| 486 | set_errno(EBADF);
|
---|
| 487 | return NULL;
|
---|
| 488 | }
|
---|
| 489 | return sock;
|
---|
| 490 | }
|
---|
| 491 |
|
---|
| 492 | /**
|
---|
| 493 | * Allocate a new socket for a given netconn.
|
---|
| 494 | *
|
---|
| 495 | * @param newconn the netconn for which to allocate a socket
|
---|
| 496 | * @param accepted 1 if socket has been created by accept(),
|
---|
| 497 | * 0 if socket has been created by socket()
|
---|
| 498 | * @return the index of the new socket; -1 on error
|
---|
| 499 | */
|
---|
| 500 | static int
|
---|
| 501 | alloc_socket(struct netconn *newconn, int accepted)
|
---|
| 502 | {
|
---|
| 503 | int i;
|
---|
| 504 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 505 | LWIP_UNUSED_ARG(accepted);
|
---|
| 506 |
|
---|
| 507 | /* allocate a new socket identifier */
|
---|
| 508 | for (i = 0; i < NUM_SOCKETS; ++i) {
|
---|
| 509 | /* Protect socket array */
|
---|
| 510 | SYS_ARCH_PROTECT(lev);
|
---|
| 511 | if (!sockets[i].conn) {
|
---|
| 512 | #if LWIP_NETCONN_FULLDUPLEX
|
---|
| 513 | if (sockets[i].fd_used) {
|
---|
| 514 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 515 | continue;
|
---|
| 516 | }
|
---|
| 517 | sockets[i].fd_used = 1;
|
---|
| 518 | sockets[i].fd_free_pending = 0;
|
---|
| 519 | #endif
|
---|
| 520 | sockets[i].conn = newconn;
|
---|
| 521 | /* The socket is not yet known to anyone, so no need to protect
|
---|
| 522 | after having marked it as used. */
|
---|
| 523 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 524 | sockets[i].lastdata.pbuf = NULL;
|
---|
| 525 | #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
|
---|
| 526 | LWIP_ASSERT("sockets[i].select_waiting == 0", sockets[i].select_waiting == 0);
|
---|
| 527 | sockets[i].rcvevent = 0;
|
---|
| 528 | /* TCP sendbuf is empty, but the socket is not yet writable until connected
|
---|
| 529 | * (unless it has been created by accept()). */
|
---|
| 530 | sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
|
---|
| 531 | sockets[i].errevent = 0;
|
---|
| 532 | #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */
|
---|
| 533 | return i + LWIP_SOCKET_OFFSET;
|
---|
| 534 | }
|
---|
| 535 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 536 | }
|
---|
| 537 | return -1;
|
---|
| 538 | }
|
---|
| 539 |
|
---|
| 540 | /** Free a socket (under lock)
|
---|
| 541 | *
|
---|
| 542 | * @param sock the socket to free
|
---|
| 543 | * @param is_tcp != 0 for TCP sockets, used to free lastdata
|
---|
| 544 | * @param conn the socekt's netconn is stored here, must be freed externally
|
---|
| 545 | * @param lastdata lastdata is stored here, must be freed externally
|
---|
| 546 | */
|
---|
| 547 | static int
|
---|
| 548 | free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn,
|
---|
| 549 | union lwip_sock_lastdata *lastdata)
|
---|
| 550 | {
|
---|
| 551 | #if LWIP_NETCONN_FULLDUPLEX
|
---|
| 552 | LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0);
|
---|
| 553 | sock->fd_used--;
|
---|
| 554 | if (sock->fd_used > 0) {
|
---|
| 555 | sock->fd_free_pending = LWIP_SOCK_FD_FREE_FREE | (is_tcp ? LWIP_SOCK_FD_FREE_TCP : 0);
|
---|
| 556 | return 0;
|
---|
| 557 | }
|
---|
| 558 | #else /* LWIP_NETCONN_FULLDUPLEX */
|
---|
| 559 | LWIP_UNUSED_ARG(is_tcp);
|
---|
| 560 | #endif /* LWIP_NETCONN_FULLDUPLEX */
|
---|
| 561 |
|
---|
| 562 | *lastdata = sock->lastdata;
|
---|
| 563 | sock->lastdata.pbuf = NULL;
|
---|
| 564 | *conn = sock->conn;
|
---|
| 565 | sock->conn = NULL;
|
---|
| 566 | return 1;
|
---|
| 567 | }
|
---|
| 568 |
|
---|
| 569 | /** Free a socket's leftover members.
|
---|
| 570 | */
|
---|
| 571 | static void
|
---|
| 572 | free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata)
|
---|
| 573 | {
|
---|
| 574 | if (lastdata->pbuf != NULL) {
|
---|
| 575 | if (is_tcp) {
|
---|
| 576 | pbuf_free(lastdata->pbuf);
|
---|
| 577 | } else {
|
---|
| 578 | netbuf_delete(lastdata->netbuf);
|
---|
| 579 | }
|
---|
| 580 | }
|
---|
| 581 | if (conn != NULL) {
|
---|
| 582 | /* netconn_prepare_delete() has already been called, here we only free the conn */
|
---|
| 583 | netconn_delete(conn);
|
---|
| 584 | }
|
---|
| 585 | }
|
---|
| 586 |
|
---|
| 587 | /** Free a socket. The socket's netconn must have been
|
---|
| 588 | * delete before!
|
---|
| 589 | *
|
---|
| 590 | * @param sock the socket to free
|
---|
| 591 | * @param is_tcp != 0 for TCP sockets, used to free lastdata
|
---|
| 592 | */
|
---|
| 593 | static void
|
---|
| 594 | free_socket(struct lwip_sock *sock, int is_tcp)
|
---|
| 595 | {
|
---|
| 596 | int freed;
|
---|
| 597 | struct netconn *conn;
|
---|
| 598 | union lwip_sock_lastdata lastdata;
|
---|
| 599 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 600 |
|
---|
| 601 | /* Protect socket array */
|
---|
| 602 | SYS_ARCH_PROTECT(lev);
|
---|
| 603 |
|
---|
| 604 | freed = free_socket_locked(sock, is_tcp, &conn, &lastdata);
|
---|
| 605 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 606 | /* don't use 'sock' after this line, as another task might have allocated it */
|
---|
| 607 |
|
---|
| 608 | if (freed) {
|
---|
| 609 | free_socket_free_elements(is_tcp, conn, &lastdata);
|
---|
| 610 | }
|
---|
| 611 | }
|
---|
| 612 |
|
---|
| 613 | /* Below this, the well-known socket functions are implemented.
|
---|
| 614 | * Use google.com or opengroup.org to get a good description :-)
|
---|
| 615 | *
|
---|
| 616 | * Exceptions are documented!
|
---|
| 617 | */
|
---|
| 618 |
|
---|
| 619 | int
|
---|
| 620 | lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
|
---|
| 621 | {
|
---|
| 622 | struct lwip_sock *sock, *nsock;
|
---|
| 623 | struct netconn *newconn;
|
---|
| 624 | ip_addr_t naddr;
|
---|
| 625 | u16_t port = 0;
|
---|
| 626 | int newsock;
|
---|
| 627 | err_t err;
|
---|
| 628 | int recvevent;
|
---|
| 629 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 630 |
|
---|
| 631 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
|
---|
| 632 | sock = get_socket(s);
|
---|
| 633 | if (!sock) {
|
---|
| 634 | return -1;
|
---|
| 635 | }
|
---|
| 636 |
|
---|
| 637 | /* wait for a new connection */
|
---|
| 638 | err = netconn_accept(sock->conn, &newconn);
|
---|
| 639 | if (err != ERR_OK) {
|
---|
| 640 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
|
---|
| 641 | if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
|
---|
| 642 | sock_set_errno(sock, EOPNOTSUPP);
|
---|
| 643 | } else if (err == ERR_CLSD) {
|
---|
| 644 | sock_set_errno(sock, EINVAL);
|
---|
| 645 | } else {
|
---|
| 646 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 647 | }
|
---|
| 648 | done_socket(sock);
|
---|
| 649 | return -1;
|
---|
| 650 | }
|
---|
| 651 | LWIP_ASSERT("newconn != NULL", newconn != NULL);
|
---|
| 652 |
|
---|
| 653 | newsock = alloc_socket(newconn, 1);
|
---|
| 654 | if (newsock == -1) {
|
---|
| 655 | netconn_delete(newconn);
|
---|
| 656 | sock_set_errno(sock, ENFILE);
|
---|
| 657 | done_socket(sock);
|
---|
| 658 | return -1;
|
---|
| 659 | }
|
---|
| 660 | LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET));
|
---|
| 661 | nsock = &sockets[newsock - LWIP_SOCKET_OFFSET];
|
---|
| 662 |
|
---|
| 663 | /* See event_callback: If data comes in right away after an accept, even
|
---|
| 664 | * though the server task might not have created a new socket yet.
|
---|
| 665 | * In that case, newconn->socket is counted down (newconn->socket--),
|
---|
| 666 | * so nsock->rcvevent is >= 1 here!
|
---|
| 667 | */
|
---|
| 668 | SYS_ARCH_PROTECT(lev);
|
---|
| 669 | recvevent = (s16_t)(-1 - newconn->socket);
|
---|
| 670 | newconn->socket = newsock;
|
---|
| 671 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 672 |
|
---|
| 673 | if (newconn->callback) {
|
---|
| 674 | LOCK_TCPIP_CORE();
|
---|
| 675 | while (recvevent > 0) {
|
---|
| 676 | recvevent--;
|
---|
| 677 | newconn->callback(newconn, NETCONN_EVT_RCVPLUS, 0);
|
---|
| 678 | }
|
---|
| 679 | UNLOCK_TCPIP_CORE();
|
---|
| 680 | }
|
---|
| 681 |
|
---|
| 682 | /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
|
---|
| 683 | * not be NULL if addr is valid.
|
---|
| 684 | */
|
---|
| 685 | if ((addr != NULL) && (addrlen != NULL)) {
|
---|
| 686 | union sockaddr_aligned tempaddr;
|
---|
| 687 | /* get the IP address and port of the remote host */
|
---|
| 688 | err = netconn_peer(newconn, &naddr, &port);
|
---|
| 689 | if (err != ERR_OK) {
|
---|
| 690 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
|
---|
| 691 | netconn_delete(newconn);
|
---|
| 692 | free_socket(nsock, 1);
|
---|
| 693 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 694 | done_socket(sock);
|
---|
| 695 | return -1;
|
---|
| 696 | }
|
---|
| 697 |
|
---|
| 698 | IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port);
|
---|
| 699 | if (*addrlen > tempaddr.sa.sa_len) {
|
---|
| 700 | *addrlen = tempaddr.sa.sa_len;
|
---|
| 701 | }
|
---|
| 702 | MEMCPY(addr, &tempaddr, *addrlen);
|
---|
| 703 |
|
---|
| 704 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
|
---|
| 705 | ip_addr_debug_print_val(SOCKETS_DEBUG, naddr);
|
---|
| 706 | LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
|
---|
| 707 | } else {
|
---|
| 708 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock));
|
---|
| 709 | }
|
---|
| 710 |
|
---|
| 711 | sock_set_errno(sock, 0);
|
---|
| 712 | done_socket(sock);
|
---|
| 713 | done_socket(nsock);
|
---|
| 714 | return newsock;
|
---|
| 715 | }
|
---|
| 716 |
|
---|
| 717 | int
|
---|
| 718 | lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
|
---|
| 719 | {
|
---|
| 720 | struct lwip_sock *sock;
|
---|
| 721 | ip_addr_t local_addr;
|
---|
| 722 | u16_t local_port;
|
---|
| 723 | err_t err;
|
---|
| 724 |
|
---|
| 725 | sock = get_socket(s);
|
---|
| 726 | if (!sock) {
|
---|
| 727 | return -1;
|
---|
| 728 | }
|
---|
| 729 |
|
---|
| 730 | if (!SOCK_ADDR_TYPE_MATCH(name, sock)) {
|
---|
| 731 | /* sockaddr does not match socket type (IPv4/IPv6) */
|
---|
| 732 | sock_set_errno(sock, err_to_errno(ERR_VAL));
|
---|
| 733 | done_socket(sock);
|
---|
| 734 | return -1;
|
---|
| 735 | }
|
---|
| 736 |
|
---|
| 737 | /* check size, family and alignment of 'name' */
|
---|
| 738 | LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) &&
|
---|
| 739 | IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)),
|
---|
| 740 | sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
|
---|
| 741 | LWIP_UNUSED_ARG(namelen);
|
---|
| 742 |
|
---|
| 743 | SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port);
|
---|
| 744 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
|
---|
| 745 | ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr);
|
---|
| 746 | LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));
|
---|
| 747 |
|
---|
| 748 | #if LWIP_IPV4 && LWIP_IPV6
|
---|
| 749 | /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
|
---|
| 750 | if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) {
|
---|
| 751 | unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr));
|
---|
| 752 | IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4);
|
---|
| 753 | }
|
---|
| 754 | #endif /* LWIP_IPV4 && LWIP_IPV6 */
|
---|
| 755 |
|
---|
| 756 | err = netconn_bind(sock->conn, &local_addr, local_port);
|
---|
| 757 |
|
---|
| 758 | if (err != ERR_OK) {
|
---|
| 759 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
|
---|
| 760 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 761 | done_socket(sock);
|
---|
| 762 | return -1;
|
---|
| 763 | }
|
---|
| 764 |
|
---|
| 765 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
|
---|
| 766 | sock_set_errno(sock, 0);
|
---|
| 767 | done_socket(sock);
|
---|
| 768 | return 0;
|
---|
| 769 | }
|
---|
| 770 |
|
---|
| 771 | int
|
---|
| 772 | lwip_close(int s)
|
---|
| 773 | {
|
---|
| 774 | struct lwip_sock *sock;
|
---|
| 775 | int is_tcp = 0;
|
---|
| 776 | err_t err;
|
---|
| 777 |
|
---|
| 778 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
|
---|
| 779 |
|
---|
| 780 | sock = get_socket(s);
|
---|
| 781 | if (!sock) {
|
---|
| 782 | return -1;
|
---|
| 783 | }
|
---|
| 784 |
|
---|
| 785 | if (sock->conn != NULL) {
|
---|
| 786 | is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP;
|
---|
| 787 | } else {
|
---|
| 788 | LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata.pbuf == NULL);
|
---|
| 789 | }
|
---|
| 790 |
|
---|
| 791 | #if LWIP_IGMP
|
---|
| 792 | /* drop all possibly joined IGMP memberships */
|
---|
| 793 | lwip_socket_drop_registered_memberships(s);
|
---|
| 794 | #endif /* LWIP_IGMP */
|
---|
| 795 | #if LWIP_IPV6_MLD
|
---|
| 796 | /* drop all possibly joined MLD6 memberships */
|
---|
| 797 | lwip_socket_drop_registered_mld6_memberships(s);
|
---|
| 798 | #endif /* LWIP_IPV6_MLD */
|
---|
| 799 |
|
---|
| 800 | err = netconn_prepare_delete(sock->conn);
|
---|
| 801 | if (err != ERR_OK) {
|
---|
| 802 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 803 | done_socket(sock);
|
---|
| 804 | return -1;
|
---|
| 805 | }
|
---|
| 806 |
|
---|
| 807 | free_socket(sock, is_tcp);
|
---|
| 808 | set_errno(0);
|
---|
| 809 | return 0;
|
---|
| 810 | }
|
---|
| 811 |
|
---|
| 812 | int
|
---|
| 813 | lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
|
---|
| 814 | {
|
---|
| 815 | struct lwip_sock *sock;
|
---|
| 816 | err_t err;
|
---|
| 817 |
|
---|
| 818 | sock = get_socket(s);
|
---|
| 819 | if (!sock) {
|
---|
| 820 | return -1;
|
---|
| 821 | }
|
---|
| 822 |
|
---|
| 823 | if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) {
|
---|
| 824 | /* sockaddr does not match socket type (IPv4/IPv6) */
|
---|
| 825 | sock_set_errno(sock, err_to_errno(ERR_VAL));
|
---|
| 826 | done_socket(sock);
|
---|
| 827 | return -1;
|
---|
| 828 | }
|
---|
| 829 |
|
---|
| 830 | LWIP_UNUSED_ARG(namelen);
|
---|
| 831 | if (name->sa_family == AF_UNSPEC) {
|
---|
| 832 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
|
---|
| 833 | err = netconn_disconnect(sock->conn);
|
---|
| 834 | } else {
|
---|
| 835 | ip_addr_t remote_addr;
|
---|
| 836 | u16_t remote_port;
|
---|
| 837 |
|
---|
| 838 | /* check size, family and alignment of 'name' */
|
---|
| 839 | LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) &&
|
---|
| 840 | IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name),
|
---|
| 841 | sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
|
---|
| 842 |
|
---|
| 843 | SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port);
|
---|
| 844 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
|
---|
| 845 | ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr);
|
---|
| 846 | LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
|
---|
| 847 |
|
---|
| 848 | #if LWIP_IPV4 && LWIP_IPV6
|
---|
| 849 | /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
|
---|
| 850 | if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) {
|
---|
| 851 | unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr));
|
---|
| 852 | IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4);
|
---|
| 853 | }
|
---|
| 854 | #endif /* LWIP_IPV4 && LWIP_IPV6 */
|
---|
| 855 |
|
---|
| 856 | err = netconn_connect(sock->conn, &remote_addr, remote_port);
|
---|
| 857 | }
|
---|
| 858 |
|
---|
| 859 | if (err != ERR_OK) {
|
---|
| 860 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
|
---|
| 861 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 862 | done_socket(sock);
|
---|
| 863 | return -1;
|
---|
| 864 | }
|
---|
| 865 |
|
---|
| 866 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
|
---|
| 867 | sock_set_errno(sock, 0);
|
---|
| 868 | done_socket(sock);
|
---|
| 869 | return 0;
|
---|
| 870 | }
|
---|
| 871 |
|
---|
| 872 | /**
|
---|
| 873 | * Set a socket into listen mode.
|
---|
| 874 | * The socket may not have been used for another connection previously.
|
---|
| 875 | *
|
---|
| 876 | * @param s the socket to set to listening mode
|
---|
| 877 | * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
|
---|
| 878 | * @return 0 on success, non-zero on failure
|
---|
| 879 | */
|
---|
| 880 | int
|
---|
| 881 | lwip_listen(int s, int backlog)
|
---|
| 882 | {
|
---|
| 883 | struct lwip_sock *sock;
|
---|
| 884 | err_t err;
|
---|
| 885 |
|
---|
| 886 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
|
---|
| 887 |
|
---|
| 888 | sock = get_socket(s);
|
---|
| 889 | if (!sock) {
|
---|
| 890 | return -1;
|
---|
| 891 | }
|
---|
| 892 |
|
---|
| 893 | /* limit the "backlog" parameter to fit in an u8_t */
|
---|
| 894 | backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
|
---|
| 895 |
|
---|
| 896 | err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
|
---|
| 897 |
|
---|
| 898 | if (err != ERR_OK) {
|
---|
| 899 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
|
---|
| 900 | if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
|
---|
| 901 | sock_set_errno(sock, EOPNOTSUPP);
|
---|
| 902 | } else {
|
---|
| 903 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 904 | }
|
---|
| 905 | done_socket(sock);
|
---|
| 906 | return -1;
|
---|
| 907 | }
|
---|
| 908 |
|
---|
| 909 | sock_set_errno(sock, 0);
|
---|
| 910 | done_socket(sock);
|
---|
| 911 | return 0;
|
---|
| 912 | }
|
---|
| 913 |
|
---|
| 914 | #if LWIP_TCP
|
---|
| 915 | /* Helper function to loop over receiving pbufs from netconn
|
---|
| 916 | * until "len" bytes are received or we're otherwise done.
|
---|
| 917 | * Keeps sock->lastdata for peeking or partly copying.
|
---|
| 918 | */
|
---|
| 919 | static ssize_t
|
---|
| 920 | lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags)
|
---|
| 921 | {
|
---|
| 922 | u8_t apiflags = NETCONN_NOAUTORCVD;
|
---|
| 923 | ssize_t recvd = 0;
|
---|
| 924 | ssize_t recv_left = (len <= SSIZE_MAX) ? (ssize_t)len : SSIZE_MAX;
|
---|
| 925 |
|
---|
| 926 | LWIP_ASSERT("no socket given", sock != NULL);
|
---|
| 927 | LWIP_ASSERT("this should be checked internally", NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP);
|
---|
| 928 |
|
---|
| 929 | if (flags & MSG_DONTWAIT) {
|
---|
| 930 | apiflags |= NETCONN_DONTBLOCK;
|
---|
| 931 | }
|
---|
| 932 |
|
---|
| 933 | do {
|
---|
| 934 | struct pbuf *p;
|
---|
| 935 | err_t err;
|
---|
| 936 | u16_t copylen;
|
---|
| 937 |
|
---|
| 938 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: top while sock->lastdata=%p\n", (void *)sock->lastdata.pbuf));
|
---|
| 939 | /* Check if there is data left from the last recv operation. */
|
---|
| 940 | if (sock->lastdata.pbuf) {
|
---|
| 941 | p = sock->lastdata.pbuf;
|
---|
| 942 | } else {
|
---|
| 943 | /* No data was left from the previous operation, so we try to get
|
---|
| 944 | some from the network. */
|
---|
| 945 | err = netconn_recv_tcp_pbuf_flags(sock->conn, &p, apiflags);
|
---|
| 946 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: netconn_recv err=%d, pbuf=%p\n",
|
---|
| 947 | err, (void *)p));
|
---|
| 948 |
|
---|
| 949 | if (err != ERR_OK) {
|
---|
| 950 | if (recvd > 0) {
|
---|
| 951 | /* already received data, return that (this trusts in getting the same error from
|
---|
| 952 | netconn layer again next time netconn_recv is called) */
|
---|
| 953 | goto lwip_recv_tcp_done;
|
---|
| 954 | }
|
---|
| 955 | /* We should really do some error checking here. */
|
---|
| 956 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: p == NULL, error is \"%s\"!\n",
|
---|
| 957 | lwip_strerr(err)));
|
---|
| 958 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 959 | if (err == ERR_CLSD) {
|
---|
| 960 | return 0;
|
---|
| 961 | } else {
|
---|
| 962 | return -1;
|
---|
| 963 | }
|
---|
| 964 | }
|
---|
| 965 | LWIP_ASSERT("p != NULL", p != NULL);
|
---|
| 966 | sock->lastdata.pbuf = p;
|
---|
| 967 | }
|
---|
| 968 |
|
---|
| 969 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: buflen=%"U16_F" recv_left=%d off=%d\n",
|
---|
| 970 | p->tot_len, (int)recv_left, (int)recvd));
|
---|
| 971 |
|
---|
| 972 | if (recv_left > p->tot_len) {
|
---|
| 973 | copylen = p->tot_len;
|
---|
| 974 | } else {
|
---|
| 975 | copylen = (u16_t)recv_left;
|
---|
| 976 | }
|
---|
| 977 | if (recvd + copylen < recvd) {
|
---|
| 978 | /* overflow */
|
---|
| 979 | copylen = (u16_t)(SSIZE_MAX - recvd);
|
---|
| 980 | }
|
---|
| 981 |
|
---|
| 982 | /* copy the contents of the received buffer into
|
---|
| 983 | the supplied memory pointer mem */
|
---|
| 984 | pbuf_copy_partial(p, (u8_t *)mem + recvd, copylen, 0);
|
---|
| 985 |
|
---|
| 986 | recvd += copylen;
|
---|
| 987 |
|
---|
| 988 | /* TCP combines multiple pbufs for one recv */
|
---|
| 989 | LWIP_ASSERT("invalid copylen, len would underflow", recv_left >= copylen);
|
---|
| 990 | recv_left -= copylen;
|
---|
| 991 |
|
---|
| 992 | /* Unless we peek the incoming message... */
|
---|
| 993 | if ((flags & MSG_PEEK) == 0) {
|
---|
| 994 | /* ... check if there is data left in the pbuf */
|
---|
| 995 | LWIP_ASSERT("invalid copylen", p->tot_len >= copylen);
|
---|
| 996 | if (p->tot_len - copylen > 0) {
|
---|
| 997 | /* If so, it should be saved in the sock structure for the next recv call.
|
---|
| 998 | We store the pbuf but hide/free the consumed data: */
|
---|
| 999 | sock->lastdata.pbuf = pbuf_free_header(p, copylen);
|
---|
| 1000 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: lastdata now pbuf=%p\n", (void *)sock->lastdata.pbuf));
|
---|
| 1001 | } else {
|
---|
| 1002 | sock->lastdata.pbuf = NULL;
|
---|
| 1003 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: deleting pbuf=%p\n", (void *)p));
|
---|
| 1004 | pbuf_free(p);
|
---|
| 1005 | }
|
---|
| 1006 | }
|
---|
| 1007 | /* once we have some data to return, only add more if we don't need to wait */
|
---|
| 1008 | apiflags |= NETCONN_DONTBLOCK | NETCONN_NOFIN;
|
---|
| 1009 | /* @todo: do we need to support peeking more than one pbuf? */
|
---|
| 1010 | } while ((recv_left > 0) && !(flags & MSG_PEEK));
|
---|
| 1011 | lwip_recv_tcp_done:
|
---|
| 1012 | if ((recvd > 0) && !(flags & MSG_PEEK)) {
|
---|
| 1013 | /* ensure window update after copying all data */
|
---|
| 1014 | netconn_tcp_recvd(sock->conn, (size_t)recvd);
|
---|
| 1015 | }
|
---|
| 1016 | sock_set_errno(sock, 0);
|
---|
| 1017 | return recvd;
|
---|
| 1018 | }
|
---|
| 1019 | #endif
|
---|
| 1020 |
|
---|
| 1021 | /* Convert a netbuf's address data to struct sockaddr */
|
---|
| 1022 | static int
|
---|
| 1023 | lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port,
|
---|
| 1024 | struct sockaddr *from, socklen_t *fromlen)
|
---|
| 1025 | {
|
---|
| 1026 | int truncated = 0;
|
---|
| 1027 | union sockaddr_aligned saddr;
|
---|
| 1028 |
|
---|
| 1029 | LWIP_UNUSED_ARG(conn);
|
---|
| 1030 |
|
---|
| 1031 | LWIP_ASSERT("fromaddr != NULL", fromaddr != NULL);
|
---|
| 1032 | LWIP_ASSERT("from != NULL", from != NULL);
|
---|
| 1033 | LWIP_ASSERT("fromlen != NULL", fromlen != NULL);
|
---|
| 1034 |
|
---|
| 1035 | #if LWIP_IPV4 && LWIP_IPV6
|
---|
| 1036 | /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
|
---|
| 1037 | if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4(fromaddr)) {
|
---|
| 1038 | ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr));
|
---|
| 1039 | IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6);
|
---|
| 1040 | }
|
---|
| 1041 | #endif /* LWIP_IPV4 && LWIP_IPV6 */
|
---|
| 1042 |
|
---|
| 1043 | IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port);
|
---|
| 1044 | if (*fromlen < saddr.sa.sa_len) {
|
---|
| 1045 | truncated = 1;
|
---|
| 1046 | } else if (*fromlen > saddr.sa.sa_len) {
|
---|
| 1047 | *fromlen = saddr.sa.sa_len;
|
---|
| 1048 | }
|
---|
| 1049 | MEMCPY(from, &saddr, *fromlen);
|
---|
| 1050 | return truncated;
|
---|
| 1051 | }
|
---|
| 1052 |
|
---|
| 1053 | #if LWIP_TCP
|
---|
| 1054 | /* Helper function to get a tcp socket's remote address info */
|
---|
| 1055 | static int
|
---|
| 1056 | lwip_recv_tcp_from(struct lwip_sock *sock, struct sockaddr *from, socklen_t *fromlen, const char *dbg_fn, int dbg_s, ssize_t dbg_ret)
|
---|
| 1057 | {
|
---|
| 1058 | if (sock == NULL) {
|
---|
| 1059 | return 0;
|
---|
| 1060 | }
|
---|
| 1061 | LWIP_UNUSED_ARG(dbg_fn);
|
---|
| 1062 | LWIP_UNUSED_ARG(dbg_s);
|
---|
| 1063 | LWIP_UNUSED_ARG(dbg_ret);
|
---|
| 1064 |
|
---|
| 1065 | #if !SOCKETS_DEBUG
|
---|
| 1066 | if (from && fromlen)
|
---|
| 1067 | #endif /* !SOCKETS_DEBUG */
|
---|
| 1068 | {
|
---|
| 1069 | /* get remote addr/port from tcp_pcb */
|
---|
| 1070 | u16_t port;
|
---|
| 1071 | ip_addr_t tmpaddr;
|
---|
| 1072 | netconn_getaddr(sock->conn, &tmpaddr, &port, 0);
|
---|
| 1073 | LWIP_DEBUGF(SOCKETS_DEBUG, ("%s(%d): addr=", dbg_fn, dbg_s));
|
---|
| 1074 | ip_addr_debug_print_val(SOCKETS_DEBUG, tmpaddr);
|
---|
| 1075 | LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, (int)dbg_ret));
|
---|
| 1076 | if (from && fromlen) {
|
---|
| 1077 | return lwip_sock_make_addr(sock->conn, &tmpaddr, port, from, fromlen);
|
---|
| 1078 | }
|
---|
| 1079 | }
|
---|
| 1080 | return 0;
|
---|
| 1081 | }
|
---|
| 1082 | #endif
|
---|
| 1083 |
|
---|
| 1084 | /* Helper function to receive a netbuf from a udp or raw netconn.
|
---|
| 1085 | * Keeps sock->lastdata for peeking.
|
---|
| 1086 | */
|
---|
| 1087 | static err_t
|
---|
| 1088 | lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16_t *datagram_len, int dbg_s)
|
---|
| 1089 | {
|
---|
| 1090 | struct netbuf *buf;
|
---|
| 1091 | u8_t apiflags;
|
---|
| 1092 | err_t err;
|
---|
| 1093 | u16_t buflen, copylen, copied;
|
---|
| 1094 | int i;
|
---|
| 1095 |
|
---|
| 1096 | LWIP_UNUSED_ARG(dbg_s);
|
---|
| 1097 | LWIP_ERROR("lwip_recvfrom_udp_raw: invalid arguments", (msg->msg_iov != NULL) || (msg->msg_iovlen <= 0), return ERR_ARG;);
|
---|
| 1098 |
|
---|
| 1099 | if (flags & MSG_DONTWAIT) {
|
---|
| 1100 | apiflags = NETCONN_DONTBLOCK;
|
---|
| 1101 | } else {
|
---|
| 1102 | apiflags = 0;
|
---|
| 1103 | }
|
---|
| 1104 |
|
---|
| 1105 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: top sock->lastdata=%p\n", (void *)sock->lastdata.netbuf));
|
---|
| 1106 | /* Check if there is data left from the last recv operation. */
|
---|
| 1107 | buf = sock->lastdata.netbuf;
|
---|
| 1108 | if (buf == NULL) {
|
---|
| 1109 | /* No data was left from the previous operation, so we try to get
|
---|
| 1110 | some from the network. */
|
---|
| 1111 | err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &buf, apiflags);
|
---|
| 1112 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: netconn_recv err=%d, netbuf=%p\n",
|
---|
| 1113 | err, (void *)buf));
|
---|
| 1114 |
|
---|
| 1115 | if (err != ERR_OK) {
|
---|
| 1116 | return err;
|
---|
| 1117 | }
|
---|
| 1118 | LWIP_ASSERT("buf != NULL", buf != NULL);
|
---|
| 1119 | sock->lastdata.netbuf = buf;
|
---|
| 1120 | }
|
---|
| 1121 | buflen = buf->p->tot_len;
|
---|
| 1122 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw: buflen=%"U16_F"\n", buflen));
|
---|
| 1123 |
|
---|
| 1124 | copied = 0;
|
---|
| 1125 | /* copy the pbuf payload into the iovs */
|
---|
| 1126 | for (i = 0; (i < msg->msg_iovlen) && (copied < buflen); i++) {
|
---|
| 1127 | u16_t len_left = (u16_t)(buflen - copied);
|
---|
| 1128 | if (msg->msg_iov[i].iov_len > len_left) {
|
---|
| 1129 | copylen = len_left;
|
---|
| 1130 | } else {
|
---|
| 1131 | copylen = (u16_t)msg->msg_iov[i].iov_len;
|
---|
| 1132 | }
|
---|
| 1133 |
|
---|
| 1134 | /* copy the contents of the received buffer into
|
---|
| 1135 | the supplied memory buffer */
|
---|
| 1136 | pbuf_copy_partial(buf->p, (u8_t *)msg->msg_iov[i].iov_base, copylen, copied);
|
---|
| 1137 | copied = (u16_t)(copied + copylen);
|
---|
| 1138 | }
|
---|
| 1139 |
|
---|
| 1140 | /* Check to see from where the data was.*/
|
---|
| 1141 | #if !SOCKETS_DEBUG
|
---|
| 1142 | if (msg->msg_name && msg->msg_namelen)
|
---|
| 1143 | #endif /* !SOCKETS_DEBUG */
|
---|
| 1144 | {
|
---|
| 1145 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw(%d): addr=", dbg_s));
|
---|
| 1146 | ip_addr_debug_print_val(SOCKETS_DEBUG, *netbuf_fromaddr(buf));
|
---|
| 1147 | LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", netbuf_fromport(buf), copied));
|
---|
| 1148 | if (msg->msg_name && msg->msg_namelen) {
|
---|
| 1149 | lwip_sock_make_addr(sock->conn, netbuf_fromaddr(buf), netbuf_fromport(buf),
|
---|
| 1150 | (struct sockaddr *)msg->msg_name, &msg->msg_namelen);
|
---|
| 1151 | }
|
---|
| 1152 | }
|
---|
| 1153 |
|
---|
| 1154 | /* Initialize flag output */
|
---|
| 1155 | msg->msg_flags = 0;
|
---|
| 1156 |
|
---|
| 1157 | if (msg->msg_control) {
|
---|
| 1158 | u8_t wrote_msg = 0;
|
---|
| 1159 | #if LWIP_NETBUF_RECVINFO
|
---|
| 1160 | /* Check if packet info was recorded */
|
---|
| 1161 | if (buf->flags & NETBUF_FLAG_DESTADDR) {
|
---|
| 1162 | if (IP_IS_V4(&buf->toaddr)) {
|
---|
| 1163 | #if LWIP_IPV4
|
---|
| 1164 | if (msg->msg_controllen >= CMSG_SPACE(sizeof(struct in_pktinfo))) {
|
---|
| 1165 | struct cmsghdr *chdr = CMSG_FIRSTHDR(msg); /* This will always return a header!! */
|
---|
| 1166 | struct in_pktinfo *pkti = (struct in_pktinfo *)CMSG_DATA(chdr);
|
---|
| 1167 | chdr->cmsg_level = IPPROTO_IP;
|
---|
| 1168 | chdr->cmsg_type = IP_PKTINFO;
|
---|
| 1169 | chdr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
---|
| 1170 | pkti->ipi_ifindex = buf->p->if_idx;
|
---|
| 1171 | inet_addr_from_ip4addr(&pkti->ipi_addr, ip_2_ip4(netbuf_destaddr(buf)));
|
---|
| 1172 | msg->msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
|
---|
| 1173 | wrote_msg = 1;
|
---|
| 1174 | } else {
|
---|
| 1175 | msg->msg_flags |= MSG_CTRUNC;
|
---|
| 1176 | }
|
---|
| 1177 | #endif /* LWIP_IPV4 */
|
---|
| 1178 | }
|
---|
| 1179 | }
|
---|
| 1180 | #endif /* LWIP_NETBUF_RECVINFO */
|
---|
| 1181 |
|
---|
| 1182 | if (!wrote_msg) {
|
---|
| 1183 | msg->msg_controllen = 0;
|
---|
| 1184 | }
|
---|
| 1185 | }
|
---|
| 1186 |
|
---|
| 1187 | /* If we don't peek the incoming message: zero lastdata pointer and free the netbuf */
|
---|
| 1188 | if ((flags & MSG_PEEK) == 0) {
|
---|
| 1189 | sock->lastdata.netbuf = NULL;
|
---|
| 1190 | netbuf_delete(buf);
|
---|
| 1191 | }
|
---|
| 1192 | if (datagram_len) {
|
---|
| 1193 | *datagram_len = buflen;
|
---|
| 1194 | }
|
---|
| 1195 | return ERR_OK;
|
---|
| 1196 | }
|
---|
| 1197 |
|
---|
| 1198 | ssize_t
|
---|
| 1199 | lwip_recvfrom(int s, void *mem, size_t len, int flags,
|
---|
| 1200 | struct sockaddr *from, socklen_t *fromlen)
|
---|
| 1201 | {
|
---|
| 1202 | struct lwip_sock *sock;
|
---|
| 1203 | ssize_t ret;
|
---|
| 1204 |
|
---|
| 1205 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
|
---|
| 1206 | sock = get_socket(s);
|
---|
| 1207 | if (!sock) {
|
---|
| 1208 | return -1;
|
---|
| 1209 | }
|
---|
| 1210 | #if LWIP_TCP
|
---|
| 1211 | if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
|
---|
| 1212 | ret = lwip_recv_tcp(sock, mem, len, flags);
|
---|
| 1213 | lwip_recv_tcp_from(sock, from, fromlen, "lwip_recvfrom", s, ret);
|
---|
| 1214 | done_socket(sock);
|
---|
| 1215 | return ret;
|
---|
| 1216 | } else
|
---|
| 1217 | #endif
|
---|
| 1218 | {
|
---|
| 1219 | u16_t datagram_len = 0;
|
---|
| 1220 | struct iovec vec;
|
---|
| 1221 | struct msghdr msg;
|
---|
| 1222 | err_t err;
|
---|
| 1223 | vec.iov_base = mem;
|
---|
| 1224 | vec.iov_len = len;
|
---|
| 1225 | msg.msg_control = NULL;
|
---|
| 1226 | msg.msg_controllen = 0;
|
---|
| 1227 | msg.msg_flags = 0;
|
---|
| 1228 | msg.msg_iov = &vec;
|
---|
| 1229 | msg.msg_iovlen = 1;
|
---|
| 1230 | msg.msg_name = from;
|
---|
| 1231 | msg.msg_namelen = (fromlen ? *fromlen : 0);
|
---|
| 1232 | err = lwip_recvfrom_udp_raw(sock, flags, &msg, &datagram_len, s);
|
---|
| 1233 | if (err != ERR_OK) {
|
---|
| 1234 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n",
|
---|
| 1235 | s, lwip_strerr(err)));
|
---|
| 1236 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 1237 | done_socket(sock);
|
---|
| 1238 | return -1;
|
---|
| 1239 | }
|
---|
| 1240 | ret = (ssize_t)LWIP_MIN(LWIP_MIN(len, datagram_len), SSIZE_MAX);
|
---|
| 1241 | if (fromlen) {
|
---|
| 1242 | *fromlen = msg.msg_namelen;
|
---|
| 1243 | }
|
---|
| 1244 | }
|
---|
| 1245 |
|
---|
| 1246 | sock_set_errno(sock, 0);
|
---|
| 1247 | done_socket(sock);
|
---|
| 1248 | return ret;
|
---|
| 1249 | }
|
---|
| 1250 |
|
---|
| 1251 | ssize_t
|
---|
| 1252 | lwip_read(int s, void *mem, size_t len)
|
---|
| 1253 | {
|
---|
| 1254 | return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
|
---|
| 1255 | }
|
---|
| 1256 |
|
---|
| 1257 | ssize_t
|
---|
| 1258 | lwip_readv(int s, const struct iovec *iov, int iovcnt)
|
---|
| 1259 | {
|
---|
| 1260 | struct msghdr msg;
|
---|
| 1261 |
|
---|
| 1262 | msg.msg_name = NULL;
|
---|
| 1263 | msg.msg_namelen = 0;
|
---|
| 1264 | /* Hack: we have to cast via number to cast from 'const' pointer to non-const.
|
---|
| 1265 | Blame the opengroup standard for this inconsistency. */
|
---|
| 1266 | msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov);
|
---|
| 1267 | msg.msg_iovlen = iovcnt;
|
---|
| 1268 | msg.msg_control = NULL;
|
---|
| 1269 | msg.msg_controllen = 0;
|
---|
| 1270 | msg.msg_flags = 0;
|
---|
| 1271 | return lwip_recvmsg(s, &msg, 0);
|
---|
| 1272 | }
|
---|
| 1273 |
|
---|
| 1274 | ssize_t
|
---|
| 1275 | lwip_recv(int s, void *mem, size_t len, int flags)
|
---|
| 1276 | {
|
---|
| 1277 | return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
|
---|
| 1278 | }
|
---|
| 1279 |
|
---|
| 1280 | ssize_t
|
---|
| 1281 | lwip_recvmsg(int s, struct msghdr *message, int flags)
|
---|
| 1282 | {
|
---|
| 1283 | struct lwip_sock *sock;
|
---|
| 1284 | int i;
|
---|
| 1285 | ssize_t buflen;
|
---|
| 1286 |
|
---|
| 1287 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg(%d, message=%p, flags=0x%x)\n", s, (void *)message, flags));
|
---|
| 1288 | LWIP_ERROR("lwip_recvmsg: invalid message pointer", message != NULL, return ERR_ARG;);
|
---|
| 1289 | LWIP_ERROR("lwip_recvmsg: unsupported flags", (flags & ~(MSG_PEEK|MSG_DONTWAIT)) == 0,
|
---|
| 1290 | set_errno(EOPNOTSUPP); return -1;);
|
---|
| 1291 |
|
---|
| 1292 | if ((message->msg_iovlen <= 0) || (message->msg_iovlen > IOV_MAX)) {
|
---|
| 1293 | set_errno(EMSGSIZE);
|
---|
| 1294 | return -1;
|
---|
| 1295 | }
|
---|
| 1296 |
|
---|
| 1297 | sock = get_socket(s);
|
---|
| 1298 | if (!sock) {
|
---|
| 1299 | return -1;
|
---|
| 1300 | }
|
---|
| 1301 |
|
---|
| 1302 | /* check for valid vectors */
|
---|
| 1303 | buflen = 0;
|
---|
| 1304 | for (i = 0; i < message->msg_iovlen; i++) {
|
---|
| 1305 | if ((message->msg_iov[i].iov_base == NULL) || ((ssize_t)message->msg_iov[i].iov_len <= 0) ||
|
---|
| 1306 | ((size_t)(ssize_t)message->msg_iov[i].iov_len != message->msg_iov[i].iov_len) ||
|
---|
| 1307 | ((ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len) <= 0)) {
|
---|
| 1308 | sock_set_errno(sock, err_to_errno(ERR_VAL));
|
---|
| 1309 | done_socket(sock);
|
---|
| 1310 | return -1;
|
---|
| 1311 | }
|
---|
| 1312 | buflen = (ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len);
|
---|
| 1313 | }
|
---|
| 1314 |
|
---|
| 1315 | if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
|
---|
| 1316 | #if LWIP_TCP
|
---|
| 1317 | int recv_flags = flags;
|
---|
| 1318 | message->msg_flags = 0;
|
---|
| 1319 | /* recv the data */
|
---|
| 1320 | buflen = 0;
|
---|
| 1321 | for (i = 0; i < message->msg_iovlen; i++) {
|
---|
| 1322 | /* try to receive into this vector's buffer */
|
---|
| 1323 | ssize_t recvd_local = lwip_recv_tcp(sock, message->msg_iov[i].iov_base, message->msg_iov[i].iov_len, recv_flags);
|
---|
| 1324 | if (recvd_local > 0) {
|
---|
| 1325 | /* sum up received bytes */
|
---|
| 1326 | buflen += recvd_local;
|
---|
| 1327 | }
|
---|
| 1328 | if ((recvd_local < 0) || (recvd_local < (int)message->msg_iov[i].iov_len) ||
|
---|
| 1329 | (flags & MSG_PEEK)) {
|
---|
| 1330 | /* returned prematurely (or peeking, which might actually be limitated to the first iov) */
|
---|
| 1331 | if (buflen <= 0) {
|
---|
| 1332 | /* nothing received at all, propagate the error */
|
---|
| 1333 | buflen = recvd_local;
|
---|
| 1334 | }
|
---|
| 1335 | break;
|
---|
| 1336 | }
|
---|
| 1337 | /* pass MSG_DONTWAIT to lwip_recv_tcp() to prevent waiting for more data */
|
---|
| 1338 | recv_flags |= MSG_DONTWAIT;
|
---|
| 1339 | }
|
---|
| 1340 | if (buflen > 0) {
|
---|
| 1341 | /* reset socket error since we have received something */
|
---|
| 1342 | sock_set_errno(sock, 0);
|
---|
| 1343 | }
|
---|
| 1344 | /* " If the socket is connected, the msg_name and msg_namelen members shall be ignored." */
|
---|
| 1345 | done_socket(sock);
|
---|
| 1346 | return buflen;
|
---|
| 1347 | #else /* LWIP_TCP */
|
---|
| 1348 | sock_set_errno(sock, err_to_errno(ERR_ARG));
|
---|
| 1349 | done_socket(sock);
|
---|
| 1350 | return -1;
|
---|
| 1351 | #endif /* LWIP_TCP */
|
---|
| 1352 | }
|
---|
| 1353 | /* else, UDP and RAW NETCONNs */
|
---|
| 1354 | #if LWIP_UDP || LWIP_RAW
|
---|
| 1355 | {
|
---|
| 1356 | u16_t datagram_len = 0;
|
---|
| 1357 | err_t err;
|
---|
| 1358 | err = lwip_recvfrom_udp_raw(sock, flags, message, &datagram_len, s);
|
---|
| 1359 | if (err != ERR_OK) {
|
---|
| 1360 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n",
|
---|
| 1361 | s, lwip_strerr(err)));
|
---|
| 1362 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 1363 | done_socket(sock);
|
---|
| 1364 | return -1;
|
---|
| 1365 | }
|
---|
| 1366 | if (datagram_len > buflen) {
|
---|
| 1367 | message->msg_flags |= MSG_TRUNC;
|
---|
| 1368 | }
|
---|
| 1369 |
|
---|
| 1370 | sock_set_errno(sock, 0);
|
---|
| 1371 | done_socket(sock);
|
---|
| 1372 | return (int)datagram_len;
|
---|
| 1373 | }
|
---|
| 1374 | #else /* LWIP_UDP || LWIP_RAW */
|
---|
| 1375 | sock_set_errno(sock, err_to_errno(ERR_ARG));
|
---|
| 1376 | done_socket(sock);
|
---|
| 1377 | return -1;
|
---|
| 1378 | #endif /* LWIP_UDP || LWIP_RAW */
|
---|
| 1379 | }
|
---|
| 1380 |
|
---|
| 1381 | ssize_t
|
---|
| 1382 | lwip_send(int s, const void *data, size_t size, int flags)
|
---|
| 1383 | {
|
---|
| 1384 | struct lwip_sock *sock;
|
---|
| 1385 | err_t err;
|
---|
| 1386 | u8_t write_flags;
|
---|
| 1387 | size_t written;
|
---|
| 1388 |
|
---|
| 1389 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
|
---|
| 1390 | s, data, size, flags));
|
---|
| 1391 |
|
---|
| 1392 | sock = get_socket(s);
|
---|
| 1393 | if (!sock) {
|
---|
| 1394 | return -1;
|
---|
| 1395 | }
|
---|
| 1396 |
|
---|
| 1397 | if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
|
---|
| 1398 | #if (LWIP_UDP || LWIP_RAW)
|
---|
| 1399 | done_socket(sock);
|
---|
| 1400 | return lwip_sendto(s, data, size, flags, NULL, 0);
|
---|
| 1401 | #else /* (LWIP_UDP || LWIP_RAW) */
|
---|
| 1402 | sock_set_errno(sock, err_to_errno(ERR_ARG));
|
---|
| 1403 | done_socket(sock);
|
---|
| 1404 | return -1;
|
---|
| 1405 | #endif /* (LWIP_UDP || LWIP_RAW) */
|
---|
| 1406 | }
|
---|
| 1407 |
|
---|
| 1408 | write_flags = (u8_t)(NETCONN_COPY |
|
---|
| 1409 | ((flags & MSG_MORE) ? NETCONN_MORE : 0) |
|
---|
| 1410 | ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0));
|
---|
| 1411 | written = 0;
|
---|
| 1412 | err = netconn_write_partly(sock->conn, data, size, write_flags, &written);
|
---|
| 1413 |
|
---|
| 1414 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written));
|
---|
| 1415 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 1416 | done_socket(sock);
|
---|
| 1417 | /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */
|
---|
| 1418 | return (err == ERR_OK ? (ssize_t)written : -1);
|
---|
| 1419 | }
|
---|
| 1420 |
|
---|
| 1421 | ssize_t
|
---|
| 1422 | lwip_sendmsg(int s, const struct msghdr *msg, int flags)
|
---|
| 1423 | {
|
---|
| 1424 | struct lwip_sock *sock;
|
---|
| 1425 | #if LWIP_TCP
|
---|
| 1426 | u8_t write_flags;
|
---|
| 1427 | size_t written;
|
---|
| 1428 | #endif
|
---|
| 1429 | err_t err = ERR_OK;
|
---|
| 1430 |
|
---|
| 1431 | sock = get_socket(s);
|
---|
| 1432 | if (!sock) {
|
---|
| 1433 | return -1;
|
---|
| 1434 | }
|
---|
| 1435 |
|
---|
| 1436 | LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL,
|
---|
| 1437 | sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
|
---|
| 1438 | LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", msg->msg_iov != NULL,
|
---|
| 1439 | sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
|
---|
| 1440 | LWIP_ERROR("lwip_sendmsg: maximum iovs exceeded", (msg->msg_iovlen > 0) && (msg->msg_iovlen <= IOV_MAX),
|
---|
| 1441 | sock_set_errno(sock, EMSGSIZE); done_socket(sock); return -1;);
|
---|
| 1442 | LWIP_ERROR("lwip_sendmsg: unsupported flags", (flags & ~(MSG_DONTWAIT | MSG_MORE)) == 0,
|
---|
| 1443 | sock_set_errno(sock, EOPNOTSUPP); done_socket(sock); return -1;);
|
---|
| 1444 |
|
---|
| 1445 | LWIP_UNUSED_ARG(msg->msg_control);
|
---|
| 1446 | LWIP_UNUSED_ARG(msg->msg_controllen);
|
---|
| 1447 | LWIP_UNUSED_ARG(msg->msg_flags);
|
---|
| 1448 |
|
---|
| 1449 | if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
|
---|
| 1450 | #if LWIP_TCP
|
---|
| 1451 | write_flags = (u8_t)(NETCONN_COPY |
|
---|
| 1452 | ((flags & MSG_MORE) ? NETCONN_MORE : 0) |
|
---|
| 1453 | ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0));
|
---|
| 1454 |
|
---|
| 1455 | written = 0;
|
---|
| 1456 | err = netconn_write_vectors_partly(sock->conn, (struct netvector *)msg->msg_iov, (u16_t)msg->msg_iovlen, write_flags, &written);
|
---|
| 1457 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 1458 | done_socket(sock);
|
---|
| 1459 | /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */
|
---|
| 1460 | return (err == ERR_OK ? (ssize_t)written : -1);
|
---|
| 1461 | #else /* LWIP_TCP */
|
---|
| 1462 | sock_set_errno(sock, err_to_errno(ERR_ARG));
|
---|
| 1463 | done_socket(sock);
|
---|
| 1464 | return -1;
|
---|
| 1465 | #endif /* LWIP_TCP */
|
---|
| 1466 | }
|
---|
| 1467 | /* else, UDP and RAW NETCONNs */
|
---|
| 1468 | #if LWIP_UDP || LWIP_RAW
|
---|
| 1469 | {
|
---|
| 1470 | struct netbuf chain_buf;
|
---|
| 1471 | int i;
|
---|
| 1472 | ssize_t size = 0;
|
---|
| 1473 |
|
---|
| 1474 | LWIP_UNUSED_ARG(flags);
|
---|
| 1475 | LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) ||
|
---|
| 1476 | IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)),
|
---|
| 1477 | sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
|
---|
| 1478 |
|
---|
| 1479 | /* initialize chain buffer with destination */
|
---|
| 1480 | memset(&chain_buf, 0, sizeof(struct netbuf));
|
---|
| 1481 | if (msg->msg_name) {
|
---|
| 1482 | u16_t remote_port;
|
---|
| 1483 | SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf.addr, remote_port);
|
---|
| 1484 | netbuf_fromport(&chain_buf) = remote_port;
|
---|
| 1485 | }
|
---|
| 1486 | #if LWIP_NETIF_TX_SINGLE_PBUF
|
---|
| 1487 | for (i = 0; i < msg->msg_iovlen; i++) {
|
---|
| 1488 | size += msg->msg_iov[i].iov_len;
|
---|
| 1489 | if ((msg->msg_iov[i].iov_len > INT_MAX) || (size < (int)msg->msg_iov[i].iov_len)) {
|
---|
| 1490 | /* overflow */
|
---|
| 1491 | goto sendmsg_emsgsize;
|
---|
| 1492 | }
|
---|
| 1493 | }
|
---|
| 1494 | if (size > 0xFFFF) {
|
---|
| 1495 | /* overflow */
|
---|
| 1496 | goto sendmsg_emsgsize;
|
---|
| 1497 | }
|
---|
| 1498 | /* Allocate a new netbuf and copy the data into it. */
|
---|
| 1499 | if (netbuf_alloc(&chain_buf, (u16_t)size) == NULL) {
|
---|
| 1500 | err = ERR_MEM;
|
---|
| 1501 | } else {
|
---|
| 1502 | /* flatten the IO vectors */
|
---|
| 1503 | size_t offset = 0;
|
---|
| 1504 | for (i = 0; i < msg->msg_iovlen; i++) {
|
---|
| 1505 | MEMCPY(&((u8_t *)chain_buf.p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
|
---|
| 1506 | offset += msg->msg_iov[i].iov_len;
|
---|
| 1507 | }
|
---|
| 1508 | #if LWIP_CHECKSUM_ON_COPY
|
---|
| 1509 | {
|
---|
| 1510 | /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */
|
---|
| 1511 | u16_t chksum = ~inet_chksum_pbuf(chain_buf.p);
|
---|
| 1512 | netbuf_set_chksum(&chain_buf, chksum);
|
---|
| 1513 | }
|
---|
| 1514 | #endif /* LWIP_CHECKSUM_ON_COPY */
|
---|
| 1515 | err = ERR_OK;
|
---|
| 1516 | }
|
---|
| 1517 | #else /* LWIP_NETIF_TX_SINGLE_PBUF */
|
---|
| 1518 | /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain
|
---|
| 1519 | manually to avoid having to allocate, chain, and delete a netbuf for each iov */
|
---|
| 1520 | for (i = 0; i < msg->msg_iovlen; i++) {
|
---|
| 1521 | struct pbuf *p;
|
---|
| 1522 | if (msg->msg_iov[i].iov_len > 0xFFFF) {
|
---|
| 1523 | /* overflow */
|
---|
| 1524 | goto sendmsg_emsgsize;
|
---|
| 1525 | }
|
---|
| 1526 | p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
|
---|
| 1527 | if (p == NULL) {
|
---|
| 1528 | err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */
|
---|
| 1529 | break;
|
---|
| 1530 | }
|
---|
| 1531 | p->payload = msg->msg_iov[i].iov_base;
|
---|
| 1532 | p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len;
|
---|
| 1533 | /* netbuf empty, add new pbuf */
|
---|
| 1534 | if (chain_buf.p == NULL) {
|
---|
| 1535 | chain_buf.p = chain_buf.ptr = p;
|
---|
| 1536 | /* add pbuf to existing pbuf chain */
|
---|
| 1537 | } else {
|
---|
| 1538 | if (chain_buf.p->tot_len + p->len > 0xffff) {
|
---|
| 1539 | /* overflow */
|
---|
| 1540 | pbuf_free(p);
|
---|
| 1541 | goto sendmsg_emsgsize;
|
---|
| 1542 | }
|
---|
| 1543 | pbuf_cat(chain_buf.p, p);
|
---|
| 1544 | }
|
---|
| 1545 | }
|
---|
| 1546 | /* save size of total chain */
|
---|
| 1547 | if (err == ERR_OK) {
|
---|
| 1548 | size = netbuf_len(&chain_buf);
|
---|
| 1549 | }
|
---|
| 1550 | #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
|
---|
| 1551 |
|
---|
| 1552 | if (err == ERR_OK) {
|
---|
| 1553 | #if LWIP_IPV4 && LWIP_IPV6
|
---|
| 1554 | /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
|
---|
| 1555 | if (IP_IS_V6_VAL(chain_buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf.addr))) {
|
---|
| 1556 | unmap_ipv4_mapped_ipv6(ip_2_ip4(&chain_buf.addr), ip_2_ip6(&chain_buf.addr));
|
---|
| 1557 | IP_SET_TYPE_VAL(chain_buf.addr, IPADDR_TYPE_V4);
|
---|
| 1558 | }
|
---|
| 1559 | #endif /* LWIP_IPV4 && LWIP_IPV6 */
|
---|
| 1560 |
|
---|
| 1561 | /* send the data */
|
---|
| 1562 | err = netconn_send(sock->conn, &chain_buf);
|
---|
| 1563 | }
|
---|
| 1564 |
|
---|
| 1565 | /* deallocated the buffer */
|
---|
| 1566 | netbuf_free(&chain_buf);
|
---|
| 1567 |
|
---|
| 1568 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 1569 | done_socket(sock);
|
---|
| 1570 | return (err == ERR_OK ? size : -1);
|
---|
| 1571 | sendmsg_emsgsize:
|
---|
| 1572 | sock_set_errno(sock, EMSGSIZE);
|
---|
| 1573 | netbuf_free(&chain_buf);
|
---|
| 1574 | done_socket(sock);
|
---|
| 1575 | return -1;
|
---|
| 1576 | }
|
---|
| 1577 | #else /* LWIP_UDP || LWIP_RAW */
|
---|
| 1578 | sock_set_errno(sock, err_to_errno(ERR_ARG));
|
---|
| 1579 | done_socket(sock);
|
---|
| 1580 | return -1;
|
---|
| 1581 | #endif /* LWIP_UDP || LWIP_RAW */
|
---|
| 1582 | }
|
---|
| 1583 |
|
---|
| 1584 | ssize_t
|
---|
| 1585 | lwip_sendto(int s, const void *data, size_t size, int flags,
|
---|
| 1586 | const struct sockaddr *to, socklen_t tolen)
|
---|
| 1587 | {
|
---|
| 1588 | struct lwip_sock *sock;
|
---|
| 1589 | err_t err;
|
---|
| 1590 | u16_t short_size;
|
---|
| 1591 | u16_t remote_port;
|
---|
| 1592 | struct netbuf buf;
|
---|
| 1593 |
|
---|
| 1594 | sock = get_socket(s);
|
---|
| 1595 | if (!sock) {
|
---|
| 1596 | return -1;
|
---|
| 1597 | }
|
---|
| 1598 |
|
---|
| 1599 | if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
|
---|
| 1600 | #if LWIP_TCP
|
---|
| 1601 | done_socket(sock);
|
---|
| 1602 | return lwip_send(s, data, size, flags);
|
---|
| 1603 | #else /* LWIP_TCP */
|
---|
| 1604 | LWIP_UNUSED_ARG(flags);
|
---|
| 1605 | sock_set_errno(sock, err_to_errno(ERR_ARG));
|
---|
| 1606 | done_socket(sock);
|
---|
| 1607 | return -1;
|
---|
| 1608 | #endif /* LWIP_TCP */
|
---|
| 1609 | }
|
---|
| 1610 |
|
---|
| 1611 | if (size > LWIP_MIN(0xFFFF, SSIZE_MAX)) {
|
---|
| 1612 | /* cannot fit into one datagram (at least for us) */
|
---|
| 1613 | sock_set_errno(sock, EMSGSIZE);
|
---|
| 1614 | done_socket(sock);
|
---|
| 1615 | return -1;
|
---|
| 1616 | }
|
---|
| 1617 | short_size = (u16_t)size;
|
---|
| 1618 | LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
|
---|
| 1619 | (IS_SOCK_ADDR_LEN_VALID(tolen) &&
|
---|
| 1620 | ((to != NULL) && (IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))))),
|
---|
| 1621 | sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
|
---|
| 1622 | LWIP_UNUSED_ARG(tolen);
|
---|
| 1623 |
|
---|
| 1624 | /* initialize a buffer */
|
---|
| 1625 | buf.p = buf.ptr = NULL;
|
---|
| 1626 | #if LWIP_CHECKSUM_ON_COPY
|
---|
| 1627 | buf.flags = 0;
|
---|
| 1628 | #endif /* LWIP_CHECKSUM_ON_COPY */
|
---|
| 1629 | if (to) {
|
---|
| 1630 | SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port);
|
---|
| 1631 | } else {
|
---|
| 1632 | remote_port = 0;
|
---|
| 1633 | ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr);
|
---|
| 1634 | }
|
---|
| 1635 | netbuf_fromport(&buf) = remote_port;
|
---|
| 1636 |
|
---|
| 1637 |
|
---|
| 1638 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
|
---|
| 1639 | s, data, short_size, flags));
|
---|
| 1640 | ip_addr_debug_print_val(SOCKETS_DEBUG, buf.addr);
|
---|
| 1641 | LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
|
---|
| 1642 |
|
---|
| 1643 | /* make the buffer point to the data that should be sent */
|
---|
| 1644 | #if LWIP_NETIF_TX_SINGLE_PBUF
|
---|
| 1645 | /* Allocate a new netbuf and copy the data into it. */
|
---|
| 1646 | if (netbuf_alloc(&buf, short_size) == NULL) {
|
---|
| 1647 | err = ERR_MEM;
|
---|
| 1648 | } else {
|
---|
| 1649 | #if LWIP_CHECKSUM_ON_COPY
|
---|
| 1650 | if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
|
---|
| 1651 | u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
|
---|
| 1652 | netbuf_set_chksum(&buf, chksum);
|
---|
| 1653 | } else
|
---|
| 1654 | #endif /* LWIP_CHECKSUM_ON_COPY */
|
---|
| 1655 | {
|
---|
| 1656 | MEMCPY(buf.p->payload, data, short_size);
|
---|
| 1657 | }
|
---|
| 1658 | err = ERR_OK;
|
---|
| 1659 | }
|
---|
| 1660 | #else /* LWIP_NETIF_TX_SINGLE_PBUF */
|
---|
| 1661 | err = netbuf_ref(&buf, data, short_size);
|
---|
| 1662 | #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
|
---|
| 1663 | if (err == ERR_OK) {
|
---|
| 1664 | #if LWIP_IPV4 && LWIP_IPV6
|
---|
| 1665 | /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
|
---|
| 1666 | if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) {
|
---|
| 1667 | unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr));
|
---|
| 1668 | IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4);
|
---|
| 1669 | }
|
---|
| 1670 | #endif /* LWIP_IPV4 && LWIP_IPV6 */
|
---|
| 1671 |
|
---|
| 1672 | /* send the data */
|
---|
| 1673 | err = netconn_send(sock->conn, &buf);
|
---|
| 1674 | }
|
---|
| 1675 |
|
---|
| 1676 | /* deallocated the buffer */
|
---|
| 1677 | netbuf_free(&buf);
|
---|
| 1678 |
|
---|
| 1679 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 1680 | done_socket(sock);
|
---|
| 1681 | return (err == ERR_OK ? short_size : -1);
|
---|
| 1682 | }
|
---|
| 1683 |
|
---|
| 1684 | int
|
---|
| 1685 | lwip_socket(int domain, int type, int protocol)
|
---|
| 1686 | {
|
---|
| 1687 | struct netconn *conn;
|
---|
| 1688 | int i;
|
---|
| 1689 |
|
---|
| 1690 | LWIP_UNUSED_ARG(domain); /* @todo: check this */
|
---|
| 1691 |
|
---|
| 1692 | /* create a netconn */
|
---|
| 1693 | switch (type) {
|
---|
| 1694 | case SOCK_RAW:
|
---|
| 1695 | conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW),
|
---|
| 1696 | (u8_t)protocol, DEFAULT_SOCKET_EVENTCB);
|
---|
| 1697 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
|
---|
| 1698 | domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
|
---|
| 1699 | break;
|
---|
| 1700 | case SOCK_DGRAM:
|
---|
| 1701 | conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain,
|
---|
| 1702 | ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)),
|
---|
| 1703 | DEFAULT_SOCKET_EVENTCB);
|
---|
| 1704 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
|
---|
| 1705 | domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
|
---|
| 1706 | #if LWIP_NETBUF_RECVINFO
|
---|
| 1707 | if (conn) {
|
---|
| 1708 | /* netconn layer enables pktinfo by default, sockets default to off */
|
---|
| 1709 | conn->flags &= ~NETCONN_FLAG_PKTINFO;
|
---|
| 1710 | }
|
---|
| 1711 | #endif /* LWIP_NETBUF_RECVINFO */
|
---|
| 1712 | break;
|
---|
| 1713 | case SOCK_STREAM:
|
---|
| 1714 | conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), DEFAULT_SOCKET_EVENTCB);
|
---|
| 1715 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
|
---|
| 1716 | domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
|
---|
| 1717 | break;
|
---|
| 1718 | default:
|
---|
| 1719 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
|
---|
| 1720 | domain, type, protocol));
|
---|
| 1721 | set_errno(EINVAL);
|
---|
| 1722 | return -1;
|
---|
| 1723 | }
|
---|
| 1724 |
|
---|
| 1725 | if (!conn) {
|
---|
| 1726 | LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
|
---|
| 1727 | set_errno(ENOBUFS);
|
---|
| 1728 | return -1;
|
---|
| 1729 | }
|
---|
| 1730 |
|
---|
| 1731 | i = alloc_socket(conn, 0);
|
---|
| 1732 |
|
---|
| 1733 | if (i == -1) {
|
---|
| 1734 | netconn_delete(conn);
|
---|
| 1735 | set_errno(ENFILE);
|
---|
| 1736 | return -1;
|
---|
| 1737 | }
|
---|
| 1738 | conn->socket = i;
|
---|
| 1739 | done_socket(&sockets[i - LWIP_SOCKET_OFFSET]);
|
---|
| 1740 | LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
|
---|
| 1741 | set_errno(0);
|
---|
| 1742 | return i;
|
---|
| 1743 | }
|
---|
| 1744 |
|
---|
| 1745 | ssize_t
|
---|
| 1746 | lwip_write(int s, const void *data, size_t size)
|
---|
| 1747 | {
|
---|
| 1748 | return lwip_send(s, data, size, 0);
|
---|
| 1749 | }
|
---|
| 1750 |
|
---|
| 1751 | ssize_t
|
---|
| 1752 | lwip_writev(int s, const struct iovec *iov, int iovcnt)
|
---|
| 1753 | {
|
---|
| 1754 | struct msghdr msg;
|
---|
| 1755 |
|
---|
| 1756 | msg.msg_name = NULL;
|
---|
| 1757 | msg.msg_namelen = 0;
|
---|
| 1758 | /* Hack: we have to cast via number to cast from 'const' pointer to non-const.
|
---|
| 1759 | Blame the opengroup standard for this inconsistency. */
|
---|
| 1760 | msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov);
|
---|
| 1761 | msg.msg_iovlen = iovcnt;
|
---|
| 1762 | msg.msg_control = NULL;
|
---|
| 1763 | msg.msg_controllen = 0;
|
---|
| 1764 | msg.msg_flags = 0;
|
---|
| 1765 | return lwip_sendmsg(s, &msg, 0);
|
---|
| 1766 | }
|
---|
| 1767 |
|
---|
| 1768 | #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
|
---|
| 1769 | /* Add select_cb to select_cb_list. */
|
---|
| 1770 | static void
|
---|
| 1771 | lwip_link_select_cb(struct lwip_select_cb *select_cb)
|
---|
| 1772 | {
|
---|
| 1773 | LWIP_SOCKET_SELECT_DECL_PROTECT(lev);
|
---|
| 1774 |
|
---|
| 1775 | /* Protect the select_cb_list */
|
---|
| 1776 | LWIP_SOCKET_SELECT_PROTECT(lev);
|
---|
| 1777 |
|
---|
| 1778 | /* Put this select_cb on top of list */
|
---|
| 1779 | select_cb->next = select_cb_list;
|
---|
| 1780 | if (select_cb_list != NULL) {
|
---|
| 1781 | select_cb_list->prev = select_cb;
|
---|
| 1782 | }
|
---|
| 1783 | select_cb_list = select_cb;
|
---|
| 1784 | #if !LWIP_TCPIP_CORE_LOCKING
|
---|
| 1785 | /* Increasing this counter tells select_check_waiters that the list has changed. */
|
---|
| 1786 | select_cb_ctr++;
|
---|
| 1787 | #endif
|
---|
| 1788 |
|
---|
| 1789 | /* Now we can safely unprotect */
|
---|
| 1790 | LWIP_SOCKET_SELECT_UNPROTECT(lev);
|
---|
| 1791 | }
|
---|
| 1792 |
|
---|
| 1793 | /* Remove select_cb from select_cb_list. */
|
---|
| 1794 | static void
|
---|
| 1795 | lwip_unlink_select_cb(struct lwip_select_cb *select_cb)
|
---|
| 1796 | {
|
---|
| 1797 | LWIP_SOCKET_SELECT_DECL_PROTECT(lev);
|
---|
| 1798 |
|
---|
| 1799 | /* Take us off the list */
|
---|
| 1800 | LWIP_SOCKET_SELECT_PROTECT(lev);
|
---|
| 1801 | if (select_cb->next != NULL) {
|
---|
| 1802 | select_cb->next->prev = select_cb->prev;
|
---|
| 1803 | }
|
---|
| 1804 | if (select_cb_list == select_cb) {
|
---|
| 1805 | LWIP_ASSERT("select_cb->prev == NULL", select_cb->prev == NULL);
|
---|
| 1806 | select_cb_list = select_cb->next;
|
---|
| 1807 | } else {
|
---|
| 1808 | LWIP_ASSERT("select_cb->prev != NULL", select_cb->prev != NULL);
|
---|
| 1809 | select_cb->prev->next = select_cb->next;
|
---|
| 1810 | }
|
---|
| 1811 | #if !LWIP_TCPIP_CORE_LOCKING
|
---|
| 1812 | /* Increasing this counter tells select_check_waiters that the list has changed. */
|
---|
| 1813 | select_cb_ctr++;
|
---|
| 1814 | #endif
|
---|
| 1815 | LWIP_SOCKET_SELECT_UNPROTECT(lev);
|
---|
| 1816 | }
|
---|
| 1817 | #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */
|
---|
| 1818 |
|
---|
| 1819 | #if LWIP_SOCKET_SELECT
|
---|
| 1820 | /**
|
---|
| 1821 | * Go through the readset and writeset lists and see which socket of the sockets
|
---|
| 1822 | * set in the sets has events. On return, readset, writeset and exceptset have
|
---|
| 1823 | * the sockets enabled that had events.
|
---|
| 1824 | *
|
---|
| 1825 | * @param maxfdp1 the highest socket index in the sets
|
---|
| 1826 | * @param readset_in set of sockets to check for read events
|
---|
| 1827 | * @param writeset_in set of sockets to check for write events
|
---|
| 1828 | * @param exceptset_in set of sockets to check for error events
|
---|
| 1829 | * @param readset_out set of sockets that had read events
|
---|
| 1830 | * @param writeset_out set of sockets that had write events
|
---|
| 1831 | * @param exceptset_out set os sockets that had error events
|
---|
| 1832 | * @return number of sockets that had events (read/write/exception) (>= 0)
|
---|
| 1833 | */
|
---|
| 1834 | static int
|
---|
| 1835 | lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
|
---|
| 1836 | fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
|
---|
| 1837 | {
|
---|
| 1838 | int i, nready = 0;
|
---|
| 1839 | fd_set lreadset, lwriteset, lexceptset;
|
---|
| 1840 | struct lwip_sock *sock;
|
---|
| 1841 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 1842 |
|
---|
| 1843 | FD_ZERO(&lreadset);
|
---|
| 1844 | FD_ZERO(&lwriteset);
|
---|
| 1845 | FD_ZERO(&lexceptset);
|
---|
| 1846 |
|
---|
| 1847 | /* Go through each socket in each list to count number of sockets which
|
---|
| 1848 | currently match */
|
---|
| 1849 | for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) {
|
---|
| 1850 | /* if this FD is not in the set, continue */
|
---|
| 1851 | if (!(readset_in && FD_ISSET(i, readset_in)) &&
|
---|
| 1852 | !(writeset_in && FD_ISSET(i, writeset_in)) &&
|
---|
| 1853 | !(exceptset_in && FD_ISSET(i, exceptset_in))) {
|
---|
| 1854 | continue;
|
---|
| 1855 | }
|
---|
| 1856 | /* First get the socket's status (protected)... */
|
---|
| 1857 | SYS_ARCH_PROTECT(lev);
|
---|
| 1858 | sock = tryget_socket_unconn_locked(i);
|
---|
| 1859 | if (sock != NULL) {
|
---|
| 1860 | void *lastdata = sock->lastdata.pbuf;
|
---|
| 1861 | s16_t rcvevent = sock->rcvevent;
|
---|
| 1862 | u16_t sendevent = sock->sendevent;
|
---|
| 1863 | u16_t errevent = sock->errevent;
|
---|
| 1864 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 1865 |
|
---|
| 1866 | /* ... then examine it: */
|
---|
| 1867 | /* See if netconn of this socket is ready for read */
|
---|
| 1868 | if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
|
---|
| 1869 | FD_SET(i, &lreadset);
|
---|
| 1870 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
|
---|
| 1871 | nready++;
|
---|
| 1872 | }
|
---|
| 1873 | /* See if netconn of this socket is ready for write */
|
---|
| 1874 | if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
|
---|
| 1875 | FD_SET(i, &lwriteset);
|
---|
| 1876 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
|
---|
| 1877 | nready++;
|
---|
| 1878 | }
|
---|
| 1879 | /* See if netconn of this socket had an error */
|
---|
| 1880 | if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
|
---|
| 1881 | FD_SET(i, &lexceptset);
|
---|
| 1882 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
|
---|
| 1883 | nready++;
|
---|
| 1884 | }
|
---|
| 1885 | done_socket(sock);
|
---|
| 1886 | } else {
|
---|
| 1887 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 1888 | /* no a valid open socket */
|
---|
| 1889 | return -1;
|
---|
| 1890 | }
|
---|
| 1891 | }
|
---|
| 1892 | /* copy local sets to the ones provided as arguments */
|
---|
| 1893 | *readset_out = lreadset;
|
---|
| 1894 | *writeset_out = lwriteset;
|
---|
| 1895 | *exceptset_out = lexceptset;
|
---|
| 1896 |
|
---|
| 1897 | LWIP_ASSERT("nready >= 0", nready >= 0);
|
---|
| 1898 | return nready;
|
---|
| 1899 | }
|
---|
| 1900 |
|
---|
| 1901 | #if LWIP_NETCONN_FULLDUPLEX
|
---|
| 1902 | /* Mark all of the set sockets in one of the three fdsets passed to select as used.
|
---|
| 1903 | * All sockets are marked (and later unmarked), whether they are open or not.
|
---|
| 1904 | * This is OK as lwip_selscan aborts select when non-open sockets are found.
|
---|
| 1905 | */
|
---|
| 1906 | static void
|
---|
| 1907 | lwip_select_inc_sockets_used_set(int maxfdp, fd_set *fdset, fd_set *used_sockets)
|
---|
| 1908 | {
|
---|
| 1909 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 1910 | if (fdset) {
|
---|
| 1911 | int i;
|
---|
| 1912 | for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) {
|
---|
| 1913 | /* if this FD is in the set, lock it (unless already done) */
|
---|
| 1914 | if (FD_ISSET(i, fdset) && !FD_ISSET(i, used_sockets)) {
|
---|
| 1915 | struct lwip_sock *sock;
|
---|
| 1916 | SYS_ARCH_PROTECT(lev);
|
---|
| 1917 | sock = tryget_socket_unconn_locked(i);
|
---|
| 1918 | if (sock != NULL) {
|
---|
| 1919 | /* leave the socket used until released by lwip_select_dec_sockets_used */
|
---|
| 1920 | FD_SET(i, used_sockets);
|
---|
| 1921 | }
|
---|
| 1922 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 1923 | }
|
---|
| 1924 | }
|
---|
| 1925 | }
|
---|
| 1926 | }
|
---|
| 1927 |
|
---|
| 1928 | /* Mark all sockets passed to select as used to prevent them from being freed
|
---|
| 1929 | * from other threads while select is running.
|
---|
| 1930 | * Marked sockets are added to 'used_sockets' to mark them only once an be able
|
---|
| 1931 | * to unmark them correctly.
|
---|
| 1932 | */
|
---|
| 1933 | static void
|
---|
| 1934 | lwip_select_inc_sockets_used(int maxfdp, fd_set *fdset1, fd_set *fdset2, fd_set *fdset3, fd_set *used_sockets)
|
---|
| 1935 | {
|
---|
| 1936 | FD_ZERO(used_sockets);
|
---|
| 1937 | lwip_select_inc_sockets_used_set(maxfdp, fdset1, used_sockets);
|
---|
| 1938 | lwip_select_inc_sockets_used_set(maxfdp, fdset2, used_sockets);
|
---|
| 1939 | lwip_select_inc_sockets_used_set(maxfdp, fdset3, used_sockets);
|
---|
| 1940 | }
|
---|
| 1941 |
|
---|
| 1942 | /* Let go all sockets that were marked as used when starting select */
|
---|
| 1943 | static void
|
---|
| 1944 | lwip_select_dec_sockets_used(int maxfdp, fd_set *used_sockets)
|
---|
| 1945 | {
|
---|
| 1946 | int i;
|
---|
| 1947 | for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) {
|
---|
| 1948 | /* if this FD is not in the set, continue */
|
---|
| 1949 | if (FD_ISSET(i, used_sockets)) {
|
---|
| 1950 | struct lwip_sock *sock = tryget_socket_unconn_nouse(i);
|
---|
| 1951 | LWIP_ASSERT("socket gone at the end of select", sock != NULL);
|
---|
| 1952 | if (sock != NULL) {
|
---|
| 1953 | done_socket(sock);
|
---|
| 1954 | }
|
---|
| 1955 | }
|
---|
| 1956 | }
|
---|
| 1957 | }
|
---|
| 1958 | #else /* LWIP_NETCONN_FULLDUPLEX */
|
---|
| 1959 | #define lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, used_sockets)
|
---|
| 1960 | #define lwip_select_dec_sockets_used(maxfdp1, used_sockets)
|
---|
| 1961 | #endif /* LWIP_NETCONN_FULLDUPLEX */
|
---|
| 1962 |
|
---|
| 1963 | int
|
---|
| 1964 | lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
|
---|
| 1965 | struct timeval *timeout)
|
---|
| 1966 | {
|
---|
| 1967 | u32_t waitres = 0;
|
---|
| 1968 | int nready;
|
---|
| 1969 | fd_set lreadset, lwriteset, lexceptset;
|
---|
| 1970 | u32_t msectimeout;
|
---|
| 1971 | int i;
|
---|
| 1972 | int maxfdp2;
|
---|
| 1973 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 1974 | int waited = 0;
|
---|
| 1975 | #endif
|
---|
| 1976 | #if LWIP_NETCONN_FULLDUPLEX
|
---|
| 1977 | fd_set used_sockets;
|
---|
| 1978 | #endif
|
---|
| 1979 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 1980 |
|
---|
| 1981 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
|
---|
| 1982 | maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
|
---|
| 1983 | timeout ? (s32_t)timeout->tv_sec : (s32_t) - 1,
|
---|
| 1984 | timeout ? (s32_t)timeout->tv_usec : (s32_t) - 1));
|
---|
| 1985 |
|
---|
| 1986 | if ((maxfdp1 < 0) || (maxfdp1 > LWIP_SELECT_MAXNFDS)) {
|
---|
| 1987 | set_errno(EINVAL);
|
---|
| 1988 | return -1;
|
---|
| 1989 | }
|
---|
| 1990 |
|
---|
| 1991 | lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, &used_sockets);
|
---|
| 1992 |
|
---|
| 1993 | /* Go through each socket in each list to count number of sockets which
|
---|
| 1994 | currently match */
|
---|
| 1995 | nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
|
---|
| 1996 |
|
---|
| 1997 | if (nready < 0) {
|
---|
| 1998 | /* one of the sockets in one of the fd_sets was invalid */
|
---|
| 1999 | set_errno(EBADF);
|
---|
| 2000 | lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
|
---|
| 2001 | return -1;
|
---|
| 2002 | } else if (nready > 0) {
|
---|
| 2003 | /* one or more sockets are set, no need to wait */
|
---|
| 2004 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
|
---|
| 2005 | } else {
|
---|
| 2006 | /* If we don't have any current events, then suspend if we are supposed to */
|
---|
| 2007 | if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
|
---|
| 2008 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
|
---|
| 2009 | /* This is OK as the local fdsets are empty and nready is zero,
|
---|
| 2010 | or we would have returned earlier. */
|
---|
| 2011 | } else {
|
---|
| 2012 | /* None ready: add our semaphore to list:
|
---|
| 2013 | We don't actually need any dynamic memory. Our entry on the
|
---|
| 2014 | list is only valid while we are in this function, so it's ok
|
---|
| 2015 | to use local variables (unless we're running in MPU compatible
|
---|
| 2016 | mode). */
|
---|
| 2017 | API_SELECT_CB_VAR_DECLARE(select_cb);
|
---|
| 2018 | API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(ENOMEM); lwip_select_dec_sockets_used(maxfdp1, &used_sockets); return -1);
|
---|
| 2019 | memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb));
|
---|
| 2020 |
|
---|
| 2021 | API_SELECT_CB_VAR_REF(select_cb).readset = readset;
|
---|
| 2022 | API_SELECT_CB_VAR_REF(select_cb).writeset = writeset;
|
---|
| 2023 | API_SELECT_CB_VAR_REF(select_cb).exceptset = exceptset;
|
---|
| 2024 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 2025 | API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET();
|
---|
| 2026 | #else /* LWIP_NETCONN_SEM_PER_THREAD */
|
---|
| 2027 | if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) {
|
---|
| 2028 | /* failed to create semaphore */
|
---|
| 2029 | set_errno(ENOMEM);
|
---|
| 2030 | lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
|
---|
| 2031 | API_SELECT_CB_VAR_FREE(select_cb);
|
---|
| 2032 | return -1;
|
---|
| 2033 | }
|
---|
| 2034 | #endif /* LWIP_NETCONN_SEM_PER_THREAD */
|
---|
| 2035 |
|
---|
| 2036 | lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb));
|
---|
| 2037 |
|
---|
| 2038 | /* Increase select_waiting for each socket we are interested in */
|
---|
| 2039 | maxfdp2 = maxfdp1;
|
---|
| 2040 | for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) {
|
---|
| 2041 | if ((readset && FD_ISSET(i, readset)) ||
|
---|
| 2042 | (writeset && FD_ISSET(i, writeset)) ||
|
---|
| 2043 | (exceptset && FD_ISSET(i, exceptset))) {
|
---|
| 2044 | struct lwip_sock *sock;
|
---|
| 2045 | SYS_ARCH_PROTECT(lev);
|
---|
| 2046 | sock = tryget_socket_unconn_locked(i);
|
---|
| 2047 | if (sock != NULL) {
|
---|
| 2048 | sock->select_waiting++;
|
---|
| 2049 | if (sock->select_waiting == 0) {
|
---|
| 2050 | /* overflow - too many threads waiting */
|
---|
| 2051 | sock->select_waiting--;
|
---|
| 2052 | nready = -1;
|
---|
| 2053 | maxfdp2 = i;
|
---|
| 2054 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 2055 | done_socket(sock);
|
---|
| 2056 | set_errno(EBUSY);
|
---|
| 2057 | break;
|
---|
| 2058 | }
|
---|
| 2059 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 2060 | done_socket(sock);
|
---|
| 2061 | } else {
|
---|
| 2062 | /* Not a valid socket */
|
---|
| 2063 | nready = -1;
|
---|
| 2064 | maxfdp2 = i;
|
---|
| 2065 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 2066 | set_errno(EBADF);
|
---|
| 2067 | break;
|
---|
| 2068 | }
|
---|
| 2069 | }
|
---|
| 2070 | }
|
---|
| 2071 |
|
---|
| 2072 | if (nready >= 0) {
|
---|
| 2073 | /* Call lwip_selscan again: there could have been events between
|
---|
| 2074 | the last scan (without us on the list) and putting us on the list! */
|
---|
| 2075 | nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
|
---|
| 2076 | if (!nready) {
|
---|
| 2077 | /* Still none ready, just wait to be woken */
|
---|
| 2078 | if (timeout == 0) {
|
---|
| 2079 | /* Wait forever */
|
---|
| 2080 | msectimeout = 0;
|
---|
| 2081 | } else {
|
---|
| 2082 | long msecs_long = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500) / 1000));
|
---|
| 2083 | if (msecs_long <= 0) {
|
---|
| 2084 | /* Wait 1ms at least (0 means wait forever) */
|
---|
| 2085 | msectimeout = 1;
|
---|
| 2086 | } else {
|
---|
| 2087 | msectimeout = (u32_t)msecs_long;
|
---|
| 2088 | }
|
---|
| 2089 | }
|
---|
| 2090 |
|
---|
| 2091 | waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout);
|
---|
| 2092 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 2093 | waited = 1;
|
---|
| 2094 | #endif
|
---|
| 2095 | }
|
---|
| 2096 | }
|
---|
| 2097 |
|
---|
| 2098 | /* Decrease select_waiting for each socket we are interested in */
|
---|
| 2099 | for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) {
|
---|
| 2100 | if ((readset && FD_ISSET(i, readset)) ||
|
---|
| 2101 | (writeset && FD_ISSET(i, writeset)) ||
|
---|
| 2102 | (exceptset && FD_ISSET(i, exceptset))) {
|
---|
| 2103 | struct lwip_sock *sock;
|
---|
| 2104 | SYS_ARCH_PROTECT(lev);
|
---|
| 2105 | sock = tryget_socket_unconn_locked(i);
|
---|
| 2106 | if (sock != NULL) {
|
---|
| 2107 | /* for now, handle select_waiting==0... */
|
---|
| 2108 | LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
|
---|
| 2109 | if (sock->select_waiting > 0) {
|
---|
| 2110 | sock->select_waiting--;
|
---|
| 2111 | }
|
---|
| 2112 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 2113 | done_socket(sock);
|
---|
| 2114 | } else {
|
---|
| 2115 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 2116 | /* Not a valid socket */
|
---|
| 2117 | nready = -1;
|
---|
| 2118 | set_errno(EBADF);
|
---|
| 2119 | }
|
---|
| 2120 | }
|
---|
| 2121 | }
|
---|
| 2122 |
|
---|
| 2123 | lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb));
|
---|
| 2124 |
|
---|
| 2125 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 2126 | if (API_SELECT_CB_VAR_REF(select_cb).sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) {
|
---|
| 2127 | /* don't leave the thread-local semaphore signalled */
|
---|
| 2128 | sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1);
|
---|
| 2129 | }
|
---|
| 2130 | #else /* LWIP_NETCONN_SEM_PER_THREAD */
|
---|
| 2131 | sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem);
|
---|
| 2132 | #endif /* LWIP_NETCONN_SEM_PER_THREAD */
|
---|
| 2133 | API_SELECT_CB_VAR_FREE(select_cb);
|
---|
| 2134 |
|
---|
| 2135 | if (nready < 0) {
|
---|
| 2136 | /* This happens when a socket got closed while waiting */
|
---|
| 2137 | lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
|
---|
| 2138 | return -1;
|
---|
| 2139 | }
|
---|
| 2140 |
|
---|
| 2141 | if (waitres == SYS_ARCH_TIMEOUT) {
|
---|
| 2142 | /* Timeout */
|
---|
| 2143 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
|
---|
| 2144 | /* This is OK as the local fdsets are empty and nready is zero,
|
---|
| 2145 | or we would have returned earlier. */
|
---|
| 2146 | } else {
|
---|
| 2147 | /* See what's set now after waiting */
|
---|
| 2148 | nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
|
---|
| 2149 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
|
---|
| 2150 | }
|
---|
| 2151 | }
|
---|
| 2152 | }
|
---|
| 2153 |
|
---|
| 2154 | lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
|
---|
| 2155 | set_errno(0);
|
---|
| 2156 | if (readset) {
|
---|
| 2157 | *readset = lreadset;
|
---|
| 2158 | }
|
---|
| 2159 | if (writeset) {
|
---|
| 2160 | *writeset = lwriteset;
|
---|
| 2161 | }
|
---|
| 2162 | if (exceptset) {
|
---|
| 2163 | *exceptset = lexceptset;
|
---|
| 2164 | }
|
---|
| 2165 | return nready;
|
---|
| 2166 | }
|
---|
| 2167 | #endif /* LWIP_SOCKET_SELECT */
|
---|
| 2168 |
|
---|
| 2169 | #if LWIP_SOCKET_POLL
|
---|
| 2170 | /** Options for the lwip_pollscan function. */
|
---|
| 2171 | enum lwip_pollscan_opts
|
---|
| 2172 | {
|
---|
| 2173 | /** Clear revents in each struct pollfd. */
|
---|
| 2174 | LWIP_POLLSCAN_CLEAR = 1,
|
---|
| 2175 |
|
---|
| 2176 | /** Increment select_waiting in each struct lwip_sock. */
|
---|
| 2177 | LWIP_POLLSCAN_INC_WAIT = 2,
|
---|
| 2178 |
|
---|
| 2179 | /** Decrement select_waiting in each struct lwip_sock. */
|
---|
| 2180 | LWIP_POLLSCAN_DEC_WAIT = 4
|
---|
| 2181 | };
|
---|
| 2182 |
|
---|
| 2183 | /**
|
---|
| 2184 | * Update revents in each struct pollfd.
|
---|
| 2185 | * Optionally update select_waiting in struct lwip_sock.
|
---|
| 2186 | *
|
---|
| 2187 | * @param fds array of structures to update
|
---|
| 2188 | * @param nfds number of structures in fds
|
---|
| 2189 | * @param opts what to update and how
|
---|
| 2190 | * @return number of structures that have revents != 0
|
---|
| 2191 | */
|
---|
| 2192 | static int
|
---|
| 2193 | lwip_pollscan(struct pollfd *fds, nfds_t nfds, enum lwip_pollscan_opts opts)
|
---|
| 2194 | {
|
---|
| 2195 | int nready = 0;
|
---|
| 2196 | nfds_t fdi;
|
---|
| 2197 | struct lwip_sock *sock;
|
---|
| 2198 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 2199 |
|
---|
| 2200 | /* Go through each struct pollfd in the array. */
|
---|
| 2201 | for (fdi = 0; fdi < nfds; fdi++) {
|
---|
| 2202 | if ((opts & LWIP_POLLSCAN_CLEAR) != 0) {
|
---|
| 2203 | fds[fdi].revents = 0;
|
---|
| 2204 | }
|
---|
| 2205 |
|
---|
| 2206 | /* Negative fd means the caller wants us to ignore this struct.
|
---|
| 2207 | POLLNVAL means we already detected that the fd is invalid;
|
---|
| 2208 | if another thread has since opened a new socket with that fd,
|
---|
| 2209 | we must not use that socket. */
|
---|
| 2210 | if (fds[fdi].fd >= 0 && (fds[fdi].revents & POLLNVAL) == 0) {
|
---|
| 2211 | /* First get the socket's status (protected)... */
|
---|
| 2212 | SYS_ARCH_PROTECT(lev);
|
---|
| 2213 | sock = tryget_socket_unconn_locked(fds[fdi].fd);
|
---|
| 2214 | if (sock != NULL) {
|
---|
| 2215 | void* lastdata = sock->lastdata.pbuf;
|
---|
| 2216 | s16_t rcvevent = sock->rcvevent;
|
---|
| 2217 | u16_t sendevent = sock->sendevent;
|
---|
| 2218 | u16_t errevent = sock->errevent;
|
---|
| 2219 |
|
---|
| 2220 | if ((opts & LWIP_POLLSCAN_INC_WAIT) != 0) {
|
---|
| 2221 | sock->select_waiting++;
|
---|
| 2222 | if (sock->select_waiting == 0) {
|
---|
| 2223 | /* overflow - too many threads waiting */
|
---|
| 2224 | sock->select_waiting--;
|
---|
| 2225 | nready = -1;
|
---|
| 2226 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 2227 | done_socket(sock);
|
---|
| 2228 | break;
|
---|
| 2229 | }
|
---|
| 2230 | } else if ((opts & LWIP_POLLSCAN_DEC_WAIT) != 0) {
|
---|
| 2231 | /* for now, handle select_waiting==0... */
|
---|
| 2232 | LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
|
---|
| 2233 | if (sock->select_waiting > 0) {
|
---|
| 2234 | sock->select_waiting--;
|
---|
| 2235 | }
|
---|
| 2236 | }
|
---|
| 2237 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 2238 | done_socket(sock);
|
---|
| 2239 |
|
---|
| 2240 | /* ... then examine it: */
|
---|
| 2241 | /* See if netconn of this socket is ready for read */
|
---|
| 2242 | if ((fds[fdi].events & POLLIN) != 0 && ((lastdata != NULL) || (rcvevent > 0))) {
|
---|
| 2243 | fds[fdi].revents |= POLLIN;
|
---|
| 2244 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for reading\n", fds[fdi].fd));
|
---|
| 2245 | }
|
---|
| 2246 | /* See if netconn of this socket is ready for write */
|
---|
| 2247 | if ((fds[fdi].events & POLLOUT) != 0 && (sendevent != 0)) {
|
---|
| 2248 | fds[fdi].revents |= POLLOUT;
|
---|
| 2249 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for writing\n", fds[fdi].fd));
|
---|
| 2250 | }
|
---|
| 2251 | /* See if netconn of this socket had an error */
|
---|
| 2252 | if (errevent != 0) {
|
---|
| 2253 | /* POLLERR is output only. */
|
---|
| 2254 | fds[fdi].revents |= POLLERR;
|
---|
| 2255 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for exception\n", fds[fdi].fd));
|
---|
| 2256 | }
|
---|
| 2257 | } else {
|
---|
| 2258 | /* Not a valid socket */
|
---|
| 2259 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 2260 | /* POLLNVAL is output only. */
|
---|
| 2261 | fds[fdi].revents |= POLLNVAL;
|
---|
| 2262 | return -1;
|
---|
| 2263 | }
|
---|
| 2264 | }
|
---|
| 2265 |
|
---|
| 2266 | /* Will return the number of structures that have events,
|
---|
| 2267 | not the number of events. */
|
---|
| 2268 | if (fds[fdi].revents != 0) {
|
---|
| 2269 | nready++;
|
---|
| 2270 | }
|
---|
| 2271 | }
|
---|
| 2272 |
|
---|
| 2273 | LWIP_ASSERT("nready >= 0", nready >= 0);
|
---|
| 2274 | return nready;
|
---|
| 2275 | }
|
---|
| 2276 |
|
---|
| 2277 | #if LWIP_NETCONN_FULLDUPLEX
|
---|
| 2278 | /* Mark all sockets as used.
|
---|
| 2279 | *
|
---|
| 2280 | * All sockets are marked (and later unmarked), whether they are open or not.
|
---|
| 2281 | * This is OK as lwip_pollscan aborts select when non-open sockets are found.
|
---|
| 2282 | */
|
---|
| 2283 | static void
|
---|
| 2284 | lwip_poll_inc_sockets_used(struct pollfd *fds, nfds_t nfds)
|
---|
| 2285 | {
|
---|
| 2286 | nfds_t fdi;
|
---|
| 2287 |
|
---|
| 2288 | if(fds) {
|
---|
| 2289 | /* Go through each struct pollfd in the array. */
|
---|
| 2290 | for (fdi = 0; fdi < nfds; fdi++) {
|
---|
| 2291 | /* Increase the reference counter */
|
---|
| 2292 | tryget_socket_unconn(fds[fdi].fd);
|
---|
| 2293 | }
|
---|
| 2294 | }
|
---|
| 2295 | }
|
---|
| 2296 |
|
---|
| 2297 | /* Let go all sockets that were marked as used when starting poll */
|
---|
| 2298 | static void
|
---|
| 2299 | lwip_poll_dec_sockets_used(struct pollfd *fds, nfds_t nfds)
|
---|
| 2300 | {
|
---|
| 2301 | nfds_t fdi;
|
---|
| 2302 |
|
---|
| 2303 | if(fds) {
|
---|
| 2304 | /* Go through each struct pollfd in the array. */
|
---|
| 2305 | for (fdi = 0; fdi < nfds; fdi++) {
|
---|
| 2306 | struct lwip_sock *sock = tryget_socket_unconn_nouse(fds[fdi].fd);
|
---|
| 2307 | if (sock != NULL) {
|
---|
| 2308 | done_socket(sock);
|
---|
| 2309 | }
|
---|
| 2310 | }
|
---|
| 2311 | }
|
---|
| 2312 | }
|
---|
| 2313 | #else /* LWIP_NETCONN_FULLDUPLEX */
|
---|
| 2314 | #define lwip_poll_inc_sockets_used(fds, nfds)
|
---|
| 2315 | #define lwip_poll_dec_sockets_used(fds, nfds)
|
---|
| 2316 | #endif /* LWIP_NETCONN_FULLDUPLEX */
|
---|
| 2317 |
|
---|
| 2318 | int
|
---|
| 2319 | lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout)
|
---|
| 2320 | {
|
---|
| 2321 | u32_t waitres = 0;
|
---|
| 2322 | int nready;
|
---|
| 2323 | u32_t msectimeout;
|
---|
| 2324 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 2325 | int waited = 0;
|
---|
| 2326 | #endif
|
---|
| 2327 |
|
---|
| 2328 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll(%p, %d, %d)\n",
|
---|
| 2329 | (void*)fds, (int)nfds, timeout));
|
---|
| 2330 | LWIP_ERROR("lwip_poll: invalid fds", ((fds != NULL && nfds > 0) || (fds == NULL && nfds == 0)),
|
---|
| 2331 | set_errno(EINVAL); return -1;);
|
---|
| 2332 |
|
---|
| 2333 | lwip_poll_inc_sockets_used(fds, nfds);
|
---|
| 2334 |
|
---|
| 2335 | /* Go through each struct pollfd to count number of structures
|
---|
| 2336 | which currently match */
|
---|
| 2337 | nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_CLEAR);
|
---|
| 2338 |
|
---|
| 2339 | if (nready < 0) {
|
---|
| 2340 | lwip_poll_dec_sockets_used(fds, nfds);
|
---|
| 2341 | return -1;
|
---|
| 2342 | }
|
---|
| 2343 |
|
---|
| 2344 | /* If we don't have any current events, then suspend if we are supposed to */
|
---|
| 2345 | if (!nready) {
|
---|
| 2346 | API_SELECT_CB_VAR_DECLARE(select_cb);
|
---|
| 2347 |
|
---|
| 2348 | if (timeout == 0) {
|
---|
| 2349 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: no timeout, returning 0\n"));
|
---|
| 2350 | goto return_success;
|
---|
| 2351 | }
|
---|
| 2352 | API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(EAGAIN); lwip_poll_dec_sockets_used(fds, nfds); return -1);
|
---|
| 2353 | memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb));
|
---|
| 2354 |
|
---|
| 2355 | /* None ready: add our semaphore to list:
|
---|
| 2356 | We don't actually need any dynamic memory. Our entry on the
|
---|
| 2357 | list is only valid while we are in this function, so it's ok
|
---|
| 2358 | to use local variables. */
|
---|
| 2359 |
|
---|
| 2360 | API_SELECT_CB_VAR_REF(select_cb).poll_fds = fds;
|
---|
| 2361 | API_SELECT_CB_VAR_REF(select_cb).poll_nfds = nfds;
|
---|
| 2362 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 2363 | API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET();
|
---|
| 2364 | #else /* LWIP_NETCONN_SEM_PER_THREAD */
|
---|
| 2365 | if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) {
|
---|
| 2366 | /* failed to create semaphore */
|
---|
| 2367 | set_errno(EAGAIN);
|
---|
| 2368 | lwip_poll_dec_sockets_used(fds, nfds);
|
---|
| 2369 | API_SELECT_CB_VAR_FREE(select_cb);
|
---|
| 2370 | return -1;
|
---|
| 2371 | }
|
---|
| 2372 | #endif /* LWIP_NETCONN_SEM_PER_THREAD */
|
---|
| 2373 |
|
---|
| 2374 | lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb));
|
---|
| 2375 |
|
---|
| 2376 | /* Increase select_waiting for each socket we are interested in.
|
---|
| 2377 | Also, check for events again: there could have been events between
|
---|
| 2378 | the last scan (without us on the list) and putting us on the list! */
|
---|
| 2379 | nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_INC_WAIT);
|
---|
| 2380 |
|
---|
| 2381 | if (!nready) {
|
---|
| 2382 | /* Still none ready, just wait to be woken */
|
---|
| 2383 | if (timeout < 0) {
|
---|
| 2384 | /* Wait forever */
|
---|
| 2385 | msectimeout = 0;
|
---|
| 2386 | } else {
|
---|
| 2387 | /* timeout == 0 would have been handled earlier. */
|
---|
| 2388 | LWIP_ASSERT("timeout > 0", timeout > 0);
|
---|
| 2389 | msectimeout = timeout;
|
---|
| 2390 | }
|
---|
| 2391 | waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout);
|
---|
| 2392 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 2393 | waited = 1;
|
---|
| 2394 | #endif
|
---|
| 2395 | }
|
---|
| 2396 |
|
---|
| 2397 | /* Decrease select_waiting for each socket we are interested in,
|
---|
| 2398 | and check which events occurred while we waited. */
|
---|
| 2399 | nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_DEC_WAIT);
|
---|
| 2400 |
|
---|
| 2401 | lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb));
|
---|
| 2402 |
|
---|
| 2403 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 2404 | if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) {
|
---|
| 2405 | /* don't leave the thread-local semaphore signalled */
|
---|
| 2406 | sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1);
|
---|
| 2407 | }
|
---|
| 2408 | #else /* LWIP_NETCONN_SEM_PER_THREAD */
|
---|
| 2409 | sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem);
|
---|
| 2410 | #endif /* LWIP_NETCONN_SEM_PER_THREAD */
|
---|
| 2411 | API_SELECT_CB_VAR_FREE(select_cb);
|
---|
| 2412 |
|
---|
| 2413 | if (nready < 0) {
|
---|
| 2414 | /* This happens when a socket got closed while waiting */
|
---|
| 2415 | lwip_poll_dec_sockets_used(fds, nfds);
|
---|
| 2416 | return -1;
|
---|
| 2417 | }
|
---|
| 2418 |
|
---|
| 2419 | if (waitres == SYS_ARCH_TIMEOUT) {
|
---|
| 2420 | /* Timeout */
|
---|
| 2421 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: timeout expired\n"));
|
---|
| 2422 | goto return_success;
|
---|
| 2423 | }
|
---|
| 2424 | }
|
---|
| 2425 |
|
---|
| 2426 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: nready=%d\n", nready));
|
---|
| 2427 | return_success:
|
---|
| 2428 | lwip_poll_dec_sockets_used(fds, nfds);
|
---|
| 2429 | set_errno(0);
|
---|
| 2430 | return nready;
|
---|
| 2431 | }
|
---|
| 2432 |
|
---|
| 2433 | /**
|
---|
| 2434 | * Check whether event_callback should wake up a thread waiting in
|
---|
| 2435 | * lwip_poll.
|
---|
| 2436 | */
|
---|
| 2437 | static int
|
---|
| 2438 | lwip_poll_should_wake(const struct lwip_select_cb *scb, int fd, int has_recvevent, int has_sendevent, int has_errevent)
|
---|
| 2439 | {
|
---|
| 2440 | nfds_t fdi;
|
---|
| 2441 | for (fdi = 0; fdi < scb->poll_nfds; fdi++) {
|
---|
| 2442 | const struct pollfd *pollfd = &scb->poll_fds[fdi];
|
---|
| 2443 | if (pollfd->fd == fd) {
|
---|
| 2444 | /* Do not update pollfd->revents right here;
|
---|
| 2445 | that would be a data race because lwip_pollscan
|
---|
| 2446 | accesses revents without protecting. */
|
---|
| 2447 | if (has_recvevent && (pollfd->events & POLLIN) != 0) {
|
---|
| 2448 | return 1;
|
---|
| 2449 | }
|
---|
| 2450 | if (has_sendevent && (pollfd->events & POLLOUT) != 0) {
|
---|
| 2451 | return 1;
|
---|
| 2452 | }
|
---|
| 2453 | if (has_errevent) {
|
---|
| 2454 | /* POLLERR is output only. */
|
---|
| 2455 | return 1;
|
---|
| 2456 | }
|
---|
| 2457 | }
|
---|
| 2458 | }
|
---|
| 2459 | return 0;
|
---|
| 2460 | }
|
---|
| 2461 | #endif /* LWIP_SOCKET_POLL */
|
---|
| 2462 |
|
---|
| 2463 | #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
|
---|
| 2464 | /**
|
---|
| 2465 | * Callback registered in the netconn layer for each socket-netconn.
|
---|
| 2466 | * Processes recvevent (data available) and wakes up tasks waiting for select.
|
---|
| 2467 | *
|
---|
| 2468 | * @note for LWIP_TCPIP_CORE_LOCKING any caller of this function
|
---|
| 2469 | * must have the core lock held when signaling the following events
|
---|
| 2470 | * as they might cause select_list_cb to be checked:
|
---|
| 2471 | * NETCONN_EVT_RCVPLUS
|
---|
| 2472 | * NETCONN_EVT_SENDPLUS
|
---|
| 2473 | * NETCONN_EVT_ERROR
|
---|
| 2474 | * This requirement will be asserted in select_check_waiters()
|
---|
| 2475 | */
|
---|
| 2476 | static void
|
---|
| 2477 | event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
|
---|
| 2478 | {
|
---|
| 2479 | int s, check_waiters;
|
---|
| 2480 | struct lwip_sock *sock;
|
---|
| 2481 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 2482 |
|
---|
| 2483 | LWIP_UNUSED_ARG(len);
|
---|
| 2484 |
|
---|
| 2485 | /* Get socket */
|
---|
| 2486 | if (conn) {
|
---|
| 2487 | s = conn->socket;
|
---|
| 2488 | if (s < 0) {
|
---|
| 2489 | /* Data comes in right away after an accept, even though
|
---|
| 2490 | * the server task might not have created a new socket yet.
|
---|
| 2491 | * Just count down (or up) if that's the case and we
|
---|
| 2492 | * will use the data later. Note that only receive events
|
---|
| 2493 | * can happen before the new socket is set up. */
|
---|
| 2494 | SYS_ARCH_PROTECT(lev);
|
---|
| 2495 | if (conn->socket < 0) {
|
---|
| 2496 | if (evt == NETCONN_EVT_RCVPLUS) {
|
---|
| 2497 | /* conn->socket is -1 on initialization
|
---|
| 2498 | lwip_accept adjusts sock->recvevent if conn->socket < -1 */
|
---|
| 2499 | conn->socket--;
|
---|
| 2500 | }
|
---|
| 2501 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 2502 | return;
|
---|
| 2503 | }
|
---|
| 2504 | s = conn->socket;
|
---|
| 2505 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 2506 | }
|
---|
| 2507 |
|
---|
| 2508 | sock = get_socket(s);
|
---|
| 2509 | if (!sock) {
|
---|
| 2510 | return;
|
---|
| 2511 | }
|
---|
| 2512 | } else {
|
---|
| 2513 | return;
|
---|
| 2514 | }
|
---|
| 2515 |
|
---|
| 2516 | check_waiters = 1;
|
---|
| 2517 | SYS_ARCH_PROTECT(lev);
|
---|
| 2518 | /* Set event as required */
|
---|
| 2519 | switch (evt) {
|
---|
| 2520 | case NETCONN_EVT_RCVPLUS:
|
---|
| 2521 | sock->rcvevent++;
|
---|
| 2522 | if (sock->rcvevent > 1) {
|
---|
| 2523 | check_waiters = 0;
|
---|
| 2524 | }
|
---|
| 2525 | break;
|
---|
| 2526 | case NETCONN_EVT_RCVMINUS:
|
---|
| 2527 | sock->rcvevent--;
|
---|
| 2528 | check_waiters = 0;
|
---|
| 2529 | break;
|
---|
| 2530 | case NETCONN_EVT_SENDPLUS:
|
---|
| 2531 | if (sock->sendevent) {
|
---|
| 2532 | check_waiters = 0;
|
---|
| 2533 | }
|
---|
| 2534 | sock->sendevent = 1;
|
---|
| 2535 | break;
|
---|
| 2536 | case NETCONN_EVT_SENDMINUS:
|
---|
| 2537 | sock->sendevent = 0;
|
---|
| 2538 | check_waiters = 0;
|
---|
| 2539 | break;
|
---|
| 2540 | case NETCONN_EVT_ERROR:
|
---|
| 2541 | sock->errevent = 1;
|
---|
| 2542 | break;
|
---|
| 2543 | default:
|
---|
| 2544 | LWIP_ASSERT("unknown event", 0);
|
---|
| 2545 | break;
|
---|
| 2546 | }
|
---|
| 2547 |
|
---|
| 2548 | if (sock->select_waiting && check_waiters) {
|
---|
| 2549 | /* Save which events are active */
|
---|
| 2550 | int has_recvevent, has_sendevent, has_errevent;
|
---|
| 2551 | has_recvevent = sock->rcvevent > 0;
|
---|
| 2552 | has_sendevent = sock->sendevent != 0;
|
---|
| 2553 | has_errevent = sock->errevent != 0;
|
---|
| 2554 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 2555 | /* Check any select calls waiting on this socket */
|
---|
| 2556 | select_check_waiters(s, has_recvevent, has_sendevent, has_errevent);
|
---|
| 2557 | } else {
|
---|
| 2558 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 2559 | }
|
---|
| 2560 | done_socket(sock);
|
---|
| 2561 | }
|
---|
| 2562 |
|
---|
| 2563 | /**
|
---|
| 2564 | * Check if any select waiters are waiting on this socket and its events
|
---|
| 2565 | *
|
---|
| 2566 | * @note on synchronization of select_cb_list:
|
---|
| 2567 | * LWIP_TCPIP_CORE_LOCKING: the select_cb_list must only be accessed while holding
|
---|
| 2568 | * the core lock. We do a single pass through the list and signal any waiters.
|
---|
| 2569 | * Core lock should already be held when calling here!!!!
|
---|
| 2570 |
|
---|
| 2571 | * !LWIP_TCPIP_CORE_LOCKING: we use SYS_ARCH_PROTECT but unlock on each iteration
|
---|
| 2572 | * of the loop, thus creating a possibility where a thread could modify the
|
---|
| 2573 | * select_cb_list during our UNPROTECT/PROTECT. We use a generational counter to
|
---|
| 2574 | * detect this change and restart the list walk. The list is expected to be small
|
---|
| 2575 | */
|
---|
| 2576 | static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent)
|
---|
| 2577 | {
|
---|
| 2578 | struct lwip_select_cb *scb;
|
---|
| 2579 | #if !LWIP_TCPIP_CORE_LOCKING
|
---|
| 2580 | int last_select_cb_ctr;
|
---|
| 2581 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 2582 | #endif /* !LWIP_TCPIP_CORE_LOCKING */
|
---|
| 2583 |
|
---|
| 2584 | LWIP_ASSERT_CORE_LOCKED();
|
---|
| 2585 |
|
---|
| 2586 | #if !LWIP_TCPIP_CORE_LOCKING
|
---|
| 2587 | SYS_ARCH_PROTECT(lev);
|
---|
| 2588 | again:
|
---|
| 2589 | /* remember the state of select_cb_list to detect changes */
|
---|
| 2590 | last_select_cb_ctr = select_cb_ctr;
|
---|
| 2591 | #endif /* !LWIP_TCPIP_CORE_LOCKING */
|
---|
| 2592 | for (scb = select_cb_list; scb != NULL; scb = scb->next) {
|
---|
| 2593 | if (scb->sem_signalled == 0) {
|
---|
| 2594 | /* semaphore not signalled yet */
|
---|
| 2595 | int do_signal = 0;
|
---|
| 2596 | #if LWIP_SOCKET_POLL
|
---|
| 2597 | if (scb->poll_fds != NULL) {
|
---|
| 2598 | do_signal = lwip_poll_should_wake(scb, s, has_recvevent, has_sendevent, has_errevent);
|
---|
| 2599 | }
|
---|
| 2600 | #endif /* LWIP_SOCKET_POLL */
|
---|
| 2601 | #if LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL
|
---|
| 2602 | else
|
---|
| 2603 | #endif /* LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL */
|
---|
| 2604 | #if LWIP_SOCKET_SELECT
|
---|
| 2605 | {
|
---|
| 2606 | /* Test this select call for our socket */
|
---|
| 2607 | if (has_recvevent) {
|
---|
| 2608 | if (scb->readset && FD_ISSET(s, scb->readset)) {
|
---|
| 2609 | do_signal = 1;
|
---|
| 2610 | }
|
---|
| 2611 | }
|
---|
| 2612 | if (has_sendevent) {
|
---|
| 2613 | if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
|
---|
| 2614 | do_signal = 1;
|
---|
| 2615 | }
|
---|
| 2616 | }
|
---|
| 2617 | if (has_errevent) {
|
---|
| 2618 | if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
|
---|
| 2619 | do_signal = 1;
|
---|
| 2620 | }
|
---|
| 2621 | }
|
---|
| 2622 | }
|
---|
| 2623 | #endif /* LWIP_SOCKET_SELECT */
|
---|
| 2624 | if (do_signal) {
|
---|
| 2625 | scb->sem_signalled = 1;
|
---|
| 2626 | /* For !LWIP_TCPIP_CORE_LOCKING, we don't call SYS_ARCH_UNPROTECT() before signaling
|
---|
| 2627 | the semaphore, as this might lead to the select thread taking itself off the list,
|
---|
| 2628 | invalidating the semaphore. */
|
---|
| 2629 | sys_sem_signal(SELECT_SEM_PTR(scb->sem));
|
---|
| 2630 | }
|
---|
| 2631 | }
|
---|
| 2632 | #if LWIP_TCPIP_CORE_LOCKING
|
---|
| 2633 | }
|
---|
| 2634 | #else
|
---|
| 2635 | /* unlock interrupts with each step */
|
---|
| 2636 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 2637 | /* this makes sure interrupt protection time is short */
|
---|
| 2638 | SYS_ARCH_PROTECT(lev);
|
---|
| 2639 | if (last_select_cb_ctr != select_cb_ctr) {
|
---|
| 2640 | /* someone has changed select_cb_list, restart at the beginning */
|
---|
| 2641 | goto again;
|
---|
| 2642 | }
|
---|
| 2643 | /* remember the state of select_cb_list to detect changes */
|
---|
| 2644 | last_select_cb_ctr = select_cb_ctr;
|
---|
| 2645 | }
|
---|
| 2646 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 2647 | #endif
|
---|
| 2648 | }
|
---|
| 2649 | #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */
|
---|
| 2650 |
|
---|
| 2651 | /**
|
---|
| 2652 | * Close one end of a full-duplex connection.
|
---|
| 2653 | */
|
---|
| 2654 | int
|
---|
| 2655 | lwip_shutdown(int s, int how)
|
---|
| 2656 | {
|
---|
| 2657 | struct lwip_sock *sock;
|
---|
| 2658 | err_t err;
|
---|
| 2659 | u8_t shut_rx = 0, shut_tx = 0;
|
---|
| 2660 |
|
---|
| 2661 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
|
---|
| 2662 |
|
---|
| 2663 | sock = get_socket(s);
|
---|
| 2664 | if (!sock) {
|
---|
| 2665 | return -1;
|
---|
| 2666 | }
|
---|
| 2667 |
|
---|
| 2668 | if (sock->conn != NULL) {
|
---|
| 2669 | if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
|
---|
| 2670 | sock_set_errno(sock, EOPNOTSUPP);
|
---|
| 2671 | done_socket(sock);
|
---|
| 2672 | return -1;
|
---|
| 2673 | }
|
---|
| 2674 | } else {
|
---|
| 2675 | sock_set_errno(sock, ENOTCONN);
|
---|
| 2676 | done_socket(sock);
|
---|
| 2677 | return -1;
|
---|
| 2678 | }
|
---|
| 2679 |
|
---|
| 2680 | if (how == SHUT_RD) {
|
---|
| 2681 | shut_rx = 1;
|
---|
| 2682 | } else if (how == SHUT_WR) {
|
---|
| 2683 | shut_tx = 1;
|
---|
| 2684 | } else if (how == SHUT_RDWR) {
|
---|
| 2685 | shut_rx = 1;
|
---|
| 2686 | shut_tx = 1;
|
---|
| 2687 | } else {
|
---|
| 2688 | sock_set_errno(sock, EINVAL);
|
---|
| 2689 | done_socket(sock);
|
---|
| 2690 | return -1;
|
---|
| 2691 | }
|
---|
| 2692 | err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
|
---|
| 2693 |
|
---|
| 2694 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 2695 | done_socket(sock);
|
---|
| 2696 | return (err == ERR_OK ? 0 : -1);
|
---|
| 2697 | }
|
---|
| 2698 |
|
---|
| 2699 | static int
|
---|
| 2700 | lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
|
---|
| 2701 | {
|
---|
| 2702 | struct lwip_sock *sock;
|
---|
| 2703 | union sockaddr_aligned saddr;
|
---|
| 2704 | ip_addr_t naddr;
|
---|
| 2705 | u16_t port;
|
---|
| 2706 | err_t err;
|
---|
| 2707 |
|
---|
| 2708 | sock = get_socket(s);
|
---|
| 2709 | if (!sock) {
|
---|
| 2710 | return -1;
|
---|
| 2711 | }
|
---|
| 2712 |
|
---|
| 2713 | /* get the IP address and port */
|
---|
| 2714 | err = netconn_getaddr(sock->conn, &naddr, &port, local);
|
---|
| 2715 | if (err != ERR_OK) {
|
---|
| 2716 | sock_set_errno(sock, err_to_errno(err));
|
---|
| 2717 | done_socket(sock);
|
---|
| 2718 | return -1;
|
---|
| 2719 | }
|
---|
| 2720 |
|
---|
| 2721 | #if LWIP_IPV4 && LWIP_IPV6
|
---|
| 2722 | /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
|
---|
| 2723 | if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) &&
|
---|
| 2724 | IP_IS_V4_VAL(naddr)) {
|
---|
| 2725 | ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&naddr), ip_2_ip4(&naddr));
|
---|
| 2726 | IP_SET_TYPE_VAL(naddr, IPADDR_TYPE_V6);
|
---|
| 2727 | }
|
---|
| 2728 | #endif /* LWIP_IPV4 && LWIP_IPV6 */
|
---|
| 2729 |
|
---|
| 2730 | IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port);
|
---|
| 2731 |
|
---|
| 2732 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
|
---|
| 2733 | ip_addr_debug_print_val(SOCKETS_DEBUG, naddr);
|
---|
| 2734 | LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port));
|
---|
| 2735 |
|
---|
| 2736 | if (*namelen > saddr.sa.sa_len) {
|
---|
| 2737 | *namelen = saddr.sa.sa_len;
|
---|
| 2738 | }
|
---|
| 2739 | MEMCPY(name, &saddr, *namelen);
|
---|
| 2740 |
|
---|
| 2741 | sock_set_errno(sock, 0);
|
---|
| 2742 | done_socket(sock);
|
---|
| 2743 | return 0;
|
---|
| 2744 | }
|
---|
| 2745 |
|
---|
| 2746 | int
|
---|
| 2747 | lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
|
---|
| 2748 | {
|
---|
| 2749 | return lwip_getaddrname(s, name, namelen, 0);
|
---|
| 2750 | }
|
---|
| 2751 |
|
---|
| 2752 | int
|
---|
| 2753 | lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
|
---|
| 2754 | {
|
---|
| 2755 | return lwip_getaddrname(s, name, namelen, 1);
|
---|
| 2756 | }
|
---|
| 2757 |
|
---|
| 2758 | int
|
---|
| 2759 | lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
|
---|
| 2760 | {
|
---|
| 2761 | int err;
|
---|
| 2762 | struct lwip_sock *sock = get_socket(s);
|
---|
| 2763 | #if !LWIP_TCPIP_CORE_LOCKING
|
---|
| 2764 | err_t cberr;
|
---|
| 2765 | LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data);
|
---|
| 2766 | #endif /* !LWIP_TCPIP_CORE_LOCKING */
|
---|
| 2767 |
|
---|
| 2768 | if (!sock) {
|
---|
| 2769 | return -1;
|
---|
| 2770 | }
|
---|
| 2771 |
|
---|
| 2772 | if ((NULL == optval) || (NULL == optlen)) {
|
---|
| 2773 | sock_set_errno(sock, EFAULT);
|
---|
| 2774 | done_socket(sock);
|
---|
| 2775 | return -1;
|
---|
| 2776 | }
|
---|
| 2777 |
|
---|
| 2778 | #if LWIP_TCPIP_CORE_LOCKING
|
---|
| 2779 | /* core-locking can just call the -impl function */
|
---|
| 2780 | LOCK_TCPIP_CORE();
|
---|
| 2781 | err = lwip_getsockopt_impl(s, level, optname, optval, optlen);
|
---|
| 2782 | UNLOCK_TCPIP_CORE();
|
---|
| 2783 |
|
---|
| 2784 | #else /* LWIP_TCPIP_CORE_LOCKING */
|
---|
| 2785 |
|
---|
| 2786 | #if LWIP_MPU_COMPATIBLE
|
---|
| 2787 | /* MPU_COMPATIBLE copies the optval data, so check for max size here */
|
---|
| 2788 | if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) {
|
---|
| 2789 | sock_set_errno(sock, ENOBUFS);
|
---|
| 2790 | done_socket(sock);
|
---|
| 2791 | return -1;
|
---|
| 2792 | }
|
---|
| 2793 | #endif /* LWIP_MPU_COMPATIBLE */
|
---|
| 2794 |
|
---|
| 2795 | LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock);
|
---|
| 2796 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s;
|
---|
| 2797 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level;
|
---|
| 2798 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
|
---|
| 2799 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen;
|
---|
| 2800 | #if !LWIP_MPU_COMPATIBLE
|
---|
| 2801 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval;
|
---|
| 2802 | #endif /* !LWIP_MPU_COMPATIBLE */
|
---|
| 2803 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0;
|
---|
| 2804 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 2805 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
|
---|
| 2806 | #else
|
---|
| 2807 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
|
---|
| 2808 | #endif
|
---|
| 2809 | cberr = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
|
---|
| 2810 | if (cberr != ERR_OK) {
|
---|
| 2811 | LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
|
---|
| 2812 | sock_set_errno(sock, err_to_errno(cberr));
|
---|
| 2813 | done_socket(sock);
|
---|
| 2814 | return -1;
|
---|
| 2815 | }
|
---|
| 2816 | sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
|
---|
| 2817 |
|
---|
| 2818 | /* write back optlen and optval */
|
---|
| 2819 | *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen;
|
---|
| 2820 | #if LWIP_MPU_COMPATIBLE
|
---|
| 2821 | MEMCPY(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval,
|
---|
| 2822 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen);
|
---|
| 2823 | #endif /* LWIP_MPU_COMPATIBLE */
|
---|
| 2824 |
|
---|
| 2825 | /* maybe lwip_getsockopt_internal has changed err */
|
---|
| 2826 | err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
|
---|
| 2827 | LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
|
---|
| 2828 | #endif /* LWIP_TCPIP_CORE_LOCKING */
|
---|
| 2829 |
|
---|
| 2830 | sock_set_errno(sock, err);
|
---|
| 2831 | done_socket(sock);
|
---|
| 2832 | return err ? -1 : 0;
|
---|
| 2833 | }
|
---|
| 2834 |
|
---|
| 2835 | #if !LWIP_TCPIP_CORE_LOCKING
|
---|
| 2836 | /** lwip_getsockopt_callback: only used without CORE_LOCKING
|
---|
| 2837 | * to get into the tcpip_thread
|
---|
| 2838 | */
|
---|
| 2839 | static void
|
---|
| 2840 | lwip_getsockopt_callback(void *arg)
|
---|
| 2841 | {
|
---|
| 2842 | struct lwip_setgetsockopt_data *data;
|
---|
| 2843 | LWIP_ASSERT("arg != NULL", arg != NULL);
|
---|
| 2844 | data = (struct lwip_setgetsockopt_data *)arg;
|
---|
| 2845 |
|
---|
| 2846 | data->err = lwip_getsockopt_impl(data->s, data->level, data->optname,
|
---|
| 2847 | #if LWIP_MPU_COMPATIBLE
|
---|
| 2848 | data->optval,
|
---|
| 2849 | #else /* LWIP_MPU_COMPATIBLE */
|
---|
| 2850 | data->optval.p,
|
---|
| 2851 | #endif /* LWIP_MPU_COMPATIBLE */
|
---|
| 2852 | &data->optlen);
|
---|
| 2853 |
|
---|
| 2854 | sys_sem_signal((sys_sem_t *)(data->completed_sem));
|
---|
| 2855 | }
|
---|
| 2856 | #endif /* LWIP_TCPIP_CORE_LOCKING */
|
---|
| 2857 |
|
---|
| 2858 | static int
|
---|
| 2859 | lwip_sockopt_to_ipopt(int optname)
|
---|
| 2860 | {
|
---|
| 2861 | /* Map SO_* values to our internal SOF_* values
|
---|
| 2862 | * We should not rely on #defines in socket.h
|
---|
| 2863 | * being in sync with ip.h.
|
---|
| 2864 | */
|
---|
| 2865 | switch (optname) {
|
---|
| 2866 | case SO_BROADCAST:
|
---|
| 2867 | return SOF_BROADCAST;
|
---|
| 2868 | case SO_KEEPALIVE:
|
---|
| 2869 | return SOF_KEEPALIVE;
|
---|
| 2870 | case SO_REUSEADDR:
|
---|
| 2871 | return SOF_REUSEADDR;
|
---|
| 2872 | default:
|
---|
| 2873 | LWIP_ASSERT("Unknown socket option", 0);
|
---|
| 2874 | return 0;
|
---|
| 2875 | }
|
---|
| 2876 | }
|
---|
| 2877 |
|
---|
| 2878 | /** lwip_getsockopt_impl: the actual implementation of getsockopt:
|
---|
| 2879 | * same argument as lwip_getsockopt, either called directly or through callback
|
---|
| 2880 | */
|
---|
| 2881 | static int
|
---|
| 2882 | lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen)
|
---|
| 2883 | {
|
---|
| 2884 | int err = 0;
|
---|
| 2885 | struct lwip_sock *sock = tryget_socket(s);
|
---|
| 2886 | if (!sock) {
|
---|
| 2887 | return EBADF;
|
---|
| 2888 | }
|
---|
| 2889 |
|
---|
| 2890 | #ifdef LWIP_HOOK_SOCKETS_GETSOCKOPT
|
---|
| 2891 | if (LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) {
|
---|
| 2892 | return err;
|
---|
| 2893 | }
|
---|
| 2894 | #endif
|
---|
| 2895 |
|
---|
| 2896 | switch (level) {
|
---|
| 2897 |
|
---|
| 2898 | /* Level: SOL_SOCKET */
|
---|
| 2899 | case SOL_SOCKET:
|
---|
| 2900 | switch (optname) {
|
---|
| 2901 |
|
---|
| 2902 | #if LWIP_TCP
|
---|
| 2903 | case SO_ACCEPTCONN:
|
---|
| 2904 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
|
---|
| 2905 | if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) {
|
---|
| 2906 | done_socket(sock);
|
---|
| 2907 | return ENOPROTOOPT;
|
---|
| 2908 | }
|
---|
| 2909 | if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) {
|
---|
| 2910 | *(int *)optval = 1;
|
---|
| 2911 | } else {
|
---|
| 2912 | *(int *)optval = 0;
|
---|
| 2913 | }
|
---|
| 2914 | break;
|
---|
| 2915 | #endif /* LWIP_TCP */
|
---|
| 2916 |
|
---|
| 2917 | /* The option flags */
|
---|
| 2918 | case SO_BROADCAST:
|
---|
| 2919 | case SO_KEEPALIVE:
|
---|
| 2920 | #if SO_REUSE
|
---|
| 2921 | case SO_REUSEADDR:
|
---|
| 2922 | #endif /* SO_REUSE */
|
---|
| 2923 | if ((optname == SO_BROADCAST) &&
|
---|
| 2924 | (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) {
|
---|
| 2925 | done_socket(sock);
|
---|
| 2926 | return ENOPROTOOPT;
|
---|
| 2927 | }
|
---|
| 2928 |
|
---|
| 2929 | optname = lwip_sockopt_to_ipopt(optname);
|
---|
| 2930 |
|
---|
| 2931 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
|
---|
| 2932 | *(int *)optval = ip_get_option(sock->conn->pcb.ip, optname);
|
---|
| 2933 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
|
---|
| 2934 | s, optname, (*(int *)optval ? "on" : "off")));
|
---|
| 2935 | break;
|
---|
| 2936 |
|
---|
| 2937 | case SO_TYPE:
|
---|
| 2938 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
|
---|
| 2939 | switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) {
|
---|
| 2940 | case NETCONN_RAW:
|
---|
| 2941 | *(int *)optval = SOCK_RAW;
|
---|
| 2942 | break;
|
---|
| 2943 | case NETCONN_TCP:
|
---|
| 2944 | *(int *)optval = SOCK_STREAM;
|
---|
| 2945 | break;
|
---|
| 2946 | case NETCONN_UDP:
|
---|
| 2947 | *(int *)optval = SOCK_DGRAM;
|
---|
| 2948 | break;
|
---|
| 2949 | default: /* unrecognized socket type */
|
---|
| 2950 | *(int *)optval = netconn_type(sock->conn);
|
---|
| 2951 | LWIP_DEBUGF(SOCKETS_DEBUG,
|
---|
| 2952 | ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
|
---|
| 2953 | s, *(int *)optval));
|
---|
| 2954 | } /* switch (netconn_type(sock->conn)) */
|
---|
| 2955 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
|
---|
| 2956 | s, *(int *)optval));
|
---|
| 2957 | break;
|
---|
| 2958 |
|
---|
| 2959 | case SO_ERROR:
|
---|
| 2960 | LWIP_SOCKOPT_CHECK_OPTLEN(sock, *optlen, int);
|
---|
| 2961 | *(int *)optval = err_to_errno(netconn_err(sock->conn));
|
---|
| 2962 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
|
---|
| 2963 | s, *(int *)optval));
|
---|
| 2964 | break;
|
---|
| 2965 |
|
---|
| 2966 | #if LWIP_SO_SNDTIMEO
|
---|
| 2967 | case SO_SNDTIMEO:
|
---|
| 2968 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
|
---|
| 2969 | LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn));
|
---|
| 2970 | break;
|
---|
| 2971 | #endif /* LWIP_SO_SNDTIMEO */
|
---|
| 2972 | #if LWIP_SO_RCVTIMEO
|
---|
| 2973 | case SO_RCVTIMEO:
|
---|
| 2974 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
|
---|
| 2975 | LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn));
|
---|
| 2976 | break;
|
---|
| 2977 | #endif /* LWIP_SO_RCVTIMEO */
|
---|
| 2978 | #if LWIP_SO_RCVBUF
|
---|
| 2979 | case SO_RCVBUF:
|
---|
| 2980 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
|
---|
| 2981 | *(int *)optval = netconn_get_recvbufsize(sock->conn);
|
---|
| 2982 | break;
|
---|
| 2983 | #endif /* LWIP_SO_RCVBUF */
|
---|
| 2984 | #if LWIP_SO_LINGER
|
---|
| 2985 | case SO_LINGER: {
|
---|
| 2986 | s16_t conn_linger;
|
---|
| 2987 | struct linger *linger = (struct linger *)optval;
|
---|
| 2988 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger);
|
---|
| 2989 | conn_linger = sock->conn->linger;
|
---|
| 2990 | if (conn_linger >= 0) {
|
---|
| 2991 | linger->l_onoff = 1;
|
---|
| 2992 | linger->l_linger = (int)conn_linger;
|
---|
| 2993 | } else {
|
---|
| 2994 | linger->l_onoff = 0;
|
---|
| 2995 | linger->l_linger = 0;
|
---|
| 2996 | }
|
---|
| 2997 | }
|
---|
| 2998 | break;
|
---|
| 2999 | #endif /* LWIP_SO_LINGER */
|
---|
| 3000 | #if LWIP_UDP
|
---|
| 3001 | case SO_NO_CHECK:
|
---|
| 3002 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP);
|
---|
| 3003 | #if LWIP_UDPLITE
|
---|
| 3004 | if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) {
|
---|
| 3005 | /* this flag is only available for UDP, not for UDP lite */
|
---|
| 3006 | done_socket(sock);
|
---|
| 3007 | return EAFNOSUPPORT;
|
---|
| 3008 | }
|
---|
| 3009 | #endif /* LWIP_UDPLITE */
|
---|
| 3010 | *(int *)optval = udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM) ? 1 : 0;
|
---|
| 3011 | break;
|
---|
| 3012 | #endif /* LWIP_UDP*/
|
---|
| 3013 | default:
|
---|
| 3014 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
|
---|
| 3015 | s, optname));
|
---|
| 3016 | err = ENOPROTOOPT;
|
---|
| 3017 | break;
|
---|
| 3018 | } /* switch (optname) */
|
---|
| 3019 | break;
|
---|
| 3020 |
|
---|
| 3021 | /* Level: IPPROTO_IP */
|
---|
| 3022 | case IPPROTO_IP:
|
---|
| 3023 | switch (optname) {
|
---|
| 3024 | case IP_TTL:
|
---|
| 3025 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
|
---|
| 3026 | *(int *)optval = sock->conn->pcb.ip->ttl;
|
---|
| 3027 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
|
---|
| 3028 | s, *(int *)optval));
|
---|
| 3029 | break;
|
---|
| 3030 | case IP_TOS:
|
---|
| 3031 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
|
---|
| 3032 | *(int *)optval = sock->conn->pcb.ip->tos;
|
---|
| 3033 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
|
---|
| 3034 | s, *(int *)optval));
|
---|
| 3035 | break;
|
---|
| 3036 | #if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP
|
---|
| 3037 | case IP_MULTICAST_TTL:
|
---|
| 3038 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
|
---|
| 3039 | if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
|
---|
| 3040 | done_socket(sock);
|
---|
| 3041 | return ENOPROTOOPT;
|
---|
| 3042 | }
|
---|
| 3043 | *(u8_t *)optval = udp_get_multicast_ttl(sock->conn->pcb.udp);
|
---|
| 3044 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
|
---|
| 3045 | s, *(int *)optval));
|
---|
| 3046 | break;
|
---|
| 3047 | case IP_MULTICAST_IF:
|
---|
| 3048 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr);
|
---|
| 3049 | if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
|
---|
| 3050 | done_socket(sock);
|
---|
| 3051 | return ENOPROTOOPT;
|
---|
| 3052 | }
|
---|
| 3053 | inet_addr_from_ip4addr((struct in_addr *)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp));
|
---|
| 3054 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
|
---|
| 3055 | s, *(u32_t *)optval));
|
---|
| 3056 | break;
|
---|
| 3057 | case IP_MULTICAST_LOOP:
|
---|
| 3058 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
|
---|
| 3059 | if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
|
---|
| 3060 | *(u8_t *)optval = 1;
|
---|
| 3061 | } else {
|
---|
| 3062 | *(u8_t *)optval = 0;
|
---|
| 3063 | }
|
---|
| 3064 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
|
---|
| 3065 | s, *(int *)optval));
|
---|
| 3066 | break;
|
---|
| 3067 | #endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */
|
---|
| 3068 | default:
|
---|
| 3069 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
|
---|
| 3070 | s, optname));
|
---|
| 3071 | err = ENOPROTOOPT;
|
---|
| 3072 | break;
|
---|
| 3073 | } /* switch (optname) */
|
---|
| 3074 | break;
|
---|
| 3075 |
|
---|
| 3076 | #if LWIP_TCP
|
---|
| 3077 | /* Level: IPPROTO_TCP */
|
---|
| 3078 | case IPPROTO_TCP:
|
---|
| 3079 | /* Special case: all IPPROTO_TCP option take an int */
|
---|
| 3080 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP);
|
---|
| 3081 | if (sock->conn->pcb.tcp->state == LISTEN) {
|
---|
| 3082 | done_socket(sock);
|
---|
| 3083 | return EINVAL;
|
---|
| 3084 | }
|
---|
| 3085 | switch (optname) {
|
---|
| 3086 | case TCP_NODELAY:
|
---|
| 3087 | *(int *)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
|
---|
| 3088 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
|
---|
| 3089 | s, (*(int *)optval) ? "on" : "off") );
|
---|
| 3090 | break;
|
---|
| 3091 | case TCP_KEEPALIVE:
|
---|
| 3092 | *(int *)optval = (int)sock->conn->pcb.tcp->keep_idle;
|
---|
| 3093 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n",
|
---|
| 3094 | s, *(int *)optval));
|
---|
| 3095 | break;
|
---|
| 3096 |
|
---|
| 3097 | #if LWIP_TCP_KEEPALIVE
|
---|
| 3098 | case TCP_KEEPIDLE:
|
---|
| 3099 | *(int *)optval = (int)(sock->conn->pcb.tcp->keep_idle / 1000);
|
---|
| 3100 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n",
|
---|
| 3101 | s, *(int *)optval));
|
---|
| 3102 | break;
|
---|
| 3103 | case TCP_KEEPINTVL:
|
---|
| 3104 | *(int *)optval = (int)(sock->conn->pcb.tcp->keep_intvl / 1000);
|
---|
| 3105 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n",
|
---|
| 3106 | s, *(int *)optval));
|
---|
| 3107 | break;
|
---|
| 3108 | case TCP_KEEPCNT:
|
---|
| 3109 | *(int *)optval = (int)sock->conn->pcb.tcp->keep_cnt;
|
---|
| 3110 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n",
|
---|
| 3111 | s, *(int *)optval));
|
---|
| 3112 | break;
|
---|
| 3113 | #endif /* LWIP_TCP_KEEPALIVE */
|
---|
| 3114 | default:
|
---|
| 3115 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
|
---|
| 3116 | s, optname));
|
---|
| 3117 | err = ENOPROTOOPT;
|
---|
| 3118 | break;
|
---|
| 3119 | } /* switch (optname) */
|
---|
| 3120 | break;
|
---|
| 3121 | #endif /* LWIP_TCP */
|
---|
| 3122 |
|
---|
| 3123 | #if LWIP_IPV6
|
---|
| 3124 | /* Level: IPPROTO_IPV6 */
|
---|
| 3125 | case IPPROTO_IPV6:
|
---|
| 3126 | switch (optname) {
|
---|
| 3127 | case IPV6_V6ONLY:
|
---|
| 3128 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
|
---|
| 3129 | *(int *)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0);
|
---|
| 3130 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n",
|
---|
| 3131 | s, *(int *)optval));
|
---|
| 3132 | break;
|
---|
| 3133 | default:
|
---|
| 3134 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
|
---|
| 3135 | s, optname));
|
---|
| 3136 | err = ENOPROTOOPT;
|
---|
| 3137 | break;
|
---|
| 3138 | } /* switch (optname) */
|
---|
| 3139 | break;
|
---|
| 3140 | #endif /* LWIP_IPV6 */
|
---|
| 3141 |
|
---|
| 3142 | #if LWIP_UDP && LWIP_UDPLITE
|
---|
| 3143 | /* Level: IPPROTO_UDPLITE */
|
---|
| 3144 | case IPPROTO_UDPLITE:
|
---|
| 3145 | /* Special case: all IPPROTO_UDPLITE option take an int */
|
---|
| 3146 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
|
---|
| 3147 | /* If this is no UDP lite socket, ignore any options. */
|
---|
| 3148 | if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
|
---|
| 3149 | done_socket(sock);
|
---|
| 3150 | return ENOPROTOOPT;
|
---|
| 3151 | }
|
---|
| 3152 | switch (optname) {
|
---|
| 3153 | case UDPLITE_SEND_CSCOV:
|
---|
| 3154 | *(int *)optval = sock->conn->pcb.udp->chksum_len_tx;
|
---|
| 3155 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
|
---|
| 3156 | s, (*(int *)optval)) );
|
---|
| 3157 | break;
|
---|
| 3158 | case UDPLITE_RECV_CSCOV:
|
---|
| 3159 | *(int *)optval = sock->conn->pcb.udp->chksum_len_rx;
|
---|
| 3160 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
|
---|
| 3161 | s, (*(int *)optval)) );
|
---|
| 3162 | break;
|
---|
| 3163 | default:
|
---|
| 3164 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
|
---|
| 3165 | s, optname));
|
---|
| 3166 | err = ENOPROTOOPT;
|
---|
| 3167 | break;
|
---|
| 3168 | } /* switch (optname) */
|
---|
| 3169 | break;
|
---|
| 3170 | #endif /* LWIP_UDP */
|
---|
| 3171 | /* Level: IPPROTO_RAW */
|
---|
| 3172 | case IPPROTO_RAW:
|
---|
| 3173 | switch (optname) {
|
---|
| 3174 | #if LWIP_IPV6 && LWIP_RAW
|
---|
| 3175 | case IPV6_CHECKSUM:
|
---|
| 3176 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW);
|
---|
| 3177 | if (sock->conn->pcb.raw->chksum_reqd == 0) {
|
---|
| 3178 | *(int *)optval = -1;
|
---|
| 3179 | } else {
|
---|
| 3180 | *(int *)optval = sock->conn->pcb.raw->chksum_offset;
|
---|
| 3181 | }
|
---|
| 3182 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n",
|
---|
| 3183 | s, (*(int *)optval)) );
|
---|
| 3184 | break;
|
---|
| 3185 | #endif /* LWIP_IPV6 && LWIP_RAW */
|
---|
| 3186 | default:
|
---|
| 3187 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
|
---|
| 3188 | s, optname));
|
---|
| 3189 | err = ENOPROTOOPT;
|
---|
| 3190 | break;
|
---|
| 3191 | } /* switch (optname) */
|
---|
| 3192 | break;
|
---|
| 3193 | default:
|
---|
| 3194 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
|
---|
| 3195 | s, level, optname));
|
---|
| 3196 | err = ENOPROTOOPT;
|
---|
| 3197 | break;
|
---|
| 3198 | } /* switch (level) */
|
---|
| 3199 |
|
---|
| 3200 | done_socket(sock);
|
---|
| 3201 | return err;
|
---|
| 3202 | }
|
---|
| 3203 |
|
---|
| 3204 | int
|
---|
| 3205 | lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
|
---|
| 3206 | {
|
---|
| 3207 | int err = 0;
|
---|
| 3208 | struct lwip_sock *sock = get_socket(s);
|
---|
| 3209 | #if !LWIP_TCPIP_CORE_LOCKING
|
---|
| 3210 | err_t cberr;
|
---|
| 3211 | LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data);
|
---|
| 3212 | #endif /* !LWIP_TCPIP_CORE_LOCKING */
|
---|
| 3213 |
|
---|
| 3214 | if (!sock) {
|
---|
| 3215 | return -1;
|
---|
| 3216 | }
|
---|
| 3217 |
|
---|
| 3218 | if (NULL == optval) {
|
---|
| 3219 | sock_set_errno(sock, EFAULT);
|
---|
| 3220 | done_socket(sock);
|
---|
| 3221 | return -1;
|
---|
| 3222 | }
|
---|
| 3223 |
|
---|
| 3224 | #if LWIP_TCPIP_CORE_LOCKING
|
---|
| 3225 | /* core-locking can just call the -impl function */
|
---|
| 3226 | LOCK_TCPIP_CORE();
|
---|
| 3227 | err = lwip_setsockopt_impl(s, level, optname, optval, optlen);
|
---|
| 3228 | UNLOCK_TCPIP_CORE();
|
---|
| 3229 |
|
---|
| 3230 | #else /* LWIP_TCPIP_CORE_LOCKING */
|
---|
| 3231 |
|
---|
| 3232 | #if LWIP_MPU_COMPATIBLE
|
---|
| 3233 | /* MPU_COMPATIBLE copies the optval data, so check for max size here */
|
---|
| 3234 | if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) {
|
---|
| 3235 | sock_set_errno(sock, ENOBUFS);
|
---|
| 3236 | done_socket(sock);
|
---|
| 3237 | return -1;
|
---|
| 3238 | }
|
---|
| 3239 | #endif /* LWIP_MPU_COMPATIBLE */
|
---|
| 3240 |
|
---|
| 3241 | LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock);
|
---|
| 3242 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s;
|
---|
| 3243 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level;
|
---|
| 3244 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
|
---|
| 3245 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen;
|
---|
| 3246 | #if LWIP_MPU_COMPATIBLE
|
---|
| 3247 | MEMCPY(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen);
|
---|
| 3248 | #else /* LWIP_MPU_COMPATIBLE */
|
---|
| 3249 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void *)optval;
|
---|
| 3250 | #endif /* LWIP_MPU_COMPATIBLE */
|
---|
| 3251 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0;
|
---|
| 3252 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 3253 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
|
---|
| 3254 | #else
|
---|
| 3255 | LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
|
---|
| 3256 | #endif
|
---|
| 3257 | cberr = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
|
---|
| 3258 | if (cberr != ERR_OK) {
|
---|
| 3259 | LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
|
---|
| 3260 | sock_set_errno(sock, err_to_errno(cberr));
|
---|
| 3261 | done_socket(sock);
|
---|
| 3262 | return -1;
|
---|
| 3263 | }
|
---|
| 3264 | sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
|
---|
| 3265 |
|
---|
| 3266 | /* maybe lwip_getsockopt_internal has changed err */
|
---|
| 3267 | err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
|
---|
| 3268 | LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
|
---|
| 3269 | #endif /* LWIP_TCPIP_CORE_LOCKING */
|
---|
| 3270 |
|
---|
| 3271 | sock_set_errno(sock, err);
|
---|
| 3272 | done_socket(sock);
|
---|
| 3273 | return err ? -1 : 0;
|
---|
| 3274 | }
|
---|
| 3275 |
|
---|
| 3276 | #if !LWIP_TCPIP_CORE_LOCKING
|
---|
| 3277 | /** lwip_setsockopt_callback: only used without CORE_LOCKING
|
---|
| 3278 | * to get into the tcpip_thread
|
---|
| 3279 | */
|
---|
| 3280 | static void
|
---|
| 3281 | lwip_setsockopt_callback(void *arg)
|
---|
| 3282 | {
|
---|
| 3283 | struct lwip_setgetsockopt_data *data;
|
---|
| 3284 | LWIP_ASSERT("arg != NULL", arg != NULL);
|
---|
| 3285 | data = (struct lwip_setgetsockopt_data *)arg;
|
---|
| 3286 |
|
---|
| 3287 | data->err = lwip_setsockopt_impl(data->s, data->level, data->optname,
|
---|
| 3288 | #if LWIP_MPU_COMPATIBLE
|
---|
| 3289 | data->optval,
|
---|
| 3290 | #else /* LWIP_MPU_COMPATIBLE */
|
---|
| 3291 | data->optval.pc,
|
---|
| 3292 | #endif /* LWIP_MPU_COMPATIBLE */
|
---|
| 3293 | data->optlen);
|
---|
| 3294 |
|
---|
| 3295 | sys_sem_signal((sys_sem_t *)(data->completed_sem));
|
---|
| 3296 | }
|
---|
| 3297 | #endif /* LWIP_TCPIP_CORE_LOCKING */
|
---|
| 3298 |
|
---|
| 3299 | /** lwip_setsockopt_impl: the actual implementation of setsockopt:
|
---|
| 3300 | * same argument as lwip_setsockopt, either called directly or through callback
|
---|
| 3301 | */
|
---|
| 3302 | static int
|
---|
| 3303 | lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen)
|
---|
| 3304 | {
|
---|
| 3305 | int err = 0;
|
---|
| 3306 | struct lwip_sock *sock = tryget_socket(s);
|
---|
| 3307 | if (!sock) {
|
---|
| 3308 | return EBADF;
|
---|
| 3309 | }
|
---|
| 3310 |
|
---|
| 3311 | #ifdef LWIP_HOOK_SOCKETS_SETSOCKOPT
|
---|
| 3312 | if (LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) {
|
---|
| 3313 | return err;
|
---|
| 3314 | }
|
---|
| 3315 | #endif
|
---|
| 3316 |
|
---|
| 3317 | switch (level) {
|
---|
| 3318 |
|
---|
| 3319 | /* Level: SOL_SOCKET */
|
---|
| 3320 | case SOL_SOCKET:
|
---|
| 3321 | switch (optname) {
|
---|
| 3322 |
|
---|
| 3323 | /* SO_ACCEPTCONN is get-only */
|
---|
| 3324 |
|
---|
| 3325 | /* The option flags */
|
---|
| 3326 | case SO_BROADCAST:
|
---|
| 3327 | case SO_KEEPALIVE:
|
---|
| 3328 | #if SO_REUSE
|
---|
| 3329 | case SO_REUSEADDR:
|
---|
| 3330 | #endif /* SO_REUSE */
|
---|
| 3331 | if ((optname == SO_BROADCAST) &&
|
---|
| 3332 | (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) {
|
---|
| 3333 | done_socket(sock);
|
---|
| 3334 | return ENOPROTOOPT;
|
---|
| 3335 | }
|
---|
| 3336 |
|
---|
| 3337 | optname = lwip_sockopt_to_ipopt(optname);
|
---|
| 3338 |
|
---|
| 3339 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
|
---|
| 3340 | if (*(const int *)optval) {
|
---|
| 3341 | ip_set_option(sock->conn->pcb.ip, optname);
|
---|
| 3342 | } else {
|
---|
| 3343 | ip_reset_option(sock->conn->pcb.ip, optname);
|
---|
| 3344 | }
|
---|
| 3345 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
|
---|
| 3346 | s, optname, (*(const int *)optval ? "on" : "off")));
|
---|
| 3347 | break;
|
---|
| 3348 |
|
---|
| 3349 | /* SO_TYPE is get-only */
|
---|
| 3350 | /* SO_ERROR is get-only */
|
---|
| 3351 |
|
---|
| 3352 | #if LWIP_SO_SNDTIMEO
|
---|
| 3353 | case SO_SNDTIMEO: {
|
---|
| 3354 | long ms_long;
|
---|
| 3355 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
|
---|
| 3356 | ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval);
|
---|
| 3357 | if (ms_long < 0) {
|
---|
| 3358 | done_socket(sock);
|
---|
| 3359 | return EINVAL;
|
---|
| 3360 | }
|
---|
| 3361 | netconn_set_sendtimeout(sock->conn, ms_long);
|
---|
| 3362 | break;
|
---|
| 3363 | }
|
---|
| 3364 | #endif /* LWIP_SO_SNDTIMEO */
|
---|
| 3365 | #if LWIP_SO_RCVTIMEO
|
---|
| 3366 | case SO_RCVTIMEO: {
|
---|
| 3367 | long ms_long;
|
---|
| 3368 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
|
---|
| 3369 | ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval);
|
---|
| 3370 | if (ms_long < 0) {
|
---|
| 3371 | done_socket(sock);
|
---|
| 3372 | return EINVAL;
|
---|
| 3373 | }
|
---|
| 3374 | netconn_set_recvtimeout(sock->conn, (u32_t)ms_long);
|
---|
| 3375 | break;
|
---|
| 3376 | }
|
---|
| 3377 | #endif /* LWIP_SO_RCVTIMEO */
|
---|
| 3378 | #if LWIP_SO_RCVBUF
|
---|
| 3379 | case SO_RCVBUF:
|
---|
| 3380 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int);
|
---|
| 3381 | netconn_set_recvbufsize(sock->conn, *(const int *)optval);
|
---|
| 3382 | break;
|
---|
| 3383 | #endif /* LWIP_SO_RCVBUF */
|
---|
| 3384 | #if LWIP_SO_LINGER
|
---|
| 3385 | case SO_LINGER: {
|
---|
| 3386 | const struct linger *linger = (const struct linger *)optval;
|
---|
| 3387 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger);
|
---|
| 3388 | if (linger->l_onoff) {
|
---|
| 3389 | int lingersec = linger->l_linger;
|
---|
| 3390 | if (lingersec < 0) {
|
---|
| 3391 | done_socket(sock);
|
---|
| 3392 | return EINVAL;
|
---|
| 3393 | }
|
---|
| 3394 | if (lingersec > 0xFFFF) {
|
---|
| 3395 | lingersec = 0xFFFF;
|
---|
| 3396 | }
|
---|
| 3397 | sock->conn->linger = (s16_t)lingersec;
|
---|
| 3398 | } else {
|
---|
| 3399 | sock->conn->linger = -1;
|
---|
| 3400 | }
|
---|
| 3401 | }
|
---|
| 3402 | break;
|
---|
| 3403 | #endif /* LWIP_SO_LINGER */
|
---|
| 3404 | #if LWIP_UDP
|
---|
| 3405 | case SO_NO_CHECK:
|
---|
| 3406 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP);
|
---|
| 3407 | #if LWIP_UDPLITE
|
---|
| 3408 | if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) {
|
---|
| 3409 | /* this flag is only available for UDP, not for UDP lite */
|
---|
| 3410 | done_socket(sock);
|
---|
| 3411 | return EAFNOSUPPORT;
|
---|
| 3412 | }
|
---|
| 3413 | #endif /* LWIP_UDPLITE */
|
---|
| 3414 | if (*(const int *)optval) {
|
---|
| 3415 | udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
|
---|
| 3416 | } else {
|
---|
| 3417 | udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
|
---|
| 3418 | }
|
---|
| 3419 | break;
|
---|
| 3420 | #endif /* LWIP_UDP */
|
---|
| 3421 | case SO_BINDTODEVICE: {
|
---|
| 3422 | const struct ifreq *iface;
|
---|
| 3423 | struct netif *n = NULL;
|
---|
| 3424 |
|
---|
| 3425 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct ifreq);
|
---|
| 3426 |
|
---|
| 3427 | iface = (const struct ifreq *)optval;
|
---|
| 3428 | if (iface->ifr_name[0] != 0) {
|
---|
| 3429 | n = netif_find(iface->ifr_name);
|
---|
| 3430 | if (n == NULL) {
|
---|
| 3431 | done_socket(sock);
|
---|
| 3432 | return ENODEV;
|
---|
| 3433 | }
|
---|
| 3434 | }
|
---|
| 3435 |
|
---|
| 3436 | switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) {
|
---|
| 3437 | #if LWIP_TCP
|
---|
| 3438 | case NETCONN_TCP:
|
---|
| 3439 | tcp_bind_netif(sock->conn->pcb.tcp, n);
|
---|
| 3440 | break;
|
---|
| 3441 | #endif
|
---|
| 3442 | #if LWIP_UDP
|
---|
| 3443 | case NETCONN_UDP:
|
---|
| 3444 | udp_bind_netif(sock->conn->pcb.udp, n);
|
---|
| 3445 | break;
|
---|
| 3446 | #endif
|
---|
| 3447 | #if LWIP_RAW
|
---|
| 3448 | case NETCONN_RAW:
|
---|
| 3449 | raw_bind_netif(sock->conn->pcb.raw, n);
|
---|
| 3450 | break;
|
---|
| 3451 | #endif
|
---|
| 3452 | default:
|
---|
| 3453 | LWIP_ASSERT("Unhandled netconn type in SO_BINDTODEVICE", 0);
|
---|
| 3454 | break;
|
---|
| 3455 | }
|
---|
| 3456 | }
|
---|
| 3457 | break;
|
---|
| 3458 | default:
|
---|
| 3459 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
|
---|
| 3460 | s, optname));
|
---|
| 3461 | err = ENOPROTOOPT;
|
---|
| 3462 | break;
|
---|
| 3463 | } /* switch (optname) */
|
---|
| 3464 | break;
|
---|
| 3465 |
|
---|
| 3466 | /* Level: IPPROTO_IP */
|
---|
| 3467 | case IPPROTO_IP:
|
---|
| 3468 | switch (optname) {
|
---|
| 3469 | case IP_TTL:
|
---|
| 3470 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
|
---|
| 3471 | sock->conn->pcb.ip->ttl = (u8_t)(*(const int *)optval);
|
---|
| 3472 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
|
---|
| 3473 | s, sock->conn->pcb.ip->ttl));
|
---|
| 3474 | break;
|
---|
| 3475 | case IP_TOS:
|
---|
| 3476 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
|
---|
| 3477 | sock->conn->pcb.ip->tos = (u8_t)(*(const int *)optval);
|
---|
| 3478 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
|
---|
| 3479 | s, sock->conn->pcb.ip->tos));
|
---|
| 3480 | break;
|
---|
| 3481 | #if LWIP_NETBUF_RECVINFO
|
---|
| 3482 | case IP_PKTINFO:
|
---|
| 3483 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP);
|
---|
| 3484 | if (*(const int *)optval) {
|
---|
| 3485 | sock->conn->flags |= NETCONN_FLAG_PKTINFO;
|
---|
| 3486 | } else {
|
---|
| 3487 | sock->conn->flags &= ~NETCONN_FLAG_PKTINFO;
|
---|
| 3488 | }
|
---|
| 3489 | break;
|
---|
| 3490 | #endif /* LWIP_NETBUF_RECVINFO */
|
---|
| 3491 | #if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP
|
---|
| 3492 | case IP_MULTICAST_TTL:
|
---|
| 3493 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
|
---|
| 3494 | udp_set_multicast_ttl(sock->conn->pcb.udp, (u8_t)(*(const u8_t *)optval));
|
---|
| 3495 | break;
|
---|
| 3496 | case IP_MULTICAST_IF: {
|
---|
| 3497 | ip4_addr_t if_addr;
|
---|
| 3498 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP);
|
---|
| 3499 | inet_addr_to_ip4addr(&if_addr, (const struct in_addr *)optval);
|
---|
| 3500 | udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr);
|
---|
| 3501 | }
|
---|
| 3502 | break;
|
---|
| 3503 | case IP_MULTICAST_LOOP:
|
---|
| 3504 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
|
---|
| 3505 | if (*(const u8_t *)optval) {
|
---|
| 3506 | udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP);
|
---|
| 3507 | } else {
|
---|
| 3508 | udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP);
|
---|
| 3509 | }
|
---|
| 3510 | break;
|
---|
| 3511 | #endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */
|
---|
| 3512 | #if LWIP_IGMP
|
---|
| 3513 | case IP_ADD_MEMBERSHIP:
|
---|
| 3514 | case IP_DROP_MEMBERSHIP: {
|
---|
| 3515 | /* If this is a TCP or a RAW socket, ignore these options. */
|
---|
| 3516 | err_t igmp_err;
|
---|
| 3517 | const struct ip_mreq *imr = (const struct ip_mreq *)optval;
|
---|
| 3518 | ip4_addr_t if_addr;
|
---|
| 3519 | ip4_addr_t multi_addr;
|
---|
| 3520 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP);
|
---|
| 3521 | inet_addr_to_ip4addr(&if_addr, &imr->imr_interface);
|
---|
| 3522 | inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr);
|
---|
| 3523 | if (optname == IP_ADD_MEMBERSHIP) {
|
---|
| 3524 | if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) {
|
---|
| 3525 | /* cannot track membership (out of memory) */
|
---|
| 3526 | err = ENOMEM;
|
---|
| 3527 | igmp_err = ERR_OK;
|
---|
| 3528 | } else {
|
---|
| 3529 | igmp_err = igmp_joingroup(&if_addr, &multi_addr);
|
---|
| 3530 | }
|
---|
| 3531 | } else {
|
---|
| 3532 | igmp_err = igmp_leavegroup(&if_addr, &multi_addr);
|
---|
| 3533 | lwip_socket_unregister_membership(s, &if_addr, &multi_addr);
|
---|
| 3534 | }
|
---|
| 3535 | if (igmp_err != ERR_OK) {
|
---|
| 3536 | err = EADDRNOTAVAIL;
|
---|
| 3537 | }
|
---|
| 3538 | }
|
---|
| 3539 | break;
|
---|
| 3540 | #endif /* LWIP_IGMP */
|
---|
| 3541 | default:
|
---|
| 3542 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
|
---|
| 3543 | s, optname));
|
---|
| 3544 | err = ENOPROTOOPT;
|
---|
| 3545 | break;
|
---|
| 3546 | } /* switch (optname) */
|
---|
| 3547 | break;
|
---|
| 3548 |
|
---|
| 3549 | #if LWIP_TCP
|
---|
| 3550 | /* Level: IPPROTO_TCP */
|
---|
| 3551 | case IPPROTO_TCP:
|
---|
| 3552 | /* Special case: all IPPROTO_TCP option take an int */
|
---|
| 3553 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
|
---|
| 3554 | if (sock->conn->pcb.tcp->state == LISTEN) {
|
---|
| 3555 | done_socket(sock);
|
---|
| 3556 | return EINVAL;
|
---|
| 3557 | }
|
---|
| 3558 | switch (optname) {
|
---|
| 3559 | case TCP_NODELAY:
|
---|
| 3560 | if (*(const int *)optval) {
|
---|
| 3561 | tcp_nagle_disable(sock->conn->pcb.tcp);
|
---|
| 3562 | } else {
|
---|
| 3563 | tcp_nagle_enable(sock->conn->pcb.tcp);
|
---|
| 3564 | }
|
---|
| 3565 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
|
---|
| 3566 | s, (*(const int *)optval) ? "on" : "off") );
|
---|
| 3567 | break;
|
---|
| 3568 | case TCP_KEEPALIVE:
|
---|
| 3569 | sock->conn->pcb.tcp->keep_idle = (u32_t)(*(const int *)optval);
|
---|
| 3570 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
|
---|
| 3571 | s, sock->conn->pcb.tcp->keep_idle));
|
---|
| 3572 | break;
|
---|
| 3573 |
|
---|
| 3574 | #if LWIP_TCP_KEEPALIVE
|
---|
| 3575 | case TCP_KEEPIDLE:
|
---|
| 3576 | sock->conn->pcb.tcp->keep_idle = 1000 * (u32_t)(*(const int *)optval);
|
---|
| 3577 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
|
---|
| 3578 | s, sock->conn->pcb.tcp->keep_idle));
|
---|
| 3579 | break;
|
---|
| 3580 | case TCP_KEEPINTVL:
|
---|
| 3581 | sock->conn->pcb.tcp->keep_intvl = 1000 * (u32_t)(*(const int *)optval);
|
---|
| 3582 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
|
---|
| 3583 | s, sock->conn->pcb.tcp->keep_intvl));
|
---|
| 3584 | break;
|
---|
| 3585 | case TCP_KEEPCNT:
|
---|
| 3586 | sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int *)optval);
|
---|
| 3587 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
|
---|
| 3588 | s, sock->conn->pcb.tcp->keep_cnt));
|
---|
| 3589 | break;
|
---|
| 3590 | #endif /* LWIP_TCP_KEEPALIVE */
|
---|
| 3591 | default:
|
---|
| 3592 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
|
---|
| 3593 | s, optname));
|
---|
| 3594 | err = ENOPROTOOPT;
|
---|
| 3595 | break;
|
---|
| 3596 | } /* switch (optname) */
|
---|
| 3597 | break;
|
---|
| 3598 | #endif /* LWIP_TCP*/
|
---|
| 3599 |
|
---|
| 3600 | #if LWIP_IPV6
|
---|
| 3601 | /* Level: IPPROTO_IPV6 */
|
---|
| 3602 | case IPPROTO_IPV6:
|
---|
| 3603 | switch (optname) {
|
---|
| 3604 | case IPV6_V6ONLY:
|
---|
| 3605 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
|
---|
| 3606 | if (*(const int *)optval) {
|
---|
| 3607 | netconn_set_ipv6only(sock->conn, 1);
|
---|
| 3608 | } else {
|
---|
| 3609 | netconn_set_ipv6only(sock->conn, 0);
|
---|
| 3610 | }
|
---|
| 3611 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n",
|
---|
| 3612 | s, (netconn_get_ipv6only(sock->conn) ? 1 : 0)));
|
---|
| 3613 | break;
|
---|
| 3614 | #if LWIP_IPV6_MLD
|
---|
| 3615 | case IPV6_JOIN_GROUP:
|
---|
| 3616 | case IPV6_LEAVE_GROUP: {
|
---|
| 3617 | /* If this is a TCP or a RAW socket, ignore these options. */
|
---|
| 3618 | err_t mld6_err;
|
---|
| 3619 | struct netif *netif;
|
---|
| 3620 | ip6_addr_t multi_addr;
|
---|
| 3621 | const struct ipv6_mreq *imr = (const struct ipv6_mreq *)optval;
|
---|
| 3622 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ipv6_mreq, NETCONN_UDP);
|
---|
| 3623 | inet6_addr_to_ip6addr(&multi_addr, &imr->ipv6mr_multiaddr);
|
---|
| 3624 | LWIP_ASSERT("Invalid netif index", imr->ipv6mr_interface <= 0xFFu);
|
---|
| 3625 | netif = netif_get_by_index((u8_t)imr->ipv6mr_interface);
|
---|
| 3626 | if (netif == NULL) {
|
---|
| 3627 | err = EADDRNOTAVAIL;
|
---|
| 3628 | break;
|
---|
| 3629 | }
|
---|
| 3630 |
|
---|
| 3631 | if (optname == IPV6_JOIN_GROUP) {
|
---|
| 3632 | if (!lwip_socket_register_mld6_membership(s, imr->ipv6mr_interface, &multi_addr)) {
|
---|
| 3633 | /* cannot track membership (out of memory) */
|
---|
| 3634 | err = ENOMEM;
|
---|
| 3635 | mld6_err = ERR_OK;
|
---|
| 3636 | } else {
|
---|
| 3637 | mld6_err = mld6_joingroup_netif(netif, &multi_addr);
|
---|
| 3638 | }
|
---|
| 3639 | } else {
|
---|
| 3640 | mld6_err = mld6_leavegroup_netif(netif, &multi_addr);
|
---|
| 3641 | lwip_socket_unregister_mld6_membership(s, imr->ipv6mr_interface, &multi_addr);
|
---|
| 3642 | }
|
---|
| 3643 | if (mld6_err != ERR_OK) {
|
---|
| 3644 | err = EADDRNOTAVAIL;
|
---|
| 3645 | }
|
---|
| 3646 | }
|
---|
| 3647 | break;
|
---|
| 3648 | #endif /* LWIP_IPV6_MLD */
|
---|
| 3649 | default:
|
---|
| 3650 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
|
---|
| 3651 | s, optname));
|
---|
| 3652 | err = ENOPROTOOPT;
|
---|
| 3653 | break;
|
---|
| 3654 | } /* switch (optname) */
|
---|
| 3655 | break;
|
---|
| 3656 | #endif /* LWIP_IPV6 */
|
---|
| 3657 |
|
---|
| 3658 | #if LWIP_UDP && LWIP_UDPLITE
|
---|
| 3659 | /* Level: IPPROTO_UDPLITE */
|
---|
| 3660 | case IPPROTO_UDPLITE:
|
---|
| 3661 | /* Special case: all IPPROTO_UDPLITE option take an int */
|
---|
| 3662 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
|
---|
| 3663 | /* If this is no UDP lite socket, ignore any options. */
|
---|
| 3664 | if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
|
---|
| 3665 | done_socket(sock);
|
---|
| 3666 | return ENOPROTOOPT;
|
---|
| 3667 | }
|
---|
| 3668 | switch (optname) {
|
---|
| 3669 | case UDPLITE_SEND_CSCOV:
|
---|
| 3670 | if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) {
|
---|
| 3671 | /* don't allow illegal values! */
|
---|
| 3672 | sock->conn->pcb.udp->chksum_len_tx = 8;
|
---|
| 3673 | } else {
|
---|
| 3674 | sock->conn->pcb.udp->chksum_len_tx = (u16_t) * (const int *)optval;
|
---|
| 3675 | }
|
---|
| 3676 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
|
---|
| 3677 | s, (*(const int *)optval)) );
|
---|
| 3678 | break;
|
---|
| 3679 | case UDPLITE_RECV_CSCOV:
|
---|
| 3680 | if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) {
|
---|
| 3681 | /* don't allow illegal values! */
|
---|
| 3682 | sock->conn->pcb.udp->chksum_len_rx = 8;
|
---|
| 3683 | } else {
|
---|
| 3684 | sock->conn->pcb.udp->chksum_len_rx = (u16_t) * (const int *)optval;
|
---|
| 3685 | }
|
---|
| 3686 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
|
---|
| 3687 | s, (*(const int *)optval)) );
|
---|
| 3688 | break;
|
---|
| 3689 | default:
|
---|
| 3690 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
|
---|
| 3691 | s, optname));
|
---|
| 3692 | err = ENOPROTOOPT;
|
---|
| 3693 | break;
|
---|
| 3694 | } /* switch (optname) */
|
---|
| 3695 | break;
|
---|
| 3696 | #endif /* LWIP_UDP */
|
---|
| 3697 | /* Level: IPPROTO_RAW */
|
---|
| 3698 | case IPPROTO_RAW:
|
---|
| 3699 | switch (optname) {
|
---|
| 3700 | #if LWIP_IPV6 && LWIP_RAW
|
---|
| 3701 | case IPV6_CHECKSUM:
|
---|
| 3702 | /* It should not be possible to disable the checksum generation with ICMPv6
|
---|
| 3703 | * as per RFC 3542 chapter 3.1 */
|
---|
| 3704 | if (sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) {
|
---|
| 3705 | done_socket(sock);
|
---|
| 3706 | return EINVAL;
|
---|
| 3707 | }
|
---|
| 3708 |
|
---|
| 3709 | LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW);
|
---|
| 3710 | if (*(const int *)optval < 0) {
|
---|
| 3711 | sock->conn->pcb.raw->chksum_reqd = 0;
|
---|
| 3712 | } else if (*(const int *)optval & 1) {
|
---|
| 3713 | /* Per RFC3542, odd offsets are not allowed */
|
---|
| 3714 | done_socket(sock);
|
---|
| 3715 | return EINVAL;
|
---|
| 3716 | } else {
|
---|
| 3717 | sock->conn->pcb.raw->chksum_reqd = 1;
|
---|
| 3718 | sock->conn->pcb.raw->chksum_offset = (u16_t) * (const int *)optval;
|
---|
| 3719 | }
|
---|
| 3720 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n",
|
---|
| 3721 | s, sock->conn->pcb.raw->chksum_reqd));
|
---|
| 3722 | break;
|
---|
| 3723 | #endif /* LWIP_IPV6 && LWIP_RAW */
|
---|
| 3724 | default:
|
---|
| 3725 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
|
---|
| 3726 | s, optname));
|
---|
| 3727 | err = ENOPROTOOPT;
|
---|
| 3728 | break;
|
---|
| 3729 | } /* switch (optname) */
|
---|
| 3730 | break;
|
---|
| 3731 | default:
|
---|
| 3732 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
|
---|
| 3733 | s, level, optname));
|
---|
| 3734 | err = ENOPROTOOPT;
|
---|
| 3735 | break;
|
---|
| 3736 | } /* switch (level) */
|
---|
| 3737 |
|
---|
| 3738 | done_socket(sock);
|
---|
| 3739 | return err;
|
---|
| 3740 | }
|
---|
| 3741 |
|
---|
| 3742 | int
|
---|
| 3743 | lwip_ioctl(int s, long cmd, void *argp)
|
---|
| 3744 | {
|
---|
| 3745 | struct lwip_sock *sock = get_socket(s);
|
---|
| 3746 | u8_t val;
|
---|
| 3747 | #if LWIP_SO_RCVBUF
|
---|
| 3748 | int recv_avail;
|
---|
| 3749 | #endif /* LWIP_SO_RCVBUF */
|
---|
| 3750 |
|
---|
| 3751 | if (!sock) {
|
---|
| 3752 | return -1;
|
---|
| 3753 | }
|
---|
| 3754 |
|
---|
| 3755 | switch (cmd) {
|
---|
| 3756 | #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE
|
---|
| 3757 | case FIONREAD:
|
---|
| 3758 | if (!argp) {
|
---|
| 3759 | sock_set_errno(sock, EINVAL);
|
---|
| 3760 | done_socket(sock);
|
---|
| 3761 | return -1;
|
---|
| 3762 | }
|
---|
| 3763 | #if LWIP_FIONREAD_LINUXMODE
|
---|
| 3764 | if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
|
---|
| 3765 | struct netbuf *nb;
|
---|
| 3766 | if (sock->lastdata.netbuf) {
|
---|
| 3767 | nb = sock->lastdata.netbuf;
|
---|
| 3768 | *((int *)argp) = nb->p->tot_len;
|
---|
| 3769 | } else {
|
---|
| 3770 | struct netbuf *rxbuf;
|
---|
| 3771 | err_t err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &rxbuf, NETCONN_DONTBLOCK);
|
---|
| 3772 | if (err != ERR_OK) {
|
---|
| 3773 | *((int *)argp) = 0;
|
---|
| 3774 | } else {
|
---|
| 3775 | sock->lastdata.netbuf = rxbuf;
|
---|
| 3776 | *((int *)argp) = rxbuf->p->tot_len;
|
---|
| 3777 | }
|
---|
| 3778 | }
|
---|
| 3779 | done_socket(sock);
|
---|
| 3780 | return 0;
|
---|
| 3781 | }
|
---|
| 3782 | #endif /* LWIP_FIONREAD_LINUXMODE */
|
---|
| 3783 |
|
---|
| 3784 | #if LWIP_SO_RCVBUF
|
---|
| 3785 | /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */
|
---|
| 3786 | SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
|
---|
| 3787 | if (recv_avail < 0) {
|
---|
| 3788 | recv_avail = 0;
|
---|
| 3789 | }
|
---|
| 3790 |
|
---|
| 3791 | /* Check if there is data left from the last recv operation. /maq 041215 */
|
---|
| 3792 | if (sock->lastdata.netbuf) {
|
---|
| 3793 | if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
|
---|
| 3794 | recv_avail += sock->lastdata.pbuf->tot_len;
|
---|
| 3795 | } else {
|
---|
| 3796 | recv_avail += sock->lastdata.netbuf->p->tot_len;
|
---|
| 3797 | }
|
---|
| 3798 | }
|
---|
| 3799 | *((int *)argp) = recv_avail;
|
---|
| 3800 |
|
---|
| 3801 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t *)argp)));
|
---|
| 3802 | sock_set_errno(sock, 0);
|
---|
| 3803 | done_socket(sock);
|
---|
| 3804 | return 0;
|
---|
| 3805 | #else /* LWIP_SO_RCVBUF */
|
---|
| 3806 | break;
|
---|
| 3807 | #endif /* LWIP_SO_RCVBUF */
|
---|
| 3808 | #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */
|
---|
| 3809 |
|
---|
| 3810 | case (long)FIONBIO:
|
---|
| 3811 | val = 0;
|
---|
| 3812 | if (argp && *(int *)argp) {
|
---|
| 3813 | val = 1;
|
---|
| 3814 | }
|
---|
| 3815 | netconn_set_nonblocking(sock->conn, val);
|
---|
| 3816 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
|
---|
| 3817 | sock_set_errno(sock, 0);
|
---|
| 3818 | done_socket(sock);
|
---|
| 3819 | return 0;
|
---|
| 3820 |
|
---|
| 3821 | default:
|
---|
| 3822 | break;
|
---|
| 3823 | } /* switch (cmd) */
|
---|
| 3824 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
|
---|
| 3825 | sock_set_errno(sock, ENOSYS); /* not yet implemented */
|
---|
| 3826 | done_socket(sock);
|
---|
| 3827 | return -1;
|
---|
| 3828 | }
|
---|
| 3829 |
|
---|
| 3830 | /** A minimal implementation of fcntl.
|
---|
| 3831 | * Currently only the commands F_GETFL and F_SETFL are implemented.
|
---|
| 3832 | * The flag O_NONBLOCK and access modes are supported for F_GETFL, only
|
---|
| 3833 | * the flag O_NONBLOCK is implemented for F_SETFL.
|
---|
| 3834 | */
|
---|
| 3835 | int
|
---|
| 3836 | lwip_fcntl(int s, int cmd, int val)
|
---|
| 3837 | {
|
---|
| 3838 | struct lwip_sock *sock = get_socket(s);
|
---|
| 3839 | int ret = -1;
|
---|
| 3840 | int op_mode = 0;
|
---|
| 3841 |
|
---|
| 3842 | if (!sock) {
|
---|
| 3843 | return -1;
|
---|
| 3844 | }
|
---|
| 3845 |
|
---|
| 3846 | switch (cmd) {
|
---|
| 3847 | case F_GETFL:
|
---|
| 3848 | ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
|
---|
| 3849 | sock_set_errno(sock, 0);
|
---|
| 3850 |
|
---|
| 3851 | if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
|
---|
| 3852 | #if LWIP_TCPIP_CORE_LOCKING
|
---|
| 3853 | LOCK_TCPIP_CORE();
|
---|
| 3854 | #else
|
---|
| 3855 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 3856 | /* the proper thing to do here would be to get into the tcpip_thread,
|
---|
| 3857 | but locking should be OK as well since we only *read* some flags */
|
---|
| 3858 | SYS_ARCH_PROTECT(lev);
|
---|
| 3859 | #endif
|
---|
| 3860 | #if LWIP_TCP
|
---|
| 3861 | if (sock->conn->pcb.tcp) {
|
---|
| 3862 | if (!(sock->conn->pcb.tcp->flags & TF_RXCLOSED)) {
|
---|
| 3863 | op_mode |= O_RDONLY;
|
---|
| 3864 | }
|
---|
| 3865 | if (!(sock->conn->pcb.tcp->flags & TF_FIN)) {
|
---|
| 3866 | op_mode |= O_WRONLY;
|
---|
| 3867 | }
|
---|
| 3868 | }
|
---|
| 3869 | #endif
|
---|
| 3870 | #if LWIP_TCPIP_CORE_LOCKING
|
---|
| 3871 | UNLOCK_TCPIP_CORE();
|
---|
| 3872 | #else
|
---|
| 3873 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 3874 | #endif
|
---|
| 3875 | } else {
|
---|
| 3876 | op_mode |= O_RDWR;
|
---|
| 3877 | }
|
---|
| 3878 |
|
---|
| 3879 | /* ensure O_RDWR for (O_RDONLY|O_WRONLY) != O_RDWR cases */
|
---|
| 3880 | ret |= (op_mode == (O_RDONLY | O_WRONLY)) ? O_RDWR : op_mode;
|
---|
| 3881 |
|
---|
| 3882 | break;
|
---|
| 3883 | case F_SETFL:
|
---|
| 3884 | /* Bits corresponding to the file access mode and the file creation flags [..] that are set in arg shall be ignored */
|
---|
| 3885 | val &= ~(O_RDONLY | O_WRONLY | O_RDWR);
|
---|
| 3886 | if ((val & ~O_NONBLOCK) == 0) {
|
---|
| 3887 | /* only O_NONBLOCK, all other bits are zero */
|
---|
| 3888 | netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
|
---|
| 3889 | ret = 0;
|
---|
| 3890 | sock_set_errno(sock, 0);
|
---|
| 3891 | } else {
|
---|
| 3892 | sock_set_errno(sock, ENOSYS); /* not yet implemented */
|
---|
| 3893 | }
|
---|
| 3894 | break;
|
---|
| 3895 | default:
|
---|
| 3896 | LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
|
---|
| 3897 | sock_set_errno(sock, ENOSYS); /* not yet implemented */
|
---|
| 3898 | break;
|
---|
| 3899 | }
|
---|
| 3900 | done_socket(sock);
|
---|
| 3901 | return ret;
|
---|
| 3902 | }
|
---|
| 3903 |
|
---|
| 3904 | #if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES
|
---|
| 3905 | int
|
---|
| 3906 | fcntl(int s, int cmd, ...)
|
---|
| 3907 | {
|
---|
| 3908 | va_list ap;
|
---|
| 3909 | int val;
|
---|
| 3910 |
|
---|
| 3911 | va_start(ap, cmd);
|
---|
| 3912 | val = va_arg(ap, int);
|
---|
| 3913 | va_end(ap);
|
---|
| 3914 | return lwip_fcntl(s, cmd, val);
|
---|
| 3915 | }
|
---|
| 3916 | #endif
|
---|
| 3917 |
|
---|
| 3918 | const char *
|
---|
| 3919 | lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size)
|
---|
| 3920 | {
|
---|
| 3921 | const char *ret = NULL;
|
---|
| 3922 | int size_int = (int)size;
|
---|
| 3923 | if (size_int < 0) {
|
---|
| 3924 | set_errno(ENOSPC);
|
---|
| 3925 | return NULL;
|
---|
| 3926 | }
|
---|
| 3927 | switch (af) {
|
---|
| 3928 | #if LWIP_IPV4
|
---|
| 3929 | case AF_INET:
|
---|
| 3930 | ret = ip4addr_ntoa_r((const ip4_addr_t *)src, dst, size_int);
|
---|
| 3931 | if (ret == NULL) {
|
---|
| 3932 | set_errno(ENOSPC);
|
---|
| 3933 | }
|
---|
| 3934 | break;
|
---|
| 3935 | #endif
|
---|
| 3936 | #if LWIP_IPV6
|
---|
| 3937 | case AF_INET6:
|
---|
| 3938 | ret = ip6addr_ntoa_r((const ip6_addr_t *)src, dst, size_int);
|
---|
| 3939 | if (ret == NULL) {
|
---|
| 3940 | set_errno(ENOSPC);
|
---|
| 3941 | }
|
---|
| 3942 | break;
|
---|
| 3943 | #endif
|
---|
| 3944 | default:
|
---|
| 3945 | set_errno(EAFNOSUPPORT);
|
---|
| 3946 | break;
|
---|
| 3947 | }
|
---|
| 3948 | return ret;
|
---|
| 3949 | }
|
---|
| 3950 |
|
---|
| 3951 | int
|
---|
| 3952 | lwip_inet_pton(int af, const char *src, void *dst)
|
---|
| 3953 | {
|
---|
| 3954 | int err;
|
---|
| 3955 | switch (af) {
|
---|
| 3956 | #if LWIP_IPV4
|
---|
| 3957 | case AF_INET:
|
---|
| 3958 | err = ip4addr_aton(src, (ip4_addr_t *)dst);
|
---|
| 3959 | break;
|
---|
| 3960 | #endif
|
---|
| 3961 | #if LWIP_IPV6
|
---|
| 3962 | case AF_INET6: {
|
---|
| 3963 | /* convert into temporary variable since ip6_addr_t might be larger
|
---|
| 3964 | than in6_addr when scopes are enabled */
|
---|
| 3965 | ip6_addr_t addr;
|
---|
| 3966 | err = ip6addr_aton(src, &addr);
|
---|
| 3967 | if (err) {
|
---|
| 3968 | memcpy(dst, &addr.addr, sizeof(addr.addr));
|
---|
| 3969 | }
|
---|
| 3970 | break;
|
---|
| 3971 | }
|
---|
| 3972 | #endif
|
---|
| 3973 | default:
|
---|
| 3974 | err = -1;
|
---|
| 3975 | set_errno(EAFNOSUPPORT);
|
---|
| 3976 | break;
|
---|
| 3977 | }
|
---|
| 3978 | return err;
|
---|
| 3979 | }
|
---|
| 3980 |
|
---|
| 3981 | #if LWIP_IGMP
|
---|
| 3982 | /** Register a new IGMP membership. On socket close, the membership is dropped automatically.
|
---|
| 3983 | *
|
---|
| 3984 | * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
|
---|
| 3985 | *
|
---|
| 3986 | * @return 1 on success, 0 on failure
|
---|
| 3987 | */
|
---|
| 3988 | static int
|
---|
| 3989 | lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
|
---|
| 3990 | {
|
---|
| 3991 | struct lwip_sock *sock = get_socket(s);
|
---|
| 3992 | int i;
|
---|
| 3993 |
|
---|
| 3994 | if (!sock) {
|
---|
| 3995 | return 0;
|
---|
| 3996 | }
|
---|
| 3997 |
|
---|
| 3998 | for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
|
---|
| 3999 | if (socket_ipv4_multicast_memberships[i].sock == NULL) {
|
---|
| 4000 | socket_ipv4_multicast_memberships[i].sock = sock;
|
---|
| 4001 | ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr);
|
---|
| 4002 | ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr);
|
---|
| 4003 | done_socket(sock);
|
---|
| 4004 | return 1;
|
---|
| 4005 | }
|
---|
| 4006 | }
|
---|
| 4007 | done_socket(sock);
|
---|
| 4008 | return 0;
|
---|
| 4009 | }
|
---|
| 4010 |
|
---|
| 4011 | /** Unregister a previously registered membership. This prevents dropping the membership
|
---|
| 4012 | * on socket close.
|
---|
| 4013 | *
|
---|
| 4014 | * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
|
---|
| 4015 | */
|
---|
| 4016 | static void
|
---|
| 4017 | lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
|
---|
| 4018 | {
|
---|
| 4019 | struct lwip_sock *sock = get_socket(s);
|
---|
| 4020 | int i;
|
---|
| 4021 |
|
---|
| 4022 | if (!sock) {
|
---|
| 4023 | return;
|
---|
| 4024 | }
|
---|
| 4025 |
|
---|
| 4026 | for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
|
---|
| 4027 | if ((socket_ipv4_multicast_memberships[i].sock == sock) &&
|
---|
| 4028 | ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) &&
|
---|
| 4029 | ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) {
|
---|
| 4030 | socket_ipv4_multicast_memberships[i].sock = NULL;
|
---|
| 4031 | ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
|
---|
| 4032 | ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
|
---|
| 4033 | break;
|
---|
| 4034 | }
|
---|
| 4035 | }
|
---|
| 4036 | done_socket(sock);
|
---|
| 4037 | }
|
---|
| 4038 |
|
---|
| 4039 | /** Drop all memberships of a socket that were not dropped explicitly via setsockopt.
|
---|
| 4040 | *
|
---|
| 4041 | * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK).
|
---|
| 4042 | */
|
---|
| 4043 | static void
|
---|
| 4044 | lwip_socket_drop_registered_memberships(int s)
|
---|
| 4045 | {
|
---|
| 4046 | struct lwip_sock *sock = get_socket(s);
|
---|
| 4047 | int i;
|
---|
| 4048 |
|
---|
| 4049 | if (!sock) {
|
---|
| 4050 | return;
|
---|
| 4051 | }
|
---|
| 4052 |
|
---|
| 4053 | for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
|
---|
| 4054 | if (socket_ipv4_multicast_memberships[i].sock == sock) {
|
---|
| 4055 | ip_addr_t multi_addr, if_addr;
|
---|
| 4056 | ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr);
|
---|
| 4057 | ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr);
|
---|
| 4058 | socket_ipv4_multicast_memberships[i].sock = NULL;
|
---|
| 4059 | ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
|
---|
| 4060 | ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
|
---|
| 4061 |
|
---|
| 4062 | netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE);
|
---|
| 4063 | }
|
---|
| 4064 | }
|
---|
| 4065 | done_socket(sock);
|
---|
| 4066 | }
|
---|
| 4067 | #endif /* LWIP_IGMP */
|
---|
| 4068 |
|
---|
| 4069 | #if LWIP_IPV6_MLD
|
---|
| 4070 | /** Register a new MLD6 membership. On socket close, the membership is dropped automatically.
|
---|
| 4071 | *
|
---|
| 4072 | * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
|
---|
| 4073 | *
|
---|
| 4074 | * @return 1 on success, 0 on failure
|
---|
| 4075 | */
|
---|
| 4076 | static int
|
---|
| 4077 | lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr)
|
---|
| 4078 | {
|
---|
| 4079 | struct lwip_sock *sock = get_socket(s);
|
---|
| 4080 | int i;
|
---|
| 4081 |
|
---|
| 4082 | if (!sock) {
|
---|
| 4083 | return 0;
|
---|
| 4084 | }
|
---|
| 4085 |
|
---|
| 4086 | for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
|
---|
| 4087 | if (socket_ipv6_multicast_memberships[i].sock == NULL) {
|
---|
| 4088 | socket_ipv6_multicast_memberships[i].sock = sock;
|
---|
| 4089 | socket_ipv6_multicast_memberships[i].if_idx = (u8_t)if_idx;
|
---|
| 4090 | ip6_addr_copy(socket_ipv6_multicast_memberships[i].multi_addr, *multi_addr);
|
---|
| 4091 | done_socket(sock);
|
---|
| 4092 | return 1;
|
---|
| 4093 | }
|
---|
| 4094 | }
|
---|
| 4095 | done_socket(sock);
|
---|
| 4096 | return 0;
|
---|
| 4097 | }
|
---|
| 4098 |
|
---|
| 4099 | /** Unregister a previously registered MLD6 membership. This prevents dropping the membership
|
---|
| 4100 | * on socket close.
|
---|
| 4101 | *
|
---|
| 4102 | * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
|
---|
| 4103 | */
|
---|
| 4104 | static void
|
---|
| 4105 | lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr)
|
---|
| 4106 | {
|
---|
| 4107 | struct lwip_sock *sock = get_socket(s);
|
---|
| 4108 | int i;
|
---|
| 4109 |
|
---|
| 4110 | if (!sock) {
|
---|
| 4111 | return;
|
---|
| 4112 | }
|
---|
| 4113 |
|
---|
| 4114 | for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
|
---|
| 4115 | if ((socket_ipv6_multicast_memberships[i].sock == sock) &&
|
---|
| 4116 | (socket_ipv6_multicast_memberships[i].if_idx == if_idx) &&
|
---|
| 4117 | ip6_addr_cmp(&socket_ipv6_multicast_memberships[i].multi_addr, multi_addr)) {
|
---|
| 4118 | socket_ipv6_multicast_memberships[i].sock = NULL;
|
---|
| 4119 | socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX;
|
---|
| 4120 | ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr);
|
---|
| 4121 | break;
|
---|
| 4122 | }
|
---|
| 4123 | }
|
---|
| 4124 | done_socket(sock);
|
---|
| 4125 | }
|
---|
| 4126 |
|
---|
| 4127 | /** Drop all MLD6 memberships of a socket that were not dropped explicitly via setsockopt.
|
---|
| 4128 | *
|
---|
| 4129 | * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK).
|
---|
| 4130 | */
|
---|
| 4131 | static void
|
---|
| 4132 | lwip_socket_drop_registered_mld6_memberships(int s)
|
---|
| 4133 | {
|
---|
| 4134 | struct lwip_sock *sock = get_socket(s);
|
---|
| 4135 | int i;
|
---|
| 4136 |
|
---|
| 4137 | if (!sock) {
|
---|
| 4138 | return;
|
---|
| 4139 | }
|
---|
| 4140 |
|
---|
| 4141 | for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
|
---|
| 4142 | if (socket_ipv6_multicast_memberships[i].sock == sock) {
|
---|
| 4143 | ip_addr_t multi_addr;
|
---|
| 4144 | u8_t if_idx;
|
---|
| 4145 |
|
---|
| 4146 | ip_addr_copy_from_ip6(multi_addr, socket_ipv6_multicast_memberships[i].multi_addr);
|
---|
| 4147 | if_idx = socket_ipv6_multicast_memberships[i].if_idx;
|
---|
| 4148 |
|
---|
| 4149 | socket_ipv6_multicast_memberships[i].sock = NULL;
|
---|
| 4150 | socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX;
|
---|
| 4151 | ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr);
|
---|
| 4152 |
|
---|
| 4153 | netconn_join_leave_group_netif(sock->conn, &multi_addr, if_idx, NETCONN_LEAVE);
|
---|
| 4154 | }
|
---|
| 4155 | }
|
---|
| 4156 | done_socket(sock);
|
---|
| 4157 | }
|
---|
| 4158 | #endif /* LWIP_IPV6_MLD */
|
---|
| 4159 |
|
---|
| 4160 | #endif /* LWIP_SOCKET */
|
---|