Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of lwip by
api_msg.c
00001 /** 00002 * @file 00003 * Sequential API Internal module 00004 * 00005 */ 00006 00007 /* 00008 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 00009 * All rights reserved. 00010 * 00011 * Redistribution and use in source and binary forms, with or without modification, 00012 * are permitted provided that the following conditions are met: 00013 * 00014 * 1. Redistributions of source code must retain the above copyright notice, 00015 * this list of conditions and the following disclaimer. 00016 * 2. Redistributions in binary form must reproduce the above copyright notice, 00017 * this list of conditions and the following disclaimer in the documentation 00018 * and/or other materials provided with the distribution. 00019 * 3. The name of the author may not be used to endorse or promote products 00020 * derived from this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00023 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00025 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00026 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00027 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00028 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00029 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00030 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00031 * OF SUCH DAMAGE. 00032 * 00033 * This file is part of the lwIP TCP/IP stack. 00034 * 00035 * Author: Adam Dunkels <adam@sics.se> 00036 * 00037 */ 00038 00039 #include "lwip/opt.h" 00040 00041 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ 00042 00043 #include "lwip/api_msg.h" 00044 00045 #include "lwip/ip.h" 00046 #include "lwip/udp.h" 00047 #include "lwip/tcp.h" 00048 #include "lwip/raw.h" 00049 00050 #include "lwip/memp.h" 00051 #include "lwip/tcpip.h" 00052 #include "lwip/igmp.h" 00053 #include "lwip/dns.h" 00054 00055 #include <string.h> 00056 00057 #define SET_NONBLOCKING_CONNECT(conn, val) do { if(val) { \ 00058 (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \ 00059 } else { \ 00060 (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0) 00061 #define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0) 00062 00063 /* forward declarations */ 00064 #if LWIP_TCP 00065 static err_t do_writemore(struct netconn *conn); 00066 static void do_close_internal(struct netconn *conn); 00067 #endif 00068 00069 #if LWIP_RAW 00070 /** 00071 * Receive callback function for RAW netconns. 00072 * Doesn't 'eat' the packet, only references it and sends it to 00073 * conn->recvmbox 00074 * 00075 * @see raw.h (struct raw_pcb.recv) for parameters and return value 00076 */ 00077 static u8_t 00078 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, 00079 ip_addr_t *addr) 00080 { 00081 struct pbuf *q; 00082 struct netbuf *buf; 00083 struct netconn *conn; 00084 00085 LWIP_UNUSED_ARG(addr); 00086 conn = (struct netconn *)arg; 00087 00088 if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) { 00089 #if LWIP_SO_RCVBUF 00090 int recv_avail; 00091 SYS_ARCH_GET(conn->recv_avail, recv_avail); 00092 if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) { 00093 return 0; 00094 } 00095 #endif /* LWIP_SO_RCVBUF */ 00096 /* copy the whole packet into new pbufs */ 00097 q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); 00098 if(q != NULL) { 00099 if (pbuf_copy(q, p) != ERR_OK) { 00100 pbuf_free(q); 00101 q = NULL; 00102 } 00103 } 00104 00105 if (q != NULL) { 00106 u16_t len; 00107 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 00108 if (buf == NULL) { 00109 pbuf_free(q); 00110 return 0; 00111 } 00112 00113 buf->p = q; 00114 buf->ptr = q; 00115 ip_addr_copy(buf->addr, *ip_current_src_addr()); 00116 buf->port = pcb->protocol; 00117 00118 len = q->tot_len; 00119 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { 00120 netbuf_delete(buf); 00121 return 0; 00122 } else { 00123 #if LWIP_SO_RCVBUF 00124 SYS_ARCH_INC(conn->recv_avail, len); 00125 #endif /* LWIP_SO_RCVBUF */ 00126 /* Register event with callback */ 00127 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 00128 } 00129 } 00130 } 00131 00132 return 0; /* do not eat the packet */ 00133 } 00134 #endif /* LWIP_RAW*/ 00135 00136 #if LWIP_UDP 00137 /** 00138 * Receive callback function for UDP netconns. 00139 * Posts the packet to conn->recvmbox or deletes it on memory error. 00140 * 00141 * @see udp.h (struct udp_pcb.recv) for parameters 00142 */ 00143 static void 00144 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, 00145 ip_addr_t *addr, u16_t port) 00146 { 00147 struct netbuf *buf; 00148 struct netconn *conn; 00149 u16_t len; 00150 #if LWIP_SO_RCVBUF 00151 int recv_avail; 00152 #endif /* LWIP_SO_RCVBUF */ 00153 00154 LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ 00155 LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); 00156 LWIP_ASSERT("recv_udp must have an argument", arg != NULL); 00157 conn = (struct netconn *)arg; 00158 LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); 00159 00160 #if LWIP_SO_RCVBUF 00161 SYS_ARCH_GET(conn->recv_avail, recv_avail); 00162 if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) || 00163 ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { 00164 #else /* LWIP_SO_RCVBUF */ 00165 if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) { 00166 #endif /* LWIP_SO_RCVBUF */ 00167 pbuf_free(p); 00168 return; 00169 } 00170 00171 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 00172 if (buf == NULL) { 00173 pbuf_free(p); 00174 return; 00175 } else { 00176 buf->p = p; 00177 buf->ptr = p; 00178 ip_addr_set(&buf->addr, addr); 00179 buf->port = port; 00180 #if LWIP_NETBUF_RECVINFO 00181 { 00182 const struct ip_hdr* iphdr = ip_current_header(); 00183 /* get the UDP header - always in the first pbuf, ensured by udp_input */ 00184 const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr)); 00185 #if LWIP_CHECKSUM_ON_COPY 00186 buf->flags = NETBUF_FLAG_DESTADDR; 00187 #endif /* LWIP_CHECKSUM_ON_COPY */ 00188 ip_addr_set(&buf->toaddr, ip_current_dest_addr()); 00189 buf->toport_chksum = udphdr->dest; 00190 } 00191 #endif /* LWIP_NETBUF_RECVINFO */ 00192 } 00193 00194 len = p->tot_len; 00195 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { 00196 netbuf_delete(buf); 00197 return; 00198 } else { 00199 #if LWIP_SO_RCVBUF 00200 SYS_ARCH_INC(conn->recv_avail, len); 00201 #endif /* LWIP_SO_RCVBUF */ 00202 /* Register event with callback */ 00203 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 00204 } 00205 } 00206 #endif /* LWIP_UDP */ 00207 00208 #if LWIP_TCP 00209 /** 00210 * Receive callback function for TCP netconns. 00211 * Posts the packet to conn->recvmbox, but doesn't delete it on errors. 00212 * 00213 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value 00214 */ 00215 static err_t 00216 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) 00217 { 00218 struct netconn *conn; 00219 u16_t len; 00220 00221 LWIP_UNUSED_ARG(pcb); 00222 LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); 00223 LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); 00224 conn = (struct netconn *)arg; 00225 LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); 00226 00227 if (conn == NULL) { 00228 return ERR_VAL; 00229 } 00230 if (!sys_mbox_valid(&conn->recvmbox)) { 00231 /* recvmbox already deleted */ 00232 if (p != NULL) { 00233 tcp_recved(pcb, p->tot_len); 00234 pbuf_free(p); 00235 } 00236 return ERR_OK; 00237 } 00238 /* Unlike for UDP or RAW pcbs, don't check for available space 00239 using recv_avail since that could break the connection 00240 (data is already ACKed) */ 00241 00242 /* don't overwrite fatal errors! */ 00243 NETCONN_SET_SAFE_ERR(conn, err); 00244 00245 if (p != NULL) { 00246 len = p->tot_len; 00247 } else { 00248 len = 0; 00249 } 00250 00251 if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) { 00252 /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */ 00253 return ERR_MEM; 00254 } else { 00255 #if LWIP_SO_RCVBUF 00256 SYS_ARCH_INC(conn->recv_avail, len); 00257 #endif /* LWIP_SO_RCVBUF */ 00258 /* Register event with callback */ 00259 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 00260 } 00261 00262 return ERR_OK; 00263 } 00264 00265 /** 00266 * Poll callback function for TCP netconns. 00267 * Wakes up an application thread that waits for a connection to close 00268 * or data to be sent. The application thread then takes the 00269 * appropriate action to go on. 00270 * 00271 * Signals the conn->sem. 00272 * netconn_close waits for conn->sem if closing failed. 00273 * 00274 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value 00275 */ 00276 static err_t 00277 poll_tcp(void *arg, struct tcp_pcb *pcb) 00278 { 00279 struct netconn *conn = (struct netconn *)arg; 00280 00281 LWIP_UNUSED_ARG(pcb); 00282 LWIP_ASSERT("conn != NULL", (conn != NULL)); 00283 00284 if (conn->state == NETCONN_WRITE) { 00285 do_writemore(conn); 00286 } else if (conn->state == NETCONN_CLOSE) { 00287 do_close_internal(conn); 00288 } 00289 /* @todo: implement connect timeout here? */ 00290 00291 /* Did a nonblocking write fail before? Then check available write-space. */ 00292 if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) { 00293 /* If the queued byte- or pbuf-count drops below the configured low-water limit, 00294 let select mark this pcb as writable again. */ 00295 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && 00296 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { 00297 conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; 00298 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 00299 } 00300 } 00301 00302 return ERR_OK; 00303 } 00304 00305 /** 00306 * Sent callback function for TCP netconns. 00307 * Signals the conn->sem and calls API_EVENT. 00308 * netconn_write waits for conn->sem if send buffer is low. 00309 * 00310 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value 00311 */ 00312 static err_t 00313 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) 00314 { 00315 struct netconn *conn = (struct netconn *)arg; 00316 00317 LWIP_UNUSED_ARG(pcb); 00318 LWIP_ASSERT("conn != NULL", (conn != NULL)); 00319 00320 if (conn->state == NETCONN_WRITE) { 00321 do_writemore(conn); 00322 } else if (conn->state == NETCONN_CLOSE) { 00323 do_close_internal(conn); 00324 } 00325 00326 if (conn) { 00327 /* If the queued byte- or pbuf-count drops below the configured low-water limit, 00328 let select mark this pcb as writable again. */ 00329 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && 00330 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { 00331 conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; 00332 API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); 00333 } 00334 } 00335 00336 return ERR_OK; 00337 } 00338 00339 /** 00340 * Error callback function for TCP netconns. 00341 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. 00342 * The application thread has then to decide what to do. 00343 * 00344 * @see tcp.h (struct tcp_pcb.err) for parameters 00345 */ 00346 static void 00347 err_tcp(void *arg, err_t err) 00348 { 00349 struct netconn *conn; 00350 enum netconn_state old_state; 00351 SYS_ARCH_DECL_PROTECT(lev); 00352 00353 conn = (struct netconn *)arg; 00354 LWIP_ASSERT("conn != NULL", (conn != NULL)); 00355 00356 conn->pcb.tcp = NULL; 00357 00358 /* no check since this is always fatal! */ 00359 SYS_ARCH_PROTECT(lev); 00360 conn->last_err = err; 00361 SYS_ARCH_UNPROTECT(lev); 00362 00363 /* reset conn->state now before waking up other threads */ 00364 old_state = conn->state; 00365 conn->state = NETCONN_NONE; 00366 00367 /* Notify the user layer about a connection error. Used to signal 00368 select. */ 00369 API_EVENT(conn, NETCONN_EVT_ERROR, 0); 00370 /* Try to release selects pending on 'read' or 'write', too. 00371 They will get an error if they actually try to read or write. */ 00372 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 00373 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 00374 00375 /* pass NULL-message to recvmbox to wake up pending recv */ 00376 if (sys_mbox_valid(&conn->recvmbox)) { 00377 /* use trypost to prevent deadlock */ 00378 sys_mbox_trypost(&conn->recvmbox, NULL); 00379 } 00380 /* pass NULL-message to acceptmbox to wake up pending accept */ 00381 if (sys_mbox_valid(&conn->acceptmbox)) { 00382 /* use trypost to preven deadlock */ 00383 sys_mbox_trypost(&conn->acceptmbox, NULL); 00384 } 00385 00386 if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || 00387 (old_state == NETCONN_CONNECT)) { 00388 /* calling do_writemore/do_close_internal is not necessary 00389 since the pcb has already been deleted! */ 00390 int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn); 00391 SET_NONBLOCKING_CONNECT(conn, 0); 00392 00393 if (!was_nonblocking_connect) { 00394 /* set error return code */ 00395 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 00396 conn->current_msg->err = err; 00397 conn->current_msg = NULL; 00398 /* wake up the waiting task */ 00399 sys_sem_signal(&conn->op_completed); 00400 } 00401 } else { 00402 LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL); 00403 } 00404 } 00405 00406 /** 00407 * Setup a tcp_pcb with the correct callback function pointers 00408 * and their arguments. 00409 * 00410 * @param conn the TCP netconn to setup 00411 */ 00412 static void 00413 setup_tcp(struct netconn *conn) 00414 { 00415 struct tcp_pcb *pcb; 00416 00417 pcb = conn->pcb.tcp; 00418 tcp_arg(pcb, conn); 00419 tcp_recv(pcb, recv_tcp); 00420 tcp_sent(pcb, sent_tcp); 00421 tcp_poll(pcb, poll_tcp, 4); 00422 tcp_err(pcb, err_tcp); 00423 } 00424 00425 /** 00426 * Accept callback function for TCP netconns. 00427 * Allocates a new netconn and posts that to conn->acceptmbox. 00428 * 00429 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value 00430 */ 00431 static err_t 00432 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) 00433 { 00434 struct netconn *newconn; 00435 struct netconn *conn = (struct netconn *)arg; 00436 00437 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state))); 00438 00439 if (!sys_mbox_valid(&conn->acceptmbox)) { 00440 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n")); 00441 return ERR_VAL; 00442 } 00443 00444 /* We have to set the callback here even though 00445 * the new socket is unknown. conn->socket is marked as -1. */ 00446 newconn = netconn_alloc(conn->type, conn->callback); 00447 if (newconn == NULL) { 00448 return ERR_MEM; 00449 } 00450 newconn->pcb.tcp = newpcb; 00451 setup_tcp(newconn); 00452 /* no protection: when creating the pcb, the netconn is not yet known 00453 to the application thread */ 00454 newconn->last_err = err; 00455 00456 if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) { 00457 /* When returning != ERR_OK, the pcb is aborted in tcp_process(), 00458 so do nothing here! */ 00459 newconn->pcb.tcp = NULL; 00460 /* no need to drain since we know the recvmbox is empty. */ 00461 sys_mbox_free(&newconn->recvmbox); 00462 sys_mbox_set_invalid(&newconn->recvmbox); 00463 netconn_free(newconn); 00464 return ERR_MEM; 00465 } else { 00466 /* Register event with callback */ 00467 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 00468 } 00469 00470 return ERR_OK; 00471 } 00472 #endif /* LWIP_TCP */ 00473 00474 /** 00475 * Create a new pcb of a specific type. 00476 * Called from do_newconn(). 00477 * 00478 * @param msg the api_msg_msg describing the connection type 00479 * @return msg->conn->err, but the return value is currently ignored 00480 */ 00481 static void 00482 pcb_new(struct api_msg_msg *msg) 00483 { 00484 LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); 00485 00486 /* Allocate a PCB for this connection */ 00487 switch(NETCONNTYPE_GROUP(msg->conn->type)) { 00488 #if LWIP_RAW 00489 case NETCONN_RAW: 00490 msg->conn->pcb.raw = raw_new(msg->msg.n.proto); 00491 if(msg->conn->pcb.raw == NULL) { 00492 msg->err = ERR_MEM; 00493 break; 00494 } 00495 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); 00496 break; 00497 #endif /* LWIP_RAW */ 00498 #if LWIP_UDP 00499 case NETCONN_UDP: 00500 msg->conn->pcb.udp = udp_new(); 00501 if(msg->conn->pcb.udp == NULL) { 00502 msg->err = ERR_MEM; 00503 break; 00504 } 00505 #if LWIP_UDPLITE 00506 if (msg->conn->type==NETCONN_UDPLITE) { 00507 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); 00508 } 00509 #endif /* LWIP_UDPLITE */ 00510 if (msg->conn->type==NETCONN_UDPNOCHKSUM) { 00511 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); 00512 } 00513 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); 00514 break; 00515 #endif /* LWIP_UDP */ 00516 #if LWIP_TCP 00517 case NETCONN_TCP: 00518 msg->conn->pcb.tcp = tcp_new(); 00519 if(msg->conn->pcb.tcp == NULL) { 00520 msg->err = ERR_MEM; 00521 break; 00522 } 00523 setup_tcp(msg->conn); 00524 break; 00525 #endif /* LWIP_TCP */ 00526 default: 00527 /* Unsupported netconn type, e.g. protocol disabled */ 00528 msg->err = ERR_VAL; 00529 break; 00530 } 00531 } 00532 00533 /** 00534 * Create a new pcb of a specific type inside a netconn. 00535 * Called from netconn_new_with_proto_and_callback. 00536 * 00537 * @param msg the api_msg_msg describing the connection type 00538 */ 00539 void 00540 do_newconn(struct api_msg_msg *msg) 00541 { 00542 msg->err = ERR_OK; 00543 if(msg->conn->pcb.tcp == NULL) { 00544 pcb_new(msg); 00545 } 00546 /* Else? This "new" connection already has a PCB allocated. */ 00547 /* Is this an error condition? Should it be deleted? */ 00548 /* We currently just are happy and return. */ 00549 00550 TCPIP_APIMSG_ACK(msg); 00551 } 00552 00553 /** 00554 * Create a new netconn (of a specific type) that has a callback function. 00555 * The corresponding pcb is NOT created! 00556 * 00557 * @param t the type of 'connection' to create (@see enum netconn_type) 00558 * @param proto the IP protocol for RAW IP pcbs 00559 * @param callback a function to call on status changes (RX available, TX'ed) 00560 * @return a newly allocated struct netconn or 00561 * NULL on memory error 00562 */ 00563 struct netconn* 00564 netconn_alloc(enum netconn_type t, netconn_callback callback) 00565 { 00566 struct netconn *conn; 00567 int size; 00568 00569 conn = (struct netconn *)memp_malloc(MEMP_NETCONN); 00570 if (conn == NULL) { 00571 return NULL; 00572 } 00573 00574 conn->last_err = ERR_OK; 00575 conn->type = t; 00576 conn->pcb.tcp = NULL; 00577 00578 #if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \ 00579 (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE) 00580 size = DEFAULT_RAW_RECVMBOX_SIZE; 00581 #else 00582 switch(NETCONNTYPE_GROUP(t)) { 00583 #if LWIP_RAW 00584 case NETCONN_RAW: 00585 size = DEFAULT_RAW_RECVMBOX_SIZE; 00586 break; 00587 #endif /* LWIP_RAW */ 00588 #if LWIP_UDP 00589 case NETCONN_UDP: 00590 size = DEFAULT_UDP_RECVMBOX_SIZE; 00591 break; 00592 #endif /* LWIP_UDP */ 00593 #if LWIP_TCP 00594 case NETCONN_TCP: 00595 size = DEFAULT_TCP_RECVMBOX_SIZE; 00596 break; 00597 #endif /* LWIP_TCP */ 00598 default: 00599 LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); 00600 break; 00601 } 00602 #endif 00603 00604 if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { 00605 memp_free(MEMP_NETCONN, conn); 00606 return NULL; 00607 } 00608 if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { 00609 sys_sem_free(&conn->op_completed); 00610 memp_free(MEMP_NETCONN, conn); 00611 return NULL; 00612 } 00613 00614 #if LWIP_TCP 00615 sys_mbox_set_invalid(&conn->acceptmbox); 00616 #endif 00617 conn->state = NETCONN_NONE; 00618 #if LWIP_SOCKET 00619 /* initialize socket to -1 since 0 is a valid socket */ 00620 conn->socket = -1; 00621 #endif /* LWIP_SOCKET */ 00622 conn->callback = callback; 00623 #if LWIP_TCP 00624 conn->current_msg = NULL; 00625 conn->write_offset = 0; 00626 #endif /* LWIP_TCP */ 00627 #if LWIP_SO_RCVTIMEO 00628 conn->recv_timeout = 0; 00629 #endif /* LWIP_SO_RCVTIMEO */ 00630 #if LWIP_SO_RCVBUF 00631 conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; 00632 conn->recv_avail = 0; 00633 #endif /* LWIP_SO_RCVBUF */ 00634 conn->flags = 0; 00635 return conn; 00636 } 00637 00638 /** 00639 * Delete a netconn and all its resources. 00640 * The pcb is NOT freed (since we might not be in the right thread context do this). 00641 * 00642 * @param conn the netconn to free 00643 */ 00644 void 00645 netconn_free(struct netconn *conn) 00646 { 00647 LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); 00648 LWIP_ASSERT("recvmbox must be deallocated before calling this function", 00649 !sys_mbox_valid(&conn->recvmbox)); 00650 #if LWIP_TCP 00651 LWIP_ASSERT("acceptmbox must be deallocated before calling this function", 00652 !sys_mbox_valid(&conn->acceptmbox)); 00653 #endif /* LWIP_TCP */ 00654 00655 sys_sem_free(&conn->op_completed); 00656 sys_sem_set_invalid(&conn->op_completed); 00657 00658 memp_free(MEMP_NETCONN, conn); 00659 } 00660 00661 /** 00662 * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in 00663 * these mboxes 00664 * 00665 * @param conn the netconn to free 00666 * @bytes_drained bytes drained from recvmbox 00667 * @accepts_drained pending connections drained from acceptmbox 00668 */ 00669 static void 00670 netconn_drain(struct netconn *conn) 00671 { 00672 void *mem; 00673 #if LWIP_TCP 00674 struct pbuf *p; 00675 #endif /* LWIP_TCP */ 00676 00677 /* This runs in tcpip_thread, so we don't need to lock against rx packets */ 00678 00679 /* Delete and drain the recvmbox. */ 00680 if (sys_mbox_valid(&conn->recvmbox)) { 00681 while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { 00682 #if LWIP_TCP 00683 if (conn->type == NETCONN_TCP) { 00684 if(mem != NULL) { 00685 p = (struct pbuf*)mem; 00686 /* pcb might be set to NULL already by err_tcp() */ 00687 if (conn->pcb.tcp != NULL) { 00688 tcp_recved(conn->pcb.tcp, p->tot_len); 00689 } 00690 pbuf_free(p); 00691 } 00692 } else 00693 #endif /* LWIP_TCP */ 00694 { 00695 netbuf_delete((struct netbuf *)mem); 00696 } 00697 } 00698 sys_mbox_free(&conn->recvmbox); 00699 sys_mbox_set_invalid(&conn->recvmbox); 00700 } 00701 00702 /* Delete and drain the acceptmbox. */ 00703 #if LWIP_TCP 00704 if (sys_mbox_valid(&conn->acceptmbox)) { 00705 while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { 00706 struct netconn *newconn = (struct netconn *)mem; 00707 /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ 00708 /* pcb might be set to NULL already by err_tcp() */ 00709 if (conn->pcb.tcp != NULL) { 00710 tcp_accepted(conn->pcb.tcp); 00711 } 00712 /* drain recvmbox */ 00713 netconn_drain(newconn); 00714 if (newconn->pcb.tcp != NULL) { 00715 tcp_abort(newconn->pcb.tcp); 00716 newconn->pcb.tcp = NULL; 00717 } 00718 netconn_free(newconn); 00719 } 00720 sys_mbox_free(&conn->acceptmbox); 00721 sys_mbox_set_invalid(&conn->acceptmbox); 00722 } 00723 #endif /* LWIP_TCP */ 00724 } 00725 00726 #if LWIP_TCP 00727 /** 00728 * Internal helper function to close a TCP netconn: since this sometimes 00729 * doesn't work at the first attempt, this function is called from multiple 00730 * places. 00731 * 00732 * @param conn the TCP netconn to close 00733 */ 00734 static void 00735 do_close_internal(struct netconn *conn) 00736 { 00737 err_t err; 00738 u8_t shut, shut_rx, shut_tx, close; 00739 00740 LWIP_ASSERT("invalid conn", (conn != NULL)); 00741 LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP)); 00742 LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); 00743 LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); 00744 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 00745 00746 shut = conn->current_msg->msg.sd.shut; 00747 shut_rx = shut & NETCONN_SHUT_RD; 00748 shut_tx = shut & NETCONN_SHUT_WR; 00749 /* shutting down both ends is the same as closing */ 00750 close = shut == NETCONN_SHUT_RDWR; 00751 00752 /* Set back some callback pointers */ 00753 if (close) { 00754 tcp_arg(conn->pcb.tcp, NULL); 00755 } 00756 if (conn->pcb.tcp->state == LISTEN) { 00757 tcp_accept(conn->pcb.tcp, NULL); 00758 } else { 00759 /* some callbacks have to be reset if tcp_close is not successful */ 00760 if (shut_rx) { 00761 tcp_recv(conn->pcb.tcp, NULL); 00762 tcp_accept(conn->pcb.tcp, NULL); 00763 } 00764 if (shut_tx) { 00765 tcp_sent(conn->pcb.tcp, NULL); 00766 } 00767 if (close) { 00768 tcp_poll(conn->pcb.tcp, NULL, 4); 00769 tcp_err(conn->pcb.tcp, NULL); 00770 } 00771 } 00772 /* Try to close the connection */ 00773 if (shut == NETCONN_SHUT_RDWR) { 00774 err = tcp_close(conn->pcb.tcp); 00775 } else { 00776 err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR); 00777 } 00778 if (err == ERR_OK) { 00779 /* Closing succeeded */ 00780 conn->current_msg->err = ERR_OK; 00781 conn->current_msg = NULL; 00782 conn->state = NETCONN_NONE; 00783 /* Set back some callback pointers as conn is going away */ 00784 conn->pcb.tcp = NULL; 00785 /* Trigger select() in socket layer. Make sure everybody notices activity 00786 on the connection, error first! */ 00787 if (close) { 00788 API_EVENT(conn, NETCONN_EVT_ERROR, 0); 00789 } 00790 if (shut_rx) { 00791 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 00792 } 00793 if (shut_tx) { 00794 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 00795 } 00796 /* wake up the application task */ 00797 sys_sem_signal(&conn->op_completed); 00798 } else { 00799 /* Closing failed, restore some of the callbacks */ 00800 /* Closing of listen pcb will never fail! */ 00801 LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN)); 00802 tcp_sent(conn->pcb.tcp, sent_tcp); 00803 tcp_poll(conn->pcb.tcp, poll_tcp, 4); 00804 tcp_err(conn->pcb.tcp, err_tcp); 00805 tcp_arg(conn->pcb.tcp, conn); 00806 /* don't restore recv callback: we don't want to receive any more data */ 00807 } 00808 /* If closing didn't succeed, we get called again either 00809 from poll_tcp or from sent_tcp */ 00810 } 00811 #endif /* LWIP_TCP */ 00812 00813 /** 00814 * Delete the pcb inside a netconn. 00815 * Called from netconn_delete. 00816 * 00817 * @param msg the api_msg_msg pointing to the connection 00818 */ 00819 void 00820 do_delconn(struct api_msg_msg *msg) 00821 { 00822 /* @todo TCP: abort running write/connect? */ 00823 if ((msg->conn->state != NETCONN_NONE) && 00824 (msg->conn->state != NETCONN_LISTEN) && 00825 (msg->conn->state != NETCONN_CONNECT)) { 00826 /* this only happens for TCP netconns */ 00827 LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); 00828 msg->err = ERR_INPROGRESS; 00829 } else { 00830 LWIP_ASSERT("blocking connect in progress", 00831 (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); 00832 /* Drain and delete mboxes */ 00833 netconn_drain(msg->conn); 00834 00835 if (msg->conn->pcb.tcp != NULL) { 00836 00837 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 00838 #if LWIP_RAW 00839 case NETCONN_RAW: 00840 raw_remove(msg->conn->pcb.raw); 00841 break; 00842 #endif /* LWIP_RAW */ 00843 #if LWIP_UDP 00844 case NETCONN_UDP: 00845 msg->conn->pcb.udp->recv_arg = NULL; 00846 udp_remove(msg->conn->pcb.udp); 00847 break; 00848 #endif /* LWIP_UDP */ 00849 #if LWIP_TCP 00850 case NETCONN_TCP: 00851 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && 00852 msg->conn->write_offset == 0); 00853 msg->conn->state = NETCONN_CLOSE; 00854 msg->msg.sd.shut = NETCONN_SHUT_RDWR; 00855 msg->conn->current_msg = msg; 00856 do_close_internal(msg->conn); 00857 /* API_EVENT is called inside do_close_internal, before releasing 00858 the application thread, so we can return at this point! */ 00859 return; 00860 #endif /* LWIP_TCP */ 00861 default: 00862 break; 00863 } 00864 msg->conn->pcb.tcp = NULL; 00865 } 00866 /* tcp netconns don't come here! */ 00867 00868 /* @todo: this lets select make the socket readable and writable, 00869 which is wrong! errfd instead? */ 00870 API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); 00871 API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); 00872 } 00873 if (sys_sem_valid(&msg->conn->op_completed)) { 00874 sys_sem_signal(&msg->conn->op_completed); 00875 } 00876 } 00877 00878 /** 00879 * Bind a pcb contained in a netconn 00880 * Called from netconn_bind. 00881 * 00882 * @param msg the api_msg_msg pointing to the connection and containing 00883 * the IP address and port to bind to 00884 */ 00885 void 00886 do_bind(struct api_msg_msg *msg) 00887 { 00888 if (ERR_IS_FATAL(msg->conn->last_err)) { 00889 msg->err = msg->conn->last_err; 00890 } else { 00891 msg->err = ERR_VAL; 00892 if (msg->conn->pcb.tcp != NULL) { 00893 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 00894 #if LWIP_RAW 00895 case NETCONN_RAW: 00896 msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr); 00897 break; 00898 #endif /* LWIP_RAW */ 00899 #if LWIP_UDP 00900 case NETCONN_UDP: 00901 msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); 00902 break; 00903 #endif /* LWIP_UDP */ 00904 #if LWIP_TCP 00905 case NETCONN_TCP: 00906 msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port); 00907 break; 00908 #endif /* LWIP_TCP */ 00909 default: 00910 break; 00911 } 00912 } 00913 } 00914 TCPIP_APIMSG_ACK(msg); 00915 } 00916 00917 #if LWIP_TCP 00918 /** 00919 * TCP callback function if a connection (opened by tcp_connect/do_connect) has 00920 * been established (or reset by the remote host). 00921 * 00922 * @see tcp.h (struct tcp_pcb.connected) for parameters and return values 00923 */ 00924 static err_t 00925 do_connected(void *arg, struct tcp_pcb *pcb, err_t err) 00926 { 00927 struct netconn *conn; 00928 int was_blocking; 00929 00930 LWIP_UNUSED_ARG(pcb); 00931 00932 conn = (struct netconn *)arg; 00933 00934 if (conn == NULL) { 00935 return ERR_VAL; 00936 } 00937 00938 LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); 00939 LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", 00940 (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); 00941 00942 if (conn->current_msg != NULL) { 00943 conn->current_msg->err = err; 00944 } 00945 if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) { 00946 setup_tcp(conn); 00947 } 00948 was_blocking = !IN_NONBLOCKING_CONNECT(conn); 00949 SET_NONBLOCKING_CONNECT(conn, 0); 00950 conn->current_msg = NULL; 00951 conn->state = NETCONN_NONE; 00952 if (!was_blocking) { 00953 NETCONN_SET_SAFE_ERR(conn, ERR_OK); 00954 } 00955 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 00956 00957 if (was_blocking) { 00958 sys_sem_signal(&conn->op_completed); 00959 } 00960 return ERR_OK; 00961 } 00962 #endif /* LWIP_TCP */ 00963 00964 /** 00965 * Connect a pcb contained inside a netconn 00966 * Called from netconn_connect. 00967 * 00968 * @param msg the api_msg_msg pointing to the connection and containing 00969 * the IP address and port to connect to 00970 */ 00971 void 00972 do_connect(struct api_msg_msg *msg) 00973 { 00974 if (msg->conn->pcb.tcp == NULL) { 00975 /* This may happen when calling netconn_connect() a second time */ 00976 msg->err = ERR_CLSD; 00977 } else { 00978 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 00979 #if LWIP_RAW 00980 case NETCONN_RAW: 00981 msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); 00982 break; 00983 #endif /* LWIP_RAW */ 00984 #if LWIP_UDP 00985 case NETCONN_UDP: 00986 msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); 00987 break; 00988 #endif /* LWIP_UDP */ 00989 #if LWIP_TCP 00990 case NETCONN_TCP: 00991 /* Prevent connect while doing any other action. */ 00992 if (msg->conn->state != NETCONN_NONE) { 00993 msg->err = ERR_ISCONN; 00994 } else { 00995 setup_tcp(msg->conn); 00996 msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, 00997 msg->msg.bc.port, do_connected); 00998 if (msg->err == ERR_OK) { 00999 u8_t non_blocking = netconn_is_nonblocking(msg->conn); 01000 msg->conn->state = NETCONN_CONNECT; 01001 SET_NONBLOCKING_CONNECT(msg->conn, non_blocking); 01002 if (non_blocking) { 01003 msg->err = ERR_INPROGRESS; 01004 } else { 01005 msg->conn->current_msg = msg; 01006 /* sys_sem_signal() is called from do_connected (or err_tcp()), 01007 * when the connection is established! */ 01008 return; 01009 } 01010 } 01011 } 01012 break; 01013 #endif /* LWIP_TCP */ 01014 default: 01015 LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0)); 01016 break; 01017 } 01018 } 01019 sys_sem_signal(&msg->conn->op_completed); 01020 } 01021 01022 /** 01023 * Connect a pcb contained inside a netconn 01024 * Only used for UDP netconns. 01025 * Called from netconn_disconnect. 01026 * 01027 * @param msg the api_msg_msg pointing to the connection to disconnect 01028 */ 01029 void 01030 do_disconnect(struct api_msg_msg *msg) 01031 { 01032 #if LWIP_UDP 01033 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 01034 udp_disconnect(msg->conn->pcb.udp); 01035 msg->err = ERR_OK; 01036 } else 01037 #endif /* LWIP_UDP */ 01038 { 01039 msg->err = ERR_VAL; 01040 } 01041 TCPIP_APIMSG_ACK(msg); 01042 } 01043 01044 #if LWIP_TCP 01045 /** 01046 * Set a TCP pcb contained in a netconn into listen mode 01047 * Called from netconn_listen. 01048 * 01049 * @param msg the api_msg_msg pointing to the connection 01050 */ 01051 void 01052 do_listen(struct api_msg_msg *msg) 01053 { 01054 if (ERR_IS_FATAL(msg->conn->last_err)) { 01055 msg->err = msg->conn->last_err; 01056 } else { 01057 msg->err = ERR_CONN; 01058 if (msg->conn->pcb.tcp != NULL) { 01059 if (msg->conn->type == NETCONN_TCP) { 01060 if (msg->conn->state == NETCONN_NONE) { 01061 #if TCP_LISTEN_BACKLOG 01062 struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); 01063 #else /* TCP_LISTEN_BACKLOG */ 01064 struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp); 01065 #endif /* TCP_LISTEN_BACKLOG */ 01066 if (lpcb == NULL) { 01067 /* in this case, the old pcb is still allocated */ 01068 msg->err = ERR_MEM; 01069 } else { 01070 /* delete the recvmbox and allocate the acceptmbox */ 01071 if (sys_mbox_valid(&msg->conn->recvmbox)) { 01072 /** @todo: should we drain the recvmbox here? */ 01073 sys_mbox_free(&msg->conn->recvmbox); 01074 sys_mbox_set_invalid(&msg->conn->recvmbox); 01075 } 01076 msg->err = ERR_OK; 01077 if (!sys_mbox_valid(&msg->conn->acceptmbox)) { 01078 msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); 01079 } 01080 if (msg->err == ERR_OK) { 01081 msg->conn->state = NETCONN_LISTEN; 01082 msg->conn->pcb.tcp = lpcb; 01083 tcp_arg(msg->conn->pcb.tcp, msg->conn); 01084 tcp_accept(msg->conn->pcb.tcp, accept_function); 01085 } else { 01086 /* since the old pcb is already deallocated, free lpcb now */ 01087 tcp_close(lpcb); 01088 msg->conn->pcb.tcp = NULL; 01089 } 01090 } 01091 } 01092 } 01093 } 01094 } 01095 TCPIP_APIMSG_ACK(msg); 01096 } 01097 #endif /* LWIP_TCP */ 01098 01099 /** 01100 * Send some data on a RAW or UDP pcb contained in a netconn 01101 * Called from netconn_send 01102 * 01103 * @param msg the api_msg_msg pointing to the connection 01104 */ 01105 void 01106 do_send(struct api_msg_msg *msg) 01107 { 01108 if (ERR_IS_FATAL(msg->conn->last_err)) { 01109 msg->err = msg->conn->last_err; 01110 } else { 01111 msg->err = ERR_CONN; 01112 if (msg->conn->pcb.tcp != NULL) { 01113 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 01114 #if LWIP_RAW 01115 case NETCONN_RAW: 01116 if (ip_addr_isany(&msg->msg.b->addr)) { 01117 msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); 01118 } else { 01119 msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); 01120 } 01121 break; 01122 #endif 01123 #if LWIP_UDP 01124 case NETCONN_UDP: 01125 #if LWIP_CHECKSUM_ON_COPY 01126 if (ip_addr_isany(&msg->msg.b->addr)) { 01127 msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, 01128 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); 01129 } else { 01130 msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, 01131 &msg->msg.b->addr, msg->msg.b->port, 01132 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); 01133 } 01134 #else /* LWIP_CHECKSUM_ON_COPY */ 01135 if (ip_addr_isany(&msg->msg.b->addr)) { 01136 msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); 01137 } else { 01138 msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port); 01139 } 01140 #endif /* LWIP_CHECKSUM_ON_COPY */ 01141 break; 01142 #endif /* LWIP_UDP */ 01143 default: 01144 break; 01145 } 01146 } 01147 } 01148 TCPIP_APIMSG_ACK(msg); 01149 } 01150 01151 #if LWIP_TCP 01152 /** 01153 * Indicate data has been received from a TCP pcb contained in a netconn 01154 * Called from netconn_recv 01155 * 01156 * @param msg the api_msg_msg pointing to the connection 01157 */ 01158 void 01159 do_recv(struct api_msg_msg *msg) 01160 { 01161 msg->err = ERR_OK; 01162 if (msg->conn->pcb.tcp != NULL) { 01163 if (msg->conn->type == NETCONN_TCP) { 01164 #if TCP_LISTEN_BACKLOG 01165 if (msg->conn->pcb.tcp->state == LISTEN) { 01166 tcp_accepted(msg->conn->pcb.tcp); 01167 } else 01168 #endif /* TCP_LISTEN_BACKLOG */ 01169 { 01170 u32_t remaining = msg->msg.r.len; 01171 do { 01172 u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining; 01173 tcp_recved(msg->conn->pcb.tcp, recved); 01174 remaining -= recved; 01175 }while(remaining != 0); 01176 } 01177 } 01178 } 01179 TCPIP_APIMSG_ACK(msg); 01180 } 01181 01182 /** 01183 * See if more data needs to be written from a previous call to netconn_write. 01184 * Called initially from do_write. If the first call can't send all data 01185 * (because of low memory or empty send-buffer), this function is called again 01186 * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the 01187 * blocking application thread (waiting in netconn_write) is released. 01188 * 01189 * @param conn netconn (that is currently in state NETCONN_WRITE) to process 01190 * @return ERR_OK 01191 * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished 01192 */ 01193 static err_t 01194 do_writemore(struct netconn *conn) 01195 { 01196 err_t err = ERR_OK; 01197 void *dataptr; 01198 u16_t len, available; 01199 u8_t write_finished = 0; 01200 size_t diff; 01201 u8_t dontblock = netconn_is_nonblocking(conn) || 01202 (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK); 01203 u8_t apiflags = conn->current_msg->msg.w.apiflags; 01204 01205 LWIP_ASSERT("conn != NULL", conn != NULL); 01206 LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); 01207 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 01208 LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); 01209 LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len", 01210 conn->write_offset < conn->current_msg->msg.w.len); 01211 01212 dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset; 01213 diff = conn->current_msg->msg.w.len - conn->write_offset; 01214 if (diff > 0xffffUL) { /* max_u16_t */ 01215 len = 0xffff; 01216 #if LWIP_TCPIP_CORE_LOCKING 01217 conn->flags |= NETCONN_FLAG_WRITE_DELAYED; 01218 #endif 01219 apiflags |= TCP_WRITE_FLAG_MORE; 01220 } else { 01221 len = (u16_t)diff; 01222 } 01223 available = tcp_sndbuf(conn->pcb.tcp); 01224 if (available < len) { 01225 /* don't try to write more than sendbuf */ 01226 len = available; 01227 #if LWIP_TCPIP_CORE_LOCKING 01228 conn->flags |= NETCONN_FLAG_WRITE_DELAYED; 01229 #endif 01230 apiflags |= TCP_WRITE_FLAG_MORE; 01231 } 01232 if (dontblock && (len < conn->current_msg->msg.w.len)) { 01233 /* failed to send all data at once -> nonblocking write not possible */ 01234 err = ERR_MEM; 01235 } 01236 if (err == ERR_OK) { 01237 LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); 01238 err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); 01239 } 01240 if (dontblock && (err == ERR_MEM)) { 01241 /* nonblocking write failed */ 01242 write_finished = 1; 01243 err = ERR_WOULDBLOCK; 01244 /* let poll_tcp check writable space to mark the pcb 01245 writable again */ 01246 conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; 01247 /* let select mark this pcb as non-writable. */ 01248 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); 01249 } else { 01250 /* if OK or memory error, check available space */ 01251 if (((err == ERR_OK) || (err == ERR_MEM)) && 01252 ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || 01253 (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT))) { 01254 /* The queued byte- or pbuf-count exceeds the configured low-water limit, 01255 let select mark this pcb as non-writable. */ 01256 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); 01257 } 01258 01259 if (err == ERR_OK) { 01260 conn->write_offset += len; 01261 if (conn->write_offset == conn->current_msg->msg.w.len) { 01262 /* everything was written */ 01263 write_finished = 1; 01264 conn->write_offset = 0; 01265 } 01266 tcp_output(conn->pcb.tcp); 01267 } else if (err == ERR_MEM) { 01268 /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called 01269 we do NOT return to the application thread, since ERR_MEM is 01270 only a temporary error! */ 01271 01272 /* tcp_write returned ERR_MEM, try tcp_output anyway */ 01273 tcp_output(conn->pcb.tcp); 01274 01275 #if LWIP_TCPIP_CORE_LOCKING 01276 conn->flags |= NETCONN_FLAG_WRITE_DELAYED; 01277 #endif 01278 } else { 01279 /* On errors != ERR_MEM, we don't try writing any more but return 01280 the error to the application thread. */ 01281 write_finished = 1; 01282 } 01283 } 01284 01285 if (write_finished) { 01286 /* everything was written: set back connection state 01287 and back to application task */ 01288 conn->current_msg->err = err; 01289 conn->current_msg = NULL; 01290 conn->state = NETCONN_NONE; 01291 #if LWIP_TCPIP_CORE_LOCKING 01292 if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0) 01293 #endif 01294 { 01295 sys_sem_signal(&conn->op_completed); 01296 } 01297 } 01298 #if LWIP_TCPIP_CORE_LOCKING 01299 else 01300 return ERR_MEM; 01301 #endif 01302 return ERR_OK; 01303 } 01304 #endif /* LWIP_TCP */ 01305 01306 /** 01307 * Send some data on a TCP pcb contained in a netconn 01308 * Called from netconn_write 01309 * 01310 * @param msg the api_msg_msg pointing to the connection 01311 */ 01312 void 01313 do_write(struct api_msg_msg *msg) 01314 { 01315 if (ERR_IS_FATAL(msg->conn->last_err)) { 01316 msg->err = msg->conn->last_err; 01317 } else { 01318 if (msg->conn->type == NETCONN_TCP) { 01319 #if LWIP_TCP 01320 if (msg->conn->state != NETCONN_NONE) { 01321 /* netconn is connecting, closing or in blocking write */ 01322 msg->err = ERR_INPROGRESS; 01323 } else if (msg->conn->pcb.tcp != NULL) { 01324 msg->conn->state = NETCONN_WRITE; 01325 /* set all the variables used by do_writemore */ 01326 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && 01327 msg->conn->write_offset == 0); 01328 LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0); 01329 msg->conn->current_msg = msg; 01330 msg->conn->write_offset = 0; 01331 #if LWIP_TCPIP_CORE_LOCKING 01332 msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED; 01333 if (do_writemore(msg->conn) != ERR_OK) { 01334 LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); 01335 UNLOCK_TCPIP_CORE(); 01336 sys_arch_sem_wait(&msg->conn->op_completed, 0); 01337 LOCK_TCPIP_CORE(); 01338 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); 01339 } 01340 #else /* LWIP_TCPIP_CORE_LOCKING */ 01341 do_writemore(msg->conn); 01342 #endif /* LWIP_TCPIP_CORE_LOCKING */ 01343 /* for both cases: if do_writemore was called, don't ACK the APIMSG 01344 since do_writemore ACKs it! */ 01345 return; 01346 } else { 01347 msg->err = ERR_CONN; 01348 } 01349 #else /* LWIP_TCP */ 01350 msg->err = ERR_VAL; 01351 #endif /* LWIP_TCP */ 01352 #if (LWIP_UDP || LWIP_RAW) 01353 } else { 01354 msg->err = ERR_VAL; 01355 #endif /* (LWIP_UDP || LWIP_RAW) */ 01356 } 01357 } 01358 TCPIP_APIMSG_ACK(msg); 01359 } 01360 01361 /** 01362 * Return a connection's local or remote address 01363 * Called from netconn_getaddr 01364 * 01365 * @param msg the api_msg_msg pointing to the connection 01366 */ 01367 void 01368 do_getaddr(struct api_msg_msg *msg) 01369 { 01370 if (msg->conn->pcb.ip != NULL) { 01371 *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip : 01372 msg->conn->pcb.ip->remote_ip); 01373 01374 msg->err = ERR_OK; 01375 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 01376 #if LWIP_RAW 01377 case NETCONN_RAW: 01378 if (msg->msg.ad.local) { 01379 *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; 01380 } else { 01381 /* return an error as connecting is only a helper for upper layers */ 01382 msg->err = ERR_CONN; 01383 } 01384 break; 01385 #endif /* LWIP_RAW */ 01386 #if LWIP_UDP 01387 case NETCONN_UDP: 01388 if (msg->msg.ad.local) { 01389 *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; 01390 } else { 01391 if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { 01392 msg->err = ERR_CONN; 01393 } else { 01394 *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; 01395 } 01396 } 01397 break; 01398 #endif /* LWIP_UDP */ 01399 #if LWIP_TCP 01400 case NETCONN_TCP: 01401 *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port); 01402 break; 01403 #endif /* LWIP_TCP */ 01404 default: 01405 LWIP_ASSERT("invalid netconn_type", 0); 01406 break; 01407 } 01408 } else { 01409 msg->err = ERR_CONN; 01410 } 01411 TCPIP_APIMSG_ACK(msg); 01412 } 01413 01414 /** 01415 * Close a TCP pcb contained in a netconn 01416 * Called from netconn_close 01417 * 01418 * @param msg the api_msg_msg pointing to the connection 01419 */ 01420 void 01421 do_close(struct api_msg_msg *msg) 01422 { 01423 #if LWIP_TCP 01424 /* @todo: abort running write/connect? */ 01425 if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) { 01426 /* this only happens for TCP netconns */ 01427 LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); 01428 msg->err = ERR_INPROGRESS; 01429 } else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { 01430 if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) { 01431 /* LISTEN doesn't support half shutdown */ 01432 msg->err = ERR_CONN; 01433 } else { 01434 if (msg->msg.sd.shut & NETCONN_SHUT_RD) { 01435 /* Drain and delete mboxes */ 01436 netconn_drain(msg->conn); 01437 } 01438 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && 01439 msg->conn->write_offset == 0); 01440 msg->conn->state = NETCONN_CLOSE; 01441 msg->conn->current_msg = msg; 01442 do_close_internal(msg->conn); 01443 /* for tcp netconns, do_close_internal ACKs the message */ 01444 return; 01445 } 01446 } else 01447 #endif /* LWIP_TCP */ 01448 { 01449 msg->err = ERR_VAL; 01450 } 01451 sys_sem_signal(&msg->conn->op_completed); 01452 } 01453 01454 #if LWIP_IGMP 01455 /** 01456 * Join multicast groups for UDP netconns. 01457 * Called from netconn_join_leave_group 01458 * 01459 * @param msg the api_msg_msg pointing to the connection 01460 */ 01461 void 01462 do_join_leave_group(struct api_msg_msg *msg) 01463 { 01464 if (ERR_IS_FATAL(msg->conn->last_err)) { 01465 msg->err = msg->conn->last_err; 01466 } else { 01467 if (msg->conn->pcb.tcp != NULL) { 01468 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 01469 #if LWIP_UDP 01470 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 01471 msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); 01472 } else { 01473 msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); 01474 } 01475 #endif /* LWIP_UDP */ 01476 #if (LWIP_TCP || LWIP_RAW) 01477 } else { 01478 msg->err = ERR_VAL; 01479 #endif /* (LWIP_TCP || LWIP_RAW) */ 01480 } 01481 } else { 01482 msg->err = ERR_CONN; 01483 } 01484 } 01485 TCPIP_APIMSG_ACK(msg); 01486 } 01487 #endif /* LWIP_IGMP */ 01488 01489 #if LWIP_DNS 01490 /** 01491 * Callback function that is called when DNS name is resolved 01492 * (or on timeout). A waiting application thread is waked up by 01493 * signaling the semaphore. 01494 */ 01495 static void 01496 do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) 01497 { 01498 struct dns_api_msg *msg = (struct dns_api_msg*)arg; 01499 01500 LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0); 01501 LWIP_UNUSED_ARG(name); 01502 01503 if (ipaddr == NULL) { 01504 /* timeout or memory error */ 01505 *msg->err = ERR_VAL; 01506 } else { 01507 /* address was resolved */ 01508 *msg->err = ERR_OK; 01509 *msg->addr = *ipaddr; 01510 } 01511 /* wake up the application task waiting in netconn_gethostbyname */ 01512 sys_sem_signal(msg->sem); 01513 } 01514 01515 /** 01516 * Execute a DNS query 01517 * Called from netconn_gethostbyname 01518 * 01519 * @param arg the dns_api_msg pointing to the query 01520 */ 01521 void 01522 do_gethostbyname(void *arg) 01523 { 01524 struct dns_api_msg *msg = (struct dns_api_msg*)arg; 01525 01526 *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg); 01527 if (*msg->err != ERR_INPROGRESS) { 01528 /* on error or immediate success, wake up the application 01529 * task waiting in netconn_gethostbyname */ 01530 sys_sem_signal(msg->sem); 01531 } 01532 } 01533 #endif /* LWIP_DNS */ 01534 01535 #endif /* LWIP_NETCONN */
Generated on Tue Jul 12 2022 11:29:36 by
