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