Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
lwip_api_lib.c
Go to the documentation of this file.
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 Sun Jul 17 2022 08:25:24 by 1.7.2