Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of lwip by
sockets.c
00001 /** 00002 * @file 00003 * Sockets BSD-Like API module 00004 * 00005 */ 00006 00007 /* 00008 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 00009 * All rights reserved. 00010 * 00011 * Redistribution and use in source and binary forms, with or without modification, 00012 * are permitted provided that the following conditions are met: 00013 * 00014 * 1. Redistributions of source code must retain the above copyright notice, 00015 * this list of conditions and the following disclaimer. 00016 * 2. Redistributions in binary form must reproduce the above copyright notice, 00017 * this list of conditions and the following disclaimer in the documentation 00018 * and/or other materials provided with the distribution. 00019 * 3. The name of the author may not be used to endorse or promote products 00020 * derived from this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00023 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00025 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00026 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00027 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00028 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00029 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00030 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00031 * OF SUCH DAMAGE. 00032 * 00033 * This file is part of the lwIP TCP/IP stack. 00034 * 00035 * Author: Adam Dunkels <adam@sics.se> 00036 * 00037 * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu> 00038 * 00039 */ 00040 00041 #include "lwip/opt.h" 00042 00043 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ 00044 00045 #include "lwip/sockets.h" 00046 #include "lwip/api.h" 00047 #include "lwip/sys.h" 00048 #include "lwip/igmp.h" 00049 #include "lwip/inet.h" 00050 #include "lwip/tcp.h" 00051 #include "lwip/raw.h" 00052 #include "lwip/udp.h" 00053 #include "lwip/tcpip.h" 00054 #include "lwip/pbuf.h" 00055 #if LWIP_CHECKSUM_ON_COPY 00056 #include "lwip/inet_chksum.h" 00057 #endif 00058 00059 #include <string.h> 00060 #include <stdio.h> 00061 00062 #define NUM_SOCKETS MEMP_NUM_NETCONN 00063 00064 /** Contains all internal pointers and states used for a socket */ 00065 struct lwip_sock { 00066 /** sockets currently are built on netconns, each socket has one netconn */ 00067 struct netconn *conn; 00068 /** data that was left from the previous read */ 00069 void *lastdata; 00070 /** offset in the data that was left from the previous read */ 00071 u16_t lastoffset; 00072 /** number of times data was received, set by event_callback(), 00073 tested by the receive and select functions */ 00074 s16_t rcvevent; 00075 /** number of times data was ACKed (free send buffer), set by event_callback(), 00076 tested by select */ 00077 u16_t sendevent; 00078 /** error happened for this socket, set by event_callback(), tested by select */ 00079 u16_t errevent; 00080 /** last error that occurred on this socket */ 00081 int err; 00082 /** counter of how many threads are waiting for this socket using select */ 00083 int select_waiting; 00084 }; 00085 00086 /** Description for a task waiting in select */ 00087 struct lwip_select_cb { 00088 /** Pointer to the next waiting task */ 00089 struct lwip_select_cb *next; 00090 /** Pointer to the previous waiting task */ 00091 struct lwip_select_cb *prev; 00092 /** readset passed to select */ 00093 fd_set *readset; 00094 /** writeset passed to select */ 00095 fd_set *writeset; 00096 /** unimplemented: exceptset passed to select */ 00097 fd_set *exceptset; 00098 /** don't signal the same semaphore twice: set to 1 when signalled */ 00099 int sem_signalled; 00100 /** semaphore to wake up a task waiting for select */ 00101 sys_sem_t sem; 00102 }; 00103 00104 /** This struct is used to pass data to the set/getsockopt_internal 00105 * functions running in tcpip_thread context (only a void* is allowed) */ 00106 struct lwip_setgetsockopt_data { 00107 /** socket struct for which to change options */ 00108 struct lwip_sock *sock; 00109 #ifdef LWIP_DEBUG 00110 /** socket index for which to change options */ 00111 int s; 00112 #endif /* LWIP_DEBUG */ 00113 /** level of the option to process */ 00114 int level; 00115 /** name of the option to process */ 00116 int optname; 00117 /** set: value to set the option to 00118 * get: value of the option is stored here */ 00119 void *optval; 00120 /** size of *optval */ 00121 socklen_t *optlen; 00122 /** if an error occures, it is temporarily stored here */ 00123 err_t err; 00124 }; 00125 00126 /** The global array of available sockets */ 00127 static struct lwip_sock sockets[NUM_SOCKETS]; 00128 /** The global list of tasks waiting for select */ 00129 static struct lwip_select_cb *select_cb_list; 00130 /** This counter is increased from lwip_select when the list is chagned 00131 and checked in event_callback to see if it has changed. */ 00132 static volatile int select_cb_ctr; 00133 00134 /** Table to quickly map an lwIP error (err_t) to a socket error 00135 * by using -err as an index */ 00136 static const int err_to_errno_table[] = { 00137 0, /* ERR_OK 0 No error, everything OK. */ 00138 ENOMEM, /* ERR_MEM -1 Out of memory error. */ 00139 ENOBUFS, /* ERR_BUF -2 Buffer error. */ 00140 EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ 00141 EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ 00142 EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ 00143 EINVAL, /* ERR_VAL -6 Illegal value. */ 00144 EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ 00145 EADDRINUSE, /* ERR_USE -8 Address in use. */ 00146 EALREADY, /* ERR_ISCONN -9 Already connected. */ 00147 ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */ 00148 ECONNRESET, /* ERR_RST -11 Connection reset. */ 00149 ENOTCONN, /* ERR_CLSD -12 Connection closed. */ 00150 ENOTCONN, /* ERR_CONN -13 Not connected. */ 00151 EIO, /* ERR_ARG -14 Illegal argument. */ 00152 -1, /* ERR_IF -15 Low-level netif error */ 00153 }; 00154 00155 #define ERR_TO_ERRNO_TABLE_SIZE \ 00156 (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0])) 00157 00158 #define err_to_errno(err) \ 00159 ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \ 00160 err_to_errno_table[-(err)] : EIO) 00161 00162 #ifdef ERRNO 00163 #ifndef set_errno 00164 #define set_errno(err) errno = (err) 00165 #endif 00166 #else /* ERRNO */ 00167 #define set_errno(err) 00168 #endif /* ERRNO */ 00169 00170 #define sock_set_errno(sk, e) do { \ 00171 sk->err = (e); \ 00172 set_errno(sk->err); \ 00173 } while (0) 00174 00175 /* Forward delcaration of some functions */ 00176 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); 00177 static void lwip_getsockopt_internal(void *arg); 00178 static void lwip_setsockopt_internal(void *arg); 00179 00180 /** 00181 * Initialize this module. This function has to be called before any other 00182 * functions in this module! 00183 */ 00184 void 00185 lwip_socket_init(void) 00186 { 00187 } 00188 00189 /** 00190 * Map a externally used socket index to the internal socket representation. 00191 * 00192 * @param s externally used socket index 00193 * @return struct lwip_sock for the socket or NULL if not found 00194 */ 00195 static struct lwip_sock * 00196 get_socket(int s) 00197 { 00198 struct lwip_sock *sock; 00199 00200 if ((s < 0) || (s >= NUM_SOCKETS)) { 00201 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s)); 00202 set_errno(EBADF); 00203 return NULL; 00204 } 00205 00206 sock = &sockets[s]; 00207 00208 if (!sock->conn) { 00209 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s)); 00210 set_errno(EBADF); 00211 return NULL; 00212 } 00213 00214 return sock; 00215 } 00216 00217 /** 00218 * Same as get_socket but doesn't set errno 00219 * 00220 * @param s externally used socket index 00221 * @return struct lwip_sock for the socket or NULL if not found 00222 */ 00223 static struct lwip_sock * 00224 tryget_socket(int s) 00225 { 00226 if ((s < 0) || (s >= NUM_SOCKETS)) { 00227 return NULL; 00228 } 00229 if (!sockets[s].conn) { 00230 return NULL; 00231 } 00232 return &sockets[s]; 00233 } 00234 00235 /** 00236 * Allocate a new socket for a given netconn. 00237 * 00238 * @param newconn the netconn for which to allocate a socket 00239 * @param accepted 1 if socket has been created by accept(), 00240 * 0 if socket has been created by socket() 00241 * @return the index of the new socket; -1 on error 00242 */ 00243 static int 00244 alloc_socket(struct netconn *newconn, int accepted) 00245 { 00246 int i; 00247 SYS_ARCH_DECL_PROTECT(lev); 00248 00249 /* allocate a new socket identifier */ 00250 for (i = 0; i < NUM_SOCKETS; ++i) { 00251 /* Protect socket array */ 00252 SYS_ARCH_PROTECT(lev); 00253 if (!sockets[i].conn) { 00254 sockets[i].conn = newconn; 00255 /* The socket is not yet known to anyone, so no need to protect 00256 after having marked it as used. */ 00257 SYS_ARCH_UNPROTECT(lev); 00258 sockets[i].lastdata = NULL; 00259 sockets[i].lastoffset = 0; 00260 sockets[i].rcvevent = 0; 00261 /* TCP sendbuf is empty, but the socket is not yet writable until connected 00262 * (unless it has been created by accept()). */ 00263 sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1); 00264 sockets[i].errevent = 0; 00265 sockets[i].err = 0; 00266 sockets[i].select_waiting = 0; 00267 return i; 00268 } 00269 SYS_ARCH_UNPROTECT(lev); 00270 } 00271 return -1; 00272 } 00273 00274 /** Free a socket. The socket's netconn must have been 00275 * delete before! 00276 * 00277 * @param sock the socket to free 00278 * @param is_tcp != 0 for TCP sockets, used to free lastdata 00279 */ 00280 static void 00281 free_socket(struct lwip_sock *sock, int is_tcp) 00282 { 00283 void *lastdata; 00284 SYS_ARCH_DECL_PROTECT(lev); 00285 00286 lastdata = sock->lastdata; 00287 sock->lastdata = NULL; 00288 sock->lastoffset = 0; 00289 sock->err = 0; 00290 00291 /* Protect socket array */ 00292 SYS_ARCH_PROTECT(lev); 00293 sock->conn = NULL; 00294 SYS_ARCH_UNPROTECT(lev); 00295 /* don't use 'sock' after this line, as another task might have allocated it */ 00296 00297 if (lastdata != NULL) { 00298 if (is_tcp) { 00299 pbuf_free((struct pbuf *)lastdata); 00300 } else { 00301 netbuf_delete((struct netbuf *)lastdata); 00302 } 00303 } 00304 } 00305 00306 /* Below this, the well-known socket functions are implemented. 00307 * Use google.com or opengroup.org to get a good description :-) 00308 * 00309 * Exceptions are documented! 00310 */ 00311 00312 int 00313 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) 00314 { 00315 struct lwip_sock *sock, *nsock; 00316 struct netconn *newconn; 00317 ip_addr_t naddr; 00318 u16_t port; 00319 int newsock; 00320 struct sockaddr_in sin; 00321 err_t err; 00322 SYS_ARCH_DECL_PROTECT(lev); 00323 00324 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); 00325 sock = get_socket(s); 00326 if (!sock) { 00327 return -1; 00328 } 00329 00330 if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) { 00331 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); 00332 sock_set_errno(sock, EWOULDBLOCK); 00333 return -1; 00334 } 00335 00336 /* wait for a new connection */ 00337 err = netconn_accept(sock->conn, &newconn); 00338 if (err != ERR_OK) { 00339 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); 00340 sock_set_errno(sock, err_to_errno(err)); 00341 return -1; 00342 } 00343 LWIP_ASSERT("newconn != NULL", newconn != NULL); 00344 /* Prevent automatic window updates, we do this on our own! */ 00345 netconn_set_noautorecved(newconn, 1); 00346 00347 /* get the IP address and port of the remote host */ 00348 err = netconn_peer(newconn, &naddr, &port); 00349 if (err != ERR_OK) { 00350 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); 00351 netconn_delete(newconn); 00352 sock_set_errno(sock, err_to_errno(err)); 00353 return -1; 00354 } 00355 00356 /* Note that POSIX only requires us to check addr is non-NULL. addrlen must 00357 * not be NULL if addr is valid. 00358 */ 00359 if (NULL != addr) { 00360 LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); 00361 memset(&sin, 0, sizeof(sin)); 00362 sin.sin_len = sizeof(sin); 00363 sin.sin_family = AF_INET; 00364 sin.sin_port = htons(port); 00365 inet_addr_from_ipaddr(&sin.sin_addr, &naddr); 00366 00367 if (*addrlen > sizeof(sin)) 00368 *addrlen = sizeof(sin); 00369 00370 MEMCPY(addr, &sin, *addrlen); 00371 } 00372 00373 newsock = alloc_socket(newconn, 1); 00374 if (newsock == -1) { 00375 netconn_delete(newconn); 00376 sock_set_errno(sock, ENFILE); 00377 return -1; 00378 } 00379 LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS)); 00380 LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback); 00381 nsock = &sockets[newsock]; 00382 00383 /* See event_callback: If data comes in right away after an accept, even 00384 * though the server task might not have created a new socket yet. 00385 * In that case, newconn->socket is counted down (newconn->socket--), 00386 * so nsock->rcvevent is >= 1 here! 00387 */ 00388 SYS_ARCH_PROTECT(lev); 00389 nsock->rcvevent += (s16_t)(-1 - newconn->socket); 00390 newconn->socket = newsock; 00391 SYS_ARCH_UNPROTECT(lev); 00392 00393 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); 00394 ip_addr_debug_print(SOCKETS_DEBUG, &naddr); 00395 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); 00396 00397 sock_set_errno(sock, 0); 00398 return newsock; 00399 } 00400 00401 int 00402 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) 00403 { 00404 struct lwip_sock *sock; 00405 ip_addr_t local_addr; 00406 u16_t local_port; 00407 err_t err; 00408 const struct sockaddr_in *name_in; 00409 00410 sock = get_socket(s); 00411 if (!sock) { 00412 return -1; 00413 } 00414 00415 /* check size, familiy and alignment of 'name' */ 00416 LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) && 00417 ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)), 00418 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 00419 name_in = (const struct sockaddr_in *)(void*)name; 00420 00421 inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr); 00422 local_port = name_in->sin_port; 00423 00424 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); 00425 ip_addr_debug_print(SOCKETS_DEBUG, &local_addr); 00426 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port))); 00427 00428 err = netconn_bind(sock->conn, &local_addr, ntohs(local_port)); 00429 00430 if (err != ERR_OK) { 00431 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); 00432 sock_set_errno(sock, err_to_errno(err)); 00433 return -1; 00434 } 00435 00436 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); 00437 sock_set_errno(sock, 0); 00438 return 0; 00439 } 00440 00441 int 00442 lwip_close(int s) 00443 { 00444 struct lwip_sock *sock; 00445 int is_tcp = 0; 00446 00447 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); 00448 00449 sock = get_socket(s); 00450 if (!sock) { 00451 return -1; 00452 } 00453 00454 if(sock->conn != NULL) { 00455 is_tcp = netconn_type(sock->conn) == NETCONN_TCP; 00456 } else { 00457 LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL); 00458 } 00459 00460 netconn_delete(sock->conn); 00461 00462 free_socket(sock, is_tcp); 00463 set_errno(0); 00464 return 0; 00465 } 00466 00467 int 00468 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) 00469 { 00470 struct lwip_sock *sock; 00471 err_t err; 00472 const struct sockaddr_in *name_in; 00473 00474 sock = get_socket(s); 00475 if (!sock) { 00476 printf("Erro get_socket\n"); 00477 return -1; 00478 } 00479 00480 /* check size, familiy and alignment of 'name' */ 00481 LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) && 00482 ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)), 00483 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 00484 name_in = (const struct sockaddr_in *)(void*)name; 00485 00486 if (name_in->sin_family == AF_UNSPEC) { 00487 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); 00488 printf("1->lwip_connect(%d, AF_UNSPEC)\n", s); 00489 err = netconn_disconnect(sock->conn); 00490 } else { 00491 ip_addr_t remote_addr; 00492 u16_t remote_port; 00493 00494 inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr); 00495 remote_port = name_in->sin_port; 00496 00497 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); 00498 //printf("2->lwip_connect(%d, addr=", s); 00499 00500 ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); 00501 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port))); 00502 //printf(" port=%d\n", ntohs(remote_port)); 00503 00504 err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); 00505 } 00506 00507 if (err != ERR_OK) { 00508 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); 00509 //printf("4->lwip_connect(%d) failed, err=%d\n", s, err); 00510 sock_set_errno(sock, err_to_errno(err)); 00511 return -1; 00512 } 00513 00514 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); 00515 sock_set_errno(sock, 0); 00516 return 0; 00517 } 00518 00519 /** 00520 * Set a socket into listen mode. 00521 * The socket may not have been used for another connection previously. 00522 * 00523 * @param s the socket to set to listening mode 00524 * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) 00525 * @return 0 on success, non-zero on failure 00526 */ 00527 int 00528 lwip_listen(int s, int backlog) 00529 { 00530 struct lwip_sock *sock; 00531 err_t err; 00532 00533 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); 00534 00535 sock = get_socket(s); 00536 if (!sock) { 00537 return -1; 00538 } 00539 00540 /* limit the "backlog" parameter to fit in an u8_t */ 00541 backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); 00542 00543 err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); 00544 00545 if (err != ERR_OK) { 00546 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); 00547 sock_set_errno(sock, err_to_errno(err)); 00548 return -1; 00549 } 00550 00551 sock_set_errno(sock, 0); 00552 return 0; 00553 } 00554 00555 int 00556 lwip_recvfrom(int s, void *mem, size_t len, int flags, 00557 struct sockaddr *from, socklen_t *fromlen) 00558 { 00559 struct lwip_sock *sock; 00560 void *buf = NULL; 00561 struct pbuf *p; 00562 u16_t buflen, copylen; 00563 int off = 0; 00564 ip_addr_t *addr; 00565 u16_t port; 00566 u8_t done = 0; 00567 err_t err; 00568 00569 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); 00570 sock = get_socket(s); 00571 if (!sock) { 00572 return -1; 00573 } 00574 00575 do { 00576 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata)); 00577 /* Check if there is data left from the last recv operation. */ 00578 if (sock->lastdata) { 00579 buf = sock->lastdata; 00580 } else { 00581 /* If this is non-blocking call, then check first */ 00582 if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && 00583 (sock->rcvevent <= 0)) { 00584 if (off > 0) { 00585 /* update receive window */ 00586 netconn_recved(sock->conn, (u32_t)off); 00587 /* already received data, return that */ 00588 sock_set_errno(sock, 0); 00589 return off; 00590 } 00591 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); 00592 sock_set_errno(sock, EWOULDBLOCK); 00593 return -1; 00594 } 00595 00596 /* No data was left from the previous operation, so we try to get 00597 some from the network. */ 00598 if (netconn_type(sock->conn) == NETCONN_TCP) { 00599 err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf); 00600 } else { 00601 err = netconn_recv(sock->conn, (struct netbuf **)&buf); 00602 } 00603 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n", 00604 err, buf)); 00605 00606 if (err != ERR_OK) { 00607 if (off > 0) { 00608 /* update receive window */ 00609 netconn_recved(sock->conn, (u32_t)off); 00610 /* already received data, return that */ 00611 sock_set_errno(sock, 0); 00612 return off; 00613 } 00614 /* We should really do some error checking here. */ 00615 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n", 00616 s, lwip_strerr(err))); 00617 sock_set_errno(sock, err_to_errno(err)); 00618 if (err == ERR_CLSD) { 00619 return 0; 00620 } else { 00621 return -1; 00622 } 00623 } 00624 LWIP_ASSERT("buf != NULL", buf != NULL); 00625 sock->lastdata = buf; 00626 } 00627 00628 if (netconn_type(sock->conn) == NETCONN_TCP) { 00629 p = (struct pbuf *)buf; 00630 } else { 00631 p = ((struct netbuf *)buf)->p; 00632 } 00633 buflen = p->tot_len; 00634 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n", 00635 buflen, len, off, sock->lastoffset)); 00636 00637 buflen -= sock->lastoffset; 00638 00639 if (len > buflen) { 00640 copylen = buflen; 00641 } else { 00642 copylen = (u16_t)len; 00643 } 00644 00645 /* copy the contents of the received buffer into 00646 the supplied memory pointer mem */ 00647 pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset); 00648 00649 off += copylen; 00650 00651 if (netconn_type(sock->conn) == NETCONN_TCP) { 00652 LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen); 00653 len -= copylen; 00654 if ( (len <= 0) || 00655 (p->flags & PBUF_FLAG_PUSH) || 00656 (sock->rcvevent <= 0) || 00657 ((flags & MSG_PEEK)!=0)) { 00658 done = 1; 00659 } 00660 } else { 00661 done = 1; 00662 } 00663 00664 /* Check to see from where the data was.*/ 00665 if (done) { 00666 ip_addr_t fromaddr; 00667 if (from && fromlen) { 00668 struct sockaddr_in sin; 00669 00670 if (netconn_type(sock->conn) == NETCONN_TCP) { 00671 addr = &fromaddr; 00672 netconn_getaddr(sock->conn, addr, &port, 0); 00673 } else { 00674 addr = netbuf_fromaddr((struct netbuf *)buf); 00675 port = netbuf_fromport((struct netbuf *)buf); 00676 } 00677 00678 memset(&sin, 0, sizeof(sin)); 00679 sin.sin_len = sizeof(sin); 00680 sin.sin_family = AF_INET; 00681 sin.sin_port = htons(port); 00682 inet_addr_from_ipaddr(&sin.sin_addr, addr); 00683 00684 if (*fromlen > sizeof(sin)) { 00685 *fromlen = sizeof(sin); 00686 } 00687 00688 MEMCPY(from, &sin, *fromlen); 00689 00690 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); 00691 ip_addr_debug_print(SOCKETS_DEBUG, addr); 00692 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); 00693 } else { 00694 #if SOCKETS_DEBUG 00695 if (netconn_type(sock->conn) == NETCONN_TCP) { 00696 addr = &fromaddr; 00697 netconn_getaddr(sock->conn, addr, &port, 0); 00698 } else { 00699 addr = netbuf_fromaddr((struct netbuf *)buf); 00700 port = netbuf_fromport((struct netbuf *)buf); 00701 } 00702 00703 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); 00704 ip_addr_debug_print(SOCKETS_DEBUG, addr); 00705 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); 00706 #endif /* SOCKETS_DEBUG */ 00707 } 00708 } 00709 00710 /* If we don't peek the incoming message... */ 00711 if ((flags & MSG_PEEK) == 0) { 00712 /* If this is a TCP socket, check if there is data left in the 00713 buffer. If so, it should be saved in the sock structure for next 00714 time around. */ 00715 if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) { 00716 sock->lastdata = buf; 00717 sock->lastoffset += copylen; 00718 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf)); 00719 } else { 00720 sock->lastdata = NULL; 00721 sock->lastoffset = 0; 00722 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf)); 00723 if (netconn_type(sock->conn) == NETCONN_TCP) { 00724 pbuf_free((struct pbuf *)buf); 00725 } else { 00726 netbuf_delete((struct netbuf *)buf); 00727 } 00728 } 00729 } 00730 } while (!done); 00731 00732 if (off > 0) { 00733 /* update receive window */ 00734 netconn_recved(sock->conn, (u32_t)off); 00735 } 00736 sock_set_errno(sock, 0); 00737 return off; 00738 } 00739 00740 int 00741 lwip_read(int s, void *mem, size_t len) 00742 { 00743 return lwip_recvfrom(s, mem, len, 0, NULL, NULL); 00744 } 00745 00746 int 00747 lwip_recv(int s, void *mem, size_t len, int flags) 00748 { 00749 return lwip_recvfrom(s, mem, len, flags, NULL, NULL); 00750 } 00751 00752 int 00753 lwip_send(int s, const void *data, size_t size, int flags) 00754 { 00755 struct lwip_sock *sock; 00756 err_t err; 00757 u8_t write_flags; 00758 00759 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", 00760 s, data, size, flags)); 00761 00762 sock = get_socket(s); 00763 if (!sock) { 00764 return -1; 00765 } 00766 00767 if (sock->conn->type != NETCONN_TCP) { 00768 #if (LWIP_UDP || LWIP_RAW) 00769 return lwip_sendto (s, data, size, flags, NULL, 0); 00770 #else /* (LWIP_UDP || LWIP_RAW) */ 00771 sock_set_errno(sock, err_to_errno(ERR_ARG)); 00772 return -1; 00773 #endif /* (LWIP_UDP || LWIP_RAW) */ 00774 } 00775 00776 if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) { 00777 if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) { 00778 /* too much data to ever send nonblocking! */ 00779 sock_set_errno(sock, EMSGSIZE); 00780 return -1; 00781 } 00782 } 00783 00784 write_flags = NETCONN_COPY | 00785 ((flags & MSG_MORE) ? NETCONN_MORE : 0) | 00786 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); 00787 err = netconn_write(sock->conn, data, size, write_flags); 00788 00789 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size)); 00790 sock_set_errno(sock, err_to_errno(err)); 00791 return (err == ERR_OK ? (int)size : -1); 00792 } 00793 00794 int 00795 lwip_sendto (int s, const void *data, size_t size, int flags, 00796 const struct sockaddr *to, socklen_t tolen) 00797 { 00798 struct lwip_sock *sock; 00799 err_t err; 00800 u16_t short_size; 00801 const struct sockaddr_in *to_in; 00802 u16_t remote_port; 00803 #if !LWIP_TCPIP_CORE_LOCKING 00804 struct netbuf buf; 00805 #endif 00806 00807 sock = get_socket(s); 00808 if (!sock) { 00809 return -1; 00810 } 00811 00812 if (sock->conn->type == NETCONN_TCP) { 00813 #if LWIP_TCP 00814 return lwip_send(s, data, size, flags); 00815 #else /* LWIP_TCP */ 00816 LWIP_UNUSED_ARG(flags); 00817 sock_set_errno(sock, err_to_errno(ERR_ARG)); 00818 return -1; 00819 #endif /* LWIP_TCP */ 00820 } 00821 00822 /* @todo: split into multiple sendto's? */ 00823 LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); 00824 short_size = (u16_t)size; 00825 LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || 00826 ((tolen == sizeof(struct sockaddr_in)) && 00827 ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))), 00828 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 00829 to_in = (const struct sockaddr_in *)(void*)to; 00830 00831 #if LWIP_TCPIP_CORE_LOCKING 00832 /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */ 00833 { 00834 struct pbuf* p; 00835 ip_addr_t *remote_addr; 00836 00837 #if LWIP_NETIF_TX_SINGLE_PBUF 00838 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM); 00839 if (p != NULL) { 00840 #if LWIP_CHECKSUM_ON_COPY 00841 u16_t chksum = 0; 00842 if (sock->conn->type != NETCONN_RAW) { 00843 chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size); 00844 } else 00845 #endif /* LWIP_CHECKSUM_ON_COPY */ 00846 MEMCPY(p->payload, data, size); 00847 #else /* LWIP_NETIF_TX_SINGLE_PBUF */ 00848 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF); 00849 if (p != NULL) { 00850 p->payload = (void*)data; 00851 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ 00852 00853 if (to_in != NULL) { 00854 inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr); 00855 remote_port = ntohs(to_in->sin_port); 00856 } else { 00857 remote_addr = &sock->conn->pcb.raw->remote_ip; 00858 if (sock->conn->type == NETCONN_RAW) { 00859 remote_port = 0; 00860 } else { 00861 remote_port = sock->conn->pcb.udp->remote_port; 00862 } 00863 } 00864 00865 LOCK_TCPIP_CORE(); 00866 if (sock->conn->type == NETCONN_RAW) { 00867 err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr); 00868 } else { 00869 #if LWIP_UDP 00870 #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF 00871 err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p, 00872 remote_addr, remote_port, 1, chksum); 00873 #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */ 00874 err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p, 00875 remote_addr, remote_port); 00876 #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */ 00877 #else /* LWIP_UDP */ 00878 err = ERR_ARG; 00879 #endif /* LWIP_UDP */ 00880 } 00881 UNLOCK_TCPIP_CORE(); 00882 00883 pbuf_free(p); 00884 } else { 00885 err = ERR_MEM; 00886 } 00887 } 00888 #else /* LWIP_TCPIP_CORE_LOCKING */ 00889 /* initialize a buffer */ 00890 buf.p = buf.ptr = NULL; 00891 #if LWIP_CHECKSUM_ON_COPY 00892 buf.flags = 0; 00893 #endif /* LWIP_CHECKSUM_ON_COPY */ 00894 if (to) { 00895 inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr); 00896 remote_port = ntohs(to_in->sin_port); 00897 netbuf_fromport(&buf) = remote_port; 00898 } else { 00899 remote_port = 0; 00900 ip_addr_set_any(&buf.addr); 00901 netbuf_fromport(&buf) = 0; 00902 } 00903 00904 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", 00905 s, data, short_size, flags)); 00906 ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr); 00907 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); 00908 00909 /* make the buffer point to the data that should be sent */ 00910 #if LWIP_NETIF_TX_SINGLE_PBUF 00911 /* Allocate a new netbuf and copy the data into it. */ 00912 if (netbuf_alloc(&buf, short_size) == NULL) { 00913 err = ERR_MEM; 00914 } else { 00915 #if LWIP_CHECKSUM_ON_COPY 00916 if (sock->conn->type != NETCONN_RAW) { 00917 u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); 00918 netbuf_set_chksum(&buf, chksum); 00919 err = ERR_OK; 00920 } else 00921 #endif /* LWIP_CHECKSUM_ON_COPY */ 00922 { 00923 err = netbuf_take(&buf, data, short_size); 00924 } 00925 } 00926 #else /* LWIP_NETIF_TX_SINGLE_PBUF */ 00927 err = netbuf_ref(&buf, data, short_size); 00928 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ 00929 if (err == ERR_OK) { 00930 /* send the data */ 00931 err = netconn_send(sock->conn, &buf); 00932 } 00933 00934 /* deallocated the buffer */ 00935 netbuf_free(&buf); 00936 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00937 sock_set_errno(sock, err_to_errno(err)); 00938 return (err == ERR_OK ? short_size : -1); 00939 } 00940 00941 int 00942 lwip_socket(int domain, int type, int protocol) 00943 { 00944 struct netconn *conn; 00945 int i; 00946 00947 LWIP_UNUSED_ARG(domain); 00948 00949 /* create a netconn */ 00950 switch (type) { 00951 case SOCK_RAW: 00952 conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback); 00953 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", 00954 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 00955 break; 00956 case SOCK_DGRAM: 00957 conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ? 00958 NETCONN_UDPLITE : NETCONN_UDP, event_callback); 00959 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", 00960 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 00961 break; 00962 case SOCK_STREAM: 00963 conn = netconn_new_with_callback(NETCONN_TCP, event_callback); 00964 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", 00965 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 00966 if (conn != NULL) { 00967 /* Prevent automatic window updates, we do this on our own! */ 00968 netconn_set_noautorecved(conn, 1); 00969 } 00970 break; 00971 default: 00972 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", 00973 domain, type, protocol)); 00974 set_errno(EINVAL); 00975 return -1; 00976 } 00977 00978 if (!conn) { 00979 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); 00980 set_errno(ENOBUFS); 00981 return -1; 00982 } 00983 00984 i = alloc_socket(conn, 0); 00985 00986 if (i == -1) { 00987 netconn_delete(conn); 00988 set_errno(ENFILE); 00989 return -1; 00990 } 00991 conn->socket = i; 00992 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); 00993 set_errno(0); 00994 return i; 00995 } 00996 00997 int 00998 lwip_write(int s, const void *data, size_t size) 00999 { 01000 return lwip_send(s, data, size, 0); 01001 } 01002 01003 /** 01004 * Go through the readset and writeset lists and see which socket of the sockets 01005 * set in the sets has events. On return, readset, writeset and exceptset have 01006 * the sockets enabled that had events. 01007 * 01008 * exceptset is not used for now!!! 01009 * 01010 * @param maxfdp1 the highest socket index in the sets 01011 * @param readset_in: set of sockets to check for read events 01012 * @param writeset_in: set of sockets to check for write events 01013 * @param exceptset_in: set of sockets to check for error events 01014 * @param readset_out: set of sockets that had read events 01015 * @param writeset_out: set of sockets that had write events 01016 * @param exceptset_out: set os sockets that had error events 01017 * @return number of sockets that had events (read/write/exception) (>= 0) 01018 */ 01019 static int 01020 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, 01021 fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) 01022 { 01023 int i, nready = 0; 01024 fd_set lreadset, lwriteset, lexceptset; 01025 struct lwip_sock *sock; 01026 SYS_ARCH_DECL_PROTECT(lev); 01027 01028 FD_ZERO(&lreadset); 01029 FD_ZERO(&lwriteset); 01030 FD_ZERO(&lexceptset); 01031 01032 /* Go through each socket in each list to count number of sockets which 01033 currently match */ 01034 for(i = 0; i < maxfdp1; i++) { 01035 void* lastdata = NULL; 01036 s16_t rcvevent = 0; 01037 u16_t sendevent = 0; 01038 u16_t errevent = 0; 01039 /* First get the socket's status (protected)... */ 01040 SYS_ARCH_PROTECT(lev); 01041 sock = tryget_socket(i); 01042 if (sock != NULL) { 01043 lastdata = sock->lastdata; 01044 rcvevent = sock->rcvevent; 01045 sendevent = sock->sendevent; 01046 errevent = sock->errevent; 01047 } 01048 SYS_ARCH_UNPROTECT(lev); 01049 /* ... then examine it: */ 01050 /* See if netconn of this socket is ready for read */ 01051 if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { 01052 FD_SET(i, &lreadset); 01053 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); 01054 nready++; 01055 } 01056 /* See if netconn of this socket is ready for write */ 01057 if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { 01058 FD_SET(i, &lwriteset); 01059 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); 01060 nready++; 01061 } 01062 /* See if netconn of this socket had an error */ 01063 if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { 01064 FD_SET(i, &lexceptset); 01065 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); 01066 nready++; 01067 } 01068 } 01069 /* copy local sets to the ones provided as arguments */ 01070 *readset_out = lreadset; 01071 *writeset_out = lwriteset; 01072 *exceptset_out = lexceptset; 01073 01074 LWIP_ASSERT("nready >= 0", nready >= 0); 01075 return nready; 01076 } 01077 01078 /** 01079 * Processing exceptset is not yet implemented. 01080 */ 01081 int 01082 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, 01083 struct timeval *timeout) 01084 { 01085 u32_t waitres = 0; 01086 int nready; 01087 fd_set lreadset, lwriteset, lexceptset; 01088 u32_t msectimeout; 01089 struct lwip_select_cb select_cb; 01090 err_t err; 01091 int i; 01092 SYS_ARCH_DECL_PROTECT(lev); 01093 01094 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", 01095 maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, 01096 timeout ? (s32_t)timeout->tv_sec : (s32_t)-1, 01097 timeout ? (s32_t)timeout->tv_usec : (s32_t)-1)); 01098 01099 /* Go through each socket in each list to count number of sockets which 01100 currently match */ 01101 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 01102 01103 /* If we don't have any current events, then suspend if we are supposed to */ 01104 if (!nready) { 01105 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { 01106 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); 01107 /* This is OK as the local fdsets are empty and nready is zero, 01108 or we would have returned earlier. */ 01109 goto return_copy_fdsets; 01110 } 01111 01112 /* None ready: add our semaphore to list: 01113 We don't actually need any dynamic memory. Our entry on the 01114 list is only valid while we are in this function, so it's ok 01115 to use local variables. */ 01116 01117 select_cb.next = NULL; 01118 select_cb.prev = NULL; 01119 select_cb.readset = readset; 01120 select_cb.writeset = writeset; 01121 select_cb.exceptset = exceptset; 01122 select_cb.sem_signalled = 0; 01123 err = sys_sem_new(&select_cb.sem, 0); 01124 if (err != ERR_OK) { 01125 /* failed to create semaphore */ 01126 set_errno(ENOMEM); 01127 return -1; 01128 } 01129 01130 /* Protect the select_cb_list */ 01131 SYS_ARCH_PROTECT(lev); 01132 01133 /* Put this select_cb on top of list */ 01134 select_cb.next = select_cb_list; 01135 if (select_cb_list != NULL) { 01136 select_cb_list->prev = &select_cb; 01137 } 01138 select_cb_list = &select_cb; 01139 /* Increasing this counter tells even_callback that the list has changed. */ 01140 select_cb_ctr++; 01141 01142 /* Now we can safely unprotect */ 01143 SYS_ARCH_UNPROTECT(lev); 01144 01145 /* Increase select_waiting for each socket we are interested in */ 01146 for(i = 0; i < maxfdp1; i++) { 01147 if ((readset && FD_ISSET(i, readset)) || 01148 (writeset && FD_ISSET(i, writeset)) || 01149 (exceptset && FD_ISSET(i, exceptset))) { 01150 struct lwip_sock *sock = tryget_socket(i); 01151 LWIP_ASSERT("sock != NULL", sock != NULL); 01152 SYS_ARCH_PROTECT(lev); 01153 sock->select_waiting++; 01154 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); 01155 SYS_ARCH_UNPROTECT(lev); 01156 } 01157 } 01158 01159 /* Call lwip_selscan again: there could have been events between 01160 the last scan (whithout us on the list) and putting us on the list! */ 01161 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 01162 if (!nready) { 01163 /* Still none ready, just wait to be woken */ 01164 if (timeout == 0) { 01165 /* Wait forever */ 01166 msectimeout = 0; 01167 } else { 01168 msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); 01169 if (msectimeout == 0) { 01170 /* Wait 1ms at least (0 means wait forever) */ 01171 msectimeout = 1; 01172 } 01173 } 01174 01175 waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout); 01176 } 01177 /* Increase select_waiting for each socket we are interested in */ 01178 for(i = 0; i < maxfdp1; i++) { 01179 if ((readset && FD_ISSET(i, readset)) || 01180 (writeset && FD_ISSET(i, writeset)) || 01181 (exceptset && FD_ISSET(i, exceptset))) { 01182 struct lwip_sock *sock = tryget_socket(i); 01183 LWIP_ASSERT("sock != NULL", sock != NULL); 01184 SYS_ARCH_PROTECT(lev); 01185 sock->select_waiting--; 01186 LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0); 01187 SYS_ARCH_UNPROTECT(lev); 01188 } 01189 } 01190 /* Take us off the list */ 01191 SYS_ARCH_PROTECT(lev); 01192 if (select_cb.next != NULL) { 01193 select_cb.next->prev = select_cb.prev; 01194 } 01195 if (select_cb_list == &select_cb) { 01196 LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL); 01197 select_cb_list = select_cb.next; 01198 } else { 01199 LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL); 01200 select_cb.prev->next = select_cb.next; 01201 } 01202 /* Increasing this counter tells even_callback that the list has changed. */ 01203 select_cb_ctr++; 01204 SYS_ARCH_UNPROTECT(lev); 01205 01206 sys_sem_free(&select_cb.sem); 01207 if (waitres == SYS_ARCH_TIMEOUT) { 01208 /* Timeout */ 01209 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); 01210 /* This is OK as the local fdsets are empty and nready is zero, 01211 or we would have returned earlier. */ 01212 goto return_copy_fdsets; 01213 } 01214 01215 /* See what's set */ 01216 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 01217 } 01218 01219 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); 01220 return_copy_fdsets: 01221 set_errno(0); 01222 if (readset) { 01223 *readset = lreadset; 01224 } 01225 if (writeset) { 01226 *writeset = lwriteset; 01227 } 01228 if (exceptset) { 01229 *exceptset = lexceptset; 01230 } 01231 01232 01233 return nready; 01234 } 01235 01236 /** 01237 * Callback registered in the netconn layer for each socket-netconn. 01238 * Processes recvevent (data available) and wakes up tasks waiting for select. 01239 */ 01240 static void 01241 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) 01242 { 01243 int s; 01244 struct lwip_sock *sock; 01245 struct lwip_select_cb *scb; 01246 int last_select_cb_ctr; 01247 SYS_ARCH_DECL_PROTECT(lev); 01248 01249 LWIP_UNUSED_ARG(len); 01250 01251 /* Get socket */ 01252 if (conn) { 01253 s = conn->socket; 01254 if (s < 0) { 01255 /* Data comes in right away after an accept, even though 01256 * the server task might not have created a new socket yet. 01257 * Just count down (or up) if that's the case and we 01258 * will use the data later. Note that only receive events 01259 * can happen before the new socket is set up. */ 01260 SYS_ARCH_PROTECT(lev); 01261 if (conn->socket < 0) { 01262 if (evt == NETCONN_EVT_RCVPLUS) { 01263 conn->socket--; 01264 } 01265 SYS_ARCH_UNPROTECT(lev); 01266 return; 01267 } 01268 s = conn->socket; 01269 SYS_ARCH_UNPROTECT(lev); 01270 } 01271 01272 sock = get_socket(s); 01273 if (!sock) { 01274 return; 01275 } 01276 } else { 01277 return; 01278 } 01279 01280 SYS_ARCH_PROTECT(lev); 01281 /* Set event as required */ 01282 switch (evt) { 01283 case NETCONN_EVT_RCVPLUS: 01284 sock->rcvevent++; 01285 break; 01286 case NETCONN_EVT_RCVMINUS: 01287 sock->rcvevent--; 01288 break; 01289 case NETCONN_EVT_SENDPLUS: 01290 sock->sendevent = 1; 01291 break; 01292 case NETCONN_EVT_SENDMINUS: 01293 sock->sendevent = 0; 01294 break; 01295 case NETCONN_EVT_ERROR: 01296 sock->errevent = 1; 01297 break; 01298 default: 01299 LWIP_ASSERT("unknown event", 0); 01300 break; 01301 } 01302 01303 if (sock->select_waiting == 0) { 01304 /* noone is waiting for this socket, no need to check select_cb_list */ 01305 SYS_ARCH_UNPROTECT(lev); 01306 return; 01307 } 01308 01309 /* Now decide if anyone is waiting for this socket */ 01310 /* NOTE: This code goes through the select_cb_list list multiple times 01311 ONLY IF a select was actually waiting. We go through the list the number 01312 of waiting select calls + 1. This list is expected to be small. */ 01313 01314 /* At this point, SYS_ARCH is still protected! */ 01315 again: 01316 for (scb = select_cb_list; scb != NULL; scb = scb->next) { 01317 if (scb->sem_signalled == 0) { 01318 /* semaphore not signalled yet */ 01319 int do_signal = 0; 01320 /* Test this select call for our socket */ 01321 if (sock->rcvevent > 0) { 01322 if (scb->readset && FD_ISSET(s, scb->readset)) { 01323 do_signal = 1; 01324 } 01325 } 01326 if (sock->sendevent != 0) { 01327 if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { 01328 do_signal = 1; 01329 } 01330 } 01331 if (sock->errevent != 0) { 01332 if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { 01333 do_signal = 1; 01334 } 01335 } 01336 if (do_signal) { 01337 scb->sem_signalled = 1; 01338 /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might 01339 lead to the select thread taking itself off the list, invalidagin the semaphore. */ 01340 sys_sem_signal(&scb->sem); 01341 } 01342 } 01343 /* unlock interrupts with each step */ 01344 last_select_cb_ctr = select_cb_ctr; 01345 SYS_ARCH_UNPROTECT(lev); 01346 /* this makes sure interrupt protection time is short */ 01347 SYS_ARCH_PROTECT(lev); 01348 if (last_select_cb_ctr != select_cb_ctr) { 01349 /* someone has changed select_cb_list, restart at the beginning */ 01350 goto again; 01351 } 01352 } 01353 SYS_ARCH_UNPROTECT(lev); 01354 } 01355 01356 /** 01357 * Unimplemented: Close one end of a full-duplex connection. 01358 * Currently, the full connection is closed. 01359 */ 01360 int 01361 lwip_shutdown(int s, int how) 01362 { 01363 struct lwip_sock *sock; 01364 err_t err; 01365 u8_t shut_rx = 0, shut_tx = 0; 01366 01367 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); 01368 01369 sock = get_socket(s); 01370 if (!sock) { 01371 return -1; 01372 } 01373 01374 if (sock->conn != NULL) { 01375 if (netconn_type(sock->conn) != NETCONN_TCP) { 01376 sock_set_errno(sock, EOPNOTSUPP); 01377 return EOPNOTSUPP; 01378 } 01379 } else { 01380 sock_set_errno(sock, ENOTCONN); 01381 return ENOTCONN; 01382 } 01383 01384 if (how == SHUT_RD) { 01385 shut_rx = 1; 01386 } else if (how == SHUT_WR) { 01387 shut_tx = 1; 01388 } else if(how == SHUT_RDWR) { 01389 shut_rx = 1; 01390 shut_tx = 1; 01391 } else { 01392 sock_set_errno(sock, EINVAL); 01393 return EINVAL; 01394 } 01395 err = netconn_shutdown(sock->conn, shut_rx, shut_tx); 01396 01397 sock_set_errno(sock, err_to_errno(err)); 01398 return (err == ERR_OK ? 0 : -1); 01399 } 01400 01401 static int 01402 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) 01403 { 01404 struct lwip_sock *sock; 01405 struct sockaddr_in sin; 01406 ip_addr_t naddr; 01407 01408 sock = get_socket(s); 01409 if (!sock) { 01410 return -1; 01411 } 01412 01413 memset(&sin, 0, sizeof(sin)); 01414 sin.sin_len = sizeof(sin); 01415 sin.sin_family = AF_INET; 01416 01417 /* get the IP address and port */ 01418 netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local); 01419 01420 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); 01421 ip_addr_debug_print(SOCKETS_DEBUG, &naddr); 01422 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port)); 01423 01424 sin.sin_port = htons(sin.sin_port); 01425 inet_addr_from_ipaddr(&sin.sin_addr, &naddr); 01426 01427 if (*namelen > sizeof(sin)) { 01428 *namelen = sizeof(sin); 01429 } 01430 01431 MEMCPY(name, &sin, *namelen); 01432 sock_set_errno(sock, 0); 01433 return 0; 01434 } 01435 01436 int 01437 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) 01438 { 01439 return lwip_getaddrname(s, name, namelen, 0); 01440 } 01441 01442 int 01443 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) 01444 { 01445 return lwip_getaddrname(s, name, namelen, 1); 01446 } 01447 01448 int 01449 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) 01450 { 01451 err_t err = ERR_OK; 01452 struct lwip_sock *sock = get_socket(s); 01453 struct lwip_setgetsockopt_data data; 01454 01455 if (!sock) { 01456 return -1; 01457 } 01458 01459 if ((NULL == optval) || (NULL == optlen)) { 01460 sock_set_errno(sock, EFAULT); 01461 return -1; 01462 } 01463 01464 /* Do length and type checks for the various options first, to keep it readable. */ 01465 switch (level) { 01466 01467 /* Level: SOL_SOCKET */ 01468 case SOL_SOCKET: 01469 switch (optname) { 01470 01471 case SO_ACCEPTCONN: 01472 case SO_BROADCAST: 01473 /* UNIMPL case SO_DEBUG: */ 01474 /* UNIMPL case SO_DONTROUTE: */ 01475 case SO_ERROR: 01476 case SO_KEEPALIVE: 01477 /* UNIMPL case SO_CONTIMEO: */ 01478 /* UNIMPL case SO_SNDTIMEO: */ 01479 #if LWIP_SO_RCVTIMEO 01480 case SO_RCVTIMEO: 01481 #endif /* LWIP_SO_RCVTIMEO */ 01482 #if LWIP_SO_RCVBUF 01483 case SO_RCVBUF: 01484 #endif /* LWIP_SO_RCVBUF */ 01485 /* UNIMPL case SO_OOBINLINE: */ 01486 /* UNIMPL case SO_SNDBUF: */ 01487 /* UNIMPL case SO_RCVLOWAT: */ 01488 /* UNIMPL case SO_SNDLOWAT: */ 01489 #if SO_REUSE 01490 case SO_REUSEADDR: 01491 case SO_REUSEPORT: 01492 #endif /* SO_REUSE */ 01493 case SO_TYPE: 01494 /* UNIMPL case SO_USELOOPBACK: */ 01495 if (*optlen < sizeof(int)) { 01496 err = EINVAL; 01497 } 01498 break; 01499 01500 case SO_NO_CHECK: 01501 if (*optlen < sizeof(int)) { 01502 err = EINVAL; 01503 } 01504 #if LWIP_UDP 01505 if ((sock->conn->type != NETCONN_UDP) || 01506 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { 01507 /* this flag is only available for UDP, not for UDP lite */ 01508 err = EAFNOSUPPORT; 01509 } 01510 #endif /* LWIP_UDP */ 01511 break; 01512 01513 default: 01514 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", 01515 s, optname)); 01516 err = ENOPROTOOPT; 01517 } /* switch (optname) */ 01518 break; 01519 01520 /* Level: IPPROTO_IP */ 01521 case IPPROTO_IP: 01522 switch (optname) { 01523 /* UNIMPL case IP_HDRINCL: */ 01524 /* UNIMPL case IP_RCVDSTADDR: */ 01525 /* UNIMPL case IP_RCVIF: */ 01526 case IP_TTL: 01527 case IP_TOS: 01528 if (*optlen < sizeof(int)) { 01529 err = EINVAL; 01530 } 01531 break; 01532 #if LWIP_IGMP 01533 case IP_MULTICAST_TTL: 01534 if (*optlen < sizeof(u8_t)) { 01535 err = EINVAL; 01536 } 01537 break; 01538 case IP_MULTICAST_IF: 01539 if (*optlen < sizeof(struct in_addr)) { 01540 err = EINVAL; 01541 } 01542 break; 01543 case IP_MULTICAST_LOOP: 01544 if (*optlen < sizeof(u8_t)) { 01545 err = EINVAL; 01546 } 01547 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { 01548 err = EAFNOSUPPORT; 01549 } 01550 break; 01551 #endif /* LWIP_IGMP */ 01552 01553 default: 01554 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", 01555 s, optname)); 01556 err = ENOPROTOOPT; 01557 } /* switch (optname) */ 01558 break; 01559 01560 #if LWIP_TCP 01561 /* Level: IPPROTO_TCP */ 01562 case IPPROTO_TCP: 01563 if (*optlen < sizeof(int)) { 01564 err = EINVAL; 01565 break; 01566 } 01567 01568 /* If this is no TCP socket, ignore any options. */ 01569 if (sock->conn->type != NETCONN_TCP) 01570 return 0; 01571 01572 switch (optname) { 01573 case TCP_NODELAY: 01574 case TCP_KEEPALIVE: 01575 #if LWIP_TCP_KEEPALIVE 01576 case TCP_KEEPIDLE: 01577 case TCP_KEEPINTVL: 01578 case TCP_KEEPCNT: 01579 #endif /* LWIP_TCP_KEEPALIVE */ 01580 break; 01581 01582 default: 01583 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", 01584 s, optname)); 01585 err = ENOPROTOOPT; 01586 } /* switch (optname) */ 01587 break; 01588 #endif /* LWIP_TCP */ 01589 #if LWIP_UDP && LWIP_UDPLITE 01590 /* Level: IPPROTO_UDPLITE */ 01591 case IPPROTO_UDPLITE: 01592 if (*optlen < sizeof(int)) { 01593 err = EINVAL; 01594 break; 01595 } 01596 01597 /* If this is no UDP lite socket, ignore any options. */ 01598 if (sock->conn->type != NETCONN_UDPLITE) { 01599 return 0; 01600 } 01601 01602 switch (optname) { 01603 case UDPLITE_SEND_CSCOV: 01604 case UDPLITE_RECV_CSCOV: 01605 break; 01606 01607 default: 01608 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", 01609 s, optname)); 01610 err = ENOPROTOOPT; 01611 } /* switch (optname) */ 01612 break; 01613 #endif /* LWIP_UDP && LWIP_UDPLITE*/ 01614 /* UNDEFINED LEVEL */ 01615 default: 01616 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", 01617 s, level, optname)); 01618 err = ENOPROTOOPT; 01619 } /* switch */ 01620 01621 01622 if (err != ERR_OK) { 01623 sock_set_errno(sock, err); 01624 return -1; 01625 } 01626 01627 /* Now do the actual option processing */ 01628 data.sock = sock; 01629 #ifdef LWIP_DEBUG 01630 data.s = s; 01631 #endif /* LWIP_DEBUG */ 01632 data.level = level; 01633 data.optname = optname; 01634 data.optval = optval; 01635 data.optlen = optlen; 01636 data.err = err; 01637 tcpip_callback(lwip_getsockopt_internal, &data); 01638 sys_arch_sem_wait(&sock->conn->op_completed, 0); 01639 /* maybe lwip_getsockopt_internal has changed err */ 01640 err = data.err; 01641 01642 sock_set_errno(sock, err); 01643 return err ? -1 : 0; 01644 } 01645 01646 static void 01647 lwip_getsockopt_internal(void *arg) 01648 { 01649 struct lwip_sock *sock; 01650 #ifdef LWIP_DEBUG 01651 int s; 01652 #endif /* LWIP_DEBUG */ 01653 int level, optname; 01654 void *optval; 01655 struct lwip_setgetsockopt_data *data; 01656 01657 LWIP_ASSERT("arg != NULL", arg != NULL); 01658 01659 data = (struct lwip_setgetsockopt_data*)arg; 01660 sock = data->sock; 01661 #ifdef LWIP_DEBUG 01662 s = data->s; 01663 #endif /* LWIP_DEBUG */ 01664 level = data->level; 01665 optname = data->optname; 01666 optval = data->optval; 01667 01668 switch (level) { 01669 01670 /* Level: SOL_SOCKET */ 01671 case SOL_SOCKET: 01672 switch (optname) { 01673 01674 /* The option flags */ 01675 case SO_ACCEPTCONN: 01676 case SO_BROADCAST: 01677 /* UNIMPL case SO_DEBUG: */ 01678 /* UNIMPL case SO_DONTROUTE: */ 01679 case SO_KEEPALIVE: 01680 /* UNIMPL case SO_OOBINCLUDE: */ 01681 #if SO_REUSE 01682 case SO_REUSEADDR: 01683 case SO_REUSEPORT: 01684 #endif /* SO_REUSE */ 01685 /*case SO_USELOOPBACK: UNIMPL */ 01686 *(int*)optval = sock->conn->pcb.ip->so_options & optname; 01687 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", 01688 s, optname, (*(int*)optval?"on":"off"))); 01689 break; 01690 01691 case SO_TYPE: 01692 switch (NETCONNTYPE_GROUP(sock->conn->type)) { 01693 case NETCONN_RAW: 01694 *(int*)optval = SOCK_RAW; 01695 break; 01696 case NETCONN_TCP: 01697 *(int*)optval = SOCK_STREAM; 01698 break; 01699 case NETCONN_UDP: 01700 *(int*)optval = SOCK_DGRAM; 01701 break; 01702 default: /* unrecognized socket type */ 01703 *(int*)optval = sock->conn->type; 01704 LWIP_DEBUGF(SOCKETS_DEBUG, 01705 ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", 01706 s, *(int *)optval)); 01707 } /* switch (sock->conn->type) */ 01708 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", 01709 s, *(int *)optval)); 01710 break; 01711 01712 case SO_ERROR: 01713 /* only overwrite ERR_OK or tempoary errors */ 01714 if ((sock->err == 0) || (sock->err == EINPROGRESS)) { 01715 sock_set_errno(sock, err_to_errno(sock->conn->last_err)); 01716 } 01717 *(int *)optval = sock->err; 01718 sock->err = 0; 01719 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", 01720 s, *(int *)optval)); 01721 break; 01722 01723 #if LWIP_SO_RCVTIMEO 01724 case SO_RCVTIMEO: 01725 *(int *)optval = netconn_get_recvtimeout(sock->conn); 01726 break; 01727 #endif /* LWIP_SO_RCVTIMEO */ 01728 #if LWIP_SO_RCVBUF 01729 case SO_RCVBUF: 01730 *(int *)optval = netconn_get_recvbufsize(sock->conn); 01731 break; 01732 #endif /* LWIP_SO_RCVBUF */ 01733 #if LWIP_UDP 01734 case SO_NO_CHECK: 01735 *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0; 01736 break; 01737 #endif /* LWIP_UDP*/ 01738 default: 01739 LWIP_ASSERT("unhandled optname", 0); 01740 break; 01741 } /* switch (optname) */ 01742 break; 01743 01744 /* Level: IPPROTO_IP */ 01745 case IPPROTO_IP: 01746 switch (optname) { 01747 case IP_TTL: 01748 *(int*)optval = sock->conn->pcb.ip->ttl; 01749 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", 01750 s, *(int *)optval)); 01751 break; 01752 case IP_TOS: 01753 *(int*)optval = sock->conn->pcb.ip->tos; 01754 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", 01755 s, *(int *)optval)); 01756 break; 01757 #if LWIP_IGMP 01758 case IP_MULTICAST_TTL: 01759 *(u8_t*)optval = sock->conn->pcb.ip->ttl; 01760 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", 01761 s, *(int *)optval)); 01762 break; 01763 case IP_MULTICAST_IF: 01764 inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip); 01765 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", 01766 s, *(u32_t *)optval)); 01767 break; 01768 case IP_MULTICAST_LOOP: 01769 if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { 01770 *(u8_t*)optval = 1; 01771 } else { 01772 *(u8_t*)optval = 0; 01773 } 01774 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", 01775 s, *(int *)optval)); 01776 break; 01777 #endif /* LWIP_IGMP */ 01778 default: 01779 LWIP_ASSERT("unhandled optname", 0); 01780 break; 01781 } /* switch (optname) */ 01782 break; 01783 01784 #if LWIP_TCP 01785 /* Level: IPPROTO_TCP */ 01786 case IPPROTO_TCP: 01787 switch (optname) { 01788 case TCP_NODELAY: 01789 *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp); 01790 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", 01791 s, (*(int*)optval)?"on":"off") ); 01792 break; 01793 case TCP_KEEPALIVE: 01794 *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle; 01795 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", 01796 s, *(int *)optval)); 01797 break; 01798 01799 #if LWIP_TCP_KEEPALIVE 01800 case TCP_KEEPIDLE: 01801 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000); 01802 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n", 01803 s, *(int *)optval)); 01804 break; 01805 case TCP_KEEPINTVL: 01806 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000); 01807 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n", 01808 s, *(int *)optval)); 01809 break; 01810 case TCP_KEEPCNT: 01811 *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt; 01812 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n", 01813 s, *(int *)optval)); 01814 break; 01815 #endif /* LWIP_TCP_KEEPALIVE */ 01816 default: 01817 LWIP_ASSERT("unhandled optname", 0); 01818 break; 01819 } /* switch (optname) */ 01820 break; 01821 #endif /* LWIP_TCP */ 01822 #if LWIP_UDP && LWIP_UDPLITE 01823 /* Level: IPPROTO_UDPLITE */ 01824 case IPPROTO_UDPLITE: 01825 switch (optname) { 01826 case UDPLITE_SEND_CSCOV: 01827 *(int*)optval = sock->conn->pcb.udp->chksum_len_tx; 01828 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", 01829 s, (*(int*)optval)) ); 01830 break; 01831 case UDPLITE_RECV_CSCOV: 01832 *(int*)optval = sock->conn->pcb.udp->chksum_len_rx; 01833 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", 01834 s, (*(int*)optval)) ); 01835 break; 01836 default: 01837 LWIP_ASSERT("unhandled optname", 0); 01838 break; 01839 } /* switch (optname) */ 01840 break; 01841 #endif /* LWIP_UDP */ 01842 default: 01843 LWIP_ASSERT("unhandled level", 0); 01844 break; 01845 } /* switch (level) */ 01846 sys_sem_signal(&sock->conn->op_completed); 01847 } 01848 01849 int 01850 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) 01851 { 01852 struct lwip_sock *sock = get_socket(s); 01853 err_t err = ERR_OK; 01854 struct lwip_setgetsockopt_data data; 01855 01856 if (!sock) { 01857 return -1; 01858 } 01859 01860 if (NULL == optval) { 01861 sock_set_errno(sock, EFAULT); 01862 return -1; 01863 } 01864 01865 /* Do length and type checks for the various options first, to keep it readable. */ 01866 switch (level) { 01867 01868 /* Level: SOL_SOCKET */ 01869 case SOL_SOCKET: 01870 switch (optname) { 01871 01872 case SO_BROADCAST: 01873 /* UNIMPL case SO_DEBUG: */ 01874 /* UNIMPL case SO_DONTROUTE: */ 01875 case SO_KEEPALIVE: 01876 /* UNIMPL case case SO_CONTIMEO: */ 01877 /* UNIMPL case case SO_SNDTIMEO: */ 01878 #if LWIP_SO_RCVTIMEO 01879 case SO_RCVTIMEO: 01880 #endif /* LWIP_SO_RCVTIMEO */ 01881 #if LWIP_SO_RCVBUF 01882 case SO_RCVBUF: 01883 #endif /* LWIP_SO_RCVBUF */ 01884 /* UNIMPL case SO_OOBINLINE: */ 01885 /* UNIMPL case SO_SNDBUF: */ 01886 /* UNIMPL case SO_RCVLOWAT: */ 01887 /* UNIMPL case SO_SNDLOWAT: */ 01888 #if SO_REUSE 01889 case SO_REUSEADDR: 01890 case SO_REUSEPORT: 01891 #endif /* SO_REUSE */ 01892 /* UNIMPL case SO_USELOOPBACK: */ 01893 if (optlen < sizeof(int)) { 01894 err = EINVAL; 01895 } 01896 break; 01897 case SO_NO_CHECK: 01898 if (optlen < sizeof(int)) { 01899 err = EINVAL; 01900 } 01901 #if LWIP_UDP 01902 if ((sock->conn->type != NETCONN_UDP) || 01903 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { 01904 /* this flag is only available for UDP, not for UDP lite */ 01905 err = EAFNOSUPPORT; 01906 } 01907 #endif /* LWIP_UDP */ 01908 break; 01909 default: 01910 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", 01911 s, optname)); 01912 err = ENOPROTOOPT; 01913 } /* switch (optname) */ 01914 break; 01915 01916 /* Level: IPPROTO_IP */ 01917 case IPPROTO_IP: 01918 switch (optname) { 01919 /* UNIMPL case IP_HDRINCL: */ 01920 /* UNIMPL case IP_RCVDSTADDR: */ 01921 /* UNIMPL case IP_RCVIF: */ 01922 case IP_TTL: 01923 case IP_TOS: 01924 if (optlen < sizeof(int)) { 01925 err = EINVAL; 01926 } 01927 break; 01928 #if LWIP_IGMP 01929 case IP_MULTICAST_TTL: 01930 if (optlen < sizeof(u8_t)) { 01931 err = EINVAL; 01932 } 01933 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { 01934 err = EAFNOSUPPORT; 01935 } 01936 break; 01937 case IP_MULTICAST_IF: 01938 if (optlen < sizeof(struct in_addr)) { 01939 err = EINVAL; 01940 } 01941 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { 01942 err = EAFNOSUPPORT; 01943 } 01944 break; 01945 case IP_MULTICAST_LOOP: 01946 if (optlen < sizeof(u8_t)) { 01947 err = EINVAL; 01948 } 01949 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { 01950 err = EAFNOSUPPORT; 01951 } 01952 break; 01953 case IP_ADD_MEMBERSHIP: 01954 case IP_DROP_MEMBERSHIP: 01955 if (optlen < sizeof(struct ip_mreq)) { 01956 err = EINVAL; 01957 } 01958 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { 01959 err = EAFNOSUPPORT; 01960 } 01961 break; 01962 #endif /* LWIP_IGMP */ 01963 default: 01964 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", 01965 s, optname)); 01966 err = ENOPROTOOPT; 01967 } /* switch (optname) */ 01968 break; 01969 01970 #if LWIP_TCP 01971 /* Level: IPPROTO_TCP */ 01972 case IPPROTO_TCP: 01973 if (optlen < sizeof(int)) { 01974 err = EINVAL; 01975 break; 01976 } 01977 01978 /* If this is no TCP socket, ignore any options. */ 01979 if (sock->conn->type != NETCONN_TCP) 01980 return 0; 01981 01982 switch (optname) { 01983 case TCP_NODELAY: 01984 case TCP_KEEPALIVE: 01985 #if LWIP_TCP_KEEPALIVE 01986 case TCP_KEEPIDLE: 01987 case TCP_KEEPINTVL: 01988 case TCP_KEEPCNT: 01989 #endif /* LWIP_TCP_KEEPALIVE */ 01990 break; 01991 01992 default: 01993 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", 01994 s, optname)); 01995 err = ENOPROTOOPT; 01996 } /* switch (optname) */ 01997 break; 01998 #endif /* LWIP_TCP */ 01999 #if LWIP_UDP && LWIP_UDPLITE 02000 /* Level: IPPROTO_UDPLITE */ 02001 case IPPROTO_UDPLITE: 02002 if (optlen < sizeof(int)) { 02003 err = EINVAL; 02004 break; 02005 } 02006 02007 /* If this is no UDP lite socket, ignore any options. */ 02008 if (sock->conn->type != NETCONN_UDPLITE) 02009 return 0; 02010 02011 switch (optname) { 02012 case UDPLITE_SEND_CSCOV: 02013 case UDPLITE_RECV_CSCOV: 02014 break; 02015 02016 default: 02017 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", 02018 s, optname)); 02019 err = ENOPROTOOPT; 02020 } /* switch (optname) */ 02021 break; 02022 #endif /* LWIP_UDP && LWIP_UDPLITE */ 02023 /* UNDEFINED LEVEL */ 02024 default: 02025 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", 02026 s, level, optname)); 02027 err = ENOPROTOOPT; 02028 } /* switch (level) */ 02029 02030 02031 if (err != ERR_OK) { 02032 sock_set_errno(sock, err); 02033 return -1; 02034 } 02035 02036 02037 /* Now do the actual option processing */ 02038 data.sock = sock; 02039 #ifdef LWIP_DEBUG 02040 data.s = s; 02041 #endif /* LWIP_DEBUG */ 02042 data.level = level; 02043 data.optname = optname; 02044 data.optval = (void*)optval; 02045 data.optlen = &optlen; 02046 data.err = err; 02047 tcpip_callback(lwip_setsockopt_internal, &data); 02048 sys_arch_sem_wait(&sock->conn->op_completed, 0); 02049 /* maybe lwip_setsockopt_internal has changed err */ 02050 err = data.err; 02051 02052 sock_set_errno(sock, err); 02053 return err ? -1 : 0; 02054 } 02055 02056 static void 02057 lwip_setsockopt_internal(void *arg) 02058 { 02059 struct lwip_sock *sock; 02060 #ifdef LWIP_DEBUG 02061 int s; 02062 #endif /* LWIP_DEBUG */ 02063 int level, optname; 02064 const void *optval; 02065 struct lwip_setgetsockopt_data *data; 02066 02067 LWIP_ASSERT("arg != NULL", arg != NULL); 02068 02069 data = (struct lwip_setgetsockopt_data*)arg; 02070 sock = data->sock; 02071 #ifdef LWIP_DEBUG 02072 s = data->s; 02073 #endif /* LWIP_DEBUG */ 02074 level = data->level; 02075 optname = data->optname; 02076 optval = data->optval; 02077 02078 switch (level) { 02079 02080 /* Level: SOL_SOCKET */ 02081 case SOL_SOCKET: 02082 switch (optname) { 02083 02084 /* The option flags */ 02085 case SO_BROADCAST: 02086 /* UNIMPL case SO_DEBUG: */ 02087 /* UNIMPL case SO_DONTROUTE: */ 02088 case SO_KEEPALIVE: 02089 /* UNIMPL case SO_OOBINCLUDE: */ 02090 #if SO_REUSE 02091 case SO_REUSEADDR: 02092 case SO_REUSEPORT: 02093 #endif /* SO_REUSE */ 02094 /* UNIMPL case SO_USELOOPBACK: */ 02095 if (*(int*)optval) { 02096 sock->conn->pcb.ip->so_options |= optname; 02097 } else { 02098 sock->conn->pcb.ip->so_options &= ~optname; 02099 } 02100 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", 02101 s, optname, (*(int*)optval?"on":"off"))); 02102 break; 02103 #if LWIP_SO_RCVTIMEO 02104 case SO_RCVTIMEO: 02105 netconn_set_recvtimeout(sock->conn, *(int*)optval); 02106 break; 02107 #endif /* LWIP_SO_RCVTIMEO */ 02108 #if LWIP_SO_RCVBUF 02109 case SO_RCVBUF: 02110 netconn_set_recvbufsize(sock->conn, *(int*)optval); 02111 break; 02112 #endif /* LWIP_SO_RCVBUF */ 02113 #if LWIP_UDP 02114 case SO_NO_CHECK: 02115 if (*(int*)optval) { 02116 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM); 02117 } else { 02118 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM); 02119 } 02120 break; 02121 #endif /* LWIP_UDP */ 02122 default: 02123 LWIP_ASSERT("unhandled optname", 0); 02124 break; 02125 } /* switch (optname) */ 02126 break; 02127 02128 /* Level: IPPROTO_IP */ 02129 case IPPROTO_IP: 02130 switch (optname) { 02131 case IP_TTL: 02132 sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval); 02133 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", 02134 s, sock->conn->pcb.ip->ttl)); 02135 break; 02136 case IP_TOS: 02137 sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval); 02138 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", 02139 s, sock->conn->pcb.ip->tos)); 02140 break; 02141 #if LWIP_IGMP 02142 case IP_MULTICAST_TTL: 02143 sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval); 02144 break; 02145 case IP_MULTICAST_IF: 02146 inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval); 02147 break; 02148 case IP_MULTICAST_LOOP: 02149 if (*(u8_t*)optval) { 02150 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP); 02151 } else { 02152 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP); 02153 } 02154 break; 02155 case IP_ADD_MEMBERSHIP: 02156 case IP_DROP_MEMBERSHIP: 02157 { 02158 /* If this is a TCP or a RAW socket, ignore these options. */ 02159 struct ip_mreq *imr = (struct ip_mreq *)optval; 02160 ip_addr_t if_addr; 02161 ip_addr_t multi_addr; 02162 inet_addr_to_ipaddr(&if_addr, &imr->imr_interface); 02163 inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr); 02164 if(optname == IP_ADD_MEMBERSHIP){ 02165 data->err = igmp_joingroup(&if_addr, &multi_addr); 02166 } else { 02167 data->err = igmp_leavegroup(&if_addr, &multi_addr); 02168 } 02169 if(data->err != ERR_OK) { 02170 data->err = EADDRNOTAVAIL; 02171 } 02172 } 02173 break; 02174 #endif /* LWIP_IGMP */ 02175 default: 02176 LWIP_ASSERT("unhandled optname", 0); 02177 break; 02178 } /* switch (optname) */ 02179 break; 02180 02181 #if LWIP_TCP 02182 /* Level: IPPROTO_TCP */ 02183 case IPPROTO_TCP: 02184 switch (optname) { 02185 case TCP_NODELAY: 02186 if (*(int*)optval) { 02187 tcp_nagle_disable(sock->conn->pcb.tcp); 02188 } else { 02189 tcp_nagle_enable(sock->conn->pcb.tcp); 02190 } 02191 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", 02192 s, (*(int *)optval)?"on":"off") ); 02193 break; 02194 case TCP_KEEPALIVE: 02195 sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval); 02196 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", 02197 s, sock->conn->pcb.tcp->keep_idle)); 02198 break; 02199 02200 #if LWIP_TCP_KEEPALIVE 02201 case TCP_KEEPIDLE: 02202 sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval); 02203 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", 02204 s, sock->conn->pcb.tcp->keep_idle)); 02205 break; 02206 case TCP_KEEPINTVL: 02207 sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval); 02208 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", 02209 s, sock->conn->pcb.tcp->keep_intvl)); 02210 break; 02211 case TCP_KEEPCNT: 02212 sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval); 02213 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", 02214 s, sock->conn->pcb.tcp->keep_cnt)); 02215 break; 02216 #endif /* LWIP_TCP_KEEPALIVE */ 02217 default: 02218 LWIP_ASSERT("unhandled optname", 0); 02219 break; 02220 } /* switch (optname) */ 02221 break; 02222 #endif /* LWIP_TCP*/ 02223 #if LWIP_UDP && LWIP_UDPLITE 02224 /* Level: IPPROTO_UDPLITE */ 02225 case IPPROTO_UDPLITE: 02226 switch (optname) { 02227 case UDPLITE_SEND_CSCOV: 02228 if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) { 02229 /* don't allow illegal values! */ 02230 sock->conn->pcb.udp->chksum_len_tx = 8; 02231 } else { 02232 sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval; 02233 } 02234 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", 02235 s, (*(int*)optval)) ); 02236 break; 02237 case UDPLITE_RECV_CSCOV: 02238 if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) { 02239 /* don't allow illegal values! */ 02240 sock->conn->pcb.udp->chksum_len_rx = 8; 02241 } else { 02242 sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval; 02243 } 02244 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", 02245 s, (*(int*)optval)) ); 02246 break; 02247 default: 02248 LWIP_ASSERT("unhandled optname", 0); 02249 break; 02250 } /* switch (optname) */ 02251 break; 02252 #endif /* LWIP_UDP */ 02253 default: 02254 LWIP_ASSERT("unhandled level", 0); 02255 break; 02256 } /* switch (level) */ 02257 sys_sem_signal(&sock->conn->op_completed); 02258 } 02259 02260 int 02261 lwip_ioctl(int s, long cmd, void *argp) 02262 { 02263 struct lwip_sock *sock = get_socket(s); 02264 u8_t val; 02265 #if LWIP_SO_RCVBUF 02266 u16_t buflen = 0; 02267 s16_t recv_avail; 02268 #endif /* LWIP_SO_RCVBUF */ 02269 02270 if (!sock) { 02271 return -1; 02272 } 02273 02274 switch (cmd) { 02275 #if LWIP_SO_RCVBUF 02276 case FIONREAD: 02277 if (!argp) { 02278 sock_set_errno(sock, EINVAL); 02279 return -1; 02280 } 02281 02282 SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); 02283 if (recv_avail < 0) { 02284 recv_avail = 0; 02285 } 02286 *((u16_t*)argp) = (u16_t)recv_avail; 02287 02288 /* Check if there is data left from the last recv operation. /maq 041215 */ 02289 if (sock->lastdata) { 02290 struct pbuf *p = (struct pbuf *)sock->lastdata; 02291 if (netconn_type(sock->conn) != NETCONN_TCP) { 02292 p = ((struct netbuf *)p)->p; 02293 } 02294 buflen = p->tot_len; 02295 buflen -= sock->lastoffset; 02296 02297 *((u16_t*)argp) += buflen; 02298 } 02299 02300 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp))); 02301 sock_set_errno(sock, 0); 02302 return 0; 02303 #endif /* LWIP_SO_RCVBUF */ 02304 02305 case FIONBIO: 02306 val = 0; 02307 if (argp && *(u32_t*)argp) { 02308 val = 1; 02309 } 02310 netconn_set_nonblocking(sock->conn, val); 02311 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); 02312 sock_set_errno(sock, 0); 02313 return 0; 02314 02315 default: 02316 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); 02317 sock_set_errno(sock, ENOSYS); /* not yet implemented */ 02318 return -1; 02319 } /* switch (cmd) */ 02320 } 02321 02322 /** A minimal implementation of fcntl. 02323 * Currently only the commands F_GETFL and F_SETFL are implemented. 02324 * Only the flag O_NONBLOCK is implemented. 02325 */ 02326 int 02327 lwip_fcntl(int s, int cmd, int val) 02328 { 02329 struct lwip_sock *sock = get_socket(s); 02330 int ret = -1; 02331 02332 if (!sock || !sock->conn) { 02333 return -1; 02334 } 02335 02336 switch (cmd) { 02337 case F_GETFL: 02338 ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; 02339 break; 02340 case F_SETFL: 02341 if ((val & ~O_NONBLOCK) == 0) { 02342 /* only O_NONBLOCK, all other bits are zero */ 02343 netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); 02344 ret = 0; 02345 } 02346 break; 02347 default: 02348 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); 02349 break; 02350 } 02351 return ret; 02352 } 02353 02354 #endif /* LWIP_SOCKET */
Generated on Tue Jul 12 2022 21:59:36 by
1.7.2
