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