Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
lwip_api_lib.c
00001 /** 00002 * @file 00003 * Sequential API External module 00004 * 00005 * @defgroup netconn Netconn API 00006 * @ingroup sequential_api 00007 * Thread-safe, to be called from non-TCPIP threads only. 00008 * TX/RX handling based on @ref netbuf (containing @ref pbuf) 00009 * to avoid copying data around. 00010 * 00011 * @defgroup netconn_common Common functions 00012 * @ingroup netconn 00013 * For use with TCP and UDP 00014 * 00015 * @defgroup netconn_tcp TCP only 00016 * @ingroup netconn 00017 * TCP only functions 00018 * 00019 * @defgroup netconn_udp UDP only 00020 * @ingroup netconn 00021 * UDP only functions 00022 */ 00023 00024 /* 00025 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 00026 * All rights reserved. 00027 * 00028 * Redistribution and use in source and binary forms, with or without modification, 00029 * are permitted provided that the following conditions are met: 00030 * 00031 * 1. Redistributions of source code must retain the above copyright notice, 00032 * this list of conditions and the following disclaimer. 00033 * 2. Redistributions in binary form must reproduce the above copyright notice, 00034 * this list of conditions and the following disclaimer in the documentation 00035 * and/or other materials provided with the distribution. 00036 * 3. The name of the author may not be used to endorse or promote products 00037 * derived from this software without specific prior written permission. 00038 * 00039 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00040 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00041 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00042 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00043 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00044 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00045 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00046 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00047 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00048 * OF SUCH DAMAGE. 00049 * 00050 * This file is part of the lwIP TCP/IP stack. 00051 * 00052 * Author: Adam Dunkels <adam@sics.se> 00053 */ 00054 00055 /* This is the part of the API that is linked with 00056 the application */ 00057 00058 #include "lwip/opt.h" 00059 00060 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ 00061 00062 #include "lwip/api.h" 00063 #include "lwip/memp.h" 00064 00065 #include "lwip/ip.h" 00066 #include "lwip/raw.h" 00067 #include "lwip/udp.h" 00068 #include "lwip/priv/api_msg.h" 00069 #include "lwip/priv/tcp_priv.h" 00070 #include "lwip/priv/tcpip_priv.h" 00071 00072 #ifdef LWIP_HOOK_FILENAME 00073 #include LWIP_HOOK_FILENAME 00074 #endif 00075 00076 #include <string.h> 00077 00078 #define API_MSG_VAR_REF(name) API_VAR_REF(name) 00079 #define API_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct api_msg, name) 00080 #define API_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, ERR_MEM) 00081 #define API_MSG_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, NULL) 00082 #define API_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_API_MSG, name) 00083 00084 #if TCP_LISTEN_BACKLOG 00085 /* need to allocate API message for accept so empty message pool does not result in event loss 00086 * see bug #47512: MPU_COMPATIBLE may fail on empty pool */ 00087 #define API_MSG_VAR_ALLOC_ACCEPT(msg) API_MSG_VAR_ALLOC(msg) 00088 #define API_MSG_VAR_FREE_ACCEPT(msg) API_MSG_VAR_FREE(msg) 00089 #else /* TCP_LISTEN_BACKLOG */ 00090 #define API_MSG_VAR_ALLOC_ACCEPT(msg) 00091 #define API_MSG_VAR_FREE_ACCEPT(msg) 00092 #endif /* TCP_LISTEN_BACKLOG */ 00093 00094 #if LWIP_NETCONN_FULLDUPLEX 00095 #define NETCONN_RECVMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->recvmbox) && (((conn)->flags & NETCONN_FLAG_MBOXINVALID) == 0)) 00096 #define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & (NETCONN_FLAG_MBOXCLOSED|NETCONN_FLAG_MBOXINVALID)) == 0)) 00097 #define NETCONN_MBOX_WAITING_INC(conn) SYS_ARCH_INC(conn->mbox_threads_waiting, 1) 00098 #define NETCONN_MBOX_WAITING_DEC(conn) SYS_ARCH_DEC(conn->mbox_threads_waiting, 1) 00099 #else /* LWIP_NETCONN_FULLDUPLEX */ 00100 #define NETCONN_RECVMBOX_WAITABLE(conn) sys_mbox_valid(&(conn)->recvmbox) 00101 #define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & NETCONN_FLAG_MBOXCLOSED) == 0)) 00102 #define NETCONN_MBOX_WAITING_INC(conn) 00103 #define NETCONN_MBOX_WAITING_DEC(conn) 00104 #endif /* LWIP_NETCONN_FULLDUPLEX */ 00105 00106 static err_t netconn_close_shutdown(struct netconn *conn, u8_t how); 00107 00108 /** 00109 * Call the lower part of a netconn_* function 00110 * This function is then running in the thread context 00111 * of tcpip_thread and has exclusive access to lwIP core code. 00112 * 00113 * @param fn function to call 00114 * @param apimsg a struct containing the function to call and its parameters 00115 * @return ERR_OK if the function was called, another err_t if not 00116 */ 00117 static err_t 00118 netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg) 00119 { 00120 err_t err; 00121 00122 #ifdef LWIP_DEBUG 00123 /* catch functions that don't set err */ 00124 apimsg->err = ERR_VAL; 00125 #endif /* LWIP_DEBUG */ 00126 00127 #if LWIP_NETCONN_SEM_PER_THREAD 00128 apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); 00129 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 00130 00131 if (sys_tcpip_thread_check()) { 00132 fn(apimsg); 00133 return ERR_OK; 00134 } else { 00135 err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg)); 00136 00137 if (err == ERR_OK) { 00138 return apimsg->err; 00139 } 00140 00141 return err; 00142 } 00143 } 00144 00145 /** 00146 * Create a new netconn (of a specific type) that has a callback function. 00147 * The corresponding pcb is also created. 00148 * 00149 * @param t the type of 'connection' to create (@see enum netconn_type) 00150 * @param proto the IP protocol for RAW IP pcbs 00151 * @param callback a function to call on status changes (RX available, TX'ed) 00152 * @return a newly allocated struct netconn or 00153 * NULL on memory error 00154 */ 00155 struct netconn * 00156 netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) 00157 { 00158 struct netconn *conn; 00159 API_MSG_VAR_DECLARE(msg); 00160 API_MSG_VAR_ALLOC_RETURN_NULL(msg); 00161 00162 conn = netconn_alloc(t, callback); 00163 if (conn != NULL) { 00164 err_t err; 00165 00166 API_MSG_VAR_REF(msg).msg.n.proto = proto; 00167 API_MSG_VAR_REF(msg).conn = conn; 00168 err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg)); 00169 if (err != ERR_OK) { 00170 LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); 00171 LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox)); 00172 #if LWIP_TCP 00173 LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox)); 00174 #endif /* LWIP_TCP */ 00175 #if !LWIP_NETCONN_SEM_PER_THREAD 00176 LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed)); 00177 sys_sem_free(&conn->op_completed); 00178 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ 00179 sys_mbox_free(&conn->recvmbox); 00180 memp_free(MEMP_NETCONN, conn); 00181 API_MSG_VAR_FREE(msg); 00182 return NULL; 00183 } 00184 } 00185 API_MSG_VAR_FREE(msg); 00186 return conn; 00187 } 00188 00189 /** 00190 * @ingroup netconn_common 00191 * Close a netconn 'connection' and free all its resources but not the netconn itself. 00192 * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate 00193 * after this returns. 00194 * 00195 * @param conn the netconn to delete 00196 * @return ERR_OK if the connection was deleted 00197 */ 00198 err_t 00199 netconn_prepare_delete(struct netconn *conn) 00200 { 00201 err_t err; 00202 API_MSG_VAR_DECLARE(msg); 00203 00204 /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ 00205 if (conn == NULL) { 00206 return ERR_OK; 00207 } 00208 00209 API_MSG_VAR_ALLOC(msg); 00210 API_MSG_VAR_REF(msg).conn = conn; 00211 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER 00212 /* get the time we started, which is later compared to 00213 sys_now() + conn->send_timeout */ 00214 API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); 00215 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 00216 #if LWIP_TCP 00217 API_MSG_VAR_REF(msg).msg.sd.polls_left = 00218 ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; 00219 #endif /* LWIP_TCP */ 00220 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 00221 err = netconn_apimsg(lwip_netconn_do_delconn, &API_MSG_VAR_REF(msg)); 00222 API_MSG_VAR_FREE(msg); 00223 00224 if (err != ERR_OK) { 00225 return err; 00226 } 00227 return ERR_OK; 00228 } 00229 00230 /** 00231 * @ingroup netconn_common 00232 * Close a netconn 'connection' and free its resources. 00233 * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate 00234 * after this returns. 00235 * 00236 * @param conn the netconn to delete 00237 * @return ERR_OK if the connection was deleted 00238 */ 00239 err_t 00240 netconn_delete(struct netconn *conn) 00241 { 00242 err_t err; 00243 00244 /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ 00245 if (conn == NULL) { 00246 return ERR_OK; 00247 } 00248 00249 #if LWIP_NETCONN_FULLDUPLEX 00250 if (conn->flags & NETCONN_FLAG_MBOXINVALID) { 00251 /* Already called netconn_prepare_delete() before */ 00252 err = ERR_OK; 00253 } else 00254 #endif /* LWIP_NETCONN_FULLDUPLEX */ 00255 { 00256 err = netconn_prepare_delete(conn); 00257 } 00258 if (err == ERR_OK) { 00259 netconn_free(conn); 00260 } 00261 return err; 00262 } 00263 00264 /** 00265 * Get the local or remote IP address and port of a netconn. 00266 * For RAW netconns, this returns the protocol instead of a port! 00267 * 00268 * @param conn the netconn to query 00269 * @param addr a pointer to which to save the IP address 00270 * @param port a pointer to which to save the port (or protocol for RAW) 00271 * @param local 1 to get the local IP address, 0 to get the remote one 00272 * @return ERR_CONN for invalid connections 00273 * ERR_OK if the information was retrieved 00274 */ 00275 err_t 00276 netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) 00277 { 00278 API_MSG_VAR_DECLARE(msg); 00279 err_t err; 00280 00281 LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); 00282 LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); 00283 LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;); 00284 00285 API_MSG_VAR_ALLOC(msg); 00286 API_MSG_VAR_REF(msg).conn = conn; 00287 API_MSG_VAR_REF(msg).msg.ad.local = local; 00288 #if LWIP_MPU_COMPATIBLE 00289 err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg)); 00290 *addr = msg->msg.ad.ipaddr; 00291 *port = msg->msg.ad.port; 00292 #else /* LWIP_MPU_COMPATIBLE */ 00293 msg.msg.ad.ipaddr = addr; 00294 msg.msg.ad.port = port; 00295 err = netconn_apimsg(lwip_netconn_do_getaddr, &msg); 00296 #endif /* LWIP_MPU_COMPATIBLE */ 00297 API_MSG_VAR_FREE(msg); 00298 00299 return err; 00300 } 00301 00302 /** 00303 * @ingroup netconn_common 00304 * Bind a netconn to a specific local IP address and port. 00305 * Binding one netconn twice might not always be checked correctly! 00306 * 00307 * @param conn the netconn to bind 00308 * @param addr the local IP address to bind the netconn to 00309 * (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses) 00310 * @param port the local port to bind the netconn to (not used for RAW) 00311 * @return ERR_OK if bound, any other err_t on failure 00312 */ 00313 err_t 00314 netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) 00315 { 00316 API_MSG_VAR_DECLARE(msg); 00317 err_t err; 00318 00319 LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); 00320 00321 #if LWIP_IPV4 00322 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 00323 if (addr == NULL) { 00324 addr = IP4_ADDR_ANY; 00325 } 00326 #endif /* LWIP_IPV4 */ 00327 00328 #if LWIP_IPV4 && LWIP_IPV6 00329 /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY, 00330 * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind 00331 */ 00332 if ((netconn_get_ipv6only(conn) == 0) && 00333 ip_addr_cmp(addr, IP6_ADDR_ANY)) { 00334 addr = IP_ANY_TYPE; 00335 } 00336 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 00337 00338 API_MSG_VAR_ALLOC(msg); 00339 API_MSG_VAR_REF(msg).conn = conn; 00340 API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); 00341 API_MSG_VAR_REF(msg).msg.bc.port = port; 00342 err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg)); 00343 API_MSG_VAR_FREE(msg); 00344 00345 return err; 00346 } 00347 00348 /** 00349 * @ingroup netconn_common 00350 * Bind a netconn to a specific interface and port. 00351 * Binding one netconn twice might not always be checked correctly! 00352 * 00353 * @param conn the netconn to bind 00354 * @param if_idx the local interface index to bind the netconn to 00355 * @return ERR_OK if bound, any other err_t on failure 00356 */ 00357 err_t 00358 netconn_bind_if(struct netconn *conn, u8_t if_idx) 00359 { 00360 API_MSG_VAR_DECLARE(msg); 00361 err_t err; 00362 00363 LWIP_ERROR("netconn_bind_if: invalid conn", (conn != NULL), return ERR_ARG;); 00364 00365 API_MSG_VAR_ALLOC(msg); 00366 API_MSG_VAR_REF(msg).conn = conn; 00367 API_MSG_VAR_REF(msg).msg.bc.if_idx = if_idx; 00368 err = netconn_apimsg(lwip_netconn_do_bind_if, &API_MSG_VAR_REF(msg)); 00369 API_MSG_VAR_FREE(msg); 00370 00371 return err; 00372 } 00373 00374 /** 00375 * @ingroup netconn_common 00376 * Connect a netconn to a specific remote IP address and port. 00377 * 00378 * @param conn the netconn to connect 00379 * @param addr the remote IP address to connect to 00380 * @param port the remote port to connect to (no used for RAW) 00381 * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise 00382 */ 00383 err_t 00384 netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) 00385 { 00386 API_MSG_VAR_DECLARE(msg); 00387 err_t err; 00388 00389 LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); 00390 00391 #if LWIP_IPV4 00392 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 00393 if (addr == NULL) { 00394 addr = IP4_ADDR_ANY; 00395 } 00396 #endif /* LWIP_IPV4 */ 00397 00398 API_MSG_VAR_ALLOC(msg); 00399 API_MSG_VAR_REF(msg).conn = conn; 00400 API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); 00401 API_MSG_VAR_REF(msg).msg.bc.port = port; 00402 err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg)); 00403 API_MSG_VAR_FREE(msg); 00404 00405 return err; 00406 } 00407 00408 /** 00409 * @ingroup netconn_udp 00410 * Disconnect a netconn from its current peer (only valid for UDP netconns). 00411 * 00412 * @param conn the netconn to disconnect 00413 * @return See @ref err_t 00414 */ 00415 err_t 00416 netconn_disconnect(struct netconn *conn) 00417 { 00418 API_MSG_VAR_DECLARE(msg); 00419 err_t err; 00420 00421 LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); 00422 00423 API_MSG_VAR_ALLOC(msg); 00424 API_MSG_VAR_REF(msg).conn = conn; 00425 err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg)); 00426 API_MSG_VAR_FREE(msg); 00427 00428 return err; 00429 } 00430 00431 /** 00432 * @ingroup netconn_tcp 00433 * Set a TCP netconn into listen mode 00434 * 00435 * @param conn the tcp netconn to set to listen mode 00436 * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1 00437 * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns 00438 * don't return any error (yet?)) 00439 */ 00440 err_t 00441 netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) 00442 { 00443 #if LWIP_TCP 00444 API_MSG_VAR_DECLARE(msg); 00445 err_t err; 00446 00447 /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ 00448 LWIP_UNUSED_ARG(backlog); 00449 00450 LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); 00451 00452 API_MSG_VAR_ALLOC(msg); 00453 API_MSG_VAR_REF(msg).conn = conn; 00454 #if TCP_LISTEN_BACKLOG 00455 API_MSG_VAR_REF(msg).msg.lb.backlog = backlog; 00456 #endif /* TCP_LISTEN_BACKLOG */ 00457 err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg)); 00458 API_MSG_VAR_FREE(msg); 00459 00460 return err; 00461 #else /* LWIP_TCP */ 00462 LWIP_UNUSED_ARG(conn); 00463 LWIP_UNUSED_ARG(backlog); 00464 return ERR_ARG; 00465 #endif /* LWIP_TCP */ 00466 } 00467 00468 /** 00469 * @ingroup netconn_tcp 00470 * Accept a new connection on a TCP listening netconn. 00471 * 00472 * @param conn the TCP listen netconn 00473 * @param new_conn pointer where the new connection is stored 00474 * @return ERR_OK if a new connection has been received or an error 00475 * code otherwise 00476 */ 00477 err_t 00478 netconn_accept(struct netconn *conn, struct netconn **new_conn) 00479 { 00480 #if LWIP_TCP 00481 err_t err; 00482 void *accept_ptr; 00483 struct netconn *newconn; 00484 #if TCP_LISTEN_BACKLOG 00485 API_MSG_VAR_DECLARE(msg); 00486 #endif /* TCP_LISTEN_BACKLOG */ 00487 00488 LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;); 00489 *new_conn = NULL; 00490 LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); 00491 00492 /* NOTE: Although the opengroup spec says a pending error shall be returned to 00493 send/recv/getsockopt(SO_ERROR) only, we return it for listening 00494 connections also, to handle embedded-system errors */ 00495 err = netconn_err(conn); 00496 if (err != ERR_OK) { 00497 /* return pending error */ 00498 return err; 00499 } 00500 if (!NETCONN_ACCEPTMBOX_WAITABLE(conn)) { 00501 /* don't accept if closed: this might block the application task 00502 waiting on acceptmbox forever! */ 00503 return ERR_CLSD; 00504 } 00505 00506 API_MSG_VAR_ALLOC_ACCEPT(msg); 00507 00508 NETCONN_MBOX_WAITING_INC(conn); 00509 if (netconn_is_nonblocking(conn)) { 00510 if (sys_arch_mbox_tryfetch(&conn->acceptmbox, &accept_ptr) == SYS_ARCH_TIMEOUT) { 00511 API_MSG_VAR_FREE_ACCEPT(msg); 00512 NETCONN_MBOX_WAITING_DEC(conn); 00513 return ERR_WOULDBLOCK; 00514 } 00515 } else { 00516 #if LWIP_SO_RCVTIMEO 00517 if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { 00518 API_MSG_VAR_FREE_ACCEPT(msg); 00519 NETCONN_MBOX_WAITING_DEC(conn); 00520 return ERR_TIMEOUT; 00521 } 00522 #else 00523 sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); 00524 #endif /* LWIP_SO_RCVTIMEO*/ 00525 } 00526 NETCONN_MBOX_WAITING_DEC(conn); 00527 #if LWIP_NETCONN_FULLDUPLEX 00528 if (conn->flags & NETCONN_FLAG_MBOXINVALID) { 00529 if (lwip_netconn_is_deallocated_msg(accept_ptr)) { 00530 /* the netconn has been closed from another thread */ 00531 API_MSG_VAR_FREE_ACCEPT(msg); 00532 return ERR_CONN; 00533 } 00534 } 00535 #endif 00536 00537 /* Register event with callback */ 00538 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); 00539 00540 if (lwip_netconn_is_err_msg(accept_ptr, &err)) { 00541 /* a connection has been aborted: e.g. out of pcbs or out of netconns during accept */ 00542 API_MSG_VAR_FREE_ACCEPT(msg); 00543 return err; 00544 } 00545 if (accept_ptr == NULL) { 00546 /* connection has been aborted */ 00547 API_MSG_VAR_FREE_ACCEPT(msg); 00548 return ERR_CLSD; 00549 } 00550 newconn = (struct netconn *)accept_ptr; 00551 #if TCP_LISTEN_BACKLOG 00552 /* Let the stack know that we have accepted the connection. */ 00553 API_MSG_VAR_REF(msg).conn = newconn; 00554 /* don't care for the return value of lwip_netconn_do_recv */ 00555 netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg)); 00556 API_MSG_VAR_FREE(msg); 00557 #endif /* TCP_LISTEN_BACKLOG */ 00558 00559 *new_conn = newconn; 00560 /* don't set conn->last_err: it's only ERR_OK, anyway */ 00561 return ERR_OK; 00562 #else /* LWIP_TCP */ 00563 LWIP_UNUSED_ARG(conn); 00564 LWIP_UNUSED_ARG(new_conn); 00565 return ERR_ARG; 00566 #endif /* LWIP_TCP */ 00567 } 00568 00569 /** 00570 * @ingroup netconn_common 00571 * Receive data: actual implementation that doesn't care whether pbuf or netbuf 00572 * is received (this is internal, it's just here for describing common errors) 00573 * 00574 * @param conn the netconn from which to receive data 00575 * @param new_buf pointer where a new pbuf/netbuf is stored when received data 00576 * @param apiflags flags that control function behaviour. For now only: 00577 * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data 00578 * @return ERR_OK if data has been received, an error code otherwise (timeout, 00579 * memory error or another error) 00580 * ERR_CONN if not connected 00581 * ERR_CLSD if TCP connection has been closed 00582 * ERR_WOULDBLOCK if the netconn is nonblocking but would block to wait for data 00583 * ERR_TIMEOUT if the netconn has a receive timeout and no data was received 00584 */ 00585 static err_t 00586 netconn_recv_data(struct netconn *conn, void **new_buf, u8_t apiflags) 00587 { 00588 void *buf = NULL; 00589 u16_t len; 00590 00591 LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); 00592 *new_buf = NULL; 00593 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); 00594 00595 if (!NETCONN_RECVMBOX_WAITABLE(conn)) { 00596 err_t err = netconn_err(conn); 00597 if (err != ERR_OK) { 00598 /* return pending error */ 00599 return err; 00600 } 00601 return ERR_CONN; 00602 } 00603 00604 NETCONN_MBOX_WAITING_INC(conn); 00605 if (netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK) || 00606 (conn->flags & NETCONN_FLAG_MBOXCLOSED) || (conn->pending_err != ERR_OK)) { 00607 if (sys_arch_mbox_tryfetch(&conn->recvmbox, &buf) == SYS_ARCH_TIMEOUT) { 00608 err_t err; 00609 NETCONN_MBOX_WAITING_DEC(conn); 00610 err = netconn_err(conn); 00611 if (err != ERR_OK) { 00612 /* return pending error */ 00613 return err; 00614 } 00615 if (conn->flags & NETCONN_FLAG_MBOXCLOSED) { 00616 return ERR_CONN; 00617 } 00618 return ERR_WOULDBLOCK; 00619 } 00620 } else { 00621 #if LWIP_SO_RCVTIMEO 00622 if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { 00623 NETCONN_MBOX_WAITING_DEC(conn); 00624 return ERR_TIMEOUT; 00625 } 00626 #else 00627 sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); 00628 #endif /* LWIP_SO_RCVTIMEO*/ 00629 } 00630 NETCONN_MBOX_WAITING_DEC(conn); 00631 #if LWIP_NETCONN_FULLDUPLEX 00632 if (conn->flags & NETCONN_FLAG_MBOXINVALID) { 00633 if (lwip_netconn_is_deallocated_msg(buf)) { 00634 /* the netconn has been closed from another thread */ 00635 API_MSG_VAR_FREE_ACCEPT(msg); 00636 return ERR_CONN; 00637 } 00638 } 00639 #endif 00640 00641 #if LWIP_TCP 00642 #if (LWIP_UDP || LWIP_RAW) 00643 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 00644 #endif /* (LWIP_UDP || LWIP_RAW) */ 00645 { 00646 err_t err; 00647 /* Check if this is an error message or a pbuf */ 00648 if (lwip_netconn_is_err_msg(buf, &err)) { 00649 /* new_buf has been zeroed above already */ 00650 if (err == ERR_CLSD) { 00651 /* connection closed translates to ERR_OK with *new_buf == NULL */ 00652 return ERR_OK; 00653 } 00654 return err; 00655 } 00656 len = ((struct pbuf *)buf)->tot_len; 00657 } 00658 #endif /* LWIP_TCP */ 00659 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW) 00660 else 00661 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ 00662 #if (LWIP_UDP || LWIP_RAW) 00663 { 00664 LWIP_ASSERT("buf != NULL", buf != NULL); 00665 len = netbuf_len((struct netbuf *)buf); 00666 } 00667 #endif /* (LWIP_UDP || LWIP_RAW) */ 00668 00669 #if LWIP_SO_RCVBUF 00670 SYS_ARCH_DEC(conn->recv_avail, len); 00671 #endif /* LWIP_SO_RCVBUF */ 00672 /* Register event with callback */ 00673 API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); 00674 00675 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len)); 00676 00677 *new_buf = buf; 00678 /* don't set conn->last_err: it's only ERR_OK, anyway */ 00679 return ERR_OK; 00680 } 00681 00682 #if LWIP_TCP 00683 static err_t 00684 netconn_tcp_recvd_msg(struct netconn *conn, size_t len, struct api_msg *msg) 00685 { 00686 LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && 00687 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); 00688 00689 msg->conn = conn; 00690 msg->msg.r.len = len; 00691 00692 return netconn_apimsg(lwip_netconn_do_recv, msg); 00693 } 00694 00695 err_t 00696 netconn_tcp_recvd(struct netconn *conn, size_t len) 00697 { 00698 err_t err; 00699 API_MSG_VAR_DECLARE(msg); 00700 LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && 00701 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); 00702 00703 API_MSG_VAR_ALLOC(msg); 00704 err = netconn_tcp_recvd_msg(conn, len, &API_VAR_REF(msg)); 00705 API_MSG_VAR_FREE(msg); 00706 return err; 00707 } 00708 00709 static err_t 00710 netconn_recv_data_tcp(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags) 00711 { 00712 err_t err; 00713 struct pbuf *buf; 00714 API_MSG_VAR_DECLARE(msg); 00715 #if LWIP_MPU_COMPATIBLE 00716 msg = NULL; 00717 #endif 00718 00719 if (!NETCONN_RECVMBOX_WAITABLE(conn)) { 00720 /* This only happens when calling this function more than once *after* receiving FIN */ 00721 return ERR_CONN; 00722 } 00723 if (netconn_is_flag_set(conn, NETCONN_FIN_RX_PENDING)) { 00724 netconn_clear_flags(conn, NETCONN_FIN_RX_PENDING); 00725 goto handle_fin; 00726 } 00727 00728 if (!(apiflags & NETCONN_NOAUTORCVD)) { 00729 /* need to allocate API message here so empty message pool does not result in event loss 00730 * see bug #47512: MPU_COMPATIBLE may fail on empty pool */ 00731 API_MSG_VAR_ALLOC(msg); 00732 } 00733 00734 err = netconn_recv_data(conn, (void **)new_buf, apiflags); 00735 if (err != ERR_OK) { 00736 if (!(apiflags & NETCONN_NOAUTORCVD)) { 00737 API_MSG_VAR_FREE(msg); 00738 } 00739 return err; 00740 } 00741 buf = *new_buf; 00742 if (!(apiflags & NETCONN_NOAUTORCVD)) { 00743 /* Let the stack know that we have taken the data. */ 00744 u16_t len = buf ? buf->tot_len : 1; 00745 /* don't care for the return value of lwip_netconn_do_recv */ 00746 /* @todo: this should really be fixed, e.g. by retrying in poll on error */ 00747 netconn_tcp_recvd_msg(conn, len, &API_VAR_REF(msg)); 00748 API_MSG_VAR_FREE(msg); 00749 } 00750 00751 /* If we are closed, we indicate that we no longer wish to use the socket */ 00752 if (buf == NULL) { 00753 if (apiflags & NETCONN_NOFIN) { 00754 /* received a FIN but the caller cannot handle it right now: 00755 re-enqueue it and return "no data" */ 00756 netconn_set_flags(conn, NETCONN_FIN_RX_PENDING); 00757 return ERR_WOULDBLOCK; 00758 } else { 00759 handle_fin: 00760 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); 00761 if (conn->pcb.ip == NULL) { 00762 /* race condition: RST during recv */ 00763 err = netconn_err(conn); 00764 if (err != ERR_OK) { 00765 return err; 00766 } 00767 return ERR_RST; 00768 } 00769 /* RX side is closed, so deallocate the recvmbox */ 00770 netconn_close_shutdown(conn, NETCONN_SHUT_RD); 00771 /* Don' store ERR_CLSD as conn->err since we are only half-closed */ 00772 return ERR_CLSD; 00773 } 00774 } 00775 return err; 00776 } 00777 00778 /** 00779 * @ingroup netconn_tcp 00780 * Receive data (in form of a pbuf) from a TCP netconn 00781 * 00782 * @param conn the netconn from which to receive data 00783 * @param new_buf pointer where a new pbuf is stored when received data 00784 * @return ERR_OK if data has been received, an error code otherwise (timeout, 00785 * memory error or another error, @see netconn_recv_data) 00786 * ERR_ARG if conn is not a TCP netconn 00787 */ 00788 err_t 00789 netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) 00790 { 00791 LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && 00792 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); 00793 00794 return netconn_recv_data_tcp(conn, new_buf, 0); 00795 } 00796 00797 /** 00798 * @ingroup netconn_tcp 00799 * Receive data (in form of a pbuf) from a TCP netconn 00800 * 00801 * @param conn the netconn from which to receive data 00802 * @param new_buf pointer where a new pbuf is stored when received data 00803 * @param apiflags flags that control function behaviour. For now only: 00804 * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data 00805 * @return ERR_OK if data has been received, an error code otherwise (timeout, 00806 * memory error or another error, @see netconn_recv_data) 00807 * ERR_ARG if conn is not a TCP netconn 00808 */ 00809 err_t 00810 netconn_recv_tcp_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags) 00811 { 00812 LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && 00813 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); 00814 00815 return netconn_recv_data_tcp(conn, new_buf, apiflags); 00816 } 00817 #endif /* LWIP_TCP */ 00818 00819 /** 00820 * Receive data (in form of a netbuf) from a UDP or RAW netconn 00821 * 00822 * @param conn the netconn from which to receive data 00823 * @param new_buf pointer where a new netbuf is stored when received data 00824 * @return ERR_OK if data has been received, an error code otherwise (timeout, 00825 * memory error or another error) 00826 * ERR_ARG if conn is not a UDP/RAW netconn 00827 */ 00828 err_t 00829 netconn_recv_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf) 00830 { 00831 LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) && 00832 NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;); 00833 00834 return netconn_recv_data(conn, (void **)new_buf, 0); 00835 } 00836 00837 /** 00838 * Receive data (in form of a netbuf) from a UDP or RAW netconn 00839 * 00840 * @param conn the netconn from which to receive data 00841 * @param new_buf pointer where a new netbuf is stored when received data 00842 * @param apiflags flags that control function behaviour. For now only: 00843 * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data 00844 * @return ERR_OK if data has been received, an error code otherwise (timeout, 00845 * memory error or another error) 00846 * ERR_ARG if conn is not a UDP/RAW netconn 00847 */ 00848 err_t 00849 netconn_recv_udp_raw_netbuf_flags(struct netconn *conn, struct netbuf **new_buf, u8_t apiflags) 00850 { 00851 LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) && 00852 NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;); 00853 00854 return netconn_recv_data(conn, (void **)new_buf, apiflags); 00855 } 00856 00857 /** 00858 * @ingroup netconn_common 00859 * Receive data (in form of a netbuf containing a packet buffer) from a netconn 00860 * 00861 * @param conn the netconn from which to receive data 00862 * @param new_buf pointer where a new netbuf is stored when received data 00863 * @return ERR_OK if data has been received, an error code otherwise (timeout, 00864 * memory error or another error) 00865 */ 00866 err_t 00867 netconn_recv(struct netconn *conn, struct netbuf **new_buf) 00868 { 00869 #if LWIP_TCP 00870 struct netbuf *buf = NULL; 00871 err_t err; 00872 #endif /* LWIP_TCP */ 00873 00874 LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); 00875 *new_buf = NULL; 00876 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); 00877 00878 #if LWIP_TCP 00879 #if (LWIP_UDP || LWIP_RAW) 00880 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 00881 #endif /* (LWIP_UDP || LWIP_RAW) */ 00882 { 00883 struct pbuf *p = NULL; 00884 /* This is not a listening netconn, since recvmbox is set */ 00885 00886 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 00887 if (buf == NULL) { 00888 return ERR_MEM; 00889 } 00890 00891 err = netconn_recv_data_tcp(conn, &p, 0); 00892 if (err != ERR_OK) { 00893 memp_free(MEMP_NETBUF, buf); 00894 return err; 00895 } 00896 LWIP_ASSERT("p != NULL", p != NULL); 00897 00898 buf->p = p; 00899 buf->ptr = p; 00900 buf->port = 0; 00901 ip_addr_set_zero(&buf->addr); 00902 *new_buf = buf; 00903 /* don't set conn->last_err: it's only ERR_OK, anyway */ 00904 return ERR_OK; 00905 } 00906 #endif /* LWIP_TCP */ 00907 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW) 00908 else 00909 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ 00910 { 00911 #if (LWIP_UDP || LWIP_RAW) 00912 return netconn_recv_data(conn, (void **)new_buf, 0); 00913 #endif /* (LWIP_UDP || LWIP_RAW) */ 00914 } 00915 } 00916 00917 /** 00918 * @ingroup netconn_udp 00919 * Send data (in form of a netbuf) to a specific remote IP address and port. 00920 * Only to be used for UDP and RAW netconns (not TCP). 00921 * 00922 * @param conn the netconn over which to send data 00923 * @param buf a netbuf containing the data to send 00924 * @param addr the remote IP address to which to send the data 00925 * @param port the remote port to which to send the data 00926 * @return ERR_OK if data was sent, any other err_t on error 00927 */ 00928 err_t 00929 netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port) 00930 { 00931 if (buf != NULL) { 00932 ip_addr_set(&buf->addr, addr); 00933 buf->port = port; 00934 return netconn_send(conn, buf); 00935 } 00936 return ERR_VAL; 00937 } 00938 00939 /** 00940 * @ingroup netconn_udp 00941 * Send data over a UDP or RAW netconn (that is already connected). 00942 * 00943 * @param conn the UDP or RAW netconn over which to send data 00944 * @param buf a netbuf containing the data to send 00945 * @return ERR_OK if data was sent, any other err_t on error 00946 */ 00947 err_t 00948 netconn_send(struct netconn *conn, struct netbuf *buf) 00949 { 00950 API_MSG_VAR_DECLARE(msg); 00951 err_t err; 00952 00953 LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); 00954 00955 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); 00956 00957 API_MSG_VAR_ALLOC(msg); 00958 API_MSG_VAR_REF(msg).conn = conn; 00959 API_MSG_VAR_REF(msg).msg.b = buf; 00960 err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg)); 00961 API_MSG_VAR_FREE(msg); 00962 00963 return err; 00964 } 00965 00966 /** 00967 * @ingroup netconn_tcp 00968 * Send data over a TCP netconn. 00969 * 00970 * @param conn the TCP netconn over which to send data 00971 * @param dataptr pointer to the application buffer that contains the data to send 00972 * @param size size of the application data to send 00973 * @param apiflags combination of following flags : 00974 * - NETCONN_COPY: data will be copied into memory belonging to the stack 00975 * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent 00976 * - NETCONN_DONTBLOCK: only write the data if all data can be written at once 00977 * @param bytes_written pointer to a location that receives the number of written bytes 00978 * @return ERR_OK if data was sent, any other err_t on error 00979 */ 00980 err_t 00981 netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, 00982 u8_t apiflags, size_t *bytes_written) 00983 { 00984 struct netvector vector; 00985 vector.ptr = dataptr; 00986 vector.len = size; 00987 return netconn_write_vectors_partly(conn, &vector, 1, apiflags, bytes_written); 00988 } 00989 00990 /** 00991 * Send vectorized data atomically over a TCP netconn. 00992 * 00993 * @param conn the TCP netconn over which to send data 00994 * @param vectors array of vectors containing data to send 00995 * @param vectorcnt number of vectors in the array 00996 * @param apiflags combination of following flags : 00997 * - NETCONN_COPY: data will be copied into memory belonging to the stack 00998 * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent 00999 * - NETCONN_DONTBLOCK: only write the data if all data can be written at once 01000 * @param bytes_written pointer to a location that receives the number of written bytes 01001 * @return ERR_OK if data was sent, any other err_t on error 01002 */ 01003 err_t 01004 netconn_write_vectors_partly(struct netconn *conn, struct netvector *vectors, u16_t vectorcnt, 01005 u8_t apiflags, size_t *bytes_written) 01006 { 01007 API_MSG_VAR_DECLARE(msg); 01008 err_t err; 01009 u8_t dontblock; 01010 size_t size; 01011 int i; 01012 01013 LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); 01014 LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP), return ERR_VAL;); 01015 dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); 01016 #if LWIP_SO_SNDTIMEO 01017 if (conn->send_timeout != 0) { 01018 dontblock = 1; 01019 } 01020 #endif /* LWIP_SO_SNDTIMEO */ 01021 if (dontblock && !bytes_written) { 01022 /* This implies netconn_write() cannot be used for non-blocking send, since 01023 it has no way to return the number of bytes written. */ 01024 return ERR_VAL; 01025 } 01026 01027 /* sum up the total size */ 01028 size = 0; 01029 for (i = 0; i < vectorcnt; i++) { 01030 size += vectors[i].len; 01031 if (size < vectors[i].len) { 01032 /* overflow */ 01033 return ERR_VAL; 01034 } 01035 } 01036 if (size == 0) { 01037 return ERR_OK; 01038 } else if (size > SSIZE_MAX) { 01039 ssize_t limited; 01040 /* this is required by the socket layer (cannot send full size_t range) */ 01041 if (!bytes_written) { 01042 return ERR_VAL; 01043 } 01044 /* limit the amount of data to send */ 01045 limited = SSIZE_MAX; 01046 size = (size_t)limited; 01047 } 01048 01049 API_MSG_VAR_ALLOC(msg); 01050 /* non-blocking write sends as much */ 01051 API_MSG_VAR_REF(msg).conn = conn; 01052 API_MSG_VAR_REF(msg).msg.w.vector = vectors; 01053 API_MSG_VAR_REF(msg).msg.w.vector_cnt = vectorcnt; 01054 API_MSG_VAR_REF(msg).msg.w.vector_off = 0; 01055 API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags; 01056 API_MSG_VAR_REF(msg).msg.w.len = size; 01057 API_MSG_VAR_REF(msg).msg.w.offset = 0; 01058 #if LWIP_SO_SNDTIMEO 01059 if (conn->send_timeout != 0) { 01060 /* get the time we started, which is later compared to 01061 sys_now() + conn->send_timeout */ 01062 API_MSG_VAR_REF(msg).msg.w.time_started = sys_now(); 01063 } else { 01064 API_MSG_VAR_REF(msg).msg.w.time_started = 0; 01065 } 01066 #endif /* LWIP_SO_SNDTIMEO */ 01067 01068 /* For locking the core: this _can_ be delayed on low memory/low send buffer, 01069 but if it is, this is done inside api_msg.c:do_write(), so we can use the 01070 non-blocking version here. */ 01071 err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg)); 01072 if (err == ERR_OK) { 01073 if (bytes_written != NULL) { 01074 *bytes_written = API_MSG_VAR_REF(msg).msg.w.offset; 01075 } 01076 /* for blocking, check all requested bytes were written, NOTE: send_timeout is 01077 treated as dontblock (see dontblock assignment above) */ 01078 if (!dontblock) { 01079 LWIP_ASSERT("do_write failed to write all bytes", API_MSG_VAR_REF(msg).msg.w.offset == size); 01080 } 01081 } 01082 API_MSG_VAR_FREE(msg); 01083 01084 return err; 01085 } 01086 01087 /** 01088 * @ingroup netconn_tcp 01089 * Close or shutdown a TCP netconn (doesn't delete it). 01090 * 01091 * @param conn the TCP netconn to close or shutdown 01092 * @param how fully close or only shutdown one side? 01093 * @return ERR_OK if the netconn was closed, any other err_t on error 01094 */ 01095 static err_t 01096 netconn_close_shutdown(struct netconn *conn, u8_t how) 01097 { 01098 API_MSG_VAR_DECLARE(msg); 01099 err_t err; 01100 LWIP_UNUSED_ARG(how); 01101 01102 LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); 01103 01104 API_MSG_VAR_ALLOC(msg); 01105 API_MSG_VAR_REF(msg).conn = conn; 01106 #if LWIP_TCP 01107 /* shutting down both ends is the same as closing */ 01108 API_MSG_VAR_REF(msg).msg.sd.shut = how; 01109 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER 01110 /* get the time we started, which is later compared to 01111 sys_now() + conn->send_timeout */ 01112 API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); 01113 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 01114 API_MSG_VAR_REF(msg).msg.sd.polls_left = 01115 ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; 01116 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 01117 #endif /* LWIP_TCP */ 01118 err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg)); 01119 API_MSG_VAR_FREE(msg); 01120 01121 return err; 01122 } 01123 01124 /** 01125 * @ingroup netconn_tcp 01126 * Close a TCP netconn (doesn't delete it). 01127 * 01128 * @param conn the TCP netconn to close 01129 * @return ERR_OK if the netconn was closed, any other err_t on error 01130 */ 01131 err_t 01132 netconn_close(struct netconn *conn) 01133 { 01134 /* shutting down both ends is the same as closing */ 01135 return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR); 01136 } 01137 01138 /** 01139 * @ingroup netconn_common 01140 * Get and reset pending error on a netconn 01141 * 01142 * @param conn the netconn to get the error from 01143 * @return and pending error or ERR_OK if no error was pending 01144 */ 01145 err_t 01146 netconn_err(struct netconn *conn) 01147 { 01148 err_t err; 01149 SYS_ARCH_DECL_PROTECT(lev); 01150 if (conn == NULL) { 01151 return ERR_OK; 01152 } 01153 SYS_ARCH_PROTECT(lev); 01154 err = conn->pending_err; 01155 conn->pending_err = ERR_OK; 01156 SYS_ARCH_UNPROTECT(lev); 01157 return err; 01158 } 01159 01160 /** 01161 * @ingroup netconn_tcp 01162 * Shut down one or both sides of a TCP netconn (doesn't delete it). 01163 * 01164 * @param conn the TCP netconn to shut down 01165 * @param shut_rx shut down the RX side (no more read possible after this) 01166 * @param shut_tx shut down the TX side (no more write possible after this) 01167 * @return ERR_OK if the netconn was closed, any other err_t on error 01168 */ 01169 err_t 01170 netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx) 01171 { 01172 return netconn_close_shutdown(conn, (u8_t)((shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0))); 01173 } 01174 01175 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) 01176 /** 01177 * @ingroup netconn_udp 01178 * Join multicast groups for UDP netconns. 01179 * 01180 * @param conn the UDP netconn for which to change multicast addresses 01181 * @param multiaddr IP address of the multicast group to join or leave 01182 * @param netif_addr the IP address of the network interface on which to send 01183 * the igmp message 01184 * @param join_or_leave flag whether to send a join- or leave-message 01185 * @return ERR_OK if the action was taken, any err_t on error 01186 */ 01187 err_t 01188 netconn_join_leave_group(struct netconn *conn, 01189 const ip_addr_t *multiaddr, 01190 const ip_addr_t *netif_addr, 01191 enum netconn_igmp join_or_leave) 01192 { 01193 API_MSG_VAR_DECLARE(msg); 01194 err_t err; 01195 01196 LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); 01197 01198 API_MSG_VAR_ALLOC(msg); 01199 01200 #if LWIP_IPV4 01201 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 01202 if (multiaddr == NULL) { 01203 multiaddr = IP4_ADDR_ANY; 01204 } 01205 if (netif_addr == NULL) { 01206 netif_addr = IP4_ADDR_ANY; 01207 } 01208 #endif /* LWIP_IPV4 */ 01209 01210 API_MSG_VAR_REF(msg).conn = conn; 01211 API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr); 01212 API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr); 01213 API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave; 01214 err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg)); 01215 API_MSG_VAR_FREE(msg); 01216 01217 return err; 01218 } 01219 /** 01220 * @ingroup netconn_udp 01221 * Join multicast groups for UDP netconns. 01222 * 01223 * @param conn the UDP netconn for which to change multicast addresses 01224 * @param multiaddr IP address of the multicast group to join or leave 01225 * @param if_idx the index of the netif 01226 * @param join_or_leave flag whether to send a join- or leave-message 01227 * @return ERR_OK if the action was taken, any err_t on error 01228 */ 01229 err_t 01230 netconn_join_leave_group_netif(struct netconn *conn, 01231 const ip_addr_t *multiaddr, 01232 u8_t if_idx, 01233 enum netconn_igmp join_or_leave) 01234 { 01235 API_MSG_VAR_DECLARE(msg); 01236 err_t err; 01237 01238 LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); 01239 01240 API_MSG_VAR_ALLOC(msg); 01241 01242 #if LWIP_IPV4 01243 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 01244 if (multiaddr == NULL) { 01245 multiaddr = IP4_ADDR_ANY; 01246 } 01247 if (if_idx == NETIF_NO_INDEX) { 01248 return ERR_IF; 01249 } 01250 #endif /* LWIP_IPV4 */ 01251 01252 API_MSG_VAR_REF(msg).conn = conn; 01253 API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr); 01254 API_MSG_VAR_REF(msg).msg.jl.if_idx = if_idx; 01255 API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave; 01256 err = netconn_apimsg(lwip_netconn_do_join_leave_group_netif, &API_MSG_VAR_REF(msg)); 01257 API_MSG_VAR_FREE(msg); 01258 01259 return err; 01260 } 01261 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ 01262 01263 #if LWIP_DNS 01264 #if LWIP_FULL_DNS 01265 01266 /** 01267 * @ingroup netconn_common 01268 * Execute a DNS query, only one IP address is returned 01269 * 01270 * @param name a string representation of the DNS host name to query 01271 * @param addr a preallocated ip_addr_t where to store the resolved IP address 01272 * @param dns_addrtype IP address type (IPv4 / IPv6) 01273 * @return ERR_OK: resolving succeeded 01274 * ERR_MEM: memory error, try again later 01275 * ERR_ARG: dns client not initialized or invalid hostname 01276 * ERR_VAL: dns server response was invalid 01277 */ 01278 #if LWIP_IPV4 && LWIP_IPV6 01279 err_t 01280 netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype) 01281 #else 01282 err_t 01283 netconn_gethostbyname(const char *name, ip_addr_t *addr) 01284 #endif 01285 { 01286 API_VAR_DECLARE(struct dns_api_msg, msg); 01287 #if !LWIP_MPU_COMPATIBLE 01288 sys_sem_t sem; 01289 #endif /* LWIP_MPU_COMPATIBLE */ 01290 err_t err; 01291 err_t cberr; 01292 01293 LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); 01294 LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); 01295 #if LWIP_MPU_COMPATIBLE 01296 if (strlen(name) >= DNS_MAX_NAME_LENGTH) { 01297 return ERR_ARG; 01298 } 01299 #endif 01300 01301 #ifdef LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE 01302 #if LWIP_IPV4 && LWIP_IPV6 01303 if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, dns_addrtype, &err)) { 01304 #else 01305 if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, NETCONN_DNS_DEFAULT, &err)) { 01306 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 01307 return err; 01308 } 01309 #endif /* LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE */ 01310 01311 API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM); 01312 #if LWIP_MPU_COMPATIBLE 01313 strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH - 1); 01314 API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH - 1] = 0; 01315 #else /* LWIP_MPU_COMPATIBLE */ 01316 msg.err = &err; 01317 msg.sem = &sem; 01318 API_VAR_REF(msg).addr = API_VAR_REF(addr); 01319 API_VAR_REF(msg).name = name; 01320 #endif /* LWIP_MPU_COMPATIBLE */ 01321 #if LWIP_IPV4 && LWIP_IPV6 01322 API_VAR_REF(msg).dns_addrtype = dns_addrtype; 01323 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 01324 #if LWIP_NETCONN_SEM_PER_THREAD 01325 API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET(); 01326 #else /* LWIP_NETCONN_SEM_PER_THREAD*/ 01327 err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0); 01328 if (err != ERR_OK) { 01329 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 01330 return err; 01331 } 01332 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 01333 01334 cberr = tcpip_send_msg_wait_sem(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg), API_EXPR_REF(API_VAR_REF(msg).sem)); 01335 #if !LWIP_NETCONN_SEM_PER_THREAD 01336 sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); 01337 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ 01338 if (cberr != ERR_OK) { 01339 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 01340 return cberr; 01341 } 01342 01343 #if LWIP_MPU_COMPATIBLE 01344 *addr = msg->addr; 01345 err = msg->err; 01346 #endif /* LWIP_MPU_COMPATIBLE */ 01347 01348 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 01349 return err; 01350 } 01351 01352 #endif /* LWIP_FULL_DNS */ 01353 #endif /* LWIP_DNS*/ 01354 01355 #if LWIP_NETCONN_SEM_PER_THREAD 01356 void 01357 netconn_thread_init(void) 01358 { 01359 sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); 01360 if ((sem == NULL) || !sys_sem_valid(sem)) { 01361 /* call alloc only once */ 01362 LWIP_NETCONN_THREAD_SEM_ALLOC(); 01363 LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET())); 01364 } 01365 } 01366 01367 void 01368 netconn_thread_cleanup(void) 01369 { 01370 sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); 01371 if ((sem != NULL) && sys_sem_valid(sem)) { 01372 /* call free only once */ 01373 LWIP_NETCONN_THREAD_SEM_FREE(); 01374 } 01375 } 01376 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 01377 01378 #endif /* LWIP_NETCONN */
Generated on Tue Jul 12 2022 13:54:27 by
