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 <[email protected]> 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 #include <string.h> 73 74 #define API_MSG_VAR_REF(name) API_VAR_REF(name) 75 #define API_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct api_msg, name) 76 #define API_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, ERR_MEM) 77 #define API_MSG_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, NULL) 78 #define API_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_API_MSG, name) 79 80 static err_t netconn_close_shutdown(struct netconn *conn, u8_t how); 81 82 /** 83 * Call the lower part of a netconn_* function 84 * This function is then running in the thread context 85 * of tcpip_thread and has exclusive access to lwIP core code. 86 * 87 * @param fn function to call 88 * @param apimsg a struct containing the function to call and its parameters 89 * @return ERR_OK if the function was called, another err_t if not 90 */ 91 static err_t 92 netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg) 93 { 94 err_t err; 95 96 #ifdef LWIP_DEBUG 97 /* catch functions that don't set err */ 98 apimsg->err = ERR_VAL; 99 #endif /* LWIP_DEBUG */ 100 101 #if LWIP_NETCONN_SEM_PER_THREAD 102 apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); 103 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 104 105 err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg)); 106 if (err == ERR_OK) { 107 return apimsg->err; 108 } 109 return err; 110 } 111 112 /** 113 * Create a new netconn (of a specific type) that has a callback function. 114 * The corresponding pcb is also created. 115 * 116 * @param t the type of 'connection' to create (@see enum netconn_type) 117 * @param proto the IP protocol for RAW IP pcbs 118 * @param callback a function to call on status changes (RX available, TX'ed) 119 * @return a newly allocated struct netconn or 120 * NULL on memory error 121 */ 122 struct netconn* 123 netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) 124 { 125 struct netconn *conn; 126 API_MSG_VAR_DECLARE(msg); 127 API_MSG_VAR_ALLOC_RETURN_NULL(msg); 128 129 conn = netconn_alloc(t, callback); 130 if (conn != NULL) { 131 err_t err; 132 133 API_MSG_VAR_REF(msg).msg.n.proto = proto; 134 API_MSG_VAR_REF(msg).conn = conn; 135 err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg)); 136 if (err != ERR_OK) { 137 LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); 138 LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox)); 139 #if LWIP_TCP 140 LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox)); 141 #endif /* LWIP_TCP */ 142 #if !LWIP_NETCONN_SEM_PER_THREAD 143 LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed)); 144 sys_sem_free(&conn->op_completed); 145 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ 146 sys_mbox_free(&conn->recvmbox); 147 memp_free(MEMP_NETCONN, conn); 148 API_MSG_VAR_FREE(msg); 149 return NULL; 150 } 151 } 152 API_MSG_VAR_FREE(msg); 153 return conn; 154 } 155 156 /** 157 * @ingroup netconn_common 158 * Close a netconn 'connection' and free its resources. 159 * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate 160 * after this returns. 161 * 162 * @param conn the netconn to delete 163 * @return ERR_OK if the connection was deleted 164 */ 165 err_t 166 netconn_delete(struct netconn *conn) 167 { 168 err_t err; 169 API_MSG_VAR_DECLARE(msg); 170 171 /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ 172 if (conn == NULL) { 173 return ERR_OK; 174 } 175 176 API_MSG_VAR_ALLOC(msg); 177 API_MSG_VAR_REF(msg).conn = conn; 178 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER 179 /* get the time we started, which is later compared to 180 sys_now() + conn->send_timeout */ 181 API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); 182 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 183 #if LWIP_TCP 184 API_MSG_VAR_REF(msg).msg.sd.polls_left = 185 ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; 186 #endif /* LWIP_TCP */ 187 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 188 err = netconn_apimsg(lwip_netconn_do_delconn, &API_MSG_VAR_REF(msg)); 189 API_MSG_VAR_FREE(msg); 190 191 if (err != ERR_OK) { 192 return err; 193 } 194 195 netconn_free(conn); 196 197 return ERR_OK; 198 } 199 200 /** 201 * Get the local or remote IP address and port of a netconn. 202 * For RAW netconns, this returns the protocol instead of a port! 203 * 204 * @param conn the netconn to query 205 * @param addr a pointer to which to save the IP address 206 * @param port a pointer to which to save the port (or protocol for RAW) 207 * @param local 1 to get the local IP address, 0 to get the remote one 208 * @return ERR_CONN for invalid connections 209 * ERR_OK if the information was retrieved 210 */ 211 err_t 212 netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) 213 { 214 API_MSG_VAR_DECLARE(msg); 215 err_t err; 216 217 LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); 218 LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); 219 LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;); 220 221 API_MSG_VAR_ALLOC(msg); 222 API_MSG_VAR_REF(msg).conn = conn; 223 API_MSG_VAR_REF(msg).msg.ad.local = local; 224 #if LWIP_MPU_COMPATIBLE 225 err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg)); 226 *addr = msg->msg.ad.ipaddr; 227 *port = msg->msg.ad.port; 228 #else /* LWIP_MPU_COMPATIBLE */ 229 msg.msg.ad.ipaddr = addr; 230 msg.msg.ad.port = port; 231 err = netconn_apimsg(lwip_netconn_do_getaddr, &msg); 232 #endif /* LWIP_MPU_COMPATIBLE */ 233 API_MSG_VAR_FREE(msg); 234 235 return err; 236 } 237 238 /** 239 * @ingroup netconn_common 240 * Bind a netconn to a specific local IP address and port. 241 * Binding one netconn twice might not always be checked correctly! 242 * 243 * @param conn the netconn to bind 244 * @param addr the local IP address to bind the netconn to 245 * (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses) 246 * @param port the local port to bind the netconn to (not used for RAW) 247 * @return ERR_OK if bound, any other err_t on failure 248 */ 249 err_t 250 netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) 251 { 252 API_MSG_VAR_DECLARE(msg); 253 err_t err; 254 255 LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); 256 257 #if LWIP_IPV4 258 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 259 if (addr == NULL) { 260 addr = IP4_ADDR_ANY; 261 } 262 #endif /* LWIP_IPV4 */ 263 264 #if LWIP_IPV4 && LWIP_IPV6 265 /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY, 266 * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind 267 */ 268 if ((netconn_get_ipv6only(conn) == 0) && 269 ip_addr_cmp(addr, IP6_ADDR_ANY)) { 270 addr = IP_ANY_TYPE; 271 } 272 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 273 274 API_MSG_VAR_ALLOC(msg); 275 API_MSG_VAR_REF(msg).conn = conn; 276 API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); 277 API_MSG_VAR_REF(msg).msg.bc.port = port; 278 err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg)); 279 API_MSG_VAR_FREE(msg); 280 281 return err; 282 } 283 284 /** 285 * @ingroup netconn_common 286 * Connect a netconn to a specific remote IP address and port. 287 * 288 * @param conn the netconn to connect 289 * @param addr the remote IP address to connect to 290 * @param port the remote port to connect to (no used for RAW) 291 * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise 292 */ 293 err_t 294 netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) 295 { 296 API_MSG_VAR_DECLARE(msg); 297 err_t err; 298 299 LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); 300 301 #if LWIP_IPV4 302 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 303 if (addr == NULL) { 304 addr = IP4_ADDR_ANY; 305 } 306 #endif /* LWIP_IPV4 */ 307 308 API_MSG_VAR_ALLOC(msg); 309 API_MSG_VAR_REF(msg).conn = conn; 310 API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); 311 API_MSG_VAR_REF(msg).msg.bc.port = port; 312 err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg)); 313 API_MSG_VAR_FREE(msg); 314 315 return err; 316 } 317 318 /** 319 * @ingroup netconn_udp 320 * Disconnect a netconn from its current peer (only valid for UDP netconns). 321 * 322 * @param conn the netconn to disconnect 323 * @return See @ref err_t 324 */ 325 err_t 326 netconn_disconnect(struct netconn *conn) 327 { 328 API_MSG_VAR_DECLARE(msg); 329 err_t err; 330 331 LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); 332 333 API_MSG_VAR_ALLOC(msg); 334 API_MSG_VAR_REF(msg).conn = conn; 335 err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg)); 336 API_MSG_VAR_FREE(msg); 337 338 return err; 339 } 340 341 /** 342 * @ingroup netconn_tcp 343 * Set a TCP netconn into listen mode 344 * 345 * @param conn the tcp netconn to set to listen mode 346 * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1 347 * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns 348 * don't return any error (yet?)) 349 */ 350 err_t 351 netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) 352 { 353 #if LWIP_TCP 354 API_MSG_VAR_DECLARE(msg); 355 err_t err; 356 357 /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ 358 LWIP_UNUSED_ARG(backlog); 359 360 LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); 361 362 API_MSG_VAR_ALLOC(msg); 363 API_MSG_VAR_REF(msg).conn = conn; 364 #if TCP_LISTEN_BACKLOG 365 API_MSG_VAR_REF(msg).msg.lb.backlog = backlog; 366 #endif /* TCP_LISTEN_BACKLOG */ 367 err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg)); 368 API_MSG_VAR_FREE(msg); 369 370 return err; 371 #else /* LWIP_TCP */ 372 LWIP_UNUSED_ARG(conn); 373 LWIP_UNUSED_ARG(backlog); 374 return ERR_ARG; 375 #endif /* LWIP_TCP */ 376 } 377 378 /** 379 * @ingroup netconn_tcp 380 * Accept a new connection on a TCP listening netconn. 381 * 382 * @param conn the TCP listen netconn 383 * @param new_conn pointer where the new connection is stored 384 * @return ERR_OK if a new connection has been received or an error 385 * code otherwise 386 */ 387 err_t 388 netconn_accept(struct netconn *conn, struct netconn **new_conn) 389 { 390 #if LWIP_TCP 391 void *accept_ptr; 392 struct netconn *newconn; 393 #if TCP_LISTEN_BACKLOG 394 API_MSG_VAR_DECLARE(msg); 395 #endif /* TCP_LISTEN_BACKLOG */ 396 397 LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;); 398 *new_conn = NULL; 399 LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); 400 401 if (ERR_IS_FATAL(conn->last_err)) { 402 /* don't recv on fatal errors: this might block the application task 403 waiting on acceptmbox forever! */ 404 return conn->last_err; 405 } 406 if (!sys_mbox_valid(&conn->acceptmbox)) { 407 return ERR_CLSD; 408 } 409 410 #if TCP_LISTEN_BACKLOG 411 API_MSG_VAR_ALLOC(msg); 412 #endif /* TCP_LISTEN_BACKLOG */ 413 414 #if LWIP_SO_RCVTIMEO 415 if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { 416 #if TCP_LISTEN_BACKLOG 417 API_MSG_VAR_FREE(msg); 418 #endif /* TCP_LISTEN_BACKLOG */ 419 return ERR_TIMEOUT; 420 } 421 #else 422 sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); 423 #endif /* LWIP_SO_RCVTIMEO*/ 424 newconn = (struct netconn *)accept_ptr; 425 /* Register event with callback */ 426 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); 427 428 if (accept_ptr == &netconn_aborted) { 429 /* a connection has been aborted: out of pcbs or out of netconns during accept */ 430 /* @todo: set netconn error, but this would be fatal and thus block further accepts */ 431 #if TCP_LISTEN_BACKLOG 432 API_MSG_VAR_FREE(msg); 433 #endif /* TCP_LISTEN_BACKLOG */ 434 return ERR_ABRT; 435 } 436 if (newconn == NULL) { 437 /* connection has been aborted */ 438 /* in this special case, we set the netconn error from application thread, as 439 on a ready-to-accept listening netconn, there should not be anything running 440 in tcpip_thread */ 441 NETCONN_SET_SAFE_ERR(conn, ERR_CLSD); 442 #if TCP_LISTEN_BACKLOG 443 API_MSG_VAR_FREE(msg); 444 #endif /* TCP_LISTEN_BACKLOG */ 445 return ERR_CLSD; 446 } 447 #if TCP_LISTEN_BACKLOG 448 /* Let the stack know that we have accepted the connection. */ 449 API_MSG_VAR_REF(msg).conn = newconn; 450 /* don't care for the return value of lwip_netconn_do_recv */ 451 netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg)); 452 API_MSG_VAR_FREE(msg); 453 #endif /* TCP_LISTEN_BACKLOG */ 454 455 *new_conn = newconn; 456 /* don't set conn->last_err: it's only ERR_OK, anyway */ 457 return ERR_OK; 458 #else /* LWIP_TCP */ 459 LWIP_UNUSED_ARG(conn); 460 LWIP_UNUSED_ARG(new_conn); 461 return ERR_ARG; 462 #endif /* LWIP_TCP */ 463 } 464 465 /** 466 * @ingroup netconn_common 467 * Receive data: actual implementation that doesn't care whether pbuf or netbuf 468 * is received 469 * 470 * @param conn the netconn from which to receive data 471 * @param new_buf pointer where a new pbuf/netbuf is stored when received data 472 * @return ERR_OK if data has been received, an error code otherwise (timeout, 473 * memory error or another error) 474 */ 475 static err_t 476 netconn_recv_data(struct netconn *conn, void **new_buf) 477 { 478 void *buf = NULL; 479 u16_t len; 480 #if LWIP_TCP 481 API_MSG_VAR_DECLARE(msg); 482 #if LWIP_MPU_COMPATIBLE 483 msg = NULL; 484 #endif 485 #endif /* LWIP_TCP */ 486 487 LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); 488 *new_buf = NULL; 489 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); 490 #if LWIP_TCP 491 #if (LWIP_UDP || LWIP_RAW) 492 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 493 #endif /* (LWIP_UDP || LWIP_RAW) */ 494 { 495 if (!sys_mbox_valid(&conn->recvmbox)) { 496 /* This happens when calling this function after receiving FIN */ 497 return sys_mbox_valid(&conn->acceptmbox) ? ERR_CONN : ERR_CLSD; 498 } 499 } 500 #endif /* LWIP_TCP */ 501 LWIP_ERROR("netconn_recv: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); 502 503 if (ERR_IS_FATAL(conn->last_err)) { 504 /* don't recv on fatal errors: this might block the application task 505 waiting on recvmbox forever! */ 506 /* @todo: this does not allow us to fetch data that has been put into recvmbox 507 before the fatal error occurred - is that a problem? */ 508 return conn->last_err; 509 } 510 #if LWIP_TCP 511 #if (LWIP_UDP || LWIP_RAW) 512 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 513 #endif /* (LWIP_UDP || LWIP_RAW) */ 514 { 515 API_MSG_VAR_ALLOC(msg); 516 } 517 #endif /* LWIP_TCP */ 518 519 #if LWIP_SO_RCVTIMEO 520 if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { 521 #if LWIP_TCP 522 #if (LWIP_UDP || LWIP_RAW) 523 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 524 #endif /* (LWIP_UDP || LWIP_RAW) */ 525 { 526 API_MSG_VAR_FREE(msg); 527 } 528 #endif /* LWIP_TCP */ 529 return ERR_TIMEOUT; 530 } 531 #else 532 sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); 533 #endif /* LWIP_SO_RCVTIMEO*/ 534 535 #if LWIP_TCP 536 #if (LWIP_UDP || LWIP_RAW) 537 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 538 #endif /* (LWIP_UDP || LWIP_RAW) */ 539 { 540 /* Let the stack know that we have taken the data. */ 541 /* @todo: Speedup: Don't block and wait for the answer here 542 (to prevent multiple thread-switches). */ 543 API_MSG_VAR_REF(msg).conn = conn; 544 if (buf != NULL) { 545 API_MSG_VAR_REF(msg).msg.r.len = ((struct pbuf *)buf)->tot_len; 546 } else { 547 API_MSG_VAR_REF(msg).msg.r.len = 1; 548 } 549 550 /* don't care for the return value of lwip_netconn_do_recv */ 551 netconn_apimsg(lwip_netconn_do_recv, &API_MSG_VAR_REF(msg)); 552 API_MSG_VAR_FREE(msg); 553 554 /* If we are closed, we indicate that we no longer wish to use the socket */ 555 if (buf == NULL) { 556 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); 557 if (conn->pcb.ip == NULL) { 558 /* race condition: RST during recv */ 559 return conn->last_err == ERR_OK ? ERR_RST : conn->last_err; 560 } 561 /* RX side is closed, so deallocate the recvmbox */ 562 netconn_close_shutdown(conn, NETCONN_SHUT_RD); 563 /* Don' store ERR_CLSD as conn->err since we are only half-closed */ 564 return ERR_CLSD; 565 } 566 len = ((struct pbuf *)buf)->tot_len; 567 } 568 #endif /* LWIP_TCP */ 569 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW) 570 else 571 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ 572 #if (LWIP_UDP || LWIP_RAW) 573 { 574 LWIP_ASSERT("buf != NULL", buf != NULL); 575 len = netbuf_len((struct netbuf*)buf); 576 } 577 #endif /* (LWIP_UDP || LWIP_RAW) */ 578 579 #if LWIP_SO_RCVBUF 580 SYS_ARCH_DEC(conn->recv_avail, len); 581 #endif /* LWIP_SO_RCVBUF */ 582 /* Register event with callback */ 583 API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); 584 585 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len)); 586 587 *new_buf = buf; 588 /* don't set conn->last_err: it's only ERR_OK, anyway */ 589 return ERR_OK; 590 } 591 592 /** 593 * @ingroup netconn_tcp 594 * Receive data (in form of a pbuf) from a TCP netconn 595 * 596 * @param conn the netconn from which to receive data 597 * @param new_buf pointer where a new pbuf is stored when received data 598 * @return ERR_OK if data has been received, an error code otherwise (timeout, 599 * memory error or another error) 600 * ERR_ARG if conn is not a TCP netconn 601 */ 602 err_t 603 netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) 604 { 605 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) && 606 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); 607 608 return netconn_recv_data(conn, (void **)new_buf); 609 } 610 611 /** 612 * @ingroup netconn_common 613 * Receive data (in form of a netbuf containing a packet buffer) from a netconn 614 * 615 * @param conn the netconn from which to receive data 616 * @param new_buf pointer where a new netbuf is stored when received data 617 * @return ERR_OK if data has been received, an error code otherwise (timeout, 618 * memory error or another error) 619 */ 620 err_t 621 netconn_recv(struct netconn *conn, struct netbuf **new_buf) 622 { 623 #if LWIP_TCP 624 struct netbuf *buf = NULL; 625 err_t err; 626 #endif /* LWIP_TCP */ 627 628 LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); 629 *new_buf = NULL; 630 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); 631 632 #if LWIP_TCP 633 #if (LWIP_UDP || LWIP_RAW) 634 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 635 #endif /* (LWIP_UDP || LWIP_RAW) */ 636 { 637 struct pbuf *p = NULL; 638 /* This is not a listening netconn, since recvmbox is set */ 639 640 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 641 if (buf == NULL) { 642 return ERR_MEM; 643 } 644 645 err = netconn_recv_data(conn, (void **)&p); 646 if (err != ERR_OK) { 647 memp_free(MEMP_NETBUF, buf); 648 return err; 649 } 650 LWIP_ASSERT("p != NULL", p != NULL); 651 652 buf->p = p; 653 buf->ptr = p; 654 buf->port = 0; 655 ip_addr_set_zero(&buf->addr); 656 *new_buf = buf; 657 /* don't set conn->last_err: it's only ERR_OK, anyway */ 658 return ERR_OK; 659 } 660 #endif /* LWIP_TCP */ 661 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW) 662 else 663 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ 664 { 665 #if (LWIP_UDP || LWIP_RAW) 666 return netconn_recv_data(conn, (void **)new_buf); 667 #endif /* (LWIP_UDP || LWIP_RAW) */ 668 } 669 } 670 671 /** 672 * @ingroup netconn_udp 673 * Send data (in form of a netbuf) to a specific remote IP address and port. 674 * Only to be used for UDP and RAW netconns (not TCP). 675 * 676 * @param conn the netconn over which to send data 677 * @param buf a netbuf containing the data to send 678 * @param addr the remote IP address to which to send the data 679 * @param port the remote port to which to send the data 680 * @return ERR_OK if data was sent, any other err_t on error 681 */ 682 err_t 683 netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port) 684 { 685 if (buf != NULL) { 686 ip_addr_set(&buf->addr, addr); 687 buf->port = port; 688 return netconn_send(conn, buf); 689 } 690 return ERR_VAL; 691 } 692 693 /** 694 * @ingroup netconn_udp 695 * Send data over a UDP or RAW netconn (that is already connected). 696 * 697 * @param conn the UDP or RAW netconn over which to send data 698 * @param buf a netbuf containing the data to send 699 * @return ERR_OK if data was sent, any other err_t on error 700 */ 701 err_t 702 netconn_send(struct netconn *conn, struct netbuf *buf) 703 { 704 API_MSG_VAR_DECLARE(msg); 705 err_t err; 706 707 LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); 708 709 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); 710 711 API_MSG_VAR_ALLOC(msg); 712 API_MSG_VAR_REF(msg).conn = conn; 713 API_MSG_VAR_REF(msg).msg.b = buf; 714 err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg)); 715 API_MSG_VAR_FREE(msg); 716 717 return err; 718 } 719 720 /** 721 * @ingroup netconn_tcp 722 * Send data over a TCP netconn. 723 * 724 * @param conn the TCP netconn over which to send data 725 * @param dataptr pointer to the application buffer that contains the data to send 726 * @param size size of the application data to send 727 * @param apiflags combination of following flags : 728 * - NETCONN_COPY: data will be copied into memory belonging to the stack 729 * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent 730 * - NETCONN_DONTBLOCK: only write the data if all data can be written at once 731 * @param bytes_written pointer to a location that receives the number of written bytes 732 * @return ERR_OK if data was sent, any other err_t on error 733 */ 734 err_t 735 netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, 736 u8_t apiflags, size_t *bytes_written) 737 { 738 API_MSG_VAR_DECLARE(msg); 739 err_t err; 740 u8_t dontblock; 741 742 LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); 743 LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;); 744 if (size == 0) { 745 return ERR_OK; 746 } 747 dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); 748 #if LWIP_SO_SNDTIMEO 749 if (conn->send_timeout != 0) { 750 dontblock = 1; 751 } 752 #endif /* LWIP_SO_SNDTIMEO */ 753 if (dontblock && !bytes_written) { 754 /* This implies netconn_write() cannot be used for non-blocking send, since 755 it has no way to return the number of bytes written. */ 756 return ERR_VAL; 757 } 758 759 API_MSG_VAR_ALLOC(msg); 760 /* non-blocking write sends as much */ 761 API_MSG_VAR_REF(msg).conn = conn; 762 API_MSG_VAR_REF(msg).msg.w.dataptr = dataptr; 763 API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags; 764 API_MSG_VAR_REF(msg).msg.w.len = size; 765 #if LWIP_SO_SNDTIMEO 766 if (conn->send_timeout != 0) { 767 /* get the time we started, which is later compared to 768 sys_now() + conn->send_timeout */ 769 API_MSG_VAR_REF(msg).msg.w.time_started = sys_now(); 770 } else { 771 API_MSG_VAR_REF(msg).msg.w.time_started = 0; 772 } 773 #endif /* LWIP_SO_SNDTIMEO */ 774 775 /* For locking the core: this _can_ be delayed on low memory/low send buffer, 776 but if it is, this is done inside api_msg.c:do_write(), so we can use the 777 non-blocking version here. */ 778 err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg)); 779 if ((err == ERR_OK) && (bytes_written != NULL)) { 780 if (dontblock) { 781 /* nonblocking write: maybe the data has been sent partly */ 782 *bytes_written = API_MSG_VAR_REF(msg).msg.w.len; 783 } else { 784 /* blocking call succeeded: all data has been sent if it */ 785 *bytes_written = size; 786 } 787 } 788 API_MSG_VAR_FREE(msg); 789 790 return err; 791 } 792 793 /** 794 * @ingroup netconn_tcp 795 * Close or shutdown a TCP netconn (doesn't delete it). 796 * 797 * @param conn the TCP netconn to close or shutdown 798 * @param how fully close or only shutdown one side? 799 * @return ERR_OK if the netconn was closed, any other err_t on error 800 */ 801 static err_t 802 netconn_close_shutdown(struct netconn *conn, u8_t how) 803 { 804 API_MSG_VAR_DECLARE(msg); 805 err_t err; 806 LWIP_UNUSED_ARG(how); 807 808 LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); 809 810 API_MSG_VAR_ALLOC(msg); 811 API_MSG_VAR_REF(msg).conn = conn; 812 #if LWIP_TCP 813 /* shutting down both ends is the same as closing */ 814 API_MSG_VAR_REF(msg).msg.sd.shut = how; 815 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER 816 /* get the time we started, which is later compared to 817 sys_now() + conn->send_timeout */ 818 API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); 819 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 820 API_MSG_VAR_REF(msg).msg.sd.polls_left = 821 ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; 822 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 823 #endif /* LWIP_TCP */ 824 err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg)); 825 API_MSG_VAR_FREE(msg); 826 827 return err; 828 } 829 830 /** 831 * @ingroup netconn_tcp 832 * Close a TCP netconn (doesn't delete it). 833 * 834 * @param conn the TCP netconn to close 835 * @return ERR_OK if the netconn was closed, any other err_t on error 836 */ 837 err_t 838 netconn_close(struct netconn *conn) 839 { 840 /* shutting down both ends is the same as closing */ 841 return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR); 842 } 843 844 /** 845 * @ingroup netconn_tcp 846 * Shut down one or both sides of a TCP netconn (doesn't delete it). 847 * 848 * @param conn the TCP netconn to shut down 849 * @param shut_rx shut down the RX side (no more read possible after this) 850 * @param shut_tx shut down the TX side (no more write possible after this) 851 * @return ERR_OK if the netconn was closed, any other err_t on error 852 */ 853 err_t 854 netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx) 855 { 856 return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)); 857 } 858 859 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) 860 /** 861 * @ingroup netconn_udp 862 * Join multicast groups for UDP netconns. 863 * 864 * @param conn the UDP netconn for which to change multicast addresses 865 * @param multiaddr IP address of the multicast group to join or leave 866 * @param netif_addr the IP address of the network interface on which to send 867 * the igmp message 868 * @param join_or_leave flag whether to send a join- or leave-message 869 * @return ERR_OK if the action was taken, any err_t on error 870 */ 871 err_t 872 netconn_join_leave_group(struct netconn *conn, 873 const ip_addr_t *multiaddr, 874 const ip_addr_t *netif_addr, 875 enum netconn_igmp join_or_leave) 876 { 877 API_MSG_VAR_DECLARE(msg); 878 err_t err; 879 880 LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); 881 882 API_MSG_VAR_ALLOC(msg); 883 884 #if LWIP_IPV4 885 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 886 if (multiaddr == NULL) { 887 multiaddr = IP4_ADDR_ANY; 888 } 889 if (netif_addr == NULL) { 890 netif_addr = IP4_ADDR_ANY; 891 } 892 #endif /* LWIP_IPV4 */ 893 894 API_MSG_VAR_REF(msg).conn = conn; 895 API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr); 896 API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr); 897 API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave; 898 err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg)); 899 API_MSG_VAR_FREE(msg); 900 901 return err; 902 } 903 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ 904 905 #if LWIP_DNS 906 /** 907 * @ingroup netconn_common 908 * Execute a DNS query, only one IP address is returned 909 * 910 * @param name a string representation of the DNS host name to query 911 * @param addr a preallocated ip_addr_t where to store the resolved IP address 912 * @param dns_addrtype IP address type (IPv4 / IPv6) 913 * @return ERR_OK: resolving succeeded 914 * ERR_MEM: memory error, try again later 915 * ERR_ARG: dns client not initialized or invalid hostname 916 * ERR_VAL: dns server response was invalid 917 */ 918 #if LWIP_IPV4 && LWIP_IPV6 919 err_t 920 netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype) 921 #else 922 err_t 923 netconn_gethostbyname(const char *name, ip_addr_t *addr) 924 #endif 925 { 926 API_VAR_DECLARE(struct dns_api_msg, msg); 927 #if !LWIP_MPU_COMPATIBLE 928 sys_sem_t sem; 929 #endif /* LWIP_MPU_COMPATIBLE */ 930 err_t err; 931 err_t cberr; 932 933 LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); 934 LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); 935 #if LWIP_MPU_COMPATIBLE 936 if (strlen(name) >= DNS_MAX_NAME_LENGTH) { 937 return ERR_ARG; 938 } 939 #endif 940 941 API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM); 942 #if LWIP_MPU_COMPATIBLE 943 strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH-1); 944 API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH-1] = 0; 945 #else /* LWIP_MPU_COMPATIBLE */ 946 msg.err = &err; 947 msg.sem = &sem; 948 API_VAR_REF(msg).addr = API_VAR_REF(addr); 949 API_VAR_REF(msg).name = name; 950 #endif /* LWIP_MPU_COMPATIBLE */ 951 #if LWIP_IPV4 && LWIP_IPV6 952 API_VAR_REF(msg).dns_addrtype = dns_addrtype; 953 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 954 #if LWIP_NETCONN_SEM_PER_THREAD 955 API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET(); 956 #else /* LWIP_NETCONN_SEM_PER_THREAD*/ 957 err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0); 958 if (err != ERR_OK) { 959 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 960 return err; 961 } 962 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 963 964 cberr = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg)); 965 if (cberr != ERR_OK) { 966 #if !LWIP_NETCONN_SEM_PER_THREAD 967 sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); 968 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ 969 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 970 return cberr; 971 } 972 sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem)); 973 #if !LWIP_NETCONN_SEM_PER_THREAD 974 sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); 975 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ 976 977 #if LWIP_MPU_COMPATIBLE 978 *addr = msg->addr; 979 err = msg->err; 980 #endif /* LWIP_MPU_COMPATIBLE */ 981 982 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 983 return err; 984 } 985 #endif /* LWIP_DNS*/ 986 987 #if LWIP_NETCONN_SEM_PER_THREAD 988 void 989 netconn_thread_init(void) 990 { 991 sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); 992 if ((sem == NULL) || !sys_sem_valid(sem)) { 993 /* call alloc only once */ 994 LWIP_NETCONN_THREAD_SEM_ALLOC(); 995 LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET())); 996 } 997 } 998 999 void 1000 netconn_thread_cleanup(void) 1001 { 1002 sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); 1003 if ((sem != NULL) && sys_sem_valid(sem)) { 1004 /* call free only once */ 1005 LWIP_NETCONN_THREAD_SEM_FREE(); 1006 } 1007 } 1008 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 1009 1010 #endif /* LWIP_NETCONN */ 1011