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.
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 #include <string.h> 00073 00074 #define API_MSG_VAR_REF(name) API_VAR_REF(name) 00075 #define API_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct api_msg, name) 00076 #define API_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, ERR_MEM) 00077 #define API_MSG_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, NULL) 00078 #define API_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_API_MSG, name) 00079 00080 static err_t netconn_close_shutdown(struct netconn *conn, u8_t how); 00081 00082 /** 00083 * Call the lower part of a netconn_* function 00084 * This function is then running in the thread context 00085 * of tcpip_thread and has exclusive access to lwIP core code. 00086 * 00087 * @param fn function to call 00088 * @param apimsg a struct containing the function to call and its parameters 00089 * @return ERR_OK if the function was called, another err_t if not 00090 */ 00091 static err_t 00092 netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg) 00093 { 00094 err_t err; 00095 00096 #ifdef LWIP_DEBUG 00097 /* catch functions that don't set err */ 00098 apimsg->err = ERR_VAL; 00099 #endif /* LWIP_DEBUG */ 00100 00101 #if LWIP_NETCONN_SEM_PER_THREAD 00102 apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); 00103 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 00104 00105 if (sys_tcpip_thread_check()) { 00106 fn(apimsg); 00107 return ERR_OK; 00108 } else { 00109 err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg)); 00110 00111 if (err == ERR_OK) { 00112 return apimsg->err; 00113 } 00114 00115 return err; 00116 } 00117 } 00118 00119 /** 00120 * Create a new netconn (of a specific type) that has a callback function. 00121 * The corresponding pcb is also created. 00122 * 00123 * @param t the type of 'connection' to create (@see enum netconn_type) 00124 * @param proto the IP protocol for RAW IP pcbs 00125 * @param callback a function to call on status changes (RX available, TX'ed) 00126 * @return a newly allocated struct netconn or 00127 * NULL on memory error 00128 */ 00129 struct netconn* 00130 netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) 00131 { 00132 struct netconn *conn; 00133 API_MSG_VAR_DECLARE(msg); 00134 API_MSG_VAR_ALLOC_RETURN_NULL(msg); 00135 00136 conn = netconn_alloc(t, callback); 00137 if (conn != NULL) { 00138 err_t err; 00139 00140 API_MSG_VAR_REF(msg).msg.n.proto = proto; 00141 API_MSG_VAR_REF(msg).conn = conn; 00142 err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg)); 00143 if (err != ERR_OK) { 00144 LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); 00145 LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox)); 00146 #if LWIP_TCP 00147 LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox)); 00148 #endif /* LWIP_TCP */ 00149 #if !LWIP_NETCONN_SEM_PER_THREAD 00150 LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed)); 00151 sys_sem_free(&conn->op_completed); 00152 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ 00153 sys_mbox_free(&conn->recvmbox); 00154 memp_free(MEMP_NETCONN, conn); 00155 API_MSG_VAR_FREE(msg); 00156 return NULL; 00157 } 00158 } 00159 API_MSG_VAR_FREE(msg); 00160 return conn; 00161 } 00162 00163 /** 00164 * @ingroup netconn_common 00165 * Close a netconn 'connection' and free its resources. 00166 * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate 00167 * after this returns. 00168 * 00169 * @param conn the netconn to delete 00170 * @return ERR_OK if the connection was deleted 00171 */ 00172 err_t 00173 netconn_delete(struct netconn *conn) 00174 { 00175 err_t err; 00176 API_MSG_VAR_DECLARE(msg); 00177 00178 /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ 00179 if (conn == NULL) { 00180 return ERR_OK; 00181 } 00182 00183 API_MSG_VAR_ALLOC(msg); 00184 API_MSG_VAR_REF(msg).conn = conn; 00185 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER 00186 /* get the time we started, which is later compared to 00187 sys_now() + conn->send_timeout */ 00188 API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); 00189 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 00190 #if LWIP_TCP 00191 API_MSG_VAR_REF(msg).msg.sd.polls_left = 00192 ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; 00193 #endif /* LWIP_TCP */ 00194 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 00195 err = netconn_apimsg(lwip_netconn_do_delconn, &API_MSG_VAR_REF(msg)); 00196 API_MSG_VAR_FREE(msg); 00197 00198 if (err != ERR_OK) { 00199 return err; 00200 } 00201 00202 netconn_free(conn); 00203 00204 return ERR_OK; 00205 } 00206 00207 /** 00208 * Get the local or remote IP address and port of a netconn. 00209 * For RAW netconns, this returns the protocol instead of a port! 00210 * 00211 * @param conn the netconn to query 00212 * @param addr a pointer to which to save the IP address 00213 * @param port a pointer to which to save the port (or protocol for RAW) 00214 * @param local 1 to get the local IP address, 0 to get the remote one 00215 * @return ERR_CONN for invalid connections 00216 * ERR_OK if the information was retrieved 00217 */ 00218 err_t 00219 netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) 00220 { 00221 API_MSG_VAR_DECLARE(msg); 00222 err_t err; 00223 00224 LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); 00225 LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); 00226 LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;); 00227 00228 API_MSG_VAR_ALLOC(msg); 00229 API_MSG_VAR_REF(msg).conn = conn; 00230 API_MSG_VAR_REF(msg).msg.ad.local = local; 00231 #if LWIP_MPU_COMPATIBLE 00232 err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg)); 00233 *addr = msg->msg.ad.ipaddr; 00234 *port = msg->msg.ad.port; 00235 #else /* LWIP_MPU_COMPATIBLE */ 00236 msg.msg.ad.ipaddr = addr; 00237 msg.msg.ad.port = port; 00238 err = netconn_apimsg(lwip_netconn_do_getaddr, &msg); 00239 #endif /* LWIP_MPU_COMPATIBLE */ 00240 API_MSG_VAR_FREE(msg); 00241 00242 return err; 00243 } 00244 00245 /** 00246 * @ingroup netconn_common 00247 * Bind a netconn to a specific local IP address and port. 00248 * Binding one netconn twice might not always be checked correctly! 00249 * 00250 * @param conn the netconn to bind 00251 * @param addr the local IP address to bind the netconn to 00252 * (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses) 00253 * @param port the local port to bind the netconn to (not used for RAW) 00254 * @return ERR_OK if bound, any other err_t on failure 00255 */ 00256 err_t 00257 netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) 00258 { 00259 API_MSG_VAR_DECLARE(msg); 00260 err_t err; 00261 00262 LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); 00263 00264 #if LWIP_IPV4 00265 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 00266 if (addr == NULL) { 00267 addr = IP4_ADDR_ANY; 00268 } 00269 #endif /* LWIP_IPV4 */ 00270 00271 #if LWIP_IPV4 && LWIP_IPV6 00272 /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY, 00273 * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind 00274 */ 00275 if ((netconn_get_ipv6only(conn) == 0) && 00276 ip_addr_cmp(addr, IP6_ADDR_ANY)) { 00277 addr = IP_ANY_TYPE; 00278 } 00279 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 00280 00281 API_MSG_VAR_ALLOC(msg); 00282 API_MSG_VAR_REF(msg).conn = conn; 00283 API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); 00284 API_MSG_VAR_REF(msg).msg.bc.port = port; 00285 err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg)); 00286 API_MSG_VAR_FREE(msg); 00287 00288 return err; 00289 } 00290 00291 /** 00292 * @ingroup netconn_common 00293 * Connect a netconn to a specific remote IP address and port. 00294 * 00295 * @param conn the netconn to connect 00296 * @param addr the remote IP address to connect to 00297 * @param port the remote port to connect to (no used for RAW) 00298 * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise 00299 */ 00300 err_t 00301 netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) 00302 { 00303 API_MSG_VAR_DECLARE(msg); 00304 err_t err; 00305 00306 LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); 00307 00308 #if LWIP_IPV4 00309 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 00310 if (addr == NULL) { 00311 addr = IP4_ADDR_ANY; 00312 } 00313 #endif /* LWIP_IPV4 */ 00314 00315 API_MSG_VAR_ALLOC(msg); 00316 API_MSG_VAR_REF(msg).conn = conn; 00317 API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); 00318 API_MSG_VAR_REF(msg).msg.bc.port = port; 00319 err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg)); 00320 API_MSG_VAR_FREE(msg); 00321 00322 return err; 00323 } 00324 00325 /** 00326 * @ingroup netconn_udp 00327 * Disconnect a netconn from its current peer (only valid for UDP netconns). 00328 * 00329 * @param conn the netconn to disconnect 00330 * @return See @ref err_t 00331 */ 00332 err_t 00333 netconn_disconnect(struct netconn *conn) 00334 { 00335 API_MSG_VAR_DECLARE(msg); 00336 err_t err; 00337 00338 LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); 00339 00340 API_MSG_VAR_ALLOC(msg); 00341 API_MSG_VAR_REF(msg).conn = conn; 00342 err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg)); 00343 API_MSG_VAR_FREE(msg); 00344 00345 return err; 00346 } 00347 00348 /** 00349 * @ingroup netconn_tcp 00350 * Set a TCP netconn into listen mode 00351 * 00352 * @param conn the tcp netconn to set to listen mode 00353 * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1 00354 * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns 00355 * don't return any error (yet?)) 00356 */ 00357 err_t 00358 netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) 00359 { 00360 #if LWIP_TCP 00361 API_MSG_VAR_DECLARE(msg); 00362 err_t err; 00363 00364 /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ 00365 LWIP_UNUSED_ARG(backlog); 00366 00367 LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); 00368 00369 API_MSG_VAR_ALLOC(msg); 00370 API_MSG_VAR_REF(msg).conn = conn; 00371 #if TCP_LISTEN_BACKLOG 00372 API_MSG_VAR_REF(msg).msg.lb.backlog = backlog; 00373 #endif /* TCP_LISTEN_BACKLOG */ 00374 err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg)); 00375 API_MSG_VAR_FREE(msg); 00376 00377 return err; 00378 #else /* LWIP_TCP */ 00379 LWIP_UNUSED_ARG(conn); 00380 LWIP_UNUSED_ARG(backlog); 00381 return ERR_ARG; 00382 #endif /* LWIP_TCP */ 00383 } 00384 00385 /** 00386 * @ingroup netconn_tcp 00387 * Accept a new connection on a TCP listening netconn. 00388 * 00389 * @param conn the TCP listen netconn 00390 * @param new_conn pointer where the new connection is stored 00391 * @return ERR_OK if a new connection has been received or an error 00392 * code otherwise 00393 */ 00394 err_t 00395 netconn_accept(struct netconn *conn, struct netconn **new_conn) 00396 { 00397 #if LWIP_TCP 00398 void *accept_ptr; 00399 struct netconn *newconn; 00400 #if TCP_LISTEN_BACKLOG 00401 API_MSG_VAR_DECLARE(msg); 00402 #endif /* TCP_LISTEN_BACKLOG */ 00403 00404 LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;); 00405 *new_conn = NULL; 00406 LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); 00407 00408 if (ERR_IS_FATAL(conn->last_err)) { 00409 /* don't recv on fatal errors: this might block the application task 00410 waiting on acceptmbox forever! */ 00411 return conn->last_err; 00412 } 00413 if (!sys_mbox_valid(&conn->acceptmbox)) { 00414 return ERR_CLSD; 00415 } 00416 00417 #if TCP_LISTEN_BACKLOG 00418 API_MSG_VAR_ALLOC(msg); 00419 #endif /* TCP_LISTEN_BACKLOG */ 00420 00421 #if LWIP_SO_RCVTIMEO 00422 if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { 00423 #if TCP_LISTEN_BACKLOG 00424 API_MSG_VAR_FREE(msg); 00425 #endif /* TCP_LISTEN_BACKLOG */ 00426 return ERR_TIMEOUT; 00427 } 00428 #else 00429 sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); 00430 #endif /* LWIP_SO_RCVTIMEO*/ 00431 newconn = (struct netconn *)accept_ptr; 00432 /* Register event with callback */ 00433 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); 00434 00435 if (accept_ptr == &netconn_aborted) { 00436 /* a connection has been aborted: out of pcbs or out of netconns during accept */ 00437 /* @todo: set netconn error, but this would be fatal and thus block further accepts */ 00438 #if TCP_LISTEN_BACKLOG 00439 API_MSG_VAR_FREE(msg); 00440 #endif /* TCP_LISTEN_BACKLOG */ 00441 return ERR_ABRT; 00442 } 00443 if (newconn == NULL) { 00444 /* connection has been aborted */ 00445 /* in this special case, we set the netconn error from application thread, as 00446 on a ready-to-accept listening netconn, there should not be anything running 00447 in tcpip_thread */ 00448 NETCONN_SET_SAFE_ERR(conn, ERR_CLSD); 00449 #if TCP_LISTEN_BACKLOG 00450 API_MSG_VAR_FREE(msg); 00451 #endif /* TCP_LISTEN_BACKLOG */ 00452 return ERR_CLSD; 00453 } 00454 #if TCP_LISTEN_BACKLOG 00455 /* Let the stack know that we have accepted the connection. */ 00456 API_MSG_VAR_REF(msg).conn = newconn; 00457 /* don't care for the return value of lwip_netconn_do_recv */ 00458 netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg)); 00459 API_MSG_VAR_FREE(msg); 00460 #endif /* TCP_LISTEN_BACKLOG */ 00461 00462 *new_conn = newconn; 00463 /* don't set conn->last_err: it's only ERR_OK, anyway */ 00464 return ERR_OK; 00465 #else /* LWIP_TCP */ 00466 LWIP_UNUSED_ARG(conn); 00467 LWIP_UNUSED_ARG(new_conn); 00468 return ERR_ARG; 00469 #endif /* LWIP_TCP */ 00470 } 00471 00472 /** 00473 * @ingroup netconn_common 00474 * Receive data: actual implementation that doesn't care whether pbuf or netbuf 00475 * is received 00476 * 00477 * @param conn the netconn from which to receive data 00478 * @param new_buf pointer where a new pbuf/netbuf is stored when received data 00479 * @return ERR_OK if data has been received, an error code otherwise (timeout, 00480 * memory error or another error) 00481 */ 00482 static err_t 00483 netconn_recv_data(struct netconn *conn, void **new_buf) 00484 { 00485 void *buf = NULL; 00486 u16_t len; 00487 #if LWIP_TCP 00488 API_MSG_VAR_DECLARE(msg); 00489 #if LWIP_MPU_COMPATIBLE 00490 msg = NULL; 00491 #endif 00492 #endif /* LWIP_TCP */ 00493 00494 LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); 00495 *new_buf = NULL; 00496 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); 00497 #if LWIP_TCP 00498 #if (LWIP_UDP || LWIP_RAW) 00499 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 00500 #endif /* (LWIP_UDP || LWIP_RAW) */ 00501 { 00502 if (!sys_mbox_valid(&conn->recvmbox)) { 00503 /* This happens when calling this function after receiving FIN */ 00504 return sys_mbox_valid(&conn->acceptmbox) ? ERR_CONN : ERR_CLSD; 00505 } 00506 } 00507 #endif /* LWIP_TCP */ 00508 LWIP_ERROR("netconn_recv: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); 00509 00510 if (ERR_IS_FATAL(conn->last_err)) { 00511 /* don't recv on fatal errors: this might block the application task 00512 waiting on recvmbox forever! */ 00513 /* @todo: this does not allow us to fetch data that has been put into recvmbox 00514 before the fatal error occurred - is that a problem? */ 00515 return conn->last_err; 00516 } 00517 #if LWIP_TCP 00518 #if (LWIP_UDP || LWIP_RAW) 00519 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 00520 #endif /* (LWIP_UDP || LWIP_RAW) */ 00521 { 00522 API_MSG_VAR_ALLOC(msg); 00523 } 00524 #endif /* LWIP_TCP */ 00525 00526 #if LWIP_SO_RCVTIMEO 00527 if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { 00528 #if LWIP_TCP 00529 #if (LWIP_UDP || LWIP_RAW) 00530 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 00531 #endif /* (LWIP_UDP || LWIP_RAW) */ 00532 { 00533 API_MSG_VAR_FREE(msg); 00534 } 00535 #endif /* LWIP_TCP */ 00536 return ERR_TIMEOUT; 00537 } 00538 #else 00539 sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); 00540 #endif /* LWIP_SO_RCVTIMEO*/ 00541 00542 #if LWIP_TCP 00543 #if (LWIP_UDP || LWIP_RAW) 00544 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 00545 #endif /* (LWIP_UDP || LWIP_RAW) */ 00546 { 00547 /* Let the stack know that we have taken the data. */ 00548 /* @todo: Speedup: Don't block and wait for the answer here 00549 (to prevent multiple thread-switches). */ 00550 API_MSG_VAR_REF(msg).conn = conn; 00551 if (buf != NULL) { 00552 API_MSG_VAR_REF(msg).msg.r.len = ((struct pbuf *)buf)->tot_len; 00553 } else { 00554 API_MSG_VAR_REF(msg).msg.r.len = 1; 00555 } 00556 00557 /* don't care for the return value of lwip_netconn_do_recv */ 00558 netconn_apimsg(lwip_netconn_do_recv, &API_MSG_VAR_REF(msg)); 00559 API_MSG_VAR_FREE(msg); 00560 00561 /* If we are closed, we indicate that we no longer wish to use the socket */ 00562 if (buf == NULL) { 00563 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); 00564 if (conn->pcb.ip == NULL) { 00565 /* race condition: RST during recv */ 00566 return conn->last_err == ERR_OK ? ERR_RST : conn->last_err; 00567 } 00568 /* RX side is closed, so deallocate the recvmbox */ 00569 netconn_close_shutdown(conn, NETCONN_SHUT_RD); 00570 /* Don' store ERR_CLSD as conn->err since we are only half-closed */ 00571 return ERR_CLSD; 00572 } 00573 len = ((struct pbuf *)buf)->tot_len; 00574 } 00575 #endif /* LWIP_TCP */ 00576 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW) 00577 else 00578 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ 00579 #if (LWIP_UDP || LWIP_RAW) 00580 { 00581 LWIP_ASSERT("buf != NULL", buf != NULL); 00582 len = netbuf_len((struct netbuf*)buf); 00583 } 00584 #endif /* (LWIP_UDP || LWIP_RAW) */ 00585 00586 #if LWIP_SO_RCVBUF 00587 SYS_ARCH_DEC(conn->recv_avail, len); 00588 #endif /* LWIP_SO_RCVBUF */ 00589 /* Register event with callback */ 00590 API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); 00591 00592 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len)); 00593 00594 *new_buf = buf; 00595 /* don't set conn->last_err: it's only ERR_OK, anyway */ 00596 return ERR_OK; 00597 } 00598 00599 /** 00600 * @ingroup netconn_tcp 00601 * Receive data (in form of a pbuf) from a TCP netconn 00602 * 00603 * @param conn the netconn from which to receive data 00604 * @param new_buf pointer where a new pbuf is stored when received data 00605 * @return ERR_OK if data has been received, an error code otherwise (timeout, 00606 * memory error or another error) 00607 * ERR_ARG if conn is not a TCP netconn 00608 */ 00609 err_t 00610 netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) 00611 { 00612 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) && 00613 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); 00614 00615 return netconn_recv_data(conn, (void **)new_buf); 00616 } 00617 00618 /** 00619 * @ingroup netconn_common 00620 * Receive data (in form of a netbuf containing a packet buffer) from a netconn 00621 * 00622 * @param conn the netconn from which to receive data 00623 * @param new_buf pointer where a new netbuf is stored when received data 00624 * @return ERR_OK if data has been received, an error code otherwise (timeout, 00625 * memory error or another error) 00626 */ 00627 err_t 00628 netconn_recv(struct netconn *conn, struct netbuf **new_buf) 00629 { 00630 #if LWIP_TCP 00631 struct netbuf *buf = NULL; 00632 err_t err; 00633 #endif /* LWIP_TCP */ 00634 00635 LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); 00636 *new_buf = NULL; 00637 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); 00638 00639 #if LWIP_TCP 00640 #if (LWIP_UDP || LWIP_RAW) 00641 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 00642 #endif /* (LWIP_UDP || LWIP_RAW) */ 00643 { 00644 struct pbuf *p = NULL; 00645 /* This is not a listening netconn, since recvmbox is set */ 00646 00647 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 00648 if (buf == NULL) { 00649 return ERR_MEM; 00650 } 00651 00652 err = netconn_recv_data(conn, (void **)&p); 00653 if (err != ERR_OK) { 00654 memp_free(MEMP_NETBUF, buf); 00655 return err; 00656 } 00657 LWIP_ASSERT("p != NULL", p != NULL); 00658 00659 buf->p = p; 00660 buf->ptr = p; 00661 buf->port = 0; 00662 ip_addr_set_zero(&buf->addr); 00663 *new_buf = buf; 00664 /* don't set conn->last_err: it's only ERR_OK, anyway */ 00665 return ERR_OK; 00666 } 00667 #endif /* LWIP_TCP */ 00668 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW) 00669 else 00670 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ 00671 { 00672 #if (LWIP_UDP || LWIP_RAW) 00673 return netconn_recv_data(conn, (void **)new_buf); 00674 #endif /* (LWIP_UDP || LWIP_RAW) */ 00675 } 00676 } 00677 00678 /** 00679 * @ingroup netconn_udp 00680 * Send data (in form of a netbuf) to a specific remote IP address and port. 00681 * Only to be used for UDP and RAW netconns (not TCP). 00682 * 00683 * @param conn the netconn over which to send data 00684 * @param buf a netbuf containing the data to send 00685 * @param addr the remote IP address to which to send the data 00686 * @param port the remote port to which to send the data 00687 * @return ERR_OK if data was sent, any other err_t on error 00688 */ 00689 err_t 00690 netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port) 00691 { 00692 if (buf != NULL) { 00693 ip_addr_set(&buf->addr, addr); 00694 buf->port = port; 00695 return netconn_send(conn, buf); 00696 } 00697 return ERR_VAL; 00698 } 00699 00700 /** 00701 * @ingroup netconn_udp 00702 * Send data over a UDP or RAW netconn (that is already connected). 00703 * 00704 * @param conn the UDP or RAW netconn over which to send data 00705 * @param buf a netbuf containing the data to send 00706 * @return ERR_OK if data was sent, any other err_t on error 00707 */ 00708 err_t 00709 netconn_send(struct netconn *conn, struct netbuf *buf) 00710 { 00711 API_MSG_VAR_DECLARE(msg); 00712 err_t err; 00713 00714 LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); 00715 00716 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); 00717 00718 API_MSG_VAR_ALLOC(msg); 00719 API_MSG_VAR_REF(msg).conn = conn; 00720 API_MSG_VAR_REF(msg).msg.b = buf; 00721 err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg)); 00722 API_MSG_VAR_FREE(msg); 00723 00724 return err; 00725 } 00726 00727 /** 00728 * @ingroup netconn_tcp 00729 * Send data over a TCP netconn. 00730 * 00731 * @param conn the TCP netconn over which to send data 00732 * @param dataptr pointer to the application buffer that contains the data to send 00733 * @param size size of the application data to send 00734 * @param apiflags combination of following flags : 00735 * - NETCONN_COPY: data will be copied into memory belonging to the stack 00736 * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent 00737 * - NETCONN_DONTBLOCK: only write the data if all data can be written at once 00738 * @param bytes_written pointer to a location that receives the number of written bytes 00739 * @return ERR_OK if data was sent, any other err_t on error 00740 */ 00741 err_t 00742 netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, 00743 u8_t apiflags, size_t *bytes_written) 00744 { 00745 API_MSG_VAR_DECLARE(msg); 00746 err_t err; 00747 u8_t dontblock; 00748 00749 LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); 00750 LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;); 00751 if (size == 0) { 00752 return ERR_OK; 00753 } 00754 dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); 00755 #if LWIP_SO_SNDTIMEO 00756 if (conn->send_timeout != 0) { 00757 dontblock = 1; 00758 } 00759 #endif /* LWIP_SO_SNDTIMEO */ 00760 if (dontblock && !bytes_written) { 00761 /* This implies netconn_write() cannot be used for non-blocking send, since 00762 it has no way to return the number of bytes written. */ 00763 return ERR_VAL; 00764 } 00765 00766 API_MSG_VAR_ALLOC(msg); 00767 /* non-blocking write sends as much */ 00768 API_MSG_VAR_REF(msg).conn = conn; 00769 API_MSG_VAR_REF(msg).msg.w.dataptr = dataptr; 00770 API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags; 00771 API_MSG_VAR_REF(msg).msg.w.len = size; 00772 #if LWIP_SO_SNDTIMEO 00773 if (conn->send_timeout != 0) { 00774 /* get the time we started, which is later compared to 00775 sys_now() + conn->send_timeout */ 00776 API_MSG_VAR_REF(msg).msg.w.time_started = sys_now(); 00777 } else { 00778 API_MSG_VAR_REF(msg).msg.w.time_started = 0; 00779 } 00780 #endif /* LWIP_SO_SNDTIMEO */ 00781 00782 /* For locking the core: this _can_ be delayed on low memory/low send buffer, 00783 but if it is, this is done inside api_msg.c:do_write(), so we can use the 00784 non-blocking version here. */ 00785 err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg)); 00786 if ((err == ERR_OK) && (bytes_written != NULL)) { 00787 if (dontblock) { 00788 /* nonblocking write: maybe the data has been sent partly */ 00789 *bytes_written = API_MSG_VAR_REF(msg).msg.w.len; 00790 } else { 00791 /* blocking call succeeded: all data has been sent if it */ 00792 *bytes_written = size; 00793 } 00794 } 00795 API_MSG_VAR_FREE(msg); 00796 00797 return err; 00798 } 00799 00800 /** 00801 * @ingroup netconn_tcp 00802 * Close or shutdown a TCP netconn (doesn't delete it). 00803 * 00804 * @param conn the TCP netconn to close or shutdown 00805 * @param how fully close or only shutdown one side? 00806 * @return ERR_OK if the netconn was closed, any other err_t on error 00807 */ 00808 static err_t 00809 netconn_close_shutdown(struct netconn *conn, u8_t how) 00810 { 00811 API_MSG_VAR_DECLARE(msg); 00812 err_t err; 00813 LWIP_UNUSED_ARG(how); 00814 00815 LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); 00816 00817 API_MSG_VAR_ALLOC(msg); 00818 API_MSG_VAR_REF(msg).conn = conn; 00819 #if LWIP_TCP 00820 /* shutting down both ends is the same as closing */ 00821 API_MSG_VAR_REF(msg).msg.sd.shut = how; 00822 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER 00823 /* get the time we started, which is later compared to 00824 sys_now() + conn->send_timeout */ 00825 API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); 00826 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 00827 API_MSG_VAR_REF(msg).msg.sd.polls_left = 00828 ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; 00829 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 00830 #endif /* LWIP_TCP */ 00831 err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg)); 00832 API_MSG_VAR_FREE(msg); 00833 00834 return err; 00835 } 00836 00837 /** 00838 * @ingroup netconn_tcp 00839 * Close a TCP netconn (doesn't delete it). 00840 * 00841 * @param conn the TCP netconn to close 00842 * @return ERR_OK if the netconn was closed, any other err_t on error 00843 */ 00844 err_t 00845 netconn_close(struct netconn *conn) 00846 { 00847 /* shutting down both ends is the same as closing */ 00848 return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR); 00849 } 00850 00851 /** 00852 * @ingroup netconn_tcp 00853 * Shut down one or both sides of a TCP netconn (doesn't delete it). 00854 * 00855 * @param conn the TCP netconn to shut down 00856 * @param shut_rx shut down the RX side (no more read possible after this) 00857 * @param shut_tx shut down the TX side (no more write possible after this) 00858 * @return ERR_OK if the netconn was closed, any other err_t on error 00859 */ 00860 err_t 00861 netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx) 00862 { 00863 return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)); 00864 } 00865 00866 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) 00867 /** 00868 * @ingroup netconn_udp 00869 * Join multicast groups for UDP netconns. 00870 * 00871 * @param conn the UDP netconn for which to change multicast addresses 00872 * @param multiaddr IP address of the multicast group to join or leave 00873 * @param netif_addr the IP address of the network interface on which to send 00874 * the igmp message 00875 * @param join_or_leave flag whether to send a join- or leave-message 00876 * @return ERR_OK if the action was taken, any err_t on error 00877 */ 00878 err_t 00879 netconn_join_leave_group(struct netconn *conn, 00880 const ip_addr_t *multiaddr, 00881 const ip_addr_t *netif_addr, 00882 enum netconn_igmp join_or_leave) 00883 { 00884 API_MSG_VAR_DECLARE(msg); 00885 err_t err; 00886 00887 LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); 00888 00889 API_MSG_VAR_ALLOC(msg); 00890 00891 #if LWIP_IPV4 00892 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 00893 if (multiaddr == NULL) { 00894 multiaddr = IP4_ADDR_ANY; 00895 } 00896 if (netif_addr == NULL) { 00897 netif_addr = IP4_ADDR_ANY; 00898 } 00899 #endif /* LWIP_IPV4 */ 00900 00901 API_MSG_VAR_REF(msg).conn = conn; 00902 API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr); 00903 API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr); 00904 API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave; 00905 err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg)); 00906 API_MSG_VAR_FREE(msg); 00907 00908 return err; 00909 } 00910 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ 00911 00912 #if LWIP_DNS 00913 #if LWIP_FULL_DNS 00914 00915 /** 00916 * @ingroup netconn_common 00917 * Execute a DNS query, only one IP address is returned 00918 * 00919 * @param name a string representation of the DNS host name to query 00920 * @param addr a preallocated ip_addr_t where to store the resolved IP address 00921 * @param dns_addrtype IP address type (IPv4 / IPv6) 00922 * @return ERR_OK: resolving succeeded 00923 * ERR_MEM: memory error, try again later 00924 * ERR_ARG: dns client not initialized or invalid hostname 00925 * ERR_VAL: dns server response was invalid 00926 */ 00927 #if LWIP_IPV4 && LWIP_IPV6 00928 err_t 00929 netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype) 00930 #else 00931 err_t 00932 netconn_gethostbyname(const char *name, ip_addr_t *addr) 00933 #endif 00934 { 00935 API_VAR_DECLARE(struct dns_api_msg, msg); 00936 #if !LWIP_MPU_COMPATIBLE 00937 sys_sem_t sem; 00938 #endif /* LWIP_MPU_COMPATIBLE */ 00939 err_t err; 00940 err_t cberr; 00941 00942 LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); 00943 LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); 00944 #if LWIP_MPU_COMPATIBLE 00945 if (strlen(name) >= DNS_MAX_NAME_LENGTH) { 00946 return ERR_ARG; 00947 } 00948 #endif 00949 00950 API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM); 00951 #if LWIP_MPU_COMPATIBLE 00952 strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH-1); 00953 API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH-1] = 0; 00954 #else /* LWIP_MPU_COMPATIBLE */ 00955 msg.err = &err; 00956 msg.sem = &sem; 00957 API_VAR_REF(msg).addr = API_VAR_REF(addr); 00958 API_VAR_REF(msg).name = name; 00959 #endif /* LWIP_MPU_COMPATIBLE */ 00960 #if LWIP_IPV4 && LWIP_IPV6 00961 API_VAR_REF(msg).dns_addrtype = dns_addrtype; 00962 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 00963 #if LWIP_NETCONN_SEM_PER_THREAD 00964 API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET(); 00965 #else /* LWIP_NETCONN_SEM_PER_THREAD*/ 00966 err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0); 00967 if (err != ERR_OK) { 00968 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 00969 return err; 00970 } 00971 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 00972 00973 cberr = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg)); 00974 if (cberr != ERR_OK) { 00975 #if !LWIP_NETCONN_SEM_PER_THREAD 00976 sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); 00977 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ 00978 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 00979 return cberr; 00980 } 00981 sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem)); 00982 #if !LWIP_NETCONN_SEM_PER_THREAD 00983 sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); 00984 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ 00985 00986 #if LWIP_MPU_COMPATIBLE 00987 *addr = msg->addr; 00988 err = msg->err; 00989 #endif /* LWIP_MPU_COMPATIBLE */ 00990 00991 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 00992 return err; 00993 } 00994 00995 #endif /* LWIP_FULL_DNS */ 00996 #endif /* LWIP_DNS*/ 00997 00998 #if LWIP_NETCONN_SEM_PER_THREAD 00999 void 01000 netconn_thread_init(void) 01001 { 01002 sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); 01003 if ((sem == NULL) || !sys_sem_valid(sem)) { 01004 /* call alloc only once */ 01005 LWIP_NETCONN_THREAD_SEM_ALLOC(); 01006 LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET())); 01007 } 01008 } 01009 01010 void 01011 netconn_thread_cleanup(void) 01012 { 01013 sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); 01014 if ((sem != NULL) && sys_sem_valid(sem)) { 01015 /* call free only once */ 01016 LWIP_NETCONN_THREAD_SEM_FREE(); 01017 } 01018 } 01019 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 01020 01021 #endif /* LWIP_NETCONN */
Generated on Tue Jul 12 2022 12:44:32 by
