]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/blob - src/api/api_msg.c
bug #26523: Compiler Warnings
[pes-rpp/rpp-lwip.git] / src / api / api_msg.c
1 /**
2  * @file
3  * Sequential API Internal module
4  *
5  */
6
7 /*
8  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9  * All rights reserved. 
10  * 
11  * Redistribution and use in source and binary forms, with or without modification, 
12  * are permitted provided that the following conditions are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright notice,
15  *    this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright notice,
17  *    this list of conditions and the following disclaimer in the documentation
18  *    and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission. 
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
25  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
27  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
30  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
31  * OF SUCH DAMAGE.
32  *
33  * This file is part of the lwIP TCP/IP stack.
34  * 
35  * Author: Adam Dunkels <adam@sics.se>
36  *
37  */
38
39 #include "lwip/opt.h"
40
41 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
42
43 #include "lwip/api_msg.h"
44
45 #include "lwip/ip.h"
46 #include "lwip/udp.h"
47 #include "lwip/tcp.h"
48 #include "lwip/raw.h"
49
50 #include "lwip/memp.h"
51 #include "lwip/tcpip.h"
52 #include "lwip/igmp.h"
53 #include "lwip/dns.h"
54
55 #include <string.h>
56
57 /* forward declarations */
58 #if LWIP_TCP
59 static err_t do_writemore(struct netconn *conn);
60 static void do_close_internal(struct netconn *conn);
61 #endif
62
63 #if LWIP_RAW
64 /**
65  * Receive callback function for RAW netconns.
66  * Doesn't 'eat' the packet, only references it and sends it to
67  * conn->recvmbox
68  *
69  * @see raw.h (struct raw_pcb.recv) for parameters and return value
70  */
71 static u8_t
72 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
73     struct ip_addr *addr)
74 {
75   struct pbuf *q;
76   struct netbuf *buf;
77   struct netconn *conn;
78 #if LWIP_SO_RCVBUF
79   int recv_avail;
80 #endif /* LWIP_SO_RCVBUF */
81
82   LWIP_UNUSED_ARG(addr);
83   conn = arg;
84
85 #if LWIP_SO_RCVBUF
86   SYS_ARCH_GET(conn->recv_avail, recv_avail);
87   if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) &&
88       ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) {
89 #else  /* LWIP_SO_RCVBUF */
90   if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) {
91 #endif /* LWIP_SO_RCVBUF */
92     /* copy the whole packet into new pbufs */
93     q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
94     if(q != NULL) {
95       if (pbuf_copy(q, p) != ERR_OK) {
96         pbuf_free(q);
97         q = NULL;
98       }
99     }
100
101     if(q != NULL) {
102       buf = memp_malloc(MEMP_NETBUF);
103       if (buf == NULL) {
104         pbuf_free(q);
105         return 0;
106       }
107
108       buf->p = q;
109       buf->ptr = q;
110       buf->addr = &(((struct ip_hdr*)(q->payload))->src);
111       buf->port = pcb->protocol;
112
113       if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
114         netbuf_delete(buf);
115         return 0;
116       } else {
117         SYS_ARCH_INC(conn->recv_avail, q->tot_len);
118         /* Register event with callback */
119         API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len);
120       }
121     }
122   }
123
124   return 0; /* do not eat the packet */
125 }
126 #endif /* LWIP_RAW*/
127
128 #if LWIP_UDP
129 /**
130  * Receive callback function for UDP netconns.
131  * Posts the packet to conn->recvmbox or deletes it on memory error.
132  *
133  * @see udp.h (struct udp_pcb.recv) for parameters
134  */
135 static void
136 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
137    struct ip_addr *addr, u16_t port)
138 {
139   struct netbuf *buf;
140   struct netconn *conn;
141 #if LWIP_SO_RCVBUF
142   int recv_avail;
143 #endif /* LWIP_SO_RCVBUF */
144
145   LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
146   LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
147   LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
148   conn = arg;
149   LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
150
151 #if LWIP_SO_RCVBUF
152   SYS_ARCH_GET(conn->recv_avail, recv_avail);
153   if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) ||
154       ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
155 #else  /* LWIP_SO_RCVBUF */
156   if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {
157 #endif /* LWIP_SO_RCVBUF */
158     pbuf_free(p);
159     return;
160   }
161
162   buf = memp_malloc(MEMP_NETBUF);
163   if (buf == NULL) {
164     pbuf_free(p);
165     return;
166   } else {
167     buf->p = p;
168     buf->ptr = p;
169     buf->addr = addr;
170     buf->port = port;
171 #if LWIP_NETBUF_RECVINFO
172     {
173       const struct ip_hdr* iphdr = ip_current_header();
174       /* get the UDP header - always in the first pbuf, ensured by udp_input */
175       const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
176       buf->toaddr = (struct ip_addr*)&iphdr->dest;
177       buf->toport = udphdr->dest;
178     }
179 #endif /* LWIP_NETBUF_RECVINFO */
180   }
181
182   if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
183     netbuf_delete(buf);
184     return;
185   } else {
186     SYS_ARCH_INC(conn->recv_avail, p->tot_len);
187     /* Register event with callback */
188     API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
189   }
190 }
191 #endif /* LWIP_UDP */
192
193 #if LWIP_TCP
194 /**
195  * Receive callback function for TCP netconns.
196  * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
197  *
198  * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
199  */
200 static err_t
201 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
202 {
203   struct netconn *conn;
204   u16_t len;
205
206   LWIP_UNUSED_ARG(pcb);
207   LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
208   LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
209   conn = arg;
210   LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
211
212   if (conn == NULL) {
213     return ERR_VAL;
214   }
215   if (conn->recvmbox == SYS_MBOX_NULL) {
216     /* recvmbox already deleted */
217     if (p != NULL) {
218       tcp_recved(pcb, p->tot_len);
219       pbuf_free(p);
220     }
221     return ERR_OK;
222   }
223
224   /* don't overwrite fatal errors! */
225   NETCONN_SET_SAFE_ERR(conn, err);
226
227   if (p != NULL) {
228     len = p->tot_len;
229     SYS_ARCH_INC(conn->recv_avail, len);
230   } else {
231     len = 0;
232   }
233
234   if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {
235     return ERR_MEM;
236   } else {
237     /* Register event with callback */
238     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
239   }
240
241   return ERR_OK;
242 }
243
244 /**
245  * Poll callback function for TCP netconns.
246  * Wakes up an application thread that waits for a connection to close
247  * or data to be sent. The application thread then takes the
248  * appropriate action to go on.
249  *
250  * Signals the conn->sem.
251  * netconn_close waits for conn->sem if closing failed.
252  *
253  * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
254  */
255 static err_t
256 poll_tcp(void *arg, struct tcp_pcb *pcb)
257 {
258   struct netconn *conn = arg;
259
260   LWIP_UNUSED_ARG(pcb);
261   LWIP_ASSERT("conn != NULL", (conn != NULL));
262
263   if (conn->state == NETCONN_WRITE) {
264     do_writemore(conn);
265   } else if (conn->state == NETCONN_CLOSE) {
266     do_close_internal(conn);
267   }
268
269   return ERR_OK;
270 }
271
272 /**
273  * Sent callback function for TCP netconns.
274  * Signals the conn->sem and calls API_EVENT.
275  * netconn_write waits for conn->sem if send buffer is low.
276  *
277  * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
278  */
279 static err_t
280 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
281 {
282   struct netconn *conn = arg;
283
284   LWIP_UNUSED_ARG(pcb);
285   LWIP_ASSERT("conn != NULL", (conn != NULL));
286
287   if (conn->state == NETCONN_WRITE) {
288     LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
289     do_writemore(conn);
290   } else if (conn->state == NETCONN_CLOSE) {
291     do_close_internal(conn);
292   }
293
294   if (conn) {
295     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) {
296       API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
297     }
298   }
299   
300   return ERR_OK;
301 }
302
303 /**
304  * Error callback function for TCP netconns.
305  * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
306  * The application thread has then to decide what to do.
307  *
308  * @see tcp.h (struct tcp_pcb.err) for parameters
309  */
310 static void
311 err_tcp(void *arg, err_t err)
312 {
313   struct netconn *conn;
314   enum netconn_state old_state;
315   SYS_ARCH_DECL_PROTECT(lev);
316
317   conn = arg;
318   LWIP_ASSERT("conn != NULL", (conn != NULL));
319
320   conn->pcb.tcp = NULL;
321
322   /* no check since this is always fatal */
323   SYS_ARCH_PROTECT(lev);
324   conn->last_err = err;
325   SYS_ARCH_UNPROTECT(lev);
326
327   /* API_EVENT might call tcp_tmr, so reset conn->state now */
328   old_state = conn->state;
329   conn->state = NETCONN_NONE;
330
331   if (conn->recvmbox != SYS_MBOX_NULL) {
332     /* Register event with callback */
333     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
334     /* use trypot to preven deadlock */
335     sys_mbox_trypost(conn->recvmbox, NULL);
336   }
337   if (conn->acceptmbox != SYS_MBOX_NULL) {
338     /* Register event with callback */
339     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
340     /* use trypot to preven deadlock */
341     sys_mbox_trypost(conn->acceptmbox, NULL);
342   }
343   if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
344       (old_state == NETCONN_CONNECT)) {
345     /* calling do_writemore/do_close_internal is not necessary
346        since the pcb has already been deleted! */
347
348     /* set error return code */
349     LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
350     conn->current_msg->err = err;
351     conn->current_msg = NULL;
352     /* wake up the waiting task */
353     sys_sem_signal(conn->op_completed);
354   } else {
355     LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
356   }
357 }
358
359 /**
360  * Setup a tcp_pcb with the correct callback function pointers
361  * and their arguments.
362  *
363  * @param conn the TCP netconn to setup
364  */
365 static void
366 setup_tcp(struct netconn *conn)
367 {
368   struct tcp_pcb *pcb;
369
370   pcb = conn->pcb.tcp;
371   tcp_arg(pcb, conn);
372   tcp_recv(pcb, recv_tcp);
373   tcp_sent(pcb, sent_tcp);
374   tcp_poll(pcb, poll_tcp, 4);
375   tcp_err(pcb, err_tcp);
376 }
377
378 /**
379  * Accept callback function for TCP netconns.
380  * Allocates a new netconn and posts that to conn->acceptmbox.
381  *
382  * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
383  */
384 static err_t
385 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
386 {
387   struct netconn *newconn;
388   struct netconn *conn;
389
390 #if API_MSG_DEBUG
391 #if TCP_DEBUG
392   tcp_debug_print_state(newpcb->state);
393 #endif /* TCP_DEBUG */
394 #endif /* API_MSG_DEBUG */
395   conn = (struct netconn *)arg;
396
397   if (conn->acceptmbox == SYS_MBOX_NULL) {
398     LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
399     return ERR_VAL;
400   }
401
402   /* We have to set the callback here even though
403    * the new socket is unknown. conn->socket is marked as -1. */
404   newconn = netconn_alloc(conn->type, conn->callback);
405   if (newconn == NULL) {
406     return ERR_MEM;
407   }
408   newconn->pcb.tcp = newpcb;
409   setup_tcp(newconn);
410   /* no protection: when creating the pcb, the netconn is not yet known
411      to the application thread */
412   newconn->last_err = err;
413
414   if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {
415     /* When returning != ERR_OK, the connection is aborted in tcp_process(),
416        so do nothing here! */
417     newconn->pcb.tcp = NULL;
418     /* no need to drain since we know the recvmbox is empty. */
419     sys_mbox_free(newconn->recvmbox);
420     newconn->recvmbox = SYS_MBOX_NULL;
421     netconn_free(newconn);
422     return ERR_MEM;
423   } else {
424     /* Register event with callback */
425     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
426   }
427
428   return ERR_OK;
429 }
430 #endif /* LWIP_TCP */
431
432 /**
433  * Create a new pcb of a specific type.
434  * Called from do_newconn().
435  *
436  * @param msg the api_msg_msg describing the connection type
437  * @return msg->conn->err, but the return value is currently ignored
438  */
439 static void
440 pcb_new(struct api_msg_msg *msg)
441 {
442   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
443
444   /* Allocate a PCB for this connection */
445   switch(NETCONNTYPE_GROUP(msg->conn->type)) {
446 #if LWIP_RAW
447   case NETCONN_RAW:
448     msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
449     if(msg->conn->pcb.raw == NULL) {
450       msg->err = ERR_MEM;
451       break;
452     }
453     raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
454     break;
455 #endif /* LWIP_RAW */
456 #if LWIP_UDP
457   case NETCONN_UDP:
458     msg->conn->pcb.udp = udp_new();
459     if(msg->conn->pcb.udp == NULL) {
460       msg->err = ERR_MEM;
461       break;
462     }
463 #if LWIP_UDPLITE
464     if (msg->conn->type==NETCONN_UDPLITE) {
465       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
466     }
467 #endif /* LWIP_UDPLITE */
468     if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
469       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
470     }
471     udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
472     break;
473 #endif /* LWIP_UDP */
474 #if LWIP_TCP
475   case NETCONN_TCP:
476     msg->conn->pcb.tcp = tcp_new();
477     if(msg->conn->pcb.tcp == NULL) {
478       msg->err = ERR_MEM;
479       break;
480     }
481     setup_tcp(msg->conn);
482     break;
483 #endif /* LWIP_TCP */
484   default:
485     /* Unsupported netconn type, e.g. protocol disabled */
486     msg->err = ERR_VAL;
487     break;
488   }
489 }
490
491 /**
492  * Create a new pcb of a specific type inside a netconn.
493  * Called from netconn_new_with_proto_and_callback.
494  *
495  * @param msg the api_msg_msg describing the connection type
496  */
497 void
498 do_newconn(struct api_msg_msg *msg)
499 {
500   msg->err = ERR_OK;
501   if(msg->conn->pcb.tcp == NULL) {
502     pcb_new(msg);
503   }
504   /* Else? This "new" connection already has a PCB allocated. */
505   /* Is this an error condition? Should it be deleted? */
506   /* We currently just are happy and return. */
507
508   TCPIP_APIMSG_ACK(msg);
509 }
510
511 /**
512  * Create a new netconn (of a specific type) that has a callback function.
513  * The corresponding pcb is NOT created!
514  *
515  * @param t the type of 'connection' to create (@see enum netconn_type)
516  * @param proto the IP protocol for RAW IP pcbs
517  * @param callback a function to call on status changes (RX available, TX'ed)
518  * @return a newly allocated struct netconn or
519  *         NULL on memory error
520  */
521 struct netconn*
522 netconn_alloc(enum netconn_type t, netconn_callback callback)
523 {
524   struct netconn *conn;
525   int size;
526
527   conn = memp_malloc(MEMP_NETCONN);
528   if (conn == NULL) {
529     return NULL;
530   }
531
532   conn->last_err = ERR_OK;
533   conn->type = t;
534   conn->pcb.tcp = NULL;
535
536 #if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \
537     (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE)
538   size = DEFAULT_RAW_RECVMBOX_SIZE;
539 #else
540   switch(NETCONNTYPE_GROUP(t)) {
541 #if LWIP_RAW
542   case NETCONN_RAW:
543     size = DEFAULT_RAW_RECVMBOX_SIZE;
544     break;
545 #endif /* LWIP_RAW */
546 #if LWIP_UDP
547   case NETCONN_UDP:
548     size = DEFAULT_UDP_RECVMBOX_SIZE;
549     break;
550 #endif /* LWIP_UDP */
551 #if LWIP_TCP
552   case NETCONN_TCP:
553     size = DEFAULT_TCP_RECVMBOX_SIZE;
554     break;
555 #endif /* LWIP_TCP */
556   default:
557     LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
558     break;
559   }
560 #endif
561
562   if ((conn->op_completed = sys_sem_new(0)) == SYS_SEM_NULL) {
563     memp_free(MEMP_NETCONN, conn);
564     return NULL;
565   }
566   if ((conn->recvmbox = sys_mbox_new(size)) == SYS_MBOX_NULL) {
567     sys_sem_free(conn->op_completed);
568     memp_free(MEMP_NETCONN, conn);
569     return NULL;
570   }
571
572   conn->acceptmbox   = SYS_MBOX_NULL;
573   conn->state        = NETCONN_NONE;
574   /* initialize socket to -1 since 0 is a valid socket */
575   conn->socket       = -1;
576   conn->callback     = callback;
577   conn->recv_avail   = 0;
578 #if LWIP_TCP
579   conn->current_msg  = NULL;
580   conn->write_offset = 0;
581 #if LWIP_TCPIP_CORE_LOCKING
582   conn->write_delayed = 0;
583 #endif /* LWIP_TCPIP_CORE_LOCKING */
584 #endif /* LWIP_TCP */
585 #if LWIP_SO_RCVTIMEO
586   conn->recv_timeout = 0;
587 #endif /* LWIP_SO_RCVTIMEO */
588 #if LWIP_SO_RCVBUF
589   conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
590 #endif /* LWIP_SO_RCVBUF */
591   return conn;
592 }
593
594 /**
595  * Delete a netconn and all its resources.
596  * The pcb is NOT freed (since we might not be in the right thread context do this).
597  *
598  * @param conn the netconn to free
599  */
600 void
601 netconn_free(struct netconn *conn)
602 {
603   LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
604   LWIP_ASSERT("recvmbox must be deallocated before calling this function",
605     conn->recvmbox == SYS_MBOX_NULL);
606   LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
607     conn->acceptmbox == SYS_MBOX_NULL);
608
609   sys_sem_free(conn->op_completed);
610   conn->op_completed = SYS_SEM_NULL;
611
612   memp_free(MEMP_NETCONN, conn);
613 }
614
615 /**
616  * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
617  * these mboxes
618  *
619  * @param conn the netconn to free
620  * @bytes_drained bytes drained from recvmbox
621  * @accepts_drained pending connections drained from acceptmbox
622  */
623 void
624 netconn_drain(struct netconn *conn)
625 {
626   void *mem;
627   struct pbuf *p;
628   sys_mbox_t mbox;
629
630   /* Delete and drain the recvmbox. */
631   mbox = conn->recvmbox;
632   conn->recvmbox = SYS_MBOX_NULL;
633   if (mbox != SYS_MBOX_NULL) {
634     while (sys_mbox_tryfetch(mbox, &mem) != SYS_MBOX_EMPTY) {
635       if (conn->type == NETCONN_TCP) {
636         if(mem != NULL) {
637           p = (struct pbuf*)mem;
638           /* pcb might be set to NULL already by err_tcp() */
639           if (conn->pcb.tcp != NULL) {
640             tcp_recved(conn->pcb.tcp, p->tot_len);
641           }
642           pbuf_free(p);
643         }
644       } else {
645         netbuf_delete((struct netbuf *)mem);
646       }
647     }
648     sys_mbox_free(mbox);
649   }
650
651   /* Delete and drain the acceptmbox. */
652   mbox = conn->acceptmbox;
653   conn->acceptmbox = SYS_MBOX_NULL;
654   if (mbox != SYS_MBOX_NULL) {
655     while (sys_mbox_tryfetch(mbox, &mem) != SYS_MBOX_EMPTY) {
656       /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
657       /* pcb might be set to NULL already by err_tcp() */
658       if (conn->pcb.tcp != NULL) {
659         tcp_accepted(conn->pcb.tcp);
660       }
661       netconn_delete((struct netconn *)mem);
662     }
663     sys_mbox_free(mbox);
664   }
665 }
666
667 #if LWIP_TCP
668 /**
669  * Internal helper function to close a TCP netconn: since this sometimes
670  * doesn't work at the first attempt, this function is called from multiple
671  * places.
672  *
673  * @param conn the TCP netconn to close
674  */
675 static void
676 do_close_internal(struct netconn *conn)
677 {
678   err_t err;
679
680   LWIP_ASSERT("invalid conn", (conn != NULL));
681   LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
682   LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
683   LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
684   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
685
686   /* Set back some callback pointers */
687   tcp_arg(conn->pcb.tcp, NULL);
688   if (conn->pcb.tcp->state == LISTEN) {
689     tcp_accept(conn->pcb.tcp, NULL);
690   } else {
691     tcp_recv(conn->pcb.tcp, NULL);
692     tcp_accept(conn->pcb.tcp, NULL);
693     /* some callbacks have to be reset if tcp_close is not successful */
694     tcp_sent(conn->pcb.tcp, NULL);
695     tcp_poll(conn->pcb.tcp, NULL, 4);
696     tcp_err(conn->pcb.tcp, NULL);
697   }
698   /* Try to close the connection */
699   err = tcp_close(conn->pcb.tcp);
700   if (err == ERR_OK) {
701     /* Closing succeeded */
702     conn->current_msg->err = ERR_OK;
703     conn->current_msg = NULL;
704     conn->state = NETCONN_NONE;
705     /* Set back some callback pointers as conn is going away */
706     conn->pcb.tcp = NULL;
707     /* Trigger select() in socket layer. This send should something else so the
708        errorfd is set, not the read and write fd! */
709     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
710     API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
711     /* wake up the application task */
712     sys_sem_signal(conn->op_completed);
713   } else {
714     /* Closing failed, restore some of the callbacks */
715     /* Closing of listen pcb will never fail! */
716     LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN));
717     tcp_sent(conn->pcb.tcp, sent_tcp);
718     tcp_poll(conn->pcb.tcp, poll_tcp, 4);
719     tcp_err(conn->pcb.tcp, err_tcp);
720     tcp_arg(conn->pcb.tcp, conn);
721   }
722   /* If closing didn't succeed, we get called again either
723      from poll_tcp or from sent_tcp */
724 }
725 #endif /* LWIP_TCP */
726
727 /**
728  * Delete the pcb inside a netconn.
729  * Called from netconn_delete.
730  *
731  * @param msg the api_msg_msg pointing to the connection
732  */
733 void
734 do_delconn(struct api_msg_msg *msg)
735 {
736   /* Drain and delete mboxes */
737   netconn_drain(msg->conn);
738
739   if (msg->conn->pcb.tcp != NULL) {
740
741     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
742 #if LWIP_RAW
743     case NETCONN_RAW:
744       raw_remove(msg->conn->pcb.raw);
745       break;
746 #endif /* LWIP_RAW */
747 #if LWIP_UDP
748     case NETCONN_UDP:
749       msg->conn->pcb.udp->recv_arg = NULL;
750       udp_remove(msg->conn->pcb.udp);
751       break;
752 #endif /* LWIP_UDP */
753 #if LWIP_TCP
754     case NETCONN_TCP:
755     LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
756       msg->conn->write_offset == 0);
757     msg->conn->state = NETCONN_CLOSE;
758     msg->conn->current_msg = msg;
759     do_close_internal(msg->conn);
760       /* API_EVENT is called inside do_close_internal, before releasing
761          the application thread, so we can return at this point! */
762       return;
763 #endif /* LWIP_TCP */
764     default:
765       break;
766     }
767   }
768   /* tcp netconns don't come here! */
769
770   /* Trigger select() in socket layer. This send should something else so the
771      errorfd is set, not the read and write fd! */
772   API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
773   API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
774
775   if (msg->conn->op_completed != SYS_SEM_NULL) {
776     sys_sem_signal(msg->conn->op_completed);
777   }
778 }
779
780 /**
781  * Bind a pcb contained in a netconn
782  * Called from netconn_bind.
783  *
784  * @param msg the api_msg_msg pointing to the connection and containing
785  *            the IP address and port to bind to
786  */
787 void
788 do_bind(struct api_msg_msg *msg)
789 {
790   if (ERR_IS_FATAL(msg->conn->last_err)) {
791     msg->err = msg->conn->last_err;
792   } else {
793     msg->err = ERR_VAL;
794     if (msg->conn->pcb.tcp != NULL) {
795       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
796 #if LWIP_RAW
797       case NETCONN_RAW:
798         msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
799         break;
800 #endif /* LWIP_RAW */
801 #if LWIP_UDP
802       case NETCONN_UDP:
803         msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
804         break;
805 #endif /* LWIP_UDP */
806 #if LWIP_TCP
807       case NETCONN_TCP:
808         msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);
809         break;
810 #endif /* LWIP_TCP */
811       default:
812         break;
813       }
814     }
815   }
816   TCPIP_APIMSG_ACK(msg);
817 }
818
819 #if LWIP_TCP
820 /**
821  * TCP callback function if a connection (opened by tcp_connect/do_connect) has
822  * been established (or reset by the remote host).
823  *
824  * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
825  */
826 static err_t
827 do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
828 {
829   struct netconn *conn;
830
831   LWIP_UNUSED_ARG(pcb);
832
833   conn = arg;
834
835   if (conn == NULL) {
836     return ERR_VAL;
837   }
838
839   LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
840   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
841
842   conn->current_msg->err = err;
843   if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {
844     setup_tcp(conn);
845   }
846   conn->current_msg = NULL;
847   conn->state = NETCONN_NONE;
848   sys_sem_signal(conn->op_completed);
849   return ERR_OK;
850 }
851 #endif /* LWIP_TCP */
852
853 /**
854  * Connect a pcb contained inside a netconn
855  * Called from netconn_connect.
856  *
857  * @param msg the api_msg_msg pointing to the connection and containing
858  *            the IP address and port to connect to
859  */
860 void
861 do_connect(struct api_msg_msg *msg)
862 {
863   if (msg->conn->pcb.tcp == NULL) {
864     /* This may happen when calling netconn_connect() a second time */
865     msg->err = ERR_CLSD;
866     sys_sem_signal(msg->conn->op_completed);
867     return;
868   }
869
870   switch (NETCONNTYPE_GROUP(msg->conn->type)) {
871 #if LWIP_RAW
872   case NETCONN_RAW:
873     msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
874     sys_sem_signal(msg->conn->op_completed);
875     break;
876 #endif /* LWIP_RAW */
877 #if LWIP_UDP
878   case NETCONN_UDP:
879     msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
880     sys_sem_signal(msg->conn->op_completed);
881     break;
882 #endif /* LWIP_UDP */
883 #if LWIP_TCP
884   case NETCONN_TCP:
885     setup_tcp(msg->conn);
886     msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,
887                            do_connected);
888     /* sys_sem_signal() is called from do_connected (or err_tcp()),
889      * when the connection is established! */
890     if (msg->err == ERR_OK) {
891       msg->conn->state = NETCONN_CONNECT;
892       msg->conn->current_msg = msg;
893     } else {
894       /* tcp_connect failed, so do_connected will not be called: return now */
895       sys_sem_signal(msg->conn->op_completed);
896     }
897     break;
898 #endif /* LWIP_TCP */
899   default:
900     LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL;
901       sys_sem_signal(msg->conn->op_completed); }while(0));
902     break;
903   }
904 }
905
906 /**
907  * Connect a pcb contained inside a netconn
908  * Only used for UDP netconns.
909  * Called from netconn_disconnect.
910  *
911  * @param msg the api_msg_msg pointing to the connection to disconnect
912  */
913 void
914 do_disconnect(struct api_msg_msg *msg)
915 {
916 #if LWIP_UDP
917   if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
918     udp_disconnect(msg->conn->pcb.udp);
919     msg->err = ERR_OK;
920   } else
921 #endif /* LWIP_UDP */
922   {
923     msg->err = ERR_VAL;
924   }
925   TCPIP_APIMSG_ACK(msg);
926 }
927
928 /**
929  * Set a TCP pcb contained in a netconn into listen mode
930  * Called from netconn_listen.
931  *
932  * @param msg the api_msg_msg pointing to the connection
933  */
934 void
935 do_listen(struct api_msg_msg *msg)
936 {
937 #if LWIP_TCP
938   if (ERR_IS_FATAL(msg->conn->last_err)) {
939     msg->err = msg->conn->last_err;
940   } else {
941     msg->err = ERR_CONN;
942     if (msg->conn->pcb.tcp != NULL) {
943       if (msg->conn->type == NETCONN_TCP) {
944         if (msg->conn->pcb.tcp->state == CLOSED) {
945 #if TCP_LISTEN_BACKLOG
946           struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
947 #else  /* TCP_LISTEN_BACKLOG */
948           struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);
949 #endif /* TCP_LISTEN_BACKLOG */
950           if (lpcb == NULL) {
951             msg->err = ERR_MEM;
952           } else {
953             /* delete the recvmbox and allocate the acceptmbox */
954             if (msg->conn->recvmbox != SYS_MBOX_NULL) {
955               /** @todo: should we drain the recvmbox here? */
956               sys_mbox_free(msg->conn->recvmbox);
957               msg->conn->recvmbox = SYS_MBOX_NULL;
958             }
959             msg->err = ERR_OK;
960             if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
961               if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) {
962                 msg->err = ERR_MEM;
963               }
964             }
965             if (msg->err == ERR_OK) {
966               msg->conn->state = NETCONN_LISTEN;
967               msg->conn->pcb.tcp = lpcb;
968               tcp_arg(msg->conn->pcb.tcp, msg->conn);
969               tcp_accept(msg->conn->pcb.tcp, accept_function);
970             }
971           }
972         }
973       }
974     }
975   }
976 #endif /* LWIP_TCP */
977   TCPIP_APIMSG_ACK(msg);
978 }
979
980 /**
981  * Send some data on a RAW or UDP pcb contained in a netconn
982  * Called from netconn_send
983  *
984  * @param msg the api_msg_msg pointing to the connection
985  */
986 void
987 do_send(struct api_msg_msg *msg)
988 {
989   if (ERR_IS_FATAL(msg->conn->last_err)) {
990     msg->err = msg->conn->last_err;
991   } else {
992     msg->err = ERR_CONN;
993     if (msg->conn->pcb.tcp != NULL) {
994       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
995 #if LWIP_RAW
996       case NETCONN_RAW:
997         if (msg->msg.b->addr == NULL) {
998           msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
999         } else {
1000           msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr);
1001         }
1002         break;
1003 #endif
1004 #if LWIP_UDP
1005       case NETCONN_UDP:
1006         if (msg->msg.b->addr == NULL) {
1007           msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
1008         } else {
1009           msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port);
1010         }
1011         break;
1012 #endif /* LWIP_UDP */
1013       default:
1014         break;
1015       }
1016     }
1017   }
1018   TCPIP_APIMSG_ACK(msg);
1019 }
1020
1021 /**
1022  * Indicate data has been received from a TCP pcb contained in a netconn
1023  * Called from netconn_recv
1024  *
1025  * @param msg the api_msg_msg pointing to the connection
1026  */
1027 void
1028 do_recv(struct api_msg_msg *msg)
1029 {
1030 #if LWIP_TCP
1031   msg->err = ERR_OK;
1032   if (msg->conn->pcb.tcp != NULL) {
1033     if (msg->conn->type == NETCONN_TCP) {
1034 #if TCP_LISTEN_BACKLOG
1035       if (msg->conn->pcb.tcp->state == LISTEN) {
1036         tcp_accepted(msg->conn->pcb.tcp);
1037       } else
1038 #endif /* TCP_LISTEN_BACKLOG */
1039       {
1040         tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len);
1041       }
1042     }
1043   }
1044 #endif /* LWIP_TCP */
1045   TCPIP_APIMSG_ACK(msg);
1046 }
1047
1048 #if LWIP_TCP
1049 /**
1050  * See if more data needs to be written from a previous call to netconn_write.
1051  * Called initially from do_write. If the first call can't send all data
1052  * (because of low memory or empty send-buffer), this function is called again
1053  * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
1054  * blocking application thread (waiting in netconn_write) is released.
1055  *
1056  * @param conn netconn (that is currently in state NETCONN_WRITE) to process
1057  * @return ERR_OK
1058  *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
1059  */
1060 static err_t
1061 do_writemore(struct netconn *conn)
1062 {
1063   err_t err;
1064   void *dataptr;
1065   u16_t len, available;
1066   u8_t write_finished = 0;
1067   size_t diff;
1068
1069   LWIP_ASSERT("conn != NULL", conn != NULL);
1070   LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
1071   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
1072
1073   dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
1074   diff = conn->current_msg->msg.w.len - conn->write_offset;
1075   if (diff > 0xffffUL) { /* max_u16_t */
1076     len = 0xffff;
1077 #if LWIP_TCPIP_CORE_LOCKING
1078     conn->write_delayed = 1;
1079 #endif
1080   } else {
1081     len = (u16_t)diff;
1082   }
1083   available = tcp_sndbuf(conn->pcb.tcp);
1084   if (available < len) {
1085     /* don't try to write more than sendbuf */
1086     len = available;
1087 #if LWIP_TCPIP_CORE_LOCKING
1088     conn->write_delayed = 1;
1089 #endif
1090   }
1091
1092   err = tcp_write(conn->pcb.tcp, dataptr, len, conn->current_msg->msg.w.apiflags);
1093   LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
1094   if (err == ERR_OK) {
1095     conn->write_offset += len;
1096     if (conn->write_offset == conn->current_msg->msg.w.len) {
1097       /* everything was written */
1098       write_finished = 1;
1099       conn->write_offset = 0;
1100       /* API_EVENT might call tcp_tmr, so reset conn->state now */
1101       conn->state = NETCONN_NONE;
1102     }
1103     err = tcp_output_nagle(conn->pcb.tcp);
1104     if ((err == ERR_OK) && (tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT)) {
1105       API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
1106     }
1107   } else if (err == ERR_MEM) {
1108     /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
1109        we do NOT return to the application thread, since ERR_MEM is
1110        only a temporary error! */
1111
1112     /* tcp_enqueue returned ERR_MEM, try tcp_output anyway */
1113     err = tcp_output(conn->pcb.tcp);
1114
1115 #if LWIP_TCPIP_CORE_LOCKING
1116     conn->write_delayed = 1;
1117 #endif
1118   } else {
1119     /* On errors != ERR_MEM, we don't try writing any more but return
1120        the error to the application thread. */
1121     write_finished = 1;
1122   }
1123
1124   if (write_finished) {
1125     /* everything was written: set back connection state
1126        and back to application task */
1127     conn->current_msg->err = err;
1128     conn->current_msg = NULL;
1129     conn->state = NETCONN_NONE;
1130 #if LWIP_TCPIP_CORE_LOCKING
1131     if (conn->write_delayed != 0)
1132 #endif
1133     {
1134       sys_sem_signal(conn->op_completed);
1135     }
1136   }
1137 #if LWIP_TCPIP_CORE_LOCKING
1138   else
1139     return ERR_MEM;
1140 #endif
1141   return ERR_OK;
1142 }
1143 #endif /* LWIP_TCP */
1144
1145 /**
1146  * Send some data on a TCP pcb contained in a netconn
1147  * Called from netconn_write
1148  *
1149  * @param msg the api_msg_msg pointing to the connection
1150  */
1151 void
1152 do_write(struct api_msg_msg *msg)
1153 {
1154   if (ERR_IS_FATAL(msg->conn->last_err)) {
1155     msg->err = msg->conn->last_err;
1156   } else {
1157     if (msg->conn->type == NETCONN_TCP) {
1158 #if LWIP_TCP
1159       if (msg->conn->pcb.tcp != NULL) {
1160         msg->conn->state = NETCONN_WRITE;
1161         /* set all the variables used by do_writemore */
1162         LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1163           msg->conn->write_offset == 0);
1164         msg->conn->current_msg = msg;
1165         msg->conn->write_offset = 0;
1166 #if LWIP_TCPIP_CORE_LOCKING
1167         msg->conn->write_delayed = 0;
1168         if (do_writemore(msg->conn) != ERR_OK) {
1169           LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
1170           UNLOCK_TCPIP_CORE();
1171           sys_arch_sem_wait(msg->conn->op_completed, 0);
1172           LOCK_TCPIP_CORE();
1173           LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1174         }
1175 #else /* LWIP_TCPIP_CORE_LOCKING */
1176         do_writemore(msg->conn);
1177 #endif /* LWIP_TCPIP_CORE_LOCKING */
1178         /* for both cases: if do_writemore was called, don't ACK the APIMSG
1179            since do_writemore ACKs it! */
1180         return;
1181       } else {
1182         msg->err = ERR_CONN;
1183       }
1184 #else /* LWIP_TCP */
1185       msg->err = ERR_VAL;
1186 #endif /* LWIP_TCP */
1187 #if (LWIP_UDP || LWIP_RAW)
1188     } else {
1189       msg->err = ERR_VAL;
1190 #endif /* (LWIP_UDP || LWIP_RAW) */
1191     }
1192   }
1193   TCPIP_APIMSG_ACK(msg);
1194 }
1195
1196 /**
1197  * Return a connection's local or remote address
1198  * Called from netconn_getaddr
1199  *
1200  * @param msg the api_msg_msg pointing to the connection
1201  */
1202 void
1203 do_getaddr(struct api_msg_msg *msg)
1204 {
1205   if (msg->conn->pcb.ip != NULL) {
1206     *(msg->msg.ad.ipaddr) = (msg->msg.ad.local?msg->conn->pcb.ip->local_ip:msg->conn->pcb.ip->remote_ip);
1207
1208     msg->err = ERR_OK;
1209     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1210 #if LWIP_RAW
1211     case NETCONN_RAW:
1212       if (msg->msg.ad.local) {
1213         *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
1214       } else {
1215         /* return an error as connecting is only a helper for upper layers */
1216         msg->err = ERR_CONN;
1217       }
1218       break;
1219 #endif /* LWIP_RAW */
1220 #if LWIP_UDP
1221     case NETCONN_UDP:
1222       if (msg->msg.ad.local) {
1223         *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
1224       } else {
1225         if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
1226           msg->err = ERR_CONN;
1227         } else {
1228           *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
1229         }
1230       }
1231       break;
1232 #endif /* LWIP_UDP */
1233 #if LWIP_TCP
1234     case NETCONN_TCP:
1235       *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port);
1236       break;
1237 #endif /* LWIP_TCP */
1238     }
1239   } else {
1240     msg->err = ERR_CONN;
1241   }
1242   TCPIP_APIMSG_ACK(msg);
1243 }
1244
1245 /**
1246  * Close a TCP pcb contained in a netconn
1247  * Called from netconn_close
1248  *
1249  * @param msg the api_msg_msg pointing to the connection
1250  */
1251 void
1252 do_close(struct api_msg_msg *msg)
1253 {
1254 #if LWIP_TCP
1255   if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
1256     netconn_drain(msg->conn);
1257     LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1258       msg->conn->write_offset == 0);
1259     msg->conn->state = NETCONN_CLOSE;
1260     msg->conn->current_msg = msg;
1261     do_close_internal(msg->conn);
1262     /* for tcp netconns, do_close_internal ACKs the message */
1263   } else
1264 #endif /* LWIP_TCP */
1265   {
1266     msg->err = ERR_VAL;
1267     sys_sem_signal(msg->conn->op_completed);
1268   }
1269 }
1270
1271 #if LWIP_IGMP
1272 /**
1273  * Join multicast groups for UDP netconns.
1274  * Called from netconn_join_leave_group
1275  *
1276  * @param msg the api_msg_msg pointing to the connection
1277  */
1278 void
1279 do_join_leave_group(struct api_msg_msg *msg)
1280
1281   if (ERR_IS_FATAL(msg->conn->last_err)) {
1282     msg->err = msg->conn->last_err;
1283   } else {
1284     if (msg->conn->pcb.tcp != NULL) {
1285       if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1286 #if LWIP_UDP
1287         if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
1288           msg->err = igmp_joingroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);
1289         } else {
1290           msg->err = igmp_leavegroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);
1291         }
1292 #endif /* LWIP_UDP */
1293 #if (LWIP_TCP || LWIP_RAW)
1294       } else {
1295         msg->err = ERR_VAL;
1296 #endif /* (LWIP_TCP || LWIP_RAW) */
1297       }
1298     } else {
1299       msg->err = ERR_CONN;
1300     }
1301   }
1302   TCPIP_APIMSG_ACK(msg);
1303 }
1304 #endif /* LWIP_IGMP */
1305
1306 #if LWIP_DNS
1307 /**
1308  * Callback function that is called when DNS name is resolved
1309  * (or on timeout). A waiting application thread is waked up by
1310  * signaling the semaphore.
1311  */
1312 static void
1313 do_dns_found(const char *name, struct ip_addr *ipaddr, void *arg)
1314 {
1315   struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1316
1317   LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0);
1318   LWIP_UNUSED_ARG(name);
1319
1320   if (ipaddr == NULL) {
1321     /* timeout or memory error */
1322     *msg->err = ERR_VAL;
1323   } else {
1324     /* address was resolved */
1325     *msg->err = ERR_OK;
1326     *msg->addr = *ipaddr;
1327   }
1328   /* wake up the application task waiting in netconn_gethostbyname */
1329   sys_sem_signal(msg->sem);
1330 }
1331
1332 /**
1333  * Execute a DNS query
1334  * Called from netconn_gethostbyname
1335  *
1336  * @param arg the dns_api_msg pointing to the query
1337  */
1338 void
1339 do_gethostbyname(void *arg)
1340 {
1341   struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1342
1343   *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg);
1344   if (*msg->err != ERR_INPROGRESS) {
1345     /* on error or immediate success, wake up the application
1346      * task waiting in netconn_gethostbyname */
1347     sys_sem_signal(msg->sem);
1348   }
1349 }
1350 #endif /* LWIP_DNS */
1351
1352 #endif /* LWIP_NETCONN */