fdsf
Dependents: sisk_proj_stat MQTT Hello_FXOS8700Q WireFSHandControl ... more
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 15:52:16 by 1.7.2