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 #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 /* need to allocate API message here so empty message pool does not result in event loss 412 * see bug #47512: MPU_COMPATIBLE may fail on empty pool */ 413 API_MSG_VAR_ALLOC(msg); 414 #endif /* TCP_LISTEN_BACKLOG */ 415 416 if (netconn_is_nonblocking(conn)) { 417 if (sys_arch_mbox_tryfetch(&conn->acceptmbox, &accept_ptr) == SYS_ARCH_TIMEOUT) { 418 #if TCP_LISTEN_BACKLOG 419 API_MSG_VAR_FREE(msg); 420 #endif /* TCP_LISTEN_BACKLOG */ 421 return ERR_WOULDBLOCK; 422 } 423 } else { 424 #if LWIP_SO_RCVTIMEO 425 if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { 426 #if TCP_LISTEN_BACKLOG 427 API_MSG_VAR_FREE(msg); 428 #endif /* TCP_LISTEN_BACKLOG */ 429 return ERR_TIMEOUT; 430 } 431 #else 432 sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); 433 #endif /* LWIP_SO_RCVTIMEO*/ 434 } 435 newconn = (struct netconn *)accept_ptr; 436 /* Register event with callback */ 437 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); 438 439 if (accept_ptr == &netconn_aborted) { 440 /* a connection has been aborted: out of pcbs or out of netconns during accept */ 441 /* @todo: set netconn error, but this would be fatal and thus block further accepts */ 442 #if TCP_LISTEN_BACKLOG 443 API_MSG_VAR_FREE(msg); 444 #endif /* TCP_LISTEN_BACKLOG */ 445 return ERR_ABRT; 446 } 447 if (newconn == NULL) { 448 /* connection has been aborted */ 449 /* in this special case, we set the netconn error from application thread, as 450 on a ready-to-accept listening netconn, there should not be anything running 451 in tcpip_thread */ 452 NETCONN_SET_SAFE_ERR(conn, ERR_CLSD); 453 #if TCP_LISTEN_BACKLOG 454 API_MSG_VAR_FREE(msg); 455 #endif /* TCP_LISTEN_BACKLOG */ 456 return ERR_CLSD; 457 } 458 #if TCP_LISTEN_BACKLOG 459 /* Let the stack know that we have accepted the connection. */ 460 API_MSG_VAR_REF(msg).conn = newconn; 461 /* don't care for the return value of lwip_netconn_do_recv */ 462 netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg)); 463 API_MSG_VAR_FREE(msg); 464 #endif /* TCP_LISTEN_BACKLOG */ 465 466 *new_conn = newconn; 467 /* don't set conn->last_err: it's only ERR_OK, anyway */ 468 return ERR_OK; 469 #else /* LWIP_TCP */ 470 LWIP_UNUSED_ARG(conn); 471 LWIP_UNUSED_ARG(new_conn); 472 return ERR_ARG; 473 #endif /* LWIP_TCP */ 474 } 475 476 /** 477 * @ingroup netconn_common 478 * Receive data: actual implementation that doesn't care whether pbuf or netbuf 479 * is received (this is internal, it's just here for describing common errors) 480 * 481 * @param conn the netconn from which to receive data 482 * @param new_buf pointer where a new pbuf/netbuf is stored when received data 483 * @param apiflags flags that control function behaviour. For now only: 484 * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data 485 * @return ERR_OK if data has been received, an error code otherwise (timeout, 486 * memory error or another error) 487 * ERR_CONN if not connected 488 * ERR_CLSD if TCP connection has been closed 489 * ERR_WOULDBLOCK if the netconn is nonblocking but would block to wait for data 490 * ERR_TIMEOUT if the netconn has a receive timeout and no data was received 491 */ 492 static err_t 493 netconn_recv_data(struct netconn *conn, void **new_buf, u8_t apiflags) 494 { 495 void *buf = NULL; 496 u16_t len; 497 498 LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); 499 *new_buf = NULL; 500 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); 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 511 if (netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK)) { 512 if (sys_arch_mbox_tryfetch(&conn->recvmbox, &buf) == SYS_ARCH_TIMEOUT) { 513 return ERR_WOULDBLOCK; 514 } 515 } else { 516 #if LWIP_SO_RCVTIMEO 517 if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { 518 return ERR_TIMEOUT; 519 } 520 #else 521 sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); 522 #endif /* LWIP_SO_RCVTIMEO*/ 523 } 524 525 #if LWIP_TCP 526 #if (LWIP_UDP || LWIP_RAW) 527 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 528 #endif /* (LWIP_UDP || LWIP_RAW) */ 529 { 530 /* If we received a NULL pointer, we are closed */ 531 if (buf == NULL) { 532 /* new_buf has been zeroed above alredy */ 533 return ERR_OK; 534 } 535 len = ((struct pbuf *)buf)->tot_len; 536 } 537 #endif /* LWIP_TCP */ 538 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW) 539 else 540 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ 541 #if (LWIP_UDP || LWIP_RAW) 542 { 543 LWIP_ASSERT("buf != NULL", buf != NULL); 544 len = netbuf_len((struct netbuf*)buf); 545 } 546 #endif /* (LWIP_UDP || LWIP_RAW) */ 547 548 #if LWIP_SO_RCVBUF 549 SYS_ARCH_DEC(conn->recv_avail, len); 550 #endif /* LWIP_SO_RCVBUF */ 551 /* Register event with callback */ 552 API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); 553 554 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len)); 555 556 *new_buf = buf; 557 /* don't set conn->last_err: it's only ERR_OK, anyway */ 558 return ERR_OK; 559 } 560 561 static err_t 562 netconn_tcp_recvd_msg(struct netconn *conn, u32_t len, struct api_msg* msg) 563 { 564 LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && 565 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); 566 567 msg->conn = conn; 568 msg->msg.r.len = len; 569 570 return netconn_apimsg(lwip_netconn_do_recv, msg); 571 } 572 573 err_t 574 netconn_tcp_recvd(struct netconn *conn, u32_t len) 575 { 576 err_t err; 577 API_MSG_VAR_DECLARE(msg); 578 LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && 579 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); 580 581 API_MSG_VAR_ALLOC(msg); 582 err = netconn_tcp_recvd_msg(conn, len, &API_VAR_REF(msg)); 583 API_MSG_VAR_FREE(msg); 584 return err; 585 } 586 587 #if LWIP_TCP 588 static err_t 589 netconn_recv_data_tcp(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags) 590 { 591 err_t err; 592 struct pbuf *buf; 593 #if LWIP_TCP 594 API_MSG_VAR_DECLARE(msg); 595 #if LWIP_MPU_COMPATIBLE 596 msg = NULL; 597 #endif 598 #endif /* LWIP_TCP */ 599 600 if (!sys_mbox_valid(&conn->recvmbox)) { 601 /* This happens when calling this function after receiving FIN */ 602 return sys_mbox_valid(&conn->acceptmbox) ? ERR_CONN : ERR_CLSD; 603 } 604 605 if (!(apiflags & NETCONN_NOAUTORCVD)) { 606 /* need to allocate API message here so empty message pool does not result in event loss 607 * see bug #47512: MPU_COMPATIBLE may fail on empty pool */ 608 API_MSG_VAR_ALLOC(msg); 609 } 610 611 err = netconn_recv_data(conn, (void **)new_buf, apiflags); 612 if (err != ERR_OK) { 613 if (!(apiflags & NETCONN_NOAUTORCVD)) { 614 API_MSG_VAR_FREE(msg); 615 } 616 return err; 617 } 618 buf = *new_buf; 619 if (!(apiflags & NETCONN_NOAUTORCVD)) { 620 /* Let the stack know that we have taken the data. */ 621 u16_t len = buf ? buf->tot_len : 1; 622 /* don't care for the return value of lwip_netconn_do_recv */ 623 /* @todo: this should really be fixed, e.g. by retrying in poll on error */ 624 netconn_tcp_recvd_msg(conn, len, &API_VAR_REF(msg)); 625 API_MSG_VAR_FREE(msg); 626 } 627 628 /* If we are closed, we indicate that we no longer wish to use the socket */ 629 if (buf == NULL) { 630 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); 631 if (conn->pcb.ip == NULL) { 632 /* race condition: RST during recv */ 633 return conn->last_err == ERR_OK ? ERR_RST : conn->last_err; 634 } 635 /* RX side is closed, so deallocate the recvmbox */ 636 netconn_close_shutdown(conn, NETCONN_SHUT_RD); 637 /* Don' store ERR_CLSD as conn->err since we are only half-closed */ 638 return ERR_CLSD; 639 } 640 return err; 641 } 642 643 /** 644 * @ingroup netconn_tcp 645 * Receive data (in form of a pbuf) from a TCP netconn 646 * 647 * @param conn the netconn from which to receive data 648 * @param new_buf pointer where a new pbuf is stored when received data 649 * @return ERR_OK if data has been received, an error code otherwise (timeout, 650 * memory error or another error, @see netconn_recv_data) 651 * ERR_ARG if conn is not a TCP netconn 652 */ 653 err_t 654 netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) 655 { 656 LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && 657 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); 658 659 return netconn_recv_data_tcp(conn, new_buf, 0); 660 } 661 662 /** 663 * @ingroup netconn_tcp 664 * Receive data (in form of a pbuf) from a TCP netconn 665 * 666 * @param conn the netconn from which to receive data 667 * @param new_buf pointer where a new pbuf is stored when received data 668 * @param apiflags flags that control function behaviour. For now only: 669 * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data 670 * @return ERR_OK if data has been received, an error code otherwise (timeout, 671 * memory error or another error, @see netconn_recv_data) 672 * ERR_ARG if conn is not a TCP netconn 673 */ 674 err_t 675 netconn_recv_tcp_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags) 676 { 677 LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && 678 NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); 679 680 return netconn_recv_data_tcp(conn, new_buf, apiflags); 681 } 682 #endif /* LWIP_TCP */ 683 684 /** 685 * Receive data (in form of a netbuf) from a UDP or RAW netconn 686 * 687 * @param conn the netconn from which to receive data 688 * @param new_buf pointer where a new netbuf is stored when received data 689 * @return ERR_OK if data has been received, an error code otherwise (timeout, 690 * memory error or another error) 691 * ERR_ARG if conn is not a UDP/RAW netconn 692 */ 693 err_t 694 netconn_recv_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf) 695 { 696 LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) && 697 NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;); 698 699 return netconn_recv_data(conn, (void **)new_buf, 0); 700 } 701 702 /** 703 * Receive data (in form of a netbuf) from a UDP or RAW netconn 704 * 705 * @param conn the netconn from which to receive data 706 * @param new_buf pointer where a new netbuf is stored when received data 707 * @param apiflags flags that control function behaviour. For now only: 708 * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data 709 * @return ERR_OK if data has been received, an error code otherwise (timeout, 710 * memory error or another error) 711 * ERR_ARG if conn is not a UDP/RAW netconn 712 */ 713 err_t 714 netconn_recv_udp_raw_netbuf_flags(struct netconn *conn, struct netbuf **new_buf, u8_t apiflags) 715 { 716 LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) && 717 NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;); 718 719 return netconn_recv_data(conn, (void **)new_buf, apiflags); 720 } 721 722 /** 723 * @ingroup netconn_common 724 * Receive data (in form of a netbuf containing a packet buffer) from a netconn 725 * 726 * @param conn the netconn from which to receive data 727 * @param new_buf pointer where a new netbuf is stored when received data 728 * @return ERR_OK if data has been received, an error code otherwise (timeout, 729 * memory error or another error) 730 */ 731 err_t 732 netconn_recv(struct netconn *conn, struct netbuf **new_buf) 733 { 734 #if LWIP_TCP 735 struct netbuf *buf = NULL; 736 err_t err; 737 #endif /* LWIP_TCP */ 738 739 LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); 740 *new_buf = NULL; 741 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); 742 743 #if LWIP_TCP 744 #if (LWIP_UDP || LWIP_RAW) 745 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) 746 #endif /* (LWIP_UDP || LWIP_RAW) */ 747 { 748 struct pbuf *p = NULL; 749 /* This is not a listening netconn, since recvmbox is set */ 750 751 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 752 if (buf == NULL) { 753 return ERR_MEM; 754 } 755 756 err = netconn_recv_data_tcp(conn, &p, 0); 757 if (err != ERR_OK) { 758 memp_free(MEMP_NETBUF, buf); 759 return err; 760 } 761 LWIP_ASSERT("p != NULL", p != NULL); 762 763 buf->p = p; 764 buf->ptr = p; 765 buf->port = 0; 766 ip_addr_set_zero(&buf->addr); 767 *new_buf = buf; 768 /* don't set conn->last_err: it's only ERR_OK, anyway */ 769 return ERR_OK; 770 } 771 #endif /* LWIP_TCP */ 772 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW) 773 else 774 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ 775 { 776 #if (LWIP_UDP || LWIP_RAW) 777 return netconn_recv_data(conn, (void **)new_buf, 0); 778 #endif /* (LWIP_UDP || LWIP_RAW) */ 779 } 780 } 781 782 /** 783 * @ingroup netconn_udp 784 * Send data (in form of a netbuf) to a specific remote IP address and port. 785 * Only to be used for UDP and RAW netconns (not TCP). 786 * 787 * @param conn the netconn over which to send data 788 * @param buf a netbuf containing the data to send 789 * @param addr the remote IP address to which to send the data 790 * @param port the remote port to which to send the data 791 * @return ERR_OK if data was sent, any other err_t on error 792 */ 793 err_t 794 netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port) 795 { 796 if (buf != NULL) { 797 ip_addr_set(&buf->addr, addr); 798 buf->port = port; 799 return netconn_send(conn, buf); 800 } 801 return ERR_VAL; 802 } 803 804 /** 805 * @ingroup netconn_udp 806 * Send data over a UDP or RAW netconn (that is already connected). 807 * 808 * @param conn the UDP or RAW netconn over which to send data 809 * @param buf a netbuf containing the data to send 810 * @return ERR_OK if data was sent, any other err_t on error 811 */ 812 err_t 813 netconn_send(struct netconn *conn, struct netbuf *buf) 814 { 815 API_MSG_VAR_DECLARE(msg); 816 err_t err; 817 818 LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); 819 820 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); 821 822 API_MSG_VAR_ALLOC(msg); 823 API_MSG_VAR_REF(msg).conn = conn; 824 API_MSG_VAR_REF(msg).msg.b = buf; 825 err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg)); 826 API_MSG_VAR_FREE(msg); 827 828 return err; 829 } 830 831 /** 832 * @ingroup netconn_tcp 833 * Send data over a TCP netconn. 834 * 835 * @param conn the TCP netconn over which to send data 836 * @param dataptr pointer to the application buffer that contains the data to send 837 * @param size size of the application data to send 838 * @param apiflags combination of following flags : 839 * - NETCONN_COPY: data will be copied into memory belonging to the stack 840 * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent 841 * - NETCONN_DONTBLOCK: only write the data if all data can be written at once 842 * @param bytes_written pointer to a location that receives the number of written bytes 843 * @return ERR_OK if data was sent, any other err_t on error 844 */ 845 err_t 846 netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, 847 u8_t apiflags, size_t *bytes_written) 848 { 849 struct netvector vector; 850 vector.ptr = dataptr; 851 vector.len = size; 852 return netconn_write_vectors_partly(conn, &vector, 1, apiflags, bytes_written); 853 } 854 855 /** 856 * Send vectorized data atomically over a TCP netconn. 857 * 858 * @param conn the TCP netconn over which to send data 859 * @param vectors array of vectors containing data to send 860 * @param vectorcnt number of vectors in the array 861 * @param apiflags combination of following flags : 862 * - NETCONN_COPY: data will be copied into memory belonging to the stack 863 * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent 864 * - NETCONN_DONTBLOCK: only write the data if all data can be written at once 865 * @param bytes_written pointer to a location that receives the number of written bytes 866 * @return ERR_OK if data was sent, any other err_t on error 867 */ 868 err_t 869 netconn_write_vectors_partly(struct netconn *conn, struct netvector *vectors, u16_t vectorcnt, 870 u8_t apiflags, size_t *bytes_written) 871 { 872 API_MSG_VAR_DECLARE(msg); 873 err_t err; 874 u8_t dontblock; 875 size_t size; 876 int i; 877 878 LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); 879 LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;); 880 dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); 881 #if LWIP_SO_SNDTIMEO 882 if (conn->send_timeout != 0) { 883 dontblock = 1; 884 } 885 #endif /* LWIP_SO_SNDTIMEO */ 886 if (dontblock && !bytes_written) { 887 /* This implies netconn_write() cannot be used for non-blocking send, since 888 it has no way to return the number of bytes written. */ 889 return ERR_VAL; 890 } 891 892 /* sum up the total size */ 893 size = 0; 894 for (i = 0; i < vectorcnt; i++) { 895 size += vectors[i].len; 896 if (size < vectors[i].len) { 897 /* overflow */ 898 return ERR_VAL; 899 } 900 } 901 if (size == 0) { 902 return ERR_OK; 903 } else if (size > INT_MAX) { 904 /* this is required by the socket layer (cannot send full size_t range) */ 905 return ERR_VAL; 906 } 907 908 API_MSG_VAR_ALLOC(msg); 909 /* non-blocking write sends as much */ 910 API_MSG_VAR_REF(msg).conn = conn; 911 API_MSG_VAR_REF(msg).msg.w.vector = vectors; 912 API_MSG_VAR_REF(msg).msg.w.vector_cnt = vectorcnt; 913 API_MSG_VAR_REF(msg).msg.w.vector_off = 0; 914 API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags; 915 API_MSG_VAR_REF(msg).msg.w.len = size; 916 API_MSG_VAR_REF(msg).msg.w.offset = 0; 917 #if LWIP_SO_SNDTIMEO 918 if (conn->send_timeout != 0) { 919 /* get the time we started, which is later compared to 920 sys_now() + conn->send_timeout */ 921 API_MSG_VAR_REF(msg).msg.w.time_started = sys_now(); 922 } else { 923 API_MSG_VAR_REF(msg).msg.w.time_started = 0; 924 } 925 #endif /* LWIP_SO_SNDTIMEO */ 926 927 /* For locking the core: this _can_ be delayed on low memory/low send buffer, 928 but if it is, this is done inside api_msg.c:do_write(), so we can use the 929 non-blocking version here. */ 930 err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg)); 931 if (err == ERR_OK) { 932 if (bytes_written != NULL) { 933 *bytes_written = API_MSG_VAR_REF(msg).msg.w.offset; 934 } 935 /* for blocking, check all requested bytes were written, NOTE: send_timeout is 936 treated as dontblock (see dontblock assignment above) */ 937 if (!dontblock) { 938 LWIP_ASSERT("do_write failed to write all bytes", API_MSG_VAR_REF(msg).msg.w.offset == size); 939 } 940 } 941 API_MSG_VAR_FREE(msg); 942 943 return err; 944 } 945 946 /** 947 * @ingroup netconn_tcp 948 * Close or shutdown a TCP netconn (doesn't delete it). 949 * 950 * @param conn the TCP netconn to close or shutdown 951 * @param how fully close or only shutdown one side? 952 * @return ERR_OK if the netconn was closed, any other err_t on error 953 */ 954 static err_t 955 netconn_close_shutdown(struct netconn *conn, u8_t how) 956 { 957 API_MSG_VAR_DECLARE(msg); 958 err_t err; 959 LWIP_UNUSED_ARG(how); 960 961 LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); 962 963 API_MSG_VAR_ALLOC(msg); 964 API_MSG_VAR_REF(msg).conn = conn; 965 #if LWIP_TCP 966 /* shutting down both ends is the same as closing */ 967 API_MSG_VAR_REF(msg).msg.sd.shut = how; 968 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER 969 /* get the time we started, which is later compared to 970 sys_now() + conn->send_timeout */ 971 API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); 972 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 973 API_MSG_VAR_REF(msg).msg.sd.polls_left = 974 ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; 975 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 976 #endif /* LWIP_TCP */ 977 err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg)); 978 API_MSG_VAR_FREE(msg); 979 980 return err; 981 } 982 983 /** 984 * @ingroup netconn_tcp 985 * Close a TCP netconn (doesn't delete it). 986 * 987 * @param conn the TCP netconn to close 988 * @return ERR_OK if the netconn was closed, any other err_t on error 989 */ 990 err_t 991 netconn_close(struct netconn *conn) 992 { 993 /* shutting down both ends is the same as closing */ 994 return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR); 995 } 996 997 /** 998 * @ingroup netconn_tcp 999 * Shut down one or both sides of a TCP netconn (doesn't delete it). 1000 * 1001 * @param conn the TCP netconn to shut down 1002 * @param shut_rx shut down the RX side (no more read possible after this) 1003 * @param shut_tx shut down the TX side (no more write possible after this) 1004 * @return ERR_OK if the netconn was closed, any other err_t on error 1005 */ 1006 err_t 1007 netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx) 1008 { 1009 return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)); 1010 } 1011 1012 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) 1013 /** 1014 * @ingroup netconn_udp 1015 * Join multicast groups for UDP netconns. 1016 * 1017 * @param conn the UDP netconn for which to change multicast addresses 1018 * @param multiaddr IP address of the multicast group to join or leave 1019 * @param netif_addr the IP address of the network interface on which to send 1020 * the igmp message 1021 * @param join_or_leave flag whether to send a join- or leave-message 1022 * @return ERR_OK if the action was taken, any err_t on error 1023 */ 1024 err_t 1025 netconn_join_leave_group(struct netconn *conn, 1026 const ip_addr_t *multiaddr, 1027 const ip_addr_t *netif_addr, 1028 enum netconn_igmp join_or_leave) 1029 { 1030 API_MSG_VAR_DECLARE(msg); 1031 err_t err; 1032 1033 LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); 1034 1035 API_MSG_VAR_ALLOC(msg); 1036 1037 #if LWIP_IPV4 1038 /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ 1039 if (multiaddr == NULL) { 1040 multiaddr = IP4_ADDR_ANY; 1041 } 1042 if (netif_addr == NULL) { 1043 netif_addr = IP4_ADDR_ANY; 1044 } 1045 #endif /* LWIP_IPV4 */ 1046 1047 API_MSG_VAR_REF(msg).conn = conn; 1048 API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr); 1049 API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr); 1050 API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave; 1051 err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg)); 1052 API_MSG_VAR_FREE(msg); 1053 1054 return err; 1055 } 1056 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ 1057 1058 #if LWIP_DNS 1059 /** 1060 * @ingroup netconn_common 1061 * Execute a DNS query, only one IP address is returned 1062 * 1063 * @param name a string representation of the DNS host name to query 1064 * @param addr a preallocated ip_addr_t where to store the resolved IP address 1065 * @param dns_addrtype IP address type (IPv4 / IPv6) 1066 * @return ERR_OK: resolving succeeded 1067 * ERR_MEM: memory error, try again later 1068 * ERR_ARG: dns client not initialized or invalid hostname 1069 * ERR_VAL: dns server response was invalid 1070 */ 1071 #if LWIP_IPV4 && LWIP_IPV6 1072 err_t 1073 netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype) 1074 #else 1075 err_t 1076 netconn_gethostbyname(const char *name, ip_addr_t *addr) 1077 #endif 1078 { 1079 API_VAR_DECLARE(struct dns_api_msg, msg); 1080 #if !LWIP_MPU_COMPATIBLE 1081 sys_sem_t sem; 1082 #endif /* LWIP_MPU_COMPATIBLE */ 1083 err_t err; 1084 err_t cberr; 1085 1086 LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); 1087 LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); 1088 #if LWIP_MPU_COMPATIBLE 1089 if (strlen(name) >= DNS_MAX_NAME_LENGTH) { 1090 return ERR_ARG; 1091 } 1092 #endif 1093 1094 API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM); 1095 #if LWIP_MPU_COMPATIBLE 1096 strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH-1); 1097 API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH-1] = 0; 1098 #else /* LWIP_MPU_COMPATIBLE */ 1099 msg.err = &err; 1100 msg.sem = &sem; 1101 API_VAR_REF(msg).addr = API_VAR_REF(addr); 1102 API_VAR_REF(msg).name = name; 1103 #endif /* LWIP_MPU_COMPATIBLE */ 1104 #if LWIP_IPV4 && LWIP_IPV6 1105 API_VAR_REF(msg).dns_addrtype = dns_addrtype; 1106 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 1107 #if LWIP_NETCONN_SEM_PER_THREAD 1108 API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET(); 1109 #else /* LWIP_NETCONN_SEM_PER_THREAD*/ 1110 err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0); 1111 if (err != ERR_OK) { 1112 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 1113 return err; 1114 } 1115 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 1116 1117 cberr = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg)); 1118 if (cberr != ERR_OK) { 1119 #if !LWIP_NETCONN_SEM_PER_THREAD 1120 sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); 1121 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ 1122 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 1123 return cberr; 1124 } 1125 sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem)); 1126 #if !LWIP_NETCONN_SEM_PER_THREAD 1127 sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); 1128 #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ 1129 1130 #if LWIP_MPU_COMPATIBLE 1131 *addr = msg->addr; 1132 err = msg->err; 1133 #endif /* LWIP_MPU_COMPATIBLE */ 1134 1135 API_VAR_FREE(MEMP_DNS_API_MSG, msg); 1136 return err; 1137 } 1138 #endif /* LWIP_DNS*/ 1139 1140 #if LWIP_NETCONN_SEM_PER_THREAD 1141 void 1142 netconn_thread_init(void) 1143 { 1144 sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); 1145 if ((sem == NULL) || !sys_sem_valid(sem)) { 1146 /* call alloc only once */ 1147 LWIP_NETCONN_THREAD_SEM_ALLOC(); 1148 LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET())); 1149 } 1150 } 1151 1152 void 1153 netconn_thread_cleanup(void) 1154 { 1155 sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); 1156 if ((sem != NULL) && sys_sem_valid(sem)) { 1157 /* call free only once */ 1158 LWIP_NETCONN_THREAD_SEM_FREE(); 1159 } 1160 } 1161 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 1162 1163 #endif /* LWIP_NETCONN */ 1164