1 /** 2 * @file 3 * Sequential API External module 4 * 5 * @defgroup netconn Netconn API 6 * @ingroup sequential_api 7 * Thread-safe, to be called from non-TCPIP threads only. 8 * TX/RX handling based on @ref netbuf (containing @ref pbuf) 9 * to avoid copying data around. 10 * 11 * @defgroup netconn_common Common functions 12 * @ingroup netconn 13 * For use with TCP and UDP 14 * 15 * @defgroup netconn_tcp TCP only 16 * @ingroup netconn 17 * TCP only functions 18 * 19 * @defgroup netconn_udp UDP only 20 * @ingroup netconn 21 * UDP only functions 22 */ 23 24 /* 25 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 26 * All rights reserved. 27 * 28 * Redistribution and use in source and binary forms, with or without modification, 29 * are permitted provided that the following conditions are met: 30 * 31 * 1. Redistributions of source code must retain the above copyright notice, 32 * this list of conditions and the following disclaimer. 33 * 2. Redistributions in binary form must reproduce the above copyright notice, 34 * this list of conditions and the following disclaimer in the documentation 35 * and/or other materials provided with the distribution. 36 * 3. The name of the author may not be used to endorse or promote products 37 * derived from this software without specific prior written permission. 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 40 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 41 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 42 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 43 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 44 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 45 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 46 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 47 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 48 * OF SUCH DAMAGE. 49 * 50 * This file is part of the lwIP TCP/IP stack. 51 * 52 * Author: Adam Dunkels <adam@sics.se> 53 */ 54 55 /* This is the part of the API that is linked with 56 the application */ 57 58 #include "lwip/opt.h" 59 60 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ 61 62 #include "lwip/api.h" 63 #include "lwip/memp.h" 64 65 #include "lwip/ip.h" 66 #include "lwip/raw.h" 67 #include "lwip/udp.h" 68 #include "lwip/priv/api_msg.h" 69 #include "lwip/priv/tcp_priv.h" 70 #include "lwip/priv/tcpip_priv.h" 71 72 #ifdef LWIP_HOOK_FILENAME 73 #include LWIP_HOOK_FILENAME 74 #endif 75 76 #include <string.h> 77 78 #define API_MSG_VAR_REF(name) API_VAR_REF(name) 79 #define API_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct api_msg, name) 80 #define API_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, ERR_MEM) 81 #define API_MSG_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, NULL) 82 #define API_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_API_MSG, name) 83 84 #if TCP_LISTEN_BACKLOG 85 /* need to allocate API message for accept so empty message pool does not result in event loss 86 * see bug #47512: MPU_COMPATIBLE may fail on empty pool */ 87 #define API_MSG_VAR_ALLOC_ACCEPT(msg) API_MSG_VAR_ALLOC(msg) 88 #define API_MSG_VAR_FREE_ACCEPT(msg) API_MSG_VAR_FREE(msg) 89 #else /* TCP_LISTEN_BACKLOG */ 90 #define API_MSG_VAR_ALLOC_ACCEPT(msg) 91 #define API_MSG_VAR_FREE_ACCEPT(msg) 92 #endif /* TCP_LISTEN_BACKLOG */ 93 94 #if LWIP_NETCONN_FULLDUPLEX 95 #define NETCONN_RECVMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->recvmbox) && (((conn)->flags & NETCONN_FLAG_MBOXINVALID) == 0)) 96 #define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & (NETCONN_FLAG_MBOXCLOSED|NETCONN_FLAG_MBOXINVALID)) == 0)) 97 #define NETCONN_MBOX_WAITING_INC(conn) SYS_ARCH_INC(conn->mbox_threads_waiting, 1) 98 #define NETCONN_MBOX_WAITING_DEC(conn) SYS_ARCH_DEC(conn->mbox_threads_waiting, 1) 99 #else /* LWIP_NETCONN_FULLDUPLEX */ 100 #define NETCONN_RECVMBOX_WAITABLE(conn) sys_mbox_valid(&(conn)->recvmbox) 101 #define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & NETCONN_FLAG_MBOXCLOSED) == 0)) 102 #define NETCONN_MBOX_WAITING_INC(conn) 103 #define NETCONN_MBOX_WAITING_DEC(conn) 104 #endif /* LWIP_NETCONN_FULLDUPLEX */ 105 106 static err_t netconn_close_shutdown(struct netconn *conn, u8_t how); 107 108 /** 109 * Call the lower part of a netconn_* function 110 * This function is then running in the thread context 111 * of tcpip_thread and has exclusive access to lwIP core code. 112 * 113 * @param fn function to call 114 * @param apimsg a struct containing the function to call and its parameters 115 * @return ERR_OK if the function was called, another err_t if not 116 */ 117 static err_t netconn_apimsg(tcpip_callback_fn fn,struct api_msg * apimsg)118 netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg) 119 { 120 err_t err; 121 122 #ifdef LWIP_DEBUG 123 /* catch functions that don't set err */ 124 apimsg->err = ERR_VAL; 125 #endif /* LWIP_DEBUG */ 126 127 #if LWIP_NETCONN_SEM_PER_THREAD 128 apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); 129 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 130 131 err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg)); 132 if (err == ERR_OK) { 133 return apimsg->err; 134 } 135 return err; 136 } 137 138 /** 139 * Create a new netconn (of a specific type) that has a callback function. 140 * The corresponding pcb is also created. 141 * 142 * @param t the type of 'connection' to create (@see enum netconn_type) 143 * @param proto the IP protocol for RAW IP pcbs 144 * @param callback a function to call on status changes (RX available, TX'ed) 145 * @return a newly allocated struct netconn or 146 * NULL on memory error 147 */ 148 struct netconn * netconn_new_with_proto_and_callback(enum netconn_type t,u8_t proto,netconn_callback callback)149 netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) 150 { 151 struct netconn *conn; 152 API_MSG_VAR_DECLARE(msg); 153 API_MSG_VAR_ALLOC_RETURN_NULL(msg); 154 155 conn = netconn_alloc(t, callback); 156 if (conn != NULL) { 157 err_t err; 158 159 API_MSG_VAR_REF(msg).msg.n.proto = proto; 160 API_MSG_VAR_REF(msg).conn = conn; 161 err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg)); 162 if (err != ERR_OK) { 163 LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); 164 LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox)); 165 #if LWIP_TCP 166 LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox)); 167 #endif /* LWIP_TCP */ 168 #if !LWIP_NETCONN_SEM_PER_THREAD 169 LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed)); 170 sys_sem_free(&conn->op_completed); 171 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ 172 sys_mbox_free(&conn->recvmbox); 173 memp_free(MEMP_NETCONN, conn); 174 API_MSG_VAR_FREE(msg); 175 return NULL; 176 } 177 } 178 API_MSG_VAR_FREE(msg); 179 return conn; 180 } 181 182 /** 183 * @ingroup netconn_common 184 * Close a netconn 'connection' and free all its resources but not the netconn itself. 185 * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate 186 * after this returns. 187 * 188 * @param conn the netconn to delete 189 * @return ERR_OK if the connection was deleted 190 */ 191 err_t netconn_prepare_delete(struct netconn * conn)192 netconn_prepare_delete(struct netconn *conn) 193 { 194 err_t err; 195 API_MSG_VAR_DECLARE(msg); 196 197 /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ 198 if (conn == NULL) { 199 return ERR_OK; 200 } 201 202 API_MSG_VAR_ALLOC(msg); 203 API_MSG_VAR_REF(msg).conn = conn; 204 #if LWIP_TCP 205 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER 206 /* get the time we started, which is later compared to 207 sys_now() + conn->send_timeout */ 208 API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); 209 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 210 API_MSG_VAR_REF(msg).msg.sd.polls_left = 211 ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; 212 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 213 #endif /* LWIP_TCP */ 214 err = netconn_apimsg(lwip_netconn_do_delconn, &API_MSG_VAR_REF(msg)); 215 API_MSG_VAR_FREE(msg); 216 217 if (err != ERR_OK) { 218 return err; 219 } 220 return ERR_OK; 221 } 222 223 /** 224 * @ingroup netconn_common 225 * Close a netconn 'connection' and free its resources. 226 * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate 227 * after this returns. 228 * 229 * @param conn the netconn to delete 230 * @return ERR_OK if the connection was deleted 231 */ 232 err_t netconn_delete(struct netconn * conn)233 netconn_delete(struct netconn *conn) 234 { 235 err_t err; 236 237 /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ 238 if (conn == NULL) { 239 return ERR_OK; 240 } 241 242 #if LWIP_NETCONN_FULLDUPLEX 243 if (conn->flags & NETCONN_FLAG_MBOXINVALID) { 244 /* Already called netconn_prepare_delete() before */ 245 err = ERR_OK; 246 } else 247 #endif /* LWIP_NETCONN_FULLDUPLEX */ 248 { 249 err = netconn_prepare_delete(conn); 250 } 251 if (err == ERR_OK) { 252 netconn_free(conn); 253 } 254 return err; 255 } 256 257 /** 258 * Get the local or remote IP address and port of a netconn. 259 * For RAW netconns, this returns the protocol instead of a port! 260 * 261 * @param conn the netconn to query 262 * @param addr a pointer to which to save the IP address 263 * @param port a pointer to which to save the port (or protocol for RAW) 264 * @param local 1 to get the local IP address, 0 to get the remote one 265 * @return ERR_CONN for invalid connections 266 * ERR_OK if the information was retrieved 267 */ 268 err_t netconn_getaddr(struct netconn * conn,ip_addr_t * addr,u16_t * port,u8_t local)269 netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) 270 { 271 API_MSG_VAR_DECLARE(msg); 272 err_t err; 273 274 LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); 275 LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); 276 LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;); 277 278 API_MSG_VAR_ALLOC(msg); 279 API_MSG_VAR_REF(msg).conn = conn; 280 API_MSG_VAR_REF(msg).msg.ad.local = local; 281 #if LWIP_MPU_COMPATIBLE 282 err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg)); 283 *addr = msg->msg.ad.ipaddr; 284 *port = msg->msg.ad.port; 285 #else /* LWIP_MPU_COMPATIBLE */ 286 msg.msg.ad.ipaddr = addr; 287 msg.msg.ad.port = port; 288 err = netconn_apimsg(lwip_netconn_do_getaddr, &msg); 289 #endif /* LWIP_MPU_COMPATIBLE */ 290 API_MSG_VAR_FREE(msg); 291 292 return err; 293 } 294 295 /** 296 * @ingroup netconn_common 297 * Bind a netconn to a specific local IP address and port. 298 * Binding one netconn twice might not always be checked correctly! 299 * 300 * @param conn the netconn to bind 301 * @param addr the local IP address to bind the netconn to 302 * (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses) 303 * @param port the local port to bind the netconn to (not used for RAW) 304 * @return ERR_OK if bound, any other err_t on failure 305 */ 306 err_t netconn_bind(struct netconn * conn,const ip_addr_t * addr,u16_t port)307 netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) 308 { 309 API_MSG_VAR_DECLARE(msg); 310 err_t err; 311 312 LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); 313 314 #if LWIP_IPV4 315 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 316 if (addr == NULL) { 317 addr = IP4_ADDR_ANY; 318 } 319 #endif /* LWIP_IPV4 */ 320 321 #if LWIP_IPV4 && LWIP_IPV6 322 /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY, 323 * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind 324 */ 325 if ((netconn_get_ipv6only(conn) == 0) && 326 ip_addr_cmp(addr, IP6_ADDR_ANY)) { 327 addr = IP_ANY_TYPE; 328 } 329 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 330 331 API_MSG_VAR_ALLOC(msg); 332 API_MSG_VAR_REF(msg).conn = conn; 333 API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); 334 API_MSG_VAR_REF(msg).msg.bc.port = port; 335 err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg)); 336 API_MSG_VAR_FREE(msg); 337 338 return err; 339 } 340 341 /** 342 * @ingroup netconn_common 343 * Bind a netconn to a specific interface and port. 344 * Binding one netconn twice might not always be checked correctly! 345 * 346 * @param conn the netconn to bind 347 * @param if_idx the local interface index to bind the netconn to 348 * @return ERR_OK if bound, any other err_t on failure 349 */ 350 err_t netconn_bind_if(struct netconn * conn,u8_t if_idx)351 netconn_bind_if(struct netconn *conn, u8_t if_idx) 352 { 353 API_MSG_VAR_DECLARE(msg); 354 err_t err; 355 356 LWIP_ERROR("netconn_bind_if: invalid conn", (conn != NULL), return ERR_ARG;); 357 358 API_MSG_VAR_ALLOC(msg); 359 API_MSG_VAR_REF(msg).conn = conn; 360 API_MSG_VAR_REF(msg).msg.bc.if_idx = if_idx; 361 err = netconn_apimsg(lwip_netconn_do_bind_if, &API_MSG_VAR_REF(msg)); 362 API_MSG_VAR_FREE(msg); 363 364 return err; 365 } 366 367 /** 368 * @ingroup netconn_common 369 * Connect a netconn to a specific remote IP address and port. 370 * 371 * @param conn the netconn to connect 372 * @param addr the remote IP address to connect to 373 * @param port the remote port to connect to (no used for RAW) 374 * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise 375 */ 376 err_t netconn_connect(struct netconn * conn,const ip_addr_t * addr,u16_t port)377 netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) 378 { 379 API_MSG_VAR_DECLARE(msg); 380 err_t err; 381 382 LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); 383 384 #if LWIP_IPV4 385 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 386 if (addr == NULL) { 387 addr = IP4_ADDR_ANY; 388 } 389 #endif /* LWIP_IPV4 */ 390 391 API_MSG_VAR_ALLOC(msg); 392 API_MSG_VAR_REF(msg).conn = conn; 393 API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); 394 API_MSG_VAR_REF(msg).msg.bc.port = port; 395 err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg)); 396 API_MSG_VAR_FREE(msg); 397 398 return err; 399 } 400 401 /** 402 * @ingroup netconn_udp 403 * Disconnect a netconn from its current peer (only valid for UDP netconns). 404 * 405 * @param conn the netconn to disconnect 406 * @return See @ref err_t 407 */ 408 err_t netconn_disconnect(struct netconn * conn)409 netconn_disconnect(struct netconn *conn) 410 { 411 API_MSG_VAR_DECLARE(msg); 412 err_t err; 413 414 LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); 415 416 API_MSG_VAR_ALLOC(msg); 417 API_MSG_VAR_REF(msg).conn = conn; 418 err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg)); 419 API_MSG_VAR_FREE(msg); 420 421 return err; 422 } 423 424 /** 425 * @ingroup netconn_tcp 426 * Set a TCP netconn into listen mode 427 * 428 * @param conn the tcp netconn to set to listen mode 429 * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1 430 * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns 431 * don't return any error (yet?)) 432 */ 433 err_t netconn_listen_with_backlog(struct netconn * conn,u8_t backlog)434 netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) 435 { 436 #if LWIP_TCP 437 API_MSG_VAR_DECLARE(msg); 438 err_t err; 439 440 /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ 441 LWIP_UNUSED_ARG(backlog); 442 443 LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); 444 445 API_MSG_VAR_ALLOC(msg); 446 API_MSG_VAR_REF(msg).conn = conn; 447 #if TCP_LISTEN_BACKLOG 448 API_MSG_VAR_REF(msg).msg.lb.backlog = backlog; 449 #endif /* TCP_LISTEN_BACKLOG */ 450 err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg)); 451 API_MSG_VAR_FREE(msg); 452 453 return err; 454 #else /* LWIP_TCP */ 455 LWIP_UNUSED_ARG(conn); 456 LWIP_UNUSED_ARG(backlog); 457 return ERR_ARG; 458 #endif /* LWIP_TCP */ 459 } 460 461 /** 462 * @ingroup netconn_tcp 463 * Accept a new connection on a TCP listening netconn. 464 * 465 * @param conn the TCP listen netconn 466 * @param new_conn pointer where the new connection is stored 467 * @return ERR_OK if a new connection has been received or an error 468 * code otherwise 469 */ 470 err_t netconn_accept(struct netconn * conn,struct netconn ** new_conn)471 netconn_accept(struct netconn *conn, struct netconn **new_conn) 472 { 473 #if LWIP_TCP 474 err_t err; 475 void *accept_ptr; 476 struct netconn *newconn; 477 #if TCP_LISTEN_BACKLOG 478 API_MSG_VAR_DECLARE(msg); 479 #endif /* TCP_LISTEN_BACKLOG */ 480 481 LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;); 482 *new_conn = NULL; 483 LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); 484 485 /* NOTE: Although the opengroup spec says a pending error shall be returned to 486 send/recv/getsockopt(SO_ERROR) only, we return it for listening 487 connections also, to handle embedded-system errors */ 488 err = netconn_err(conn); 489 if (err != ERR_OK) { 490 /* return pending error */ 491 return err; 492 } 493 if (!NETCONN_ACCEPTMBOX_WAITABLE(conn)) { 494 /* don't accept if closed: this might block the application task 495 waiting on acceptmbox forever! */ 496 return ERR_CLSD; 497 } 498 499 API_MSG_VAR_ALLOC_ACCEPT(msg); 500 501 NETCONN_MBOX_WAITING_INC(conn); 502 if (netconn_is_nonblocking(conn)) { 503 if (sys_arch_mbox_tryfetch(&conn->acceptmbox, &accept_ptr) == SYS_MBOX_EMPTY) { 504 API_MSG_VAR_FREE_ACCEPT(msg); 505 NETCONN_MBOX_WAITING_DEC(conn); 506 return ERR_WOULDBLOCK; 507 } 508 } else { 509 #if LWIP_SO_RCVTIMEO 510 if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { 511 API_MSG_VAR_FREE_ACCEPT(msg); 512 NETCONN_MBOX_WAITING_DEC(conn); 513 return ERR_TIMEOUT; 514 } 515 #else 516 sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); 517 #endif /* LWIP_SO_RCVTIMEO*/ 518 } 519 NETCONN_MBOX_WAITING_DEC(conn); 520 #if LWIP_NETCONN_FULLDUPLEX 521 if (conn->flags & NETCONN_FLAG_MBOXINVALID) { 522 if (lwip_netconn_is_deallocated_msg(accept_ptr)) { 523 /* the netconn has been closed from another thread */ 524 API_MSG_VAR_FREE_ACCEPT(msg); 525 return ERR_CONN; 526 } 527 } 528 #endif 529 530 /* Register event with callback */ 531 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); 532 533 if (lwip_netconn_is_err_msg(accept_ptr, &err)) { 534 /* a connection has been aborted: e.g. out of pcbs or out of netconns during accept */ 535 API_MSG_VAR_FREE_ACCEPT(msg); 536 return err; 537 } 538 if (accept_ptr == NULL) { 539 /* connection has been aborted */ 540 API_MSG_VAR_FREE_ACCEPT(msg); 541 return ERR_CLSD; 542 } 543 newconn = (struct netconn *)accept_ptr; 544 #if TCP_LISTEN_BACKLOG 545 /* Let the stack know that we have accepted the connection. */ 546 API_MSG_VAR_REF(msg).conn = newconn; 547 /* don't care for the return value of lwip_netconn_do_recv */ 548 netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg)); 549 API_MSG_VAR_FREE(msg); 550 #endif /* TCP_LISTEN_BACKLOG */ 551 552 *new_conn = newconn; 553 /* don't set conn->last_err: it's only ERR_OK, anyway */ 554 return ERR_OK; 555 #else /* LWIP_TCP */ 556 LWIP_UNUSED_ARG(conn); 557 LWIP_UNUSED_ARG(new_conn); 558 return ERR_ARG; 559 #endif /* LWIP_TCP */ 560 } 561 562 /** 563 * @ingroup netconn_common 564 * Receive data: actual implementation that doesn't care whether pbuf or netbuf 565 * is received (this is internal, it's just here for describing common errors) 566 * 567 * @param conn the netconn from which to receive data 568 * @param new_buf pointer where a new pbuf/netbuf is stored when received data 569 * @param apiflags flags that control function behaviour. For now only: 570 * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data 571 * @return ERR_OK if data has been received, an error code otherwise (timeout, 572 * memory error or another error) 573 * ERR_CONN if not connected 574 * ERR_CLSD if TCP connection has been closed 575 * ERR_WOULDBLOCK if the netconn is nonblocking but would block to wait for data 576 * ERR_TIMEOUT if the netconn has a receive timeout and no data was received 577 */ 578 static err_t netconn_recv_data(struct netconn * conn,void ** new_buf,u8_t apiflags)579 netconn_recv_data(struct netconn *conn, void **new_buf, u8_t apiflags) 580 { 581 void *buf = NULL; 582 u16_t len; 583 584 LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); 585 *new_buf = NULL; 586 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); 587 588 if (!NETCONN_RECVMBOX_WAITABLE(conn)) { 589 err_t err = netconn_err(conn); 590 if (err != ERR_OK) { 591 /* return pending error */ 592 return err; 593 } 594 return ERR_CONN; 595 } 596 597 NETCONN_MBOX_WAITING_INC(conn); 598 if (netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK) || 599 (conn->flags & NETCONN_FLAG_MBOXCLOSED) || (conn->pending_err != ERR_OK)) { 600 if (sys_arch_mbox_tryfetch(&conn->recvmbox, &buf) == SYS_MBOX_EMPTY) { 601 err_t err; 602 NETCONN_MBOX_WAITING_DEC(conn); 603 err = netconn_err(conn); 604 if (err != ERR_OK) { 605 /* return pending error */ 606 return err; 607 } 608 if (conn->flags & NETCONN_FLAG_MBOXCLOSED) { 609 return ERR_CONN; 610 } 611 return ERR_WOULDBLOCK; 612 } 613 } else { 614 #if LWIP_SO_RCVTIMEO 615 if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { 616 NETCONN_MBOX_WAITING_DEC(conn); 617 return ERR_TIMEOUT; 618 } 619 #else 620 sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); 621 #endif /* LWIP_SO_RCVTIMEO*/ 622 } 623 NETCONN_MBOX_WAITING_DEC(conn); 624 #if LWIP_NETCONN_FULLDUPLEX 625 if (conn->flags & NETCONN_FLAG_MBOXINVALID) { 626 if (lwip_netconn_is_deallocated_msg(buf)) { 627 /* the netconn has been closed from another thread */ 628 API_MSG_VAR_FREE_ACCEPT(msg); 629 return ERR_CONN; 630 } 631 } 632 #endif 633 634 #if LWIP_TCP 635 #if (LWIP_UDP || LWIP_RAW) 636 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 637 #endif /* (LWIP_UDP || LWIP_RAW) */ 638 { 639 err_t err; 640 /* Check if this is an error message or a pbuf */ 641 if (lwip_netconn_is_err_msg(buf, &err)) { 642 /* new_buf has been zeroed above already */ 643 if (err == ERR_CLSD) { 644 /* connection closed translates to ERR_OK with *new_buf == NULL */ 645 return ERR_OK; 646 } 647 return err; 648 } 649 len = ((struct pbuf *)buf)->tot_len; 650 } 651 #endif /* LWIP_TCP */ 652 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW) 653 else 654 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ 655 #if (LWIP_UDP || LWIP_RAW) 656 { 657 LWIP_ASSERT("buf != NULL", buf != NULL); 658 len = netbuf_len((struct netbuf *)buf); 659 } 660 #endif /* (LWIP_UDP || LWIP_RAW) */ 661 662 #if LWIP_SO_RCVBUF 663 SYS_ARCH_DEC(conn->recv_avail, len); 664 #endif /* LWIP_SO_RCVBUF */ 665 /* Register event with callback */ 666 API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); 667 668 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len)); 669 670 *new_buf = buf; 671 /* don't set conn->last_err: it's only ERR_OK, anyway */ 672 return ERR_OK; 673 } 674 675 #if LWIP_TCP 676 static err_t netconn_tcp_recvd_msg(struct netconn * conn,size_t len,struct api_msg * msg)677 netconn_tcp_recvd_msg(struct netconn *conn, size_t len, struct api_msg *msg) 678 { 679 LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && 680 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); 681 682 msg->conn = conn; 683 msg->msg.r.len = len; 684 685 return netconn_apimsg(lwip_netconn_do_recv, msg); 686 } 687 688 err_t netconn_tcp_recvd(struct netconn * conn,size_t len)689 netconn_tcp_recvd(struct netconn *conn, size_t len) 690 { 691 err_t err; 692 API_MSG_VAR_DECLARE(msg); 693 LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && 694 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); 695 696 API_MSG_VAR_ALLOC(msg); 697 err = netconn_tcp_recvd_msg(conn, len, &API_VAR_REF(msg)); 698 API_MSG_VAR_FREE(msg); 699 return err; 700 } 701 702 static err_t netconn_recv_data_tcp(struct netconn * conn,struct pbuf ** new_buf,u8_t apiflags)703 netconn_recv_data_tcp(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags) 704 { 705 err_t err; 706 struct pbuf *buf; 707 API_MSG_VAR_DECLARE(msg); 708 #if LWIP_MPU_COMPATIBLE 709 msg = NULL; 710 #endif 711 712 if (!NETCONN_RECVMBOX_WAITABLE(conn)) { 713 /* This only happens when calling this function more than once *after* receiving FIN */ 714 return ERR_CONN; 715 } 716 if (netconn_is_flag_set(conn, NETCONN_FIN_RX_PENDING)) { 717 netconn_clear_flags(conn, NETCONN_FIN_RX_PENDING); 718 goto handle_fin; 719 } 720 721 if (!(apiflags & NETCONN_NOAUTORCVD)) { 722 /* need to allocate API message here so empty message pool does not result in event loss 723 * see bug #47512: MPU_COMPATIBLE may fail on empty pool */ 724 API_MSG_VAR_ALLOC(msg); 725 } 726 727 err = netconn_recv_data(conn, (void **)new_buf, apiflags); 728 if (err != ERR_OK) { 729 if (!(apiflags & NETCONN_NOAUTORCVD)) { 730 API_MSG_VAR_FREE(msg); 731 } 732 return err; 733 } 734 buf = *new_buf; 735 if (!(apiflags & NETCONN_NOAUTORCVD)) { 736 /* Let the stack know that we have taken the data. */ 737 u16_t len = buf ? buf->tot_len : 1; 738 /* don't care for the return value of lwip_netconn_do_recv */ 739 /* @todo: this should really be fixed, e.g. by retrying in poll on error */ 740 netconn_tcp_recvd_msg(conn, len, &API_VAR_REF(msg)); 741 API_MSG_VAR_FREE(msg); 742 } 743 744 /* If we are closed, we indicate that we no longer wish to use the socket */ 745 if (buf == NULL) { 746 if (apiflags & NETCONN_NOFIN) { 747 /* received a FIN but the caller cannot handle it right now: 748 re-enqueue it and return "no data" */ 749 netconn_set_flags(conn, NETCONN_FIN_RX_PENDING); 750 return ERR_WOULDBLOCK; 751 } else { 752 handle_fin: 753 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); 754 if (conn->pcb.ip == NULL) { 755 /* race condition: RST during recv */ 756 err = netconn_err(conn); 757 if (err != ERR_OK) { 758 return err; 759 } 760 return ERR_RST; 761 } 762 /* RX side is closed, so deallocate the recvmbox */ 763 netconn_close_shutdown(conn, NETCONN_SHUT_RD); 764 /* Don' store ERR_CLSD as conn->err since we are only half-closed */ 765 return ERR_CLSD; 766 } 767 } 768 return err; 769 } 770 771 /** 772 * @ingroup netconn_tcp 773 * Receive data (in form of a pbuf) from a TCP netconn 774 * 775 * @param conn the netconn from which to receive data 776 * @param new_buf pointer where a new pbuf is stored when received data 777 * @return ERR_OK if data has been received, an error code otherwise (timeout, 778 * memory error or another error, @see netconn_recv_data) 779 * ERR_ARG if conn is not a TCP netconn 780 */ 781 err_t netconn_recv_tcp_pbuf(struct netconn * conn,struct pbuf ** new_buf)782 netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) 783 { 784 LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && 785 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); 786 787 return netconn_recv_data_tcp(conn, new_buf, 0); 788 } 789 790 /** 791 * @ingroup netconn_tcp 792 * Receive data (in form of a pbuf) from a TCP netconn 793 * 794 * @param conn the netconn from which to receive data 795 * @param new_buf pointer where a new pbuf is stored when received data 796 * @param apiflags flags that control function behaviour. For now only: 797 * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data 798 * @return ERR_OK if data has been received, an error code otherwise (timeout, 799 * memory error or another error, @see netconn_recv_data) 800 * ERR_ARG if conn is not a TCP netconn 801 */ 802 err_t netconn_recv_tcp_pbuf_flags(struct netconn * conn,struct pbuf ** new_buf,u8_t apiflags)803 netconn_recv_tcp_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags) 804 { 805 LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && 806 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); 807 808 return netconn_recv_data_tcp(conn, new_buf, apiflags); 809 } 810 #endif /* LWIP_TCP */ 811 812 /** 813 * Receive data (in form of a netbuf) from a UDP or RAW netconn 814 * 815 * @param conn the netconn from which to receive data 816 * @param new_buf pointer where a new netbuf is stored when received data 817 * @return ERR_OK if data has been received, an error code otherwise (timeout, 818 * memory error or another error) 819 * ERR_ARG if conn is not a UDP/RAW netconn 820 */ 821 err_t netconn_recv_udp_raw_netbuf(struct netconn * conn,struct netbuf ** new_buf)822 netconn_recv_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf) 823 { 824 LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) && 825 NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;); 826 827 return netconn_recv_data(conn, (void **)new_buf, 0); 828 } 829 830 /** 831 * Receive data (in form of a netbuf) from a UDP or RAW netconn 832 * 833 * @param conn the netconn from which to receive data 834 * @param new_buf pointer where a new netbuf is stored when received data 835 * @param apiflags flags that control function behaviour. For now only: 836 * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data 837 * @return ERR_OK if data has been received, an error code otherwise (timeout, 838 * memory error or another error) 839 * ERR_ARG if conn is not a UDP/RAW netconn 840 */ 841 err_t netconn_recv_udp_raw_netbuf_flags(struct netconn * conn,struct netbuf ** new_buf,u8_t apiflags)842 netconn_recv_udp_raw_netbuf_flags(struct netconn *conn, struct netbuf **new_buf, u8_t apiflags) 843 { 844 LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) && 845 NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;); 846 847 return netconn_recv_data(conn, (void **)new_buf, apiflags); 848 } 849 850 /** 851 * @ingroup netconn_common 852 * Receive data (in form of a netbuf containing a packet buffer) from a netconn 853 * 854 * @param conn the netconn from which to receive data 855 * @param new_buf pointer where a new netbuf is stored when received data 856 * @return ERR_OK if data has been received, an error code otherwise (timeout, 857 * memory error or another error) 858 */ 859 err_t netconn_recv(struct netconn * conn,struct netbuf ** new_buf)860 netconn_recv(struct netconn *conn, struct netbuf **new_buf) 861 { 862 #if LWIP_TCP 863 struct netbuf *buf = NULL; 864 err_t err; 865 #endif /* LWIP_TCP */ 866 867 LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); 868 *new_buf = NULL; 869 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); 870 871 #if LWIP_TCP 872 #if (LWIP_UDP || LWIP_RAW) 873 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 874 #endif /* (LWIP_UDP || LWIP_RAW) */ 875 { 876 struct pbuf *p = NULL; 877 /* This is not a listening netconn, since recvmbox is set */ 878 879 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 880 if (buf == NULL) { 881 return ERR_MEM; 882 } 883 884 err = netconn_recv_data_tcp(conn, &p, 0); 885 if (err != ERR_OK) { 886 memp_free(MEMP_NETBUF, buf); 887 return err; 888 } 889 LWIP_ASSERT("p != NULL", p != NULL); 890 891 buf->p = p; 892 buf->ptr = p; 893 buf->port = 0; 894 ip_addr_set_zero(&buf->addr); 895 *new_buf = buf; 896 /* don't set conn->last_err: it's only ERR_OK, anyway */ 897 return ERR_OK; 898 } 899 #endif /* LWIP_TCP */ 900 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW) 901 else 902 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ 903 { 904 #if (LWIP_UDP || LWIP_RAW) 905 return netconn_recv_data(conn, (void **)new_buf, 0); 906 #endif /* (LWIP_UDP || LWIP_RAW) */ 907 } 908 } 909 910 /** 911 * @ingroup netconn_udp 912 * Send data (in form of a netbuf) to a specific remote IP address and port. 913 * Only to be used for UDP and RAW netconns (not TCP). 914 * 915 * @param conn the netconn over which to send data 916 * @param buf a netbuf containing the data to send 917 * @param addr the remote IP address to which to send the data 918 * @param port the remote port to which to send the data 919 * @return ERR_OK if data was sent, any other err_t on error 920 */ 921 err_t netconn_sendto(struct netconn * conn,struct netbuf * buf,const ip_addr_t * addr,u16_t port)922 netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port) 923 { 924 if (buf != NULL) { 925 ip_addr_set(&buf->addr, addr); 926 buf->port = port; 927 return netconn_send(conn, buf); 928 } 929 return ERR_VAL; 930 } 931 932 /** 933 * @ingroup netconn_udp 934 * Send data over a UDP or RAW netconn (that is already connected). 935 * 936 * @param conn the UDP or RAW netconn over which to send data 937 * @param buf a netbuf containing the data to send 938 * @return ERR_OK if data was sent, any other err_t on error 939 */ 940 err_t netconn_send(struct netconn * conn,struct netbuf * buf)941 netconn_send(struct netconn *conn, struct netbuf *buf) 942 { 943 API_MSG_VAR_DECLARE(msg); 944 err_t err; 945 946 LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); 947 948 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); 949 950 API_MSG_VAR_ALLOC(msg); 951 API_MSG_VAR_REF(msg).conn = conn; 952 API_MSG_VAR_REF(msg).msg.b = buf; 953 err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg)); 954 API_MSG_VAR_FREE(msg); 955 956 return err; 957 } 958 959 /** 960 * @ingroup netconn_tcp 961 * Send data over a TCP netconn. 962 * 963 * @param conn the TCP netconn over which to send data 964 * @param dataptr pointer to the application buffer that contains the data to send 965 * @param size size of the application data to send 966 * @param apiflags combination of following flags : 967 * - NETCONN_COPY: data will be copied into memory belonging to the stack 968 * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent 969 * - NETCONN_DONTBLOCK: only write the data if all data can be written at once 970 * @param bytes_written pointer to a location that receives the number of written bytes 971 * @return ERR_OK if data was sent, any other err_t on error 972 */ 973 err_t netconn_write_partly(struct netconn * conn,const void * dataptr,size_t size,u8_t apiflags,size_t * bytes_written)974 netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, 975 u8_t apiflags, size_t *bytes_written) 976 { 977 struct netvector vector; 978 vector.ptr = dataptr; 979 vector.len = size; 980 return netconn_write_vectors_partly(conn, &vector, 1, apiflags, bytes_written); 981 } 982 983 /** 984 * Send vectorized data atomically over a TCP netconn. 985 * 986 * @param conn the TCP netconn over which to send data 987 * @param vectors array of vectors containing data to send 988 * @param vectorcnt number of vectors in the array 989 * @param apiflags combination of following flags : 990 * - NETCONN_COPY: data will be copied into memory belonging to the stack 991 * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent 992 * - NETCONN_DONTBLOCK: only write the data if all data can be written at once 993 * @param bytes_written pointer to a location that receives the number of written bytes 994 * @return ERR_OK if data was sent, any other err_t on error 995 */ 996 err_t netconn_write_vectors_partly(struct netconn * conn,struct netvector * vectors,u16_t vectorcnt,u8_t apiflags,size_t * bytes_written)997 netconn_write_vectors_partly(struct netconn *conn, struct netvector *vectors, u16_t vectorcnt, 998 u8_t apiflags, size_t *bytes_written) 999 { 1000 API_MSG_VAR_DECLARE(msg); 1001 err_t err; 1002 u8_t dontblock; 1003 size_t size; 1004 int i; 1005 1006 LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); 1007 LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP), return ERR_VAL;); 1008 dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); 1009 #if LWIP_SO_SNDTIMEO 1010 if (conn->send_timeout != 0) { 1011 dontblock = 1; 1012 } 1013 #endif /* LWIP_SO_SNDTIMEO */ 1014 if (dontblock && !bytes_written) { 1015 /* This implies netconn_write() cannot be used for non-blocking send, since 1016 it has no way to return the number of bytes written. */ 1017 return ERR_VAL; 1018 } 1019 1020 /* sum up the total size */ 1021 size = 0; 1022 for (i = 0; i < vectorcnt; i++) { 1023 size += vectors[i].len; 1024 if (size < vectors[i].len) { 1025 /* overflow */ 1026 return ERR_VAL; 1027 } 1028 } 1029 if (size == 0) { 1030 return ERR_OK; 1031 } else if (size > SSIZE_MAX) { 1032 ssize_t limited; 1033 /* this is required by the socket layer (cannot send full size_t range) */ 1034 if (!bytes_written) { 1035 return ERR_VAL; 1036 } 1037 /* limit the amount of data to send */ 1038 limited = SSIZE_MAX; 1039 size = (size_t)limited; 1040 } 1041 1042 API_MSG_VAR_ALLOC(msg); 1043 /* non-blocking write sends as much */ 1044 API_MSG_VAR_REF(msg).conn = conn; 1045 API_MSG_VAR_REF(msg).msg.w.vector = vectors; 1046 API_MSG_VAR_REF(msg).msg.w.vector_cnt = vectorcnt; 1047 API_MSG_VAR_REF(msg).msg.w.vector_off = 0; 1048 API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags; 1049 API_MSG_VAR_REF(msg).msg.w.len = size; 1050 API_MSG_VAR_REF(msg).msg.w.offset = 0; 1051 #if LWIP_SO_SNDTIMEO 1052 if (conn->send_timeout != 0) { 1053 /* get the time we started, which is later compared to 1054 sys_now() + conn->send_timeout */ 1055 API_MSG_VAR_REF(msg).msg.w.time_started = sys_now(); 1056 } else { 1057 API_MSG_VAR_REF(msg).msg.w.time_started = 0; 1058 } 1059 #endif /* LWIP_SO_SNDTIMEO */ 1060 1061 /* For locking the core: this _can_ be delayed on low memory/low send buffer, 1062 but if it is, this is done inside api_msg.c:do_write(), so we can use the 1063 non-blocking version here. */ 1064 err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg)); 1065 if (err == ERR_OK) { 1066 if (bytes_written != NULL) { 1067 *bytes_written = API_MSG_VAR_REF(msg).msg.w.offset; 1068 } 1069 /* for blocking, check all requested bytes were written, NOTE: send_timeout is 1070 treated as dontblock (see dontblock assignment above) */ 1071 if (!dontblock) { 1072 LWIP_ASSERT("do_write failed to write all bytes", API_MSG_VAR_REF(msg).msg.w.offset == size); 1073 } 1074 } 1075 API_MSG_VAR_FREE(msg); 1076 1077 return err; 1078 } 1079 1080 /** 1081 * @ingroup netconn_tcp 1082 * Close or shutdown a TCP netconn (doesn't delete it). 1083 * 1084 * @param conn the TCP netconn to close or shutdown 1085 * @param how fully close or only shutdown one side? 1086 * @return ERR_OK if the netconn was closed, any other err_t on error 1087 */ 1088 static err_t netconn_close_shutdown(struct netconn * conn,u8_t how)1089 netconn_close_shutdown(struct netconn *conn, u8_t how) 1090 { 1091 API_MSG_VAR_DECLARE(msg); 1092 err_t err; 1093 LWIP_UNUSED_ARG(how); 1094 1095 LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); 1096 1097 API_MSG_VAR_ALLOC(msg); 1098 API_MSG_VAR_REF(msg).conn = conn; 1099 #if LWIP_TCP 1100 /* shutting down both ends is the same as closing */ 1101 API_MSG_VAR_REF(msg).msg.sd.shut = how; 1102 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER 1103 /* get the time we started, which is later compared to 1104 sys_now() + conn->send_timeout */ 1105 API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); 1106 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 1107 API_MSG_VAR_REF(msg).msg.sd.polls_left = 1108 ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; 1109 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 1110 #endif /* LWIP_TCP */ 1111 err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg)); 1112 API_MSG_VAR_FREE(msg); 1113 1114 return err; 1115 } 1116 1117 /** 1118 * @ingroup netconn_tcp 1119 * Close a TCP netconn (doesn't delete it). 1120 * 1121 * @param conn the TCP netconn to close 1122 * @return ERR_OK if the netconn was closed, any other err_t on error 1123 */ 1124 err_t netconn_close(struct netconn * conn)1125 netconn_close(struct netconn *conn) 1126 { 1127 /* shutting down both ends is the same as closing */ 1128 return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR); 1129 } 1130 1131 /** 1132 * @ingroup netconn_common 1133 * Get and reset pending error on a netconn 1134 * 1135 * @param conn the netconn to get the error from 1136 * @return and pending error or ERR_OK if no error was pending 1137 */ 1138 err_t netconn_err(struct netconn * conn)1139 netconn_err(struct netconn *conn) 1140 { 1141 err_t err; 1142 SYS_ARCH_DECL_PROTECT(lev); 1143 if (conn == NULL) { 1144 return ERR_OK; 1145 } 1146 SYS_ARCH_PROTECT(lev); 1147 err = conn->pending_err; 1148 conn->pending_err = ERR_OK; 1149 SYS_ARCH_UNPROTECT(lev); 1150 return err; 1151 } 1152 1153 /** 1154 * @ingroup netconn_tcp 1155 * Shut down one or both sides of a TCP netconn (doesn't delete it). 1156 * 1157 * @param conn the TCP netconn to shut down 1158 * @param shut_rx shut down the RX side (no more read possible after this) 1159 * @param shut_tx shut down the TX side (no more write possible after this) 1160 * @return ERR_OK if the netconn was closed, any other err_t on error 1161 */ 1162 err_t netconn_shutdown(struct netconn * conn,u8_t shut_rx,u8_t shut_tx)1163 netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx) 1164 { 1165 return netconn_close_shutdown(conn, (u8_t)((shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0))); 1166 } 1167 1168 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) 1169 /** 1170 * @ingroup netconn_udp 1171 * Join multicast groups for UDP netconns. 1172 * 1173 * @param conn the UDP netconn for which to change multicast addresses 1174 * @param multiaddr IP address of the multicast group to join or leave 1175 * @param netif_addr the IP address of the network interface on which to send 1176 * the igmp message 1177 * @param join_or_leave flag whether to send a join- or leave-message 1178 * @return ERR_OK if the action was taken, any err_t on error 1179 */ 1180 err_t netconn_join_leave_group(struct netconn * conn,const ip_addr_t * multiaddr,const ip_addr_t * netif_addr,enum netconn_igmp join_or_leave)1181 netconn_join_leave_group(struct netconn *conn, 1182 const ip_addr_t *multiaddr, 1183 const ip_addr_t *netif_addr, 1184 enum netconn_igmp join_or_leave) 1185 { 1186 API_MSG_VAR_DECLARE(msg); 1187 err_t err; 1188 1189 LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); 1190 1191 API_MSG_VAR_ALLOC(msg); 1192 1193 #if LWIP_IPV4 1194 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 1195 if (multiaddr == NULL) { 1196 multiaddr = IP4_ADDR_ANY; 1197 } 1198 if (netif_addr == NULL) { 1199 netif_addr = IP4_ADDR_ANY; 1200 } 1201 #endif /* LWIP_IPV4 */ 1202 1203 API_MSG_VAR_REF(msg).conn = conn; 1204 API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr); 1205 API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr); 1206 API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave; 1207 err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg)); 1208 API_MSG_VAR_FREE(msg); 1209 1210 return err; 1211 } 1212 /** 1213 * @ingroup netconn_udp 1214 * Join multicast groups for UDP netconns. 1215 * 1216 * @param conn the UDP netconn for which to change multicast addresses 1217 * @param multiaddr IP address of the multicast group to join or leave 1218 * @param if_idx the index of the netif 1219 * @param join_or_leave flag whether to send a join- or leave-message 1220 * @return ERR_OK if the action was taken, any err_t on error 1221 */ 1222 err_t netconn_join_leave_group_netif(struct netconn * conn,const ip_addr_t * multiaddr,u8_t if_idx,enum netconn_igmp join_or_leave)1223 netconn_join_leave_group_netif(struct netconn *conn, 1224 const ip_addr_t *multiaddr, 1225 u8_t if_idx, 1226 enum netconn_igmp join_or_leave) 1227 { 1228 API_MSG_VAR_DECLARE(msg); 1229 err_t err; 1230 1231 LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); 1232 1233 API_MSG_VAR_ALLOC(msg); 1234 1235 #if LWIP_IPV4 1236 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 1237 if (multiaddr == NULL) { 1238 multiaddr = IP4_ADDR_ANY; 1239 } 1240 if (if_idx == NETIF_NO_INDEX) { 1241 return ERR_IF; 1242 } 1243 #endif /* LWIP_IPV4 */ 1244 1245 API_MSG_VAR_REF(msg).conn = conn; 1246 API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr); 1247 API_MSG_VAR_REF(msg).msg.jl.if_idx = if_idx; 1248 API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave; 1249 err = netconn_apimsg(lwip_netconn_do_join_leave_group_netif, &API_MSG_VAR_REF(msg)); 1250 API_MSG_VAR_FREE(msg); 1251 1252 return err; 1253 } 1254 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ 1255 1256 #if LWIP_DNS 1257 /** 1258 * @ingroup netconn_common 1259 * Execute a DNS query, only one IP address is returned 1260 * 1261 * @param name a string representation of the DNS host name to query 1262 * @param addr a preallocated ip_addr_t where to store the resolved IP address 1263 * @param dns_addrtype IP address type (IPv4 / IPv6) 1264 * @return ERR_OK: resolving succeeded 1265 * ERR_MEM: memory error, try again later 1266 * ERR_ARG: dns client not initialized or invalid hostname 1267 * ERR_VAL: dns server response was invalid 1268 */ 1269 #if LWIP_IPV4 && LWIP_IPV6 1270 err_t netconn_gethostbyname_addrtype(const char * name,ip_addr_t * addr,u8_t dns_addrtype)1271 netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype) 1272 #else 1273 err_t 1274 netconn_gethostbyname(const char *name, ip_addr_t *addr) 1275 #endif 1276 { 1277 API_VAR_DECLARE(struct dns_api_msg, msg); 1278 #if !LWIP_MPU_COMPATIBLE 1279 sys_sem_t sem; 1280 #endif /* LWIP_MPU_COMPATIBLE */ 1281 err_t err; 1282 err_t cberr; 1283 1284 LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); 1285 LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); 1286 #if LWIP_MPU_COMPATIBLE 1287 if (strlen(name) >= DNS_MAX_NAME_LENGTH) { 1288 return ERR_ARG; 1289 } 1290 #endif 1291 1292 #ifdef LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE 1293 #if LWIP_IPV4 && LWIP_IPV6 1294 if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, dns_addrtype, &err)) { 1295 #else 1296 if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, NETCONN_DNS_DEFAULT, &err)) { 1297 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 1298 return err; 1299 } 1300 #endif /* LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE */ 1301 1302 API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM); 1303 #if LWIP_MPU_COMPATIBLE 1304 strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH - 1); 1305 API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH - 1] = 0; 1306 #else /* LWIP_MPU_COMPATIBLE */ 1307 msg.err = &err; 1308 msg.sem = &sem; 1309 API_VAR_REF(msg).addr = API_VAR_REF(addr); 1310 API_VAR_REF(msg).name = name; 1311 #endif /* LWIP_MPU_COMPATIBLE */ 1312 #if LWIP_IPV4 && LWIP_IPV6 1313 API_VAR_REF(msg).dns_addrtype = dns_addrtype; 1314 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 1315 #if LWIP_NETCONN_SEM_PER_THREAD 1316 API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET(); 1317 #else /* LWIP_NETCONN_SEM_PER_THREAD*/ 1318 err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0); 1319 if (err != ERR_OK) { 1320 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 1321 return err; 1322 } 1323 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 1324 1325 cberr = tcpip_send_msg_wait_sem(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg), API_EXPR_REF(API_VAR_REF(msg).sem)); 1326 #if !LWIP_NETCONN_SEM_PER_THREAD 1327 sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); 1328 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ 1329 if (cberr != ERR_OK) { 1330 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 1331 return cberr; 1332 } 1333 1334 #if LWIP_MPU_COMPATIBLE 1335 *addr = msg->addr; 1336 err = msg->err; 1337 #endif /* LWIP_MPU_COMPATIBLE */ 1338 1339 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 1340 return err; 1341 } 1342 #endif /* LWIP_DNS*/ 1343 1344 #if LWIP_NETCONN_SEM_PER_THREAD 1345 void 1346 netconn_thread_init(void) 1347 { 1348 sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); 1349 if (!sys_sem_valid(sem)) { 1350 /* call alloc only once */ 1351 LWIP_NETCONN_THREAD_SEM_ALLOC(); 1352 LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET())); 1353 } 1354 } 1355 1356 void 1357 netconn_thread_cleanup(void) 1358 { 1359 sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); 1360 if (sys_sem_valid(sem)) { 1361 /* call free only once */ 1362 LWIP_NETCONN_THREAD_SEM_FREE(); 1363 } 1364 } 1365 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 1366 1367 #endif /* LWIP_NETCONN */ 1368