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: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
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 11:02:40 by
