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.
Fork of lwip by
api_msg.c
00001 /** 00002 * @file 00003 * Sequential API Internal module 00004 * 00005 */ 00006 00007 /* 00008 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 00009 * All rights reserved. 00010 * 00011 * Redistribution and use in source and binary forms, with or without modification, 00012 * are permitted provided that the following conditions are met: 00013 * 00014 * 1. Redistributions of source code must retain the above copyright notice, 00015 * this list of conditions and the following disclaimer. 00016 * 2. Redistributions in binary form must reproduce the above copyright notice, 00017 * this list of conditions and the following disclaimer in the documentation 00018 * and/or other materials provided with the distribution. 00019 * 3. The name of the author may not be used to endorse or promote products 00020 * derived from this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00023 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00025 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00026 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00027 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00028 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00029 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00030 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00031 * OF SUCH DAMAGE. 00032 * 00033 * This file is part of the lwIP TCP/IP stack. 00034 * 00035 * Author: Adam Dunkels <adam@sics.se> 00036 * 00037 */ 00038 00039 #include "lwip/opt.h" 00040 00041 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ 00042 00043 #include "lwip/api_msg.h" 00044 00045 #include "lwip/ip.h" 00046 #include "lwip/udp.h" 00047 #include "lwip/tcp.h" 00048 #include "lwip/raw.h" 00049 00050 #include "lwip/memp.h" 00051 #include "lwip/tcpip.h" 00052 #include "lwip/igmp.h" 00053 #include "lwip/dns.h" 00054 00055 /* forward declarations */ 00056 #if LWIP_TCP 00057 static err_t do_writemore(struct netconn *conn); 00058 static void do_close_internal(struct netconn *conn); 00059 #endif 00060 00061 #if LWIP_RAW 00062 /** 00063 * Receive callback function for RAW netconns. 00064 * Doesn't 'eat' the packet, only references it and sends it to 00065 * conn->recvmbox 00066 * 00067 * @see raw.h (struct raw_pcb.recv) for parameters and return value 00068 */ 00069 static u8_t 00070 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, 00071 struct ip_addr *addr) 00072 { 00073 struct pbuf *q; 00074 struct netbuf *buf; 00075 struct netconn *conn; 00076 #if LWIP_SO_RCVBUF 00077 int recv_avail; 00078 #endif /* LWIP_SO_RCVBUF */ 00079 00080 LWIP_UNUSED_ARG(addr); 00081 conn = arg; 00082 00083 #if LWIP_SO_RCVBUF 00084 SYS_ARCH_GET(conn->recv_avail, recv_avail); 00085 if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) && 00086 ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) { 00087 #else /* LWIP_SO_RCVBUF */ 00088 if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) { 00089 #endif /* LWIP_SO_RCVBUF */ 00090 /* copy the whole packet into new pbufs */ 00091 q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); 00092 if(q != NULL) { 00093 if (pbuf_copy(q, p) != ERR_OK) { 00094 pbuf_free(q); 00095 q = NULL; 00096 } 00097 } 00098 00099 if(q != NULL) { 00100 buf = memp_malloc(MEMP_NETBUF); 00101 if (buf == NULL) { 00102 pbuf_free(q); 00103 return 0; 00104 } 00105 00106 buf->p = q; 00107 buf->ptr = q; 00108 buf->addr = &(((struct ip_hdr*)(q->payload))->src); 00109 buf->port = pcb->protocol; 00110 00111 SYS_ARCH_INC(conn->recv_avail, q->tot_len); 00112 /* Register event with callback */ 00113 API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len); 00114 if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) { 00115 netbuf_delete(buf); 00116 } 00117 } 00118 } 00119 00120 return 0; /* do not eat the packet */ 00121 } 00122 #endif /* LWIP_RAW*/ 00123 00124 #if LWIP_UDP 00125 /** 00126 * Receive callback function for UDP netconns. 00127 * Posts the packet to conn->recvmbox or deletes it on memory error. 00128 * 00129 * @see udp.h (struct udp_pcb.recv) for parameters 00130 */ 00131 static void 00132 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, 00133 struct ip_addr *addr, u16_t port) 00134 { 00135 struct netbuf *buf; 00136 struct netconn *conn; 00137 #if LWIP_SO_RCVBUF 00138 int recv_avail; 00139 #endif /* LWIP_SO_RCVBUF */ 00140 00141 LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ 00142 LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); 00143 LWIP_ASSERT("recv_udp must have an argument", arg != NULL); 00144 conn = arg; 00145 LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); 00146 00147 #if LWIP_SO_RCVBUF 00148 SYS_ARCH_GET(conn->recv_avail, recv_avail); 00149 if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) || 00150 ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { 00151 #else /* LWIP_SO_RCVBUF */ 00152 if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) { 00153 #endif /* LWIP_SO_RCVBUF */ 00154 pbuf_free(p); 00155 return; 00156 } 00157 00158 buf = memp_malloc(MEMP_NETBUF); 00159 if (buf == NULL) { 00160 pbuf_free(p); 00161 return; 00162 } else { 00163 buf->p = p; 00164 buf->ptr = p; 00165 buf->addr = addr; 00166 buf->port = port; 00167 } 00168 00169 SYS_ARCH_INC(conn->recv_avail, p->tot_len); 00170 /* Register event with callback */ 00171 API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len); 00172 if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) { 00173 netbuf_delete(buf); 00174 return; 00175 } 00176 } 00177 #endif /* LWIP_UDP */ 00178 00179 #if LWIP_TCP 00180 /** 00181 * Receive callback function for TCP netconns. 00182 * Posts the packet to conn->recvmbox, but doesn't delete it on errors. 00183 * 00184 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value 00185 */ 00186 static err_t 00187 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) 00188 { 00189 struct netconn *conn; 00190 u16_t len; 00191 00192 LWIP_UNUSED_ARG(pcb); 00193 LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); 00194 LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); 00195 conn = arg; 00196 LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); 00197 00198 if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) { 00199 return ERR_VAL; 00200 } 00201 00202 conn->err = err; 00203 if (p != NULL) { 00204 len = p->tot_len; 00205 SYS_ARCH_INC(conn->recv_avail, len); 00206 } else { 00207 len = 0; 00208 } 00209 /* Register event with callback */ 00210 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 00211 if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) { 00212 return ERR_MEM; 00213 } 00214 00215 return ERR_OK; 00216 } 00217 00218 /** 00219 * Poll callback function for TCP netconns. 00220 * Wakes up an application thread that waits for a connection to close 00221 * or data to be sent. The application thread then takes the 00222 * appropriate action to go on. 00223 * 00224 * Signals the conn->sem. 00225 * netconn_close waits for conn->sem if closing failed. 00226 * 00227 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value 00228 */ 00229 static err_t 00230 poll_tcp(void *arg, struct tcp_pcb *pcb) 00231 { 00232 struct netconn *conn = arg; 00233 00234 LWIP_UNUSED_ARG(pcb); 00235 LWIP_ASSERT("conn != NULL", (conn != NULL)); 00236 00237 if (conn->state == NETCONN_WRITE) { 00238 do_writemore(conn); 00239 } else if (conn->state == NETCONN_CLOSE) { 00240 do_close_internal(conn); 00241 } 00242 00243 return ERR_OK; 00244 } 00245 00246 /** 00247 * Sent callback function for TCP netconns. 00248 * Signals the conn->sem and calls API_EVENT. 00249 * netconn_write waits for conn->sem if send buffer is low. 00250 * 00251 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value 00252 */ 00253 static err_t 00254 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) 00255 { 00256 struct netconn *conn = arg; 00257 00258 LWIP_UNUSED_ARG(pcb); 00259 LWIP_ASSERT("conn != NULL", (conn != NULL)); 00260 00261 if (conn->state == NETCONN_WRITE) { 00262 LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); 00263 do_writemore(conn); 00264 } else if (conn->state == NETCONN_CLOSE) { 00265 do_close_internal(conn); 00266 } 00267 00268 if (conn) { 00269 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) { 00270 API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); 00271 } 00272 } 00273 00274 return ERR_OK; 00275 } 00276 00277 /** 00278 * Error callback function for TCP netconns. 00279 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. 00280 * The application thread has then to decide what to do. 00281 * 00282 * @see tcp.h (struct tcp_pcb.err) for parameters 00283 */ 00284 static void 00285 err_tcp(void *arg, err_t err) 00286 { 00287 struct netconn *conn; 00288 00289 conn = arg; 00290 LWIP_ASSERT("conn != NULL", (conn != NULL)); 00291 00292 conn->pcb.tcp = NULL; 00293 00294 conn->err = err; 00295 if (conn->recvmbox != SYS_MBOX_NULL) { 00296 /* Register event with callback */ 00297 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 00298 sys_mbox_post(conn->recvmbox, NULL); 00299 } 00300 if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) { 00301 conn->state = NETCONN_NONE; 00302 sys_sem_signal(conn->op_completed); 00303 } 00304 if (conn->acceptmbox != SYS_MBOX_NULL) { 00305 /* Register event with callback */ 00306 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 00307 sys_mbox_post(conn->acceptmbox, NULL); 00308 } 00309 if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) { 00310 /* calling do_writemore/do_close_internal is not necessary 00311 since the pcb has already been deleted! */ 00312 conn->state = NETCONN_NONE; 00313 /* wake up the waiting task */ 00314 sys_sem_signal(conn->op_completed); 00315 } 00316 } 00317 00318 /** 00319 * Setup a tcp_pcb with the correct callback function pointers 00320 * and their arguments. 00321 * 00322 * @param conn the TCP netconn to setup 00323 */ 00324 static void 00325 setup_tcp(struct netconn *conn) 00326 { 00327 struct tcp_pcb *pcb; 00328 00329 pcb = conn->pcb.tcp; 00330 tcp_arg(pcb, conn); 00331 tcp_recv(pcb, recv_tcp); 00332 tcp_sent(pcb, sent_tcp); 00333 tcp_poll(pcb, poll_tcp, 4); 00334 tcp_err(pcb, err_tcp); 00335 } 00336 00337 /** 00338 * Accept callback function for TCP netconns. 00339 * Allocates a new netconn and posts that to conn->acceptmbox. 00340 * 00341 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value 00342 */ 00343 static err_t 00344 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) 00345 { 00346 struct netconn *newconn; 00347 struct netconn *conn; 00348 00349 #if API_MSG_DEBUG 00350 #if TCP_DEBUG 00351 tcp_debug_print_state(newpcb->state); 00352 #endif /* TCP_DEBUG */ 00353 #endif /* API_MSG_DEBUG */ 00354 conn = (struct netconn *)arg; 00355 00356 LWIP_ERROR("accept_function: invalid conn->acceptmbox", 00357 conn->acceptmbox != SYS_MBOX_NULL, return ERR_VAL;); 00358 00359 /* We have to set the callback here even though 00360 * the new socket is unknown. conn->socket is marked as -1. */ 00361 newconn = netconn_alloc(conn->type, conn->callback); 00362 if (newconn == NULL) { 00363 return ERR_MEM; 00364 } 00365 newconn->pcb.tcp = newpcb; 00366 setup_tcp(newconn); 00367 newconn->err = err; 00368 /* Register event with callback */ 00369 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 00370 00371 if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) { 00372 /* When returning != ERR_OK, the connection is aborted in tcp_process(), 00373 so do nothing here! */ 00374 newconn->pcb.tcp = NULL; 00375 netconn_free(newconn); 00376 return ERR_MEM; 00377 } 00378 return ERR_OK; 00379 } 00380 #endif /* LWIP_TCP */ 00381 00382 /** 00383 * Create a new pcb of a specific type. 00384 * Called from do_newconn(). 00385 * 00386 * @param msg the api_msg_msg describing the connection type 00387 * @return msg->conn->err, but the return value is currently ignored 00388 */ 00389 static err_t 00390 pcb_new(struct api_msg_msg *msg) 00391 { 00392 msg->conn->err = ERR_OK; 00393 00394 LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); 00395 00396 /* Allocate a PCB for this connection */ 00397 switch(NETCONNTYPE_GROUP(msg->conn->type)) { 00398 #if LWIP_RAW 00399 case NETCONN_RAW: 00400 msg->conn->pcb.raw = raw_new(msg->msg.n.proto); 00401 if(msg->conn->pcb.raw == NULL) { 00402 msg->conn->err = ERR_MEM; 00403 break; 00404 } 00405 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); 00406 break; 00407 #endif /* LWIP_RAW */ 00408 #if LWIP_UDP 00409 case NETCONN_UDP: 00410 msg->conn->pcb.udp = udp_new(); 00411 if(msg->conn->pcb.udp == NULL) { 00412 msg->conn->err = ERR_MEM; 00413 break; 00414 } 00415 #if LWIP_UDPLITE 00416 if (msg->conn->type==NETCONN_UDPLITE) { 00417 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); 00418 } 00419 #endif /* LWIP_UDPLITE */ 00420 if (msg->conn->type==NETCONN_UDPNOCHKSUM) { 00421 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); 00422 } 00423 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); 00424 break; 00425 #endif /* LWIP_UDP */ 00426 #if LWIP_TCP 00427 case NETCONN_TCP: 00428 msg->conn->pcb.tcp = tcp_new(); 00429 if(msg->conn->pcb.tcp == NULL) { 00430 msg->conn->err = ERR_MEM; 00431 break; 00432 } 00433 setup_tcp(msg->conn); 00434 break; 00435 #endif /* LWIP_TCP */ 00436 default: 00437 /* Unsupported netconn type, e.g. protocol disabled */ 00438 msg->conn->err = ERR_VAL; 00439 break; 00440 } 00441 00442 return msg->conn->err; 00443 } 00444 00445 /** 00446 * Create a new pcb of a specific type inside a netconn. 00447 * Called from netconn_new_with_proto_and_callback. 00448 * 00449 * @param msg the api_msg_msg describing the connection type 00450 */ 00451 void 00452 do_newconn(struct api_msg_msg *msg) 00453 { 00454 if(msg->conn->pcb.tcp == NULL) { 00455 pcb_new(msg); 00456 } 00457 /* Else? This "new" connection already has a PCB allocated. */ 00458 /* Is this an error condition? Should it be deleted? */ 00459 /* We currently just are happy and return. */ 00460 00461 TCPIP_APIMSG_ACK(msg); 00462 } 00463 00464 /** 00465 * Create a new netconn (of a specific type) that has a callback function. 00466 * The corresponding pcb is NOT created! 00467 * 00468 * @param t the type of 'connection' to create (@see enum netconn_type) 00469 * @param proto the IP protocol for RAW IP pcbs 00470 * @param callback a function to call on status changes (RX available, TX'ed) 00471 * @return a newly allocated struct netconn or 00472 * NULL on memory error 00473 */ 00474 struct netconn* 00475 netconn_alloc(enum netconn_type t, netconn_callback callback) 00476 { 00477 struct netconn *conn; 00478 int size; 00479 00480 conn = memp_malloc(MEMP_NETCONN); 00481 if (conn == NULL) { 00482 return NULL; 00483 } 00484 00485 conn->err = ERR_OK; 00486 conn->type = t; 00487 conn->pcb.tcp = NULL; 00488 00489 #if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \ 00490 (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE) 00491 size = DEFAULT_RAW_RECVMBOX_SIZE; 00492 #else 00493 switch(NETCONNTYPE_GROUP(t)) { 00494 #if LWIP_RAW 00495 case NETCONN_RAW: 00496 size = DEFAULT_RAW_RECVMBOX_SIZE; 00497 break; 00498 #endif /* LWIP_RAW */ 00499 #if LWIP_UDP 00500 case NETCONN_UDP: 00501 size = DEFAULT_UDP_RECVMBOX_SIZE; 00502 break; 00503 #endif /* LWIP_UDP */ 00504 #if LWIP_TCP 00505 case NETCONN_TCP: 00506 size = DEFAULT_TCP_RECVMBOX_SIZE; 00507 break; 00508 #endif /* LWIP_TCP */ 00509 default: 00510 LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); 00511 break; 00512 } 00513 #endif 00514 00515 if ((conn->op_completed = sys_sem_new(0)) == SYS_SEM_NULL) { 00516 memp_free(MEMP_NETCONN, conn); 00517 return NULL; 00518 } 00519 if ((conn->recvmbox = sys_mbox_new(size)) == SYS_MBOX_NULL) { 00520 sys_sem_free(conn->op_completed); 00521 memp_free(MEMP_NETCONN, conn); 00522 return NULL; 00523 } 00524 00525 conn->acceptmbox = SYS_MBOX_NULL; 00526 conn->state = NETCONN_NONE; 00527 /* initialize socket to -1 since 0 is a valid socket */ 00528 conn->socket = -1; 00529 conn->callback = callback; 00530 conn->recv_avail = 0; 00531 #if LWIP_SO_RCVTIMEO 00532 conn->recv_timeout = 0; 00533 #endif /* LWIP_SO_RCVTIMEO */ 00534 #if LWIP_SO_RCVBUF 00535 conn->recv_bufsize = INT_MAX; 00536 #endif /* LWIP_SO_RCVBUF */ 00537 return conn; 00538 } 00539 00540 /** 00541 * Delete a netconn and all its resources. 00542 * The pcb is NOT freed (since we might not be in the right thread context do this). 00543 * 00544 * @param conn the netconn to free 00545 */ 00546 void 00547 netconn_free(struct netconn *conn) 00548 { 00549 void *mem; 00550 LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); 00551 00552 /* Drain the recvmbox. */ 00553 if (conn->recvmbox != SYS_MBOX_NULL) { 00554 while (sys_mbox_tryfetch(conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { 00555 if (conn->type == NETCONN_TCP) { 00556 if(mem != NULL) { 00557 pbuf_free((struct pbuf *)mem); 00558 } 00559 } else { 00560 netbuf_delete((struct netbuf *)mem); 00561 } 00562 } 00563 sys_mbox_free(conn->recvmbox); 00564 conn->recvmbox = SYS_MBOX_NULL; 00565 } 00566 00567 /* Drain the acceptmbox. */ 00568 if (conn->acceptmbox != SYS_MBOX_NULL) { 00569 while (sys_mbox_tryfetch(conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { 00570 netconn_delete((struct netconn *)mem); 00571 } 00572 sys_mbox_free(conn->acceptmbox); 00573 conn->acceptmbox = SYS_MBOX_NULL; 00574 } 00575 00576 sys_sem_free(conn->op_completed); 00577 conn->op_completed = SYS_SEM_NULL; 00578 00579 memp_free(MEMP_NETCONN, conn); 00580 } 00581 00582 #if LWIP_TCP 00583 /** 00584 * Internal helper function to close a TCP netconn: since this sometimes 00585 * doesn't work at the first attempt, this function is called from multiple 00586 * places. 00587 * 00588 * @param conn the TCP netconn to close 00589 */ 00590 static void 00591 do_close_internal(struct netconn *conn) 00592 { 00593 err_t err; 00594 00595 LWIP_ASSERT("invalid conn", (conn != NULL)); 00596 LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP)); 00597 LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); 00598 LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); 00599 00600 /* Set back some callback pointers */ 00601 if (conn->pcb.tcp->state == LISTEN) { 00602 tcp_arg(conn->pcb.tcp, NULL); 00603 tcp_accept(conn->pcb.tcp, NULL); 00604 } else { 00605 tcp_recv(conn->pcb.tcp, NULL); 00606 } 00607 /* Try to close the connection */ 00608 err = tcp_close(conn->pcb.tcp); 00609 if (err == ERR_OK) { 00610 /* Closing succeeded */ 00611 conn->state = NETCONN_NONE; 00612 /* Set back some callback pointers as conn is going away */ 00613 tcp_err(conn->pcb.tcp, NULL); 00614 tcp_poll(conn->pcb.tcp, NULL, 4); 00615 tcp_sent(conn->pcb.tcp, NULL); 00616 tcp_recv(conn->pcb.tcp, NULL); 00617 tcp_arg(conn->pcb.tcp, NULL); 00618 conn->pcb.tcp = NULL; 00619 conn->err = ERR_OK; 00620 /* Trigger select() in socket layer. This send should something else so the 00621 errorfd is set, not the read and write fd! */ 00622 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 00623 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 00624 /* wake up the application task */ 00625 sys_sem_signal(conn->op_completed); 00626 } 00627 /* If closing didn't succeed, we get called again either 00628 from poll_tcp or from sent_tcp */ 00629 } 00630 #endif /* LWIP_TCP */ 00631 00632 /** 00633 * Delete the pcb inside a netconn. 00634 * Called from netconn_delete. 00635 * 00636 * @param msg the api_msg_msg pointing to the connection 00637 */ 00638 void 00639 do_delconn(struct api_msg_msg *msg) 00640 { 00641 if (msg->conn->pcb.tcp != NULL) { 00642 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 00643 #if LWIP_RAW 00644 case NETCONN_RAW: 00645 raw_remove(msg->conn->pcb.raw); 00646 break; 00647 #endif /* LWIP_RAW */ 00648 #if LWIP_UDP 00649 case NETCONN_UDP: 00650 msg->conn->pcb.udp->recv_arg = NULL; 00651 udp_remove(msg->conn->pcb.udp); 00652 break; 00653 #endif /* LWIP_UDP */ 00654 #if LWIP_TCP 00655 case NETCONN_TCP: 00656 msg->conn->state = NETCONN_CLOSE; 00657 do_close_internal(msg->conn); 00658 /* API_EVENT is called inside do_close_internal, before releasing 00659 the application thread, so we can return at this point! */ 00660 return; 00661 #endif /* LWIP_TCP */ 00662 default: 00663 break; 00664 } 00665 } 00666 /* tcp netconns don't come here! */ 00667 00668 /* Trigger select() in socket layer. This send should something else so the 00669 errorfd is set, not the read and write fd! */ 00670 API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); 00671 API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); 00672 00673 if (msg->conn->op_completed != SYS_SEM_NULL) { 00674 sys_sem_signal(msg->conn->op_completed); 00675 } 00676 } 00677 00678 /** 00679 * Bind a pcb contained in a netconn 00680 * Called from netconn_bind. 00681 * 00682 * @param msg the api_msg_msg pointing to the connection and containing 00683 * the IP address and port to bind to 00684 */ 00685 void 00686 do_bind(struct api_msg_msg *msg) 00687 { 00688 if (!ERR_IS_FATAL(msg->conn->err)) { 00689 if (msg->conn->pcb.tcp != NULL) { 00690 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 00691 #if LWIP_RAW 00692 case NETCONN_RAW: 00693 msg->conn->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr); 00694 break; 00695 #endif /* LWIP_RAW */ 00696 #if LWIP_UDP 00697 case NETCONN_UDP: 00698 msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); 00699 break; 00700 #endif /* LWIP_UDP */ 00701 #if LWIP_TCP 00702 case NETCONN_TCP: 00703 msg->conn->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port); 00704 break; 00705 #endif /* LWIP_TCP */ 00706 default: 00707 break; 00708 } 00709 } else { 00710 /* msg->conn->pcb is NULL */ 00711 msg->conn->err = ERR_VAL; 00712 } 00713 } 00714 TCPIP_APIMSG_ACK(msg); 00715 } 00716 00717 #if LWIP_TCP 00718 /** 00719 * TCP callback function if a connection (opened by tcp_connect/do_connect) has 00720 * been established (or reset by the remote host). 00721 * 00722 * @see tcp.h (struct tcp_pcb.connected) for parameters and return values 00723 */ 00724 static err_t 00725 do_connected(void *arg, struct tcp_pcb *pcb, err_t err) 00726 { 00727 struct netconn *conn; 00728 00729 LWIP_UNUSED_ARG(pcb); 00730 00731 conn = arg; 00732 00733 if (conn == NULL) { 00734 return ERR_VAL; 00735 } 00736 00737 conn->err = err; 00738 if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) { 00739 setup_tcp(conn); 00740 } 00741 conn->state = NETCONN_NONE; 00742 sys_sem_signal(conn->op_completed); 00743 return ERR_OK; 00744 } 00745 #endif /* LWIP_TCP */ 00746 00747 /** 00748 * Connect a pcb contained inside a netconn 00749 * Called from netconn_connect. 00750 * 00751 * @param msg the api_msg_msg pointing to the connection and containing 00752 * the IP address and port to connect to 00753 */ 00754 void 00755 do_connect(struct api_msg_msg *msg) 00756 { 00757 if (msg->conn->pcb.tcp == NULL) { 00758 sys_sem_signal(msg->conn->op_completed); 00759 return; 00760 } 00761 00762 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 00763 #if LWIP_RAW 00764 case NETCONN_RAW: 00765 msg->conn->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); 00766 sys_sem_signal(msg->conn->op_completed); 00767 break; 00768 #endif /* LWIP_RAW */ 00769 #if LWIP_UDP 00770 case NETCONN_UDP: 00771 msg->conn->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); 00772 sys_sem_signal(msg->conn->op_completed); 00773 break; 00774 #endif /* LWIP_UDP */ 00775 #if LWIP_TCP 00776 case NETCONN_TCP: 00777 msg->conn->state = NETCONN_CONNECT; 00778 setup_tcp(msg->conn); 00779 msg->conn->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port, 00780 do_connected); 00781 /* sys_sem_signal() is called from do_connected (or err_tcp()), 00782 * when the connection is established! */ 00783 break; 00784 #endif /* LWIP_TCP */ 00785 default: 00786 break; 00787 } 00788 } 00789 00790 /** 00791 * Connect a pcb contained inside a netconn 00792 * Only used for UDP netconns. 00793 * Called from netconn_disconnect. 00794 * 00795 * @param msg the api_msg_msg pointing to the connection to disconnect 00796 */ 00797 void 00798 do_disconnect(struct api_msg_msg *msg) 00799 { 00800 #if LWIP_UDP 00801 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 00802 udp_disconnect(msg->conn->pcb.udp); 00803 } 00804 #endif /* LWIP_UDP */ 00805 TCPIP_APIMSG_ACK(msg); 00806 } 00807 00808 /** 00809 * Set a TCP pcb contained in a netconn into listen mode 00810 * Called from netconn_listen. 00811 * 00812 * @param msg the api_msg_msg pointing to the connection 00813 */ 00814 void 00815 do_listen(struct api_msg_msg *msg) 00816 { 00817 #if LWIP_TCP 00818 if (!ERR_IS_FATAL(msg->conn->err)) { 00819 if (msg->conn->pcb.tcp != NULL) { 00820 if (msg->conn->type == NETCONN_TCP) { 00821 if (msg->conn->pcb.tcp->state == CLOSED) { 00822 #if TCP_LISTEN_BACKLOG 00823 struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); 00824 #else /* TCP_LISTEN_BACKLOG */ 00825 struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp); 00826 #endif /* TCP_LISTEN_BACKLOG */ 00827 if (lpcb == NULL) { 00828 msg->conn->err = ERR_MEM; 00829 } else { 00830 /* delete the recvmbox and allocate the acceptmbox */ 00831 if (msg->conn->recvmbox != SYS_MBOX_NULL) { 00832 /** @todo: should we drain the recvmbox here? */ 00833 sys_mbox_free(msg->conn->recvmbox); 00834 msg->conn->recvmbox = SYS_MBOX_NULL; 00835 } 00836 if (msg->conn->acceptmbox == SYS_MBOX_NULL) { 00837 if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) { 00838 msg->conn->err = ERR_MEM; 00839 } 00840 } 00841 if (msg->conn->err == ERR_OK) { 00842 msg->conn->state = NETCONN_LISTEN; 00843 msg->conn->pcb.tcp = lpcb; 00844 tcp_arg(msg->conn->pcb.tcp, msg->conn); 00845 tcp_accept(msg->conn->pcb.tcp, accept_function); 00846 } 00847 } 00848 } else { 00849 msg->conn->err = ERR_CONN; 00850 } 00851 } 00852 } 00853 } 00854 #endif /* LWIP_TCP */ 00855 TCPIP_APIMSG_ACK(msg); 00856 } 00857 00858 /** 00859 * Send some data on a RAW or UDP pcb contained in a netconn 00860 * Called from netconn_send 00861 * 00862 * @param msg the api_msg_msg pointing to the connection 00863 */ 00864 void 00865 do_send(struct api_msg_msg *msg) 00866 { 00867 if (!ERR_IS_FATAL(msg->conn->err)) { 00868 if (msg->conn->pcb.tcp != NULL) { 00869 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 00870 #if LWIP_RAW 00871 case NETCONN_RAW: 00872 if (msg->msg.b->addr == NULL) { 00873 msg->conn->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); 00874 } else { 00875 msg->conn->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr); 00876 } 00877 break; 00878 #endif 00879 #if LWIP_UDP 00880 case NETCONN_UDP: 00881 if (msg->msg.b->addr == NULL) { 00882 msg->conn->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); 00883 } else { 00884 msg->conn->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port); 00885 } 00886 break; 00887 #endif /* LWIP_UDP */ 00888 default: 00889 break; 00890 } 00891 } 00892 } 00893 TCPIP_APIMSG_ACK(msg); 00894 } 00895 00896 /** 00897 * Recv some data from a RAW or UDP pcb contained in a netconn 00898 * Called from netconn_recv 00899 * 00900 * @param msg the api_msg_msg pointing to the connection 00901 */ 00902 void 00903 do_recv(struct api_msg_msg *msg) 00904 { 00905 #if LWIP_TCP 00906 if (!ERR_IS_FATAL(msg->conn->err)) { 00907 if (msg->conn->pcb.tcp != NULL) { 00908 if (msg->conn->type == NETCONN_TCP) { 00909 #if TCP_LISTEN_BACKLOG 00910 if (msg->conn->pcb.tcp->state == LISTEN) { 00911 tcp_accepted(msg->conn->pcb.tcp); 00912 } else 00913 #endif /* TCP_LISTEN_BACKLOG */ 00914 { 00915 tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len); 00916 } 00917 } 00918 } 00919 } 00920 #endif /* LWIP_TCP */ 00921 TCPIP_APIMSG_ACK(msg); 00922 } 00923 00924 #if LWIP_TCP 00925 /** 00926 * See if more data needs to be written from a previous call to netconn_write. 00927 * Called initially from do_write. If the first call can't send all data 00928 * (because of low memory or empty send-buffer), this function is called again 00929 * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the 00930 * blocking application thread (waiting in netconn_write) is released. 00931 * 00932 * @param conn netconn (that is currently in state NETCONN_WRITE) to process 00933 * @return ERR_OK 00934 * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished 00935 */ 00936 static err_t 00937 do_writemore(struct netconn *conn) 00938 { 00939 err_t err; 00940 void *dataptr; 00941 u16_t len, available; 00942 u8_t write_finished = 0; 00943 00944 LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); 00945 00946 dataptr = (u8_t*)conn->write_msg->msg.w.dataptr + conn->write_offset; 00947 if ((conn->write_msg->msg.w.len - conn->write_offset > 0xffff)) { /* max_u16_t */ 00948 len = 0xffff; 00949 #if LWIP_TCPIP_CORE_LOCKING 00950 conn->write_delayed = 1; 00951 #endif 00952 } else { 00953 len = conn->write_msg->msg.w.len - conn->write_offset; 00954 } 00955 available = tcp_sndbuf(conn->pcb.tcp); 00956 if (available < len) { 00957 /* don't try to write more than sendbuf */ 00958 len = available; 00959 #if LWIP_TCPIP_CORE_LOCKING 00960 conn->write_delayed = 1; 00961 #endif 00962 } 00963 00964 err = tcp_write(conn->pcb.tcp, dataptr, len, conn->write_msg->msg.w.apiflags); 00965 LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->write_msg->msg.w.len)); 00966 if (err == ERR_OK) { 00967 conn->write_offset += len; 00968 if (conn->write_offset == conn->write_msg->msg.w.len) { 00969 /* everything was written */ 00970 write_finished = 1; 00971 conn->write_msg = NULL; 00972 conn->write_offset = 0; 00973 } 00974 err = tcp_output_nagle(conn->pcb.tcp); 00975 conn->err = err; 00976 if ((err == ERR_OK) && (tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT)) { 00977 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); 00978 } 00979 } else if (err == ERR_MEM) { 00980 /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called 00981 we do NOT return to the application thread, since ERR_MEM is 00982 only a temporary error! */ 00983 00984 /* tcp_enqueue returned ERR_MEM, try tcp_output anyway */ 00985 err = tcp_output(conn->pcb.tcp); 00986 00987 #if LWIP_TCPIP_CORE_LOCKING 00988 conn->write_delayed = 1; 00989 #endif 00990 } else { 00991 /* On errors != ERR_MEM, we don't try writing any more but return 00992 the error to the application thread. */ 00993 conn->err = err; 00994 write_finished = 1; 00995 } 00996 00997 if (write_finished) { 00998 /* everything was written: set back connection state 00999 and back to application task */ 01000 conn->state = NETCONN_NONE; 01001 #if LWIP_TCPIP_CORE_LOCKING 01002 if (conn->write_delayed != 0) 01003 #endif 01004 { 01005 sys_sem_signal(conn->op_completed); 01006 } 01007 } 01008 #if LWIP_TCPIP_CORE_LOCKING 01009 else 01010 return ERR_MEM; 01011 #endif 01012 return ERR_OK; 01013 } 01014 #endif /* LWIP_TCP */ 01015 01016 /** 01017 * Send some data on a TCP pcb contained in a netconn 01018 * Called from netconn_write 01019 * 01020 * @param msg the api_msg_msg pointing to the connection 01021 */ 01022 void 01023 do_write(struct api_msg_msg *msg) 01024 { 01025 if (!ERR_IS_FATAL(msg->conn->err)) { 01026 if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { 01027 #if LWIP_TCP 01028 msg->conn->state = NETCONN_WRITE; 01029 /* set all the variables used by do_writemore */ 01030 msg->conn->write_msg = msg; 01031 msg->conn->write_offset = 0; 01032 #if LWIP_TCPIP_CORE_LOCKING 01033 msg->conn->write_delayed = 0; 01034 if (do_writemore(msg->conn) != ERR_OK) { 01035 LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); 01036 UNLOCK_TCPIP_CORE(); 01037 sys_arch_sem_wait(msg->conn->op_completed, 0); 01038 LOCK_TCPIP_CORE(); 01039 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); 01040 } 01041 #else 01042 do_writemore(msg->conn); 01043 #endif 01044 /* for both cases: if do_writemore was called, don't ACK the APIMSG! */ 01045 return; 01046 #endif /* LWIP_TCP */ 01047 #if (LWIP_UDP || LWIP_RAW) 01048 } else { 01049 msg->conn->err = ERR_VAL; 01050 #endif /* (LWIP_UDP || LWIP_RAW) */ 01051 } 01052 } 01053 TCPIP_APIMSG_ACK(msg); 01054 } 01055 01056 /** 01057 * Return a connection's local or remote address 01058 * Called from netconn_getaddr 01059 * 01060 * @param msg the api_msg_msg pointing to the connection 01061 */ 01062 void 01063 do_getaddr(struct api_msg_msg *msg) 01064 { 01065 if (msg->conn->pcb.ip != NULL) { 01066 *(msg->msg.ad.ipaddr) = (msg->msg.ad.local?msg->conn->pcb.ip->local_ip:msg->conn->pcb.ip->remote_ip); 01067 01068 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 01069 #if LWIP_RAW 01070 case NETCONN_RAW: 01071 if (msg->msg.ad.local) { 01072 *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; 01073 } else { 01074 /* return an error as connecting is only a helper for upper layers */ 01075 msg->conn->err = ERR_CONN; 01076 } 01077 break; 01078 #endif /* LWIP_RAW */ 01079 #if LWIP_UDP 01080 case NETCONN_UDP: 01081 if (msg->msg.ad.local) { 01082 *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; 01083 } else { 01084 if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { 01085 msg->conn->err = ERR_CONN; 01086 } else { 01087 *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; 01088 } 01089 } 01090 break; 01091 #endif /* LWIP_UDP */ 01092 #if LWIP_TCP 01093 case NETCONN_TCP: 01094 *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port); 01095 break; 01096 #endif /* LWIP_TCP */ 01097 } 01098 } else { 01099 msg->conn->err = ERR_CONN; 01100 } 01101 TCPIP_APIMSG_ACK(msg); 01102 } 01103 01104 /** 01105 * Close a TCP pcb contained in a netconn 01106 * Called from netconn_close 01107 * 01108 * @param msg the api_msg_msg pointing to the connection 01109 */ 01110 void 01111 do_close(struct api_msg_msg *msg) 01112 { 01113 #if LWIP_TCP 01114 if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { 01115 msg->conn->state = NETCONN_CLOSE; 01116 do_close_internal(msg->conn); 01117 /* for tcp netconns, do_close_internal ACKs the message */ 01118 } else 01119 #endif /* LWIP_TCP */ 01120 { 01121 msg->conn->err = ERR_VAL; 01122 TCPIP_APIMSG_ACK(msg); 01123 } 01124 } 01125 01126 #if LWIP_IGMP 01127 /** 01128 * Join multicast groups for UDP netconns. 01129 * Called from netconn_join_leave_group 01130 * 01131 * @param msg the api_msg_msg pointing to the connection 01132 */ 01133 void 01134 do_join_leave_group(struct api_msg_msg *msg) 01135 { 01136 if (!ERR_IS_FATAL(msg->conn->err)) { 01137 if (msg->conn->pcb.tcp != NULL) { 01138 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 01139 #if LWIP_UDP 01140 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 01141 msg->conn->err = igmp_joingroup(msg->msg.jl.interface, msg->msg.jl.multiaddr); 01142 } else { 01143 msg->conn->err = igmp_leavegroup(msg->msg.jl.interface, msg->msg.jl.multiaddr); 01144 } 01145 #endif /* LWIP_UDP */ 01146 #if (LWIP_TCP || LWIP_RAW) 01147 } else { 01148 msg->conn->err = ERR_VAL; 01149 #endif /* (LWIP_TCP || LWIP_RAW) */ 01150 } 01151 } 01152 } 01153 TCPIP_APIMSG_ACK(msg); 01154 } 01155 #endif /* LWIP_IGMP */ 01156 01157 #if LWIP_DNS 01158 /** 01159 * Callback function that is called when DNS name is resolved 01160 * (or on timeout). A waiting application thread is waked up by 01161 * signaling the semaphore. 01162 */ 01163 static void 01164 do_dns_found(const char *name, struct ip_addr *ipaddr, void *arg) 01165 { 01166 struct dns_api_msg *msg = (struct dns_api_msg*)arg; 01167 01168 LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0); 01169 01170 if (ipaddr == NULL) { 01171 /* timeout or memory error */ 01172 *msg->err = ERR_VAL; 01173 } else { 01174 /* address was resolved */ 01175 *msg->err = ERR_OK; 01176 *msg->addr = *ipaddr; 01177 } 01178 /* wake up the application task waiting in netconn_gethostbyname */ 01179 sys_sem_signal(msg->sem); 01180 } 01181 01182 /** 01183 * Execute a DNS query 01184 * Called from netconn_gethostbyname 01185 * 01186 * @param arg the dns_api_msg pointing to the query 01187 */ 01188 void 01189 do_gethostbyname(void *arg) 01190 { 01191 struct dns_api_msg *msg = (struct dns_api_msg*)arg; 01192 01193 *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg); 01194 if (*msg->err != ERR_INPROGRESS) { 01195 /* on error or immediate success, wake up the application 01196 * task waiting in netconn_gethostbyname */ 01197 sys_sem_signal(msg->sem); 01198 } 01199 } 01200 #endif /* LWIP_DNS */ 01201 01202 #endif /* LWIP_NETCONN */
Generated on Tue Jul 12 2022 16:07:01 by
1.7.2
