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.
Dependents: mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more
lwip_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/priv/api_msg.h" 00044 00045 #include "lwip/ip.h" 00046 #include "lwip/ip_addr.h" 00047 #include "lwip/udp.h" 00048 #include "lwip/tcp.h" 00049 #include "lwip/raw.h" 00050 00051 #include "lwip/memp.h" 00052 #include "lwip/igmp.h" 00053 #include "lwip/dns.h" 00054 #include "lwip/mld6.h" 00055 #include "lwip/priv/tcpip_priv.h" 00056 00057 #include <string.h> 00058 00059 /* netconns are polled once per second (e.g. continue write on memory error) */ 00060 #define NETCONN_TCP_POLL_INTERVAL 2 00061 00062 #define SET_NONBLOCKING_CONNECT(conn, val) do { if (val) { \ 00063 (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \ 00064 } else { \ 00065 (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0) 00066 #define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0) 00067 00068 /* forward declarations */ 00069 #if LWIP_TCP 00070 #if LWIP_TCPIP_CORE_LOCKING 00071 #define WRITE_DELAYED , 1 00072 #define WRITE_DELAYED_PARAM , u8_t delayed 00073 #else /* LWIP_TCPIP_CORE_LOCKING */ 00074 #define WRITE_DELAYED 00075 #define WRITE_DELAYED_PARAM 00076 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00077 static err_t lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM); 00078 static err_t lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM); 00079 #endif 00080 00081 #if LWIP_TCPIP_CORE_LOCKING 00082 #define TCPIP_APIMSG_ACK(m) NETCONN_SET_SAFE_ERR((m)->conn, (m)->err) 00083 #else /* LWIP_TCPIP_CORE_LOCKING */ 00084 #define TCPIP_APIMSG_ACK(m) do { NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0) 00085 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00086 00087 #if LWIP_TCP 00088 u8_t netconn_aborted; 00089 #endif /* LWIP_TCP */ 00090 00091 #if LWIP_RAW 00092 /** 00093 * Receive callback function for RAW netconns. 00094 * Doesn't 'eat' the packet, only copies it and sends it to 00095 * conn->recvmbox 00096 * 00097 * @see raw.h (struct raw_pcb.recv) for parameters and return value 00098 */ 00099 static u8_t 00100 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, 00101 const ip_addr_t *addr) 00102 { 00103 struct pbuf *q; 00104 struct netbuf *buf; 00105 struct netconn *conn; 00106 00107 LWIP_UNUSED_ARG(addr); 00108 conn = (struct netconn *)arg; 00109 00110 if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) { 00111 #if LWIP_SO_RCVBUF 00112 int recv_avail; 00113 SYS_ARCH_GET(conn->recv_avail, recv_avail); 00114 if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) { 00115 return 0; 00116 } 00117 #endif /* LWIP_SO_RCVBUF */ 00118 /* copy the whole packet into new pbufs */ 00119 q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); 00120 if (q != NULL) { 00121 if (pbuf_copy(q, p) != ERR_OK) { 00122 pbuf_free(q); 00123 q = NULL; 00124 } 00125 } 00126 00127 if (q != NULL) { 00128 u16_t len; 00129 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 00130 if (buf == NULL) { 00131 pbuf_free(q); 00132 return 0; 00133 } 00134 00135 buf->p = q; 00136 buf->ptr = q; 00137 ip_addr_copy(buf->addr, *ip_current_src_addr()); 00138 buf->port = pcb->protocol; 00139 00140 len = q->tot_len; 00141 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { 00142 netbuf_delete(buf); 00143 return 0; 00144 } else { 00145 #if LWIP_SO_RCVBUF 00146 SYS_ARCH_INC(conn->recv_avail, len); 00147 #endif /* LWIP_SO_RCVBUF */ 00148 /* Register event with callback */ 00149 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 00150 } 00151 } 00152 } 00153 00154 return 0; /* do not eat the packet */ 00155 } 00156 #endif /* LWIP_RAW*/ 00157 00158 #if LWIP_UDP 00159 /** 00160 * Receive callback function for UDP netconns. 00161 * Posts the packet to conn->recvmbox or deletes it on memory error. 00162 * 00163 * @see udp.h (struct udp_pcb.recv) for parameters 00164 */ 00165 static void 00166 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, 00167 const ip_addr_t *addr, u16_t port) 00168 { 00169 struct netbuf *buf; 00170 struct netconn *conn; 00171 u16_t len; 00172 #if LWIP_SO_RCVBUF 00173 int recv_avail; 00174 #endif /* LWIP_SO_RCVBUF */ 00175 00176 LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ 00177 LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); 00178 LWIP_ASSERT("recv_udp must have an argument", arg != NULL); 00179 conn = (struct netconn *)arg; 00180 LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); 00181 00182 #if LWIP_SO_RCVBUF 00183 SYS_ARCH_GET(conn->recv_avail, recv_avail); 00184 if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) || 00185 ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { 00186 #else /* LWIP_SO_RCVBUF */ 00187 if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) { 00188 #endif /* LWIP_SO_RCVBUF */ 00189 pbuf_free(p); 00190 return; 00191 } 00192 00193 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 00194 if (buf == NULL) { 00195 pbuf_free(p); 00196 return; 00197 } else { 00198 buf->p = p; 00199 buf->ptr = p; 00200 ip_addr_set(&buf->addr, addr); 00201 buf->port = port; 00202 #if LWIP_NETBUF_RECVINFO 00203 { 00204 /* get the UDP header - always in the first pbuf, ensured by udp_input */ 00205 const struct udp_hdr* udphdr = (const struct udp_hdr*)ip_next_header_ptr(); 00206 #if LWIP_CHECKSUM_ON_COPY 00207 buf->flags = NETBUF_FLAG_DESTADDR; 00208 #endif /* LWIP_CHECKSUM_ON_COPY */ 00209 ip_addr_set(&buf->toaddr, ip_current_dest_addr()); 00210 buf->toport_chksum = udphdr->dest; 00211 } 00212 #endif /* LWIP_NETBUF_RECVINFO */ 00213 } 00214 00215 len = p->tot_len; 00216 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { 00217 netbuf_delete(buf); 00218 return; 00219 } else { 00220 #if LWIP_SO_RCVBUF 00221 SYS_ARCH_INC(conn->recv_avail, len); 00222 #endif /* LWIP_SO_RCVBUF */ 00223 /* Register event with callback */ 00224 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 00225 } 00226 } 00227 #endif /* LWIP_UDP */ 00228 00229 #if LWIP_TCP 00230 /** 00231 * Receive callback function for TCP netconns. 00232 * Posts the packet to conn->recvmbox, but doesn't delete it on errors. 00233 * 00234 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value 00235 */ 00236 static err_t 00237 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) 00238 { 00239 struct netconn *conn; 00240 u16_t len; 00241 00242 LWIP_UNUSED_ARG(pcb); 00243 LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); 00244 LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); 00245 conn = (struct netconn *)arg; 00246 00247 if (conn == NULL) { 00248 return ERR_VAL; 00249 } 00250 LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); 00251 00252 if (!sys_mbox_valid(&conn->recvmbox)) { 00253 /* recvmbox already deleted */ 00254 if (p != NULL) { 00255 tcp_recved(pcb, p->tot_len); 00256 pbuf_free(p); 00257 } 00258 return ERR_OK; 00259 } 00260 /* Unlike for UDP or RAW pcbs, don't check for available space 00261 using recv_avail since that could break the connection 00262 (data is already ACKed) */ 00263 00264 /* don't overwrite fatal errors! */ 00265 if (err != ERR_OK) { 00266 NETCONN_SET_SAFE_ERR(conn, err); 00267 } 00268 00269 if (p != NULL) { 00270 len = p->tot_len; 00271 } else { 00272 len = 0; 00273 } 00274 00275 if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) { 00276 /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */ 00277 return ERR_MEM; 00278 } else { 00279 #if LWIP_SO_RCVBUF 00280 SYS_ARCH_INC(conn->recv_avail, len); 00281 #endif /* LWIP_SO_RCVBUF */ 00282 /* Register event with callback */ 00283 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 00284 } 00285 00286 return ERR_OK; 00287 } 00288 00289 /** 00290 * Poll callback function for TCP netconns. 00291 * Wakes up an application thread that waits for a connection to close 00292 * or data to be sent. The application thread then takes the 00293 * appropriate action to go on. 00294 * 00295 * Signals the conn->sem. 00296 * netconn_close waits for conn->sem if closing failed. 00297 * 00298 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value 00299 */ 00300 static err_t 00301 poll_tcp(void *arg, struct tcp_pcb *pcb) 00302 { 00303 struct netconn *conn = (struct netconn *)arg; 00304 00305 LWIP_UNUSED_ARG(pcb); 00306 LWIP_ASSERT("conn != NULL", (conn != NULL)); 00307 00308 if (conn->state == NETCONN_WRITE) { 00309 lwip_netconn_do_writemore(conn WRITE_DELAYED); 00310 } else if (conn->state == NETCONN_CLOSE) { 00311 #if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER 00312 if (conn->current_msg && conn->current_msg->msg.sd.polls_left) { 00313 conn->current_msg->msg.sd.polls_left--; 00314 } 00315 #endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */ 00316 lwip_netconn_do_close_internal(conn WRITE_DELAYED); 00317 } 00318 /* @todo: implement connect timeout here? */ 00319 00320 /* Did a nonblocking write fail before? Then check available write-space. */ 00321 if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) { 00322 /* If the queued byte- or pbuf-count drops below the configured low-water limit, 00323 let select mark this pcb as writable again. */ 00324 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && 00325 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { 00326 conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; 00327 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 00328 } 00329 } 00330 00331 return ERR_OK; 00332 } 00333 00334 /** 00335 * Sent callback function for TCP netconns. 00336 * Signals the conn->sem and calls API_EVENT. 00337 * netconn_write waits for conn->sem if send buffer is low. 00338 * 00339 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value 00340 */ 00341 static err_t 00342 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) 00343 { 00344 struct netconn *conn = (struct netconn *)arg; 00345 00346 LWIP_UNUSED_ARG(pcb); 00347 LWIP_ASSERT("conn != NULL", (conn != NULL)); 00348 00349 if (conn) { 00350 if (conn->state == NETCONN_WRITE) { 00351 lwip_netconn_do_writemore(conn WRITE_DELAYED); 00352 } else if (conn->state == NETCONN_CLOSE) { 00353 lwip_netconn_do_close_internal(conn WRITE_DELAYED); 00354 } 00355 00356 /* If the queued byte- or pbuf-count drops below the configured low-water limit, 00357 let select mark this pcb as writable again. */ 00358 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && 00359 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { 00360 conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; 00361 API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); 00362 } 00363 } 00364 00365 return ERR_OK; 00366 } 00367 00368 /** 00369 * Error callback function for TCP netconns. 00370 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. 00371 * The application thread has then to decide what to do. 00372 * 00373 * @see tcp.h (struct tcp_pcb.err) for parameters 00374 */ 00375 static void 00376 err_tcp(void *arg, err_t err) 00377 { 00378 struct netconn *conn; 00379 enum netconn_state old_state; 00380 00381 conn = (struct netconn *)arg; 00382 LWIP_ASSERT("conn != NULL", (conn != NULL)); 00383 00384 conn->pcb.tcp = NULL; 00385 00386 /* reset conn->state now before waking up other threads */ 00387 old_state = conn->state; 00388 conn->state = NETCONN_NONE; 00389 00390 if (old_state == NETCONN_CLOSE) { 00391 /* RST during close: let close return success & dealloc the netconn */ 00392 err = ERR_OK; 00393 NETCONN_SET_SAFE_ERR(conn, ERR_OK); 00394 } else { 00395 /* no check since this is always fatal! */ 00396 SYS_ARCH_SET(conn->last_err, err); 00397 } 00398 00399 /* @todo: the type of NETCONN_EVT created should depend on 'old_state' */ 00400 00401 /* Notify the user layer about a connection error. Used to signal select. */ 00402 API_EVENT(conn, NETCONN_EVT_ERROR, 0); 00403 /* Try to release selects pending on 'read' or 'write', too. 00404 They will get an error if they actually try to read or write. */ 00405 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 00406 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 00407 00408 /* pass NULL-message to recvmbox to wake up pending recv */ 00409 if (sys_mbox_valid(&conn->recvmbox)) { 00410 /* use trypost to prevent deadlock */ 00411 sys_mbox_trypost(&conn->recvmbox, NULL); 00412 } 00413 /* pass NULL-message to acceptmbox to wake up pending accept */ 00414 if (sys_mbox_valid(&conn->acceptmbox)) { 00415 /* use trypost to preven deadlock */ 00416 sys_mbox_trypost(&conn->acceptmbox, NULL); 00417 } 00418 00419 if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || 00420 (old_state == NETCONN_CONNECT)) { 00421 /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary 00422 since the pcb has already been deleted! */ 00423 int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn); 00424 SET_NONBLOCKING_CONNECT(conn, 0); 00425 00426 if (!was_nonblocking_connect) { 00427 sys_sem_t* op_completed_sem; 00428 /* set error return code */ 00429 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 00430 conn->current_msg->err = err; 00431 op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 00432 LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem)); 00433 conn->current_msg = NULL; 00434 /* wake up the waiting task */ 00435 NETCONN_SET_SAFE_ERR(conn, err); 00436 sys_sem_signal(op_completed_sem); 00437 } 00438 } else { 00439 LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL); 00440 } 00441 } 00442 00443 /** 00444 * Setup a tcp_pcb with the correct callback function pointers 00445 * and their arguments. 00446 * 00447 * @param conn the TCP netconn to setup 00448 */ 00449 static void 00450 setup_tcp(struct netconn *conn) 00451 { 00452 struct tcp_pcb *pcb; 00453 00454 pcb = conn->pcb.tcp; 00455 tcp_arg(pcb, conn); 00456 tcp_recv(pcb, recv_tcp); 00457 tcp_sent(pcb, sent_tcp); 00458 tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL); 00459 tcp_err(pcb, err_tcp); 00460 } 00461 00462 /** 00463 * Accept callback function for TCP netconns. 00464 * Allocates a new netconn and posts that to conn->acceptmbox. 00465 * 00466 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value 00467 */ 00468 static err_t 00469 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) 00470 { 00471 struct netconn *newconn; 00472 struct netconn *conn = (struct netconn *)arg; 00473 00474 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state))); 00475 00476 if (conn == NULL) { 00477 return ERR_VAL; 00478 } 00479 if (!sys_mbox_valid(&conn->acceptmbox)) { 00480 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n")); 00481 return ERR_VAL; 00482 } 00483 00484 if (newpcb == NULL) { 00485 /* out-of-pcbs during connect: pass on this error to the application */ 00486 if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) { 00487 /* Register event with callback */ 00488 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 00489 } 00490 return ERR_VAL; 00491 } 00492 00493 /* We have to set the callback here even though 00494 * the new socket is unknown. newconn->socket is marked as -1. */ 00495 newconn = netconn_alloc(conn->type, conn->callback); 00496 if (newconn == NULL) { 00497 /* outof netconns: pass on this error to the application */ 00498 if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) { 00499 /* Register event with callback */ 00500 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 00501 } 00502 return ERR_MEM; 00503 } 00504 newconn->pcb.tcp = newpcb; 00505 setup_tcp(newconn); 00506 /* no protection: when creating the pcb, the netconn is not yet known 00507 to the application thread */ 00508 newconn->last_err = err; 00509 00510 /* handle backlog counter */ 00511 tcp_backlog_delayed(newpcb); 00512 00513 if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) { 00514 /* When returning != ERR_OK, the pcb is aborted in tcp_process(), 00515 so do nothing here! */ 00516 /* remove all references to this netconn from the pcb */ 00517 struct tcp_pcb* pcb = newconn->pcb.tcp; 00518 tcp_arg(pcb, NULL); 00519 tcp_recv(pcb, NULL); 00520 tcp_sent(pcb, NULL); 00521 tcp_poll(pcb, NULL, 0); 00522 tcp_err(pcb, NULL); 00523 /* remove reference from to the pcb from this netconn */ 00524 newconn->pcb.tcp = NULL; 00525 /* no need to drain since we know the recvmbox is empty. */ 00526 sys_mbox_free(&newconn->recvmbox); 00527 sys_mbox_set_invalid(&newconn->recvmbox); 00528 netconn_free(newconn); 00529 return ERR_MEM; 00530 } else { 00531 /* Register event with callback */ 00532 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 00533 } 00534 00535 return ERR_OK; 00536 } 00537 #endif /* LWIP_TCP */ 00538 00539 /** 00540 * Create a new pcb of a specific type. 00541 * Called from lwip_netconn_do_newconn(). 00542 * 00543 * @param msg the api_msg_msg describing the connection type 00544 */ 00545 static void 00546 pcb_new(struct api_msg *msg) 00547 { 00548 enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4; 00549 00550 LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); 00551 00552 #if LWIP_IPV6 && LWIP_IPV4 00553 /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */ 00554 if(NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) { 00555 iptype = IPADDR_TYPE_ANY; 00556 } 00557 #endif 00558 00559 /* Allocate a PCB for this connection */ 00560 switch(NETCONNTYPE_GROUP(msg->conn->type)) { 00561 #if LWIP_RAW 00562 case NETCONN_RAW: 00563 msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto); 00564 if (msg->conn->pcb.raw != NULL) { 00565 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); 00566 } 00567 break; 00568 #endif /* LWIP_RAW */ 00569 #if LWIP_UDP 00570 case NETCONN_UDP: 00571 msg->conn->pcb.udp = udp_new_ip_type(iptype); 00572 if (msg->conn->pcb.udp != NULL) { 00573 #if LWIP_UDPLITE 00574 if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { 00575 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); 00576 } 00577 #endif /* LWIP_UDPLITE */ 00578 if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) { 00579 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); 00580 } 00581 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); 00582 } 00583 break; 00584 #endif /* LWIP_UDP */ 00585 #if LWIP_TCP 00586 case NETCONN_TCP: 00587 msg->conn->pcb.tcp = tcp_new_ip_type(iptype); 00588 if (msg->conn->pcb.tcp != NULL) { 00589 setup_tcp(msg->conn); 00590 } 00591 break; 00592 #endif /* LWIP_TCP */ 00593 default: 00594 /* Unsupported netconn type, e.g. protocol disabled */ 00595 msg->err = ERR_VAL; 00596 return; 00597 } 00598 if (msg->conn->pcb.ip == NULL) { 00599 msg->err = ERR_MEM; 00600 } 00601 } 00602 00603 /** 00604 * Create a new pcb of a specific type inside a netconn. 00605 * Called from netconn_new_with_proto_and_callback. 00606 * 00607 * @param m the api_msg_msg describing the connection type 00608 */ 00609 void 00610 lwip_netconn_do_newconn(void *m) 00611 { 00612 struct api_msg *msg = (struct api_msg*)m; 00613 00614 msg->err = ERR_OK; 00615 if (msg->conn->pcb.tcp == NULL) { 00616 pcb_new(msg); 00617 } 00618 /* Else? This "new" connection already has a PCB allocated. */ 00619 /* Is this an error condition? Should it be deleted? */ 00620 /* We currently just are happy and return. */ 00621 00622 TCPIP_APIMSG_ACK(msg); 00623 } 00624 00625 /** 00626 * Create a new netconn (of a specific type) that has a callback function. 00627 * The corresponding pcb is NOT created! 00628 * 00629 * @param t the type of 'connection' to create (@see enum netconn_type) 00630 * @param callback a function to call on status changes (RX available, TX'ed) 00631 * @return a newly allocated struct netconn or 00632 * NULL on memory error 00633 */ 00634 struct netconn* 00635 netconn_alloc(enum netconn_type t, netconn_callback callback) 00636 { 00637 struct netconn *conn; 00638 int size; 00639 00640 conn = (struct netconn *)memp_malloc(MEMP_NETCONN); 00641 if (conn == NULL) { 00642 return NULL; 00643 } 00644 00645 conn->last_err = ERR_OK; 00646 conn->type = t; 00647 conn->pcb.tcp = NULL; 00648 00649 /* If all sizes are the same, every compiler should optimize this switch to nothing */ 00650 switch(NETCONNTYPE_GROUP(t)) { 00651 #if LWIP_RAW 00652 case NETCONN_RAW: 00653 size = DEFAULT_RAW_RECVMBOX_SIZE; 00654 break; 00655 #endif /* LWIP_RAW */ 00656 #if LWIP_UDP 00657 case NETCONN_UDP: 00658 size = DEFAULT_UDP_RECVMBOX_SIZE; 00659 break; 00660 #endif /* LWIP_UDP */ 00661 #if LWIP_TCP 00662 case NETCONN_TCP: 00663 size = DEFAULT_TCP_RECVMBOX_SIZE; 00664 break; 00665 #endif /* LWIP_TCP */ 00666 default: 00667 LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); 00668 goto free_and_return; 00669 } 00670 00671 if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { 00672 goto free_and_return; 00673 } 00674 #if !LWIP_NETCONN_SEM_PER_THREAD 00675 if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { 00676 sys_mbox_free(&conn->recvmbox); 00677 goto free_and_return; 00678 } 00679 #endif 00680 00681 #if LWIP_TCP 00682 sys_mbox_set_invalid(&conn->acceptmbox); 00683 #endif 00684 conn->state = NETCONN_NONE; 00685 #if LWIP_SOCKET 00686 /* initialize socket to -1 since 0 is a valid socket */ 00687 conn->socket = -1; 00688 #endif /* LWIP_SOCKET */ 00689 conn->callback = callback; 00690 #if LWIP_TCP 00691 conn->current_msg = NULL; 00692 conn->write_offset = 0; 00693 #endif /* LWIP_TCP */ 00694 #if LWIP_SO_SNDTIMEO 00695 conn->send_timeout = 0; 00696 #endif /* LWIP_SO_SNDTIMEO */ 00697 #if LWIP_SO_RCVTIMEO 00698 conn->recv_timeout = 0; 00699 #endif /* LWIP_SO_RCVTIMEO */ 00700 #if LWIP_SO_RCVBUF 00701 conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; 00702 conn->recv_avail = 0; 00703 #endif /* LWIP_SO_RCVBUF */ 00704 #if LWIP_SO_LINGER 00705 conn->linger = -1; 00706 #endif /* LWIP_SO_LINGER */ 00707 conn->flags = 0; 00708 return conn; 00709 free_and_return: 00710 memp_free(MEMP_NETCONN, conn); 00711 return NULL; 00712 } 00713 00714 /** 00715 * Delete a netconn and all its resources. 00716 * The pcb is NOT freed (since we might not be in the right thread context do this). 00717 * 00718 * @param conn the netconn to free 00719 */ 00720 void 00721 netconn_free(struct netconn *conn) 00722 { 00723 LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); 00724 LWIP_ASSERT("recvmbox must be deallocated before calling this function", 00725 !sys_mbox_valid(&conn->recvmbox)); 00726 #if LWIP_TCP 00727 LWIP_ASSERT("acceptmbox must be deallocated before calling this function", 00728 !sys_mbox_valid(&conn->acceptmbox)); 00729 #endif /* LWIP_TCP */ 00730 00731 #if !LWIP_NETCONN_SEM_PER_THREAD 00732 sys_sem_free(&conn->op_completed); 00733 sys_sem_set_invalid(&conn->op_completed); 00734 #endif 00735 00736 memp_free(MEMP_NETCONN, conn); 00737 } 00738 00739 /** 00740 * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in 00741 * these mboxes 00742 * 00743 * @param conn the netconn to free 00744 * @bytes_drained bytes drained from recvmbox 00745 * @accepts_drained pending connections drained from acceptmbox 00746 */ 00747 static void 00748 netconn_drain(struct netconn *conn) 00749 { 00750 void *mem; 00751 #if LWIP_TCP 00752 struct pbuf *p; 00753 #endif /* LWIP_TCP */ 00754 00755 /* This runs in tcpip_thread, so we don't need to lock against rx packets */ 00756 00757 /* Delete and drain the recvmbox. */ 00758 if (sys_mbox_valid(&conn->recvmbox)) { 00759 while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { 00760 #if LWIP_TCP 00761 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) { 00762 if (mem != NULL) { 00763 p = (struct pbuf*)mem; 00764 /* pcb might be set to NULL already by err_tcp() */ 00765 if (conn->pcb.tcp != NULL) { 00766 tcp_recved(conn->pcb.tcp, p->tot_len); 00767 } 00768 pbuf_free(p); 00769 } 00770 } else 00771 #endif /* LWIP_TCP */ 00772 { 00773 netbuf_delete((struct netbuf *)mem); 00774 } 00775 } 00776 sys_mbox_free(&conn->recvmbox); 00777 sys_mbox_set_invalid(&conn->recvmbox); 00778 } 00779 00780 /* Delete and drain the acceptmbox. */ 00781 #if LWIP_TCP 00782 if (sys_mbox_valid(&conn->acceptmbox)) { 00783 while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { 00784 if (mem != &netconn_aborted) { 00785 struct netconn *newconn = (struct netconn *)mem; 00786 /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ 00787 /* pcb might be set to NULL already by err_tcp() */ 00788 /* drain recvmbox */ 00789 netconn_drain(newconn); 00790 if (newconn->pcb.tcp != NULL) { 00791 tcp_abort(newconn->pcb.tcp); 00792 newconn->pcb.tcp = NULL; 00793 } 00794 netconn_free(newconn); 00795 } 00796 } 00797 sys_mbox_free(&conn->acceptmbox); 00798 sys_mbox_set_invalid(&conn->acceptmbox); 00799 } 00800 #endif /* LWIP_TCP */ 00801 } 00802 00803 #if LWIP_TCP 00804 /** 00805 * Internal helper function to close a TCP netconn: since this sometimes 00806 * doesn't work at the first attempt, this function is called from multiple 00807 * places. 00808 * 00809 * @param conn the TCP netconn to close 00810 */ 00811 static err_t 00812 lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM) 00813 { 00814 err_t err; 00815 u8_t shut, shut_rx, shut_tx, close; 00816 u8_t close_finished = 0; 00817 struct tcp_pcb* tpcb; 00818 #if LWIP_SO_LINGER 00819 u8_t linger_wait_required = 0; 00820 #endif /* LWIP_SO_LINGER */ 00821 00822 LWIP_ASSERT("invalid conn", (conn != NULL)); 00823 LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)); 00824 LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); 00825 LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); 00826 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 00827 00828 tpcb = conn->pcb.tcp; 00829 shut = conn->current_msg->msg.sd.shut; 00830 shut_rx = shut & NETCONN_SHUT_RD; 00831 shut_tx = shut & NETCONN_SHUT_WR; 00832 /* shutting down both ends is the same as closing 00833 (also if RD or WR side was shut down before already) */ 00834 if (shut == NETCONN_SHUT_RDWR) { 00835 close = 1; 00836 } else if (shut_rx && 00837 ((tpcb->state == FIN_WAIT_1) || 00838 (tpcb->state == FIN_WAIT_2) || 00839 (tpcb->state == CLOSING))) { 00840 close = 1; 00841 } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) { 00842 close = 1; 00843 } else { 00844 close = 0; 00845 } 00846 00847 /* Set back some callback pointers */ 00848 if (close) { 00849 tcp_arg(tpcb, NULL); 00850 } 00851 if (tpcb->state == LISTEN) { 00852 tcp_accept(tpcb, NULL); 00853 } else { 00854 /* some callbacks have to be reset if tcp_close is not successful */ 00855 if (shut_rx) { 00856 tcp_recv(tpcb, NULL); 00857 tcp_accept(tpcb, NULL); 00858 } 00859 if (shut_tx) { 00860 tcp_sent(tpcb, NULL); 00861 } 00862 if (close) { 00863 tcp_poll(tpcb, NULL, 0); 00864 tcp_err(tpcb, NULL); 00865 } 00866 } 00867 /* Try to close the connection */ 00868 if (close) { 00869 #if LWIP_SO_LINGER 00870 /* check linger possibilites before calling tcp_close */ 00871 err = ERR_OK; 00872 /* linger enabled/required at all? (i.e. is there untransmitted data left?) */ 00873 if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) { 00874 if ((conn->linger == 0)) { 00875 /* data left but linger prevents waiting */ 00876 tcp_abort(tpcb); 00877 tpcb = NULL; 00878 } else if (conn->linger > 0) { 00879 /* data left and linger says we should wait */ 00880 if (netconn_is_nonblocking(conn)) { 00881 /* data left on a nonblocking netconn -> cannot linger */ 00882 err = ERR_WOULDBLOCK; 00883 } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= 00884 (conn->linger * 1000)) { 00885 /* data left but linger timeout has expired (this happens on further 00886 calls to this function through poll_tcp */ 00887 tcp_abort(tpcb); 00888 tpcb = NULL; 00889 } else { 00890 /* data left -> need to wait for ACK after successful close */ 00891 linger_wait_required = 1; 00892 } 00893 } 00894 } 00895 if ((err == ERR_OK) && (tpcb != NULL)) 00896 #endif /* LWIP_SO_LINGER */ 00897 { 00898 err = tcp_close(tpcb); 00899 } 00900 } else { 00901 err = tcp_shutdown(tpcb, shut_rx, shut_tx); 00902 } 00903 if (err == ERR_OK) { 00904 close_finished = 1; 00905 #if LWIP_SO_LINGER 00906 if (linger_wait_required) { 00907 /* wait for ACK of all unsent/unacked data by just getting called again */ 00908 close_finished = 0; 00909 err = ERR_INPROGRESS; 00910 } 00911 #endif /* LWIP_SO_LINGER */ 00912 } else { 00913 if (err == ERR_MEM) { 00914 /* Closing failed because of memory shortage, try again later. Even for 00915 nonblocking netconns, we have to wait since no standard socket application 00916 is prepared for close failing because of resource shortage. 00917 Check the timeout: this is kind of an lwip addition to the standard sockets: 00918 we wait for some time when failing to allocate a segment for the FIN */ 00919 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER 00920 s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT; 00921 #if LWIP_SO_SNDTIMEO 00922 if (conn->send_timeout > 0) { 00923 close_timeout = conn->send_timeout; 00924 } 00925 #endif /* LWIP_SO_SNDTIMEO */ 00926 #if LWIP_SO_LINGER 00927 if (conn->linger >= 0) { 00928 /* use linger timeout (seconds) */ 00929 close_timeout = conn->linger * 1000U; 00930 } 00931 #endif 00932 if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) { 00933 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 00934 if (conn->current_msg->msg.sd.polls_left == 0) { 00935 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 00936 close_finished = 1; 00937 if (close) { 00938 /* in this case, we want to RST the connection */ 00939 tcp_abort(tpcb); 00940 err = ERR_OK; 00941 } 00942 } 00943 } else { 00944 /* Closing failed for a non-memory error: give up */ 00945 close_finished = 1; 00946 } 00947 } 00948 if (close_finished) { 00949 /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */ 00950 sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 00951 conn->current_msg->err = err; 00952 conn->current_msg = NULL; 00953 conn->state = NETCONN_NONE; 00954 if (err == ERR_OK) { 00955 if (close) { 00956 /* Set back some callback pointers as conn is going away */ 00957 conn->pcb.tcp = NULL; 00958 /* Trigger select() in socket layer. Make sure everybody notices activity 00959 on the connection, error first! */ 00960 API_EVENT(conn, NETCONN_EVT_ERROR, 0); 00961 } 00962 if (shut_rx) { 00963 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 00964 } 00965 if (shut_tx) { 00966 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 00967 } 00968 } 00969 NETCONN_SET_SAFE_ERR(conn, err); 00970 #if LWIP_TCPIP_CORE_LOCKING 00971 if (delayed) 00972 #endif 00973 { 00974 /* wake up the application task */ 00975 sys_sem_signal(op_completed_sem); 00976 } 00977 return ERR_OK; 00978 } 00979 if (!close_finished) { 00980 /* Closing failed and we want to wait: restore some of the callbacks */ 00981 /* Closing of listen pcb will never fail! */ 00982 LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN)); 00983 if (shut_tx) { 00984 tcp_sent(tpcb, sent_tcp); 00985 } 00986 /* when waiting for close, set up poll interval to 500ms */ 00987 tcp_poll(tpcb, poll_tcp, 1); 00988 tcp_err(tpcb, err_tcp); 00989 tcp_arg(tpcb, conn); 00990 /* don't restore recv callback: we don't want to receive any more data */ 00991 } 00992 /* If closing didn't succeed, we get called again either 00993 from poll_tcp or from sent_tcp */ 00994 LWIP_ASSERT("err != ERR_OK", err != ERR_OK); 00995 return err; 00996 } 00997 #endif /* LWIP_TCP */ 00998 00999 /** 01000 * Delete the pcb inside a netconn. 01001 * Called from netconn_delete. 01002 * 01003 * @param m the api_msg_msg pointing to the connection 01004 */ 01005 void 01006 lwip_netconn_do_delconn(void *m) 01007 { 01008 struct api_msg *msg = (struct api_msg*)m; 01009 01010 enum netconn_state state = msg->conn->state; 01011 LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */ 01012 (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP)); 01013 #if LWIP_NETCONN_FULLDUPLEX 01014 /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */ 01015 if (state != NETCONN_NONE) { 01016 if ((state == NETCONN_WRITE) || 01017 ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) { 01018 /* close requested, abort running write/connect */ 01019 sys_sem_t* op_completed_sem; 01020 LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); 01021 op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); 01022 msg->conn->current_msg->err = ERR_CLSD; 01023 msg->conn->current_msg = NULL; 01024 msg->conn->write_offset = 0; 01025 msg->conn->state = NETCONN_NONE; 01026 NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD); 01027 sys_sem_signal(op_completed_sem); 01028 } 01029 } 01030 #else /* LWIP_NETCONN_FULLDUPLEX */ 01031 if (((state != NETCONN_NONE) && 01032 (state != NETCONN_LISTEN) && 01033 (state != NETCONN_CONNECT)) || 01034 ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) { 01035 /* This means either a blocking write or blocking connect is running 01036 (nonblocking write returns and sets state to NONE) */ 01037 msg->err = ERR_INPROGRESS; 01038 } else 01039 #endif /* LWIP_NETCONN_FULLDUPLEX */ 01040 { 01041 LWIP_ASSERT("blocking connect in progress", 01042 (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); 01043 msg->err = ERR_OK; 01044 /* Drain and delete mboxes */ 01045 netconn_drain(msg->conn); 01046 01047 if (msg->conn->pcb.tcp != NULL) { 01048 01049 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 01050 #if LWIP_RAW 01051 case NETCONN_RAW: 01052 raw_remove(msg->conn->pcb.raw); 01053 break; 01054 #endif /* LWIP_RAW */ 01055 #if LWIP_UDP 01056 case NETCONN_UDP: 01057 msg->conn->pcb.udp->recv_arg = NULL; 01058 udp_remove(msg->conn->pcb.udp); 01059 break; 01060 #endif /* LWIP_UDP */ 01061 #if LWIP_TCP 01062 case NETCONN_TCP: 01063 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && 01064 msg->conn->write_offset == 0); 01065 msg->conn->state = NETCONN_CLOSE; 01066 msg->msg.sd.shut = NETCONN_SHUT_RDWR; 01067 msg->conn->current_msg = msg; 01068 #if LWIP_TCPIP_CORE_LOCKING 01069 if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) { 01070 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE); 01071 UNLOCK_TCPIP_CORE(); 01072 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 01073 LOCK_TCPIP_CORE(); 01074 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); 01075 } 01076 #else /* LWIP_TCPIP_CORE_LOCKING */ 01077 lwip_netconn_do_close_internal(msg->conn); 01078 #endif /* LWIP_TCPIP_CORE_LOCKING */ 01079 /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing 01080 the application thread, so we can return at this point! */ 01081 return; 01082 #endif /* LWIP_TCP */ 01083 default: 01084 break; 01085 } 01086 msg->conn->pcb.tcp = NULL; 01087 } 01088 /* tcp netconns don't come here! */ 01089 01090 /* @todo: this lets select make the socket readable and writable, 01091 which is wrong! errfd instead? */ 01092 API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); 01093 API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); 01094 } 01095 if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) { 01096 TCPIP_APIMSG_ACK(msg); 01097 } 01098 } 01099 01100 /** 01101 * Bind a pcb contained in a netconn 01102 * Called from netconn_bind. 01103 * 01104 * @param m the api_msg_msg pointing to the connection and containing 01105 * the IP address and port to bind to 01106 */ 01107 void 01108 lwip_netconn_do_bind(void *m) 01109 { 01110 struct api_msg *msg = (struct api_msg*)m; 01111 01112 if (ERR_IS_FATAL(msg->conn->last_err)) { 01113 msg->err = msg->conn->last_err; 01114 } else { 01115 msg->err = ERR_VAL; 01116 if (msg->conn->pcb.tcp != NULL) { 01117 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 01118 #if LWIP_RAW 01119 case NETCONN_RAW: 01120 msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); 01121 break; 01122 #endif /* LWIP_RAW */ 01123 #if LWIP_UDP 01124 case NETCONN_UDP: 01125 msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); 01126 break; 01127 #endif /* LWIP_UDP */ 01128 #if LWIP_TCP 01129 case NETCONN_TCP: 01130 msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); 01131 break; 01132 #endif /* LWIP_TCP */ 01133 default: 01134 break; 01135 } 01136 } 01137 } 01138 TCPIP_APIMSG_ACK(msg); 01139 } 01140 01141 #if LWIP_TCP 01142 /** 01143 * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has 01144 * been established (or reset by the remote host). 01145 * 01146 * @see tcp.h (struct tcp_pcb.connected) for parameters and return values 01147 */ 01148 static err_t 01149 lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) 01150 { 01151 struct netconn *conn; 01152 int was_blocking; 01153 sys_sem_t* op_completed_sem = NULL; 01154 01155 LWIP_UNUSED_ARG(pcb); 01156 01157 conn = (struct netconn *)arg; 01158 01159 if (conn == NULL) { 01160 return ERR_VAL; 01161 } 01162 01163 LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); 01164 LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", 01165 (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); 01166 01167 if (conn->current_msg != NULL) { 01168 conn->current_msg->err = err; 01169 op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 01170 } 01171 if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) { 01172 setup_tcp(conn); 01173 } 01174 was_blocking = !IN_NONBLOCKING_CONNECT(conn); 01175 SET_NONBLOCKING_CONNECT(conn, 0); 01176 LWIP_ASSERT("blocking connect state error", 01177 (was_blocking && op_completed_sem != NULL) || 01178 (!was_blocking && op_completed_sem == NULL)); 01179 conn->current_msg = NULL; 01180 conn->state = NETCONN_NONE; 01181 NETCONN_SET_SAFE_ERR(conn, ERR_OK); 01182 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 01183 01184 if (was_blocking) { 01185 sys_sem_signal(op_completed_sem); 01186 } 01187 return ERR_OK; 01188 } 01189 #endif /* LWIP_TCP */ 01190 01191 /** 01192 * Connect a pcb contained inside a netconn 01193 * Called from netconn_connect. 01194 * 01195 * @param m the api_msg_msg pointing to the connection and containing 01196 * the IP address and port to connect to 01197 */ 01198 void 01199 lwip_netconn_do_connect(void *m) 01200 { 01201 struct api_msg *msg = (struct api_msg*)m; 01202 01203 if (msg->conn->pcb.tcp == NULL) { 01204 /* This may happen when calling netconn_connect() a second time */ 01205 msg->err = ERR_CLSD; 01206 } else { 01207 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 01208 #if LWIP_RAW 01209 case NETCONN_RAW: 01210 msg->err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); 01211 break; 01212 #endif /* LWIP_RAW */ 01213 #if LWIP_UDP 01214 case NETCONN_UDP: 01215 msg->err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); 01216 break; 01217 #endif /* LWIP_UDP */ 01218 #if LWIP_TCP 01219 case NETCONN_TCP: 01220 /* Prevent connect while doing any other action. */ 01221 if (msg->conn->state == NETCONN_CONNECT) { 01222 msg->err = ERR_ALREADY; 01223 } else if (msg->conn->state != NETCONN_NONE) { 01224 msg->err = ERR_ISCONN; 01225 } else { 01226 setup_tcp(msg->conn); 01227 msg->err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), 01228 msg->msg.bc.port, lwip_netconn_do_connected); 01229 if (msg->err == ERR_OK) { 01230 u8_t non_blocking = netconn_is_nonblocking(msg->conn); 01231 msg->conn->state = NETCONN_CONNECT; 01232 SET_NONBLOCKING_CONNECT(msg->conn, non_blocking); 01233 if (non_blocking) { 01234 msg->err = ERR_INPROGRESS; 01235 } else { 01236 msg->conn->current_msg = msg; 01237 /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()), 01238 when the connection is established! */ 01239 #if LWIP_TCPIP_CORE_LOCKING 01240 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT); 01241 UNLOCK_TCPIP_CORE(); 01242 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 01243 LOCK_TCPIP_CORE(); 01244 LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT); 01245 #endif /* LWIP_TCPIP_CORE_LOCKING */ 01246 return; 01247 } 01248 } 01249 } 01250 break; 01251 #endif /* LWIP_TCP */ 01252 default: 01253 LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0)); 01254 break; 01255 } 01256 } 01257 /* For all other protocols, netconn_connect() calls TCPIP_APIMSG(), 01258 so use TCPIP_APIMSG_ACK() here. */ 01259 TCPIP_APIMSG_ACK(msg); 01260 } 01261 01262 /** 01263 * Disconnect a pcb contained inside a netconn 01264 * Only used for UDP netconns. 01265 * Called from netconn_disconnect. 01266 * 01267 * @param m the api_msg_msg pointing to the connection to disconnect 01268 */ 01269 void 01270 lwip_netconn_do_disconnect(void *m) 01271 { 01272 struct api_msg *msg = (struct api_msg*)m; 01273 01274 #if LWIP_UDP 01275 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 01276 udp_disconnect(msg->conn->pcb.udp); 01277 msg->err = ERR_OK; 01278 } else 01279 #endif /* LWIP_UDP */ 01280 { 01281 msg->err = ERR_VAL; 01282 } 01283 TCPIP_APIMSG_ACK(msg); 01284 } 01285 01286 #if LWIP_TCP 01287 /** 01288 * Set a TCP pcb contained in a netconn into listen mode 01289 * Called from netconn_listen. 01290 * 01291 * @param m the api_msg_msg pointing to the connection 01292 */ 01293 void 01294 lwip_netconn_do_listen(void *m) 01295 { 01296 struct api_msg *msg = (struct api_msg*)m; 01297 01298 if (ERR_IS_FATAL(msg->conn->last_err)) { 01299 msg->err = msg->conn->last_err; 01300 } else { 01301 msg->err = ERR_CONN; 01302 if (msg->conn->pcb.tcp != NULL) { 01303 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 01304 if (msg->conn->state == NETCONN_NONE) { 01305 struct tcp_pcb* lpcb; 01306 if (msg->conn->pcb.tcp->state != CLOSED) { 01307 /* connection is not closed, cannot listen */ 01308 msg->err = ERR_VAL; 01309 } else { 01310 err_t err; 01311 u8_t backlog; 01312 #if TCP_LISTEN_BACKLOG 01313 backlog = msg->msg.lb.backlog; 01314 #else /* TCP_LISTEN_BACKLOG */ 01315 backlog = TCP_DEFAULT_LISTEN_BACKLOG; 01316 #endif /* TCP_LISTEN_BACKLOG */ 01317 #if LWIP_IPV4 && LWIP_IPV6 01318 /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY, 01319 * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen 01320 */ 01321 if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) && 01322 (netconn_get_ipv6only(msg->conn) == 0)) { 01323 /* change PCB type to IPADDR_TYPE_ANY */ 01324 IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip, IPADDR_TYPE_ANY); 01325 IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY); 01326 } 01327 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 01328 01329 lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err); 01330 01331 if (lpcb == NULL) { 01332 /* in this case, the old pcb is still allocated */ 01333 msg->err = err; 01334 } else { 01335 /* delete the recvmbox and allocate the acceptmbox */ 01336 if (sys_mbox_valid(&msg->conn->recvmbox)) { 01337 /** @todo: should we drain the recvmbox here? */ 01338 sys_mbox_free(&msg->conn->recvmbox); 01339 sys_mbox_set_invalid(&msg->conn->recvmbox); 01340 } 01341 msg->err = ERR_OK; 01342 if (!sys_mbox_valid(&msg->conn->acceptmbox)) { 01343 msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); 01344 } 01345 if (msg->err == ERR_OK) { 01346 msg->conn->state = NETCONN_LISTEN; 01347 msg->conn->pcb.tcp = lpcb; 01348 tcp_arg(msg->conn->pcb.tcp, msg->conn); 01349 tcp_accept(msg->conn->pcb.tcp, accept_function); 01350 } else { 01351 /* since the old pcb is already deallocated, free lpcb now */ 01352 tcp_close(lpcb); 01353 msg->conn->pcb.tcp = NULL; 01354 } 01355 } 01356 } 01357 } else if (msg->conn->state == NETCONN_LISTEN) { 01358 /* already listening, allow updating of the backlog */ 01359 msg->err = ERR_OK; 01360 tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog); 01361 } 01362 } else { 01363 msg->err = ERR_ARG; 01364 } 01365 } 01366 } 01367 TCPIP_APIMSG_ACK(msg); 01368 } 01369 #endif /* LWIP_TCP */ 01370 01371 /** 01372 * Send some data on a RAW or UDP pcb contained in a netconn 01373 * Called from netconn_send 01374 * 01375 * @param m the api_msg_msg pointing to the connection 01376 */ 01377 void 01378 lwip_netconn_do_send(void *m) 01379 { 01380 struct api_msg *msg = (struct api_msg*)m; 01381 01382 if (ERR_IS_FATAL(msg->conn->last_err)) { 01383 msg->err = msg->conn->last_err; 01384 } else { 01385 msg->err = ERR_CONN; 01386 if (msg->conn->pcb.tcp != NULL) { 01387 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 01388 #if LWIP_RAW 01389 case NETCONN_RAW: 01390 if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { 01391 msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); 01392 } else { 01393 msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); 01394 } 01395 break; 01396 #endif 01397 #if LWIP_UDP 01398 case NETCONN_UDP: 01399 #if LWIP_CHECKSUM_ON_COPY 01400 if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { 01401 msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, 01402 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); 01403 } else { 01404 msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, 01405 &msg->msg.b->addr, msg->msg.b->port, 01406 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); 01407 } 01408 #else /* LWIP_CHECKSUM_ON_COPY */ 01409 if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { 01410 msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); 01411 } else { 01412 msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port); 01413 } 01414 #endif /* LWIP_CHECKSUM_ON_COPY */ 01415 break; 01416 #endif /* LWIP_UDP */ 01417 default: 01418 break; 01419 } 01420 } 01421 } 01422 TCPIP_APIMSG_ACK(msg); 01423 } 01424 01425 #if LWIP_TCP 01426 /** 01427 * Indicate data has been received from a TCP pcb contained in a netconn 01428 * Called from netconn_recv 01429 * 01430 * @param m the api_msg_msg pointing to the connection 01431 */ 01432 void 01433 lwip_netconn_do_recv(void *m) 01434 { 01435 struct api_msg *msg = (struct api_msg*)m; 01436 01437 msg->err = ERR_OK; 01438 if (msg->conn->pcb.tcp != NULL) { 01439 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 01440 u32_t remaining = msg->msg.r.len; 01441 do { 01442 u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining; 01443 tcp_recved(msg->conn->pcb.tcp, recved); 01444 remaining -= recved; 01445 } while (remaining != 0); 01446 } 01447 } 01448 TCPIP_APIMSG_ACK(msg); 01449 } 01450 01451 #if TCP_LISTEN_BACKLOG 01452 /** Indicate that a TCP pcb has been accepted 01453 * Called from netconn_accept 01454 * 01455 * @param m the api_msg_msg pointing to the connection 01456 */ 01457 void 01458 lwip_netconn_do_accepted(void *m) 01459 { 01460 struct api_msg *msg = (struct api_msg*)m; 01461 01462 msg->err = ERR_OK; 01463 if (msg->conn->pcb.tcp != NULL) { 01464 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 01465 tcp_backlog_accepted(msg->conn->pcb.tcp); 01466 } 01467 } 01468 TCPIP_APIMSG_ACK(msg); 01469 } 01470 #endif /* TCP_LISTEN_BACKLOG */ 01471 01472 /** 01473 * See if more data needs to be written from a previous call to netconn_write. 01474 * Called initially from lwip_netconn_do_write. If the first call can't send all data 01475 * (because of low memory or empty send-buffer), this function is called again 01476 * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the 01477 * blocking application thread (waiting in netconn_write) is released. 01478 * 01479 * @param conn netconn (that is currently in state NETCONN_WRITE) to process 01480 * @return ERR_OK 01481 * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished 01482 */ 01483 static err_t 01484 lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) 01485 { 01486 err_t err; 01487 const void *dataptr; 01488 u16_t len, available; 01489 u8_t write_finished = 0; 01490 size_t diff; 01491 u8_t dontblock; 01492 u8_t apiflags; 01493 01494 LWIP_ASSERT("conn != NULL", conn != NULL); 01495 LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); 01496 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 01497 LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); 01498 LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len", 01499 conn->write_offset < conn->current_msg->msg.w.len); 01500 01501 apiflags = conn->current_msg->msg.w.apiflags; 01502 dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); 01503 01504 #if LWIP_SO_SNDTIMEO 01505 if ((conn->send_timeout != 0) && 01506 ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) { 01507 write_finished = 1; 01508 if (conn->write_offset == 0) { 01509 /* nothing has been written */ 01510 err = ERR_WOULDBLOCK; 01511 conn->current_msg->msg.w.len = 0; 01512 } else { 01513 /* partial write */ 01514 err = ERR_OK; 01515 conn->current_msg->msg.w.len = conn->write_offset; 01516 conn->write_offset = 0; 01517 } 01518 } else 01519 #endif /* LWIP_SO_SNDTIMEO */ 01520 { 01521 dataptr = (const u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset; 01522 diff = conn->current_msg->msg.w.len - conn->write_offset; 01523 if (diff > 0xffffUL) { /* max_u16_t */ 01524 len = 0xffff; 01525 apiflags |= TCP_WRITE_FLAG_MORE; 01526 } else { 01527 len = (u16_t)diff; 01528 } 01529 available = tcp_sndbuf(conn->pcb.tcp); 01530 if (available < len) { 01531 /* don't try to write more than sendbuf */ 01532 len = available; 01533 if (dontblock) { 01534 if (!len) { 01535 err = ERR_WOULDBLOCK; 01536 goto err_mem; 01537 } 01538 } else { 01539 apiflags |= TCP_WRITE_FLAG_MORE; 01540 } 01541 } 01542 LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); 01543 err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); 01544 /* if OK or memory error, check available space */ 01545 if ((err == ERR_OK) || (err == ERR_MEM)) { 01546 err_mem: 01547 if (dontblock && (len < conn->current_msg->msg.w.len)) { 01548 /* non-blocking write did not write everything: mark the pcb non-writable 01549 and let poll_tcp check writable space to mark the pcb writable again */ 01550 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); 01551 conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; 01552 } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || 01553 (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { 01554 /* The queued byte- or pbuf-count exceeds the configured low-water limit, 01555 let select mark this pcb as non-writable. */ 01556 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); 01557 } 01558 } 01559 01560 if (err == ERR_OK) { 01561 err_t out_err; 01562 conn->write_offset += len; 01563 if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) { 01564 /* return sent length */ 01565 conn->current_msg->msg.w.len = conn->write_offset; 01566 /* everything was written */ 01567 write_finished = 1; 01568 } 01569 out_err = tcp_output(conn->pcb.tcp); 01570 if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) { 01571 /* If tcp_output fails with fatal error or no route is found, 01572 don't try writing any more but return the error 01573 to the application thread. */ 01574 err = out_err; 01575 write_finished = 1; 01576 conn->current_msg->msg.w.len = 0; 01577 } 01578 } else if (err == ERR_MEM) { 01579 /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called. 01580 For blocking sockets, we do NOT return to the application 01581 thread, since ERR_MEM is only a temporary error! Non-blocking 01582 will remain non-writable until sent_tcp/poll_tcp is called */ 01583 01584 /* tcp_write returned ERR_MEM, try tcp_output anyway */ 01585 err_t out_err = tcp_output(conn->pcb.tcp); 01586 if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) { 01587 /* If tcp_output fails with fatal error or no route is found, 01588 don't try writing any more but return the error 01589 to the application thread. */ 01590 err = out_err; 01591 write_finished = 1; 01592 conn->current_msg->msg.w.len = 0; 01593 } else if (dontblock) { 01594 /* non-blocking write is done on ERR_MEM */ 01595 err = ERR_WOULDBLOCK; 01596 write_finished = 1; 01597 conn->current_msg->msg.w.len = 0; 01598 } 01599 } else { 01600 /* On errors != ERR_MEM, we don't try writing any more but return 01601 the error to the application thread. */ 01602 write_finished = 1; 01603 conn->current_msg->msg.w.len = 0; 01604 } 01605 } 01606 if (write_finished) { 01607 /* everything was written: set back connection state 01608 and back to application task */ 01609 sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 01610 conn->current_msg->err = err; 01611 conn->current_msg = NULL; 01612 conn->write_offset = 0; 01613 conn->state = NETCONN_NONE; 01614 NETCONN_SET_SAFE_ERR(conn, err); 01615 #if LWIP_TCPIP_CORE_LOCKING 01616 if (delayed) 01617 #endif 01618 { 01619 sys_sem_signal(op_completed_sem); 01620 } 01621 } 01622 #if LWIP_TCPIP_CORE_LOCKING 01623 else { 01624 return ERR_MEM; 01625 } 01626 #endif 01627 return ERR_OK; 01628 } 01629 #endif /* LWIP_TCP */ 01630 01631 /** 01632 * Send some data on a TCP pcb contained in a netconn 01633 * Called from netconn_write 01634 * 01635 * @param m the api_msg_msg pointing to the connection 01636 */ 01637 void 01638 lwip_netconn_do_write(void *m) 01639 { 01640 struct api_msg *msg = (struct api_msg*)m; 01641 01642 if (ERR_IS_FATAL(msg->conn->last_err)) { 01643 msg->err = msg->conn->last_err; 01644 } else { 01645 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 01646 #if LWIP_TCP 01647 if (msg->conn->state != NETCONN_NONE) { 01648 /* netconn is connecting, closing or in blocking write */ 01649 msg->err = ERR_INPROGRESS; 01650 } else if (msg->conn->pcb.tcp != NULL) { 01651 msg->conn->state = NETCONN_WRITE; 01652 /* set all the variables used by lwip_netconn_do_writemore */ 01653 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && 01654 msg->conn->write_offset == 0); 01655 LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0); 01656 msg->conn->current_msg = msg; 01657 msg->conn->write_offset = 0; 01658 #if LWIP_TCPIP_CORE_LOCKING 01659 if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) { 01660 LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); 01661 UNLOCK_TCPIP_CORE(); 01662 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 01663 LOCK_TCPIP_CORE(); 01664 LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE); 01665 } 01666 #else /* LWIP_TCPIP_CORE_LOCKING */ 01667 lwip_netconn_do_writemore(msg->conn); 01668 #endif /* LWIP_TCPIP_CORE_LOCKING */ 01669 /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG 01670 since lwip_netconn_do_writemore ACKs it! */ 01671 return; 01672 } else { 01673 msg->err = ERR_CONN; 01674 } 01675 #else /* LWIP_TCP */ 01676 msg->err = ERR_VAL; 01677 #endif /* LWIP_TCP */ 01678 #if (LWIP_UDP || LWIP_RAW) 01679 } else { 01680 msg->err = ERR_VAL; 01681 #endif /* (LWIP_UDP || LWIP_RAW) */ 01682 } 01683 } 01684 TCPIP_APIMSG_ACK(msg); 01685 } 01686 01687 /** 01688 * Return a connection's local or remote address 01689 * Called from netconn_getaddr 01690 * 01691 * @param m the api_msg_msg pointing to the connection 01692 */ 01693 void 01694 lwip_netconn_do_getaddr(void *m) 01695 { 01696 struct api_msg *msg = (struct api_msg*)m; 01697 01698 if (msg->conn->pcb.ip != NULL) { 01699 if (msg->msg.ad.local) { 01700 ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), 01701 msg->conn->pcb.ip->local_ip); 01702 } else { 01703 ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), 01704 msg->conn->pcb.ip->remote_ip); 01705 } 01706 01707 msg->err = ERR_OK; 01708 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 01709 #if LWIP_RAW 01710 case NETCONN_RAW: 01711 if (msg->msg.ad.local) { 01712 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; 01713 } else { 01714 /* return an error as connecting is only a helper for upper layers */ 01715 msg->err = ERR_CONN; 01716 } 01717 break; 01718 #endif /* LWIP_RAW */ 01719 #if LWIP_UDP 01720 case NETCONN_UDP: 01721 if (msg->msg.ad.local) { 01722 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; 01723 } else { 01724 if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { 01725 msg->err = ERR_CONN; 01726 } else { 01727 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; 01728 } 01729 } 01730 break; 01731 #endif /* LWIP_UDP */ 01732 #if LWIP_TCP 01733 case NETCONN_TCP: 01734 if ((msg->msg.ad.local == 0) && 01735 ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) { 01736 /* pcb is not connected and remote name is requested */ 01737 msg->err = ERR_CONN; 01738 } else { 01739 API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port); 01740 } 01741 break; 01742 #endif /* LWIP_TCP */ 01743 default: 01744 LWIP_ASSERT("invalid netconn_type", 0); 01745 break; 01746 } 01747 } else { 01748 msg->err = ERR_CONN; 01749 } 01750 TCPIP_APIMSG_ACK(msg); 01751 } 01752 01753 /** 01754 * Close or half-shutdown a TCP pcb contained in a netconn 01755 * Called from netconn_close 01756 * In contrast to closing sockets, the netconn is not deallocated. 01757 * 01758 * @param m the api_msg_msg pointing to the connection 01759 */ 01760 void 01761 lwip_netconn_do_close(void *m) 01762 { 01763 struct api_msg *msg = (struct api_msg*)m; 01764 01765 #if LWIP_TCP 01766 enum netconn_state state = msg->conn->state; 01767 /* First check if this is a TCP netconn and if it is in a correct state 01768 (LISTEN doesn't support half shutdown) */ 01769 if ((msg->conn->pcb.tcp != NULL) && 01770 (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) && 01771 ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) { 01772 /* Check if we are in a connected state */ 01773 if (state == NETCONN_CONNECT) { 01774 /* TCP connect in progress: cannot shutdown */ 01775 msg->err = ERR_CONN; 01776 } else if (state == NETCONN_WRITE) { 01777 #if LWIP_NETCONN_FULLDUPLEX 01778 if (msg->msg.sd.shut & NETCONN_SHUT_WR) { 01779 /* close requested, abort running write */ 01780 sys_sem_t* op_completed_sem; 01781 LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); 01782 op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); 01783 msg->conn->current_msg->err = ERR_CLSD; 01784 msg->conn->current_msg = NULL; 01785 msg->conn->write_offset = 0; 01786 msg->conn->state = NETCONN_NONE; 01787 NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD); 01788 sys_sem_signal(op_completed_sem); 01789 } else { 01790 LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD); 01791 /* In this case, let the write continue and do not interfere with 01792 conn->current_msg or conn->state! */ 01793 msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0); 01794 } 01795 #else /* LWIP_NETCONN_FULLDUPLEX */ 01796 msg->err = ERR_INPROGRESS; 01797 #endif /* LWIP_NETCONN_FULLDUPLEX */ 01798 } else { 01799 if (msg->msg.sd.shut & NETCONN_SHUT_RD) { 01800 /* Drain and delete mboxes */ 01801 netconn_drain(msg->conn); 01802 } 01803 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && 01804 msg->conn->write_offset == 0); 01805 msg->conn->state = NETCONN_CLOSE; 01806 msg->conn->current_msg = msg; 01807 #if LWIP_TCPIP_CORE_LOCKING 01808 if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) { 01809 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE); 01810 UNLOCK_TCPIP_CORE(); 01811 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 01812 LOCK_TCPIP_CORE(); 01813 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); 01814 } 01815 #else /* LWIP_TCPIP_CORE_LOCKING */ 01816 lwip_netconn_do_close_internal(msg->conn); 01817 #endif /* LWIP_TCPIP_CORE_LOCKING */ 01818 /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */ 01819 return; 01820 } 01821 } else 01822 #endif /* LWIP_TCP */ 01823 { 01824 msg->err = ERR_CONN; 01825 } 01826 TCPIP_APIMSG_ACK(msg); 01827 } 01828 01829 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) 01830 /** 01831 * Join multicast groups for UDP netconns. 01832 * Called from netconn_join_leave_group 01833 * 01834 * @param m the api_msg_msg pointing to the connection 01835 */ 01836 void 01837 lwip_netconn_do_join_leave_group(void *m) 01838 { 01839 struct api_msg *msg = (struct api_msg*)m; 01840 01841 if (ERR_IS_FATAL(msg->conn->last_err)) { 01842 msg->err = msg->conn->last_err; 01843 } else { 01844 if (msg->conn->pcb.tcp != NULL) { 01845 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 01846 #if LWIP_UDP 01847 #if LWIP_IPV6 && LWIP_IPV6_MLD 01848 if (NETCONNTYPE_ISIPV6(msg->conn->type)) { 01849 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 01850 msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), 01851 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); 01852 } else { 01853 msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), 01854 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); 01855 } 01856 } 01857 else 01858 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ 01859 { 01860 #if LWIP_IGMP 01861 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 01862 msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), 01863 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); 01864 } else { 01865 msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), 01866 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); 01867 } 01868 #endif /* LWIP_IGMP */ 01869 } 01870 #endif /* LWIP_UDP */ 01871 #if (LWIP_TCP || LWIP_RAW) 01872 } else { 01873 msg->err = ERR_VAL; 01874 #endif /* (LWIP_TCP || LWIP_RAW) */ 01875 } 01876 } else { 01877 msg->err = ERR_CONN; 01878 } 01879 } 01880 TCPIP_APIMSG_ACK(msg); 01881 } 01882 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ 01883 01884 #if LWIP_DNS 01885 /** 01886 * Callback function that is called when DNS name is resolved 01887 * (or on timeout). A waiting application thread is waked up by 01888 * signaling the semaphore. 01889 */ 01890 static void 01891 lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg) 01892 { 01893 struct dns_api_msg *msg = (struct dns_api_msg*)arg; 01894 01895 /* we trust the internal implementation to be correct :-) */ 01896 LWIP_UNUSED_ARG(name); 01897 01898 if (ipaddr == NULL) { 01899 /* timeout or memory error */ 01900 API_EXPR_DEREF(msg->err) = ERR_VAL; 01901 } else { 01902 /* address was resolved */ 01903 API_EXPR_DEREF(msg->err) = ERR_OK; 01904 API_EXPR_DEREF(msg->addr) = *ipaddr; 01905 } 01906 /* wake up the application task waiting in netconn_gethostbyname */ 01907 sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); 01908 } 01909 01910 /** 01911 * Execute a DNS query 01912 * Called from netconn_gethostbyname 01913 * 01914 * @param arg the dns_api_msg pointing to the query 01915 */ 01916 void 01917 lwip_netconn_do_gethostbyname(void *arg) 01918 { 01919 struct dns_api_msg *msg = (struct dns_api_msg*)arg; 01920 u8_t addrtype = 01921 #if LWIP_IPV4 && LWIP_IPV6 01922 msg->dns_addrtype; 01923 #else 01924 LWIP_DNS_ADDRTYPE_DEFAULT; 01925 #endif 01926 01927 API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name, 01928 API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype); 01929 if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) { 01930 /* on error or immediate success, wake up the application 01931 * task waiting in netconn_gethostbyname */ 01932 sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); 01933 } 01934 } 01935 #endif /* LWIP_DNS */ 01936 01937 #endif /* LWIP_NETCONN */
Generated on Tue Jul 12 2022 11:02:25 by
1.7.2