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