ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

api_msg.c
Go to the documentation of this file.
00001 
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 #include <string.h>
00056 
00057 #define SET_NONBLOCKING_CONNECT(conn, val)  do { if(val) { \
00058   (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \
00059 } else { \
00060   (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0)
00061 #define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0)
00062 
00063 /* forward declarations */
00064 #if LWIP_TCP
00065 static err_t do_writemore(struct netconn *conn);
00066 static void do_close_internal(struct netconn *conn);
00067 #endif
00068 
00069 #if LWIP_RAW
00070 
00077 static u8_t
00078 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
00079     ip_addr_t *addr)
00080 {
00081   struct pbuf *q;
00082   struct netbuf *buf;
00083   struct netconn *conn;
00084 
00085   LWIP_UNUSED_ARG(addr);
00086   conn = (struct netconn *)arg;
00087 
00088   if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) {
00089 #if LWIP_SO_RCVBUF
00090     int recv_avail;
00091     SYS_ARCH_GET(conn->recv_avail, recv_avail);
00092     if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
00093       return 0;
00094     }
00095 #endif /* LWIP_SO_RCVBUF */
00096     /* copy the whole packet into new pbufs */
00097     q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
00098     if(q != NULL) {
00099       if (pbuf_copy(q, p) != ERR_OK) {
00100         pbuf_free(q);
00101         q = NULL;
00102       }
00103     }
00104 
00105     if (q != NULL) {
00106       u16_t len;
00107       buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
00108       if (buf == NULL) {
00109         pbuf_free(q);
00110         return 0;
00111       }
00112 
00113       buf->p = q;
00114       buf->ptr = q;
00115       ip_addr_copy(buf->addr, *ip_current_src_addr());
00116       buf->port = pcb->protocol;
00117 
00118       len = q->tot_len;
00119       if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
00120         netbuf_delete(buf);
00121         return 0;
00122       } else {
00123 #if LWIP_SO_RCVBUF
00124         SYS_ARCH_INC(conn->recv_avail, len);
00125 #endif /* LWIP_SO_RCVBUF */
00126         /* Register event with callback */
00127         API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
00128       }
00129     }
00130   }
00131 
00132   return 0; /* do not eat the packet */
00133 }
00134 #endif /* LWIP_RAW*/
00135 
00136 #if LWIP_UDP
00137 
00143 static void
00144 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
00145    ip_addr_t *addr, u16_t port)
00146 {
00147   struct netbuf *buf;
00148   struct netconn *conn;
00149   u16_t len;
00150 #if LWIP_SO_RCVBUF
00151   int recv_avail;
00152 #endif /* LWIP_SO_RCVBUF */
00153 
00154   LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
00155   LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
00156   LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
00157   conn = (struct netconn *)arg;
00158   LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
00159 
00160 #if LWIP_SO_RCVBUF
00161   SYS_ARCH_GET(conn->recv_avail, recv_avail);
00162   if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) ||
00163       ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
00164 #else  /* LWIP_SO_RCVBUF */
00165   if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) {
00166 #endif /* LWIP_SO_RCVBUF */
00167     pbuf_free(p);
00168     return;
00169   }
00170 
00171   buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
00172   if (buf == NULL) {
00173     pbuf_free(p);
00174     return;
00175   } else {
00176     buf->p = p;
00177     buf->ptr = p;
00178     ip_addr_set(&buf->addr, addr);
00179     buf->port = port;
00180 #if LWIP_NETBUF_RECVINFO
00181     {
00182       const struct ip_hdr* iphdr = ip_current_header();
00183       /* get the UDP header - always in the first pbuf, ensured by udp_input */
00184       const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
00185 #if LWIP_CHECKSUM_ON_COPY
00186       buf->flags = NETBUF_FLAG_DESTADDR;
00187 #endif /* LWIP_CHECKSUM_ON_COPY */
00188       ip_addr_set(&buf->toaddr, ip_current_dest_addr());
00189       buf->toport_chksum = udphdr->dest;
00190     }
00191 #endif /* LWIP_NETBUF_RECVINFO */
00192   }
00193 
00194   len = p->tot_len;
00195   if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
00196     netbuf_delete(buf);
00197     return;
00198   } else {
00199 #if LWIP_SO_RCVBUF
00200     SYS_ARCH_INC(conn->recv_avail, len);
00201 #endif /* LWIP_SO_RCVBUF */
00202     /* Register event with callback */
00203     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
00204   }
00205 }
00206 #endif /* LWIP_UDP */
00207 
00208 #if LWIP_TCP
00209 
00215 static err_t
00216 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
00217 {
00218   struct netconn *conn;
00219   u16_t len;
00220 
00221   LWIP_UNUSED_ARG(pcb);
00222   LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
00223   LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
00224   conn = (struct netconn *)arg;
00225   LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
00226 
00227   if (conn == NULL) {
00228     return ERR_VAL;
00229   }
00230   if (!sys_mbox_valid(&conn->recvmbox)) {
00231     /* recvmbox already deleted */
00232     if (p != NULL) {
00233       tcp_recved(pcb, p->tot_len);
00234       pbuf_free(p);
00235     }
00236     return ERR_OK;
00237   }
00238   /* Unlike for UDP or RAW pcbs, don't check for available space
00239      using recv_avail since that could break the connection
00240      (data is already ACKed) */
00241 
00242   /* don't overwrite fatal errors! */
00243   NETCONN_SET_SAFE_ERR(conn, err);
00244 
00245   if (p != NULL) {
00246     len = p->tot_len;
00247   } else {
00248     len = 0;
00249   }
00250 
00251   if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) {
00252     /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
00253     return ERR_MEM;
00254   } else {
00255 #if LWIP_SO_RCVBUF
00256     SYS_ARCH_INC(conn->recv_avail, len);
00257 #endif /* LWIP_SO_RCVBUF */
00258     /* Register event with callback */
00259     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
00260   }
00261 
00262   return ERR_OK;
00263 }
00264 
00276 static err_t
00277 poll_tcp(void *arg, struct tcp_pcb *pcb)
00278 {
00279   struct netconn *conn = (struct netconn *)arg;
00280 
00281   LWIP_UNUSED_ARG(pcb);
00282   LWIP_ASSERT("conn != NULL", (conn != NULL));
00283 
00284   if (conn->state == NETCONN_WRITE) {
00285     do_writemore(conn);
00286   } else if (conn->state == NETCONN_CLOSE) {
00287     do_close_internal(conn);
00288   }
00289   /* @todo: implement connect timeout here? */
00290 
00291   /* Did a nonblocking write fail before? Then check available write-space. */
00292   if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
00293     /* If the queued byte- or pbuf-count drops below the configured low-water limit,
00294        let select mark this pcb as writable again. */
00295     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
00296       (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
00297       conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
00298       API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
00299     }
00300   }
00301 
00302   return ERR_OK;
00303 }
00304 
00312 static err_t
00313 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
00314 {
00315   struct netconn *conn = (struct netconn *)arg;
00316 
00317   LWIP_UNUSED_ARG(pcb);
00318   LWIP_ASSERT("conn != NULL", (conn != NULL));
00319 
00320   if (conn->state == NETCONN_WRITE) {
00321     do_writemore(conn);
00322   } else if (conn->state == NETCONN_CLOSE) {
00323     do_close_internal(conn);
00324   }
00325 
00326   if (conn) {
00327     /* If the queued byte- or pbuf-count drops below the configured low-water limit,
00328        let select mark this pcb as writable again. */
00329     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
00330       (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
00331       conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
00332       API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
00333     }
00334   }
00335   
00336   return ERR_OK;
00337 }
00338 
00346 static void
00347 err_tcp(void *arg, err_t err)
00348 {
00349   struct netconn *conn;
00350   enum netconn_state old_state;
00351   SYS_ARCH_DECL_PROTECT(lev);
00352 
00353   conn = (struct netconn *)arg;
00354   LWIP_ASSERT("conn != NULL", (conn != NULL));
00355 
00356   conn->pcb.tcp = NULL;
00357 
00358   /* no check since this is always fatal! */
00359   SYS_ARCH_PROTECT(lev);
00360   conn->last_err = err;
00361   SYS_ARCH_UNPROTECT(lev);
00362 
00363   /* reset conn->state now before waking up other threads */
00364   old_state = conn->state;
00365   conn->state = NETCONN_NONE;
00366 
00367   /* Notify the user layer about a connection error. Used to signal
00368      select. */
00369   API_EVENT(conn, NETCONN_EVT_ERROR, 0);
00370   /* Try to release selects pending on 'read' or 'write', too.
00371      They will get an error if they actually try to read or write. */
00372   API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
00373   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
00374 
00375   /* pass NULL-message to recvmbox to wake up pending recv */
00376   if (sys_mbox_valid(&conn->recvmbox)) {
00377     /* use trypost to prevent deadlock */
00378     sys_mbox_trypost(&conn->recvmbox, NULL);
00379   }
00380   /* pass NULL-message to acceptmbox to wake up pending accept */
00381   if (sys_mbox_valid(&conn->acceptmbox)) {
00382     /* use trypost to preven deadlock */
00383     sys_mbox_trypost(&conn->acceptmbox, NULL);
00384   }
00385 
00386   if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
00387       (old_state == NETCONN_CONNECT)) {
00388     /* calling do_writemore/do_close_internal is not necessary
00389        since the pcb has already been deleted! */
00390     int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
00391     SET_NONBLOCKING_CONNECT(conn, 0);
00392 
00393     if (!was_nonblocking_connect) {
00394       /* set error return code */
00395       LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
00396       conn->current_msg->err = err;
00397       conn->current_msg = NULL;
00398       /* wake up the waiting task */
00399       sys_sem_signal(&conn->op_completed);
00400     }
00401   } else {
00402     LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
00403   }
00404 }
00405 
00412 static void
00413 setup_tcp(struct netconn *conn)
00414 {
00415   struct tcp_pcb *pcb;
00416 
00417   pcb = conn->pcb.tcp;
00418   tcp_arg(pcb, conn);
00419   tcp_recv(pcb, recv_tcp);
00420   tcp_sent(pcb, sent_tcp);
00421   tcp_poll(pcb, poll_tcp, 4);
00422   tcp_err(pcb, err_tcp);
00423 }
00424 
00431 static err_t
00432 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
00433 {
00434   struct netconn *newconn;
00435   struct netconn *conn = (struct netconn *)arg;
00436 
00437   LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state)));
00438 
00439   if (!sys_mbox_valid(&conn->acceptmbox)) {
00440     LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
00441     return ERR_VAL;
00442   }
00443 
00444   /* We have to set the callback here even though
00445    * the new socket is unknown. conn->socket is marked as -1. */
00446   newconn = netconn_alloc(conn->type, conn->callback);
00447   if (newconn == NULL) {
00448     return ERR_MEM;
00449   }
00450   newconn->pcb.tcp = newpcb;
00451   setup_tcp(newconn);
00452   /* no protection: when creating the pcb, the netconn is not yet known
00453      to the application thread */
00454   newconn->last_err = err;
00455 
00456   if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
00457     /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
00458        so do nothing here! */
00459     newconn->pcb.tcp = NULL;
00460     /* no need to drain since we know the recvmbox is empty. */
00461     sys_mbox_free(&newconn->recvmbox);
00462     sys_mbox_set_invalid(&newconn->recvmbox);
00463     netconn_free(newconn);
00464     return ERR_MEM;
00465   } else {
00466     /* Register event with callback */
00467     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
00468   }
00469 
00470   return ERR_OK;
00471 }
00472 #endif /* LWIP_TCP */
00473 
00481 static void
00482 pcb_new(struct api_msg_msg *msg)
00483 {
00484   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
00485 
00486   /* Allocate a PCB for this connection */
00487   switch(NETCONNTYPE_GROUP(msg->conn->type)) {
00488 #if LWIP_RAW
00489   case NETCONN_RAW:
00490     msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
00491     if(msg->conn->pcb.raw == NULL) {
00492       msg->err = ERR_MEM;
00493       break;
00494     }
00495     raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
00496     break;
00497 #endif /* LWIP_RAW */
00498 #if LWIP_UDP
00499   case NETCONN_UDP:
00500     msg->conn->pcb.udp = udp_new();
00501     if(msg->conn->pcb.udp == NULL) {
00502       msg->err = ERR_MEM;
00503       break;
00504     }
00505 #if LWIP_UDPLITE
00506     if (msg->conn->type==NETCONN_UDPLITE) {
00507       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
00508     }
00509 #endif /* LWIP_UDPLITE */
00510     if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
00511       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
00512     }
00513     udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
00514     break;
00515 #endif /* LWIP_UDP */
00516 #if LWIP_TCP
00517   case NETCONN_TCP:
00518     msg->conn->pcb.tcp = tcp_new();
00519     if(msg->conn->pcb.tcp == NULL) {
00520       msg->err = ERR_MEM;
00521       break;
00522     }
00523     setup_tcp(msg->conn);
00524     break;
00525 #endif /* LWIP_TCP */
00526   default:
00527     /* Unsupported netconn type, e.g. protocol disabled */
00528     msg->err = ERR_VAL;
00529     break;
00530   }
00531 }
00532 
00539 void
00540 do_newconn(struct api_msg_msg *msg)
00541 {
00542   msg->err = ERR_OK;
00543   if(msg->conn->pcb.tcp == NULL) {
00544     pcb_new(msg);
00545   }
00546   /* Else? This "new" connection already has a PCB allocated. */
00547   /* Is this an error condition? Should it be deleted? */
00548   /* We currently just are happy and return. */
00549 
00550   TCPIP_APIMSG_ACK(msg);
00551 }
00552 
00563 struct netconn*
00564 netconn_alloc(enum netconn_type t, netconn_callback callback)
00565 {
00566   struct netconn *conn;
00567   int size;
00568 
00569   conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
00570   if (conn == NULL) {
00571     return NULL;
00572   }
00573 
00574   conn->last_err = ERR_OK;
00575   conn->type = t;
00576   conn->pcb.tcp = NULL;
00577 
00578 #if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \
00579     (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE)
00580   size = DEFAULT_RAW_RECVMBOX_SIZE;
00581 #else
00582   switch(NETCONNTYPE_GROUP(t)) {
00583 #if LWIP_RAW
00584   case NETCONN_RAW:
00585     size = DEFAULT_RAW_RECVMBOX_SIZE;
00586     break;
00587 #endif /* LWIP_RAW */
00588 #if LWIP_UDP
00589   case NETCONN_UDP:
00590     size = DEFAULT_UDP_RECVMBOX_SIZE;
00591     break;
00592 #endif /* LWIP_UDP */
00593 #if LWIP_TCP
00594   case NETCONN_TCP:
00595     size = DEFAULT_TCP_RECVMBOX_SIZE;
00596     break;
00597 #endif /* LWIP_TCP */
00598   default:
00599     LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
00600     break;
00601   }
00602 #endif
00603 
00604   if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
00605     memp_free(MEMP_NETCONN, conn);
00606     return NULL;
00607   }
00608   if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
00609     sys_sem_free(&conn->op_completed);
00610     memp_free(MEMP_NETCONN, conn);
00611     return NULL;
00612   }
00613 
00614 #if LWIP_TCP
00615   sys_mbox_set_invalid(&conn->acceptmbox);
00616 #endif
00617   conn->state        = NETCONN_NONE;
00618 #if LWIP_SOCKET
00619   /* initialize socket to -1 since 0 is a valid socket */
00620   conn->socket       = -1;
00621 #endif /* LWIP_SOCKET */
00622   conn->callback     = callback;
00623 #if LWIP_TCP
00624   conn->current_msg  = NULL;
00625   conn->write_offset = 0;
00626 #endif /* LWIP_TCP */
00627 #if LWIP_SO_RCVTIMEO
00628   conn->recv_timeout = 0;
00629 #endif /* LWIP_SO_RCVTIMEO */
00630 #if LWIP_SO_RCVBUF
00631   conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
00632   conn->recv_avail   = 0;
00633 #endif /* LWIP_SO_RCVBUF */
00634   conn->flags = 0;
00635   return conn;
00636 }
00637 
00644 void
00645 netconn_free(struct netconn *conn)
00646 {
00647   LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
00648   LWIP_ASSERT("recvmbox must be deallocated before calling this function",
00649     !sys_mbox_valid(&conn->recvmbox));
00650 #if LWIP_TCP
00651   LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
00652     !sys_mbox_valid(&conn->acceptmbox));
00653 #endif /* LWIP_TCP */
00654 
00655   sys_sem_free(&conn->op_completed);
00656   sys_sem_set_invalid(&conn->op_completed);
00657 
00658   memp_free(MEMP_NETCONN, conn);
00659 }
00660 
00669 static void
00670 netconn_drain(struct netconn *conn)
00671 {
00672   void *mem;
00673 #if LWIP_TCP
00674   struct pbuf *p;
00675 #endif /* LWIP_TCP */
00676 
00677   /* This runs in tcpip_thread, so we don't need to lock against rx packets */
00678 
00679   /* Delete and drain the recvmbox. */
00680   if (sys_mbox_valid(&conn->recvmbox)) {
00681     while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
00682 #if LWIP_TCP
00683       if (conn->type == NETCONN_TCP) {
00684         if(mem != NULL) {
00685           p = (struct pbuf*)mem;
00686           /* pcb might be set to NULL already by err_tcp() */
00687           if (conn->pcb.tcp != NULL) {
00688             tcp_recved(conn->pcb.tcp, p->tot_len);
00689           }
00690           pbuf_free(p);
00691         }
00692       } else
00693 #endif /* LWIP_TCP */
00694       {
00695         netbuf_delete((struct netbuf *)mem);
00696       }
00697     }
00698     sys_mbox_free(&conn->recvmbox);
00699     sys_mbox_set_invalid(&conn->recvmbox);
00700   }
00701 
00702   /* Delete and drain the acceptmbox. */
00703 #if LWIP_TCP
00704   if (sys_mbox_valid(&conn->acceptmbox)) {
00705     while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
00706       struct netconn *newconn = (struct netconn *)mem;
00707       /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
00708       /* pcb might be set to NULL already by err_tcp() */
00709       if (conn->pcb.tcp != NULL) {
00710         tcp_accepted(conn->pcb.tcp);
00711       }
00712       /* drain recvmbox */
00713       netconn_drain(newconn);
00714       if (newconn->pcb.tcp != NULL) {
00715         tcp_abort(newconn->pcb.tcp);
00716         newconn->pcb.tcp = NULL;
00717       }
00718       netconn_free(newconn);
00719     }
00720     sys_mbox_free(&conn->acceptmbox);
00721     sys_mbox_set_invalid(&conn->acceptmbox);
00722   }
00723 #endif /* LWIP_TCP */
00724 }
00725 
00726 #if LWIP_TCP
00727 
00734 static void
00735 do_close_internal(struct netconn *conn)
00736 {
00737   err_t err;
00738   u8_t shut, shut_rx, shut_tx, close;
00739 
00740   LWIP_ASSERT("invalid conn", (conn != NULL));
00741   LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
00742   LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
00743   LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
00744   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
00745 
00746   shut = conn->current_msg->msg.sd.shut;
00747   shut_rx = shut & NETCONN_SHUT_RD;
00748   shut_tx = shut & NETCONN_SHUT_WR;
00749   /* shutting down both ends is the same as closing */
00750   close = shut == NETCONN_SHUT_RDWR;
00751 
00752   /* Set back some callback pointers */
00753   if (close) {
00754     tcp_arg(conn->pcb.tcp, NULL);
00755   }
00756   if (conn->pcb.tcp->state == LISTEN) {
00757     tcp_accept(conn->pcb.tcp, NULL);
00758   } else {
00759     /* some callbacks have to be reset if tcp_close is not successful */
00760     if (shut_rx) {
00761       tcp_recv(conn->pcb.tcp, NULL);
00762       tcp_accept(conn->pcb.tcp, NULL);
00763     }
00764     if (shut_tx) {
00765       tcp_sent(conn->pcb.tcp, NULL);
00766     }
00767     if (close) {
00768       tcp_poll(conn->pcb.tcp, NULL, 4);
00769       tcp_err(conn->pcb.tcp, NULL);
00770     }
00771   }
00772   /* Try to close the connection */
00773   if (shut == NETCONN_SHUT_RDWR) {
00774     err = tcp_close(conn->pcb.tcp);
00775   } else {
00776     err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR);
00777   }
00778   if (err == ERR_OK) {
00779     /* Closing succeeded */
00780     conn->current_msg->err = ERR_OK;
00781     conn->current_msg = NULL;
00782     conn->state = NETCONN_NONE;
00783     /* Set back some callback pointers as conn is going away */
00784     conn->pcb.tcp = NULL;
00785     /* Trigger select() in socket layer. Make sure everybody notices activity
00786        on the connection, error first! */
00787     if (close) {
00788       API_EVENT(conn, NETCONN_EVT_ERROR, 0);
00789     }
00790     if (shut_rx) {
00791       API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
00792     }
00793     if (shut_tx) {
00794       API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
00795     }
00796     /* wake up the application task */
00797     sys_sem_signal(&conn->op_completed);
00798   } else {
00799     /* Closing failed, restore some of the callbacks */
00800     /* Closing of listen pcb will never fail! */
00801     LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN));
00802     tcp_sent(conn->pcb.tcp, sent_tcp);
00803     tcp_poll(conn->pcb.tcp, poll_tcp, 4);
00804     tcp_err(conn->pcb.tcp, err_tcp);
00805     tcp_arg(conn->pcb.tcp, conn);
00806     /* don't restore recv callback: we don't want to receive any more data */
00807   }
00808   /* If closing didn't succeed, we get called again either
00809      from poll_tcp or from sent_tcp */
00810 }
00811 #endif /* LWIP_TCP */
00812 
00819 void
00820 do_delconn(struct api_msg_msg *msg)
00821 {
00822   /* @todo TCP: abort running write/connect? */
00823  if ((msg->conn->state != NETCONN_NONE) &&
00824      (msg->conn->state != NETCONN_LISTEN) &&
00825      (msg->conn->state != NETCONN_CONNECT)) {
00826     /* this only happens for TCP netconns */
00827     LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP);
00828     msg->err = ERR_INPROGRESS;
00829   } else {
00830     LWIP_ASSERT("blocking connect in progress",
00831       (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
00832     /* Drain and delete mboxes */
00833     netconn_drain(msg->conn);
00834 
00835     if (msg->conn->pcb.tcp != NULL) {
00836 
00837       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
00838 #if LWIP_RAW
00839       case NETCONN_RAW:
00840         raw_remove(msg->conn->pcb.raw);
00841         break;
00842 #endif /* LWIP_RAW */
00843 #if LWIP_UDP
00844       case NETCONN_UDP:
00845         msg->conn->pcb.udp->recv_arg = NULL;
00846         udp_remove(msg->conn->pcb.udp);
00847         break;
00848 #endif /* LWIP_UDP */
00849 #if LWIP_TCP
00850       case NETCONN_TCP:
00851         LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
00852           msg->conn->write_offset == 0);
00853         msg->conn->state = NETCONN_CLOSE;
00854         msg->msg.sd.shut = NETCONN_SHUT_RDWR;
00855         msg->conn->current_msg = msg;
00856         do_close_internal(msg->conn);
00857         /* API_EVENT is called inside do_close_internal, before releasing
00858            the application thread, so we can return at this point! */
00859         return;
00860 #endif /* LWIP_TCP */
00861       default:
00862         break;
00863       }
00864       msg->conn->pcb.tcp = NULL;
00865     }
00866     /* tcp netconns don't come here! */
00867 
00868     /* @todo: this lets select make the socket readable and writable,
00869        which is wrong! errfd instead? */
00870     API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
00871     API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
00872   }
00873   if (sys_sem_valid(&msg->conn->op_completed)) {
00874     sys_sem_signal(&msg->conn->op_completed);
00875   }
00876 }
00877 
00885 void
00886 do_bind(struct api_msg_msg *msg)
00887 {
00888   if (ERR_IS_FATAL(msg->conn->last_err)) {
00889     msg->err = msg->conn->last_err;
00890   } else {
00891     msg->err = ERR_VAL;
00892     if (msg->conn->pcb.tcp != NULL) {
00893       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
00894 #if LWIP_RAW
00895       case NETCONN_RAW:
00896         msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
00897         break;
00898 #endif /* LWIP_RAW */
00899 #if LWIP_UDP
00900       case NETCONN_UDP:
00901         msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
00902         break;
00903 #endif /* LWIP_UDP */
00904 #if LWIP_TCP
00905       case NETCONN_TCP:
00906         msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);
00907         break;
00908 #endif /* LWIP_TCP */
00909       default:
00910         break;
00911       }
00912     }
00913   }
00914   TCPIP_APIMSG_ACK(msg);
00915 }
00916 
00917 #if LWIP_TCP
00918 
00924 static err_t
00925 do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
00926 {
00927   struct netconn *conn;
00928   int was_blocking;
00929 
00930   LWIP_UNUSED_ARG(pcb);
00931 
00932   conn = (struct netconn *)arg;
00933 
00934   if (conn == NULL) {
00935     return ERR_VAL;
00936   }
00937 
00938   LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
00939   LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
00940     (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
00941 
00942   if (conn->current_msg != NULL) {
00943     conn->current_msg->err = err;
00944   }
00945   if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {
00946     setup_tcp(conn);
00947   }
00948   was_blocking = !IN_NONBLOCKING_CONNECT(conn);
00949   SET_NONBLOCKING_CONNECT(conn, 0);
00950   conn->current_msg = NULL;
00951   conn->state = NETCONN_NONE;
00952   if (!was_blocking) {
00953     NETCONN_SET_SAFE_ERR(conn, ERR_OK);
00954   }
00955   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
00956 
00957   if (was_blocking) {
00958     sys_sem_signal(&conn->op_completed);
00959   }
00960   return ERR_OK;
00961 }
00962 #endif /* LWIP_TCP */
00963 
00971 void
00972 do_connect(struct api_msg_msg *msg)
00973 {
00974   if (msg->conn->pcb.tcp == NULL) {
00975     /* This may happen when calling netconn_connect() a second time */
00976     msg->err = ERR_CLSD;
00977   } else {
00978     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
00979 #if LWIP_RAW
00980   case NETCONN_RAW:
00981     msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
00982     break;
00983 #endif /* LWIP_RAW */
00984 #if LWIP_UDP
00985   case NETCONN_UDP:
00986     msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
00987     break;
00988 #endif /* LWIP_UDP */
00989 #if LWIP_TCP
00990   case NETCONN_TCP:
00991     /* Prevent connect while doing any other action. */
00992     if (msg->conn->state != NETCONN_NONE) {
00993       msg->err = ERR_ISCONN;
00994     } else {
00995       setup_tcp(msg->conn);
00996       msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr,
00997         msg->msg.bc.port, do_connected);
00998       if (msg->err == ERR_OK) {
00999         u8_t non_blocking = netconn_is_nonblocking(msg->conn);
01000         msg->conn->state = NETCONN_CONNECT;
01001         SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
01002         if (non_blocking) {
01003           msg->err = ERR_INPROGRESS;
01004         } else {
01005           msg->conn->current_msg = msg;
01006           /* sys_sem_signal() is called from do_connected (or err_tcp()),
01007           * when the connection is established! */
01008           return;
01009         }
01010       }
01011     }
01012     break;
01013 #endif /* LWIP_TCP */
01014   default:
01015     LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
01016     break;
01017     }
01018   }
01019   sys_sem_signal(&msg->conn->op_completed);
01020 }
01021 
01029 void
01030 do_disconnect(struct api_msg_msg *msg)
01031 {
01032 #if LWIP_UDP
01033   if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
01034     udp_disconnect(msg->conn->pcb.udp);
01035     msg->err = ERR_OK;
01036   } else
01037 #endif /* LWIP_UDP */
01038   {
01039     msg->err = ERR_VAL;
01040   }
01041   TCPIP_APIMSG_ACK(msg);
01042 }
01043 
01044 #if LWIP_TCP
01045 
01051 void
01052 do_listen(struct api_msg_msg *msg)
01053 {
01054   if (ERR_IS_FATAL(msg->conn->last_err)) {
01055     msg->err = msg->conn->last_err;
01056   } else {
01057     msg->err = ERR_CONN;
01058     if (msg->conn->pcb.tcp != NULL) {
01059       if (msg->conn->type == NETCONN_TCP) {
01060         if (msg->conn->state == NETCONN_NONE) {
01061 #if TCP_LISTEN_BACKLOG
01062           struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
01063 #else  /* TCP_LISTEN_BACKLOG */
01064           struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);
01065 #endif /* TCP_LISTEN_BACKLOG */
01066           if (lpcb == NULL) {
01067             /* in this case, the old pcb is still allocated */
01068             msg->err = ERR_MEM;
01069           } else {
01070             /* delete the recvmbox and allocate the acceptmbox */
01071             if (sys_mbox_valid(&msg->conn->recvmbox)) {
01073               sys_mbox_free(&msg->conn->recvmbox);
01074               sys_mbox_set_invalid(&msg->conn->recvmbox);
01075             }
01076             msg->err = ERR_OK;
01077             if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
01078               msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
01079             }
01080             if (msg->err == ERR_OK) {
01081               msg->conn->state = NETCONN_LISTEN;
01082               msg->conn->pcb.tcp = lpcb;
01083               tcp_arg(msg->conn->pcb.tcp, msg->conn);
01084               tcp_accept(msg->conn->pcb.tcp, accept_function);
01085             } else {
01086               /* since the old pcb is already deallocated, free lpcb now */
01087               tcp_close(lpcb);
01088               msg->conn->pcb.tcp = NULL;
01089             }
01090           }
01091         }
01092       }
01093     }
01094   }
01095   TCPIP_APIMSG_ACK(msg);
01096 }
01097 #endif /* LWIP_TCP */
01098 
01105 void
01106 do_send(struct api_msg_msg *msg)
01107 {
01108   if (ERR_IS_FATAL(msg->conn->last_err)) {
01109     msg->err = msg->conn->last_err;
01110   } else {
01111     msg->err = ERR_CONN;
01112     if (msg->conn->pcb.tcp != NULL) {
01113       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01114 #if LWIP_RAW
01115       case NETCONN_RAW:
01116         if (ip_addr_isany(&msg->msg.b->addr)) {
01117           msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
01118         } else {
01119           msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
01120         }
01121         break;
01122 #endif
01123 #if LWIP_UDP
01124       case NETCONN_UDP:
01125 #if LWIP_CHECKSUM_ON_COPY
01126         if (ip_addr_isany(&msg->msg.b->addr)) {
01127           msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
01128             msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
01129         } else {
01130           msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
01131             &msg->msg.b->addr, msg->msg.b->port,
01132             msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
01133         }
01134 #else /* LWIP_CHECKSUM_ON_COPY */
01135         if (ip_addr_isany(&msg->msg.b->addr)) {
01136           msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
01137         } else {
01138           msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
01139         }
01140 #endif /* LWIP_CHECKSUM_ON_COPY */
01141         break;
01142 #endif /* LWIP_UDP */
01143       default:
01144         break;
01145       }
01146     }
01147   }
01148   TCPIP_APIMSG_ACK(msg);
01149 }
01150 
01151 #if LWIP_TCP
01152 
01158 void
01159 do_recv(struct api_msg_msg *msg)
01160 {
01161   msg->err = ERR_OK;
01162   if (msg->conn->pcb.tcp != NULL) {
01163     if (msg->conn->type == NETCONN_TCP) {
01164 #if TCP_LISTEN_BACKLOG
01165       if (msg->conn->pcb.tcp->state == LISTEN) {
01166         tcp_accepted(msg->conn->pcb.tcp);
01167       } else
01168 #endif /* TCP_LISTEN_BACKLOG */
01169       {
01170         u32_t remaining = msg->msg.r.len;
01171         do {
01172           u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
01173           tcp_recved(msg->conn->pcb.tcp, recved);
01174           remaining -= recved;
01175         }while(remaining != 0);
01176       }
01177     }
01178   }
01179   TCPIP_APIMSG_ACK(msg);
01180 }
01181 
01193 static err_t
01194 do_writemore(struct netconn *conn)
01195 {
01196   err_t err = ERR_OK;
01197   void *dataptr;
01198   u16_t len, available;
01199   u8_t write_finished = 0;
01200   size_t diff;
01201   u8_t dontblock = netconn_is_nonblocking(conn) ||
01202        (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK);
01203   u8_t apiflags = conn->current_msg->msg.w.apiflags;
01204 
01205   LWIP_ASSERT("conn != NULL", conn != NULL);
01206   LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
01207   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
01208   LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
01209   LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
01210     conn->write_offset < conn->current_msg->msg.w.len);
01211 
01212   dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
01213   diff = conn->current_msg->msg.w.len - conn->write_offset;
01214   if (diff > 0xffffUL) { /* max_u16_t */
01215     len = 0xffff;
01216 #if LWIP_TCPIP_CORE_LOCKING
01217     conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
01218 #endif
01219     apiflags |= TCP_WRITE_FLAG_MORE;
01220   } else {
01221     len = (u16_t)diff;
01222   }
01223   available = tcp_sndbuf(conn->pcb.tcp);
01224   if (available < len) {
01225     /* don't try to write more than sendbuf */
01226     len = available;
01227 #if LWIP_TCPIP_CORE_LOCKING
01228     conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
01229 #endif
01230     apiflags |= TCP_WRITE_FLAG_MORE;
01231   }
01232   if (dontblock && (len < conn->current_msg->msg.w.len)) {
01233     /* failed to send all data at once -> nonblocking write not possible */
01234     err = ERR_MEM;
01235   }
01236   if (err == ERR_OK) {
01237     LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
01238     err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
01239   }
01240   if (dontblock && (err == ERR_MEM)) {
01241     /* nonblocking write failed */
01242     write_finished = 1;
01243     err = ERR_WOULDBLOCK;
01244     /* let poll_tcp check writable space to mark the pcb
01245        writable again */
01246     conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
01247     /* let select mark this pcb as non-writable. */
01248     API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
01249   } else {
01250     /* if OK or memory error, check available space */
01251     if (((err == ERR_OK) || (err == ERR_MEM)) &&
01252         ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
01253          (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT))) {
01254       /* The queued byte- or pbuf-count exceeds the configured low-water limit,
01255          let select mark this pcb as non-writable. */
01256       API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
01257     }
01258 
01259     if (err == ERR_OK) {
01260       conn->write_offset += len;
01261       if (conn->write_offset == conn->current_msg->msg.w.len) {
01262         /* everything was written */
01263         write_finished = 1;
01264         conn->write_offset = 0;
01265       }
01266       tcp_output(conn->pcb.tcp);
01267     } else if (err == ERR_MEM) {
01268       /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
01269          we do NOT return to the application thread, since ERR_MEM is
01270          only a temporary error! */
01271 
01272       /* tcp_write returned ERR_MEM, try tcp_output anyway */
01273       tcp_output(conn->pcb.tcp);
01274 
01275   #if LWIP_TCPIP_CORE_LOCKING
01276       conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
01277   #endif
01278     } else {
01279       /* On errors != ERR_MEM, we don't try writing any more but return
01280          the error to the application thread. */
01281       write_finished = 1;
01282     }
01283   }
01284 
01285   if (write_finished) {
01286     /* everything was written: set back connection state
01287        and back to application task */
01288     conn->current_msg->err = err;
01289     conn->current_msg = NULL;
01290     conn->state = NETCONN_NONE;
01291 #if LWIP_TCPIP_CORE_LOCKING
01292     if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0)
01293 #endif
01294     {
01295       sys_sem_signal(&conn->op_completed);
01296     }
01297   }
01298 #if LWIP_TCPIP_CORE_LOCKING
01299   else
01300     return ERR_MEM;
01301 #endif
01302   return ERR_OK;
01303 }
01304 #endif /* LWIP_TCP */
01305 
01312 void
01313 do_write(struct api_msg_msg *msg)
01314 {
01315   if (ERR_IS_FATAL(msg->conn->last_err)) {
01316     msg->err = msg->conn->last_err;
01317   } else {
01318     if (msg->conn->type == NETCONN_TCP) {
01319 #if LWIP_TCP
01320       if (msg->conn->state != NETCONN_NONE) {
01321         /* netconn is connecting, closing or in blocking write */
01322         msg->err = ERR_INPROGRESS;
01323       } else if (msg->conn->pcb.tcp != NULL) {
01324         msg->conn->state = NETCONN_WRITE;
01325         /* set all the variables used by do_writemore */
01326         LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
01327           msg->conn->write_offset == 0);
01328         LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
01329         msg->conn->current_msg = msg;
01330         msg->conn->write_offset = 0;
01331 #if LWIP_TCPIP_CORE_LOCKING
01332         msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED;
01333         if (do_writemore(msg->conn) != ERR_OK) {
01334           LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
01335           UNLOCK_TCPIP_CORE();
01336           sys_arch_sem_wait(&msg->conn->op_completed, 0);
01337           LOCK_TCPIP_CORE();
01338           LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
01339         }
01340 #else /* LWIP_TCPIP_CORE_LOCKING */
01341         do_writemore(msg->conn);
01342 #endif /* LWIP_TCPIP_CORE_LOCKING */
01343         /* for both cases: if do_writemore was called, don't ACK the APIMSG
01344            since do_writemore ACKs it! */
01345         return;
01346       } else {
01347         msg->err = ERR_CONN;
01348       }
01349 #else /* LWIP_TCP */
01350       msg->err = ERR_VAL;
01351 #endif /* LWIP_TCP */
01352 #if (LWIP_UDP || LWIP_RAW)
01353     } else {
01354       msg->err = ERR_VAL;
01355 #endif /* (LWIP_UDP || LWIP_RAW) */
01356     }
01357   }
01358   TCPIP_APIMSG_ACK(msg);
01359 }
01360 
01367 void
01368 do_getaddr(struct api_msg_msg *msg)
01369 {
01370   if (msg->conn->pcb.ip != NULL) {
01371     *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip :
01372                              msg->conn->pcb.ip->remote_ip);
01373 
01374     msg->err = ERR_OK;
01375     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01376 #if LWIP_RAW
01377     case NETCONN_RAW:
01378       if (msg->msg.ad.local) {
01379         *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
01380       } else {
01381         /* return an error as connecting is only a helper for upper layers */
01382         msg->err = ERR_CONN;
01383       }
01384       break;
01385 #endif /* LWIP_RAW */
01386 #if LWIP_UDP
01387     case NETCONN_UDP:
01388       if (msg->msg.ad.local) {
01389         *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
01390       } else {
01391         if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
01392           msg->err = ERR_CONN;
01393         } else {
01394           *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
01395         }
01396       }
01397       break;
01398 #endif /* LWIP_UDP */
01399 #if LWIP_TCP
01400     case NETCONN_TCP:
01401       *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port);
01402       break;
01403 #endif /* LWIP_TCP */
01404     default:
01405       LWIP_ASSERT("invalid netconn_type", 0);
01406       break;
01407     }
01408   } else {
01409     msg->err = ERR_CONN;
01410   }
01411   TCPIP_APIMSG_ACK(msg);
01412 }
01413 
01420 void
01421 do_close(struct api_msg_msg *msg)
01422 {
01423 #if LWIP_TCP
01424   /* @todo: abort running write/connect? */
01425   if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) {
01426     /* this only happens for TCP netconns */
01427     LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP);
01428     msg->err = ERR_INPROGRESS;
01429   } else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
01430     if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) {
01431       /* LISTEN doesn't support half shutdown */
01432       msg->err = ERR_CONN;
01433     } else {
01434       if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
01435         /* Drain and delete mboxes */
01436         netconn_drain(msg->conn);
01437       }
01438       LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
01439         msg->conn->write_offset == 0);
01440       msg->conn->state = NETCONN_CLOSE;
01441       msg->conn->current_msg = msg;
01442       do_close_internal(msg->conn);
01443       /* for tcp netconns, do_close_internal ACKs the message */
01444       return;
01445     }
01446   } else
01447 #endif /* LWIP_TCP */
01448   {
01449     msg->err = ERR_VAL;
01450   }
01451   sys_sem_signal(&msg->conn->op_completed);
01452 }
01453 
01454 #if LWIP_IGMP
01455 
01461 void
01462 do_join_leave_group(struct api_msg_msg *msg)
01463 { 
01464   if (ERR_IS_FATAL(msg->conn->last_err)) {
01465     msg->err = msg->conn->last_err;
01466   } else {
01467     if (msg->conn->pcb.tcp != NULL) {
01468       if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
01469 #if LWIP_UDP
01470         if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
01471           msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
01472         } else {
01473           msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
01474         }
01475 #endif /* LWIP_UDP */
01476 #if (LWIP_TCP || LWIP_RAW)
01477       } else {
01478         msg->err = ERR_VAL;
01479 #endif /* (LWIP_TCP || LWIP_RAW) */
01480       }
01481     } else {
01482       msg->err = ERR_CONN;
01483     }
01484   }
01485   TCPIP_APIMSG_ACK(msg);
01486 }
01487 #endif /* LWIP_IGMP */
01488 
01489 #if LWIP_DNS
01490 
01495 static void
01496 do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
01497 {
01498   struct dns_api_msg *msg = (struct dns_api_msg*)arg;
01499 
01500   LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0);
01501   LWIP_UNUSED_ARG(name);
01502 
01503   if (ipaddr == NULL) {
01504     /* timeout or memory error */
01505     *msg->err = ERR_VAL;
01506   } else {
01507     /* address was resolved */
01508     *msg->err = ERR_OK;
01509     *msg->addr = *ipaddr;
01510   }
01511   /* wake up the application task waiting in netconn_gethostbyname */
01512   sys_sem_signal(msg->sem);
01513 }
01514 
01521 void
01522 do_gethostbyname(void *arg)
01523 {
01524   struct dns_api_msg *msg = (struct dns_api_msg*)arg;
01525 
01526   *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg);
01527   if (*msg->err != ERR_INPROGRESS) {
01528     /* on error or immediate success, wake up the application
01529      * task waiting in netconn_gethostbyname */
01530     sys_sem_signal(msg->sem);
01531   }
01532 }
01533 #endif /* LWIP_DNS */
01534 
01535 #endif /* LWIP_NETCONN */

Generated on Sat May 26 2012 04:34:56 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.