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