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