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 F7_Ethernet 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 /* remove all references to this netconn from the pcb */ 00460 struct tcp_pcb* pcb = newconn->pcb.tcp; 00461 tcp_arg(pcb, NULL); 00462 tcp_recv(pcb, NULL); 00463 tcp_sent(pcb, NULL); 00464 tcp_poll(pcb, NULL, 4); 00465 tcp_err(pcb, NULL); 00466 /* remove reference from to the pcb from this netconn */ 00467 newconn->pcb.tcp = NULL; 00468 /* no need to drain since we know the recvmbox is empty. */ 00469 sys_mbox_free(&newconn->recvmbox); 00470 sys_mbox_set_invalid(&newconn->recvmbox); 00471 netconn_free(newconn); 00472 return ERR_MEM; 00473 } else { 00474 /* Register event with callback */ 00475 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 00476 } 00477 00478 return ERR_OK; 00479 } 00480 #endif /* LWIP_TCP */ 00481 00482 /** 00483 * Create a new pcb of a specific type. 00484 * Called from do_newconn(). 00485 * 00486 * @param msg the api_msg_msg describing the connection type 00487 * @return msg->conn->err, but the return value is currently ignored 00488 */ 00489 static void 00490 pcb_new(struct api_msg_msg *msg) 00491 { 00492 LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); 00493 00494 /* Allocate a PCB for this connection */ 00495 switch(NETCONNTYPE_GROUP(msg->conn->type)) { 00496 #if LWIP_RAW 00497 case NETCONN_RAW: 00498 msg->conn->pcb.raw = raw_new(msg->msg.n.proto); 00499 if(msg->conn->pcb.raw == NULL) { 00500 msg->err = ERR_MEM; 00501 break; 00502 } 00503 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); 00504 break; 00505 #endif /* LWIP_RAW */ 00506 #if LWIP_UDP 00507 case NETCONN_UDP: 00508 msg->conn->pcb.udp = udp_new(); 00509 if(msg->conn->pcb.udp == NULL) { 00510 msg->err = ERR_MEM; 00511 break; 00512 } 00513 #if LWIP_UDPLITE 00514 if (msg->conn->type==NETCONN_UDPLITE) { 00515 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); 00516 } 00517 #endif /* LWIP_UDPLITE */ 00518 if (msg->conn->type==NETCONN_UDPNOCHKSUM) { 00519 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); 00520 } 00521 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); 00522 break; 00523 #endif /* LWIP_UDP */ 00524 #if LWIP_TCP 00525 case NETCONN_TCP: 00526 msg->conn->pcb.tcp = tcp_new(); 00527 if(msg->conn->pcb.tcp == NULL) { 00528 msg->err = ERR_MEM; 00529 break; 00530 } 00531 setup_tcp(msg->conn); 00532 break; 00533 #endif /* LWIP_TCP */ 00534 default: 00535 /* Unsupported netconn type, e.g. protocol disabled */ 00536 msg->err = ERR_VAL; 00537 break; 00538 } 00539 } 00540 00541 /** 00542 * Create a new pcb of a specific type inside a netconn. 00543 * Called from netconn_new_with_proto_and_callback. 00544 * 00545 * @param msg the api_msg_msg describing the connection type 00546 */ 00547 void 00548 do_newconn(struct api_msg_msg *msg) 00549 { 00550 msg->err = ERR_OK; 00551 if(msg->conn->pcb.tcp == NULL) { 00552 pcb_new(msg); 00553 } 00554 /* Else? This "new" connection already has a PCB allocated. */ 00555 /* Is this an error condition? Should it be deleted? */ 00556 /* We currently just are happy and return. */ 00557 00558 TCPIP_APIMSG_ACK(msg); 00559 } 00560 00561 /** 00562 * Create a new netconn (of a specific type) that has a callback function. 00563 * The corresponding pcb is NOT created! 00564 * 00565 * @param t the type of 'connection' to create (@see enum netconn_type) 00566 * @param proto the IP protocol for RAW IP pcbs 00567 * @param callback a function to call on status changes (RX available, TX'ed) 00568 * @return a newly allocated struct netconn or 00569 * NULL on memory error 00570 */ 00571 struct netconn* 00572 netconn_alloc(enum netconn_type t, netconn_callback callback) 00573 { 00574 struct netconn *conn; 00575 int size; 00576 00577 conn = (struct netconn *)memp_malloc(MEMP_NETCONN); 00578 if (conn == NULL) { 00579 return NULL; 00580 } 00581 00582 conn->last_err = ERR_OK; 00583 conn->type = t; 00584 conn->pcb.tcp = NULL; 00585 00586 #if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \ 00587 (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE) 00588 size = DEFAULT_RAW_RECVMBOX_SIZE; 00589 #else 00590 switch(NETCONNTYPE_GROUP(t)) { 00591 #if LWIP_RAW 00592 case NETCONN_RAW: 00593 size = DEFAULT_RAW_RECVMBOX_SIZE; 00594 break; 00595 #endif /* LWIP_RAW */ 00596 #if LWIP_UDP 00597 case NETCONN_UDP: 00598 size = DEFAULT_UDP_RECVMBOX_SIZE; 00599 break; 00600 #endif /* LWIP_UDP */ 00601 #if LWIP_TCP 00602 case NETCONN_TCP: 00603 size = DEFAULT_TCP_RECVMBOX_SIZE; 00604 break; 00605 #endif /* LWIP_TCP */ 00606 default: 00607 LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); 00608 goto free_and_return; 00609 } 00610 #endif 00611 00612 if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { 00613 goto free_and_return; 00614 } 00615 if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { 00616 sys_sem_free(&conn->op_completed); 00617 goto free_and_return; 00618 } 00619 00620 #if LWIP_TCP 00621 sys_mbox_set_invalid(&conn->acceptmbox); 00622 #endif 00623 conn->state = NETCONN_NONE; 00624 #if LWIP_SOCKET 00625 /* initialize socket to -1 since 0 is a valid socket */ 00626 conn->socket = -1; 00627 #endif /* LWIP_SOCKET */ 00628 conn->callback = callback; 00629 #if LWIP_TCP 00630 conn->current_msg = NULL; 00631 conn->write_offset = 0; 00632 #endif /* LWIP_TCP */ 00633 #if LWIP_SO_SNDTIMEO 00634 conn->send_timeout = 0; 00635 #endif /* LWIP_SO_SNDTIMEO */ 00636 #if LWIP_SO_RCVTIMEO 00637 conn->recv_timeout = 0; 00638 #endif /* LWIP_SO_RCVTIMEO */ 00639 #if LWIP_SO_RCVBUF 00640 conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; 00641 conn->recv_avail = 0; 00642 #endif /* LWIP_SO_RCVBUF */ 00643 conn->flags = 0; 00644 return conn; 00645 free_and_return: 00646 memp_free(MEMP_NETCONN, conn); 00647 return NULL; 00648 } 00649 00650 /** 00651 * Delete a netconn and all its resources. 00652 * The pcb is NOT freed (since we might not be in the right thread context do this). 00653 * 00654 * @param conn the netconn to free 00655 */ 00656 void 00657 netconn_free(struct netconn *conn) 00658 { 00659 LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); 00660 LWIP_ASSERT("recvmbox must be deallocated before calling this function", 00661 !sys_mbox_valid(&conn->recvmbox)); 00662 #if LWIP_TCP 00663 LWIP_ASSERT("acceptmbox must be deallocated before calling this function", 00664 !sys_mbox_valid(&conn->acceptmbox)); 00665 #endif /* LWIP_TCP */ 00666 00667 sys_sem_free(&conn->op_completed); 00668 sys_sem_set_invalid(&conn->op_completed); 00669 00670 memp_free(MEMP_NETCONN, conn); 00671 } 00672 00673 /** 00674 * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in 00675 * these mboxes 00676 * 00677 * @param conn the netconn to free 00678 * @bytes_drained bytes drained from recvmbox 00679 * @accepts_drained pending connections drained from acceptmbox 00680 */ 00681 static void 00682 netconn_drain(struct netconn *conn) 00683 { 00684 void *mem; 00685 #if LWIP_TCP 00686 struct pbuf *p; 00687 #endif /* LWIP_TCP */ 00688 00689 /* This runs in tcpip_thread, so we don't need to lock against rx packets */ 00690 00691 /* Delete and drain the recvmbox. */ 00692 if (sys_mbox_valid(&conn->recvmbox)) { 00693 while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { 00694 #if LWIP_TCP 00695 if (conn->type == NETCONN_TCP) { 00696 if(mem != NULL) { 00697 p = (struct pbuf*)mem; 00698 /* pcb might be set to NULL already by err_tcp() */ 00699 if (conn->pcb.tcp != NULL) { 00700 tcp_recved(conn->pcb.tcp, p->tot_len); 00701 } 00702 pbuf_free(p); 00703 } 00704 } else 00705 #endif /* LWIP_TCP */ 00706 { 00707 netbuf_delete((struct netbuf *)mem); 00708 } 00709 } 00710 sys_mbox_free(&conn->recvmbox); 00711 sys_mbox_set_invalid(&conn->recvmbox); 00712 } 00713 00714 /* Delete and drain the acceptmbox. */ 00715 #if LWIP_TCP 00716 if (sys_mbox_valid(&conn->acceptmbox)) { 00717 while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { 00718 struct netconn *newconn = (struct netconn *)mem; 00719 /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ 00720 /* pcb might be set to NULL already by err_tcp() */ 00721 if (conn->pcb.tcp != NULL) { 00722 tcp_accepted(conn->pcb.tcp); 00723 } 00724 /* drain recvmbox */ 00725 netconn_drain(newconn); 00726 if (newconn->pcb.tcp != NULL) { 00727 tcp_abort(newconn->pcb.tcp); 00728 newconn->pcb.tcp = NULL; 00729 } 00730 netconn_free(newconn); 00731 } 00732 sys_mbox_free(&conn->acceptmbox); 00733 sys_mbox_set_invalid(&conn->acceptmbox); 00734 } 00735 #endif /* LWIP_TCP */ 00736 } 00737 00738 #if LWIP_TCP 00739 /** 00740 * Internal helper function to close a TCP netconn: since this sometimes 00741 * doesn't work at the first attempt, this function is called from multiple 00742 * places. 00743 * 00744 * @param conn the TCP netconn to close 00745 */ 00746 static void 00747 do_close_internal(struct netconn *conn) 00748 { 00749 err_t err; 00750 u8_t shut, shut_rx, shut_tx, close; 00751 00752 LWIP_ASSERT("invalid conn", (conn != NULL)); 00753 LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP)); 00754 LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); 00755 LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); 00756 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 00757 00758 shut = conn->current_msg->msg.sd.shut; 00759 shut_rx = shut & NETCONN_SHUT_RD; 00760 shut_tx = shut & NETCONN_SHUT_WR; 00761 /* shutting down both ends is the same as closing */ 00762 close = shut == NETCONN_SHUT_RDWR; 00763 00764 /* Set back some callback pointers */ 00765 if (close) { 00766 tcp_arg(conn->pcb.tcp, NULL); 00767 } 00768 if (conn->pcb.tcp->state == LISTEN) { 00769 tcp_accept(conn->pcb.tcp, NULL); 00770 } else { 00771 /* some callbacks have to be reset if tcp_close is not successful */ 00772 if (shut_rx) { 00773 tcp_recv(conn->pcb.tcp, NULL); 00774 tcp_accept(conn->pcb.tcp, NULL); 00775 } 00776 if (shut_tx) { 00777 tcp_sent(conn->pcb.tcp, NULL); 00778 } 00779 if (close) { 00780 tcp_poll(conn->pcb.tcp, NULL, 4); 00781 tcp_err(conn->pcb.tcp, NULL); 00782 } 00783 } 00784 /* Try to close the connection */ 00785 if (close) { 00786 err = tcp_close(conn->pcb.tcp); 00787 } else { 00788 err = tcp_shutdown(conn->pcb.tcp, shut_rx, shut_tx); 00789 } 00790 if (err == ERR_OK) { 00791 /* Closing succeeded */ 00792 conn->current_msg->err = ERR_OK; 00793 conn->current_msg = NULL; 00794 conn->state = NETCONN_NONE; 00795 if (close) { 00796 /* Set back some callback pointers as conn is going away */ 00797 conn->pcb.tcp = NULL; 00798 /* Trigger select() in socket layer. Make sure everybody notices activity 00799 on the connection, error first! */ 00800 API_EVENT(conn, NETCONN_EVT_ERROR, 0); 00801 } 00802 if (shut_rx) { 00803 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 00804 } 00805 if (shut_tx) { 00806 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 00807 } 00808 /* wake up the application task */ 00809 sys_sem_signal(&conn->op_completed); 00810 } else { 00811 /* Closing failed, restore some of the callbacks */ 00812 /* Closing of listen pcb will never fail! */ 00813 LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN)); 00814 tcp_sent(conn->pcb.tcp, sent_tcp); 00815 tcp_poll(conn->pcb.tcp, poll_tcp, 4); 00816 tcp_err(conn->pcb.tcp, err_tcp); 00817 tcp_arg(conn->pcb.tcp, conn); 00818 /* don't restore recv callback: we don't want to receive any more data */ 00819 } 00820 /* If closing didn't succeed, we get called again either 00821 from poll_tcp or from sent_tcp */ 00822 } 00823 #endif /* LWIP_TCP */ 00824 00825 /** 00826 * Delete the pcb inside a netconn. 00827 * Called from netconn_delete. 00828 * 00829 * @param msg the api_msg_msg pointing to the connection 00830 */ 00831 void 00832 do_delconn(struct api_msg_msg *msg) 00833 { 00834 /* @todo TCP: abort running write/connect? */ 00835 if ((msg->conn->state != NETCONN_NONE) && 00836 (msg->conn->state != NETCONN_LISTEN) && 00837 (msg->conn->state != NETCONN_CONNECT)) { 00838 /* this only happens for TCP netconns */ 00839 LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); 00840 msg->err = ERR_INPROGRESS; 00841 } else { 00842 LWIP_ASSERT("blocking connect in progress", 00843 (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); 00844 /* Drain and delete mboxes */ 00845 netconn_drain(msg->conn); 00846 00847 if (msg->conn->pcb.tcp != NULL) { 00848 00849 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 00850 #if LWIP_RAW 00851 case NETCONN_RAW: 00852 raw_remove(msg->conn->pcb.raw); 00853 break; 00854 #endif /* LWIP_RAW */ 00855 #if LWIP_UDP 00856 case NETCONN_UDP: 00857 msg->conn->pcb.udp->recv_arg = NULL; 00858 udp_remove(msg->conn->pcb.udp); 00859 break; 00860 #endif /* LWIP_UDP */ 00861 #if LWIP_TCP 00862 case NETCONN_TCP: 00863 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && 00864 msg->conn->write_offset == 0); 00865 msg->conn->state = NETCONN_CLOSE; 00866 msg->msg.sd.shut = NETCONN_SHUT_RDWR; 00867 msg->conn->current_msg = msg; 00868 do_close_internal(msg->conn); 00869 /* API_EVENT is called inside do_close_internal, before releasing 00870 the application thread, so we can return at this point! */ 00871 return; 00872 #endif /* LWIP_TCP */ 00873 default: 00874 break; 00875 } 00876 msg->conn->pcb.tcp = NULL; 00877 } 00878 /* tcp netconns don't come here! */ 00879 00880 /* @todo: this lets select make the socket readable and writable, 00881 which is wrong! errfd instead? */ 00882 API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); 00883 API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); 00884 } 00885 if (sys_sem_valid(&msg->conn->op_completed)) { 00886 sys_sem_signal(&msg->conn->op_completed); 00887 } 00888 } 00889 00890 /** 00891 * Bind a pcb contained in a netconn 00892 * Called from netconn_bind. 00893 * 00894 * @param msg the api_msg_msg pointing to the connection and containing 00895 * the IP address and port to bind to 00896 */ 00897 void 00898 do_bind(struct api_msg_msg *msg) 00899 { 00900 if (ERR_IS_FATAL(msg->conn->last_err)) { 00901 msg->err = msg->conn->last_err; 00902 } else { 00903 msg->err = ERR_VAL; 00904 if (msg->conn->pcb.tcp != NULL) { 00905 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 00906 #if LWIP_RAW 00907 case NETCONN_RAW: 00908 msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr); 00909 break; 00910 #endif /* LWIP_RAW */ 00911 #if LWIP_UDP 00912 case NETCONN_UDP: 00913 msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); 00914 break; 00915 #endif /* LWIP_UDP */ 00916 #if LWIP_TCP 00917 case NETCONN_TCP: 00918 msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port); 00919 break; 00920 #endif /* LWIP_TCP */ 00921 default: 00922 break; 00923 } 00924 } 00925 } 00926 TCPIP_APIMSG_ACK(msg); 00927 } 00928 00929 #if LWIP_TCP 00930 /** 00931 * TCP callback function if a connection (opened by tcp_connect/do_connect) has 00932 * been established (or reset by the remote host). 00933 * 00934 * @see tcp.h (struct tcp_pcb.connected) for parameters and return values 00935 */ 00936 static err_t 00937 do_connected(void *arg, struct tcp_pcb *pcb, err_t err) 00938 { 00939 struct netconn *conn; 00940 int was_blocking; 00941 00942 LWIP_UNUSED_ARG(pcb); 00943 00944 conn = (struct netconn *)arg; 00945 00946 if (conn == NULL) { 00947 return ERR_VAL; 00948 } 00949 00950 LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); 00951 LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", 00952 (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); 00953 00954 if (conn->current_msg != NULL) { 00955 conn->current_msg->err = err; 00956 } 00957 if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) { 00958 setup_tcp(conn); 00959 } 00960 was_blocking = !IN_NONBLOCKING_CONNECT(conn); 00961 SET_NONBLOCKING_CONNECT(conn, 0); 00962 conn->current_msg = NULL; 00963 conn->state = NETCONN_NONE; 00964 if (!was_blocking) { 00965 NETCONN_SET_SAFE_ERR(conn, ERR_OK); 00966 } 00967 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 00968 00969 if (was_blocking) { 00970 sys_sem_signal(&conn->op_completed); 00971 } 00972 return ERR_OK; 00973 } 00974 #endif /* LWIP_TCP */ 00975 00976 /** 00977 * Connect a pcb contained inside a netconn 00978 * Called from netconn_connect. 00979 * 00980 * @param msg the api_msg_msg pointing to the connection and containing 00981 * the IP address and port to connect to 00982 */ 00983 void 00984 do_connect(struct api_msg_msg *msg) 00985 { 00986 if (msg->conn->pcb.tcp == NULL) { 00987 /* This may happen when calling netconn_connect() a second time */ 00988 msg->err = ERR_CLSD; 00989 } else { 00990 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 00991 #if LWIP_RAW 00992 case NETCONN_RAW: 00993 msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); 00994 break; 00995 #endif /* LWIP_RAW */ 00996 #if LWIP_UDP 00997 case NETCONN_UDP: 00998 msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); 00999 break; 01000 #endif /* LWIP_UDP */ 01001 #if LWIP_TCP 01002 case NETCONN_TCP: 01003 /* Prevent connect while doing any other action. */ 01004 if (msg->conn->state != NETCONN_NONE) { 01005 msg->err = ERR_ISCONN; 01006 } else { 01007 setup_tcp(msg->conn); 01008 msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, 01009 msg->msg.bc.port, do_connected); 01010 if (msg->err == ERR_OK) { 01011 u8_t non_blocking = netconn_is_nonblocking(msg->conn); 01012 msg->conn->state = NETCONN_CONNECT; 01013 SET_NONBLOCKING_CONNECT(msg->conn, non_blocking); 01014 if (non_blocking) { 01015 msg->err = ERR_INPROGRESS; 01016 } else { 01017 msg->conn->current_msg = msg; 01018 /* sys_sem_signal() is called from do_connected (or err_tcp()), 01019 * when the connection is established! */ 01020 return; 01021 } 01022 } 01023 } 01024 break; 01025 #endif /* LWIP_TCP */ 01026 default: 01027 LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0)); 01028 break; 01029 } 01030 } 01031 sys_sem_signal(&msg->conn->op_completed); 01032 } 01033 01034 /** 01035 * Connect a pcb contained inside a netconn 01036 * Only used for UDP netconns. 01037 * Called from netconn_disconnect. 01038 * 01039 * @param msg the api_msg_msg pointing to the connection to disconnect 01040 */ 01041 void 01042 do_disconnect(struct api_msg_msg *msg) 01043 { 01044 #if LWIP_UDP 01045 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 01046 udp_disconnect(msg->conn->pcb.udp); 01047 msg->err = ERR_OK; 01048 } else 01049 #endif /* LWIP_UDP */ 01050 { 01051 msg->err = ERR_VAL; 01052 } 01053 TCPIP_APIMSG_ACK(msg); 01054 } 01055 01056 #if LWIP_TCP 01057 /** 01058 * Set a TCP pcb contained in a netconn into listen mode 01059 * Called from netconn_listen. 01060 * 01061 * @param msg the api_msg_msg pointing to the connection 01062 */ 01063 void 01064 do_listen(struct api_msg_msg *msg) 01065 { 01066 if (ERR_IS_FATAL(msg->conn->last_err)) { 01067 msg->err = msg->conn->last_err; 01068 } else { 01069 msg->err = ERR_CONN; 01070 if (msg->conn->pcb.tcp != NULL) { 01071 if (msg->conn->type == NETCONN_TCP) { 01072 if (msg->conn->state == NETCONN_NONE) { 01073 #if TCP_LISTEN_BACKLOG 01074 struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); 01075 #else /* TCP_LISTEN_BACKLOG */ 01076 struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp); 01077 #endif /* TCP_LISTEN_BACKLOG */ 01078 if (lpcb == NULL) { 01079 /* in this case, the old pcb is still allocated */ 01080 msg->err = ERR_MEM; 01081 } else { 01082 /* delete the recvmbox and allocate the acceptmbox */ 01083 if (sys_mbox_valid(&msg->conn->recvmbox)) { 01084 /** @todo: should we drain the recvmbox here? */ 01085 sys_mbox_free(&msg->conn->recvmbox); 01086 sys_mbox_set_invalid(&msg->conn->recvmbox); 01087 } 01088 msg->err = ERR_OK; 01089 if (!sys_mbox_valid(&msg->conn->acceptmbox)) { 01090 msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); 01091 } 01092 if (msg->err == ERR_OK) { 01093 msg->conn->state = NETCONN_LISTEN; 01094 msg->conn->pcb.tcp = lpcb; 01095 tcp_arg(msg->conn->pcb.tcp, msg->conn); 01096 tcp_accept(msg->conn->pcb.tcp, accept_function); 01097 } else { 01098 /* since the old pcb is already deallocated, free lpcb now */ 01099 tcp_close(lpcb); 01100 msg->conn->pcb.tcp = NULL; 01101 } 01102 } 01103 } 01104 } else { 01105 msg->err = ERR_ARG; 01106 } 01107 } 01108 } 01109 TCPIP_APIMSG_ACK(msg); 01110 } 01111 #endif /* LWIP_TCP */ 01112 01113 /** 01114 * Send some data on a RAW or UDP pcb contained in a netconn 01115 * Called from netconn_send 01116 * 01117 * @param msg the api_msg_msg pointing to the connection 01118 */ 01119 void 01120 do_send(struct api_msg_msg *msg) 01121 { 01122 if (ERR_IS_FATAL(msg->conn->last_err)) { 01123 msg->err = msg->conn->last_err; 01124 } else { 01125 msg->err = ERR_CONN; 01126 if (msg->conn->pcb.tcp != NULL) { 01127 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 01128 #if LWIP_RAW 01129 case NETCONN_RAW: 01130 if (ip_addr_isany(&msg->msg.b->addr)) { 01131 msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); 01132 } else { 01133 msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); 01134 } 01135 break; 01136 #endif 01137 #if LWIP_UDP 01138 case NETCONN_UDP: 01139 #if LWIP_CHECKSUM_ON_COPY 01140 if (ip_addr_isany(&msg->msg.b->addr)) { 01141 msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, 01142 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); 01143 } else { 01144 msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, 01145 &msg->msg.b->addr, msg->msg.b->port, 01146 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); 01147 } 01148 #else /* LWIP_CHECKSUM_ON_COPY */ 01149 if (ip_addr_isany(&msg->msg.b->addr)) { 01150 msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); 01151 } else { 01152 msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port); 01153 } 01154 #endif /* LWIP_CHECKSUM_ON_COPY */ 01155 break; 01156 #endif /* LWIP_UDP */ 01157 default: 01158 break; 01159 } 01160 } 01161 } 01162 TCPIP_APIMSG_ACK(msg); 01163 } 01164 01165 #if LWIP_TCP 01166 /** 01167 * Indicate data has been received from a TCP pcb contained in a netconn 01168 * Called from netconn_recv 01169 * 01170 * @param msg the api_msg_msg pointing to the connection 01171 */ 01172 void 01173 do_recv(struct api_msg_msg *msg) 01174 { 01175 msg->err = ERR_OK; 01176 if (msg->conn->pcb.tcp != NULL) { 01177 if (msg->conn->type == NETCONN_TCP) { 01178 #if TCP_LISTEN_BACKLOG 01179 if (msg->conn->pcb.tcp->state == LISTEN) { 01180 tcp_accepted(msg->conn->pcb.tcp); 01181 } else 01182 #endif /* TCP_LISTEN_BACKLOG */ 01183 { 01184 u32_t remaining = msg->msg.r.len; 01185 do { 01186 u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining; 01187 tcp_recved(msg->conn->pcb.tcp, recved); 01188 remaining -= recved; 01189 }while(remaining != 0); 01190 } 01191 } 01192 } 01193 TCPIP_APIMSG_ACK(msg); 01194 } 01195 01196 /** 01197 * See if more data needs to be written from a previous call to netconn_write. 01198 * Called initially from do_write. If the first call can't send all data 01199 * (because of low memory or empty send-buffer), this function is called again 01200 * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the 01201 * blocking application thread (waiting in netconn_write) is released. 01202 * 01203 * @param conn netconn (that is currently in state NETCONN_WRITE) to process 01204 * @return ERR_OK 01205 * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished 01206 */ 01207 static err_t 01208 do_writemore(struct netconn *conn) 01209 { 01210 err_t err; 01211 void *dataptr; 01212 u16_t len, available; 01213 u8_t write_finished = 0; 01214 size_t diff; 01215 u8_t dontblock = netconn_is_nonblocking(conn) || 01216 (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK); 01217 u8_t apiflags = conn->current_msg->msg.w.apiflags; 01218 01219 LWIP_ASSERT("conn != NULL", conn != NULL); 01220 LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); 01221 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 01222 LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); 01223 LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len", 01224 conn->write_offset < conn->current_msg->msg.w.len); 01225 01226 #if LWIP_SO_SNDTIMEO 01227 if ((conn->send_timeout != 0) && 01228 ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) { 01229 write_finished = 1; 01230 if (conn->write_offset == 0) { 01231 /* nothing has been written */ 01232 err = ERR_WOULDBLOCK; 01233 conn->current_msg->msg.w.len = 0; 01234 } else { 01235 /* partial write */ 01236 err = ERR_OK; 01237 conn->current_msg->msg.w.len = conn->write_offset; 01238 } 01239 } else 01240 #endif /* LWIP_SO_SNDTIMEO */ 01241 { 01242 dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset; 01243 diff = conn->current_msg->msg.w.len - conn->write_offset; 01244 if (diff > 0xffffUL) { /* max_u16_t */ 01245 len = 0xffff; 01246 #if LWIP_TCPIP_CORE_LOCKING 01247 conn->flags |= NETCONN_FLAG_WRITE_DELAYED; 01248 #endif 01249 apiflags |= TCP_WRITE_FLAG_MORE; 01250 } else { 01251 len = (u16_t)diff; 01252 } 01253 available = tcp_sndbuf(conn->pcb.tcp); 01254 if (available < len) { 01255 /* don't try to write more than sendbuf */ 01256 len = available; 01257 if (dontblock){ 01258 if (!len) { 01259 err = ERR_WOULDBLOCK; 01260 goto err_mem; 01261 } 01262 } else { 01263 #if LWIP_TCPIP_CORE_LOCKING 01264 conn->flags |= NETCONN_FLAG_WRITE_DELAYED; 01265 #endif 01266 apiflags |= TCP_WRITE_FLAG_MORE; 01267 } 01268 } 01269 LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); 01270 err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); 01271 /* if OK or memory error, check available space */ 01272 if ((err == ERR_OK) || (err == ERR_MEM)) { 01273 err_mem: 01274 if (dontblock && (len < conn->current_msg->msg.w.len)) { 01275 /* non-blocking write did not write everything: mark the pcb non-writable 01276 and let poll_tcp check writable space to mark the pcb writable again */ 01277 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); 01278 conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; 01279 } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || 01280 (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { 01281 /* The queued byte- or pbuf-count exceeds the configured low-water limit, 01282 let select mark this pcb as non-writable. */ 01283 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); 01284 } 01285 } 01286 01287 if (err == ERR_OK) { 01288 conn->write_offset += len; 01289 if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) { 01290 /* return sent length */ 01291 conn->current_msg->msg.w.len = conn->write_offset; 01292 /* everything was written */ 01293 write_finished = 1; 01294 conn->write_offset = 0; 01295 } 01296 tcp_output(conn->pcb.tcp); 01297 } else if ((err == ERR_MEM) && !dontblock) { 01298 /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called 01299 we do NOT return to the application thread, since ERR_MEM is 01300 only a temporary error! */ 01301 01302 /* tcp_write returned ERR_MEM, try tcp_output anyway */ 01303 tcp_output(conn->pcb.tcp); 01304 01305 #if LWIP_TCPIP_CORE_LOCKING 01306 conn->flags |= NETCONN_FLAG_WRITE_DELAYED; 01307 #endif 01308 } else { 01309 /* On errors != ERR_MEM, we don't try writing any more but return 01310 the error to the application thread. */ 01311 write_finished = 1; 01312 conn->current_msg->msg.w.len = 0; 01313 } 01314 } 01315 if (write_finished) { 01316 /* everything was written: set back connection state 01317 and back to application task */ 01318 conn->current_msg->err = err; 01319 conn->current_msg = NULL; 01320 conn->state = NETCONN_NONE; 01321 #if LWIP_TCPIP_CORE_LOCKING 01322 if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0) 01323 #endif 01324 { 01325 sys_sem_signal(&conn->op_completed); 01326 } 01327 } 01328 #if LWIP_TCPIP_CORE_LOCKING 01329 else 01330 return ERR_MEM; 01331 #endif 01332 return ERR_OK; 01333 } 01334 #endif /* LWIP_TCP */ 01335 01336 /** 01337 * Send some data on a TCP pcb contained in a netconn 01338 * Called from netconn_write 01339 * 01340 * @param msg the api_msg_msg pointing to the connection 01341 */ 01342 void 01343 do_write(struct api_msg_msg *msg) 01344 { 01345 if (ERR_IS_FATAL(msg->conn->last_err)) { 01346 msg->err = msg->conn->last_err; 01347 } else { 01348 if (msg->conn->type == NETCONN_TCP) { 01349 #if LWIP_TCP 01350 if (msg->conn->state != NETCONN_NONE) { 01351 /* netconn is connecting, closing or in blocking write */ 01352 msg->err = ERR_INPROGRESS; 01353 } else if (msg->conn->pcb.tcp != NULL) { 01354 msg->conn->state = NETCONN_WRITE; 01355 /* set all the variables used by do_writemore */ 01356 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && 01357 msg->conn->write_offset == 0); 01358 LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0); 01359 msg->conn->current_msg = msg; 01360 msg->conn->write_offset = 0; 01361 #if LWIP_TCPIP_CORE_LOCKING 01362 msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED; 01363 if (do_writemore(msg->conn) != ERR_OK) { 01364 LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); 01365 UNLOCK_TCPIP_CORE(); 01366 sys_arch_sem_wait(&msg->conn->op_completed, 0); 01367 LOCK_TCPIP_CORE(); 01368 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); 01369 } 01370 #else /* LWIP_TCPIP_CORE_LOCKING */ 01371 do_writemore(msg->conn); 01372 #endif /* LWIP_TCPIP_CORE_LOCKING */ 01373 /* for both cases: if do_writemore was called, don't ACK the APIMSG 01374 since do_writemore ACKs it! */ 01375 return; 01376 } else { 01377 msg->err = ERR_CONN; 01378 } 01379 #else /* LWIP_TCP */ 01380 msg->err = ERR_VAL; 01381 #endif /* LWIP_TCP */ 01382 #if (LWIP_UDP || LWIP_RAW) 01383 } else { 01384 msg->err = ERR_VAL; 01385 #endif /* (LWIP_UDP || LWIP_RAW) */ 01386 } 01387 } 01388 TCPIP_APIMSG_ACK(msg); 01389 } 01390 01391 /** 01392 * Return a connection's local or remote address 01393 * Called from netconn_getaddr 01394 * 01395 * @param msg the api_msg_msg pointing to the connection 01396 */ 01397 void 01398 do_getaddr(struct api_msg_msg *msg) 01399 { 01400 if (msg->conn->pcb.ip != NULL) { 01401 *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip : 01402 msg->conn->pcb.ip->remote_ip); 01403 01404 msg->err = ERR_OK; 01405 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 01406 #if LWIP_RAW 01407 case NETCONN_RAW: 01408 if (msg->msg.ad.local) { 01409 *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; 01410 } else { 01411 /* return an error as connecting is only a helper for upper layers */ 01412 msg->err = ERR_CONN; 01413 } 01414 break; 01415 #endif /* LWIP_RAW */ 01416 #if LWIP_UDP 01417 case NETCONN_UDP: 01418 if (msg->msg.ad.local) { 01419 *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; 01420 } else { 01421 if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { 01422 msg->err = ERR_CONN; 01423 } else { 01424 *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; 01425 } 01426 } 01427 break; 01428 #endif /* LWIP_UDP */ 01429 #if LWIP_TCP 01430 case NETCONN_TCP: 01431 *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port); 01432 break; 01433 #endif /* LWIP_TCP */ 01434 default: 01435 LWIP_ASSERT("invalid netconn_type", 0); 01436 break; 01437 } 01438 } else { 01439 msg->err = ERR_CONN; 01440 } 01441 TCPIP_APIMSG_ACK(msg); 01442 } 01443 01444 /** 01445 * Close a TCP pcb contained in a netconn 01446 * Called from netconn_close 01447 * 01448 * @param msg the api_msg_msg pointing to the connection 01449 */ 01450 void 01451 do_close(struct api_msg_msg *msg) 01452 { 01453 #if LWIP_TCP 01454 /* @todo: abort running write/connect? */ 01455 if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) { 01456 /* this only happens for TCP netconns */ 01457 LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); 01458 msg->err = ERR_INPROGRESS; 01459 } else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { 01460 if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) { 01461 /* LISTEN doesn't support half shutdown */ 01462 msg->err = ERR_CONN; 01463 } else { 01464 if (msg->msg.sd.shut & NETCONN_SHUT_RD) { 01465 /* Drain and delete mboxes */ 01466 netconn_drain(msg->conn); 01467 } 01468 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && 01469 msg->conn->write_offset == 0); 01470 msg->conn->state = NETCONN_CLOSE; 01471 msg->conn->current_msg = msg; 01472 do_close_internal(msg->conn); 01473 /* for tcp netconns, do_close_internal ACKs the message */ 01474 return; 01475 } 01476 } else 01477 #endif /* LWIP_TCP */ 01478 { 01479 msg->err = ERR_VAL; 01480 } 01481 sys_sem_signal(&msg->conn->op_completed); 01482 } 01483 01484 #if LWIP_IGMP 01485 /** 01486 * Join multicast groups for UDP netconns. 01487 * Called from netconn_join_leave_group 01488 * 01489 * @param msg the api_msg_msg pointing to the connection 01490 */ 01491 void 01492 do_join_leave_group(struct api_msg_msg *msg) 01493 { 01494 if (ERR_IS_FATAL(msg->conn->last_err)) { 01495 msg->err = msg->conn->last_err; 01496 } else { 01497 if (msg->conn->pcb.tcp != NULL) { 01498 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 01499 #if LWIP_UDP 01500 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 01501 msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); 01502 } else { 01503 msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); 01504 } 01505 #endif /* LWIP_UDP */ 01506 #if (LWIP_TCP || LWIP_RAW) 01507 } else { 01508 msg->err = ERR_VAL; 01509 #endif /* (LWIP_TCP || LWIP_RAW) */ 01510 } 01511 } else { 01512 msg->err = ERR_CONN; 01513 } 01514 } 01515 TCPIP_APIMSG_ACK(msg); 01516 } 01517 #endif /* LWIP_IGMP */ 01518 01519 #if LWIP_DNS 01520 /** 01521 * Callback function that is called when DNS name is resolved 01522 * (or on timeout). A waiting application thread is waked up by 01523 * signaling the semaphore. 01524 */ 01525 static void 01526 do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) 01527 { 01528 struct dns_api_msg *msg = (struct dns_api_msg*)arg; 01529 01530 LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0); 01531 LWIP_UNUSED_ARG(name); 01532 01533 if (ipaddr == NULL) { 01534 /* timeout or memory error */ 01535 *msg->err = ERR_VAL; 01536 } else { 01537 /* address was resolved */ 01538 *msg->err = ERR_OK; 01539 *msg->addr = *ipaddr; 01540 } 01541 /* wake up the application task waiting in netconn_gethostbyname */ 01542 sys_sem_signal(msg->sem); 01543 01544 } 01545 01546 /** 01547 * Execute a DNS query 01548 * Called from netconn_gethostbyname 01549 * 01550 * @param arg the dns_api_msg pointing to the query 01551 */ 01552 void 01553 do_gethostbyname(void *arg) 01554 { 01555 struct dns_api_msg *msg = (struct dns_api_msg*)arg; 01556 01557 *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg); 01558 if (*msg->err != ERR_INPROGRESS) { 01559 /* on error or immediate success, wake up the application 01560 * task waiting in netconn_gethostbyname */ 01561 sys_sem_signal(msg->sem); 01562 } 01563 } 01564 #endif /* LWIP_DNS */ 01565 01566 #endif /* LWIP_NETCONN */
Generated on Tue Jul 12 2022 21:19:01 by
1.7.2
