]>
Commit | Line | Data |
---|---|---|
6e6d4a8b JP |
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 | /* forward declarations */ | |
56 | #if LWIP_TCP | |
57 | static err_t do_writemore(struct netconn *conn); | |
58 | static void do_close_internal(struct netconn *conn); | |
59 | #endif | |
60 | ||
61 | #if LWIP_RAW | |
62 | /** | |
63 | * Receive callback function for RAW netconns. | |
64 | * Doesn't 'eat' the packet, only references it and sends it to | |
65 | * conn->recvmbox | |
66 | * | |
67 | * @see raw.h (struct raw_pcb.recv) for parameters and return value | |
68 | */ | |
69 | static u8_t | |
70 | recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, | |
71 | struct ip_addr *addr) | |
72 | { | |
73 | struct pbuf *q; | |
74 | struct netbuf *buf; | |
75 | struct netconn *conn; | |
76 | #if LWIP_SO_RCVBUF | |
77 | int recv_avail; | |
78 | #endif /* LWIP_SO_RCVBUF */ | |
79 | ||
80 | LWIP_UNUSED_ARG(addr); | |
81 | conn = arg; | |
82 | ||
83 | #if LWIP_SO_RCVBUF | |
84 | SYS_ARCH_GET(conn->recv_avail, recv_avail); | |
85 | if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) && | |
86 | ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) { | |
87 | #else /* LWIP_SO_RCVBUF */ | |
88 | if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) { | |
89 | #endif /* LWIP_SO_RCVBUF */ | |
90 | /* copy the whole packet into new pbufs */ | |
91 | q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); | |
92 | if(q != NULL) { | |
93 | if (pbuf_copy(q, p) != ERR_OK) { | |
94 | pbuf_free(q); | |
95 | q = NULL; | |
96 | } | |
97 | } | |
98 | ||
99 | if(q != NULL) { | |
100 | buf = memp_malloc(MEMP_NETBUF); | |
101 | if (buf == NULL) { | |
102 | pbuf_free(q); | |
103 | return 0; | |
104 | } | |
105 | ||
106 | buf->p = q; | |
107 | buf->ptr = q; | |
108 | buf->addr = &(((struct ip_hdr*)(q->payload))->src); | |
109 | buf->port = pcb->protocol; | |
110 | ||
111 | SYS_ARCH_INC(conn->recv_avail, q->tot_len); | |
112 | /* Register event with callback */ | |
113 | API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len); | |
114 | if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) { | |
115 | netbuf_delete(buf); | |
116 | } | |
117 | } | |
118 | } | |
119 | ||
120 | return 0; /* do not eat the packet */ | |
121 | } | |
122 | #endif /* LWIP_RAW*/ | |
123 | ||
124 | #if LWIP_UDP | |
125 | /** | |
126 | * Receive callback function for UDP netconns. | |
127 | * Posts the packet to conn->recvmbox or deletes it on memory error. | |
128 | * | |
129 | * @see udp.h (struct udp_pcb.recv) for parameters | |
130 | */ | |
131 | static void | |
132 | recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, | |
133 | struct ip_addr *addr, u16_t port) | |
134 | { | |
135 | struct netbuf *buf; | |
136 | struct netconn *conn; | |
137 | #if LWIP_SO_RCVBUF | |
138 | int recv_avail; | |
139 | #endif /* LWIP_SO_RCVBUF */ | |
140 | ||
141 | LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ | |
142 | LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); | |
143 | LWIP_ASSERT("recv_udp must have an argument", arg != NULL); | |
144 | conn = arg; | |
145 | LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); | |
146 | ||
147 | #if LWIP_SO_RCVBUF | |
148 | SYS_ARCH_GET(conn->recv_avail, recv_avail); | |
149 | if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) || | |
150 | ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { | |
151 | #else /* LWIP_SO_RCVBUF */ | |
152 | if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) { | |
153 | #endif /* LWIP_SO_RCVBUF */ | |
154 | pbuf_free(p); | |
155 | return; | |
156 | } | |
157 | ||
158 | buf = memp_malloc(MEMP_NETBUF); | |
159 | if (buf == NULL) { | |
160 | pbuf_free(p); | |
161 | return; | |
162 | } else { | |
163 | buf->p = p; | |
164 | buf->ptr = p; | |
165 | buf->addr = addr; | |
166 | buf->port = port; | |
167 | } | |
168 | ||
169 | SYS_ARCH_INC(conn->recv_avail, p->tot_len); | |
170 | /* Register event with callback */ | |
171 | API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len); | |
172 | if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) { | |
173 | netbuf_delete(buf); | |
174 | return; | |
175 | } | |
176 | } | |
177 | #endif /* LWIP_UDP */ | |
178 | ||
179 | #if LWIP_TCP | |
180 | /** | |
181 | * Receive callback function for TCP netconns. | |
182 | * Posts the packet to conn->recvmbox, but doesn't delete it on errors. | |
183 | * | |
184 | * @see tcp.h (struct tcp_pcb.recv) for parameters and return value | |
185 | */ | |
186 | static err_t | |
187 | recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) | |
188 | { | |
189 | struct netconn *conn; | |
190 | u16_t len; | |
191 | ||
192 | LWIP_UNUSED_ARG(pcb); | |
193 | LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); | |
194 | LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); | |
195 | conn = arg; | |
196 | LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); | |
197 | ||
198 | if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) { | |
199 | return ERR_VAL; | |
200 | } | |
201 | ||
202 | conn->err = err; | |
203 | if (p != NULL) { | |
204 | len = p->tot_len; | |
205 | SYS_ARCH_INC(conn->recv_avail, len); | |
206 | } else { | |
207 | len = 0; | |
208 | } | |
209 | /* Register event with callback */ | |
210 | API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); | |
211 | if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) { | |
212 | return ERR_MEM; | |
213 | } | |
214 | ||
215 | return ERR_OK; | |
216 | } | |
217 | ||
218 | /** | |
219 | * Poll callback function for TCP netconns. | |
220 | * Wakes up an application thread that waits for a connection to close | |
221 | * or data to be sent. The application thread then takes the | |
222 | * appropriate action to go on. | |
223 | * | |
224 | * Signals the conn->sem. | |
225 | * netconn_close waits for conn->sem if closing failed. | |
226 | * | |
227 | * @see tcp.h (struct tcp_pcb.poll) for parameters and return value | |
228 | */ | |
229 | static err_t | |
230 | poll_tcp(void *arg, struct tcp_pcb *pcb) | |
231 | { | |
232 | struct netconn *conn = arg; | |
233 | ||
234 | LWIP_UNUSED_ARG(pcb); | |
235 | LWIP_ASSERT("conn != NULL", (conn != NULL)); | |
236 | ||
237 | if (conn->state == NETCONN_WRITE) { | |
238 | do_writemore(conn); | |
239 | } else if (conn->state == NETCONN_CLOSE) { | |
240 | do_close_internal(conn); | |
241 | } | |
242 | ||
243 | return ERR_OK; | |
244 | } | |
245 | ||
246 | /** | |
247 | * Sent callback function for TCP netconns. | |
248 | * Signals the conn->sem and calls API_EVENT. | |
249 | * netconn_write waits for conn->sem if send buffer is low. | |
250 | * | |
251 | * @see tcp.h (struct tcp_pcb.sent) for parameters and return value | |
252 | */ | |
253 | static err_t | |
254 | sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) | |
255 | { | |
256 | struct netconn *conn = arg; | |
257 | ||
258 | LWIP_UNUSED_ARG(pcb); | |
259 | LWIP_ASSERT("conn != NULL", (conn != NULL)); | |
260 | ||
261 | if (conn->state == NETCONN_WRITE) { | |
262 | LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); | |
263 | do_writemore(conn); | |
264 | } else if (conn->state == NETCONN_CLOSE) { | |
265 | do_close_internal(conn); | |
266 | } | |
267 | ||
268 | if (conn) { | |
269 | if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) { | |
270 | API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); | |
271 | } | |
272 | } | |
273 | ||
274 | return ERR_OK; | |
275 | } | |
276 | ||
277 | /** | |
278 | * Error callback function for TCP netconns. | |
279 | * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. | |
280 | * The application thread has then to decide what to do. | |
281 | * | |
282 | * @see tcp.h (struct tcp_pcb.err) for parameters | |
283 | */ | |
284 | static void | |
285 | err_tcp(void *arg, err_t err) | |
286 | { | |
287 | struct netconn *conn; | |
288 | ||
289 | conn = arg; | |
290 | LWIP_ASSERT("conn != NULL", (conn != NULL)); | |
291 | ||
292 | conn->pcb.tcp = NULL; | |
293 | ||
294 | conn->err = err; | |
295 | if (conn->recvmbox != SYS_MBOX_NULL) { | |
296 | /* Register event with callback */ | |
297 | API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); | |
298 | sys_mbox_post(conn->recvmbox, NULL); | |
299 | } | |
300 | if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) { | |
301 | conn->state = NETCONN_NONE; | |
302 | sys_sem_signal(conn->op_completed); | |
303 | } | |
304 | if (conn->acceptmbox != SYS_MBOX_NULL) { | |
305 | /* Register event with callback */ | |
306 | API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); | |
307 | sys_mbox_post(conn->acceptmbox, NULL); | |
308 | } | |
309 | if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) { | |
310 | /* calling do_writemore/do_close_internal is not necessary | |
311 | since the pcb has already been deleted! */ | |
312 | conn->state = NETCONN_NONE; | |
313 | /* wake up the waiting task */ | |
314 | sys_sem_signal(conn->op_completed); | |
315 | } | |
316 | } | |
317 | ||
318 | /** | |
319 | * Setup a tcp_pcb with the correct callback function pointers | |
320 | * and their arguments. | |
321 | * | |
322 | * @param conn the TCP netconn to setup | |
323 | */ | |
324 | static void | |
325 | setup_tcp(struct netconn *conn) | |
326 | { | |
327 | struct tcp_pcb *pcb; | |
328 | ||
329 | pcb = conn->pcb.tcp; | |
330 | tcp_arg(pcb, conn); | |
331 | tcp_recv(pcb, recv_tcp); | |
332 | tcp_sent(pcb, sent_tcp); | |
333 | tcp_poll(pcb, poll_tcp, 4); | |
334 | tcp_err(pcb, err_tcp); | |
335 | } | |
336 | ||
337 | /** | |
338 | * Accept callback function for TCP netconns. | |
339 | * Allocates a new netconn and posts that to conn->acceptmbox. | |
340 | * | |
341 | * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value | |
342 | */ | |
343 | static err_t | |
344 | accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) | |
345 | { | |
346 | struct netconn *newconn; | |
347 | struct netconn *conn; | |
348 | ||
349 | #if API_MSG_DEBUG | |
350 | #if TCP_DEBUG | |
351 | tcp_debug_print_state(newpcb->state); | |
352 | #endif /* TCP_DEBUG */ | |
353 | #endif /* API_MSG_DEBUG */ | |
354 | conn = (struct netconn *)arg; | |
355 | ||
356 | LWIP_ERROR("accept_function: invalid conn->acceptmbox", | |
357 | conn->acceptmbox != SYS_MBOX_NULL, return ERR_VAL;); | |
358 | ||
359 | /* We have to set the callback here even though | |
360 | * the new socket is unknown. conn->socket is marked as -1. */ | |
361 | newconn = netconn_alloc(conn->type, conn->callback); | |
362 | if (newconn == NULL) { | |
363 | return ERR_MEM; | |
364 | } | |
365 | newconn->pcb.tcp = newpcb; | |
366 | setup_tcp(newconn); | |
367 | newconn->err = err; | |
368 | /* Register event with callback */ | |
369 | API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); | |
370 | ||
371 | if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) { | |
372 | /* When returning != ERR_OK, the connection is aborted in tcp_process(), | |
373 | so do nothing here! */ | |
374 | newconn->pcb.tcp = NULL; | |
375 | netconn_free(newconn); | |
376 | return ERR_MEM; | |
377 | } | |
378 | return ERR_OK; | |
379 | } | |
380 | #endif /* LWIP_TCP */ | |
381 | ||
382 | /** | |
383 | * Create a new pcb of a specific type. | |
384 | * Called from do_newconn(). | |
385 | * | |
386 | * @param msg the api_msg_msg describing the connection type | |
387 | * @return msg->conn->err, but the return value is currently ignored | |
388 | */ | |
389 | static err_t | |
390 | pcb_new(struct api_msg_msg *msg) | |
391 | { | |
392 | msg->conn->err = ERR_OK; | |
393 | ||
394 | LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); | |
395 | ||
396 | /* Allocate a PCB for this connection */ | |
397 | switch(NETCONNTYPE_GROUP(msg->conn->type)) { | |
398 | #if LWIP_RAW | |
399 | case NETCONN_RAW: | |
400 | msg->conn->pcb.raw = raw_new(msg->msg.n.proto); | |
401 | if(msg->conn->pcb.raw == NULL) { | |
402 | msg->conn->err = ERR_MEM; | |
403 | break; | |
404 | } | |
405 | raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); | |
406 | break; | |
407 | #endif /* LWIP_RAW */ | |
408 | #if LWIP_UDP | |
409 | case NETCONN_UDP: | |
410 | msg->conn->pcb.udp = udp_new(); | |
411 | if(msg->conn->pcb.udp == NULL) { | |
412 | msg->conn->err = ERR_MEM; | |
413 | break; | |
414 | } | |
415 | #if LWIP_UDPLITE | |
416 | if (msg->conn->type==NETCONN_UDPLITE) { | |
417 | udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); | |
418 | } | |
419 | #endif /* LWIP_UDPLITE */ | |
420 | if (msg->conn->type==NETCONN_UDPNOCHKSUM) { | |
421 | udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); | |
422 | } | |
423 | udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); | |
424 | break; | |
425 | #endif /* LWIP_UDP */ | |
426 | #if LWIP_TCP | |
427 | case NETCONN_TCP: | |
428 | msg->conn->pcb.tcp = tcp_new(); | |
429 | if(msg->conn->pcb.tcp == NULL) { | |
430 | msg->conn->err = ERR_MEM; | |
431 | break; | |
432 | } | |
433 | setup_tcp(msg->conn); | |
434 | break; | |
435 | #endif /* LWIP_TCP */ | |
436 | default: | |
437 | /* Unsupported netconn type, e.g. protocol disabled */ | |
438 | msg->conn->err = ERR_VAL; | |
439 | break; | |
440 | } | |
441 | ||
442 | return msg->conn->err; | |
443 | } | |
444 | ||
445 | /** | |
446 | * Create a new pcb of a specific type inside a netconn. | |
447 | * Called from netconn_new_with_proto_and_callback. | |
448 | * | |
449 | * @param msg the api_msg_msg describing the connection type | |
450 | */ | |
451 | void | |
452 | do_newconn(struct api_msg_msg *msg) | |
453 | { | |
454 | if(msg->conn->pcb.tcp == NULL) { | |
455 | pcb_new(msg); | |
456 | } | |
457 | /* Else? This "new" connection already has a PCB allocated. */ | |
458 | /* Is this an error condition? Should it be deleted? */ | |
459 | /* We currently just are happy and return. */ | |
460 | ||
461 | TCPIP_APIMSG_ACK(msg); | |
462 | } | |
463 | ||
464 | /** | |
465 | * Create a new netconn (of a specific type) that has a callback function. | |
466 | * The corresponding pcb is NOT created! | |
467 | * | |
468 | * @param t the type of 'connection' to create (@see enum netconn_type) | |
469 | * @param proto the IP protocol for RAW IP pcbs | |
470 | * @param callback a function to call on status changes (RX available, TX'ed) | |
471 | * @return a newly allocated struct netconn or | |
472 | * NULL on memory error | |
473 | */ | |
474 | struct netconn* | |
475 | netconn_alloc(enum netconn_type t, netconn_callback callback) | |
476 | { | |
477 | struct netconn *conn; | |
478 | int size; | |
479 | ||
480 | conn = memp_malloc(MEMP_NETCONN); | |
481 | if (conn == NULL) { | |
482 | return NULL; | |
483 | } | |
484 | ||
485 | conn->err = ERR_OK; | |
486 | conn->type = t; | |
487 | conn->pcb.tcp = NULL; | |
488 | ||
489 | #if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \ | |
490 | (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE) | |
491 | size = DEFAULT_RAW_RECVMBOX_SIZE; | |
492 | #else | |
493 | switch(NETCONNTYPE_GROUP(t)) { | |
494 | #if LWIP_RAW | |
495 | case NETCONN_RAW: | |
496 | size = DEFAULT_RAW_RECVMBOX_SIZE; | |
497 | break; | |
498 | #endif /* LWIP_RAW */ | |
499 | #if LWIP_UDP | |
500 | case NETCONN_UDP: | |
501 | size = DEFAULT_UDP_RECVMBOX_SIZE; | |
502 | break; | |
503 | #endif /* LWIP_UDP */ | |
504 | #if LWIP_TCP | |
505 | case NETCONN_TCP: | |
506 | size = DEFAULT_TCP_RECVMBOX_SIZE; | |
507 | break; | |
508 | #endif /* LWIP_TCP */ | |
509 | default: | |
510 | LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); | |
511 | break; | |
512 | } | |
513 | #endif | |
514 | ||
515 | if ((conn->op_completed = sys_sem_new(0)) == SYS_SEM_NULL) { | |
516 | memp_free(MEMP_NETCONN, conn); | |
517 | return NULL; | |
518 | } | |
519 | if ((conn->recvmbox = sys_mbox_new(size)) == SYS_MBOX_NULL) { | |
520 | sys_sem_free(conn->op_completed); | |
521 | memp_free(MEMP_NETCONN, conn); | |
522 | return NULL; | |
523 | } | |
524 | ||
525 | conn->acceptmbox = SYS_MBOX_NULL; | |
526 | conn->state = NETCONN_NONE; | |
527 | /* initialize socket to -1 since 0 is a valid socket */ | |
528 | conn->socket = -1; | |
529 | conn->callback = callback; | |
530 | conn->recv_avail = 0; | |
531 | #if LWIP_SO_RCVTIMEO | |
532 | conn->recv_timeout = 0; | |
533 | #endif /* LWIP_SO_RCVTIMEO */ | |
534 | #if LWIP_SO_RCVBUF | |
535 | conn->recv_bufsize = INT_MAX; | |
536 | #endif /* LWIP_SO_RCVBUF */ | |
537 | return conn; | |
538 | } | |
539 | ||
540 | /** | |
541 | * Delete a netconn and all its resources. | |
542 | * The pcb is NOT freed (since we might not be in the right thread context do this). | |
543 | * | |
544 | * @param conn the netconn to free | |
545 | */ | |
546 | void | |
547 | netconn_free(struct netconn *conn) | |
548 | { | |
549 | void *mem; | |
550 | LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); | |
551 | ||
552 | /* Drain the recvmbox. */ | |
553 | if (conn->recvmbox != SYS_MBOX_NULL) { | |
554 | while (sys_mbox_tryfetch(conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { | |
555 | if (conn->type == NETCONN_TCP) { | |
556 | if(mem != NULL) { | |
557 | pbuf_free((struct pbuf *)mem); | |
558 | } | |
559 | } else { | |
560 | netbuf_delete((struct netbuf *)mem); | |
561 | } | |
562 | } | |
563 | sys_mbox_free(conn->recvmbox); | |
564 | conn->recvmbox = SYS_MBOX_NULL; | |
565 | } | |
566 | ||
567 | /* Drain the acceptmbox. */ | |
568 | if (conn->acceptmbox != SYS_MBOX_NULL) { | |
569 | while (sys_mbox_tryfetch(conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { | |
570 | netconn_delete((struct netconn *)mem); | |
571 | } | |
572 | sys_mbox_free(conn->acceptmbox); | |
573 | conn->acceptmbox = SYS_MBOX_NULL; | |
574 | } | |
575 | ||
576 | sys_sem_free(conn->op_completed); | |
577 | conn->op_completed = SYS_SEM_NULL; | |
578 | ||
579 | memp_free(MEMP_NETCONN, conn); | |
580 | } | |
581 | ||
582 | #if LWIP_TCP | |
583 | /** | |
584 | * Internal helper function to close a TCP netconn: since this sometimes | |
585 | * doesn't work at the first attempt, this function is called from multiple | |
586 | * places. | |
587 | * | |
588 | * @param conn the TCP netconn to close | |
589 | */ | |
590 | static void | |
591 | do_close_internal(struct netconn *conn) | |
592 | { | |
593 | err_t err; | |
594 | ||
595 | LWIP_ASSERT("invalid conn", (conn != NULL)); | |
596 | LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP)); | |
597 | LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); | |
598 | LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); | |
599 | ||
600 | /* Set back some callback pointers */ | |
601 | if (conn->pcb.tcp->state == LISTEN) { | |
602 | tcp_arg(conn->pcb.tcp, NULL); | |
603 | tcp_accept(conn->pcb.tcp, NULL); | |
604 | } else { | |
605 | tcp_recv(conn->pcb.tcp, NULL); | |
606 | } | |
607 | /* Try to close the connection */ | |
608 | err = tcp_close(conn->pcb.tcp); | |
609 | if (err == ERR_OK) { | |
610 | /* Closing succeeded */ | |
611 | conn->state = NETCONN_NONE; | |
612 | /* Set back some callback pointers as conn is going away */ | |
613 | tcp_err(conn->pcb.tcp, NULL); | |
614 | tcp_poll(conn->pcb.tcp, NULL, 4); | |
615 | tcp_sent(conn->pcb.tcp, NULL); | |
616 | tcp_recv(conn->pcb.tcp, NULL); | |
617 | tcp_arg(conn->pcb.tcp, NULL); | |
618 | conn->pcb.tcp = NULL; | |
619 | conn->err = ERR_OK; | |
620 | /* Trigger select() in socket layer. This send should something else so the | |
621 | errorfd is set, not the read and write fd! */ | |
622 | API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); | |
623 | API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); | |
624 | /* wake up the application task */ | |
625 | sys_sem_signal(conn->op_completed); | |
626 | } | |
627 | /* If closing didn't succeed, we get called again either | |
628 | from poll_tcp or from sent_tcp */ | |
629 | } | |
630 | #endif /* LWIP_TCP */ | |
631 | ||
632 | /** | |
633 | * Delete the pcb inside a netconn. | |
634 | * Called from netconn_delete. | |
635 | * | |
636 | * @param msg the api_msg_msg pointing to the connection | |
637 | */ | |
638 | void | |
639 | do_delconn(struct api_msg_msg *msg) | |
640 | { | |
641 | if (msg->conn->pcb.tcp != NULL) { | |
642 | switch (NETCONNTYPE_GROUP(msg->conn->type)) { | |
643 | #if LWIP_RAW | |
644 | case NETCONN_RAW: | |
645 | raw_remove(msg->conn->pcb.raw); | |
646 | break; | |
647 | #endif /* LWIP_RAW */ | |
648 | #if LWIP_UDP | |
649 | case NETCONN_UDP: | |
650 | msg->conn->pcb.udp->recv_arg = NULL; | |
651 | udp_remove(msg->conn->pcb.udp); | |
652 | break; | |
653 | #endif /* LWIP_UDP */ | |
654 | #if LWIP_TCP | |
655 | case NETCONN_TCP: | |
656 | msg->conn->state = NETCONN_CLOSE; | |
657 | do_close_internal(msg->conn); | |
658 | /* API_EVENT is called inside do_close_internal, before releasing | |
659 | the application thread, so we can return at this point! */ | |
660 | return; | |
661 | #endif /* LWIP_TCP */ | |
662 | default: | |
663 | break; | |
664 | } | |
665 | } | |
666 | /* tcp netconns don't come here! */ | |
667 | ||
668 | /* Trigger select() in socket layer. This send should something else so the | |
669 | errorfd is set, not the read and write fd! */ | |
670 | API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); | |
671 | API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); | |
672 | ||
673 | if (msg->conn->op_completed != SYS_SEM_NULL) { | |
674 | sys_sem_signal(msg->conn->op_completed); | |
675 | } | |
676 | } | |
677 | ||
678 | /** | |
679 | * Bind a pcb contained in a netconn | |
680 | * Called from netconn_bind. | |
681 | * | |
682 | * @param msg the api_msg_msg pointing to the connection and containing | |
683 | * the IP address and port to bind to | |
684 | */ | |
685 | void | |
686 | do_bind(struct api_msg_msg *msg) | |
687 | { | |
688 | if (!ERR_IS_FATAL(msg->conn->err)) { | |
689 | if (msg->conn->pcb.tcp != NULL) { | |
690 | switch (NETCONNTYPE_GROUP(msg->conn->type)) { | |
691 | #if LWIP_RAW | |
692 | case NETCONN_RAW: | |
693 | msg->conn->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr); | |
694 | break; | |
695 | #endif /* LWIP_RAW */ | |
696 | #if LWIP_UDP | |
697 | case NETCONN_UDP: | |
698 | msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); | |
699 | break; | |
700 | #endif /* LWIP_UDP */ | |
701 | #if LWIP_TCP | |
702 | case NETCONN_TCP: | |
703 | msg->conn->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port); | |
704 | break; | |
705 | #endif /* LWIP_TCP */ | |
706 | default: | |
707 | break; | |
708 | } | |
709 | } else { | |
710 | /* msg->conn->pcb is NULL */ | |
711 | msg->conn->err = ERR_VAL; | |
712 | } | |
713 | } | |
714 | TCPIP_APIMSG_ACK(msg); | |
715 | } | |
716 | ||
717 | #if LWIP_TCP | |
718 | /** | |
719 | * TCP callback function if a connection (opened by tcp_connect/do_connect) has | |
720 | * been established (or reset by the remote host). | |
721 | * | |
722 | * @see tcp.h (struct tcp_pcb.connected) for parameters and return values | |
723 | */ | |
724 | static err_t | |
725 | do_connected(void *arg, struct tcp_pcb *pcb, err_t err) | |
726 | { | |
727 | struct netconn *conn; | |
728 | ||
729 | LWIP_UNUSED_ARG(pcb); | |
730 | ||
731 | conn = arg; | |
732 | ||
733 | if (conn == NULL) { | |
734 | return ERR_VAL; | |
735 | } | |
736 | ||
737 | conn->err = err; | |
738 | if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) { | |
739 | setup_tcp(conn); | |
740 | } | |
741 | conn->state = NETCONN_NONE; | |
742 | sys_sem_signal(conn->op_completed); | |
743 | return ERR_OK; | |
744 | } | |
745 | #endif /* LWIP_TCP */ | |
746 | ||
747 | /** | |
748 | * Connect a pcb contained inside a netconn | |
749 | * Called from netconn_connect. | |
750 | * | |
751 | * @param msg the api_msg_msg pointing to the connection and containing | |
752 | * the IP address and port to connect to | |
753 | */ | |
754 | void | |
755 | do_connect(struct api_msg_msg *msg) | |
756 | { | |
757 | if (msg->conn->pcb.tcp == NULL) { | |
758 | sys_sem_signal(msg->conn->op_completed); | |
759 | return; | |
760 | } | |
761 | ||
762 | switch (NETCONNTYPE_GROUP(msg->conn->type)) { | |
763 | #if LWIP_RAW | |
764 | case NETCONN_RAW: | |
765 | msg->conn->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); | |
766 | sys_sem_signal(msg->conn->op_completed); | |
767 | break; | |
768 | #endif /* LWIP_RAW */ | |
769 | #if LWIP_UDP | |
770 | case NETCONN_UDP: | |
771 | msg->conn->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); | |
772 | sys_sem_signal(msg->conn->op_completed); | |
773 | break; | |
774 | #endif /* LWIP_UDP */ | |
775 | #if LWIP_TCP | |
776 | case NETCONN_TCP: | |
777 | msg->conn->state = NETCONN_CONNECT; | |
778 | setup_tcp(msg->conn); | |
779 | msg->conn->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port, | |
780 | do_connected); | |
781 | /* sys_sem_signal() is called from do_connected (or err_tcp()), | |
782 | * when the connection is established! */ | |
783 | break; | |
784 | #endif /* LWIP_TCP */ | |
785 | default: | |
786 | break; | |
787 | } | |
788 | } | |
789 | ||
790 | /** | |
791 | * Connect a pcb contained inside a netconn | |
792 | * Only used for UDP netconns. | |
793 | * Called from netconn_disconnect. | |
794 | * | |
795 | * @param msg the api_msg_msg pointing to the connection to disconnect | |
796 | */ | |
797 | void | |
798 | do_disconnect(struct api_msg_msg *msg) | |
799 | { | |
800 | #if LWIP_UDP | |
801 | if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { | |
802 | udp_disconnect(msg->conn->pcb.udp); | |
803 | } | |
804 | #endif /* LWIP_UDP */ | |
805 | TCPIP_APIMSG_ACK(msg); | |
806 | } | |
807 | ||
808 | /** | |
809 | * Set a TCP pcb contained in a netconn into listen mode | |
810 | * Called from netconn_listen. | |
811 | * | |
812 | * @param msg the api_msg_msg pointing to the connection | |
813 | */ | |
814 | void | |
815 | do_listen(struct api_msg_msg *msg) | |
816 | { | |
817 | #if LWIP_TCP | |
818 | if (!ERR_IS_FATAL(msg->conn->err)) { | |
819 | if (msg->conn->pcb.tcp != NULL) { | |
820 | if (msg->conn->type == NETCONN_TCP) { | |
821 | if (msg->conn->pcb.tcp->state == CLOSED) { | |
822 | #if TCP_LISTEN_BACKLOG | |
823 | struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); | |
824 | #else /* TCP_LISTEN_BACKLOG */ | |
825 | struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp); | |
826 | #endif /* TCP_LISTEN_BACKLOG */ | |
827 | if (lpcb == NULL) { | |
828 | msg->conn->err = ERR_MEM; | |
829 | } else { | |
830 | /* delete the recvmbox and allocate the acceptmbox */ | |
831 | if (msg->conn->recvmbox != SYS_MBOX_NULL) { | |
832 | /** @todo: should we drain the recvmbox here? */ | |
833 | sys_mbox_free(msg->conn->recvmbox); | |
834 | msg->conn->recvmbox = SYS_MBOX_NULL; | |
835 | } | |
836 | if (msg->conn->acceptmbox == SYS_MBOX_NULL) { | |
837 | if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) { | |
838 | msg->conn->err = ERR_MEM; | |
839 | } | |
840 | } | |
841 | if (msg->conn->err == ERR_OK) { | |
842 | msg->conn->state = NETCONN_LISTEN; | |
843 | msg->conn->pcb.tcp = lpcb; | |
844 | tcp_arg(msg->conn->pcb.tcp, msg->conn); | |
845 | tcp_accept(msg->conn->pcb.tcp, accept_function); | |
846 | } | |
847 | } | |
848 | } else { | |
849 | msg->conn->err = ERR_CONN; | |
850 | } | |
851 | } | |
852 | } | |
853 | } | |
854 | #endif /* LWIP_TCP */ | |
855 | TCPIP_APIMSG_ACK(msg); | |
856 | } | |
857 | ||
858 | /** | |
859 | * Send some data on a RAW or UDP pcb contained in a netconn | |
860 | * Called from netconn_send | |
861 | * | |
862 | * @param msg the api_msg_msg pointing to the connection | |
863 | */ | |
864 | void | |
865 | do_send(struct api_msg_msg *msg) | |
866 | { | |
867 | if (!ERR_IS_FATAL(msg->conn->err)) { | |
868 | if (msg->conn->pcb.tcp != NULL) { | |
869 | switch (NETCONNTYPE_GROUP(msg->conn->type)) { | |
870 | #if LWIP_RAW | |
871 | case NETCONN_RAW: | |
872 | if (msg->msg.b->addr == NULL) { | |
873 | msg->conn->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); | |
874 | } else { | |
875 | msg->conn->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr); | |
876 | } | |
877 | break; | |
878 | #endif | |
879 | #if LWIP_UDP | |
880 | case NETCONN_UDP: | |
881 | if (msg->msg.b->addr == NULL) { | |
882 | msg->conn->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); | |
883 | } else { | |
884 | msg->conn->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port); | |
885 | } | |
886 | break; | |
887 | #endif /* LWIP_UDP */ | |
888 | default: | |
889 | break; | |
890 | } | |
891 | } | |
892 | } | |
893 | TCPIP_APIMSG_ACK(msg); | |
894 | } | |
895 | ||
896 | /** | |
897 | * Recv some data from a RAW or UDP pcb contained in a netconn | |
898 | * Called from netconn_recv | |
899 | * | |
900 | * @param msg the api_msg_msg pointing to the connection | |
901 | */ | |
902 | void | |
903 | do_recv(struct api_msg_msg *msg) | |
904 | { | |
905 | #if LWIP_TCP | |
906 | if (!ERR_IS_FATAL(msg->conn->err)) { | |
907 | if (msg->conn->pcb.tcp != NULL) { | |
908 | if (msg->conn->type == NETCONN_TCP) { | |
909 | #if TCP_LISTEN_BACKLOG | |
910 | if (msg->conn->pcb.tcp->state == LISTEN) { | |
911 | tcp_accepted(msg->conn->pcb.tcp); | |
912 | } else | |
913 | #endif /* TCP_LISTEN_BACKLOG */ | |
914 | { | |
915 | tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len); | |
916 | } | |
917 | } | |
918 | } | |
919 | } | |
920 | #endif /* LWIP_TCP */ | |
921 | TCPIP_APIMSG_ACK(msg); | |
922 | } | |
923 | ||
924 | #if LWIP_TCP | |
925 | /** | |
926 | * See if more data needs to be written from a previous call to netconn_write. | |
927 | * Called initially from do_write. If the first call can't send all data | |
928 | * (because of low memory or empty send-buffer), this function is called again | |
929 | * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the | |
930 | * blocking application thread (waiting in netconn_write) is released. | |
931 | * | |
932 | * @param conn netconn (that is currently in state NETCONN_WRITE) to process | |
933 | * @return ERR_OK | |
934 | * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished | |
935 | */ | |
936 | static err_t | |
937 | do_writemore(struct netconn *conn) | |
938 | { | |
939 | err_t err; | |
940 | void *dataptr; | |
941 | u16_t len, available; | |
942 | u8_t write_finished = 0; | |
943 | ||
944 | LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); | |
945 | ||
946 | dataptr = (u8_t*)conn->write_msg->msg.w.dataptr + conn->write_offset; | |
947 | if ((conn->write_msg->msg.w.len - conn->write_offset > 0xffff)) { /* max_u16_t */ | |
948 | len = 0xffff; | |
949 | #if LWIP_TCPIP_CORE_LOCKING | |
950 | conn->write_delayed = 1; | |
951 | #endif | |
952 | } else { | |
953 | len = conn->write_msg->msg.w.len - conn->write_offset; | |
954 | } | |
955 | available = tcp_sndbuf(conn->pcb.tcp); | |
956 | if (available < len) { | |
957 | /* don't try to write more than sendbuf */ | |
958 | len = available; | |
959 | #if LWIP_TCPIP_CORE_LOCKING | |
960 | conn->write_delayed = 1; | |
961 | #endif | |
962 | } | |
963 | ||
964 | err = tcp_write(conn->pcb.tcp, dataptr, len, conn->write_msg->msg.w.apiflags); | |
965 | LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->write_msg->msg.w.len)); | |
966 | if (err == ERR_OK) { | |
967 | conn->write_offset += len; | |
968 | if (conn->write_offset == conn->write_msg->msg.w.len) { | |
969 | /* everything was written */ | |
970 | write_finished = 1; | |
971 | conn->write_msg = NULL; | |
972 | conn->write_offset = 0; | |
973 | } | |
974 | err = tcp_output_nagle(conn->pcb.tcp); | |
975 | conn->err = err; | |
976 | if ((err == ERR_OK) && (tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT)) { | |
977 | API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); | |
978 | } | |
979 | } else if (err == ERR_MEM) { | |
980 | /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called | |
981 | we do NOT return to the application thread, since ERR_MEM is | |
982 | only a temporary error! */ | |
983 | ||
984 | /* tcp_enqueue returned ERR_MEM, try tcp_output anyway */ | |
985 | err = tcp_output(conn->pcb.tcp); | |
986 | ||
987 | #if LWIP_TCPIP_CORE_LOCKING | |
988 | conn->write_delayed = 1; | |
989 | #endif | |
990 | } else { | |
991 | /* On errors != ERR_MEM, we don't try writing any more but return | |
992 | the error to the application thread. */ | |
993 | conn->err = err; | |
994 | write_finished = 1; | |
995 | } | |
996 | ||
997 | if (write_finished) { | |
998 | /* everything was written: set back connection state | |
999 | and back to application task */ | |
1000 | conn->state = NETCONN_NONE; | |
1001 | #if LWIP_TCPIP_CORE_LOCKING | |
1002 | if (conn->write_delayed != 0) | |
1003 | #endif | |
1004 | { | |
1005 | sys_sem_signal(conn->op_completed); | |
1006 | } | |
1007 | } | |
1008 | #if LWIP_TCPIP_CORE_LOCKING | |
1009 | else | |
1010 | return ERR_MEM; | |
1011 | #endif | |
1012 | return ERR_OK; | |
1013 | } | |
1014 | #endif /* LWIP_TCP */ | |
1015 | ||
1016 | /** | |
1017 | * Send some data on a TCP pcb contained in a netconn | |
1018 | * Called from netconn_write | |
1019 | * | |
1020 | * @param msg the api_msg_msg pointing to the connection | |
1021 | */ | |
1022 | void | |
1023 | do_write(struct api_msg_msg *msg) | |
1024 | { | |
1025 | if (!ERR_IS_FATAL(msg->conn->err)) { | |
1026 | if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { | |
1027 | #if LWIP_TCP | |
1028 | msg->conn->state = NETCONN_WRITE; | |
1029 | /* set all the variables used by do_writemore */ | |
1030 | msg->conn->write_msg = msg; | |
1031 | msg->conn->write_offset = 0; | |
1032 | #if LWIP_TCPIP_CORE_LOCKING | |
1033 | msg->conn->write_delayed = 0; | |
1034 | if (do_writemore(msg->conn) != ERR_OK) { | |
1035 | LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); | |
1036 | UNLOCK_TCPIP_CORE(); | |
1037 | sys_arch_sem_wait(msg->conn->op_completed, 0); | |
1038 | LOCK_TCPIP_CORE(); | |
1039 | LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); | |
1040 | } | |
1041 | #else | |
1042 | do_writemore(msg->conn); | |
1043 | #endif | |
1044 | /* for both cases: if do_writemore was called, don't ACK the APIMSG! */ | |
1045 | return; | |
1046 | #endif /* LWIP_TCP */ | |
1047 | #if (LWIP_UDP || LWIP_RAW) | |
1048 | } else { | |
1049 | msg->conn->err = ERR_VAL; | |
1050 | #endif /* (LWIP_UDP || LWIP_RAW) */ | |
1051 | } | |
1052 | } | |
1053 | TCPIP_APIMSG_ACK(msg); | |
1054 | } | |
1055 | ||
1056 | /** | |
1057 | * Return a connection's local or remote address | |
1058 | * Called from netconn_getaddr | |
1059 | * | |
1060 | * @param msg the api_msg_msg pointing to the connection | |
1061 | */ | |
1062 | void | |
1063 | do_getaddr(struct api_msg_msg *msg) | |
1064 | { | |
1065 | if (msg->conn->pcb.ip != NULL) { | |
1066 | *(msg->msg.ad.ipaddr) = (msg->msg.ad.local?msg->conn->pcb.ip->local_ip:msg->conn->pcb.ip->remote_ip); | |
1067 | ||
1068 | switch (NETCONNTYPE_GROUP(msg->conn->type)) { | |
1069 | #if LWIP_RAW | |
1070 | case NETCONN_RAW: | |
1071 | if (msg->msg.ad.local) { | |
1072 | *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; | |
1073 | } else { | |
1074 | /* return an error as connecting is only a helper for upper layers */ | |
1075 | msg->conn->err = ERR_CONN; | |
1076 | } | |
1077 | break; | |
1078 | #endif /* LWIP_RAW */ | |
1079 | #if LWIP_UDP | |
1080 | case NETCONN_UDP: | |
1081 | if (msg->msg.ad.local) { | |
1082 | *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; | |
1083 | } else { | |
1084 | if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { | |
1085 | msg->conn->err = ERR_CONN; | |
1086 | } else { | |
1087 | *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; | |
1088 | } | |
1089 | } | |
1090 | break; | |
1091 | #endif /* LWIP_UDP */ | |
1092 | #if LWIP_TCP | |
1093 | case NETCONN_TCP: | |
1094 | *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port); | |
1095 | break; | |
1096 | #endif /* LWIP_TCP */ | |
1097 | } | |
1098 | } else { | |
1099 | msg->conn->err = ERR_CONN; | |
1100 | } | |
1101 | TCPIP_APIMSG_ACK(msg); | |
1102 | } | |
1103 | ||
1104 | /** | |
1105 | * Close a TCP pcb contained in a netconn | |
1106 | * Called from netconn_close | |
1107 | * | |
1108 | * @param msg the api_msg_msg pointing to the connection | |
1109 | */ | |
1110 | void | |
1111 | do_close(struct api_msg_msg *msg) | |
1112 | { | |
1113 | #if LWIP_TCP | |
1114 | if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { | |
1115 | msg->conn->state = NETCONN_CLOSE; | |
1116 | do_close_internal(msg->conn); | |
1117 | /* for tcp netconns, do_close_internal ACKs the message */ | |
1118 | } else | |
1119 | #endif /* LWIP_TCP */ | |
1120 | { | |
1121 | msg->conn->err = ERR_VAL; | |
1122 | TCPIP_APIMSG_ACK(msg); | |
1123 | } | |
1124 | } | |
1125 | ||
1126 | #if LWIP_IGMP | |
1127 | /** | |
1128 | * Join multicast groups for UDP netconns. | |
1129 | * Called from netconn_join_leave_group | |
1130 | * | |
1131 | * @param msg the api_msg_msg pointing to the connection | |
1132 | */ | |
1133 | void | |
1134 | do_join_leave_group(struct api_msg_msg *msg) | |
1135 | { | |
1136 | if (!ERR_IS_FATAL(msg->conn->err)) { | |
1137 | if (msg->conn->pcb.tcp != NULL) { | |
1138 | if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { | |
1139 | #if LWIP_UDP | |
1140 | if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { | |
1141 | msg->conn->err = igmp_joingroup(msg->msg.jl.interface, msg->msg.jl.multiaddr); | |
1142 | } else { | |
1143 | msg->conn->err = igmp_leavegroup(msg->msg.jl.interface, msg->msg.jl.multiaddr); | |
1144 | } | |
1145 | #endif /* LWIP_UDP */ | |
1146 | #if (LWIP_TCP || LWIP_RAW) | |
1147 | } else { | |
1148 | msg->conn->err = ERR_VAL; | |
1149 | #endif /* (LWIP_TCP || LWIP_RAW) */ | |
1150 | } | |
1151 | } | |
1152 | } | |
1153 | TCPIP_APIMSG_ACK(msg); | |
1154 | } | |
1155 | #endif /* LWIP_IGMP */ | |
1156 | ||
1157 | #if LWIP_DNS | |
1158 | /** | |
1159 | * Callback function that is called when DNS name is resolved | |
1160 | * (or on timeout). A waiting application thread is waked up by | |
1161 | * signaling the semaphore. | |
1162 | */ | |
1163 | static void | |
1164 | do_dns_found(const char *name, struct ip_addr *ipaddr, void *arg) | |
1165 | { | |
1166 | struct dns_api_msg *msg = (struct dns_api_msg*)arg; | |
1167 | ||
1168 | LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0); | |
1169 | ||
1170 | if (ipaddr == NULL) { | |
1171 | /* timeout or memory error */ | |
1172 | *msg->err = ERR_VAL; | |
1173 | } else { | |
1174 | /* address was resolved */ | |
1175 | *msg->err = ERR_OK; | |
1176 | *msg->addr = *ipaddr; | |
1177 | } | |
1178 | /* wake up the application task waiting in netconn_gethostbyname */ | |
1179 | sys_sem_signal(msg->sem); | |
1180 | } | |
1181 | ||
1182 | /** | |
1183 | * Execute a DNS query | |
1184 | * Called from netconn_gethostbyname | |
1185 | * | |
1186 | * @param arg the dns_api_msg pointing to the query | |
1187 | */ | |
1188 | void | |
1189 | do_gethostbyname(void *arg) | |
1190 | { | |
1191 | struct dns_api_msg *msg = (struct dns_api_msg*)arg; | |
1192 | ||
1193 | *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg); | |
1194 | if (*msg->err != ERR_INPROGRESS) { | |
1195 | /* on error or immediate success, wake up the application | |
1196 | * task waiting in netconn_gethostbyname */ | |
1197 | sys_sem_signal(msg->sem); | |
1198 | } | |
1199 | } | |
1200 | #endif /* LWIP_DNS */ | |
1201 | ||
1202 | #endif /* LWIP_NETCONN */ |