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 (at) 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/api_msg.h" 44 45 #include "lwip/ip.h" 46 #include "lwip/udp.h" 47 #include "lwip/tcp.h" 48 #include "lwip/raw.h" 49 50 #include "lwip/memp.h" 51 #include "lwip/tcpip.h" 52 #include "lwip/igmp.h" 53 #include "lwip/dns.h" 54 55 #include <string.h> 56 57 #define SET_NONBLOCKING_CONNECT(conn, val) do { if(val) { \ 58 (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \ 59 } else { \ 60 (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0) 61 #define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0) 62 63 /* forward declarations */ 64 #if LWIP_TCP 65 static err_t do_writemore(struct netconn *conn); 66 static void do_close_internal(struct netconn *conn); 67 #endif 68 69 #if LWIP_RAW 70 /** 71 * Receive callback function for RAW netconns. 72 * Doesn't 'eat' the packet, only references it and sends it to 73 * conn->recvmbox 74 * 75 * @see raw.h (struct raw_pcb.recv) for parameters and return value 76 */ 77 static u8_t 78 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, 79 ip_addr_t *addr) 80 { 81 struct pbuf *q; 82 struct netbuf *buf; 83 struct netconn *conn; 84 85 LWIP_UNUSED_ARG(addr); 86 conn = (struct netconn *)arg; 87 88 if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) { 89 #if LWIP_SO_RCVBUF 90 int recv_avail; 91 SYS_ARCH_GET(conn->recv_avail, recv_avail); 92 if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) { 93 return 0; 94 } 95 #endif /* LWIP_SO_RCVBUF */ 96 /* copy the whole packet into new pbufs */ 97 q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); 98 if(q != NULL) { 99 if (pbuf_copy(q, p) != ERR_OK) { 100 pbuf_free(q); 101 q = NULL; 102 } 103 } 104 105 if (q != NULL) { 106 u16_t len; 107 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 108 if (buf == NULL) { 109 pbuf_free(q); 110 return 0; 111 } 112 113 buf->p = q; 114 buf->ptr = q; 115 ip_addr_copy(buf->addr, *ip_current_src_addr()); 116 buf->port = pcb->protocol; 117 118 len = q->tot_len; 119 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { 120 netbuf_delete(buf); 121 return 0; 122 } else { 123 #if LWIP_SO_RCVBUF 124 SYS_ARCH_INC(conn->recv_avail, len); 125 #endif /* LWIP_SO_RCVBUF */ 126 /* Register event with callback */ 127 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 128 } 129 } 130 } 131 132 return 0; /* do not eat the packet */ 133 } 134 #endif /* LWIP_RAW*/ 135 136 #if LWIP_UDP 137 /** 138 * Receive callback function for UDP netconns. 139 * Posts the packet to conn->recvmbox or deletes it on memory error. 140 * 141 * @see udp.h (struct udp_pcb.recv) for parameters 142 */ 143 static void 144 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, 145 ip_addr_t *addr, u16_t port) 146 { 147 struct netbuf *buf; 148 struct netconn *conn; 149 u16_t len; 150 #if LWIP_SO_RCVBUF 151 int recv_avail; 152 #endif /* LWIP_SO_RCVBUF */ 153 154 LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ 155 LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); 156 LWIP_ASSERT("recv_udp must have an argument", arg != NULL); 157 conn = (struct netconn *)arg; 158 LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); 159 160 #if LWIP_SO_RCVBUF 161 SYS_ARCH_GET(conn->recv_avail, recv_avail); 162 if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) || 163 ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { 164 #else /* LWIP_SO_RCVBUF */ 165 if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) { 166 #endif /* LWIP_SO_RCVBUF */ 167 pbuf_free(p); 168 return; 169 } 170 171 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 172 if (buf == NULL) { 173 pbuf_free(p); 174 return; 175 } else { 176 buf->p = p; 177 buf->ptr = p; 178 ip_addr_set(&buf->addr, addr); 179 buf->port = port; 180 #if LWIP_NETBUF_RECVINFO 181 { 182 const struct ip_hdr* iphdr = ip_current_header(); 183 /* get the UDP header - always in the first pbuf, ensured by udp_input */ 184 const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr)); 185 #if LWIP_CHECKSUM_ON_COPY 186 buf->flags = NETBUF_FLAG_DESTADDR; 187 #endif /* LWIP_CHECKSUM_ON_COPY */ 188 ip_addr_set(&buf->toaddr, ip_current_dest_addr()); 189 buf->toport_chksum = udphdr->dest; 190 } 191 #endif /* LWIP_NETBUF_RECVINFO */ 192 } 193 194 len = p->tot_len; 195 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { 196 netbuf_delete(buf); 197 return; 198 } else { 199 #if LWIP_SO_RCVBUF 200 SYS_ARCH_INC(conn->recv_avail, len); 201 #endif /* LWIP_SO_RCVBUF */ 202 /* Register event with callback */ 203 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 204 } 205 } 206 #endif /* LWIP_UDP */ 207 208 #if LWIP_TCP 209 /** 210 * Receive callback function for TCP netconns. 211 * Posts the packet to conn->recvmbox, but doesn't delete it on errors. 212 * 213 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value 214 */ 215 static err_t 216 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) 217 { 218 struct netconn *conn; 219 u16_t len; 220 221 LWIP_UNUSED_ARG(pcb); 222 LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); 223 LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); 224 conn = (struct netconn *)arg; 225 LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); 226 227 if (conn == NULL) { 228 return ERR_VAL; 229 } 230 if (!sys_mbox_valid(&conn->recvmbox)) { 231 /* recvmbox already deleted */ 232 if (p != NULL) { 233 tcp_recved(pcb, p->tot_len); 234 pbuf_free(p); 235 } 236 return ERR_OK; 237 } 238 /* Unlike for UDP or RAW pcbs, don't check for available space 239 using recv_avail since that could break the connection 240 (data is already ACKed) */ 241 242 /* don't overwrite fatal errors! */ 243 NETCONN_SET_SAFE_ERR(conn, err); 244 245 if (p != NULL) { 246 len = p->tot_len; 247 } else { 248 len = 0; 249 } 250 251 if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) { 252 /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */ 253 return ERR_MEM; 254 } else { 255 #if LWIP_SO_RCVBUF 256 SYS_ARCH_INC(conn->recv_avail, len); 257 #endif /* LWIP_SO_RCVBUF */ 258 /* Register event with callback */ 259 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 260 } 261 262 return ERR_OK; 263 } 264 265 /** 266 * Poll callback function for TCP netconns. 267 * Wakes up an application thread that waits for a connection to close 268 * or data to be sent. The application thread then takes the 269 * appropriate action to go on. 270 * 271 * Signals the conn->sem. 272 * netconn_close waits for conn->sem if closing failed. 273 * 274 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value 275 */ 276 static err_t 277 poll_tcp(void *arg, struct tcp_pcb *pcb) 278 { 279 struct netconn *conn = (struct netconn *)arg; 280 281 LWIP_UNUSED_ARG(pcb); 282 LWIP_ASSERT("conn != NULL", (conn != NULL)); 283 284 if (conn->state == NETCONN_WRITE) { 285 do_writemore(conn); 286 } else if (conn->state == NETCONN_CLOSE) { 287 do_close_internal(conn); 288 } 289 /* @todo: implement connect timeout here? */ 290 291 /* Did a nonblocking write fail before? Then check available write-space. */ 292 if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) { 293 /* If the queued byte- or pbuf-count drops below the configured low-water limit, 294 let select mark this pcb as writable again. */ 295 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && 296 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { 297 conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; 298 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 299 } 300 } 301 302 return ERR_OK; 303 } 304 305 /** 306 * Sent callback function for TCP netconns. 307 * Signals the conn->sem and calls API_EVENT. 308 * netconn_write waits for conn->sem if send buffer is low. 309 * 310 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value 311 */ 312 static err_t 313 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) 314 { 315 struct netconn *conn = (struct netconn *)arg; 316 317 LWIP_UNUSED_ARG(pcb); 318 LWIP_ASSERT("conn != NULL", (conn != NULL)); 319 320 if (conn->state == NETCONN_WRITE) { 321 do_writemore(conn); 322 } else if (conn->state == NETCONN_CLOSE) { 323 do_close_internal(conn); 324 } 325 326 if (conn) { 327 /* If the queued byte- or pbuf-count drops below the configured low-water limit, 328 let select mark this pcb as writable again. */ 329 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && 330 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { 331 conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; 332 API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); 333 } 334 } 335 336 return ERR_OK; 337 } 338 339 /** 340 * Error callback function for TCP netconns. 341 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. 342 * The application thread has then to decide what to do. 343 * 344 * @see tcp.h (struct tcp_pcb.err) for parameters 345 */ 346 static void 347 err_tcp(void *arg, err_t err) 348 { 349 struct netconn *conn; 350 enum netconn_state old_state; 351 SYS_ARCH_DECL_PROTECT(lev); 352 353 conn = (struct netconn *)arg; 354 LWIP_ASSERT("conn != NULL", (conn != NULL)); 355 356 conn->pcb.tcp = NULL; 357 358 /* no check since this is always fatal! */ 359 SYS_ARCH_PROTECT(lev); 360 conn->last_err = err; 361 SYS_ARCH_UNPROTECT(lev); 362 363 /* reset conn->state now before waking up other threads */ 364 old_state = conn->state; 365 conn->state = NETCONN_NONE; 366 367 /* Notify the user layer about a connection error. Used to signal 368 select. */ 369 API_EVENT(conn, NETCONN_EVT_ERROR, 0); 370 /* Try to release selects pending on 'read' or 'write', too. 371 They will get an error if they actually try to read or write. */ 372 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 373 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 374 375 /* pass NULL-message to recvmbox to wake up pending recv */ 376 if (sys_mbox_valid(&conn->recvmbox)) { 377 /* use trypost to prevent deadlock */ 378 sys_mbox_trypost(&conn->recvmbox, NULL); 379 } 380 /* pass NULL-message to acceptmbox to wake up pending accept */ 381 if (sys_mbox_valid(&conn->acceptmbox)) { 382 /* use trypost to preven deadlock */ 383 sys_mbox_trypost(&conn->acceptmbox, NULL); 384 } 385 386 if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || 387 (old_state == NETCONN_CONNECT)) { 388 /* calling do_writemore/do_close_internal is not necessary 389 since the pcb has already been deleted! */ 390 int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn); 391 SET_NONBLOCKING_CONNECT(conn, 0); 392 393 if (!was_nonblocking_connect) { 394 /* set error return code */ 395 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 396 conn->current_msg->err = err; 397 conn->current_msg = NULL; 398 /* wake up the waiting task */ 399 sys_sem_signal(&conn->op_completed); 400 } 401 } else { 402 LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL); 403 } 404 } 405 406 /** 407 * Setup a tcp_pcb with the correct callback function pointers 408 * and their arguments. 409 * 410 * @param conn the TCP netconn to setup 411 */ 412 static void 413 setup_tcp(struct netconn *conn) 414 { 415 struct tcp_pcb *pcb; 416 417 pcb = conn->pcb.tcp; 418 tcp_arg(pcb, conn); 419 tcp_recv(pcb, recv_tcp); 420 tcp_sent(pcb, sent_tcp); 421 tcp_poll(pcb, poll_tcp, 4); 422 tcp_err(pcb, err_tcp); 423 } 424 425 /** 426 * Accept callback function for TCP netconns. 427 * Allocates a new netconn and posts that to conn->acceptmbox. 428 * 429 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value 430 */ 431 static err_t 432 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) 433 { 434 struct netconn *newconn; 435 struct netconn *conn = (struct netconn *)arg; 436 437 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state))); 438 439 if (!sys_mbox_valid(&conn->acceptmbox)) { 440 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n")); 441 return ERR_VAL; 442 } 443 444 /* We have to set the callback here even though 445 * the new socket is unknown. conn->socket is marked as -1. */ 446 newconn = netconn_alloc(conn->type, conn->callback); 447 if (newconn == NULL) { 448 return ERR_MEM; 449 } 450 newconn->pcb.tcp = newpcb; 451 setup_tcp(newconn); 452 /* no protection: when creating the pcb, the netconn is not yet known 453 to the application thread */ 454 newconn->last_err = err; 455 456 if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) { 457 /* When returning != ERR_OK, the pcb is aborted in tcp_process(), 458 so do nothing here! */ 459 newconn->pcb.tcp = NULL; 460 /* no need to drain since we know the recvmbox is empty. */ 461 sys_mbox_free(&newconn->recvmbox); 462 sys_mbox_set_invalid(&newconn->recvmbox); 463 netconn_free(newconn); 464 return ERR_MEM; 465 } else { 466 /* Register event with callback */ 467 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 468 } 469 470 return ERR_OK; 471 } 472 #endif /* LWIP_TCP */ 473 474 /** 475 * Create a new pcb of a specific type. 476 * Called from do_newconn(). 477 * 478 * @param msg the api_msg_msg describing the connection type 479 * @return msg->conn->err, but the return value is currently ignored 480 */ 481 static void 482 pcb_new(struct api_msg_msg *msg) 483 { 484 LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); 485 486 /* Allocate a PCB for this connection */ 487 switch(NETCONNTYPE_GROUP(msg->conn->type)) { 488 #if LWIP_RAW 489 case NETCONN_RAW: 490 msg->conn->pcb.raw = raw_new(msg->msg.n.proto); 491 if(msg->conn->pcb.raw == NULL) { 492 msg->err = ERR_MEM; 493 break; 494 } 495 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); 496 break; 497 #endif /* LWIP_RAW */ 498 #if LWIP_UDP 499 case NETCONN_UDP: 500 msg->conn->pcb.udp = udp_new(); 501 if(msg->conn->pcb.udp == NULL) { 502 msg->err = ERR_MEM; 503 break; 504 } 505 #if LWIP_UDPLITE 506 if (msg->conn->type==NETCONN_UDPLITE) { 507 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); 508 } 509 #endif /* LWIP_UDPLITE */ 510 if (msg->conn->type==NETCONN_UDPNOCHKSUM) { 511 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); 512 } 513 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); 514 break; 515 #endif /* LWIP_UDP */ 516 #if LWIP_TCP 517 case NETCONN_TCP: 518 msg->conn->pcb.tcp = tcp_new(); 519 if(msg->conn->pcb.tcp == NULL) { 520 msg->err = ERR_MEM; 521 break; 522 } 523 setup_tcp(msg->conn); 524 break; 525 #endif /* LWIP_TCP */ 526 default: 527 /* Unsupported netconn type, e.g. protocol disabled */ 528 msg->err = ERR_VAL; 529 break; 530 } 531 } 532 533 /** 534 * Create a new pcb of a specific type inside a netconn. 535 * Called from netconn_new_with_proto_and_callback. 536 * 537 * @param msg the api_msg_msg describing the connection type 538 */ 539 void 540 do_newconn(struct api_msg_msg *msg) 541 { 542 msg->err = ERR_OK; 543 if(msg->conn->pcb.tcp == NULL) { 544 pcb_new(msg); 545 } 546 /* Else? This "new" connection already has a PCB allocated. */ 547 /* Is this an error condition? Should it be deleted? */ 548 /* We currently just are happy and return. */ 549 550 TCPIP_APIMSG_ACK(msg); 551 } 552 553 /** 554 * Create a new netconn (of a specific type) that has a callback function. 555 * The corresponding pcb is NOT created! 556 * 557 * @param t the type of 'connection' to create (@see enum netconn_type) 558 * @param proto the IP protocol for RAW IP pcbs 559 * @param callback a function to call on status changes (RX available, TX'ed) 560 * @return a newly allocated struct netconn or 561 * NULL on memory error 562 */ 563 struct netconn* 564 netconn_alloc(enum netconn_type t, netconn_callback callback) 565 { 566 struct netconn *conn; 567 int size; 568 569 conn = (struct netconn *)memp_malloc(MEMP_NETCONN); 570 if (conn == NULL) { 571 return NULL; 572 } 573 574 conn->last_err = ERR_OK; 575 conn->type = t; 576 conn->pcb.tcp = NULL; 577 578 #if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \ 579 (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE) 580 size = DEFAULT_RAW_RECVMBOX_SIZE; 581 #else 582 switch(NETCONNTYPE_GROUP(t)) { 583 #if LWIP_RAW 584 case NETCONN_RAW: 585 size = DEFAULT_RAW_RECVMBOX_SIZE; 586 break; 587 #endif /* LWIP_RAW */ 588 #if LWIP_UDP 589 case NETCONN_UDP: 590 size = DEFAULT_UDP_RECVMBOX_SIZE; 591 break; 592 #endif /* LWIP_UDP */ 593 #if LWIP_TCP 594 case NETCONN_TCP: 595 size = DEFAULT_TCP_RECVMBOX_SIZE; 596 break; 597 #endif /* LWIP_TCP */ 598 default: 599 LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); 600 break; 601 } 602 #endif 603 604 if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { 605 memp_free(MEMP_NETCONN, conn); 606 return NULL; 607 } 608 if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { 609 sys_sem_free(&conn->op_completed); 610 memp_free(MEMP_NETCONN, conn); 611 return NULL; 612 } 613 614 #if LWIP_TCP 615 sys_mbox_set_invalid(&conn->acceptmbox); 616 #endif 617 conn->state = NETCONN_NONE; 618 #if LWIP_SOCKET 619 /* initialize socket to -1 since 0 is a valid socket */ 620 conn->socket = -1; 621 #endif /* LWIP_SOCKET */ 622 conn->callback = callback; 623 #if LWIP_TCP 624 conn->current_msg = NULL; 625 conn->write_offset = 0; 626 #endif /* LWIP_TCP */ 627 #if LWIP_SO_RCVTIMEO 628 conn->recv_timeout = 0; 629 #endif /* LWIP_SO_RCVTIMEO */ 630 #if LWIP_SO_RCVBUF 631 conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; 632 conn->recv_avail = 0; 633 #endif /* LWIP_SO_RCVBUF */ 634 conn->flags = 0; 635 return conn; 636 } 637 638 /** 639 * Delete a netconn and all its resources. 640 * The pcb is NOT freed (since we might not be in the right thread context do this). 641 * 642 * @param conn the netconn to free 643 */ 644 void 645 netconn_free(struct netconn *conn) 646 { 647 LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); 648 LWIP_ASSERT("recvmbox must be deallocated before calling this function", 649 !sys_mbox_valid(&conn->recvmbox)); 650 #if LWIP_TCP 651 LWIP_ASSERT("acceptmbox must be deallocated before calling this function", 652 !sys_mbox_valid(&conn->acceptmbox)); 653 #endif /* LWIP_TCP */ 654 655 sys_sem_free(&conn->op_completed); 656 sys_sem_set_invalid(&conn->op_completed); 657 658 memp_free(MEMP_NETCONN, conn); 659 } 660 661 /** 662 * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in 663 * these mboxes 664 * 665 * @param conn the netconn to free 666 * @bytes_drained bytes drained from recvmbox 667 * @accepts_drained pending connections drained from acceptmbox 668 */ 669 static void 670 netconn_drain(struct netconn *conn) 671 { 672 void *mem; 673 #if LWIP_TCP 674 struct pbuf *p; 675 #endif /* LWIP_TCP */ 676 677 /* This runs in tcpip_thread, so we don't need to lock against rx packets */ 678 679 /* Delete and drain the recvmbox. */ 680 if (sys_mbox_valid(&conn->recvmbox)) { 681 while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { 682 #if LWIP_TCP 683 if (conn->type == NETCONN_TCP) { 684 if(mem != NULL) { 685 p = (struct pbuf*)mem; 686 /* pcb might be set to NULL already by err_tcp() */ 687 if (conn->pcb.tcp != NULL) { 688 tcp_recved(conn->pcb.tcp, p->tot_len); 689 } 690 pbuf_free(p); 691 } 692 } else 693 #endif /* LWIP_TCP */ 694 { 695 netbuf_delete((struct netbuf *)mem); 696 } 697 } 698 sys_mbox_free(&conn->recvmbox); 699 sys_mbox_set_invalid(&conn->recvmbox); 700 } 701 702 /* Delete and drain the acceptmbox. */ 703 #if LWIP_TCP 704 if (sys_mbox_valid(&conn->acceptmbox)) { 705 while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { 706 struct netconn *newconn = (struct netconn *)mem; 707 /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ 708 /* pcb might be set to NULL already by err_tcp() */ 709 if (conn->pcb.tcp != NULL) { 710 tcp_accepted(conn->pcb.tcp); 711 } 712 /* drain recvmbox */ 713 netconn_drain(newconn); 714 if (newconn->pcb.tcp != NULL) { 715 tcp_abort(newconn->pcb.tcp); 716 newconn->pcb.tcp = NULL; 717 } 718 netconn_free(newconn); 719 } 720 sys_mbox_free(&conn->acceptmbox); 721 sys_mbox_set_invalid(&conn->acceptmbox); 722 } 723 #endif /* LWIP_TCP */ 724 } 725 726 #if LWIP_TCP 727 /** 728 * Internal helper function to close a TCP netconn: since this sometimes 729 * doesn't work at the first attempt, this function is called from multiple 730 * places. 731 * 732 * @param conn the TCP netconn to close 733 */ 734 static void 735 do_close_internal(struct netconn *conn) 736 { 737 err_t err; 738 u8_t shut, shut_rx, shut_tx, close; 739 740 LWIP_ASSERT("invalid conn", (conn != NULL)); 741 LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP)); 742 LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); 743 LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); 744 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 745 746 shut = conn->current_msg->msg.sd.shut; 747 shut_rx = shut & NETCONN_SHUT_RD; 748 shut_tx = shut & NETCONN_SHUT_WR; 749 /* shutting down both ends is the same as closing */ 750 close = shut == NETCONN_SHUT_RDWR; 751 752 /* Set back some callback pointers */ 753 if (close) { 754 tcp_arg(conn->pcb.tcp, NULL); 755 } 756 if (conn->pcb.tcp->state == LISTEN) { 757 tcp_accept(conn->pcb.tcp, NULL); 758 } else { 759 /* some callbacks have to be reset if tcp_close is not successful */ 760 if (shut_rx) { 761 tcp_recv(conn->pcb.tcp, NULL); 762 tcp_accept(conn->pcb.tcp, NULL); 763 } 764 if (shut_tx) { 765 tcp_sent(conn->pcb.tcp, NULL); 766 } 767 if (close) { 768 tcp_poll(conn->pcb.tcp, NULL, 4); 769 tcp_err(conn->pcb.tcp, NULL); 770 } 771 } 772 /* Try to close the connection */ 773 if (shut == NETCONN_SHUT_RDWR) { 774 err = tcp_close(conn->pcb.tcp); 775 } else { 776 err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR); 777 } 778 if (err == ERR_OK) { 779 /* Closing succeeded */ 780 conn->current_msg->err = ERR_OK; 781 conn->current_msg = NULL; 782 conn->state = NETCONN_NONE; 783 /* Set back some callback pointers as conn is going away */ 784 conn->pcb.tcp = NULL; 785 /* Trigger select() in socket layer. Make sure everybody notices activity 786 on the connection, error first! */ 787 if (close) { 788 API_EVENT(conn, NETCONN_EVT_ERROR, 0); 789 } 790 if (shut_rx) { 791 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 792 } 793 if (shut_tx) { 794 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 795 } 796 /* wake up the application task */ 797 sys_sem_signal(&conn->op_completed); 798 } else { 799 /* Closing failed, restore some of the callbacks */ 800 /* Closing of listen pcb will never fail! */ 801 LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN)); 802 tcp_sent(conn->pcb.tcp, sent_tcp); 803 tcp_poll(conn->pcb.tcp, poll_tcp, 4); 804 tcp_err(conn->pcb.tcp, err_tcp); 805 tcp_arg(conn->pcb.tcp, conn); 806 /* don't restore recv callback: we don't want to receive any more data */ 807 } 808 /* If closing didn't succeed, we get called again either 809 from poll_tcp or from sent_tcp */ 810 } 811 #endif /* LWIP_TCP */ 812 813 /** 814 * Delete the pcb inside a netconn. 815 * Called from netconn_delete. 816 * 817 * @param msg the api_msg_msg pointing to the connection 818 */ 819 void 820 do_delconn(struct api_msg_msg *msg) 821 { 822 /* @todo TCP: abort running write/connect? */ 823 if ((msg->conn->state != NETCONN_NONE) && 824 (msg->conn->state != NETCONN_LISTEN) && 825 (msg->conn->state != NETCONN_CONNECT)) { 826 /* this only happens for TCP netconns */ 827 LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); 828 msg->err = ERR_INPROGRESS; 829 } else { 830 LWIP_ASSERT("blocking connect in progress", 831 (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); 832 /* Drain and delete mboxes */ 833 netconn_drain(msg->conn); 834 835 if (msg->conn->pcb.tcp != NULL) { 836 837 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 838 #if LWIP_RAW 839 case NETCONN_RAW: 840 raw_remove(msg->conn->pcb.raw); 841 break; 842 #endif /* LWIP_RAW */ 843 #if LWIP_UDP 844 case NETCONN_UDP: 845 msg->conn->pcb.udp->recv_arg = NULL; 846 udp_remove(msg->conn->pcb.udp); 847 break; 848 #endif /* LWIP_UDP */ 849 #if LWIP_TCP 850 case NETCONN_TCP: 851 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && 852 msg->conn->write_offset == 0); 853 msg->conn->state = NETCONN_CLOSE; 854 msg->msg.sd.shut = NETCONN_SHUT_RDWR; 855 msg->conn->current_msg = msg; 856 do_close_internal(msg->conn); 857 /* API_EVENT is called inside do_close_internal, before releasing 858 the application thread, so we can return at this point! */ 859 return; 860 #endif /* LWIP_TCP */ 861 default: 862 break; 863 } 864 msg->conn->pcb.tcp = NULL; 865 } 866 /* tcp netconns don't come here! */ 867 868 /* @todo: this lets select make the socket readable and writable, 869 which is wrong! errfd instead? */ 870 API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); 871 API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); 872 } 873 if (sys_sem_valid(&msg->conn->op_completed)) { 874 sys_sem_signal(&msg->conn->op_completed); 875 } 876 } 877 878 /** 879 * Bind a pcb contained in a netconn 880 * Called from netconn_bind. 881 * 882 * @param msg the api_msg_msg pointing to the connection and containing 883 * the IP address and port to bind to 884 */ 885 void 886 do_bind(struct api_msg_msg *msg) 887 { 888 if (ERR_IS_FATAL(msg->conn->last_err)) { 889 msg->err = msg->conn->last_err; 890 } else { 891 msg->err = ERR_VAL; 892 if (msg->conn->pcb.tcp != NULL) { 893 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 894 #if LWIP_RAW 895 case NETCONN_RAW: 896 msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr); 897 break; 898 #endif /* LWIP_RAW */ 899 #if LWIP_UDP 900 case NETCONN_UDP: 901 msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); 902 break; 903 #endif /* LWIP_UDP */ 904 #if LWIP_TCP 905 case NETCONN_TCP: 906 msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port); 907 break; 908 #endif /* LWIP_TCP */ 909 default: 910 break; 911 } 912 } 913 } 914 TCPIP_APIMSG_ACK(msg); 915 } 916 917 #if LWIP_TCP 918 /** 919 * TCP callback function if a connection (opened by tcp_connect/do_connect) has 920 * been established (or reset by the remote host). 921 * 922 * @see tcp.h (struct tcp_pcb.connected) for parameters and return values 923 */ 924 static err_t 925 do_connected(void *arg, struct tcp_pcb *pcb, err_t err) 926 { 927 struct netconn *conn; 928 int was_blocking; 929 930 LWIP_UNUSED_ARG(pcb); 931 932 conn = (struct netconn *)arg; 933 934 if (conn == NULL) { 935 return ERR_VAL; 936 } 937 938 LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); 939 LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", 940 (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); 941 942 if (conn->current_msg != NULL) { 943 conn->current_msg->err = err; 944 } 945 if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) { 946 setup_tcp(conn); 947 } 948 was_blocking = !IN_NONBLOCKING_CONNECT(conn); 949 SET_NONBLOCKING_CONNECT(conn, 0); 950 conn->current_msg = NULL; 951 conn->state = NETCONN_NONE; 952 if (!was_blocking) { 953 NETCONN_SET_SAFE_ERR(conn, ERR_OK); 954 } 955 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 956 957 if (was_blocking) { 958 sys_sem_signal(&conn->op_completed); 959 } 960 return ERR_OK; 961 } 962 #endif /* LWIP_TCP */ 963 964 /** 965 * Connect a pcb contained inside a netconn 966 * Called from netconn_connect. 967 * 968 * @param msg the api_msg_msg pointing to the connection and containing 969 * the IP address and port to connect to 970 */ 971 void 972 do_connect(struct api_msg_msg *msg) 973 { 974 if (msg->conn->pcb.tcp == NULL) { 975 /* This may happen when calling netconn_connect() a second time */ 976 msg->err = ERR_CLSD; 977 } else { 978 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 979 #if LWIP_RAW 980 case NETCONN_RAW: 981 msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); 982 break; 983 #endif /* LWIP_RAW */ 984 #if LWIP_UDP 985 case NETCONN_UDP: 986 msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); 987 break; 988 #endif /* LWIP_UDP */ 989 #if LWIP_TCP 990 case NETCONN_TCP: 991 /* Prevent connect while doing any other action. */ 992 if (msg->conn->state != NETCONN_NONE) { 993 msg->err = ERR_ISCONN; 994 } else { 995 setup_tcp(msg->conn); 996 msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, 997 msg->msg.bc.port, do_connected); 998 if (msg->err == ERR_OK) { 999 u8_t non_blocking = netconn_is_nonblocking(msg->conn); 1000 msg->conn->state = NETCONN_CONNECT; 1001 SET_NONBLOCKING_CONNECT(msg->conn, non_blocking); 1002 if (non_blocking) { 1003 msg->err = ERR_INPROGRESS; 1004 } else { 1005 msg->conn->current_msg = msg; 1006 /* sys_sem_signal() is called from do_connected (or err_tcp()), 1007 * when the connection is established! */ 1008 return; 1009 } 1010 } 1011 } 1012 break; 1013 #endif /* LWIP_TCP */ 1014 default: 1015 LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0)); 1016 break; 1017 } 1018 } 1019 sys_sem_signal(&msg->conn->op_completed); 1020 } 1021 1022 /** 1023 * Connect a pcb contained inside a netconn 1024 * Only used for UDP netconns. 1025 * Called from netconn_disconnect. 1026 * 1027 * @param msg the api_msg_msg pointing to the connection to disconnect 1028 */ 1029 void 1030 do_disconnect(struct api_msg_msg *msg) 1031 { 1032 #if LWIP_UDP 1033 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 1034 udp_disconnect(msg->conn->pcb.udp); 1035 msg->err = ERR_OK; 1036 } else 1037 #endif /* LWIP_UDP */ 1038 { 1039 msg->err = ERR_VAL; 1040 } 1041 TCPIP_APIMSG_ACK(msg); 1042 } 1043 1044 #if LWIP_TCP 1045 /** 1046 * Set a TCP pcb contained in a netconn into listen mode 1047 * Called from netconn_listen. 1048 * 1049 * @param msg the api_msg_msg pointing to the connection 1050 */ 1051 void 1052 do_listen(struct api_msg_msg *msg) 1053 { 1054 if (ERR_IS_FATAL(msg->conn->last_err)) { 1055 msg->err = msg->conn->last_err; 1056 } else { 1057 msg->err = ERR_CONN; 1058 if (msg->conn->pcb.tcp != NULL) { 1059 if (msg->conn->type == NETCONN_TCP) { 1060 if (msg->conn->state == NETCONN_NONE) { 1061 #if TCP_LISTEN_BACKLOG 1062 struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); 1063 #else /* TCP_LISTEN_BACKLOG */ 1064 struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp); 1065 #endif /* TCP_LISTEN_BACKLOG */ 1066 if (lpcb == NULL) { 1067 /* in this case, the old pcb is still allocated */ 1068 msg->err = ERR_MEM; 1069 } else { 1070 /* delete the recvmbox and allocate the acceptmbox */ 1071 if (sys_mbox_valid(&msg->conn->recvmbox)) { 1072 /** @todo: should we drain the recvmbox here? */ 1073 sys_mbox_free(&msg->conn->recvmbox); 1074 sys_mbox_set_invalid(&msg->conn->recvmbox); 1075 } 1076 msg->err = ERR_OK; 1077 if (!sys_mbox_valid(&msg->conn->acceptmbox)) { 1078 msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); 1079 } 1080 if (msg->err == ERR_OK) { 1081 msg->conn->state = NETCONN_LISTEN; 1082 msg->conn->pcb.tcp = lpcb; 1083 tcp_arg(msg->conn->pcb.tcp, msg->conn); 1084 tcp_accept(msg->conn->pcb.tcp, accept_function); 1085 } else { 1086 /* since the old pcb is already deallocated, free lpcb now */ 1087 tcp_close(lpcb); 1088 msg->conn->pcb.tcp = NULL; 1089 } 1090 } 1091 } 1092 } 1093 } 1094 } 1095 TCPIP_APIMSG_ACK(msg); 1096 } 1097 #endif /* LWIP_TCP */ 1098 1099 /** 1100 * Send some data on a RAW or UDP pcb contained in a netconn 1101 * Called from netconn_send 1102 * 1103 * @param msg the api_msg_msg pointing to the connection 1104 */ 1105 void 1106 do_send(struct api_msg_msg *msg) 1107 { 1108 if (ERR_IS_FATAL(msg->conn->last_err)) { 1109 msg->err = msg->conn->last_err; 1110 } else { 1111 msg->err = ERR_CONN; 1112 if (msg->conn->pcb.tcp != NULL) { 1113 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1114 #if LWIP_RAW 1115 case NETCONN_RAW: 1116 if (ip_addr_isany(&msg->msg.b->addr)) { 1117 msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); 1118 } else { 1119 msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); 1120 } 1121 break; 1122 #endif 1123 #if LWIP_UDP 1124 case NETCONN_UDP: 1125 #if LWIP_CHECKSUM_ON_COPY 1126 if (ip_addr_isany(&msg->msg.b->addr)) { 1127 msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, 1128 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); 1129 } else { 1130 msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, 1131 &msg->msg.b->addr, msg->msg.b->port, 1132 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); 1133 } 1134 #else /* LWIP_CHECKSUM_ON_COPY */ 1135 if (ip_addr_isany(&msg->msg.b->addr)) { 1136 msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); 1137 } else { 1138 msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port); 1139 } 1140 #endif /* LWIP_CHECKSUM_ON_COPY */ 1141 break; 1142 #endif /* LWIP_UDP */ 1143 default: 1144 break; 1145 } 1146 } 1147 } 1148 TCPIP_APIMSG_ACK(msg); 1149 } 1150 1151 #if LWIP_TCP 1152 /** 1153 * Indicate data has been received from a TCP pcb contained in a netconn 1154 * Called from netconn_recv 1155 * 1156 * @param msg the api_msg_msg pointing to the connection 1157 */ 1158 void 1159 do_recv(struct api_msg_msg *msg) 1160 { 1161 msg->err = ERR_OK; 1162 if (msg->conn->pcb.tcp != NULL) { 1163 if (msg->conn->type == NETCONN_TCP) { 1164 #if TCP_LISTEN_BACKLOG 1165 if (msg->conn->pcb.tcp->state == LISTEN) { 1166 tcp_accepted(msg->conn->pcb.tcp); 1167 } else 1168 #endif /* TCP_LISTEN_BACKLOG */ 1169 { 1170 u32_t remaining = msg->msg.r.len; 1171 do { 1172 u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining; 1173 tcp_recved(msg->conn->pcb.tcp, recved); 1174 remaining -= recved; 1175 }while(remaining != 0); 1176 } 1177 } 1178 } 1179 TCPIP_APIMSG_ACK(msg); 1180 } 1181 1182 /** 1183 * See if more data needs to be written from a previous call to netconn_write. 1184 * Called initially from do_write. If the first call can't send all data 1185 * (because of low memory or empty send-buffer), this function is called again 1186 * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the 1187 * blocking application thread (waiting in netconn_write) is released. 1188 * 1189 * @param conn netconn (that is currently in state NETCONN_WRITE) to process 1190 * @return ERR_OK 1191 * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished 1192 */ 1193 static err_t 1194 do_writemore(struct netconn *conn) 1195 { 1196 err_t err = ERR_OK; 1197 void *dataptr; 1198 u16_t len, available; 1199 u8_t write_finished = 0; 1200 size_t diff; 1201 u8_t dontblock = netconn_is_nonblocking(conn) || 1202 (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK); 1203 u8_t apiflags = conn->current_msg->msg.w.apiflags; 1204 1205 LWIP_ASSERT("conn != NULL", conn != NULL); 1206 LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); 1207 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 1208 LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); 1209 LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len", 1210 conn->write_offset < conn->current_msg->msg.w.len); 1211 1212 dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset; 1213 diff = conn->current_msg->msg.w.len - conn->write_offset; 1214 if (diff > 0xffffUL) { /* max_u16_t */ 1215 len = 0xffff; 1216 #if LWIP_TCPIP_CORE_LOCKING 1217 conn->flags |= NETCONN_FLAG_WRITE_DELAYED; 1218 #endif 1219 apiflags |= TCP_WRITE_FLAG_MORE; 1220 } else { 1221 len = (u16_t)diff; 1222 } 1223 available = tcp_sndbuf(conn->pcb.tcp); 1224 if (available < len) { 1225 /* don't try to write more than sendbuf */ 1226 len = available; 1227 #if LWIP_TCPIP_CORE_LOCKING 1228 conn->flags |= NETCONN_FLAG_WRITE_DELAYED; 1229 #endif 1230 apiflags |= TCP_WRITE_FLAG_MORE; 1231 } 1232 if (dontblock && (len < conn->current_msg->msg.w.len)) { 1233 /* failed to send all data at once -> nonblocking write not possible */ 1234 err = ERR_MEM; 1235 } 1236 if (err == ERR_OK) { 1237 LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); 1238 err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); 1239 } 1240 if (dontblock && (err == ERR_MEM)) { 1241 /* nonblocking write failed */ 1242 write_finished = 1; 1243 err = ERR_WOULDBLOCK; 1244 /* let poll_tcp check writable space to mark the pcb 1245 writable again */ 1246 conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; 1247 /* let select mark this pcb as non-writable. */ 1248 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); 1249 } else { 1250 /* if OK or memory error, check available space */ 1251 if (((err == ERR_OK) || (err == ERR_MEM)) && 1252 ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || 1253 (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT))) { 1254 /* The queued byte- or pbuf-count exceeds the configured low-water limit, 1255 let select mark this pcb as non-writable. */ 1256 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); 1257 } 1258 1259 if (err == ERR_OK) { 1260 conn->write_offset += len; 1261 if (conn->write_offset == conn->current_msg->msg.w.len) { 1262 /* everything was written */ 1263 write_finished = 1; 1264 conn->write_offset = 0; 1265 } 1266 tcp_output(conn->pcb.tcp); 1267 } else if (err == ERR_MEM) { 1268 /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called 1269 we do NOT return to the application thread, since ERR_MEM is 1270 only a temporary error! */ 1271 1272 /* tcp_write returned ERR_MEM, try tcp_output anyway */ 1273 tcp_output(conn->pcb.tcp); 1274 1275 #if LWIP_TCPIP_CORE_LOCKING 1276 conn->flags |= NETCONN_FLAG_WRITE_DELAYED; 1277 #endif 1278 } else { 1279 /* On errors != ERR_MEM, we don't try writing any more but return 1280 the error to the application thread. */ 1281 write_finished = 1; 1282 } 1283 } 1284 1285 if (write_finished) { 1286 /* everything was written: set back connection state 1287 and back to application task */ 1288 conn->current_msg->err = err; 1289 conn->current_msg = NULL; 1290 conn->state = NETCONN_NONE; 1291 #if LWIP_TCPIP_CORE_LOCKING 1292 if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0) 1293 #endif 1294 { 1295 sys_sem_signal(&conn->op_completed); 1296 } 1297 } 1298 #if LWIP_TCPIP_CORE_LOCKING 1299 else 1300 return ERR_MEM; 1301 #endif 1302 return ERR_OK; 1303 } 1304 #endif /* LWIP_TCP */ 1305 1306 /** 1307 * Send some data on a TCP pcb contained in a netconn 1308 * Called from netconn_write 1309 * 1310 * @param msg the api_msg_msg pointing to the connection 1311 */ 1312 void 1313 do_write(struct api_msg_msg *msg) 1314 { 1315 if (ERR_IS_FATAL(msg->conn->last_err)) { 1316 msg->err = msg->conn->last_err; 1317 } else { 1318 if (msg->conn->type == NETCONN_TCP) { 1319 #if LWIP_TCP 1320 if (msg->conn->state != NETCONN_NONE) { 1321 /* netconn is connecting, closing or in blocking write */ 1322 msg->err = ERR_INPROGRESS; 1323 } else if (msg->conn->pcb.tcp != NULL) { 1324 msg->conn->state = NETCONN_WRITE; 1325 /* set all the variables used by do_writemore */ 1326 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && 1327 msg->conn->write_offset == 0); 1328 LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0); 1329 msg->conn->current_msg = msg; 1330 msg->conn->write_offset = 0; 1331 #if LWIP_TCPIP_CORE_LOCKING 1332 msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED; 1333 if (do_writemore(msg->conn) != ERR_OK) { 1334 LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); 1335 UNLOCK_TCPIP_CORE(); 1336 sys_arch_sem_wait(&msg->conn->op_completed, 0); 1337 LOCK_TCPIP_CORE(); 1338 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); 1339 } 1340 #else /* LWIP_TCPIP_CORE_LOCKING */ 1341 do_writemore(msg->conn); 1342 #endif /* LWIP_TCPIP_CORE_LOCKING */ 1343 /* for both cases: if do_writemore was called, don't ACK the APIMSG 1344 since do_writemore ACKs it! */ 1345 return; 1346 } else { 1347 msg->err = ERR_CONN; 1348 } 1349 #else /* LWIP_TCP */ 1350 msg->err = ERR_VAL; 1351 #endif /* LWIP_TCP */ 1352 #if (LWIP_UDP || LWIP_RAW) 1353 } else { 1354 msg->err = ERR_VAL; 1355 #endif /* (LWIP_UDP || LWIP_RAW) */ 1356 } 1357 } 1358 TCPIP_APIMSG_ACK(msg); 1359 } 1360 1361 /** 1362 * Return a connection's local or remote address 1363 * Called from netconn_getaddr 1364 * 1365 * @param msg the api_msg_msg pointing to the connection 1366 */ 1367 void 1368 do_getaddr(struct api_msg_msg *msg) 1369 { 1370 if (msg->conn->pcb.ip != NULL) { 1371 *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip : 1372 msg->conn->pcb.ip->remote_ip); 1373 1374 msg->err = ERR_OK; 1375 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1376 #if LWIP_RAW 1377 case NETCONN_RAW: 1378 if (msg->msg.ad.local) { 1379 *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; 1380 } else { 1381 /* return an error as connecting is only a helper for upper layers */ 1382 msg->err = ERR_CONN; 1383 } 1384 break; 1385 #endif /* LWIP_RAW */ 1386 #if LWIP_UDP 1387 case NETCONN_UDP: 1388 if (msg->msg.ad.local) { 1389 *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; 1390 } else { 1391 if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { 1392 msg->err = ERR_CONN; 1393 } else { 1394 *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; 1395 } 1396 } 1397 break; 1398 #endif /* LWIP_UDP */ 1399 #if LWIP_TCP 1400 case NETCONN_TCP: 1401 *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port); 1402 break; 1403 #endif /* LWIP_TCP */ 1404 default: 1405 LWIP_ASSERT("invalid netconn_type", 0); 1406 break; 1407 } 1408 } else { 1409 msg->err = ERR_CONN; 1410 } 1411 TCPIP_APIMSG_ACK(msg); 1412 } 1413 1414 /** 1415 * Close a TCP pcb contained in a netconn 1416 * Called from netconn_close 1417 * 1418 * @param msg the api_msg_msg pointing to the connection 1419 */ 1420 void 1421 do_close(struct api_msg_msg *msg) 1422 { 1423 #if LWIP_TCP 1424 /* @todo: abort running write/connect? */ 1425 if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) { 1426 /* this only happens for TCP netconns */ 1427 LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); 1428 msg->err = ERR_INPROGRESS; 1429 } else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { 1430 if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) { 1431 /* LISTEN doesn't support half shutdown */ 1432 msg->err = ERR_CONN; 1433 } else { 1434 if (msg->msg.sd.shut & NETCONN_SHUT_RD) { 1435 /* Drain and delete mboxes */ 1436 netconn_drain(msg->conn); 1437 } 1438 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && 1439 msg->conn->write_offset == 0); 1440 msg->conn->state = NETCONN_CLOSE; 1441 msg->conn->current_msg = msg; 1442 do_close_internal(msg->conn); 1443 /* for tcp netconns, do_close_internal ACKs the message */ 1444 return; 1445 } 1446 } else 1447 #endif /* LWIP_TCP */ 1448 { 1449 msg->err = ERR_VAL; 1450 } 1451 sys_sem_signal(&msg->conn->op_completed); 1452 } 1453 1454 #if LWIP_IGMP 1455 /** 1456 * Join multicast groups for UDP netconns. 1457 * Called from netconn_join_leave_group 1458 * 1459 * @param msg the api_msg_msg pointing to the connection 1460 */ 1461 void 1462 do_join_leave_group(struct api_msg_msg *msg) 1463 { 1464 if (ERR_IS_FATAL(msg->conn->last_err)) { 1465 msg->err = msg->conn->last_err; 1466 } else { 1467 if (msg->conn->pcb.tcp != NULL) { 1468 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 1469 #if LWIP_UDP 1470 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 1471 msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); 1472 } else { 1473 msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); 1474 } 1475 #endif /* LWIP_UDP */ 1476 #if (LWIP_TCP || LWIP_RAW) 1477 } else { 1478 msg->err = ERR_VAL; 1479 #endif /* (LWIP_TCP || LWIP_RAW) */ 1480 } 1481 } else { 1482 msg->err = ERR_CONN; 1483 } 1484 } 1485 TCPIP_APIMSG_ACK(msg); 1486 } 1487 #endif /* LWIP_IGMP */ 1488 1489 #if LWIP_DNS 1490 /** 1491 * Callback function that is called when DNS name is resolved 1492 * (or on timeout). A waiting application thread is waked up by 1493 * signaling the semaphore. 1494 */ 1495 static void 1496 do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) 1497 { 1498 struct dns_api_msg *msg = (struct dns_api_msg*)arg; 1499 1500 LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0); 1501 LWIP_UNUSED_ARG(name); 1502 1503 if (ipaddr == NULL) { 1504 /* timeout or memory error */ 1505 *msg->err = ERR_VAL; 1506 } else { 1507 /* address was resolved */ 1508 *msg->err = ERR_OK; 1509 *msg->addr = *ipaddr; 1510 } 1511 /* wake up the application task waiting in netconn_gethostbyname */ 1512 sys_sem_signal(msg->sem); 1513 } 1514 1515 /** 1516 * Execute a DNS query 1517 * Called from netconn_gethostbyname 1518 * 1519 * @param arg the dns_api_msg pointing to the query 1520 */ 1521 void 1522 do_gethostbyname(void *arg) 1523 { 1524 struct dns_api_msg *msg = (struct dns_api_msg*)arg; 1525 1526 *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg); 1527 if (*msg->err != ERR_INPROGRESS) { 1528 /* on error or immediate success, wake up the application 1529 * task waiting in netconn_gethostbyname */ 1530 sys_sem_signal(msg->sem); 1531 } 1532 } 1533 #endif /* LWIP_DNS */ 1534 1535 #endif /* LWIP_NETCONN */ 1536