Ethernet for Nucleo and Disco board STM32F746 works with gcc and arm. IAC is untested
Dependents: STM32F746_iothub_client_sample_mqtt DISCO-F746NG_Ethernet Nucleo_F746ZG_Ethernet thethingsiO-DISCO_F746NG-mqtt ... 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 /* 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 18:14:54 by 1.7.2