Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/lwip/api/api_msg.c need to be fixed.

0001 /**
0002  * @file
0003  * Sequential API Internal module
0004  *
0005  */
0006 
0007 /*
0008  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
0009  * All rights reserved. 
0010  * 
0011  * Redistribution and use in source and binary forms, with or without modification, 
0012  * are permitted provided that the following conditions are met:
0013  *
0014  * 1. Redistributions of source code must retain the above copyright notice,
0015  *    this list of conditions and the following disclaimer.
0016  * 2. Redistributions in binary form must reproduce the above copyright notice,
0017  *    this list of conditions and the following disclaimer in the documentation
0018  *    and/or other materials provided with the distribution.
0019  * 3. The name of the author may not be used to endorse or promote products
0020  *    derived from this software without specific prior written permission. 
0021  *
0022  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
0023  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
0024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
0025  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
0026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
0027  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
0030  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
0031  * OF SUCH DAMAGE.
0032  *
0033  * This file is part of the lwIP TCP/IP stack.
0034  * 
0035  * Author: Adam Dunkels <adam@sics.se>
0036  *
0037  */
0038 
0039 #include "lwip/opt.h"
0040 
0041 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
0042 
0043 #include "lwip/api_msg.h"
0044 
0045 #include "lwip/ip.h"
0046 #include "lwip/udp.h"
0047 #include "lwip/tcp.h"
0048 #include "lwip/raw.h"
0049 
0050 #include "lwip/memp.h"
0051 #include "lwip/tcpip.h"
0052 #include "lwip/igmp.h"
0053 #include "lwip/dns.h"
0054 
0055 #include <string.h>
0056 
0057 /* forward declarations */
0058 #if LWIP_TCP
0059 static err_t do_writemore(struct netconn *conn);
0060 static void do_close_internal(struct netconn *conn);
0061 #endif
0062 
0063 #if LWIP_RAW
0064 /**
0065  * Receive callback function for RAW netconns.
0066  * Doesn't 'eat' the packet, only references it and sends it to
0067  * conn->recvmbox
0068  *
0069  * @see raw.h (struct raw_pcb.recv) for parameters and return value
0070  */
0071 static u8_t
0072 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
0073     struct ip_addr *addr)
0074 {
0075   struct pbuf *q;
0076   struct netbuf *buf;
0077   struct netconn *conn;
0078 #if LWIP_SO_RCVBUF
0079   int recv_avail;
0080 #endif /* LWIP_SO_RCVBUF */
0081 
0082   LWIP_UNUSED_ARG(addr);
0083   conn = arg;
0084 
0085 #if LWIP_SO_RCVBUF
0086   SYS_ARCH_GET(conn->recv_avail, recv_avail);
0087   if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) &&
0088       ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) {
0089 #else  /* LWIP_SO_RCVBUF */
0090   if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) {
0091 #endif /* LWIP_SO_RCVBUF */
0092     /* copy the whole packet into new pbufs */
0093     q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
0094     if(q != NULL) {
0095       if (pbuf_copy(q, p) != ERR_OK) {
0096         pbuf_free(q);
0097         q = NULL;
0098       }
0099     }
0100 
0101     if(q != NULL) {
0102       buf = memp_malloc(MEMP_NETBUF);
0103       if (buf == NULL) {
0104         pbuf_free(q);
0105         return 0;
0106       }
0107 
0108       buf->p = q;
0109       buf->ptr = q;
0110       buf->addr = &(((struct ip_hdr*)(q->payload))->src);
0111       buf->port = pcb->protocol;
0112 
0113       if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
0114         netbuf_delete(buf);
0115         return 0;
0116       } else {
0117         SYS_ARCH_INC(conn->recv_avail, q->tot_len);
0118         /* Register event with callback */
0119         API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len);
0120       }
0121     }
0122   }
0123 
0124   return 0; /* do not eat the packet */
0125 }
0126 #endif /* LWIP_RAW*/
0127 
0128 #if LWIP_UDP
0129 /**
0130  * Receive callback function for UDP netconns.
0131  * Posts the packet to conn->recvmbox or deletes it on memory error.
0132  *
0133  * @see udp.h (struct udp_pcb.recv) for parameters
0134  */
0135 static void
0136 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
0137    struct ip_addr *addr, u16_t port)
0138 {
0139   struct netbuf *buf;
0140   struct netconn *conn;
0141 #if LWIP_SO_RCVBUF
0142   int recv_avail;
0143 #endif /* LWIP_SO_RCVBUF */
0144 
0145   LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
0146   LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
0147   LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
0148   conn = arg;
0149   LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
0150 
0151 #if LWIP_SO_RCVBUF
0152   SYS_ARCH_GET(conn->recv_avail, recv_avail);
0153   if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) ||
0154       ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
0155 #else  /* LWIP_SO_RCVBUF */
0156   if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {
0157 #endif /* LWIP_SO_RCVBUF */
0158     pbuf_free(p);
0159     return;
0160   }
0161 
0162   buf = memp_malloc(MEMP_NETBUF);
0163   if (buf == NULL) {
0164     pbuf_free(p);
0165     return;
0166   } else {
0167     buf->p = p;
0168     buf->ptr = p;
0169     buf->addr = addr;
0170     buf->port = port;
0171 #if LWIP_NETBUF_RECVINFO
0172     {
0173       const struct ip_hdr* iphdr = ip_current_header();
0174       /* get the UDP header - always in the first pbuf, ensured by udp_input */
0175       const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
0176       buf->toaddr = (struct ip_addr*)&iphdr->dest;
0177       buf->toport = udphdr->dest;
0178     }
0179 #endif /* LWIP_NETBUF_RECVINFO */
0180   }
0181 
0182   if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
0183     netbuf_delete(buf);
0184     return;
0185   } else {
0186     SYS_ARCH_INC(conn->recv_avail, p->tot_len);
0187     /* Register event with callback */
0188     API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
0189   }
0190 }
0191 #endif /* LWIP_UDP */
0192 
0193 #if LWIP_TCP
0194 /**
0195  * Receive callback function for TCP netconns.
0196  * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
0197  *
0198  * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
0199  */
0200 static err_t
0201 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
0202 {
0203   struct netconn *conn;
0204   u16_t len;
0205 
0206   LWIP_UNUSED_ARG(pcb);
0207   LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
0208   LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
0209   conn = arg;
0210   LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
0211 
0212   if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {
0213     return ERR_VAL;
0214   }
0215 
0216   conn->err = err;
0217   if (p != NULL) {
0218     len = p->tot_len;
0219     SYS_ARCH_INC(conn->recv_avail, len);
0220   } else {
0221     len = 0;
0222   }
0223 
0224   if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {
0225     return ERR_MEM;
0226   } else {
0227     /* Register event with callback */
0228     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
0229   }
0230 
0231   return ERR_OK;
0232 }
0233 
0234 /**
0235  * Poll callback function for TCP netconns.
0236  * Wakes up an application thread that waits for a connection to close
0237  * or data to be sent. The application thread then takes the
0238  * appropriate action to go on.
0239  *
0240  * Signals the conn->sem.
0241  * netconn_close waits for conn->sem if closing failed.
0242  *
0243  * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
0244  */
0245 static err_t
0246 poll_tcp(void *arg, struct tcp_pcb *pcb)
0247 {
0248   struct netconn *conn = arg;
0249 
0250   LWIP_UNUSED_ARG(pcb);
0251   LWIP_ASSERT("conn != NULL", (conn != NULL));
0252 
0253   if (conn->state == NETCONN_WRITE) {
0254     do_writemore(conn);
0255   } else if (conn->state == NETCONN_CLOSE) {
0256     do_close_internal(conn);
0257   }
0258 
0259   return ERR_OK;
0260 }
0261 
0262 /**
0263  * Sent callback function for TCP netconns.
0264  * Signals the conn->sem and calls API_EVENT.
0265  * netconn_write waits for conn->sem if send buffer is low.
0266  *
0267  * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
0268  */
0269 static err_t
0270 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
0271 {
0272   struct netconn *conn = arg;
0273 
0274   LWIP_UNUSED_ARG(pcb);
0275   LWIP_ASSERT("conn != NULL", (conn != NULL));
0276 
0277   if (conn->state == NETCONN_WRITE) {
0278     LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
0279     do_writemore(conn);
0280   } else if (conn->state == NETCONN_CLOSE) {
0281     do_close_internal(conn);
0282   }
0283 
0284   if (conn) {
0285     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) {
0286       API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
0287     }
0288   }
0289   
0290   return ERR_OK;
0291 }
0292 
0293 /**
0294  * Error callback function for TCP netconns.
0295  * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
0296  * The application thread has then to decide what to do.
0297  *
0298  * @see tcp.h (struct tcp_pcb.err) for parameters
0299  */
0300 static void
0301 err_tcp(void *arg, err_t err)
0302 {
0303   struct netconn *conn;
0304 
0305   conn = arg;
0306   LWIP_ASSERT("conn != NULL", (conn != NULL));
0307 
0308   conn->pcb.tcp = NULL;
0309 
0310   conn->err = err;
0311   if (conn->recvmbox != SYS_MBOX_NULL) {
0312     /* Register event with callback */
0313     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
0314     sys_mbox_post(conn->recvmbox, NULL);
0315   }
0316   if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) {
0317     conn->state = NETCONN_NONE;
0318     sys_sem_signal(conn->op_completed);
0319   }
0320   if (conn->acceptmbox != SYS_MBOX_NULL) {
0321     /* Register event with callback */
0322     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
0323     sys_mbox_post(conn->acceptmbox, NULL);
0324   }
0325   if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {
0326     /* calling do_writemore/do_close_internal is not necessary
0327        since the pcb has already been deleted! */
0328     conn->state = NETCONN_NONE;
0329     /* wake up the waiting task */
0330     sys_sem_signal(conn->op_completed);
0331   }
0332 }
0333 
0334 /**
0335  * Setup a tcp_pcb with the correct callback function pointers
0336  * and their arguments.
0337  *
0338  * @param conn the TCP netconn to setup
0339  */
0340 static void
0341 setup_tcp(struct netconn *conn)
0342 {
0343   struct tcp_pcb *pcb;
0344 
0345   pcb = conn->pcb.tcp;
0346   tcp_arg(pcb, conn);
0347   tcp_recv(pcb, recv_tcp);
0348   tcp_sent(pcb, sent_tcp);
0349   tcp_poll(pcb, poll_tcp, 4);
0350   tcp_err(pcb, err_tcp);
0351 }
0352 
0353 /**
0354  * Accept callback function for TCP netconns.
0355  * Allocates a new netconn and posts that to conn->acceptmbox.
0356  *
0357  * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
0358  */
0359 static err_t
0360 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
0361 {
0362   struct netconn *newconn;
0363   struct netconn *conn;
0364 
0365 #if API_MSG_DEBUG
0366 #if TCP_DEBUG
0367   tcp_debug_print_state(newpcb->state);
0368 #endif /* TCP_DEBUG */
0369 #endif /* API_MSG_DEBUG */
0370   conn = (struct netconn *)arg;
0371 
0372   LWIP_ERROR("accept_function: invalid conn->acceptmbox",
0373              conn->acceptmbox != SYS_MBOX_NULL, return ERR_VAL;);
0374 
0375   /* We have to set the callback here even though
0376    * the new socket is unknown. conn->socket is marked as -1. */
0377   newconn = netconn_alloc(conn->type, conn->callback);
0378   if (newconn == NULL) {
0379     return ERR_MEM;
0380   }
0381   newconn->pcb.tcp = newpcb;
0382   setup_tcp(newconn);
0383   newconn->err = err;
0384 
0385   if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {
0386     /* When returning != ERR_OK, the connection is aborted in tcp_process(),
0387        so do nothing here! */
0388     newconn->pcb.tcp = NULL;
0389     netconn_free(newconn);
0390     return ERR_MEM;
0391   } else {
0392     /* Register event with callback */
0393     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
0394   }
0395 
0396   return ERR_OK;
0397 }
0398 #endif /* LWIP_TCP */
0399 
0400 /**
0401  * Create a new pcb of a specific type.
0402  * Called from do_newconn().
0403  *
0404  * @param msg the api_msg_msg describing the connection type
0405  * @return msg->conn->err, but the return value is currently ignored
0406  */
0407 static err_t
0408 pcb_new(struct api_msg_msg *msg)
0409 {
0410    msg->conn->err = ERR_OK;
0411 
0412    LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
0413 
0414    /* Allocate a PCB for this connection */
0415    switch(NETCONNTYPE_GROUP(msg->conn->type)) {
0416 #if LWIP_RAW
0417    case NETCONN_RAW:
0418      msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
0419      if(msg->conn->pcb.raw == NULL) {
0420        msg->conn->err = ERR_MEM;
0421        break;
0422      }
0423      raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
0424      break;
0425 #endif /* LWIP_RAW */
0426 #if LWIP_UDP
0427    case NETCONN_UDP:
0428      msg->conn->pcb.udp = udp_new();
0429      if(msg->conn->pcb.udp == NULL) {
0430        msg->conn->err = ERR_MEM;
0431        break;
0432      }
0433 #if LWIP_UDPLITE
0434      if (msg->conn->type==NETCONN_UDPLITE) {
0435        udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
0436      }
0437 #endif /* LWIP_UDPLITE */
0438      if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
0439        udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
0440      }
0441      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
0442      break;
0443 #endif /* LWIP_UDP */
0444 #if LWIP_TCP
0445    case NETCONN_TCP:
0446      msg->conn->pcb.tcp = tcp_new();
0447      if(msg->conn->pcb.tcp == NULL) {
0448        msg->conn->err = ERR_MEM;
0449        break;
0450      }
0451      setup_tcp(msg->conn);
0452      break;
0453 #endif /* LWIP_TCP */
0454    default:
0455      /* Unsupported netconn type, e.g. protocol disabled */
0456      msg->conn->err = ERR_VAL;
0457      break;
0458    }
0459 
0460   return msg->conn->err;
0461 }
0462 
0463 /**
0464  * Create a new pcb of a specific type inside a netconn.
0465  * Called from netconn_new_with_proto_and_callback.
0466  *
0467  * @param msg the api_msg_msg describing the connection type
0468  */
0469 void
0470 do_newconn(struct api_msg_msg *msg)
0471 {
0472    if(msg->conn->pcb.tcp == NULL) {
0473      pcb_new(msg);
0474    }
0475    /* Else? This "new" connection already has a PCB allocated. */
0476    /* Is this an error condition? Should it be deleted? */
0477    /* We currently just are happy and return. */
0478 
0479    TCPIP_APIMSG_ACK(msg);
0480 }
0481 
0482 /**
0483  * Create a new netconn (of a specific type) that has a callback function.
0484  * The corresponding pcb is NOT created!
0485  *
0486  * @param t the type of 'connection' to create (@see enum netconn_type)
0487  * @param proto the IP protocol for RAW IP pcbs
0488  * @param callback a function to call on status changes (RX available, TX'ed)
0489  * @return a newly allocated struct netconn or
0490  *         NULL on memory error
0491  */
0492 struct netconn*
0493 netconn_alloc(enum netconn_type t, netconn_callback callback)
0494 {
0495   struct netconn *conn;
0496   int size;
0497 
0498   conn = memp_malloc(MEMP_NETCONN);
0499   if (conn == NULL) {
0500     return NULL;
0501   }
0502 
0503   conn->err = ERR_OK;
0504   conn->type = t;
0505   conn->pcb.tcp = NULL;
0506 
0507 #if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \
0508     (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE)
0509   size = DEFAULT_RAW_RECVMBOX_SIZE;
0510 #else
0511   switch(NETCONNTYPE_GROUP(t)) {
0512 #if LWIP_RAW
0513   case NETCONN_RAW:
0514     size = DEFAULT_RAW_RECVMBOX_SIZE;
0515     break;
0516 #endif /* LWIP_RAW */
0517 #if LWIP_UDP
0518   case NETCONN_UDP:
0519     size = DEFAULT_UDP_RECVMBOX_SIZE;
0520     break;
0521 #endif /* LWIP_UDP */
0522 #if LWIP_TCP
0523   case NETCONN_TCP:
0524     size = DEFAULT_TCP_RECVMBOX_SIZE;
0525     break;
0526 #endif /* LWIP_TCP */
0527   default:
0528     LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
0529     break;
0530   }
0531 #endif
0532 
0533   if ((conn->op_completed = sys_sem_new(0)) == SYS_SEM_NULL) {
0534     memp_free(MEMP_NETCONN, conn);
0535     return NULL;
0536   }
0537   if ((conn->recvmbox = sys_mbox_new(size)) == SYS_MBOX_NULL) {
0538     sys_sem_free(conn->op_completed);
0539     memp_free(MEMP_NETCONN, conn);
0540     return NULL;
0541   }
0542 
0543   conn->acceptmbox   = SYS_MBOX_NULL;
0544   conn->state        = NETCONN_NONE;
0545   /* initialize socket to -1 since 0 is a valid socket */
0546   conn->socket       = -1;
0547   conn->callback     = callback;
0548   conn->recv_avail   = 0;
0549 #if LWIP_TCP
0550   conn->write_msg    = NULL;
0551   conn->write_offset = 0;
0552 #if LWIP_TCPIP_CORE_LOCKING
0553   conn->write_delayed = 0;
0554 #endif /* LWIP_TCPIP_CORE_LOCKING */
0555 #endif /* LWIP_TCP */
0556 #if LWIP_SO_RCVTIMEO
0557   conn->recv_timeout = 0;
0558 #endif /* LWIP_SO_RCVTIMEO */
0559 #if LWIP_SO_RCVBUF
0560   conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
0561 #endif /* LWIP_SO_RCVBUF */
0562   return conn;
0563 }
0564 
0565 /**
0566  * Delete a netconn and all its resources.
0567  * The pcb is NOT freed (since we might not be in the right thread context do this).
0568  *
0569  * @param conn the netconn to free
0570  */
0571 void
0572 netconn_free(struct netconn *conn)
0573 {
0574   void *mem;
0575   LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
0576 
0577   /* Drain the recvmbox. */
0578   if (conn->recvmbox != SYS_MBOX_NULL) {
0579     while (sys_mbox_tryfetch(conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
0580       if (conn->type == NETCONN_TCP) {
0581         if(mem != NULL) {
0582           pbuf_free((struct pbuf *)mem);
0583         }
0584       } else {
0585         netbuf_delete((struct netbuf *)mem);
0586       }
0587     }
0588     sys_mbox_free(conn->recvmbox);
0589     conn->recvmbox = SYS_MBOX_NULL;
0590   }
0591 
0592   /* Drain the acceptmbox. */
0593   if (conn->acceptmbox != SYS_MBOX_NULL) {
0594     while (sys_mbox_tryfetch(conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
0595       netconn_delete((struct netconn *)mem);
0596     }
0597     sys_mbox_free(conn->acceptmbox);
0598     conn->acceptmbox = SYS_MBOX_NULL;
0599   }
0600 
0601   sys_sem_free(conn->op_completed);
0602   conn->op_completed = SYS_SEM_NULL;
0603 
0604   memp_free(MEMP_NETCONN, conn);
0605 }
0606 
0607 #if LWIP_TCP
0608 /**
0609  * Internal helper function to close a TCP netconn: since this sometimes
0610  * doesn't work at the first attempt, this function is called from multiple
0611  * places.
0612  *
0613  * @param conn the TCP netconn to close
0614  */
0615 static void
0616 do_close_internal(struct netconn *conn)
0617 {
0618   err_t err;
0619 
0620   LWIP_ASSERT("invalid conn", (conn != NULL));
0621   LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
0622   LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
0623   LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
0624 
0625   /* Set back some callback pointers */
0626   tcp_arg(conn->pcb.tcp, NULL);
0627   if (conn->pcb.tcp->state == LISTEN) {
0628     tcp_accept(conn->pcb.tcp, NULL);
0629   } else {
0630     tcp_recv(conn->pcb.tcp, NULL);
0631     tcp_accept(conn->pcb.tcp, NULL);
0632     /* some callbacks have to be reset if tcp_close is not successful */
0633     tcp_sent(conn->pcb.tcp, NULL);
0634     tcp_poll(conn->pcb.tcp, NULL, 4);
0635     tcp_err(conn->pcb.tcp, NULL);
0636   }
0637   /* Try to close the connection */
0638   err = tcp_close(conn->pcb.tcp);
0639   if (err == ERR_OK) {
0640     /* Closing succeeded */
0641     conn->state = NETCONN_NONE;
0642     /* Set back some callback pointers as conn is going away */
0643     conn->pcb.tcp = NULL;
0644     conn->err = ERR_OK;
0645     /* Trigger select() in socket layer. This send should something else so the
0646        errorfd is set, not the read and write fd! */
0647     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
0648     API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
0649     /* wake up the application task */
0650     sys_sem_signal(conn->op_completed);
0651   } else {
0652     /* Closing failed, restore some of the callbacks */
0653     /* Closing of listen pcb will never fail! */
0654     LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN));
0655     tcp_sent(conn->pcb.tcp, sent_tcp);
0656     tcp_poll(conn->pcb.tcp, poll_tcp, 4);
0657     tcp_err(conn->pcb.tcp, err_tcp);
0658     tcp_arg(conn->pcb.tcp, conn);
0659   }
0660   /* If closing didn't succeed, we get called again either
0661      from poll_tcp or from sent_tcp */
0662 }
0663 #endif /* LWIP_TCP */
0664 
0665 /**
0666  * Delete the pcb inside a netconn.
0667  * Called from netconn_delete.
0668  *
0669  * @param msg the api_msg_msg pointing to the connection
0670  */
0671 void
0672 do_delconn(struct api_msg_msg *msg)
0673 {
0674   if (msg->conn->pcb.tcp != NULL) {
0675     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
0676 #if LWIP_RAW
0677     case NETCONN_RAW:
0678       raw_remove(msg->conn->pcb.raw);
0679       break;
0680 #endif /* LWIP_RAW */
0681 #if LWIP_UDP
0682     case NETCONN_UDP:
0683       msg->conn->pcb.udp->recv_arg = NULL;
0684       udp_remove(msg->conn->pcb.udp);
0685       break;
0686 #endif /* LWIP_UDP */
0687 #if LWIP_TCP
0688     case NETCONN_TCP:
0689       msg->conn->state = NETCONN_CLOSE;
0690       do_close_internal(msg->conn);
0691       /* API_EVENT is called inside do_close_internal, before releasing
0692          the application thread, so we can return at this point! */
0693       return;
0694 #endif /* LWIP_TCP */
0695     default:
0696       break;
0697     }
0698   }
0699   /* tcp netconns don't come here! */
0700 
0701   /* Trigger select() in socket layer. This send should something else so the
0702      errorfd is set, not the read and write fd! */
0703   API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
0704   API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
0705 
0706   if (msg->conn->op_completed != SYS_SEM_NULL) {
0707     sys_sem_signal(msg->conn->op_completed);
0708   }
0709 }
0710 
0711 /**
0712  * Bind a pcb contained in a netconn
0713  * Called from netconn_bind.
0714  *
0715  * @param msg the api_msg_msg pointing to the connection and containing
0716  *            the IP address and port to bind to
0717  */
0718 void
0719 do_bind(struct api_msg_msg *msg)
0720 {
0721   if (!ERR_IS_FATAL(msg->conn->err)) {
0722     if (msg->conn->pcb.tcp != NULL) {
0723       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
0724 #if LWIP_RAW
0725       case NETCONN_RAW:
0726         msg->conn->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
0727         break;
0728 #endif /* LWIP_RAW */
0729 #if LWIP_UDP
0730       case NETCONN_UDP:
0731         msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
0732         break;
0733 #endif /* LWIP_UDP */
0734 #if LWIP_TCP
0735       case NETCONN_TCP:
0736         msg->conn->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);
0737         break;
0738 #endif /* LWIP_TCP */
0739       default:
0740         break;
0741       }
0742     } else {
0743       /* msg->conn->pcb is NULL */
0744       msg->conn->err = ERR_VAL;
0745     }
0746   }
0747   TCPIP_APIMSG_ACK(msg);
0748 }
0749 
0750 #if LWIP_TCP
0751 /**
0752  * TCP callback function if a connection (opened by tcp_connect/do_connect) has
0753  * been established (or reset by the remote host).
0754  *
0755  * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
0756  */
0757 static err_t
0758 do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
0759 {
0760   struct netconn *conn;
0761 
0762   LWIP_UNUSED_ARG(pcb);
0763 
0764   conn = arg;
0765 
0766   if (conn == NULL) {
0767     return ERR_VAL;
0768   }
0769 
0770   conn->err = err;
0771   if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {
0772     setup_tcp(conn);
0773   }
0774   conn->state = NETCONN_NONE;
0775   sys_sem_signal(conn->op_completed);
0776   return ERR_OK;
0777 }
0778 #endif /* LWIP_TCP */
0779 
0780 /**
0781  * Connect a pcb contained inside a netconn
0782  * Called from netconn_connect.
0783  *
0784  * @param msg the api_msg_msg pointing to the connection and containing
0785  *            the IP address and port to connect to
0786  */
0787 void
0788 do_connect(struct api_msg_msg *msg)
0789 {
0790   if (msg->conn->pcb.tcp == NULL) {
0791     sys_sem_signal(msg->conn->op_completed);
0792     return;
0793   }
0794 
0795   switch (NETCONNTYPE_GROUP(msg->conn->type)) {
0796 #if LWIP_RAW
0797   case NETCONN_RAW:
0798     msg->conn->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
0799     sys_sem_signal(msg->conn->op_completed);
0800     break;
0801 #endif /* LWIP_RAW */
0802 #if LWIP_UDP
0803   case NETCONN_UDP:
0804     msg->conn->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
0805     sys_sem_signal(msg->conn->op_completed);
0806     break;
0807 #endif /* LWIP_UDP */
0808 #if LWIP_TCP
0809   case NETCONN_TCP:
0810     msg->conn->state = NETCONN_CONNECT;
0811     setup_tcp(msg->conn);
0812     msg->conn->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,
0813                                  do_connected);
0814     /* sys_sem_signal() is called from do_connected (or err_tcp()),
0815      * when the connection is established! */
0816     break;
0817 #endif /* LWIP_TCP */
0818   default:
0819     LWIP_ERROR("Invalid netconn type", 0, do{ msg->conn->err = ERR_VAL;
0820       sys_sem_signal(msg->conn->op_completed); }while(0));
0821     break;
0822   }
0823 }
0824 
0825 /**
0826  * Connect a pcb contained inside a netconn
0827  * Only used for UDP netconns.
0828  * Called from netconn_disconnect.
0829  *
0830  * @param msg the api_msg_msg pointing to the connection to disconnect
0831  */
0832 void
0833 do_disconnect(struct api_msg_msg *msg)
0834 {
0835 #if LWIP_UDP
0836   if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
0837     udp_disconnect(msg->conn->pcb.udp);
0838   }
0839 #endif /* LWIP_UDP */
0840   TCPIP_APIMSG_ACK(msg);
0841 }
0842 
0843 /**
0844  * Set a TCP pcb contained in a netconn into listen mode
0845  * Called from netconn_listen.
0846  *
0847  * @param msg the api_msg_msg pointing to the connection
0848  */
0849 void
0850 do_listen(struct api_msg_msg *msg)
0851 {
0852 #if LWIP_TCP
0853   if (!ERR_IS_FATAL(msg->conn->err)) {
0854     if (msg->conn->pcb.tcp != NULL) {
0855       if (msg->conn->type == NETCONN_TCP) {
0856         if (msg->conn->pcb.tcp->state == CLOSED) {
0857 #if TCP_LISTEN_BACKLOG
0858           struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
0859 #else  /* TCP_LISTEN_BACKLOG */
0860           struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);
0861 #endif /* TCP_LISTEN_BACKLOG */
0862           if (lpcb == NULL) {
0863             msg->conn->err = ERR_MEM;
0864           } else {
0865             /* delete the recvmbox and allocate the acceptmbox */
0866             if (msg->conn->recvmbox != SYS_MBOX_NULL) {
0867               /** @todo: should we drain the recvmbox here? */
0868               sys_mbox_free(msg->conn->recvmbox);
0869               msg->conn->recvmbox = SYS_MBOX_NULL;
0870             }
0871             if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
0872               if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) {
0873                 msg->conn->err = ERR_MEM;
0874               }
0875             }
0876             if (msg->conn->err == ERR_OK) {
0877               msg->conn->state = NETCONN_LISTEN;
0878               msg->conn->pcb.tcp = lpcb;
0879               tcp_arg(msg->conn->pcb.tcp, msg->conn);
0880               tcp_accept(msg->conn->pcb.tcp, accept_function);
0881             }
0882           }
0883         } else {
0884           msg->conn->err = ERR_CONN;
0885         }
0886       }
0887     }
0888   }
0889 #endif /* LWIP_TCP */
0890   TCPIP_APIMSG_ACK(msg);
0891 }
0892 
0893 /**
0894  * Send some data on a RAW or UDP pcb contained in a netconn
0895  * Called from netconn_send
0896  *
0897  * @param msg the api_msg_msg pointing to the connection
0898  */
0899 void
0900 do_send(struct api_msg_msg *msg)
0901 {
0902   if (!ERR_IS_FATAL(msg->conn->err)) {
0903     if (msg->conn->pcb.tcp != NULL) {
0904       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
0905 #if LWIP_RAW
0906       case NETCONN_RAW:
0907         if (msg->msg.b->addr == NULL) {
0908           msg->conn->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
0909         } else {
0910           msg->conn->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr);
0911         }
0912         break;
0913 #endif
0914 #if LWIP_UDP
0915       case NETCONN_UDP:
0916         if (msg->msg.b->addr == NULL) {
0917           msg->conn->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
0918         } else {
0919           msg->conn->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port);
0920         }
0921         break;
0922 #endif /* LWIP_UDP */
0923       default:
0924         break;
0925       }
0926     }
0927   }
0928   TCPIP_APIMSG_ACK(msg);
0929 }
0930 
0931 /**
0932  * Indicate data has been received from a TCP pcb contained in a netconn
0933  * Called from netconn_recv
0934  *
0935  * @param msg the api_msg_msg pointing to the connection
0936  */
0937 void
0938 do_recv(struct api_msg_msg *msg)
0939 {
0940 #if LWIP_TCP
0941   if (!ERR_IS_FATAL(msg->conn->err)) {
0942     if (msg->conn->pcb.tcp != NULL) {
0943       if (msg->conn->type == NETCONN_TCP) {
0944 #if TCP_LISTEN_BACKLOG
0945         if (msg->conn->pcb.tcp->state == LISTEN) {
0946           tcp_accepted(msg->conn->pcb.tcp);
0947         } else
0948 #endif /* TCP_LISTEN_BACKLOG */
0949         {
0950           tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len);
0951         }
0952       }
0953     }
0954   }
0955 #endif /* LWIP_TCP */
0956   TCPIP_APIMSG_ACK(msg);
0957 }
0958 
0959 #if LWIP_TCP
0960 /**
0961  * See if more data needs to be written from a previous call to netconn_write.
0962  * Called initially from do_write. If the first call can't send all data
0963  * (because of low memory or empty send-buffer), this function is called again
0964  * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
0965  * blocking application thread (waiting in netconn_write) is released.
0966  *
0967  * @param conn netconn (that is currently in state NETCONN_WRITE) to process
0968  * @return ERR_OK
0969  *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
0970  */
0971 static err_t
0972 do_writemore(struct netconn *conn)
0973 {
0974   err_t err;
0975   void *dataptr;
0976   u16_t len, available;
0977   u8_t write_finished = 0;
0978   size_t diff;
0979 
0980   LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
0981 
0982   dataptr = (u8_t*)conn->write_msg->msg.w.dataptr + conn->write_offset;
0983   diff = conn->write_msg->msg.w.len - conn->write_offset;
0984   if (diff > 0xffffUL) { /* max_u16_t */
0985     len = 0xffff;
0986 #if LWIP_TCPIP_CORE_LOCKING
0987     conn->write_delayed = 1;
0988 #endif
0989   } else {
0990     len = (u16_t)diff;
0991   }
0992   available = tcp_sndbuf(conn->pcb.tcp);
0993   if (available < len) {
0994     /* don't try to write more than sendbuf */
0995     len = available;
0996 #if LWIP_TCPIP_CORE_LOCKING
0997     conn->write_delayed = 1;
0998 #endif
0999   }
1000 
1001   err = tcp_write(conn->pcb.tcp, dataptr, len, conn->write_msg->msg.w.apiflags);
1002   LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->write_msg->msg.w.len));
1003   if (err == ERR_OK) {
1004     conn->write_offset += len;
1005     if (conn->write_offset == conn->write_msg->msg.w.len) {
1006       /* everything was written */
1007       write_finished = 1;
1008       conn->write_msg = NULL;
1009       conn->write_offset = 0;
1010       /* API_EVENT might call tcp_tmr, so reset conn->state now */
1011       conn->state = NETCONN_NONE;
1012     }
1013     err = tcp_output_nagle(conn->pcb.tcp);
1014     conn->err = err;
1015     if ((err == ERR_OK) && (tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT)) {
1016       API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
1017     }
1018   } else if (err == ERR_MEM) {
1019     /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
1020        we do NOT return to the application thread, since ERR_MEM is
1021        only a temporary error! */
1022 
1023     /* tcp_enqueue returned ERR_MEM, try tcp_output anyway */
1024     err = tcp_output(conn->pcb.tcp);
1025 
1026 #if LWIP_TCPIP_CORE_LOCKING
1027     conn->write_delayed = 1;
1028 #endif
1029   } else {
1030     /* On errors != ERR_MEM, we don't try writing any more but return
1031        the error to the application thread. */
1032     conn->err = err;
1033     write_finished = 1;
1034   }
1035 
1036   if (write_finished) {
1037     /* everything was written: set back connection state
1038        and back to application task */
1039     conn->state = NETCONN_NONE;
1040 #if LWIP_TCPIP_CORE_LOCKING
1041     if (conn->write_delayed != 0)
1042 #endif
1043     {
1044       sys_sem_signal(conn->op_completed);
1045     }
1046   }
1047 #if LWIP_TCPIP_CORE_LOCKING
1048   else
1049     return ERR_MEM;
1050 #endif
1051   return ERR_OK;
1052 }
1053 #endif /* LWIP_TCP */
1054 
1055 /**
1056  * Send some data on a TCP pcb contained in a netconn
1057  * Called from netconn_write
1058  *
1059  * @param msg the api_msg_msg pointing to the connection
1060  */
1061 void
1062 do_write(struct api_msg_msg *msg)
1063 {
1064   if (!ERR_IS_FATAL(msg->conn->err)) {
1065     if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
1066 #if LWIP_TCP
1067       msg->conn->state = NETCONN_WRITE;
1068       /* set all the variables used by do_writemore */
1069       LWIP_ASSERT("already writing", msg->conn->write_msg == NULL &&
1070         msg->conn->write_offset == 0);
1071       msg->conn->write_msg = msg;
1072       msg->conn->write_offset = 0;
1073 #if LWIP_TCPIP_CORE_LOCKING
1074       msg->conn->write_delayed = 0;
1075       if (do_writemore(msg->conn) != ERR_OK) {
1076         LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
1077         UNLOCK_TCPIP_CORE();
1078         sys_arch_sem_wait(msg->conn->op_completed, 0);
1079         LOCK_TCPIP_CORE();
1080         LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1081       }
1082 #else
1083       do_writemore(msg->conn);
1084 #endif
1085       /* for both cases: if do_writemore was called, don't ACK the APIMSG! */
1086       return;
1087 #endif /* LWIP_TCP */
1088 #if (LWIP_UDP || LWIP_RAW)
1089     } else {
1090       msg->conn->err = ERR_VAL;
1091 #endif /* (LWIP_UDP || LWIP_RAW) */
1092     }
1093   }
1094   TCPIP_APIMSG_ACK(msg);
1095 }
1096 
1097 /**
1098  * Return a connection's local or remote address
1099  * Called from netconn_getaddr
1100  *
1101  * @param msg the api_msg_msg pointing to the connection
1102  */
1103 void
1104 do_getaddr(struct api_msg_msg *msg)
1105 {
1106   if (msg->conn->pcb.ip != NULL) {
1107     *(msg->msg.ad.ipaddr) = (msg->msg.ad.local?msg->conn->pcb.ip->local_ip:msg->conn->pcb.ip->remote_ip);
1108     
1109     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1110 #if LWIP_RAW
1111     case NETCONN_RAW:
1112       if (msg->msg.ad.local) {
1113         *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
1114       } else {
1115         /* return an error as connecting is only a helper for upper layers */
1116         msg->conn->err = ERR_CONN;
1117       }
1118       break;
1119 #endif /* LWIP_RAW */
1120 #if LWIP_UDP
1121     case NETCONN_UDP:
1122       if (msg->msg.ad.local) {
1123         *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
1124       } else {
1125         if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
1126           msg->conn->err = ERR_CONN;
1127         } else {
1128           *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
1129         }
1130       }
1131       break;
1132 #endif /* LWIP_UDP */
1133 #if LWIP_TCP
1134     case NETCONN_TCP:
1135       *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port);
1136       break;
1137 #endif /* LWIP_TCP */
1138     }
1139   } else {
1140     msg->conn->err = ERR_CONN;
1141   }
1142   TCPIP_APIMSG_ACK(msg);
1143 }
1144 
1145 /**
1146  * Close a TCP pcb contained in a netconn
1147  * Called from netconn_close
1148  *
1149  * @param msg the api_msg_msg pointing to the connection
1150  */
1151 void
1152 do_close(struct api_msg_msg *msg)
1153 {
1154 #if LWIP_TCP
1155   if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
1156       msg->conn->state = NETCONN_CLOSE;
1157       do_close_internal(msg->conn);
1158       /* for tcp netconns, do_close_internal ACKs the message */
1159   } else
1160 #endif /* LWIP_TCP */
1161   {
1162     msg->conn->err = ERR_VAL;
1163     sys_sem_signal(msg->conn->op_completed);
1164   }
1165 }
1166 
1167 #if LWIP_IGMP
1168 /**
1169  * Join multicast groups for UDP netconns.
1170  * Called from netconn_join_leave_group
1171  *
1172  * @param msg the api_msg_msg pointing to the connection
1173  */
1174 void
1175 do_join_leave_group(struct api_msg_msg *msg)
1176 { 
1177   if (!ERR_IS_FATAL(msg->conn->err)) {
1178     if (msg->conn->pcb.tcp != NULL) {
1179       if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1180 #if LWIP_UDP
1181         if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
1182           msg->conn->err = igmp_joingroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);
1183         } else {
1184           msg->conn->err = igmp_leavegroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);
1185         }
1186 #endif /* LWIP_UDP */
1187 #if (LWIP_TCP || LWIP_RAW)
1188       } else {
1189         msg->conn->err = ERR_VAL;
1190 #endif /* (LWIP_TCP || LWIP_RAW) */
1191       }
1192     }
1193   }
1194   TCPIP_APIMSG_ACK(msg);
1195 }
1196 #endif /* LWIP_IGMP */
1197 
1198 #if LWIP_DNS
1199 /**
1200  * Callback function that is called when DNS name is resolved
1201  * (or on timeout). A waiting application thread is waked up by
1202  * signaling the semaphore.
1203  */
1204 static void
1205 do_dns_found(const char *name, struct ip_addr *ipaddr, void *arg)
1206 {
1207   struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1208 
1209   LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0);
1210 
1211   if (ipaddr == NULL) {
1212     /* timeout or memory error */
1213     *msg->err = ERR_VAL;
1214   } else {
1215     /* address was resolved */
1216     *msg->err = ERR_OK;
1217     *msg->addr = *ipaddr;
1218   }
1219   /* wake up the application task waiting in netconn_gethostbyname */
1220   sys_sem_signal(msg->sem);
1221 }
1222 
1223 /**
1224  * Execute a DNS query
1225  * Called from netconn_gethostbyname
1226  *
1227  * @param arg the dns_api_msg pointing to the query
1228  */
1229 void
1230 do_gethostbyname(void *arg)
1231 {
1232   struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1233 
1234   *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg);
1235   if (*msg->err != ERR_INPROGRESS) {
1236     /* on error or immediate success, wake up the application
1237      * task waiting in netconn_gethostbyname */
1238     sys_sem_signal(msg->sem);
1239   }
1240 }
1241 #endif /* LWIP_DNS */
1242 
1243 #endif /* LWIP_NETCONN */