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