1 /** 2 * @file 3 * Sequential API Internal module 4 * 5 */ 6 7 /* 8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without modification, 12 * are permitted provided that the following conditions are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright notice, 15 * this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright notice, 17 * this list of conditions and the following disclaimer in the documentation 18 * and/or other materials provided with the distribution. 19 * 3. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 31 * OF SUCH DAMAGE. 32 * 33 * This file is part of the lwIP TCP/IP stack. 34 * 35 * Author: Adam Dunkels <[email protected]> 36 * 37 */ 38 39 #include "lwip/opt.h" 40 41 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ 42 43 #include "lwip/priv/api_msg.h" 44 45 #include "lwip/ip.h" 46 #include "lwip/ip_addr.h" 47 #include "lwip/udp.h" 48 #include "lwip/tcp.h" 49 #include "lwip/raw.h" 50 51 #include "lwip/memp.h" 52 #include "lwip/igmp.h" 53 #include "lwip/dns.h" 54 #include "lwip/mld6.h" 55 #include "lwip/priv/tcpip_priv.h" 56 57 #include <string.h> 58 59 /* netconns are polled once per second (e.g. continue write on memory error) */ 60 #define NETCONN_TCP_POLL_INTERVAL 2 61 62 #define SET_NONBLOCKING_CONNECT(conn, val) do { if (val) { \ 63 netconn_set_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); \ 64 } else { \ 65 netconn_clear_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); }} while(0) 66 #define IN_NONBLOCKING_CONNECT(conn) netconn_is_flag_set(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT) 67 68 #if LWIP_NETCONN_FULLDUPLEX 69 #define NETCONN_MBOX_VALID(conn, mbox) (sys_mbox_valid(mbox) && ((conn->flags & NETCONN_FLAG_MBOXINVALID) == 0)) 70 #else 71 #define NETCONN_MBOX_VALID(conn, mbox) sys_mbox_valid(mbox) 72 #endif 73 74 /* forward declarations */ 75 #if LWIP_TCP 76 #if LWIP_TCPIP_CORE_LOCKING 77 #define WRITE_DELAYED , 1 78 #define WRITE_DELAYED_PARAM , u8_t delayed 79 #else /* LWIP_TCPIP_CORE_LOCKING */ 80 #define WRITE_DELAYED 81 #define WRITE_DELAYED_PARAM 82 #endif /* LWIP_TCPIP_CORE_LOCKING */ 83 static err_t lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM); 84 static err_t lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM); 85 #endif 86 87 static void netconn_drain(struct netconn *conn); 88 89 #if LWIP_TCPIP_CORE_LOCKING 90 #define TCPIP_APIMSG_ACK(m) 91 #else /* LWIP_TCPIP_CORE_LOCKING */ 92 #define TCPIP_APIMSG_ACK(m) do { sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0) 93 #endif /* LWIP_TCPIP_CORE_LOCKING */ 94 95 #if LWIP_NETCONN_FULLDUPLEX 96 const u8_t netconn_deleted = 0; 97 98 int 99 lwip_netconn_is_deallocated_msg(void *msg) 100 { 101 if (msg == &netconn_deleted) { 102 return 1; 103 } 104 return 0; 105 } 106 #endif /* LWIP_NETCONN_FULLDUPLEX */ 107 108 #if LWIP_TCP 109 const u8_t netconn_aborted = 0; 110 const u8_t netconn_reset = 0; 111 const u8_t netconn_closed = 0; 112 113 /** Translate an error to a unique void* passed via an mbox */ 114 static void * 115 lwip_netconn_err_to_msg(err_t err) 116 { 117 switch (err) { 118 case ERR_ABRT: 119 return LWIP_CONST_CAST(void *, &netconn_aborted); 120 case ERR_RST: 121 return LWIP_CONST_CAST(void *, &netconn_reset); 122 case ERR_CLSD: 123 return LWIP_CONST_CAST(void *, &netconn_closed); 124 default: 125 LWIP_ASSERT("unhandled error", err == ERR_OK); 126 return NULL; 127 } 128 } 129 130 int 131 lwip_netconn_is_err_msg(void *msg, err_t *err) 132 { 133 LWIP_ASSERT("err != NULL", err != NULL); 134 135 if (msg == &netconn_aborted) { 136 *err = ERR_ABRT; 137 return 1; 138 } else if (msg == &netconn_reset) { 139 *err = ERR_RST; 140 return 1; 141 } else if (msg == &netconn_closed) { 142 *err = ERR_CLSD; 143 return 1; 144 } 145 return 0; 146 } 147 #endif /* LWIP_TCP */ 148 149 150 #if LWIP_RAW 151 /** 152 * Receive callback function for RAW netconns. 153 * Doesn't 'eat' the packet, only copies it and sends it to 154 * conn->recvmbox 155 * 156 * @see raw.h (struct raw_pcb.recv) for parameters and return value 157 */ 158 static u8_t 159 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, 160 const ip_addr_t *addr) 161 { 162 struct pbuf *q; 163 struct netbuf *buf; 164 struct netconn *conn; 165 166 LWIP_UNUSED_ARG(addr); 167 conn = (struct netconn *)arg; 168 169 if ((conn != NULL) && NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { 170 #if LWIP_SO_RCVBUF 171 int recv_avail; 172 SYS_ARCH_GET(conn->recv_avail, recv_avail); 173 if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) { 174 return 0; 175 } 176 #endif /* LWIP_SO_RCVBUF */ 177 /* copy the whole packet into new pbufs */ 178 q = pbuf_clone(PBUF_RAW, PBUF_RAM, p); 179 if (q != NULL) { 180 u16_t len; 181 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 182 if (buf == NULL) { 183 pbuf_free(q); 184 return 0; 185 } 186 187 buf->p = q; 188 buf->ptr = q; 189 ip_addr_copy(buf->addr, *ip_current_src_addr()); 190 buf->port = pcb->protocol; 191 192 len = q->tot_len; 193 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { 194 netbuf_delete(buf); 195 return 0; 196 } else { 197 #if LWIP_SO_RCVBUF 198 SYS_ARCH_INC(conn->recv_avail, len); 199 #endif /* LWIP_SO_RCVBUF */ 200 /* Register event with callback */ 201 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 202 } 203 } 204 } 205 206 return 0; /* do not eat the packet */ 207 } 208 #endif /* LWIP_RAW*/ 209 210 #if LWIP_UDP 211 /** 212 * Receive callback function for UDP netconns. 213 * Posts the packet to conn->recvmbox or deletes it on memory error. 214 * 215 * @see udp.h (struct udp_pcb.recv) for parameters 216 */ 217 static void 218 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, 219 const ip_addr_t *addr, u16_t port) 220 { 221 struct netbuf *buf; 222 struct netconn *conn; 223 u16_t len; 224 #if LWIP_SO_RCVBUF 225 int recv_avail; 226 #endif /* LWIP_SO_RCVBUF */ 227 228 LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ 229 LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); 230 LWIP_ASSERT("recv_udp must have an argument", arg != NULL); 231 conn = (struct netconn *)arg; 232 233 if (conn == NULL) { 234 pbuf_free(p); 235 return; 236 } 237 238 LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); 239 240 #if LWIP_SO_RCVBUF 241 SYS_ARCH_GET(conn->recv_avail, recv_avail); 242 if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox) || 243 ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { 244 #else /* LWIP_SO_RCVBUF */ 245 if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { 246 #endif /* LWIP_SO_RCVBUF */ 247 pbuf_free(p); 248 return; 249 } 250 251 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 252 if (buf == NULL) { 253 pbuf_free(p); 254 return; 255 } else { 256 buf->p = p; 257 buf->ptr = p; 258 ip_addr_set(&buf->addr, addr); 259 buf->port = port; 260 #if LWIP_NETBUF_RECVINFO 261 if (conn->flags & NETCONN_FLAG_PKTINFO) { 262 /* get the UDP header - always in the first pbuf, ensured by udp_input */ 263 const struct udp_hdr *udphdr = (const struct udp_hdr *)ip_next_header_ptr(); 264 buf->flags = NETBUF_FLAG_DESTADDR; 265 ip_addr_set(&buf->toaddr, ip_current_dest_addr()); 266 buf->toport_chksum = udphdr->dest; 267 } 268 #endif /* LWIP_NETBUF_RECVINFO */ 269 } 270 271 len = p->tot_len; 272 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { 273 netbuf_delete(buf); 274 return; 275 } else { 276 #if LWIP_SO_RCVBUF 277 SYS_ARCH_INC(conn->recv_avail, len); 278 #endif /* LWIP_SO_RCVBUF */ 279 /* Register event with callback */ 280 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 281 } 282 } 283 #endif /* LWIP_UDP */ 284 285 #if LWIP_TCP 286 /** 287 * Receive callback function for TCP netconns. 288 * Posts the packet to conn->recvmbox, but doesn't delete it on errors. 289 * 290 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value 291 */ 292 static err_t 293 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) 294 { 295 struct netconn *conn; 296 u16_t len; 297 void *msg; 298 299 LWIP_UNUSED_ARG(pcb); 300 LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); 301 LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); 302 LWIP_ASSERT("err != ERR_OK unhandled", err == ERR_OK); 303 LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */ 304 conn = (struct netconn *)arg; 305 306 if (conn == NULL) { 307 return ERR_VAL; 308 } 309 LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); 310 311 if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { 312 /* recvmbox already deleted */ 313 if (p != NULL) { 314 tcp_recved(pcb, p->tot_len); 315 pbuf_free(p); 316 } 317 return ERR_OK; 318 } 319 /* Unlike for UDP or RAW pcbs, don't check for available space 320 using recv_avail since that could break the connection 321 (data is already ACKed) */ 322 323 if (p != NULL) { 324 msg = p; 325 len = p->tot_len; 326 } else { 327 msg = LWIP_CONST_CAST(void *, &netconn_closed); 328 len = 0; 329 } 330 331 if (sys_mbox_trypost(&conn->recvmbox, msg) != ERR_OK) { 332 /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */ 333 return ERR_MEM; 334 } else { 335 #if LWIP_SO_RCVBUF 336 SYS_ARCH_INC(conn->recv_avail, len); 337 #endif /* LWIP_SO_RCVBUF */ 338 /* Register event with callback */ 339 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 340 } 341 342 return ERR_OK; 343 } 344 345 /** 346 * Poll callback function for TCP netconns. 347 * Wakes up an application thread that waits for a connection to close 348 * or data to be sent. The application thread then takes the 349 * appropriate action to go on. 350 * 351 * Signals the conn->sem. 352 * netconn_close waits for conn->sem if closing failed. 353 * 354 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value 355 */ 356 static err_t 357 poll_tcp(void *arg, struct tcp_pcb *pcb) 358 { 359 struct netconn *conn = (struct netconn *)arg; 360 361 LWIP_UNUSED_ARG(pcb); 362 LWIP_ASSERT("conn != NULL", (conn != NULL)); 363 364 if (conn->state == NETCONN_WRITE) { 365 lwip_netconn_do_writemore(conn WRITE_DELAYED); 366 } else if (conn->state == NETCONN_CLOSE) { 367 #if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER 368 if (conn->current_msg && conn->current_msg->msg.sd.polls_left) { 369 conn->current_msg->msg.sd.polls_left--; 370 } 371 #endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */ 372 lwip_netconn_do_close_internal(conn WRITE_DELAYED); 373 } 374 /* @todo: implement connect timeout here? */ 375 376 /* Did a nonblocking write fail before? Then check available write-space. */ 377 if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) { 378 /* If the queued byte- or pbuf-count drops below the configured low-water limit, 379 let select mark this pcb as writable again. */ 380 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && 381 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { 382 netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE); 383 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 384 } 385 } 386 387 return ERR_OK; 388 } 389 390 /** 391 * Sent callback function for TCP netconns. 392 * Signals the conn->sem and calls API_EVENT. 393 * netconn_write waits for conn->sem if send buffer is low. 394 * 395 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value 396 */ 397 static err_t 398 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) 399 { 400 struct netconn *conn = (struct netconn *)arg; 401 402 LWIP_UNUSED_ARG(pcb); 403 LWIP_ASSERT("conn != NULL", (conn != NULL)); 404 405 if (conn) { 406 if (conn->state == NETCONN_WRITE) { 407 lwip_netconn_do_writemore(conn WRITE_DELAYED); 408 } else if (conn->state == NETCONN_CLOSE) { 409 lwip_netconn_do_close_internal(conn WRITE_DELAYED); 410 } 411 412 /* If the queued byte- or pbuf-count drops below the configured low-water limit, 413 let select mark this pcb as writable again. */ 414 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && 415 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { 416 netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE); 417 API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); 418 } 419 } 420 421 return ERR_OK; 422 } 423 424 /** 425 * Error callback function for TCP netconns. 426 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. 427 * The application thread has then to decide what to do. 428 * 429 * @see tcp.h (struct tcp_pcb.err) for parameters 430 */ 431 static void 432 err_tcp(void *arg, err_t err) 433 { 434 struct netconn *conn; 435 enum netconn_state old_state; 436 void *mbox_msg; 437 SYS_ARCH_DECL_PROTECT(lev); 438 439 conn = (struct netconn *)arg; 440 LWIP_ASSERT("conn != NULL", (conn != NULL)); 441 442 SYS_ARCH_PROTECT(lev); 443 444 /* when err is called, the pcb is deallocated, so delete the reference */ 445 conn->pcb.tcp = NULL; 446 /* store pending error */ 447 conn->pending_err = err; 448 /* prevent application threads from blocking on 'recvmbox'/'acceptmbox' */ 449 conn->flags |= NETCONN_FLAG_MBOXCLOSED; 450 451 /* reset conn->state now before waking up other threads */ 452 old_state = conn->state; 453 conn->state = NETCONN_NONE; 454 455 SYS_ARCH_UNPROTECT(lev); 456 457 /* Notify the user layer about a connection error. Used to signal select. */ 458 API_EVENT(conn, NETCONN_EVT_ERROR, 0); 459 /* Try to release selects pending on 'read' or 'write', too. 460 They will get an error if they actually try to read or write. */ 461 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 462 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 463 464 mbox_msg = lwip_netconn_err_to_msg(err); 465 /* pass error message to recvmbox to wake up pending recv */ 466 if (NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { 467 /* use trypost to prevent deadlock */ 468 sys_mbox_trypost(&conn->recvmbox, mbox_msg); 469 } 470 /* pass error message to acceptmbox to wake up pending accept */ 471 if (NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) { 472 /* use trypost to preven deadlock */ 473 sys_mbox_trypost(&conn->acceptmbox, mbox_msg); 474 } 475 476 if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || 477 (old_state == NETCONN_CONNECT)) { 478 /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary 479 since the pcb has already been deleted! */ 480 int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn); 481 SET_NONBLOCKING_CONNECT(conn, 0); 482 483 if (!was_nonblocking_connect) { 484 sys_sem_t *op_completed_sem; 485 /* set error return code */ 486 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 487 if (old_state == NETCONN_CLOSE) { 488 /* let close succeed: the connection is closed after all... */ 489 conn->current_msg->err = ERR_OK; 490 } else { 491 /* Write and connect fail */ 492 conn->current_msg->err = err; 493 } 494 op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 495 LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem)); 496 conn->current_msg = NULL; 497 /* wake up the waiting task */ 498 sys_sem_signal(op_completed_sem); 499 } else { 500 /* @todo: test what happens for error on nonblocking connect */ 501 } 502 } else { 503 LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL); 504 } 505 } 506 507 /** 508 * Setup a tcp_pcb with the correct callback function pointers 509 * and their arguments. 510 * 511 * @param conn the TCP netconn to setup 512 */ 513 static void 514 setup_tcp(struct netconn *conn) 515 { 516 struct tcp_pcb *pcb; 517 518 pcb = conn->pcb.tcp; 519 tcp_arg(pcb, conn); 520 tcp_recv(pcb, recv_tcp); 521 tcp_sent(pcb, sent_tcp); 522 tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL); 523 tcp_err(pcb, err_tcp); 524 } 525 526 /** 527 * Accept callback function for TCP netconns. 528 * Allocates a new netconn and posts that to conn->acceptmbox. 529 * 530 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value 531 */ 532 static err_t 533 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) 534 { 535 struct netconn *newconn; 536 struct netconn *conn = (struct netconn *)arg; 537 538 if (conn == NULL) { 539 return ERR_VAL; 540 } 541 if (!NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) { 542 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n")); 543 return ERR_VAL; 544 } 545 546 if (newpcb == NULL) { 547 /* out-of-pcbs during connect: pass on this error to the application */ 548 if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) { 549 /* Register event with callback */ 550 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 551 } 552 return ERR_VAL; 553 } 554 LWIP_ASSERT("expect newpcb == NULL or err == ERR_OK", err == ERR_OK); 555 LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */ 556 557 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->state: %s\n", tcp_debug_state_str(newpcb->state))); 558 559 /* We have to set the callback here even though 560 * the new socket is unknown. newconn->socket is marked as -1. */ 561 newconn = netconn_alloc(conn->type, conn->callback); 562 if (newconn == NULL) { 563 /* outof netconns: pass on this error to the application */ 564 if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) { 565 /* Register event with callback */ 566 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 567 } 568 return ERR_MEM; 569 } 570 newconn->pcb.tcp = newpcb; 571 setup_tcp(newconn); 572 573 /* handle backlog counter */ 574 tcp_backlog_delayed(newpcb); 575 576 if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) { 577 /* When returning != ERR_OK, the pcb is aborted in tcp_process(), 578 so do nothing here! */ 579 /* remove all references to this netconn from the pcb */ 580 struct tcp_pcb *pcb = newconn->pcb.tcp; 581 tcp_arg(pcb, NULL); 582 tcp_recv(pcb, NULL); 583 tcp_sent(pcb, NULL); 584 tcp_poll(pcb, NULL, 0); 585 tcp_err(pcb, NULL); 586 /* remove reference from to the pcb from this netconn */ 587 newconn->pcb.tcp = NULL; 588 /* no need to drain since we know the recvmbox is empty. */ 589 sys_mbox_free(&newconn->recvmbox); 590 sys_mbox_set_invalid(&newconn->recvmbox); 591 netconn_free(newconn); 592 return ERR_MEM; 593 } else { 594 /* Register event with callback */ 595 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 596 } 597 598 return ERR_OK; 599 } 600 #endif /* LWIP_TCP */ 601 602 /** 603 * Create a new pcb of a specific type. 604 * Called from lwip_netconn_do_newconn(). 605 * 606 * @param msg the api_msg describing the connection type 607 */ 608 static void 609 pcb_new(struct api_msg *msg) 610 { 611 enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4; 612 613 LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); 614 615 #if LWIP_IPV6 && LWIP_IPV4 616 /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */ 617 if (NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) { 618 iptype = IPADDR_TYPE_ANY; 619 } 620 #endif 621 622 /* Allocate a PCB for this connection */ 623 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 624 #if LWIP_RAW 625 case NETCONN_RAW: 626 msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto); 627 if (msg->conn->pcb.raw != NULL) { 628 #if LWIP_IPV6 629 /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */ 630 if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) { 631 msg->conn->pcb.raw->chksum_reqd = 1; 632 msg->conn->pcb.raw->chksum_offset = 2; 633 } 634 #endif /* LWIP_IPV6 */ 635 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); 636 } 637 break; 638 #endif /* LWIP_RAW */ 639 #if LWIP_UDP 640 case NETCONN_UDP: 641 msg->conn->pcb.udp = udp_new_ip_type(iptype); 642 if (msg->conn->pcb.udp != NULL) { 643 #if LWIP_UDPLITE 644 if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { 645 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); 646 } 647 #endif /* LWIP_UDPLITE */ 648 if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) { 649 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); 650 } 651 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); 652 } 653 break; 654 #endif /* LWIP_UDP */ 655 #if LWIP_TCP 656 case NETCONN_TCP: 657 msg->conn->pcb.tcp = tcp_new_ip_type(iptype); 658 if (msg->conn->pcb.tcp != NULL) { 659 setup_tcp(msg->conn); 660 } 661 break; 662 #endif /* LWIP_TCP */ 663 default: 664 /* Unsupported netconn type, e.g. protocol disabled */ 665 msg->err = ERR_VAL; 666 return; 667 } 668 if (msg->conn->pcb.ip == NULL) { 669 msg->err = ERR_MEM; 670 } 671 } 672 673 /** 674 * Create a new pcb of a specific type inside a netconn. 675 * Called from netconn_new_with_proto_and_callback. 676 * 677 * @param m the api_msg describing the connection type 678 */ 679 void 680 lwip_netconn_do_newconn(void *m) 681 { 682 struct api_msg *msg = (struct api_msg *)m; 683 684 msg->err = ERR_OK; 685 if (msg->conn->pcb.tcp == NULL) { 686 pcb_new(msg); 687 } 688 /* Else? This "new" connection already has a PCB allocated. */ 689 /* Is this an error condition? Should it be deleted? */ 690 /* We currently just are happy and return. */ 691 692 TCPIP_APIMSG_ACK(msg); 693 } 694 695 /** 696 * Create a new netconn (of a specific type) that has a callback function. 697 * The corresponding pcb is NOT created! 698 * 699 * @param t the type of 'connection' to create (@see enum netconn_type) 700 * @param callback a function to call on status changes (RX available, TX'ed) 701 * @return a newly allocated struct netconn or 702 * NULL on memory error 703 */ 704 struct netconn * 705 netconn_alloc(enum netconn_type t, netconn_callback callback) 706 { 707 struct netconn *conn; 708 int size; 709 u8_t init_flags = 0; 710 711 conn = (struct netconn *)memp_malloc(MEMP_NETCONN); 712 if (conn == NULL) { 713 return NULL; 714 } 715 716 conn->pending_err = ERR_OK; 717 conn->type = t; 718 conn->pcb.tcp = NULL; 719 720 /* If all sizes are the same, every compiler should optimize this switch to nothing */ 721 switch (NETCONNTYPE_GROUP(t)) { 722 #if LWIP_RAW 723 case NETCONN_RAW: 724 size = DEFAULT_RAW_RECVMBOX_SIZE; 725 break; 726 #endif /* LWIP_RAW */ 727 #if LWIP_UDP 728 case NETCONN_UDP: 729 size = DEFAULT_UDP_RECVMBOX_SIZE; 730 #if LWIP_NETBUF_RECVINFO 731 init_flags |= NETCONN_FLAG_PKTINFO; 732 #endif /* LWIP_NETBUF_RECVINFO */ 733 break; 734 #endif /* LWIP_UDP */ 735 #if LWIP_TCP 736 case NETCONN_TCP: 737 size = DEFAULT_TCP_RECVMBOX_SIZE; 738 break; 739 #endif /* LWIP_TCP */ 740 default: 741 LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); 742 goto free_and_return; 743 } 744 745 if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { 746 goto free_and_return; 747 } 748 #if !LWIP_NETCONN_SEM_PER_THREAD 749 if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { 750 sys_mbox_free(&conn->recvmbox); 751 goto free_and_return; 752 } 753 #endif 754 755 #if LWIP_TCP 756 sys_mbox_set_invalid(&conn->acceptmbox); 757 #endif 758 conn->state = NETCONN_NONE; 759 #if LWIP_SOCKET 760 /* initialize socket to -1 since 0 is a valid socket */ 761 conn->socket = -1; 762 #endif /* LWIP_SOCKET */ 763 conn->callback = callback; 764 #if LWIP_TCP 765 conn->current_msg = NULL; 766 #endif /* LWIP_TCP */ 767 #if LWIP_SO_SNDTIMEO 768 conn->send_timeout = 0; 769 #endif /* LWIP_SO_SNDTIMEO */ 770 #if LWIP_SO_RCVTIMEO 771 conn->recv_timeout = 0; 772 #endif /* LWIP_SO_RCVTIMEO */ 773 #if LWIP_SO_RCVBUF 774 conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; 775 conn->recv_avail = 0; 776 #endif /* LWIP_SO_RCVBUF */ 777 #if LWIP_SO_LINGER 778 conn->linger = -1; 779 #endif /* LWIP_SO_LINGER */ 780 conn->flags = init_flags; 781 return conn; 782 free_and_return: 783 memp_free(MEMP_NETCONN, conn); 784 return NULL; 785 } 786 787 /** 788 * Delete a netconn and all its resources. 789 * The pcb is NOT freed (since we might not be in the right thread context do this). 790 * 791 * @param conn the netconn to free 792 */ 793 void 794 netconn_free(struct netconn *conn) 795 { 796 LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); 797 798 #if LWIP_NETCONN_FULLDUPLEX 799 /* in fullduplex, netconn is drained here */ 800 netconn_drain(conn); 801 #endif /* LWIP_NETCONN_FULLDUPLEX */ 802 803 LWIP_ASSERT("recvmbox must be deallocated before calling this function", 804 !sys_mbox_valid(&conn->recvmbox)); 805 #if LWIP_TCP 806 LWIP_ASSERT("acceptmbox must be deallocated before calling this function", 807 !sys_mbox_valid(&conn->acceptmbox)); 808 #endif /* LWIP_TCP */ 809 810 #if !LWIP_NETCONN_SEM_PER_THREAD 811 sys_sem_free(&conn->op_completed); 812 sys_sem_set_invalid(&conn->op_completed); 813 #endif 814 815 memp_free(MEMP_NETCONN, conn); 816 } 817 818 /** 819 * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in 820 * these mboxes 821 * 822 * @param conn the netconn to free 823 * @bytes_drained bytes drained from recvmbox 824 * @accepts_drained pending connections drained from acceptmbox 825 */ 826 static void 827 netconn_drain(struct netconn *conn) 828 { 829 void *mem; 830 831 /* This runs when mbox and netconn are marked as closed, 832 so we don't need to lock against rx packets */ 833 #if LWIP_NETCONN_FULLDUPLEX 834 LWIP_ASSERT("netconn marked closed", conn->flags & NETCONN_FLAG_MBOXINVALID); 835 #endif /* LWIP_NETCONN_FULLDUPLEX */ 836 837 /* Delete and drain the recvmbox. */ 838 if (sys_mbox_valid(&conn->recvmbox)) { 839 while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { 840 #if LWIP_NETCONN_FULLDUPLEX 841 if (!lwip_netconn_is_deallocated_msg(mem)) 842 #endif /* LWIP_NETCONN_FULLDUPLEX */ 843 { 844 #if LWIP_TCP 845 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) { 846 err_t err; 847 if (!lwip_netconn_is_err_msg(mem, &err)) { 848 pbuf_free((struct pbuf *)mem); 849 } 850 } else 851 #endif /* LWIP_TCP */ 852 { 853 netbuf_delete((struct netbuf *)mem); 854 } 855 } 856 } 857 sys_mbox_free(&conn->recvmbox); 858 sys_mbox_set_invalid(&conn->recvmbox); 859 } 860 861 /* Delete and drain the acceptmbox. */ 862 #if LWIP_TCP 863 if (sys_mbox_valid(&conn->acceptmbox)) { 864 while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { 865 #if LWIP_NETCONN_FULLDUPLEX 866 if (!lwip_netconn_is_deallocated_msg(mem)) 867 #endif /* LWIP_NETCONN_FULLDUPLEX */ 868 { 869 err_t err; 870 if (!lwip_netconn_is_err_msg(mem, &err)) { 871 struct netconn *newconn = (struct netconn *)mem; 872 /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ 873 /* pcb might be set to NULL already by err_tcp() */ 874 /* drain recvmbox */ 875 netconn_drain(newconn); 876 if (newconn->pcb.tcp != NULL) { 877 tcp_abort(newconn->pcb.tcp); 878 newconn->pcb.tcp = NULL; 879 } 880 netconn_free(newconn); 881 } 882 } 883 } 884 sys_mbox_free(&conn->acceptmbox); 885 sys_mbox_set_invalid(&conn->acceptmbox); 886 } 887 #endif /* LWIP_TCP */ 888 } 889 890 #if LWIP_NETCONN_FULLDUPLEX 891 static void 892 netconn_mark_mbox_invalid(struct netconn *conn) 893 { 894 int i, num_waiting; 895 void *msg = LWIP_CONST_CAST(void *, &netconn_deleted); 896 897 /* Prevent new calls/threads from reading from the mbox */ 898 conn->flags |= NETCONN_FLAG_MBOXINVALID; 899 900 SYS_ARCH_LOCKED(num_waiting = conn->mbox_threads_waiting); 901 for (i = 0; i < num_waiting; i++) { 902 if (sys_mbox_valid_val(conn->recvmbox)) { 903 sys_mbox_trypost(&conn->recvmbox, msg); 904 } else { 905 sys_mbox_trypost(&conn->acceptmbox, msg); 906 } 907 } 908 } 909 #endif /* LWIP_NETCONN_FULLDUPLEX */ 910 911 #if LWIP_TCP 912 /** 913 * Internal helper function to close a TCP netconn: since this sometimes 914 * doesn't work at the first attempt, this function is called from multiple 915 * places. 916 * 917 * @param conn the TCP netconn to close 918 */ 919 static err_t 920 lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM) 921 { 922 err_t err; 923 u8_t shut, shut_rx, shut_tx, shut_close; 924 u8_t close_finished = 0; 925 struct tcp_pcb *tpcb; 926 #if LWIP_SO_LINGER 927 u8_t linger_wait_required = 0; 928 #endif /* LWIP_SO_LINGER */ 929 930 LWIP_ASSERT("invalid conn", (conn != NULL)); 931 LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)); 932 LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); 933 LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); 934 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 935 936 tpcb = conn->pcb.tcp; 937 shut = conn->current_msg->msg.sd.shut; 938 shut_rx = shut & NETCONN_SHUT_RD; 939 shut_tx = shut & NETCONN_SHUT_WR; 940 /* shutting down both ends is the same as closing 941 (also if RD or WR side was shut down before already) */ 942 if (shut == NETCONN_SHUT_RDWR) { 943 shut_close = 1; 944 } else if (shut_rx && 945 ((tpcb->state == FIN_WAIT_1) || 946 (tpcb->state == FIN_WAIT_2) || 947 (tpcb->state == CLOSING))) { 948 shut_close = 1; 949 } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) { 950 shut_close = 1; 951 } else { 952 shut_close = 0; 953 } 954 955 /* Set back some callback pointers */ 956 if (shut_close) { 957 tcp_arg(tpcb, NULL); 958 } 959 if (tpcb->state == LISTEN) { 960 tcp_accept(tpcb, NULL); 961 } else { 962 /* some callbacks have to be reset if tcp_close is not successful */ 963 if (shut_rx) { 964 tcp_recv(tpcb, NULL); 965 tcp_accept(tpcb, NULL); 966 } 967 if (shut_tx) { 968 tcp_sent(tpcb, NULL); 969 } 970 if (shut_close) { 971 tcp_poll(tpcb, NULL, 0); 972 tcp_err(tpcb, NULL); 973 } 974 } 975 /* Try to close the connection */ 976 if (shut_close) { 977 #if LWIP_SO_LINGER 978 /* check linger possibilites before calling tcp_close */ 979 err = ERR_OK; 980 /* linger enabled/required at all? (i.e. is there untransmitted data left?) */ 981 if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) { 982 if ((conn->linger == 0)) { 983 /* data left but linger prevents waiting */ 984 tcp_abort(tpcb); 985 tpcb = NULL; 986 } else if (conn->linger > 0) { 987 /* data left and linger says we should wait */ 988 if (netconn_is_nonblocking(conn)) { 989 /* data left on a nonblocking netconn -> cannot linger */ 990 err = ERR_WOULDBLOCK; 991 } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= 992 (conn->linger * 1000)) { 993 /* data left but linger timeout has expired (this happens on further 994 calls to this function through poll_tcp */ 995 tcp_abort(tpcb); 996 tpcb = NULL; 997 } else { 998 /* data left -> need to wait for ACK after successful close */ 999 linger_wait_required = 1; 1000 } 1001 } 1002 } 1003 if ((err == ERR_OK) && (tpcb != NULL)) 1004 #endif /* LWIP_SO_LINGER */ 1005 { 1006 err = tcp_close(tpcb); 1007 } 1008 } else { 1009 err = tcp_shutdown(tpcb, shut_rx, shut_tx); 1010 } 1011 if (err == ERR_OK) { 1012 close_finished = 1; 1013 #if LWIP_SO_LINGER 1014 if (linger_wait_required) { 1015 /* wait for ACK of all unsent/unacked data by just getting called again */ 1016 close_finished = 0; 1017 err = ERR_INPROGRESS; 1018 } 1019 #endif /* LWIP_SO_LINGER */ 1020 } else { 1021 if (err == ERR_MEM) { 1022 /* Closing failed because of memory shortage, try again later. Even for 1023 nonblocking netconns, we have to wait since no standard socket application 1024 is prepared for close failing because of resource shortage. 1025 Check the timeout: this is kind of an lwip addition to the standard sockets: 1026 we wait for some time when failing to allocate a segment for the FIN */ 1027 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER 1028 s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT; 1029 #if LWIP_SO_SNDTIMEO 1030 if (conn->send_timeout > 0) { 1031 close_timeout = conn->send_timeout; 1032 } 1033 #endif /* LWIP_SO_SNDTIMEO */ 1034 #if LWIP_SO_LINGER 1035 if (conn->linger >= 0) { 1036 /* use linger timeout (seconds) */ 1037 close_timeout = conn->linger * 1000U; 1038 } 1039 #endif 1040 if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) { 1041 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 1042 if (conn->current_msg->msg.sd.polls_left == 0) { 1043 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 1044 close_finished = 1; 1045 if (shut_close) { 1046 /* in this case, we want to RST the connection */ 1047 tcp_abort(tpcb); 1048 err = ERR_OK; 1049 } 1050 } 1051 } else { 1052 /* Closing failed for a non-memory error: give up */ 1053 close_finished = 1; 1054 } 1055 } 1056 if (close_finished) { 1057 /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */ 1058 sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 1059 conn->current_msg->err = err; 1060 conn->current_msg = NULL; 1061 conn->state = NETCONN_NONE; 1062 if (err == ERR_OK) { 1063 if (shut_close) { 1064 /* Set back some callback pointers as conn is going away */ 1065 conn->pcb.tcp = NULL; 1066 /* Trigger select() in socket layer. Make sure everybody notices activity 1067 on the connection, error first! */ 1068 API_EVENT(conn, NETCONN_EVT_ERROR, 0); 1069 } 1070 if (shut_rx) { 1071 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 1072 } 1073 if (shut_tx) { 1074 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 1075 } 1076 } 1077 #if LWIP_TCPIP_CORE_LOCKING 1078 if (delayed) 1079 #endif 1080 { 1081 /* wake up the application task */ 1082 sys_sem_signal(op_completed_sem); 1083 } 1084 return ERR_OK; 1085 } 1086 if (!close_finished) { 1087 /* Closing failed and we want to wait: restore some of the callbacks */ 1088 /* Closing of listen pcb will never fail! */ 1089 LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN)); 1090 if (shut_tx) { 1091 tcp_sent(tpcb, sent_tcp); 1092 } 1093 /* when waiting for close, set up poll interval to 500ms */ 1094 tcp_poll(tpcb, poll_tcp, 1); 1095 tcp_err(tpcb, err_tcp); 1096 tcp_arg(tpcb, conn); 1097 /* don't restore recv callback: we don't want to receive any more data */ 1098 } 1099 /* If closing didn't succeed, we get called again either 1100 from poll_tcp or from sent_tcp */ 1101 LWIP_ASSERT("err != ERR_OK", err != ERR_OK); 1102 return err; 1103 } 1104 #endif /* LWIP_TCP */ 1105 1106 /** 1107 * Delete the pcb inside a netconn. 1108 * Called from netconn_delete. 1109 * 1110 * @param m the api_msg pointing to the connection 1111 */ 1112 void 1113 lwip_netconn_do_delconn(void *m) 1114 { 1115 struct api_msg *msg = (struct api_msg *)m; 1116 1117 enum netconn_state state = msg->conn->state; 1118 LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */ 1119 (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP)); 1120 #if LWIP_NETCONN_FULLDUPLEX 1121 /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */ 1122 if (state != NETCONN_NONE) { 1123 if ((state == NETCONN_WRITE) || 1124 ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) { 1125 /* close requested, abort running write/connect */ 1126 sys_sem_t *op_completed_sem; 1127 LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); 1128 op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); 1129 msg->conn->current_msg->err = ERR_CLSD; 1130 msg->conn->current_msg = NULL; 1131 msg->conn->state = NETCONN_NONE; 1132 sys_sem_signal(op_completed_sem); 1133 } 1134 } 1135 #else /* LWIP_NETCONN_FULLDUPLEX */ 1136 if (((state != NETCONN_NONE) && 1137 (state != NETCONN_LISTEN) && 1138 (state != NETCONN_CONNECT)) || 1139 ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) { 1140 /* This means either a blocking write or blocking connect is running 1141 (nonblocking write returns and sets state to NONE) */ 1142 msg->err = ERR_INPROGRESS; 1143 } else 1144 #endif /* LWIP_NETCONN_FULLDUPLEX */ 1145 { 1146 LWIP_ASSERT("blocking connect in progress", 1147 (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); 1148 msg->err = ERR_OK; 1149 #if LWIP_NETCONN_FULLDUPLEX 1150 /* Mark mboxes invalid */ 1151 netconn_mark_mbox_invalid(msg->conn); 1152 #else /* LWIP_NETCONN_FULLDUPLEX */ 1153 netconn_drain(msg->conn); 1154 #endif /* LWIP_NETCONN_FULLDUPLEX */ 1155 1156 if (msg->conn->pcb.tcp != NULL) { 1157 1158 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1159 #if LWIP_RAW 1160 case NETCONN_RAW: 1161 raw_remove(msg->conn->pcb.raw); 1162 break; 1163 #endif /* LWIP_RAW */ 1164 #if LWIP_UDP 1165 case NETCONN_UDP: 1166 msg->conn->pcb.udp->recv_arg = NULL; 1167 udp_remove(msg->conn->pcb.udp); 1168 break; 1169 #endif /* LWIP_UDP */ 1170 #if LWIP_TCP 1171 case NETCONN_TCP: 1172 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL); 1173 msg->conn->state = NETCONN_CLOSE; 1174 msg->msg.sd.shut = NETCONN_SHUT_RDWR; 1175 msg->conn->current_msg = msg; 1176 #if LWIP_TCPIP_CORE_LOCKING 1177 if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) { 1178 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE); 1179 UNLOCK_TCPIP_CORE(); 1180 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 1181 LOCK_TCPIP_CORE(); 1182 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); 1183 } 1184 #else /* LWIP_TCPIP_CORE_LOCKING */ 1185 lwip_netconn_do_close_internal(msg->conn); 1186 #endif /* LWIP_TCPIP_CORE_LOCKING */ 1187 /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing 1188 the application thread, so we can return at this point! */ 1189 return; 1190 #endif /* LWIP_TCP */ 1191 default: 1192 break; 1193 } 1194 msg->conn->pcb.tcp = NULL; 1195 } 1196 /* tcp netconns don't come here! */ 1197 1198 /* @todo: this lets select make the socket readable and writable, 1199 which is wrong! errfd instead? */ 1200 API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); 1201 API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); 1202 } 1203 if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) { 1204 TCPIP_APIMSG_ACK(msg); 1205 } 1206 } 1207 1208 /** 1209 * Bind a pcb contained in a netconn 1210 * Called from netconn_bind. 1211 * 1212 * @param m the api_msg pointing to the connection and containing 1213 * the IP address and port to bind to 1214 */ 1215 void 1216 lwip_netconn_do_bind(void *m) 1217 { 1218 struct api_msg *msg = (struct api_msg *)m; 1219 err_t err; 1220 1221 if (msg->conn->pcb.tcp != NULL) { 1222 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1223 #if LWIP_RAW 1224 case NETCONN_RAW: 1225 err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); 1226 break; 1227 #endif /* LWIP_RAW */ 1228 #if LWIP_UDP 1229 case NETCONN_UDP: 1230 err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); 1231 break; 1232 #endif /* LWIP_UDP */ 1233 #if LWIP_TCP 1234 case NETCONN_TCP: 1235 err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); 1236 break; 1237 #endif /* LWIP_TCP */ 1238 default: 1239 err = ERR_VAL; 1240 break; 1241 } 1242 } else { 1243 err = ERR_VAL; 1244 } 1245 msg->err = err; 1246 TCPIP_APIMSG_ACK(msg); 1247 } 1248 /** 1249 * Bind a pcb contained in a netconn to an interface 1250 * Called from netconn_bind_if. 1251 * 1252 * @param m the api_msg pointing to the connection and containing 1253 * the IP address and port to bind to 1254 */ 1255 void 1256 lwip_netconn_do_bind_if(void *m) 1257 { 1258 struct netif *netif; 1259 struct api_msg *msg = (struct api_msg *)m; 1260 err_t err; 1261 1262 netif = netif_get_by_index(msg->msg.bc.if_idx); 1263 1264 if ((netif != NULL) && (msg->conn->pcb.tcp != NULL)) { 1265 err = ERR_OK; 1266 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1267 #if LWIP_RAW 1268 case NETCONN_RAW: 1269 raw_bind_netif(msg->conn->pcb.raw, netif); 1270 break; 1271 #endif /* LWIP_RAW */ 1272 #if LWIP_UDP 1273 case NETCONN_UDP: 1274 udp_bind_netif(msg->conn->pcb.udp, netif); 1275 break; 1276 #endif /* LWIP_UDP */ 1277 #if LWIP_TCP 1278 case NETCONN_TCP: 1279 tcp_bind_netif(msg->conn->pcb.tcp, netif); 1280 break; 1281 #endif /* LWIP_TCP */ 1282 default: 1283 err = ERR_VAL; 1284 break; 1285 } 1286 } else { 1287 err = ERR_VAL; 1288 } 1289 msg->err = err; 1290 TCPIP_APIMSG_ACK(msg); 1291 } 1292 1293 #if LWIP_TCP 1294 /** 1295 * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has 1296 * been established (or reset by the remote host). 1297 * 1298 * @see tcp.h (struct tcp_pcb.connected) for parameters and return values 1299 */ 1300 static err_t 1301 lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) 1302 { 1303 struct netconn *conn; 1304 int was_blocking; 1305 sys_sem_t *op_completed_sem = NULL; 1306 1307 LWIP_UNUSED_ARG(pcb); 1308 1309 conn = (struct netconn *)arg; 1310 1311 if (conn == NULL) { 1312 return ERR_VAL; 1313 } 1314 1315 LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); 1316 LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", 1317 (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); 1318 1319 if (conn->current_msg != NULL) { 1320 conn->current_msg->err = err; 1321 op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 1322 } 1323 if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) { 1324 setup_tcp(conn); 1325 } 1326 was_blocking = !IN_NONBLOCKING_CONNECT(conn); 1327 SET_NONBLOCKING_CONNECT(conn, 0); 1328 LWIP_ASSERT("blocking connect state error", 1329 (was_blocking && op_completed_sem != NULL) || 1330 (!was_blocking && op_completed_sem == NULL)); 1331 conn->current_msg = NULL; 1332 conn->state = NETCONN_NONE; 1333 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 1334 1335 if (was_blocking) { 1336 sys_sem_signal(op_completed_sem); 1337 } 1338 return ERR_OK; 1339 } 1340 #endif /* LWIP_TCP */ 1341 1342 /** 1343 * Connect a pcb contained inside a netconn 1344 * Called from netconn_connect. 1345 * 1346 * @param m the api_msg pointing to the connection and containing 1347 * the IP address and port to connect to 1348 */ 1349 void 1350 lwip_netconn_do_connect(void *m) 1351 { 1352 struct api_msg *msg = (struct api_msg *)m; 1353 err_t err; 1354 1355 if (msg->conn->pcb.tcp == NULL) { 1356 /* This may happen when calling netconn_connect() a second time */ 1357 err = ERR_CLSD; 1358 } else { 1359 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1360 #if LWIP_RAW 1361 case NETCONN_RAW: 1362 err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); 1363 break; 1364 #endif /* LWIP_RAW */ 1365 #if LWIP_UDP 1366 case NETCONN_UDP: 1367 err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); 1368 break; 1369 #endif /* LWIP_UDP */ 1370 #if LWIP_TCP 1371 case NETCONN_TCP: 1372 /* Prevent connect while doing any other action. */ 1373 if (msg->conn->state == NETCONN_CONNECT) { 1374 err = ERR_ALREADY; 1375 } else if (msg->conn->state != NETCONN_NONE) { 1376 err = ERR_ISCONN; 1377 } else { 1378 setup_tcp(msg->conn); 1379 err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), 1380 msg->msg.bc.port, lwip_netconn_do_connected); 1381 if (err == ERR_OK) { 1382 u8_t non_blocking = netconn_is_nonblocking(msg->conn); 1383 msg->conn->state = NETCONN_CONNECT; 1384 SET_NONBLOCKING_CONNECT(msg->conn, non_blocking); 1385 if (non_blocking) { 1386 err = ERR_INPROGRESS; 1387 } else { 1388 msg->conn->current_msg = msg; 1389 /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()), 1390 when the connection is established! */ 1391 #if LWIP_TCPIP_CORE_LOCKING 1392 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT); 1393 UNLOCK_TCPIP_CORE(); 1394 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 1395 LOCK_TCPIP_CORE(); 1396 LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT); 1397 #endif /* LWIP_TCPIP_CORE_LOCKING */ 1398 return; 1399 } 1400 } 1401 } 1402 break; 1403 #endif /* LWIP_TCP */ 1404 default: 1405 LWIP_ERROR("Invalid netconn type", 0, do { 1406 err = ERR_VAL; 1407 } while (0)); 1408 break; 1409 } 1410 } 1411 msg->err = err; 1412 /* For all other protocols, netconn_connect() calls netconn_apimsg(), 1413 so use TCPIP_APIMSG_ACK() here. */ 1414 TCPIP_APIMSG_ACK(msg); 1415 } 1416 1417 /** 1418 * Disconnect a pcb contained inside a netconn 1419 * Only used for UDP netconns. 1420 * Called from netconn_disconnect. 1421 * 1422 * @param m the api_msg pointing to the connection to disconnect 1423 */ 1424 void 1425 lwip_netconn_do_disconnect(void *m) 1426 { 1427 struct api_msg *msg = (struct api_msg *)m; 1428 1429 #if LWIP_UDP 1430 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 1431 udp_disconnect(msg->conn->pcb.udp); 1432 msg->err = ERR_OK; 1433 } else 1434 #endif /* LWIP_UDP */ 1435 { 1436 msg->err = ERR_VAL; 1437 } 1438 TCPIP_APIMSG_ACK(msg); 1439 } 1440 1441 #if LWIP_TCP 1442 /** 1443 * Set a TCP pcb contained in a netconn into listen mode 1444 * Called from netconn_listen. 1445 * 1446 * @param m the api_msg pointing to the connection 1447 */ 1448 void 1449 lwip_netconn_do_listen(void *m) 1450 { 1451 struct api_msg *msg = (struct api_msg *)m; 1452 err_t err; 1453 1454 if (msg->conn->pcb.tcp != NULL) { 1455 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 1456 if (msg->conn->state == NETCONN_NONE) { 1457 struct tcp_pcb *lpcb; 1458 if (msg->conn->pcb.tcp->state != CLOSED) { 1459 /* connection is not closed, cannot listen */ 1460 err = ERR_VAL; 1461 } else { 1462 u8_t backlog; 1463 #if TCP_LISTEN_BACKLOG 1464 backlog = msg->msg.lb.backlog; 1465 #else /* TCP_LISTEN_BACKLOG */ 1466 backlog = TCP_DEFAULT_LISTEN_BACKLOG; 1467 #endif /* TCP_LISTEN_BACKLOG */ 1468 #if LWIP_IPV4 && LWIP_IPV6 1469 /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY, 1470 * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen 1471 */ 1472 if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) && 1473 (netconn_get_ipv6only(msg->conn) == 0)) { 1474 /* change PCB type to IPADDR_TYPE_ANY */ 1475 IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip, IPADDR_TYPE_ANY); 1476 IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY); 1477 } 1478 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 1479 1480 lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err); 1481 1482 if (lpcb == NULL) { 1483 /* in this case, the old pcb is still allocated */ 1484 } else { 1485 /* delete the recvmbox and allocate the acceptmbox */ 1486 if (sys_mbox_valid(&msg->conn->recvmbox)) { 1487 /** @todo: should we drain the recvmbox here? */ 1488 sys_mbox_free(&msg->conn->recvmbox); 1489 sys_mbox_set_invalid(&msg->conn->recvmbox); 1490 } 1491 err = ERR_OK; 1492 if (!sys_mbox_valid(&msg->conn->acceptmbox)) { 1493 err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); 1494 } 1495 if (err == ERR_OK) { 1496 msg->conn->state = NETCONN_LISTEN; 1497 msg->conn->pcb.tcp = lpcb; 1498 tcp_arg(msg->conn->pcb.tcp, msg->conn); 1499 tcp_accept(msg->conn->pcb.tcp, accept_function); 1500 } else { 1501 /* since the old pcb is already deallocated, free lpcb now */ 1502 tcp_close(lpcb); 1503 msg->conn->pcb.tcp = NULL; 1504 } 1505 } 1506 } 1507 } else if (msg->conn->state == NETCONN_LISTEN) { 1508 /* already listening, allow updating of the backlog */ 1509 err = ERR_OK; 1510 tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog); 1511 } else { 1512 err = ERR_CONN; 1513 } 1514 } else { 1515 err = ERR_ARG; 1516 } 1517 } else { 1518 err = ERR_CONN; 1519 } 1520 msg->err = err; 1521 TCPIP_APIMSG_ACK(msg); 1522 } 1523 #endif /* LWIP_TCP */ 1524 1525 /** 1526 * Send some data on a RAW or UDP pcb contained in a netconn 1527 * Called from netconn_send 1528 * 1529 * @param m the api_msg pointing to the connection 1530 */ 1531 void 1532 lwip_netconn_do_send(void *m) 1533 { 1534 struct api_msg *msg = (struct api_msg *)m; 1535 1536 err_t err = netconn_err(msg->conn); 1537 if (err == ERR_OK) { 1538 if (msg->conn->pcb.tcp != NULL) { 1539 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1540 #if LWIP_RAW 1541 case NETCONN_RAW: 1542 if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { 1543 err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); 1544 } else { 1545 err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); 1546 } 1547 break; 1548 #endif 1549 #if LWIP_UDP 1550 case NETCONN_UDP: 1551 #if LWIP_CHECKSUM_ON_COPY 1552 if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { 1553 err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, 1554 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); 1555 } else { 1556 err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, 1557 &msg->msg.b->addr, msg->msg.b->port, 1558 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); 1559 } 1560 #else /* LWIP_CHECKSUM_ON_COPY */ 1561 if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { 1562 err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); 1563 } else { 1564 err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port); 1565 } 1566 #endif /* LWIP_CHECKSUM_ON_COPY */ 1567 break; 1568 #endif /* LWIP_UDP */ 1569 default: 1570 err = ERR_CONN; 1571 break; 1572 } 1573 } else { 1574 err = ERR_CONN; 1575 } 1576 } 1577 msg->err = err; 1578 TCPIP_APIMSG_ACK(msg); 1579 } 1580 1581 #if LWIP_TCP 1582 /** 1583 * Indicate data has been received from a TCP pcb contained in a netconn 1584 * Called from netconn_recv 1585 * 1586 * @param m the api_msg pointing to the connection 1587 */ 1588 void 1589 lwip_netconn_do_recv(void *m) 1590 { 1591 struct api_msg *msg = (struct api_msg *)m; 1592 1593 msg->err = ERR_OK; 1594 if (msg->conn->pcb.tcp != NULL) { 1595 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 1596 size_t remaining = msg->msg.r.len; 1597 do { 1598 u16_t recved = (u16_t)((remaining > 0xffff) ? 0xffff : remaining); 1599 tcp_recved(msg->conn->pcb.tcp, recved); 1600 remaining -= recved; 1601 } while (remaining != 0); 1602 } 1603 } 1604 TCPIP_APIMSG_ACK(msg); 1605 } 1606 1607 #if TCP_LISTEN_BACKLOG 1608 /** Indicate that a TCP pcb has been accepted 1609 * Called from netconn_accept 1610 * 1611 * @param m the api_msg pointing to the connection 1612 */ 1613 void 1614 lwip_netconn_do_accepted(void *m) 1615 { 1616 struct api_msg *msg = (struct api_msg *)m; 1617 1618 msg->err = ERR_OK; 1619 if (msg->conn->pcb.tcp != NULL) { 1620 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 1621 tcp_backlog_accepted(msg->conn->pcb.tcp); 1622 } 1623 } 1624 TCPIP_APIMSG_ACK(msg); 1625 } 1626 #endif /* TCP_LISTEN_BACKLOG */ 1627 1628 /** 1629 * See if more data needs to be written from a previous call to netconn_write. 1630 * Called initially from lwip_netconn_do_write. If the first call can't send all data 1631 * (because of low memory or empty send-buffer), this function is called again 1632 * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the 1633 * blocking application thread (waiting in netconn_write) is released. 1634 * 1635 * @param conn netconn (that is currently in state NETCONN_WRITE) to process 1636 * @return ERR_OK 1637 * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished 1638 */ 1639 static err_t 1640 lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) 1641 { 1642 err_t err; 1643 const void *dataptr; 1644 u16_t len, available; 1645 u8_t write_finished = 0; 1646 size_t diff; 1647 u8_t dontblock; 1648 u8_t apiflags; 1649 u8_t write_more; 1650 1651 LWIP_ASSERT("conn != NULL", conn != NULL); 1652 LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); 1653 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 1654 LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); 1655 LWIP_ASSERT("conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len", 1656 conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len); 1657 LWIP_ASSERT("conn->current_msg->msg.w.vector_cnt > 0", conn->current_msg->msg.w.vector_cnt > 0); 1658 1659 apiflags = conn->current_msg->msg.w.apiflags; 1660 dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); 1661 1662 #if LWIP_SO_SNDTIMEO 1663 if ((conn->send_timeout != 0) && 1664 ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) { 1665 write_finished = 1; 1666 if (conn->current_msg->msg.w.offset == 0) { 1667 /* nothing has been written */ 1668 err = ERR_WOULDBLOCK; 1669 } else { 1670 /* partial write */ 1671 err = ERR_OK; 1672 } 1673 } else 1674 #endif /* LWIP_SO_SNDTIMEO */ 1675 { 1676 do { 1677 dataptr = (const u8_t *)conn->current_msg->msg.w.vector->ptr + conn->current_msg->msg.w.vector_off; 1678 diff = conn->current_msg->msg.w.vector->len - conn->current_msg->msg.w.vector_off; 1679 if (diff > 0xffffUL) { /* max_u16_t */ 1680 len = 0xffff; 1681 apiflags |= TCP_WRITE_FLAG_MORE; 1682 } else { 1683 len = (u16_t)diff; 1684 } 1685 available = tcp_sndbuf(conn->pcb.tcp); 1686 if (available < len) { 1687 /* don't try to write more than sendbuf */ 1688 len = available; 1689 if (dontblock) { 1690 if (!len) { 1691 /* set error according to partial write or not */ 1692 err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK; 1693 goto err_mem; 1694 } 1695 } else { 1696 apiflags |= TCP_WRITE_FLAG_MORE; 1697 } 1698 } 1699 LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", 1700 ((conn->current_msg->msg.w.vector_off + len) <= conn->current_msg->msg.w.vector->len)); 1701 /* we should loop around for more sending in the following cases: 1702 1) We couldn't finish the current vector because of 16-bit size limitations. 1703 tcp_write() and tcp_sndbuf() both are limited to 16-bit sizes 1704 2) We are sending the remainder of the current vector and have more */ 1705 if ((len == 0xffff && diff > 0xffffUL) || 1706 (len == (u16_t)diff && conn->current_msg->msg.w.vector_cnt > 1)) { 1707 write_more = 1; 1708 apiflags |= TCP_WRITE_FLAG_MORE; 1709 } else { 1710 write_more = 0; 1711 } 1712 err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); 1713 if (err == ERR_OK) { 1714 conn->current_msg->msg.w.offset += len; 1715 conn->current_msg->msg.w.vector_off += len; 1716 /* check if current vector is finished */ 1717 if (conn->current_msg->msg.w.vector_off == conn->current_msg->msg.w.vector->len) { 1718 conn->current_msg->msg.w.vector_cnt--; 1719 /* if we have additional vectors, move on to them */ 1720 if (conn->current_msg->msg.w.vector_cnt > 0) { 1721 conn->current_msg->msg.w.vector++; 1722 conn->current_msg->msg.w.vector_off = 0; 1723 } 1724 } 1725 } 1726 } while (write_more && err == ERR_OK); 1727 /* if OK or memory error, check available space */ 1728 if ((err == ERR_OK) || (err == ERR_MEM)) { 1729 err_mem: 1730 if (dontblock && (conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len)) { 1731 /* non-blocking write did not write everything: mark the pcb non-writable 1732 and let poll_tcp check writable space to mark the pcb writable again */ 1733 API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0); 1734 conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; 1735 } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || 1736 (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { 1737 /* The queued byte- or pbuf-count exceeds the configured low-water limit, 1738 let select mark this pcb as non-writable. */ 1739 API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0); 1740 } 1741 } 1742 1743 if (err == ERR_OK) { 1744 err_t out_err; 1745 if ((conn->current_msg->msg.w.offset == conn->current_msg->msg.w.len) || dontblock) { 1746 /* return sent length (caller reads length from msg.w.offset) */ 1747 write_finished = 1; 1748 } 1749 out_err = tcp_output(conn->pcb.tcp); 1750 if (out_err == ERR_RTE) { 1751 /* If tcp_output fails because no route is found, 1752 don't try writing any more but return the error 1753 to the application thread. */ 1754 err = out_err; 1755 write_finished = 1; 1756 } 1757 } else if (err == ERR_MEM) { 1758 /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called. 1759 For blocking sockets, we do NOT return to the application 1760 thread, since ERR_MEM is only a temporary error! Non-blocking 1761 will remain non-writable until sent_tcp/poll_tcp is called */ 1762 1763 /* tcp_write returned ERR_MEM, try tcp_output anyway */ 1764 err_t out_err = tcp_output(conn->pcb.tcp); 1765 if (out_err == ERR_RTE) { 1766 /* If tcp_output fails because no route is found, 1767 don't try writing any more but return the error 1768 to the application thread. */ 1769 err = out_err; 1770 write_finished = 1; 1771 } else if (dontblock) { 1772 /* non-blocking write is done on ERR_MEM, set error according 1773 to partial write or not */ 1774 err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK; 1775 write_finished = 1; 1776 } 1777 } else { 1778 /* On errors != ERR_MEM, we don't try writing any more but return 1779 the error to the application thread. */ 1780 write_finished = 1; 1781 } 1782 } 1783 if (write_finished) { 1784 /* everything was written: set back connection state 1785 and back to application task */ 1786 sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 1787 conn->current_msg->err = err; 1788 conn->current_msg = NULL; 1789 conn->state = NETCONN_NONE; 1790 #if LWIP_TCPIP_CORE_LOCKING 1791 if (delayed) 1792 #endif 1793 { 1794 sys_sem_signal(op_completed_sem); 1795 } 1796 } 1797 #if LWIP_TCPIP_CORE_LOCKING 1798 else { 1799 return ERR_MEM; 1800 } 1801 #endif 1802 return ERR_OK; 1803 } 1804 #endif /* LWIP_TCP */ 1805 1806 /** 1807 * Send some data on a TCP pcb contained in a netconn 1808 * Called from netconn_write 1809 * 1810 * @param m the api_msg pointing to the connection 1811 */ 1812 void 1813 lwip_netconn_do_write(void *m) 1814 { 1815 struct api_msg *msg = (struct api_msg *)m; 1816 1817 err_t err = netconn_err(msg->conn); 1818 if (err == ERR_OK) { 1819 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 1820 #if LWIP_TCP 1821 if (msg->conn->state != NETCONN_NONE) { 1822 /* netconn is connecting, closing or in blocking write */ 1823 err = ERR_INPROGRESS; 1824 } else if (msg->conn->pcb.tcp != NULL) { 1825 msg->conn->state = NETCONN_WRITE; 1826 /* set all the variables used by lwip_netconn_do_writemore */ 1827 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL); 1828 LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0); 1829 msg->conn->current_msg = msg; 1830 #if LWIP_TCPIP_CORE_LOCKING 1831 if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) { 1832 LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); 1833 UNLOCK_TCPIP_CORE(); 1834 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 1835 LOCK_TCPIP_CORE(); 1836 LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE); 1837 } 1838 #else /* LWIP_TCPIP_CORE_LOCKING */ 1839 lwip_netconn_do_writemore(msg->conn); 1840 #endif /* LWIP_TCPIP_CORE_LOCKING */ 1841 /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG 1842 since lwip_netconn_do_writemore ACKs it! */ 1843 return; 1844 } else { 1845 err = ERR_CONN; 1846 } 1847 #else /* LWIP_TCP */ 1848 err = ERR_VAL; 1849 #endif /* LWIP_TCP */ 1850 #if (LWIP_UDP || LWIP_RAW) 1851 } else { 1852 err = ERR_VAL; 1853 #endif /* (LWIP_UDP || LWIP_RAW) */ 1854 } 1855 } 1856 msg->err = err; 1857 TCPIP_APIMSG_ACK(msg); 1858 } 1859 1860 /** 1861 * Return a connection's local or remote address 1862 * Called from netconn_getaddr 1863 * 1864 * @param m the api_msg pointing to the connection 1865 */ 1866 void 1867 lwip_netconn_do_getaddr(void *m) 1868 { 1869 struct api_msg *msg = (struct api_msg *)m; 1870 1871 if (msg->conn->pcb.ip != NULL) { 1872 if (msg->msg.ad.local) { 1873 ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), 1874 msg->conn->pcb.ip->local_ip); 1875 } else { 1876 ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), 1877 msg->conn->pcb.ip->remote_ip); 1878 } 1879 1880 msg->err = ERR_OK; 1881 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1882 #if LWIP_RAW 1883 case NETCONN_RAW: 1884 if (msg->msg.ad.local) { 1885 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; 1886 } else { 1887 /* return an error as connecting is only a helper for upper layers */ 1888 msg->err = ERR_CONN; 1889 } 1890 break; 1891 #endif /* LWIP_RAW */ 1892 #if LWIP_UDP 1893 case NETCONN_UDP: 1894 if (msg->msg.ad.local) { 1895 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; 1896 } else { 1897 if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { 1898 msg->err = ERR_CONN; 1899 } else { 1900 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; 1901 } 1902 } 1903 break; 1904 #endif /* LWIP_UDP */ 1905 #if LWIP_TCP 1906 case NETCONN_TCP: 1907 if ((msg->msg.ad.local == 0) && 1908 ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) { 1909 /* pcb is not connected and remote name is requested */ 1910 msg->err = ERR_CONN; 1911 } else { 1912 API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port); 1913 } 1914 break; 1915 #endif /* LWIP_TCP */ 1916 default: 1917 LWIP_ASSERT("invalid netconn_type", 0); 1918 break; 1919 } 1920 } else { 1921 msg->err = ERR_CONN; 1922 } 1923 TCPIP_APIMSG_ACK(msg); 1924 } 1925 1926 /** 1927 * Close or half-shutdown a TCP pcb contained in a netconn 1928 * Called from netconn_close 1929 * In contrast to closing sockets, the netconn is not deallocated. 1930 * 1931 * @param m the api_msg pointing to the connection 1932 */ 1933 void 1934 lwip_netconn_do_close(void *m) 1935 { 1936 struct api_msg *msg = (struct api_msg *)m; 1937 1938 #if LWIP_TCP 1939 enum netconn_state state = msg->conn->state; 1940 /* First check if this is a TCP netconn and if it is in a correct state 1941 (LISTEN doesn't support half shutdown) */ 1942 if ((msg->conn->pcb.tcp != NULL) && 1943 (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) && 1944 ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) { 1945 /* Check if we are in a connected state */ 1946 if (state == NETCONN_CONNECT) { 1947 /* TCP connect in progress: cannot shutdown */ 1948 msg->err = ERR_CONN; 1949 } else if (state == NETCONN_WRITE) { 1950 #if LWIP_NETCONN_FULLDUPLEX 1951 if (msg->msg.sd.shut & NETCONN_SHUT_WR) { 1952 /* close requested, abort running write */ 1953 sys_sem_t *write_completed_sem; 1954 LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); 1955 write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); 1956 msg->conn->current_msg->err = ERR_CLSD; 1957 msg->conn->current_msg = NULL; 1958 msg->conn->state = NETCONN_NONE; 1959 state = NETCONN_NONE; 1960 sys_sem_signal(write_completed_sem); 1961 } else { 1962 LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD); 1963 /* In this case, let the write continue and do not interfere with 1964 conn->current_msg or conn->state! */ 1965 msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0); 1966 } 1967 } 1968 if (state == NETCONN_NONE) { 1969 #else /* LWIP_NETCONN_FULLDUPLEX */ 1970 msg->err = ERR_INPROGRESS; 1971 } else { 1972 #endif /* LWIP_NETCONN_FULLDUPLEX */ 1973 if (msg->msg.sd.shut & NETCONN_SHUT_RD) { 1974 #if LWIP_NETCONN_FULLDUPLEX 1975 /* Mark mboxes invalid */ 1976 netconn_mark_mbox_invalid(msg->conn); 1977 #else /* LWIP_NETCONN_FULLDUPLEX */ 1978 netconn_drain(msg->conn); 1979 #endif /* LWIP_NETCONN_FULLDUPLEX */ 1980 } 1981 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL); 1982 msg->conn->state = NETCONN_CLOSE; 1983 msg->conn->current_msg = msg; 1984 #if LWIP_TCPIP_CORE_LOCKING 1985 if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) { 1986 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE); 1987 UNLOCK_TCPIP_CORE(); 1988 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 1989 LOCK_TCPIP_CORE(); 1990 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); 1991 } 1992 #else /* LWIP_TCPIP_CORE_LOCKING */ 1993 lwip_netconn_do_close_internal(msg->conn); 1994 #endif /* LWIP_TCPIP_CORE_LOCKING */ 1995 /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */ 1996 return; 1997 } 1998 } else 1999 #endif /* LWIP_TCP */ 2000 { 2001 msg->err = ERR_CONN; 2002 } 2003 TCPIP_APIMSG_ACK(msg); 2004 } 2005 2006 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) 2007 /** 2008 * Join multicast groups for UDP netconns. 2009 * Called from netconn_join_leave_group 2010 * 2011 * @param m the api_msg pointing to the connection 2012 */ 2013 void 2014 lwip_netconn_do_join_leave_group(void *m) 2015 { 2016 struct api_msg *msg = (struct api_msg *)m; 2017 2018 msg->err = ERR_CONN; 2019 if (msg->conn->pcb.tcp != NULL) { 2020 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 2021 #if LWIP_UDP 2022 #if LWIP_IPV6 && LWIP_IPV6_MLD 2023 if (NETCONNTYPE_ISIPV6(msg->conn->type)) { 2024 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 2025 msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), 2026 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); 2027 } else { 2028 msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), 2029 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); 2030 } 2031 } else 2032 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ 2033 { 2034 #if LWIP_IGMP 2035 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 2036 msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), 2037 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); 2038 } else { 2039 msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), 2040 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); 2041 } 2042 #endif /* LWIP_IGMP */ 2043 } 2044 #endif /* LWIP_UDP */ 2045 #if (LWIP_TCP || LWIP_RAW) 2046 } else { 2047 msg->err = ERR_VAL; 2048 #endif /* (LWIP_TCP || LWIP_RAW) */ 2049 } 2050 } 2051 TCPIP_APIMSG_ACK(msg); 2052 } 2053 /** 2054 * Join multicast groups for UDP netconns. 2055 * Called from netconn_join_leave_group_netif 2056 * 2057 * @param m the api_msg pointing to the connection 2058 */ 2059 void 2060 lwip_netconn_do_join_leave_group_netif(void *m) 2061 { 2062 struct api_msg *msg = (struct api_msg *)m; 2063 struct netif *netif; 2064 2065 netif = netif_get_by_index(msg->msg.jl.if_idx); 2066 if (netif == NULL) { 2067 msg->err = ERR_IF; 2068 goto done; 2069 } 2070 2071 msg->err = ERR_CONN; 2072 if (msg->conn->pcb.tcp != NULL) { 2073 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 2074 #if LWIP_UDP 2075 #if LWIP_IPV6 && LWIP_IPV6_MLD 2076 if (NETCONNTYPE_ISIPV6(msg->conn->type)) { 2077 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 2078 msg->err = mld6_joingroup_netif(netif, 2079 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); 2080 } else { 2081 msg->err = mld6_leavegroup_netif(netif, 2082 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); 2083 } 2084 } else 2085 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ 2086 { 2087 #if LWIP_IGMP 2088 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 2089 msg->err = igmp_joingroup_netif(netif, 2090 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); 2091 } else { 2092 msg->err = igmp_leavegroup_netif(netif, 2093 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); 2094 } 2095 #endif /* LWIP_IGMP */ 2096 } 2097 #endif /* LWIP_UDP */ 2098 #if (LWIP_TCP || LWIP_RAW) 2099 } else { 2100 msg->err = ERR_VAL; 2101 #endif /* (LWIP_TCP || LWIP_RAW) */ 2102 } 2103 } 2104 2105 done: 2106 TCPIP_APIMSG_ACK(msg); 2107 } 2108 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ 2109 2110 #if LWIP_DNS 2111 /** 2112 * Callback function that is called when DNS name is resolved 2113 * (or on timeout). A waiting application thread is waked up by 2114 * signaling the semaphore. 2115 */ 2116 static void 2117 lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg) 2118 { 2119 struct dns_api_msg *msg = (struct dns_api_msg *)arg; 2120 2121 /* we trust the internal implementation to be correct :-) */ 2122 LWIP_UNUSED_ARG(name); 2123 2124 if (ipaddr == NULL) { 2125 /* timeout or memory error */ 2126 API_EXPR_DEREF(msg->err) = ERR_VAL; 2127 } else { 2128 /* address was resolved */ 2129 API_EXPR_DEREF(msg->err) = ERR_OK; 2130 API_EXPR_DEREF(msg->addr) = *ipaddr; 2131 } 2132 /* wake up the application task waiting in netconn_gethostbyname */ 2133 sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); 2134 } 2135 2136 /** 2137 * Execute a DNS query 2138 * Called from netconn_gethostbyname 2139 * 2140 * @param arg the dns_api_msg pointing to the query 2141 */ 2142 void 2143 lwip_netconn_do_gethostbyname(void *arg) 2144 { 2145 struct dns_api_msg *msg = (struct dns_api_msg *)arg; 2146 u8_t addrtype = 2147 #if LWIP_IPV4 && LWIP_IPV6 2148 msg->dns_addrtype; 2149 #else 2150 LWIP_DNS_ADDRTYPE_DEFAULT; 2151 #endif 2152 2153 API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name, 2154 API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype); 2155 #if LWIP_TCPIP_CORE_LOCKING 2156 /* For core locking, only block if we need to wait for answer/timeout */ 2157 if (API_EXPR_DEREF(msg->err) == ERR_INPROGRESS) { 2158 UNLOCK_TCPIP_CORE(); 2159 sys_sem_wait(API_EXPR_REF_SEM(msg->sem)); 2160 LOCK_TCPIP_CORE(); 2161 LWIP_ASSERT("do_gethostbyname still in progress!!", API_EXPR_DEREF(msg->err) != ERR_INPROGRESS); 2162 } 2163 #else /* LWIP_TCPIP_CORE_LOCKING */ 2164 if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) { 2165 /* on error or immediate success, wake up the application 2166 * task waiting in netconn_gethostbyname */ 2167 sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); 2168 } 2169 #endif /* LWIP_TCPIP_CORE_LOCKING */ 2170 } 2171 #endif /* LWIP_DNS */ 2172 2173 #endif /* LWIP_NETCONN */ 2174