1 /** 2 * @file 3 * Sockets BSD-Like API module 4 * 5 */ 6 7 /* 8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without modification, 12 * are permitted provided that the following conditions are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright notice, 15 * this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright notice, 17 * this list of conditions and the following disclaimer in the documentation 18 * and/or other materials provided with the distribution. 19 * 3. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 31 * OF SUCH DAMAGE. 32 * 33 * This file is part of the lwIP TCP/IP stack. 34 * 35 * Author: Adam Dunkels <adam@sics.se> 36 * 37 * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu> 38 * 39 */ 40 41 #include "lwip/opt.h" 42 43 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ 44 45 #include "lwip/sockets.h" 46 #include "lwip/api.h" 47 #include "lwip/sys.h" 48 #include "lwip/igmp.h" 49 #include "lwip/inet.h" 50 #include "lwip/tcp.h" 51 #include "lwip/raw.h" 52 #include "lwip/udp.h" 53 #include "lwip/tcpip.h" 54 #include "lwip/pbuf.h" 55 #if LWIP_CHECKSUM_ON_COPY 56 #include "lwip/inet_chksum.h" 57 #endif 58 59 #include <string.h> 60 61 #define NUM_SOCKETS MEMP_NUM_NETCONN 62 63 /** Contains all internal pointers and states used for a socket */ 64 struct lwip_sock { 65 /** sockets currently are built on netconns, each socket has one netconn */ 66 struct netconn *conn; 67 /** data that was left from the previous read */ 68 void *lastdata; 69 /** offset in the data that was left from the previous read */ 70 u16_t lastoffset; 71 /** number of times data was received, set by event_callback(), 72 tested by the receive and select functions */ 73 s16_t rcvevent; 74 /** number of times data was ACKed (free send buffer), set by event_callback(), 75 tested by select */ 76 u16_t sendevent; 77 /** error happened for this socket, set by event_callback(), tested by select */ 78 u16_t errevent; 79 /** last error that occurred on this socket */ 80 int err; 81 /** counter of how many threads are waiting for this socket using select */ 82 int select_waiting; 83 }; 84 85 /** Description for a task waiting in select */ 86 struct lwip_select_cb { 87 /** Pointer to the next waiting task */ 88 struct lwip_select_cb *next; 89 /** Pointer to the previous waiting task */ 90 struct lwip_select_cb *prev; 91 /** readset passed to select */ 92 fd_set *readset; 93 /** writeset passed to select */ 94 fd_set *writeset; 95 /** unimplemented: exceptset passed to select */ 96 fd_set *exceptset; 97 /** don't signal the same semaphore twice: set to 1 when signalled */ 98 int sem_signalled; 99 /** semaphore to wake up a task waiting for select */ 100 sys_sem_t sem; 101 }; 102 103 /** This struct is used to pass data to the set/getsockopt_internal 104 * functions running in tcpip_thread context (only a void* is allowed) */ 105 struct lwip_setgetsockopt_data { 106 /** socket struct for which to change options */ 107 struct lwip_sock *sock; 108 #ifdef LWIP_DEBUG 109 /** socket index for which to change options */ 110 int s; 111 #endif /* LWIP_DEBUG */ 112 /** level of the option to process */ 113 int level; 114 /** name of the option to process */ 115 int optname; 116 /** set: value to set the option to 117 * get: value of the option is stored here */ 118 void *optval; 119 /** size of *optval */ 120 socklen_t *optlen; 121 /** if an error occures, it is temporarily stored here */ 122 err_t err; 123 }; 124 125 /** The global array of available sockets */ 126 static struct lwip_sock sockets[NUM_SOCKETS]; 127 /** The global list of tasks waiting for select */ 128 static struct lwip_select_cb *select_cb_list; 129 /** This counter is increased from lwip_select when the list is chagned 130 and checked in event_callback to see if it has changed. */ 131 static volatile int select_cb_ctr; 132 133 /** Table to quickly map an lwIP error (err_t) to a socket error 134 * by using -err as an index */ 135 static const int err_to_errno_table[] = { 136 0, /* ERR_OK 0 No error, everything OK. */ 137 ENOMEM, /* ERR_MEM -1 Out of memory error. */ 138 ENOBUFS, /* ERR_BUF -2 Buffer error. */ 139 EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ 140 EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ 141 EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ 142 EINVAL, /* ERR_VAL -6 Illegal value. */ 143 EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ 144 EADDRINUSE, /* ERR_USE -8 Address in use. */ 145 EALREADY, /* ERR_ISCONN -9 Already connected. */ 146 ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */ 147 ECONNRESET, /* ERR_RST -11 Connection reset. */ 148 ENOTCONN, /* ERR_CLSD -12 Connection closed. */ 149 ENOTCONN, /* ERR_CONN -13 Not connected. */ 150 EIO, /* ERR_ARG -14 Illegal argument. */ 151 -1, /* ERR_IF -15 Low-level netif error */ 152 }; 153 154 #define ERR_TO_ERRNO_TABLE_SIZE \ 155 (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0])) 156 157 #define err_to_errno(err) \ 158 ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \ 159 err_to_errno_table[-(err)] : EIO) 160 161 #ifdef ERRNO 162 #ifndef set_errno 163 #define set_errno(err) errno = (err) 164 #endif 165 #else /* ERRNO */ 166 #define set_errno(err) 167 #endif /* ERRNO */ 168 169 #define sock_set_errno(sk, e) do { \ 170 sk->err = (e); \ 171 set_errno(sk->err); \ 172 } while (0) 173 174 /* Forward delcaration of some functions */ 175 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); 176 static void lwip_getsockopt_internal(void *arg); 177 static void lwip_setsockopt_internal(void *arg); 178 179 /** 180 * Initialize this module. This function has to be called before any other 181 * functions in this module! 182 */ 183 void 184 lwip_socket_init(void) 185 { 186 } 187 188 /** 189 * Map a externally used socket index to the internal socket representation. 190 * 191 * @param s externally used socket index 192 * @return struct lwip_sock for the socket or NULL if not found 193 */ 194 static struct lwip_sock * 195 get_socket(int s) 196 { 197 struct lwip_sock *sock; 198 199 if ((s < 0) || (s >= NUM_SOCKETS)) { 200 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s)); 201 set_errno(EBADF); 202 return NULL; 203 } 204 205 sock = &sockets[s]; 206 207 if (!sock->conn) { 208 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s)); 209 set_errno(EBADF); 210 return NULL; 211 } 212 213 return sock; 214 } 215 216 /** 217 * Same as get_socket but doesn't set errno 218 * 219 * @param s externally used socket index 220 * @return struct lwip_sock for the socket or NULL if not found 221 */ 222 static struct lwip_sock * 223 tryget_socket(int s) 224 { 225 if ((s < 0) || (s >= NUM_SOCKETS)) { 226 return NULL; 227 } 228 if (!sockets[s].conn) { 229 return NULL; 230 } 231 return &sockets[s]; 232 } 233 234 /** 235 * Allocate a new socket for a given netconn. 236 * 237 * @param newconn the netconn for which to allocate a socket 238 * @param accepted 1 if socket has been created by accept(), 239 * 0 if socket has been created by socket() 240 * @return the index of the new socket; -1 on error 241 */ 242 static int 243 alloc_socket(struct netconn *newconn, int accepted) 244 { 245 int i; 246 SYS_ARCH_DECL_PROTECT(lev); 247 248 /* allocate a new socket identifier */ 249 for (i = 0; i < NUM_SOCKETS; ++i) { 250 /* Protect socket array */ 251 SYS_ARCH_PROTECT(lev); 252 if (!sockets[i].conn) { 253 sockets[i].conn = newconn; 254 /* The socket is not yet known to anyone, so no need to protect 255 after having marked it as used. */ 256 SYS_ARCH_UNPROTECT(lev); 257 sockets[i].lastdata = NULL; 258 sockets[i].lastoffset = 0; 259 sockets[i].rcvevent = 0; 260 /* TCP sendbuf is empty, but the socket is not yet writable until connected 261 * (unless it has been created by accept()). */ 262 sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1); 263 sockets[i].errevent = 0; 264 sockets[i].err = 0; 265 sockets[i].select_waiting = 0; 266 return i; 267 } 268 SYS_ARCH_UNPROTECT(lev); 269 } 270 return -1; 271 } 272 273 /** Free a socket. The socket's netconn must have been 274 * delete before! 275 * 276 * @param sock the socket to free 277 * @param is_tcp != 0 for TCP sockets, used to free lastdata 278 */ 279 static void 280 free_socket(struct lwip_sock *sock, int is_tcp) 281 { 282 void *lastdata; 283 SYS_ARCH_DECL_PROTECT(lev); 284 285 lastdata = sock->lastdata; 286 sock->lastdata = NULL; 287 sock->lastoffset = 0; 288 sock->err = 0; 289 290 /* Protect socket array */ 291 SYS_ARCH_PROTECT(lev); 292 sock->conn = NULL; 293 SYS_ARCH_UNPROTECT(lev); 294 /* don't use 'sock' after this line, as another task might have allocated it */ 295 296 if (lastdata != NULL) { 297 if (is_tcp) { 298 pbuf_free((struct pbuf *)lastdata); 299 } else { 300 netbuf_delete((struct netbuf *)lastdata); 301 } 302 } 303 } 304 305 /* Below this, the well-known socket functions are implemented. 306 * Use google.com or opengroup.org to get a good description :-) 307 * 308 * Exceptions are documented! 309 */ 310 311 int 312 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) 313 { 314 struct lwip_sock *sock, *nsock; 315 struct netconn *newconn; 316 ip_addr_t naddr; 317 u16_t port; 318 int newsock; 319 struct sockaddr_in sin; 320 err_t err; 321 SYS_ARCH_DECL_PROTECT(lev); 322 323 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); 324 sock = get_socket(s); 325 if (!sock) { 326 return -1; 327 } 328 329 if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) { 330 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); 331 sock_set_errno(sock, EWOULDBLOCK); 332 return -1; 333 } 334 335 /* wait for a new connection */ 336 err = netconn_accept(sock->conn, &newconn); 337 if (err != ERR_OK) { 338 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); 339 if (netconn_type(sock->conn) != NETCONN_TCP) { 340 sock_set_errno(sock, EOPNOTSUPP); 341 return EOPNOTSUPP; 342 } 343 sock_set_errno(sock, err_to_errno(err)); 344 return -1; 345 } 346 LWIP_ASSERT("newconn != NULL", newconn != NULL); 347 /* Prevent automatic window updates, we do this on our own! */ 348 netconn_set_noautorecved(newconn, 1); 349 350 /* get the IP address and port of the remote host */ 351 err = netconn_peer(newconn, &naddr, &port); 352 if (err != ERR_OK) { 353 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); 354 netconn_delete(newconn); 355 sock_set_errno(sock, err_to_errno(err)); 356 return -1; 357 } 358 359 /* Note that POSIX only requires us to check addr is non-NULL. addrlen must 360 * not be NULL if addr is valid. 361 */ 362 if (NULL != addr) { 363 LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); 364 memset(&sin, 0, sizeof(sin)); 365 sin.sin_len = sizeof(sin); 366 sin.sin_family = AF_INET; 367 sin.sin_port = htons(port); 368 inet_addr_from_ipaddr(&sin.sin_addr, &naddr); 369 370 if (*addrlen > sizeof(sin)) 371 *addrlen = sizeof(sin); 372 373 MEMCPY(addr, &sin, *addrlen); 374 } 375 376 newsock = alloc_socket(newconn, 1); 377 if (newsock == -1) { 378 netconn_delete(newconn); 379 sock_set_errno(sock, ENFILE); 380 return -1; 381 } 382 LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS)); 383 LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback); 384 nsock = &sockets[newsock]; 385 386 /* See event_callback: If data comes in right away after an accept, even 387 * though the server task might not have created a new socket yet. 388 * In that case, newconn->socket is counted down (newconn->socket--), 389 * so nsock->rcvevent is >= 1 here! 390 */ 391 SYS_ARCH_PROTECT(lev); 392 nsock->rcvevent += (s16_t)(-1 - newconn->socket); 393 newconn->socket = newsock; 394 SYS_ARCH_UNPROTECT(lev); 395 396 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); 397 ip_addr_debug_print(SOCKETS_DEBUG, &naddr); 398 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); 399 400 sock_set_errno(sock, 0); 401 return newsock; 402 } 403 404 int 405 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) 406 { 407 struct lwip_sock *sock; 408 ip_addr_t local_addr; 409 u16_t local_port; 410 err_t err; 411 const struct sockaddr_in *name_in; 412 413 sock = get_socket(s); 414 if (!sock) { 415 return -1; 416 } 417 418 /* check size, familiy and alignment of 'name' */ 419 LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) && 420 ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)), 421 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 422 name_in = (const struct sockaddr_in *)(void*)name; 423 424 inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr); 425 local_port = name_in->sin_port; 426 427 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); 428 ip_addr_debug_print(SOCKETS_DEBUG, &local_addr); 429 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port))); 430 431 err = netconn_bind(sock->conn, &local_addr, ntohs(local_port)); 432 433 if (err != ERR_OK) { 434 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); 435 sock_set_errno(sock, err_to_errno(err)); 436 return -1; 437 } 438 439 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); 440 sock_set_errno(sock, 0); 441 return 0; 442 } 443 444 int 445 lwip_close(int s) 446 { 447 struct lwip_sock *sock; 448 int is_tcp = 0; 449 450 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); 451 452 sock = get_socket(s); 453 if (!sock) { 454 return -1; 455 } 456 457 if(sock->conn != NULL) { 458 is_tcp = netconn_type(sock->conn) == NETCONN_TCP; 459 } else { 460 LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL); 461 } 462 463 netconn_delete(sock->conn); 464 465 free_socket(sock, is_tcp); 466 set_errno(0); 467 return 0; 468 } 469 470 int 471 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) 472 { 473 struct lwip_sock *sock; 474 err_t err; 475 const struct sockaddr_in *name_in; 476 477 sock = get_socket(s); 478 if (!sock) { 479 return -1; 480 } 481 482 /* check size, familiy and alignment of 'name' */ 483 LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) && 484 ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)), 485 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 486 name_in = (const struct sockaddr_in *)(void*)name; 487 488 if (name_in->sin_family == AF_UNSPEC) { 489 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); 490 err = netconn_disconnect(sock->conn); 491 } else { 492 ip_addr_t remote_addr; 493 u16_t remote_port; 494 495 inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr); 496 remote_port = name_in->sin_port; 497 498 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); 499 ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); 500 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port))); 501 502 err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); 503 } 504 505 if (err != ERR_OK) { 506 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); 507 sock_set_errno(sock, err_to_errno(err)); 508 return -1; 509 } 510 511 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); 512 sock_set_errno(sock, 0); 513 return 0; 514 } 515 516 /** 517 * Set a socket into listen mode. 518 * The socket may not have been used for another connection previously. 519 * 520 * @param s the socket to set to listening mode 521 * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) 522 * @return 0 on success, non-zero on failure 523 */ 524 int 525 lwip_listen(int s, int backlog) 526 { 527 struct lwip_sock *sock; 528 err_t err; 529 530 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); 531 532 sock = get_socket(s); 533 if (!sock) { 534 return -1; 535 } 536 537 /* limit the "backlog" parameter to fit in an u8_t */ 538 backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); 539 540 err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); 541 542 if (err != ERR_OK) { 543 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); 544 if (netconn_type(sock->conn) != NETCONN_TCP) { 545 sock_set_errno(sock, EOPNOTSUPP); 546 return EOPNOTSUPP; 547 } 548 sock_set_errno(sock, err_to_errno(err)); 549 return -1; 550 } 551 552 sock_set_errno(sock, 0); 553 return 0; 554 } 555 556 int 557 lwip_recvfrom(int s, void *mem, size_t len, int flags, 558 struct sockaddr *from, socklen_t *fromlen) 559 { 560 struct lwip_sock *sock; 561 void *buf = NULL; 562 struct pbuf *p; 563 u16_t buflen, copylen; 564 int off = 0; 565 ip_addr_t *addr; 566 u16_t port; 567 u8_t done = 0; 568 err_t err; 569 570 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); 571 sock = get_socket(s); 572 if (!sock) { 573 return -1; 574 } 575 576 do { 577 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata)); 578 /* Check if there is data left from the last recv operation. */ 579 if (sock->lastdata) { 580 buf = sock->lastdata; 581 } else { 582 /* If this is non-blocking call, then check first */ 583 if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && 584 (sock->rcvevent <= 0)) { 585 if (off > 0) { 586 /* update receive window */ 587 netconn_recved(sock->conn, (u32_t)off); 588 /* already received data, return that */ 589 sock_set_errno(sock, 0); 590 return off; 591 } 592 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); 593 sock_set_errno(sock, EWOULDBLOCK); 594 return -1; 595 } 596 597 /* No data was left from the previous operation, so we try to get 598 some from the network. */ 599 if (netconn_type(sock->conn) == NETCONN_TCP) { 600 err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf); 601 } else { 602 err = netconn_recv(sock->conn, (struct netbuf **)&buf); 603 } 604 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n", 605 err, buf)); 606 607 if (err != ERR_OK) { 608 if (off > 0) { 609 /* update receive window */ 610 netconn_recved(sock->conn, (u32_t)off); 611 /* already received data, return that */ 612 sock_set_errno(sock, 0); 613 return off; 614 } 615 /* We should really do some error checking here. */ 616 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n", 617 s, lwip_strerr(err))); 618 sock_set_errno(sock, err_to_errno(err)); 619 if (err == ERR_CLSD) { 620 return 0; 621 } else { 622 return -1; 623 } 624 } 625 LWIP_ASSERT("buf != NULL", buf != NULL); 626 sock->lastdata = buf; 627 } 628 629 if (netconn_type(sock->conn) == NETCONN_TCP) { 630 p = (struct pbuf *)buf; 631 } else { 632 p = ((struct netbuf *)buf)->p; 633 } 634 buflen = p->tot_len; 635 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n", 636 buflen, len, off, sock->lastoffset)); 637 638 buflen -= sock->lastoffset; 639 640 if (len > buflen) { 641 copylen = buflen; 642 } else { 643 copylen = (u16_t)len; 644 } 645 646 /* copy the contents of the received buffer into 647 the supplied memory pointer mem */ 648 pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset); 649 650 off += copylen; 651 652 if (netconn_type(sock->conn) == NETCONN_TCP) { 653 LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen); 654 len -= copylen; 655 if ( (len <= 0) || 656 (p->flags & PBUF_FLAG_PUSH) || 657 (sock->rcvevent <= 0) || 658 ((flags & MSG_PEEK)!=0)) { 659 done = 1; 660 } 661 } else { 662 done = 1; 663 } 664 665 /* Check to see from where the data was.*/ 666 if (done) { 667 ip_addr_t fromaddr; 668 if (from && fromlen) { 669 struct sockaddr_in sin; 670 671 if (netconn_type(sock->conn) == NETCONN_TCP) { 672 addr = &fromaddr; 673 netconn_getaddr(sock->conn, addr, &port, 0); 674 } else { 675 addr = netbuf_fromaddr((struct netbuf *)buf); 676 port = netbuf_fromport((struct netbuf *)buf); 677 } 678 679 memset(&sin, 0, sizeof(sin)); 680 sin.sin_len = sizeof(sin); 681 sin.sin_family = AF_INET; 682 sin.sin_port = htons(port); 683 inet_addr_from_ipaddr(&sin.sin_addr, addr); 684 685 if (*fromlen > sizeof(sin)) { 686 *fromlen = sizeof(sin); 687 } 688 689 MEMCPY(from, &sin, *fromlen); 690 691 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); 692 ip_addr_debug_print(SOCKETS_DEBUG, addr); 693 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); 694 } else { 695 #if SOCKETS_DEBUG 696 if (netconn_type(sock->conn) == NETCONN_TCP) { 697 addr = &fromaddr; 698 netconn_getaddr(sock->conn, addr, &port, 0); 699 } else { 700 addr = netbuf_fromaddr((struct netbuf *)buf); 701 port = netbuf_fromport((struct netbuf *)buf); 702 } 703 704 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); 705 ip_addr_debug_print(SOCKETS_DEBUG, addr); 706 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); 707 #endif /* SOCKETS_DEBUG */ 708 } 709 } 710 711 /* If we don't peek the incoming message... */ 712 if ((flags & MSG_PEEK) == 0) { 713 /* If this is a TCP socket, check if there is data left in the 714 buffer. If so, it should be saved in the sock structure for next 715 time around. */ 716 if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) { 717 sock->lastdata = buf; 718 sock->lastoffset += copylen; 719 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf)); 720 } else { 721 sock->lastdata = NULL; 722 sock->lastoffset = 0; 723 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf)); 724 if (netconn_type(sock->conn) == NETCONN_TCP) { 725 pbuf_free((struct pbuf *)buf); 726 } else { 727 netbuf_delete((struct netbuf *)buf); 728 } 729 } 730 } 731 } while (!done); 732 733 if (off > 0) { 734 /* update receive window */ 735 netconn_recved(sock->conn, (u32_t)off); 736 } 737 sock_set_errno(sock, 0); 738 return off; 739 } 740 741 int 742 lwip_read(int s, void *mem, size_t len) 743 { 744 return lwip_recvfrom(s, mem, len, 0, NULL, NULL); 745 } 746 747 int 748 lwip_recv(int s, void *mem, size_t len, int flags) 749 { 750 return lwip_recvfrom(s, mem, len, flags, NULL, NULL); 751 } 752 753 int 754 lwip_send(int s, const void *data, size_t size, int flags) 755 { 756 struct lwip_sock *sock; 757 err_t err; 758 u8_t write_flags; 759 size_t written; 760 761 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", 762 s, data, size, flags)); 763 764 sock = get_socket(s); 765 if (!sock) { 766 return -1; 767 } 768 769 if (sock->conn->type != NETCONN_TCP) { 770 #if (LWIP_UDP || LWIP_RAW) 771 return lwip_sendto(s, data, size, flags, NULL, 0); 772 #else /* (LWIP_UDP || LWIP_RAW) */ 773 sock_set_errno(sock, err_to_errno(ERR_ARG)); 774 return -1; 775 #endif /* (LWIP_UDP || LWIP_RAW) */ 776 } 777 778 write_flags = NETCONN_COPY | 779 ((flags & MSG_MORE) ? NETCONN_MORE : 0) | 780 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); 781 written = 0; 782 err = netconn_write_partly(sock->conn, data, size, write_flags, &written); 783 784 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written)); 785 sock_set_errno(sock, err_to_errno(err)); 786 return (err == ERR_OK ? (int)written : -1); 787 } 788 789 int 790 lwip_sendto(int s, const void *data, size_t size, int flags, 791 const struct sockaddr *to, socklen_t tolen) 792 { 793 struct lwip_sock *sock; 794 err_t err; 795 u16_t short_size; 796 const struct sockaddr_in *to_in; 797 u16_t remote_port; 798 #if !LWIP_TCPIP_CORE_LOCKING 799 struct netbuf buf; 800 #endif 801 802 sock = get_socket(s); 803 if (!sock) { 804 return -1; 805 } 806 807 if (sock->conn->type == NETCONN_TCP) { 808 #if LWIP_TCP 809 return lwip_send(s, data, size, flags); 810 #else /* LWIP_TCP */ 811 LWIP_UNUSED_ARG(flags); 812 sock_set_errno(sock, err_to_errno(ERR_ARG)); 813 return -1; 814 #endif /* LWIP_TCP */ 815 } 816 817 /* @todo: split into multiple sendto's? */ 818 LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); 819 short_size = (u16_t)size; 820 LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || 821 ((tolen == sizeof(struct sockaddr_in)) && 822 ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))), 823 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 824 to_in = (const struct sockaddr_in *)(void*)to; 825 826 #if LWIP_TCPIP_CORE_LOCKING 827 /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */ 828 { 829 struct pbuf* p; 830 ip_addr_t *remote_addr; 831 832 #if LWIP_NETIF_TX_SINGLE_PBUF 833 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM); 834 if (p != NULL) { 835 #if LWIP_CHECKSUM_ON_COPY 836 u16_t chksum = 0; 837 if (sock->conn->type != NETCONN_RAW) { 838 chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size); 839 } else 840 #endif /* LWIP_CHECKSUM_ON_COPY */ 841 MEMCPY(p->payload, data, size); 842 #else /* LWIP_NETIF_TX_SINGLE_PBUF */ 843 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF); 844 if (p != NULL) { 845 p->payload = (void*)data; 846 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ 847 848 if (to_in != NULL) { 849 inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr); 850 remote_port = ntohs(to_in->sin_port); 851 } else { 852 remote_addr = &sock->conn->pcb.ip->remote_ip; 853 #if LWIP_UDP 854 if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_UDP) { 855 remote_port = sock->conn->pcb.udp->remote_port; 856 } else 857 #endif /* LWIP_UDP */ 858 { 859 remote_port = 0; 860 } 861 } 862 863 LOCK_TCPIP_CORE(); 864 if (netconn_type(sock->conn) == NETCONN_RAW) { 865 #if LWIP_RAW 866 err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr); 867 #else /* LWIP_RAW */ 868 err = ERR_ARG; 869 #endif /* LWIP_RAW */ 870 } 871 #if LWIP_UDP && LWIP_RAW 872 else 873 #endif /* LWIP_UDP && LWIP_RAW */ 874 { 875 #if LWIP_UDP 876 #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF 877 err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p, 878 remote_addr, remote_port, 1, chksum); 879 #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */ 880 err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p, 881 remote_addr, remote_port); 882 #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */ 883 #else /* LWIP_UDP */ 884 err = ERR_ARG; 885 #endif /* LWIP_UDP */ 886 } 887 UNLOCK_TCPIP_CORE(); 888 889 pbuf_free(p); 890 } else { 891 err = ERR_MEM; 892 } 893 } 894 #else /* LWIP_TCPIP_CORE_LOCKING */ 895 /* initialize a buffer */ 896 buf.p = buf.ptr = NULL; 897 #if LWIP_CHECKSUM_ON_COPY 898 buf.flags = 0; 899 #endif /* LWIP_CHECKSUM_ON_COPY */ 900 if (to) { 901 inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr); 902 remote_port = ntohs(to_in->sin_port); 903 netbuf_fromport(&buf) = remote_port; 904 } else { 905 remote_port = 0; 906 ip_addr_set_any(&buf.addr); 907 netbuf_fromport(&buf) = 0; 908 } 909 910 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", 911 s, data, short_size, flags)); 912 ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr); 913 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); 914 915 /* make the buffer point to the data that should be sent */ 916 #if LWIP_NETIF_TX_SINGLE_PBUF 917 /* Allocate a new netbuf and copy the data into it. */ 918 if (netbuf_alloc(&buf, short_size) == NULL) { 919 err = ERR_MEM; 920 } else { 921 #if LWIP_CHECKSUM_ON_COPY 922 if (sock->conn->type != NETCONN_RAW) { 923 u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); 924 netbuf_set_chksum(&buf, chksum); 925 err = ERR_OK; 926 } else 927 #endif /* LWIP_CHECKSUM_ON_COPY */ 928 { 929 err = netbuf_take(&buf, data, short_size); 930 } 931 } 932 #else /* LWIP_NETIF_TX_SINGLE_PBUF */ 933 err = netbuf_ref(&buf, data, short_size); 934 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ 935 if (err == ERR_OK) { 936 /* send the data */ 937 err = netconn_send(sock->conn, &buf); 938 } 939 940 /* deallocated the buffer */ 941 netbuf_free(&buf); 942 #endif /* LWIP_TCPIP_CORE_LOCKING */ 943 sock_set_errno(sock, err_to_errno(err)); 944 return (err == ERR_OK ? short_size : -1); 945 } 946 947 int 948 lwip_socket(int domain, int type, int protocol) 949 { 950 struct netconn *conn; 951 int i; 952 953 LWIP_UNUSED_ARG(domain); 954 955 /* create a netconn */ 956 switch (type) { 957 case SOCK_RAW: 958 conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback); 959 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", 960 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 961 break; 962 case SOCK_DGRAM: 963 conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ? 964 NETCONN_UDPLITE : NETCONN_UDP, event_callback); 965 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", 966 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 967 break; 968 case SOCK_STREAM: 969 conn = netconn_new_with_callback(NETCONN_TCP, event_callback); 970 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", 971 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 972 if (conn != NULL) { 973 /* Prevent automatic window updates, we do this on our own! */ 974 netconn_set_noautorecved(conn, 1); 975 } 976 break; 977 default: 978 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", 979 domain, type, protocol)); 980 set_errno(EINVAL); 981 return -1; 982 } 983 984 if (!conn) { 985 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); 986 set_errno(ENOBUFS); 987 return -1; 988 } 989 990 i = alloc_socket(conn, 0); 991 992 if (i == -1) { 993 netconn_delete(conn); 994 set_errno(ENFILE); 995 return -1; 996 } 997 conn->socket = i; 998 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); 999 set_errno(0); 1000 return i; 1001 } 1002 1003 int 1004 lwip_write(int s, const void *data, size_t size) 1005 { 1006 return lwip_send(s, data, size, 0); 1007 } 1008 1009 /** 1010 * Go through the readset and writeset lists and see which socket of the sockets 1011 * set in the sets has events. On return, readset, writeset and exceptset have 1012 * the sockets enabled that had events. 1013 * 1014 * exceptset is not used for now!!! 1015 * 1016 * @param maxfdp1 the highest socket index in the sets 1017 * @param readset_in: set of sockets to check for read events 1018 * @param writeset_in: set of sockets to check for write events 1019 * @param exceptset_in: set of sockets to check for error events 1020 * @param readset_out: set of sockets that had read events 1021 * @param writeset_out: set of sockets that had write events 1022 * @param exceptset_out: set os sockets that had error events 1023 * @return number of sockets that had events (read/write/exception) (>= 0) 1024 */ 1025 static int 1026 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, 1027 fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) 1028 { 1029 int i, nready = 0; 1030 fd_set lreadset, lwriteset, lexceptset; 1031 struct lwip_sock *sock; 1032 SYS_ARCH_DECL_PROTECT(lev); 1033 1034 FD_ZERO(&lreadset); 1035 FD_ZERO(&lwriteset); 1036 FD_ZERO(&lexceptset); 1037 1038 /* Go through each socket in each list to count number of sockets which 1039 currently match */ 1040 for(i = 0; i < maxfdp1; i++) { 1041 void* lastdata = NULL; 1042 s16_t rcvevent = 0; 1043 u16_t sendevent = 0; 1044 u16_t errevent = 0; 1045 /* First get the socket's status (protected)... */ 1046 SYS_ARCH_PROTECT(lev); 1047 sock = tryget_socket(i); 1048 if (sock != NULL) { 1049 lastdata = sock->lastdata; 1050 rcvevent = sock->rcvevent; 1051 sendevent = sock->sendevent; 1052 errevent = sock->errevent; 1053 } 1054 SYS_ARCH_UNPROTECT(lev); 1055 /* ... then examine it: */ 1056 /* See if netconn of this socket is ready for read */ 1057 if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { 1058 FD_SET(i, &lreadset); 1059 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); 1060 nready++; 1061 } 1062 /* See if netconn of this socket is ready for write */ 1063 if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { 1064 FD_SET(i, &lwriteset); 1065 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); 1066 nready++; 1067 } 1068 /* See if netconn of this socket had an error */ 1069 if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { 1070 FD_SET(i, &lexceptset); 1071 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); 1072 nready++; 1073 } 1074 } 1075 /* copy local sets to the ones provided as arguments */ 1076 *readset_out = lreadset; 1077 *writeset_out = lwriteset; 1078 *exceptset_out = lexceptset; 1079 1080 LWIP_ASSERT("nready >= 0", nready >= 0); 1081 return nready; 1082 } 1083 1084 /** 1085 * Processing exceptset is not yet implemented. 1086 */ 1087 int 1088 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, 1089 struct timeval *timeout) 1090 { 1091 u32_t waitres = 0; 1092 int nready; 1093 fd_set lreadset, lwriteset, lexceptset; 1094 u32_t msectimeout; 1095 struct lwip_select_cb select_cb; 1096 err_t err; 1097 int i; 1098 SYS_ARCH_DECL_PROTECT(lev); 1099 1100 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", 1101 maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, 1102 timeout ? (s32_t)timeout->tv_sec : (s32_t)-1, 1103 timeout ? (s32_t)timeout->tv_usec : (s32_t)-1)); 1104 1105 /* Go through each socket in each list to count number of sockets which 1106 currently match */ 1107 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 1108 1109 /* If we don't have any current events, then suspend if we are supposed to */ 1110 if (!nready) { 1111 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { 1112 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); 1113 /* This is OK as the local fdsets are empty and nready is zero, 1114 or we would have returned earlier. */ 1115 goto return_copy_fdsets; 1116 } 1117 1118 /* None ready: add our semaphore to list: 1119 We don't actually need any dynamic memory. Our entry on the 1120 list is only valid while we are in this function, so it's ok 1121 to use local variables. */ 1122 1123 select_cb.next = NULL; 1124 select_cb.prev = NULL; 1125 select_cb.readset = readset; 1126 select_cb.writeset = writeset; 1127 select_cb.exceptset = exceptset; 1128 select_cb.sem_signalled = 0; 1129 err = sys_sem_new(&select_cb.sem, 0); 1130 if (err != ERR_OK) { 1131 /* failed to create semaphore */ 1132 set_errno(ENOMEM); 1133 return -1; 1134 } 1135 1136 /* Protect the select_cb_list */ 1137 SYS_ARCH_PROTECT(lev); 1138 1139 /* Put this select_cb on top of list */ 1140 select_cb.next = select_cb_list; 1141 if (select_cb_list != NULL) { 1142 select_cb_list->prev = &select_cb; 1143 } 1144 select_cb_list = &select_cb; 1145 /* Increasing this counter tells even_callback that the list has changed. */ 1146 select_cb_ctr++; 1147 1148 /* Now we can safely unprotect */ 1149 SYS_ARCH_UNPROTECT(lev); 1150 1151 /* Increase select_waiting for each socket we are interested in */ 1152 for(i = 0; i < maxfdp1; i++) { 1153 if ((readset && FD_ISSET(i, readset)) || 1154 (writeset && FD_ISSET(i, writeset)) || 1155 (exceptset && FD_ISSET(i, exceptset))) { 1156 struct lwip_sock *sock = tryget_socket(i); 1157 LWIP_ASSERT("sock != NULL", sock != NULL); 1158 SYS_ARCH_PROTECT(lev); 1159 sock->select_waiting++; 1160 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); 1161 SYS_ARCH_UNPROTECT(lev); 1162 } 1163 } 1164 1165 /* Call lwip_selscan again: there could have been events between 1166 the last scan (whithout us on the list) and putting us on the list! */ 1167 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 1168 if (!nready) { 1169 /* Still none ready, just wait to be woken */ 1170 if (timeout == 0) { 1171 /* Wait forever */ 1172 msectimeout = 0; 1173 } else { 1174 msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); 1175 if (msectimeout == 0) { 1176 /* Wait 1ms at least (0 means wait forever) */ 1177 msectimeout = 1; 1178 } 1179 } 1180 1181 waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout); 1182 } 1183 /* Increase select_waiting for each socket we are interested in */ 1184 for(i = 0; i < maxfdp1; i++) { 1185 if ((readset && FD_ISSET(i, readset)) || 1186 (writeset && FD_ISSET(i, writeset)) || 1187 (exceptset && FD_ISSET(i, exceptset))) { 1188 struct lwip_sock *sock = tryget_socket(i); 1189 LWIP_ASSERT("sock != NULL", sock != NULL); 1190 SYS_ARCH_PROTECT(lev); 1191 sock->select_waiting--; 1192 LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0); 1193 SYS_ARCH_UNPROTECT(lev); 1194 } 1195 } 1196 /* Take us off the list */ 1197 SYS_ARCH_PROTECT(lev); 1198 if (select_cb.next != NULL) { 1199 select_cb.next->prev = select_cb.prev; 1200 } 1201 if (select_cb_list == &select_cb) { 1202 LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL); 1203 select_cb_list = select_cb.next; 1204 } else { 1205 LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL); 1206 select_cb.prev->next = select_cb.next; 1207 } 1208 /* Increasing this counter tells even_callback that the list has changed. */ 1209 select_cb_ctr++; 1210 SYS_ARCH_UNPROTECT(lev); 1211 1212 sys_sem_free(&select_cb.sem); 1213 if (waitres == SYS_ARCH_TIMEOUT) { 1214 /* Timeout */ 1215 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); 1216 /* This is OK as the local fdsets are empty and nready is zero, 1217 or we would have returned earlier. */ 1218 goto return_copy_fdsets; 1219 } 1220 1221 /* See what's set */ 1222 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 1223 } 1224 1225 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); 1226 return_copy_fdsets: 1227 set_errno(0); 1228 if (readset) { 1229 *readset = lreadset; 1230 } 1231 if (writeset) { 1232 *writeset = lwriteset; 1233 } 1234 if (exceptset) { 1235 *exceptset = lexceptset; 1236 } 1237 1238 1239 return nready; 1240 } 1241 1242 /** 1243 * Callback registered in the netconn layer for each socket-netconn. 1244 * Processes recvevent (data available) and wakes up tasks waiting for select. 1245 */ 1246 static void 1247 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) 1248 { 1249 int s; 1250 struct lwip_sock *sock; 1251 struct lwip_select_cb *scb; 1252 int last_select_cb_ctr; 1253 SYS_ARCH_DECL_PROTECT(lev); 1254 1255 LWIP_UNUSED_ARG(len); 1256 1257 /* Get socket */ 1258 if (conn) { 1259 s = conn->socket; 1260 if (s < 0) { 1261 /* Data comes in right away after an accept, even though 1262 * the server task might not have created a new socket yet. 1263 * Just count down (or up) if that's the case and we 1264 * will use the data later. Note that only receive events 1265 * can happen before the new socket is set up. */ 1266 SYS_ARCH_PROTECT(lev); 1267 if (conn->socket < 0) { 1268 if (evt == NETCONN_EVT_RCVPLUS) { 1269 conn->socket--; 1270 } 1271 SYS_ARCH_UNPROTECT(lev); 1272 return; 1273 } 1274 s = conn->socket; 1275 SYS_ARCH_UNPROTECT(lev); 1276 } 1277 1278 sock = get_socket(s); 1279 if (!sock) { 1280 return; 1281 } 1282 } else { 1283 return; 1284 } 1285 1286 SYS_ARCH_PROTECT(lev); 1287 /* Set event as required */ 1288 switch (evt) { 1289 case NETCONN_EVT_RCVPLUS: 1290 sock->rcvevent++; 1291 break; 1292 case NETCONN_EVT_RCVMINUS: 1293 sock->rcvevent--; 1294 break; 1295 case NETCONN_EVT_SENDPLUS: 1296 sock->sendevent = 1; 1297 break; 1298 case NETCONN_EVT_SENDMINUS: 1299 sock->sendevent = 0; 1300 break; 1301 case NETCONN_EVT_ERROR: 1302 sock->errevent = 1; 1303 break; 1304 default: 1305 LWIP_ASSERT("unknown event", 0); 1306 break; 1307 } 1308 1309 if (sock->select_waiting == 0) { 1310 /* noone is waiting for this socket, no need to check select_cb_list */ 1311 SYS_ARCH_UNPROTECT(lev); 1312 return; 1313 } 1314 1315 /* Now decide if anyone is waiting for this socket */ 1316 /* NOTE: This code goes through the select_cb_list list multiple times 1317 ONLY IF a select was actually waiting. We go through the list the number 1318 of waiting select calls + 1. This list is expected to be small. */ 1319 1320 /* At this point, SYS_ARCH is still protected! */ 1321 again: 1322 for (scb = select_cb_list; scb != NULL; scb = scb->next) { 1323 if (scb->sem_signalled == 0) { 1324 /* semaphore not signalled yet */ 1325 int do_signal = 0; 1326 /* Test this select call for our socket */ 1327 if (sock->rcvevent > 0) { 1328 if (scb->readset && FD_ISSET(s, scb->readset)) { 1329 do_signal = 1; 1330 } 1331 } 1332 if (sock->sendevent != 0) { 1333 if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { 1334 do_signal = 1; 1335 } 1336 } 1337 if (sock->errevent != 0) { 1338 if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { 1339 do_signal = 1; 1340 } 1341 } 1342 if (do_signal) { 1343 scb->sem_signalled = 1; 1344 /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might 1345 lead to the select thread taking itself off the list, invalidagin the semaphore. */ 1346 sys_sem_signal(&scb->sem); 1347 } 1348 } 1349 /* unlock interrupts with each step */ 1350 last_select_cb_ctr = select_cb_ctr; 1351 SYS_ARCH_UNPROTECT(lev); 1352 /* this makes sure interrupt protection time is short */ 1353 SYS_ARCH_PROTECT(lev); 1354 if (last_select_cb_ctr != select_cb_ctr) { 1355 /* someone has changed select_cb_list, restart at the beginning */ 1356 goto again; 1357 } 1358 } 1359 SYS_ARCH_UNPROTECT(lev); 1360 } 1361 1362 /** 1363 * Unimplemented: Close one end of a full-duplex connection. 1364 * Currently, the full connection is closed. 1365 */ 1366 int 1367 lwip_shutdown(int s, int how) 1368 { 1369 struct lwip_sock *sock; 1370 err_t err; 1371 u8_t shut_rx = 0, shut_tx = 0; 1372 1373 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); 1374 1375 sock = get_socket(s); 1376 if (!sock) { 1377 return -1; 1378 } 1379 1380 if (sock->conn != NULL) { 1381 if (netconn_type(sock->conn) != NETCONN_TCP) { 1382 sock_set_errno(sock, EOPNOTSUPP); 1383 return EOPNOTSUPP; 1384 } 1385 } else { 1386 sock_set_errno(sock, ENOTCONN); 1387 return ENOTCONN; 1388 } 1389 1390 if (how == SHUT_RD) { 1391 shut_rx = 1; 1392 } else if (how == SHUT_WR) { 1393 shut_tx = 1; 1394 } else if(how == SHUT_RDWR) { 1395 shut_rx = 1; 1396 shut_tx = 1; 1397 } else { 1398 sock_set_errno(sock, EINVAL); 1399 return EINVAL; 1400 } 1401 err = netconn_shutdown(sock->conn, shut_rx, shut_tx); 1402 1403 sock_set_errno(sock, err_to_errno(err)); 1404 return (err == ERR_OK ? 0 : -1); 1405 } 1406 1407 static int 1408 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) 1409 { 1410 struct lwip_sock *sock; 1411 struct sockaddr_in sin; 1412 ip_addr_t naddr; 1413 1414 sock = get_socket(s); 1415 if (!sock) { 1416 return -1; 1417 } 1418 1419 memset(&sin, 0, sizeof(sin)); 1420 sin.sin_len = sizeof(sin); 1421 sin.sin_family = AF_INET; 1422 1423 /* get the IP address and port */ 1424 netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local); 1425 1426 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); 1427 ip_addr_debug_print(SOCKETS_DEBUG, &naddr); 1428 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port)); 1429 1430 sin.sin_port = htons(sin.sin_port); 1431 inet_addr_from_ipaddr(&sin.sin_addr, &naddr); 1432 1433 if (*namelen > sizeof(sin)) { 1434 *namelen = sizeof(sin); 1435 } 1436 1437 MEMCPY(name, &sin, *namelen); 1438 sock_set_errno(sock, 0); 1439 return 0; 1440 } 1441 1442 int 1443 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) 1444 { 1445 return lwip_getaddrname(s, name, namelen, 0); 1446 } 1447 1448 int 1449 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) 1450 { 1451 return lwip_getaddrname(s, name, namelen, 1); 1452 } 1453 1454 int 1455 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) 1456 { 1457 err_t err = ERR_OK; 1458 struct lwip_sock *sock = get_socket(s); 1459 struct lwip_setgetsockopt_data data; 1460 1461 if (!sock) { 1462 return -1; 1463 } 1464 1465 if ((NULL == optval) || (NULL == optlen)) { 1466 sock_set_errno(sock, EFAULT); 1467 return -1; 1468 } 1469 1470 /* Do length and type checks for the various options first, to keep it readable. */ 1471 switch (level) { 1472 1473 /* Level: SOL_SOCKET */ 1474 case SOL_SOCKET: 1475 switch (optname) { 1476 1477 case SO_ACCEPTCONN: 1478 case SO_BROADCAST: 1479 /* UNIMPL case SO_DEBUG: */ 1480 /* UNIMPL case SO_DONTROUTE: */ 1481 case SO_ERROR: 1482 case SO_KEEPALIVE: 1483 /* UNIMPL case SO_CONTIMEO: */ 1484 #if LWIP_SO_SNDTIMEO 1485 case SO_SNDTIMEO: 1486 #endif /* LWIP_SO_SNDTIMEO */ 1487 #if LWIP_SO_RCVTIMEO 1488 case SO_RCVTIMEO: 1489 #endif /* LWIP_SO_RCVTIMEO */ 1490 #if LWIP_SO_RCVBUF 1491 case SO_RCVBUF: 1492 #endif /* LWIP_SO_RCVBUF */ 1493 /* UNIMPL case SO_OOBINLINE: */ 1494 /* UNIMPL case SO_SNDBUF: */ 1495 /* UNIMPL case SO_RCVLOWAT: */ 1496 /* UNIMPL case SO_SNDLOWAT: */ 1497 #if SO_REUSE 1498 case SO_REUSEADDR: 1499 case SO_REUSEPORT: 1500 #endif /* SO_REUSE */ 1501 case SO_TYPE: 1502 /* UNIMPL case SO_USELOOPBACK: */ 1503 if (*optlen < sizeof(int)) { 1504 err = EINVAL; 1505 } 1506 break; 1507 1508 case SO_NO_CHECK: 1509 if (*optlen < sizeof(int)) { 1510 err = EINVAL; 1511 } 1512 #if LWIP_UDP 1513 if ((sock->conn->type != NETCONN_UDP) || 1514 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { 1515 /* this flag is only available for UDP, not for UDP lite */ 1516 err = EAFNOSUPPORT; 1517 } 1518 #endif /* LWIP_UDP */ 1519 break; 1520 1521 default: 1522 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", 1523 s, optname)); 1524 err = ENOPROTOOPT; 1525 } /* switch (optname) */ 1526 break; 1527 1528 /* Level: IPPROTO_IP */ 1529 case IPPROTO_IP: 1530 switch (optname) { 1531 /* UNIMPL case IP_HDRINCL: */ 1532 /* UNIMPL case IP_RCVDSTADDR: */ 1533 /* UNIMPL case IP_RCVIF: */ 1534 case IP_TTL: 1535 case IP_TOS: 1536 if (*optlen < sizeof(int)) { 1537 err = EINVAL; 1538 } 1539 break; 1540 #if LWIP_IGMP 1541 case IP_MULTICAST_TTL: 1542 if (*optlen < sizeof(u8_t)) { 1543 err = EINVAL; 1544 } 1545 break; 1546 case IP_MULTICAST_IF: 1547 if (*optlen < sizeof(struct in_addr)) { 1548 err = EINVAL; 1549 } 1550 break; 1551 case IP_MULTICAST_LOOP: 1552 if (*optlen < sizeof(u8_t)) { 1553 err = EINVAL; 1554 } 1555 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { 1556 err = EAFNOSUPPORT; 1557 } 1558 break; 1559 #endif /* LWIP_IGMP */ 1560 1561 default: 1562 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", 1563 s, optname)); 1564 err = ENOPROTOOPT; 1565 } /* switch (optname) */ 1566 break; 1567 1568 #if LWIP_TCP 1569 /* Level: IPPROTO_TCP */ 1570 case IPPROTO_TCP: 1571 if (*optlen < sizeof(int)) { 1572 err = EINVAL; 1573 break; 1574 } 1575 1576 /* If this is no TCP socket, ignore any options. */ 1577 if (sock->conn->type != NETCONN_TCP) 1578 return 0; 1579 1580 switch (optname) { 1581 case TCP_NODELAY: 1582 case TCP_KEEPALIVE: 1583 #if LWIP_TCP_KEEPALIVE 1584 case TCP_KEEPIDLE: 1585 case TCP_KEEPINTVL: 1586 case TCP_KEEPCNT: 1587 #endif /* LWIP_TCP_KEEPALIVE */ 1588 break; 1589 1590 default: 1591 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", 1592 s, optname)); 1593 err = ENOPROTOOPT; 1594 } /* switch (optname) */ 1595 break; 1596 #endif /* LWIP_TCP */ 1597 #if LWIP_UDP && LWIP_UDPLITE 1598 /* Level: IPPROTO_UDPLITE */ 1599 case IPPROTO_UDPLITE: 1600 if (*optlen < sizeof(int)) { 1601 err = EINVAL; 1602 break; 1603 } 1604 1605 /* If this is no UDP lite socket, ignore any options. */ 1606 if (sock->conn->type != NETCONN_UDPLITE) { 1607 return 0; 1608 } 1609 1610 switch (optname) { 1611 case UDPLITE_SEND_CSCOV: 1612 case UDPLITE_RECV_CSCOV: 1613 break; 1614 1615 default: 1616 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", 1617 s, optname)); 1618 err = ENOPROTOOPT; 1619 } /* switch (optname) */ 1620 break; 1621 #endif /* LWIP_UDP && LWIP_UDPLITE*/ 1622 /* UNDEFINED LEVEL */ 1623 default: 1624 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", 1625 s, level, optname)); 1626 err = ENOPROTOOPT; 1627 } /* switch */ 1628 1629 1630 if (err != ERR_OK) { 1631 sock_set_errno(sock, err); 1632 return -1; 1633 } 1634 1635 /* Now do the actual option processing */ 1636 data.sock = sock; 1637 #ifdef LWIP_DEBUG 1638 data.s = s; 1639 #endif /* LWIP_DEBUG */ 1640 data.level = level; 1641 data.optname = optname; 1642 data.optval = optval; 1643 data.optlen = optlen; 1644 data.err = err; 1645 tcpip_callback(lwip_getsockopt_internal, &data); 1646 sys_arch_sem_wait(&sock->conn->op_completed, 0); 1647 /* maybe lwip_getsockopt_internal has changed err */ 1648 err = data.err; 1649 1650 sock_set_errno(sock, err); 1651 return err ? -1 : 0; 1652 } 1653 1654 static void 1655 lwip_getsockopt_internal(void *arg) 1656 { 1657 struct lwip_sock *sock; 1658 #ifdef LWIP_DEBUG 1659 int s; 1660 #endif /* LWIP_DEBUG */ 1661 int level, optname; 1662 void *optval; 1663 struct lwip_setgetsockopt_data *data; 1664 1665 LWIP_ASSERT("arg != NULL", arg != NULL); 1666 1667 data = (struct lwip_setgetsockopt_data*)arg; 1668 sock = data->sock; 1669 #ifdef LWIP_DEBUG 1670 s = data->s; 1671 #endif /* LWIP_DEBUG */ 1672 level = data->level; 1673 optname = data->optname; 1674 optval = data->optval; 1675 1676 switch (level) { 1677 1678 /* Level: SOL_SOCKET */ 1679 case SOL_SOCKET: 1680 switch (optname) { 1681 1682 /* The option flags */ 1683 case SO_ACCEPTCONN: 1684 case SO_BROADCAST: 1685 /* UNIMPL case SO_DEBUG: */ 1686 /* UNIMPL case SO_DONTROUTE: */ 1687 case SO_KEEPALIVE: 1688 /* UNIMPL case SO_OOBINCLUDE: */ 1689 #if SO_REUSE 1690 case SO_REUSEADDR: 1691 case SO_REUSEPORT: 1692 #endif /* SO_REUSE */ 1693 /*case SO_USELOOPBACK: UNIMPL */ 1694 *(int*)optval = ip_get_option(sock->conn->pcb.ip, optname); 1695 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", 1696 s, optname, (*(int*)optval?"on":"off"))); 1697 break; 1698 1699 case SO_TYPE: 1700 switch (NETCONNTYPE_GROUP(sock->conn->type)) { 1701 case NETCONN_RAW: 1702 *(int*)optval = SOCK_RAW; 1703 break; 1704 case NETCONN_TCP: 1705 *(int*)optval = SOCK_STREAM; 1706 break; 1707 case NETCONN_UDP: 1708 *(int*)optval = SOCK_DGRAM; 1709 break; 1710 default: /* unrecognized socket type */ 1711 *(int*)optval = sock->conn->type; 1712 LWIP_DEBUGF(SOCKETS_DEBUG, 1713 ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", 1714 s, *(int *)optval)); 1715 } /* switch (sock->conn->type) */ 1716 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", 1717 s, *(int *)optval)); 1718 break; 1719 1720 case SO_ERROR: 1721 /* only overwrite ERR_OK or tempoary errors */ 1722 if ((sock->err == 0) || (sock->err == EINPROGRESS)) { 1723 sock_set_errno(sock, err_to_errno(sock->conn->last_err)); 1724 } 1725 *(int *)optval = sock->err; 1726 sock->err = 0; 1727 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", 1728 s, *(int *)optval)); 1729 break; 1730 1731 #if LWIP_SO_SNDTIMEO 1732 case SO_SNDTIMEO: 1733 *(int *)optval = netconn_get_sendtimeout(sock->conn); 1734 break; 1735 #endif /* LWIP_SO_SNDTIMEO */ 1736 #if LWIP_SO_RCVTIMEO 1737 case SO_RCVTIMEO: 1738 *(int *)optval = netconn_get_recvtimeout(sock->conn); 1739 break; 1740 #endif /* LWIP_SO_RCVTIMEO */ 1741 #if LWIP_SO_RCVBUF 1742 case SO_RCVBUF: 1743 *(int *)optval = netconn_get_recvbufsize(sock->conn); 1744 break; 1745 #endif /* LWIP_SO_RCVBUF */ 1746 #if LWIP_UDP 1747 case SO_NO_CHECK: 1748 *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0; 1749 break; 1750 #endif /* LWIP_UDP*/ 1751 default: 1752 LWIP_ASSERT("unhandled optname", 0); 1753 break; 1754 } /* switch (optname) */ 1755 break; 1756 1757 /* Level: IPPROTO_IP */ 1758 case IPPROTO_IP: 1759 switch (optname) { 1760 case IP_TTL: 1761 *(int*)optval = sock->conn->pcb.ip->ttl; 1762 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", 1763 s, *(int *)optval)); 1764 break; 1765 case IP_TOS: 1766 *(int*)optval = sock->conn->pcb.ip->tos; 1767 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", 1768 s, *(int *)optval)); 1769 break; 1770 #if LWIP_IGMP 1771 case IP_MULTICAST_TTL: 1772 *(u8_t*)optval = sock->conn->pcb.ip->ttl; 1773 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", 1774 s, *(int *)optval)); 1775 break; 1776 case IP_MULTICAST_IF: 1777 inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip); 1778 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", 1779 s, *(u32_t *)optval)); 1780 break; 1781 case IP_MULTICAST_LOOP: 1782 if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { 1783 *(u8_t*)optval = 1; 1784 } else { 1785 *(u8_t*)optval = 0; 1786 } 1787 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", 1788 s, *(int *)optval)); 1789 break; 1790 #endif /* LWIP_IGMP */ 1791 default: 1792 LWIP_ASSERT("unhandled optname", 0); 1793 break; 1794 } /* switch (optname) */ 1795 break; 1796 1797 #if LWIP_TCP 1798 /* Level: IPPROTO_TCP */ 1799 case IPPROTO_TCP: 1800 switch (optname) { 1801 case TCP_NODELAY: 1802 *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp); 1803 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", 1804 s, (*(int*)optval)?"on":"off") ); 1805 break; 1806 case TCP_KEEPALIVE: 1807 *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle; 1808 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", 1809 s, *(int *)optval)); 1810 break; 1811 1812 #if LWIP_TCP_KEEPALIVE 1813 case TCP_KEEPIDLE: 1814 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000); 1815 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n", 1816 s, *(int *)optval)); 1817 break; 1818 case TCP_KEEPINTVL: 1819 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000); 1820 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n", 1821 s, *(int *)optval)); 1822 break; 1823 case TCP_KEEPCNT: 1824 *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt; 1825 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n", 1826 s, *(int *)optval)); 1827 break; 1828 #endif /* LWIP_TCP_KEEPALIVE */ 1829 default: 1830 LWIP_ASSERT("unhandled optname", 0); 1831 break; 1832 } /* switch (optname) */ 1833 break; 1834 #endif /* LWIP_TCP */ 1835 #if LWIP_UDP && LWIP_UDPLITE 1836 /* Level: IPPROTO_UDPLITE */ 1837 case IPPROTO_UDPLITE: 1838 switch (optname) { 1839 case UDPLITE_SEND_CSCOV: 1840 *(int*)optval = sock->conn->pcb.udp->chksum_len_tx; 1841 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", 1842 s, (*(int*)optval)) ); 1843 break; 1844 case UDPLITE_RECV_CSCOV: 1845 *(int*)optval = sock->conn->pcb.udp->chksum_len_rx; 1846 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", 1847 s, (*(int*)optval)) ); 1848 break; 1849 default: 1850 LWIP_ASSERT("unhandled optname", 0); 1851 break; 1852 } /* switch (optname) */ 1853 break; 1854 #endif /* LWIP_UDP */ 1855 default: 1856 LWIP_ASSERT("unhandled level", 0); 1857 break; 1858 } /* switch (level) */ 1859 sys_sem_signal(&sock->conn->op_completed); 1860 } 1861 1862 int 1863 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) 1864 { 1865 struct lwip_sock *sock = get_socket(s); 1866 err_t err = ERR_OK; 1867 struct lwip_setgetsockopt_data data; 1868 1869 if (!sock) { 1870 return -1; 1871 } 1872 1873 if (NULL == optval) { 1874 sock_set_errno(sock, EFAULT); 1875 return -1; 1876 } 1877 1878 /* Do length and type checks for the various options first, to keep it readable. */ 1879 switch (level) { 1880 1881 /* Level: SOL_SOCKET */ 1882 case SOL_SOCKET: 1883 switch (optname) { 1884 1885 case SO_BROADCAST: 1886 /* UNIMPL case SO_DEBUG: */ 1887 /* UNIMPL case SO_DONTROUTE: */ 1888 case SO_KEEPALIVE: 1889 /* UNIMPL case case SO_CONTIMEO: */ 1890 #if LWIP_SO_SNDTIMEO 1891 case SO_SNDTIMEO: 1892 #endif /* LWIP_SO_SNDTIMEO */ 1893 #if LWIP_SO_RCVTIMEO 1894 case SO_RCVTIMEO: 1895 #endif /* LWIP_SO_RCVTIMEO */ 1896 #if LWIP_SO_RCVBUF 1897 case SO_RCVBUF: 1898 #endif /* LWIP_SO_RCVBUF */ 1899 /* UNIMPL case SO_OOBINLINE: */ 1900 /* UNIMPL case SO_SNDBUF: */ 1901 /* UNIMPL case SO_RCVLOWAT: */ 1902 /* UNIMPL case SO_SNDLOWAT: */ 1903 #if SO_REUSE 1904 case SO_REUSEADDR: 1905 case SO_REUSEPORT: 1906 #endif /* SO_REUSE */ 1907 /* UNIMPL case SO_USELOOPBACK: */ 1908 if (optlen < sizeof(int)) { 1909 err = EINVAL; 1910 } 1911 break; 1912 case SO_NO_CHECK: 1913 if (optlen < sizeof(int)) { 1914 err = EINVAL; 1915 } 1916 #if LWIP_UDP 1917 if ((sock->conn->type != NETCONN_UDP) || 1918 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { 1919 /* this flag is only available for UDP, not for UDP lite */ 1920 err = EAFNOSUPPORT; 1921 } 1922 #endif /* LWIP_UDP */ 1923 break; 1924 default: 1925 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", 1926 s, optname)); 1927 err = ENOPROTOOPT; 1928 } /* switch (optname) */ 1929 break; 1930 1931 /* Level: IPPROTO_IP */ 1932 case IPPROTO_IP: 1933 switch (optname) { 1934 /* UNIMPL case IP_HDRINCL: */ 1935 /* UNIMPL case IP_RCVDSTADDR: */ 1936 /* UNIMPL case IP_RCVIF: */ 1937 case IP_TTL: 1938 case IP_TOS: 1939 if (optlen < sizeof(int)) { 1940 err = EINVAL; 1941 } 1942 break; 1943 #if LWIP_IGMP 1944 case IP_MULTICAST_TTL: 1945 if (optlen < sizeof(u8_t)) { 1946 err = EINVAL; 1947 } 1948 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { 1949 err = EAFNOSUPPORT; 1950 } 1951 break; 1952 case IP_MULTICAST_IF: 1953 if (optlen < sizeof(struct in_addr)) { 1954 err = EINVAL; 1955 } 1956 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { 1957 err = EAFNOSUPPORT; 1958 } 1959 break; 1960 case IP_MULTICAST_LOOP: 1961 if (optlen < sizeof(u8_t)) { 1962 err = EINVAL; 1963 } 1964 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { 1965 err = EAFNOSUPPORT; 1966 } 1967 break; 1968 case IP_ADD_MEMBERSHIP: 1969 case IP_DROP_MEMBERSHIP: 1970 if (optlen < sizeof(struct ip_mreq)) { 1971 err = EINVAL; 1972 } 1973 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { 1974 err = EAFNOSUPPORT; 1975 } 1976 break; 1977 #endif /* LWIP_IGMP */ 1978 default: 1979 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", 1980 s, optname)); 1981 err = ENOPROTOOPT; 1982 } /* switch (optname) */ 1983 break; 1984 1985 #if LWIP_TCP 1986 /* Level: IPPROTO_TCP */ 1987 case IPPROTO_TCP: 1988 if (optlen < sizeof(int)) { 1989 err = EINVAL; 1990 break; 1991 } 1992 1993 /* If this is no TCP socket, ignore any options. */ 1994 if (sock->conn->type != NETCONN_TCP) 1995 return 0; 1996 1997 switch (optname) { 1998 case TCP_NODELAY: 1999 case TCP_KEEPALIVE: 2000 #if LWIP_TCP_KEEPALIVE 2001 case TCP_KEEPIDLE: 2002 case TCP_KEEPINTVL: 2003 case TCP_KEEPCNT: 2004 #endif /* LWIP_TCP_KEEPALIVE */ 2005 break; 2006 2007 default: 2008 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", 2009 s, optname)); 2010 err = ENOPROTOOPT; 2011 } /* switch (optname) */ 2012 break; 2013 #endif /* LWIP_TCP */ 2014 #if LWIP_UDP && LWIP_UDPLITE 2015 /* Level: IPPROTO_UDPLITE */ 2016 case IPPROTO_UDPLITE: 2017 if (optlen < sizeof(int)) { 2018 err = EINVAL; 2019 break; 2020 } 2021 2022 /* If this is no UDP lite socket, ignore any options. */ 2023 if (sock->conn->type != NETCONN_UDPLITE) 2024 return 0; 2025 2026 switch (optname) { 2027 case UDPLITE_SEND_CSCOV: 2028 case UDPLITE_RECV_CSCOV: 2029 break; 2030 2031 default: 2032 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", 2033 s, optname)); 2034 err = ENOPROTOOPT; 2035 } /* switch (optname) */ 2036 break; 2037 #endif /* LWIP_UDP && LWIP_UDPLITE */ 2038 /* UNDEFINED LEVEL */ 2039 default: 2040 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", 2041 s, level, optname)); 2042 err = ENOPROTOOPT; 2043 } /* switch (level) */ 2044 2045 2046 if (err != ERR_OK) { 2047 sock_set_errno(sock, err); 2048 return -1; 2049 } 2050 2051 2052 /* Now do the actual option processing */ 2053 data.sock = sock; 2054 #ifdef LWIP_DEBUG 2055 data.s = s; 2056 #endif /* LWIP_DEBUG */ 2057 data.level = level; 2058 data.optname = optname; 2059 data.optval = (void*)optval; 2060 data.optlen = &optlen; 2061 data.err = err; 2062 tcpip_callback(lwip_setsockopt_internal, &data); 2063 sys_arch_sem_wait(&sock->conn->op_completed, 0); 2064 /* maybe lwip_setsockopt_internal has changed err */ 2065 err = data.err; 2066 2067 sock_set_errno(sock, err); 2068 return err ? -1 : 0; 2069 } 2070 2071 static void 2072 lwip_setsockopt_internal(void *arg) 2073 { 2074 struct lwip_sock *sock; 2075 #ifdef LWIP_DEBUG 2076 int s; 2077 #endif /* LWIP_DEBUG */ 2078 int level, optname; 2079 const void *optval; 2080 struct lwip_setgetsockopt_data *data; 2081 2082 LWIP_ASSERT("arg != NULL", arg != NULL); 2083 2084 data = (struct lwip_setgetsockopt_data*)arg; 2085 sock = data->sock; 2086 #ifdef LWIP_DEBUG 2087 s = data->s; 2088 #endif /* LWIP_DEBUG */ 2089 level = data->level; 2090 optname = data->optname; 2091 optval = data->optval; 2092 2093 switch (level) { 2094 2095 /* Level: SOL_SOCKET */ 2096 case SOL_SOCKET: 2097 switch (optname) { 2098 2099 /* The option flags */ 2100 case SO_BROADCAST: 2101 /* UNIMPL case SO_DEBUG: */ 2102 /* UNIMPL case SO_DONTROUTE: */ 2103 case SO_KEEPALIVE: 2104 /* UNIMPL case SO_OOBINCLUDE: */ 2105 #if SO_REUSE 2106 case SO_REUSEADDR: 2107 case SO_REUSEPORT: 2108 #endif /* SO_REUSE */ 2109 /* UNIMPL case SO_USELOOPBACK: */ 2110 if (*(int*)optval) { 2111 ip_set_option(sock->conn->pcb.ip, optname); 2112 } else { 2113 ip_reset_option(sock->conn->pcb.ip, optname); 2114 } 2115 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", 2116 s, optname, (*(int*)optval?"on":"off"))); 2117 break; 2118 #if LWIP_SO_SNDTIMEO 2119 case SO_SNDTIMEO: 2120 netconn_set_sendtimeout(sock->conn, (s32_t)*(int*)optval); 2121 break; 2122 #endif /* LWIP_SO_SNDTIMEO */ 2123 #if LWIP_SO_RCVTIMEO 2124 case SO_RCVTIMEO: 2125 netconn_set_recvtimeout(sock->conn, *(int*)optval); 2126 break; 2127 #endif /* LWIP_SO_RCVTIMEO */ 2128 #if LWIP_SO_RCVBUF 2129 case SO_RCVBUF: 2130 netconn_set_recvbufsize(sock->conn, *(int*)optval); 2131 break; 2132 #endif /* LWIP_SO_RCVBUF */ 2133 #if LWIP_UDP 2134 case SO_NO_CHECK: 2135 if (*(int*)optval) { 2136 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM); 2137 } else { 2138 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM); 2139 } 2140 break; 2141 #endif /* LWIP_UDP */ 2142 default: 2143 LWIP_ASSERT("unhandled optname", 0); 2144 break; 2145 } /* switch (optname) */ 2146 break; 2147 2148 /* Level: IPPROTO_IP */ 2149 case IPPROTO_IP: 2150 switch (optname) { 2151 case IP_TTL: 2152 sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval); 2153 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", 2154 s, sock->conn->pcb.ip->ttl)); 2155 break; 2156 case IP_TOS: 2157 sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval); 2158 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", 2159 s, sock->conn->pcb.ip->tos)); 2160 break; 2161 #if LWIP_IGMP 2162 case IP_MULTICAST_TTL: 2163 sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval); 2164 break; 2165 case IP_MULTICAST_IF: 2166 inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval); 2167 break; 2168 case IP_MULTICAST_LOOP: 2169 if (*(u8_t*)optval) { 2170 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP); 2171 } else { 2172 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP); 2173 } 2174 break; 2175 case IP_ADD_MEMBERSHIP: 2176 case IP_DROP_MEMBERSHIP: 2177 { 2178 /* If this is a TCP or a RAW socket, ignore these options. */ 2179 struct ip_mreq *imr = (struct ip_mreq *)optval; 2180 ip_addr_t if_addr; 2181 ip_addr_t multi_addr; 2182 inet_addr_to_ipaddr(&if_addr, &imr->imr_interface); 2183 inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr); 2184 if(optname == IP_ADD_MEMBERSHIP){ 2185 data->err = igmp_joingroup(&if_addr, &multi_addr); 2186 } else { 2187 data->err = igmp_leavegroup(&if_addr, &multi_addr); 2188 } 2189 if(data->err != ERR_OK) { 2190 data->err = EADDRNOTAVAIL; 2191 } 2192 } 2193 break; 2194 #endif /* LWIP_IGMP */ 2195 default: 2196 LWIP_ASSERT("unhandled optname", 0); 2197 break; 2198 } /* switch (optname) */ 2199 break; 2200 2201 #if LWIP_TCP 2202 /* Level: IPPROTO_TCP */ 2203 case IPPROTO_TCP: 2204 switch (optname) { 2205 case TCP_NODELAY: 2206 if (*(int*)optval) { 2207 tcp_nagle_disable(sock->conn->pcb.tcp); 2208 } else { 2209 tcp_nagle_enable(sock->conn->pcb.tcp); 2210 } 2211 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", 2212 s, (*(int *)optval)?"on":"off") ); 2213 break; 2214 case TCP_KEEPALIVE: 2215 sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval); 2216 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", 2217 s, sock->conn->pcb.tcp->keep_idle)); 2218 break; 2219 2220 #if LWIP_TCP_KEEPALIVE 2221 case TCP_KEEPIDLE: 2222 sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval); 2223 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", 2224 s, sock->conn->pcb.tcp->keep_idle)); 2225 break; 2226 case TCP_KEEPINTVL: 2227 sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval); 2228 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", 2229 s, sock->conn->pcb.tcp->keep_intvl)); 2230 break; 2231 case TCP_KEEPCNT: 2232 sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval); 2233 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", 2234 s, sock->conn->pcb.tcp->keep_cnt)); 2235 break; 2236 #endif /* LWIP_TCP_KEEPALIVE */ 2237 default: 2238 LWIP_ASSERT("unhandled optname", 0); 2239 break; 2240 } /* switch (optname) */ 2241 break; 2242 #endif /* LWIP_TCP*/ 2243 #if LWIP_UDP && LWIP_UDPLITE 2244 /* Level: IPPROTO_UDPLITE */ 2245 case IPPROTO_UDPLITE: 2246 switch (optname) { 2247 case UDPLITE_SEND_CSCOV: 2248 if ((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) { 2249 /* don't allow illegal values! */ 2250 sock->conn->pcb.udp->chksum_len_tx = 8; 2251 } else { 2252 sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval; 2253 } 2254 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", 2255 s, (*(int*)optval)) ); 2256 break; 2257 case UDPLITE_RECV_CSCOV: 2258 if ((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) { 2259 /* don't allow illegal values! */ 2260 sock->conn->pcb.udp->chksum_len_rx = 8; 2261 } else { 2262 sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval; 2263 } 2264 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", 2265 s, (*(int*)optval)) ); 2266 break; 2267 default: 2268 LWIP_ASSERT("unhandled optname", 0); 2269 break; 2270 } /* switch (optname) */ 2271 break; 2272 #endif /* LWIP_UDP */ 2273 default: 2274 LWIP_ASSERT("unhandled level", 0); 2275 break; 2276 } /* switch (level) */ 2277 sys_sem_signal(&sock->conn->op_completed); 2278 } 2279 2280 int 2281 lwip_ioctl(int s, long cmd, void *argp) 2282 { 2283 struct lwip_sock *sock = get_socket(s); 2284 u8_t val; 2285 #if LWIP_SO_RCVBUF 2286 u16_t buflen = 0; 2287 s16_t recv_avail; 2288 #endif /* LWIP_SO_RCVBUF */ 2289 2290 if (!sock) { 2291 return -1; 2292 } 2293 2294 switch (cmd) { 2295 #if LWIP_SO_RCVBUF 2296 case FIONREAD: 2297 if (!argp) { 2298 sock_set_errno(sock, EINVAL); 2299 return -1; 2300 } 2301 2302 SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); 2303 if (recv_avail < 0) { 2304 recv_avail = 0; 2305 } 2306 *((u16_t*)argp) = (u16_t)recv_avail; 2307 2308 /* Check if there is data left from the last recv operation. /maq 041215 */ 2309 if (sock->lastdata) { 2310 struct pbuf *p = (struct pbuf *)sock->lastdata; 2311 if (netconn_type(sock->conn) != NETCONN_TCP) { 2312 p = ((struct netbuf *)p)->p; 2313 } 2314 buflen = p->tot_len; 2315 buflen -= sock->lastoffset; 2316 2317 *((u16_t*)argp) += buflen; 2318 } 2319 2320 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp))); 2321 sock_set_errno(sock, 0); 2322 return 0; 2323 #endif /* LWIP_SO_RCVBUF */ 2324 2325 case FIONBIO: 2326 val = 0; 2327 if (argp && *(u32_t*)argp) { 2328 val = 1; 2329 } 2330 netconn_set_nonblocking(sock->conn, val); 2331 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); 2332 sock_set_errno(sock, 0); 2333 return 0; 2334 2335 default: 2336 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); 2337 sock_set_errno(sock, ENOSYS); /* not yet implemented */ 2338 return -1; 2339 } /* switch (cmd) */ 2340 } 2341 2342 /** A minimal implementation of fcntl. 2343 * Currently only the commands F_GETFL and F_SETFL are implemented. 2344 * Only the flag O_NONBLOCK is implemented. 2345 */ 2346 int 2347 lwip_fcntl(int s, int cmd, int val) 2348 { 2349 struct lwip_sock *sock = get_socket(s); 2350 int ret = -1; 2351 2352 if (!sock || !sock->conn) { 2353 return -1; 2354 } 2355 2356 switch (cmd) { 2357 case F_GETFL: 2358 ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; 2359 break; 2360 case F_SETFL: 2361 if ((val & ~O_NONBLOCK) == 0) { 2362 /* only O_NONBLOCK, all other bits are zero */ 2363 netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); 2364 ret = 0; 2365 } 2366 break; 2367 default: 2368 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); 2369 break; 2370 } 2371 return ret; 2372 } 2373 2374 #endif /* LWIP_SOCKET */ 2375