/[lwip]/lwip/src/api/api_lib.c
ViewVC logotype

Contents of /lwip/src/api/api_lib.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.48 - (show annotations) (download)
Wed May 23 19:18:09 2007 UTC (16 years, 6 months ago) by fbernon
Branch: MAIN
Changes since 1.47: +15 -3 lines
File MIME type: text/plain
api_lib.c: Implement SO_RCVTIMEO for accept and recv on TCP connections, such present in patch #5959.

1 /*
2 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25 * OF SUCH DAMAGE.
26 *
27 * This file is part of the lwIP TCP/IP stack.
28 *
29 * Author: Adam Dunkels <adam@sics.se>
30 *
31 */
32
33 /* This is the part of the API that is linked with
34 the application */
35
36 #include <string.h>
37 #include "lwip/opt.h"
38 #include "lwip/api.h"
39 #include "lwip/api_msg.h"
40 #include "lwip/tcpip.h"
41 #include "lwip/memp.h"
42
43 #if !NO_SYS
44
45 struct
46 netbuf *netbuf_new(void)
47 {
48 struct netbuf *buf;
49
50 buf = memp_malloc(MEMP_NETBUF);
51 if (buf != NULL) {
52 buf->p = NULL;
53 buf->ptr = NULL;
54 buf->addr = NULL;
55 return buf;
56 } else {
57 return NULL;
58 }
59 }
60
61 void
62 netbuf_delete(struct netbuf *buf)
63 {
64 if (buf != NULL) {
65 if (buf->p != NULL) {
66 pbuf_free(buf->p);
67 buf->p = buf->ptr = NULL;
68 }
69 memp_free(MEMP_NETBUF, buf);
70 }
71 }
72
73 void *
74 netbuf_alloc(struct netbuf *buf, u16_t size)
75 {
76 /* Deallocate any previously allocated memory. */
77 if (buf->p != NULL) {
78 pbuf_free(buf->p);
79 }
80 buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
81 if (buf->p == NULL) {
82 return NULL;
83 }
84 buf->ptr = buf->p;
85 return buf->p->payload;
86 }
87
88 void
89 netbuf_free(struct netbuf *buf)
90 {
91 if (buf->p != NULL) {
92 pbuf_free(buf->p);
93 }
94 buf->p = buf->ptr = NULL;
95 }
96
97 err_t
98 netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
99 {
100 if (buf->p != NULL) {
101 pbuf_free(buf->p);
102 }
103 buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
104 if (buf->p == NULL) {
105 buf->ptr = NULL;
106 return ERR_MEM;
107 }
108 buf->p->payload = (void*)dataptr;
109 buf->p->len = buf->p->tot_len = size;
110 buf->ptr = buf->p;
111 return ERR_OK;
112 }
113
114 void
115 netbuf_chain(struct netbuf *head, struct netbuf *tail)
116 {
117 pbuf_chain(head->p, tail->p);
118 head->ptr = head->p;
119 memp_free(MEMP_NETBUF, tail);
120 }
121
122 err_t
123 netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
124 {
125 if (buf->ptr == NULL) {
126 return ERR_BUF;
127 }
128 *dataptr = buf->ptr->payload;
129 *len = buf->ptr->len;
130 return ERR_OK;
131 }
132
133 s8_t
134 netbuf_next(struct netbuf *buf)
135 {
136 if (buf->ptr->next == NULL) {
137 return -1;
138 }
139 buf->ptr = buf->ptr->next;
140 if (buf->ptr->next == NULL) {
141 return 1;
142 }
143 return 0;
144 }
145
146 void
147 netbuf_first(struct netbuf *buf)
148 {
149 buf->ptr = buf->p;
150 }
151
152 void
153 netbuf_copy_partial(struct netbuf *buf, void *dataptr, u16_t len, u16_t offset)
154 {
155 struct pbuf *p;
156 u16_t left;
157 u16_t buf_copy_len;
158
159 left = 0;
160
161 if(buf == NULL || dataptr == NULL) {
162 return;
163 }
164
165 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
166 for(p = buf->p; len != 0 && p != NULL; p = p->next) {
167 if (offset != 0 && offset >= p->len) {
168 /* don't copy from this buffer -> on to the next */
169 offset -= p->len;
170 } else {
171 /* copy from this buffer. maybe only partially. */
172 buf_copy_len = p->len - offset;
173 if (buf_copy_len > len)
174 buf_copy_len = len;
175 /* copy the necessary parts of the buffer */
176 MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
177 left += buf_copy_len;
178 len -= buf_copy_len;
179 offset = 0;
180 }
181 }
182 }
183
184 struct
185 netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,
186 void (*callback)(struct netconn *, enum netconn_evt, u16_t len))
187 {
188 struct netconn *conn;
189 struct api_msg msg;
190
191 conn = memp_malloc(MEMP_NETCONN);
192 if (conn == NULL) {
193 return NULL;
194 }
195
196 conn->err = ERR_OK;
197 conn->type = t;
198 conn->pcb.tcp = NULL;
199
200 if ((conn->mbox = sys_mbox_new()) == SYS_MBOX_NULL) {
201 memp_free(MEMP_NETCONN, conn);
202 return NULL;
203 }
204 conn->recvmbox = SYS_MBOX_NULL;
205 conn->acceptmbox = SYS_MBOX_NULL;
206 conn->sem = sys_sem_new(0);
207 if (conn->sem == SYS_SEM_NULL) {
208 sys_mbox_free(conn->mbox);
209 memp_free(MEMP_NETCONN, conn);
210 return NULL;
211 }
212 conn->state = NETCONN_NONE;
213 conn->socket = 0;
214 conn->callback = callback;
215 conn->recv_avail = 0;
216 #if LWIP_SO_RCVTIMEO
217 conn->recv_timeout = 0;
218 #endif /* LWIP_SO_RCVTIMEO */
219
220 msg.function = do_newconn;
221 msg.msg.msg.n.proto = proto;
222 msg.msg.conn = conn;
223 tcpip_apimsg(&msg);
224
225 if ( conn->err != ERR_OK ) {
226 sys_sem_free(conn->sem);
227 sys_mbox_free(conn->mbox);
228 memp_free(MEMP_NETCONN, conn);
229 return NULL;
230 }
231
232 return conn;
233 }
234
235 struct
236 netconn *netconn_new(enum netconn_type t)
237 {
238 return netconn_new_with_proto_and_callback(t,0,NULL);
239 }
240
241 struct
242 netconn *netconn_new_with_callback(enum netconn_type t,
243 void (*callback)(struct netconn *, enum netconn_evt, u16_t len))
244 {
245 return netconn_new_with_proto_and_callback(t,0,callback);
246 }
247
248 err_t
249 netconn_delete(struct netconn *conn)
250 {
251 struct api_msg msg;
252 void *mem;
253
254 /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
255 if (conn == NULL) {
256 return ERR_OK;
257 }
258
259 msg.function = do_delconn;
260 msg.msg.conn = conn;
261 tcpip_apimsg(&msg);
262
263 /* Drain the recvmbox. */
264 if (conn->recvmbox != SYS_MBOX_NULL) {
265 while (sys_mbox_tryfetch(conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
266 if (conn->type == NETCONN_TCP) {
267 if(mem != NULL)
268 pbuf_free((struct pbuf *)mem);
269 } else {
270 netbuf_delete((struct netbuf *)mem);
271 }
272 }
273 sys_mbox_free(conn->recvmbox);
274 conn->recvmbox = SYS_MBOX_NULL;
275 }
276
277 /* Drain the acceptmbox. */
278 if (conn->acceptmbox != SYS_MBOX_NULL) {
279 while (sys_mbox_tryfetch(conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
280 netconn_delete((struct netconn *)mem);
281 }
282 sys_mbox_free(conn->acceptmbox);
283 conn->acceptmbox = SYS_MBOX_NULL;
284 }
285
286 sys_mbox_free(conn->mbox);
287 conn->mbox = SYS_MBOX_NULL;
288
289 if (conn->sem != SYS_SEM_NULL) {
290 sys_sem_free(conn->sem);
291 /* conn->sem = SYS_SEM_NULL; */
292 }
293
294 memp_free(MEMP_NETCONN, conn);
295 return ERR_OK;
296 }
297
298 enum netconn_type
299 netconn_type(struct netconn *conn)
300 {
301 return conn->type;
302 }
303
304 err_t
305 netconn_peer(struct netconn *conn, struct ip_addr *addr, u16_t *port)
306 {
307 switch (NETCONNTYPE_GROUP(conn->type)) {
308 case NETCONN_RAW:
309 /* return an error as connecting is only a helper for upper layers */
310 return ERR_CONN;
311 case NETCONN_UDP:
312 if (conn->pcb.udp == NULL ||
313 ((conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0))
314 return ERR_CONN;
315 *addr = (conn->pcb.udp->remote_ip);
316 *port = conn->pcb.udp->remote_port;
317 break;
318 case NETCONN_TCP:
319 if (conn->pcb.tcp == NULL)
320 return ERR_CONN;
321 *addr = (conn->pcb.tcp->remote_ip);
322 *port = conn->pcb.tcp->remote_port;
323 break;
324 }
325 return (conn->err = ERR_OK);
326 }
327
328 err_t
329 netconn_addr(struct netconn *conn, struct ip_addr **addr, u16_t *port)
330 {
331 switch (NETCONNTYPE_GROUP(conn->type)) {
332 case NETCONN_RAW:
333 *addr = &(conn->pcb.raw->local_ip);
334 *port = conn->pcb.raw->protocol;
335 break;
336 case NETCONN_UDP:
337 *addr = &(conn->pcb.udp->local_ip);
338 *port = conn->pcb.udp->local_port;
339 break;
340 case NETCONN_TCP:
341 *addr = &(conn->pcb.tcp->local_ip);
342 *port = conn->pcb.tcp->local_port;
343 break;
344 }
345 return (conn->err = ERR_OK);
346 }
347
348 err_t
349 netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port)
350 {
351 struct api_msg msg;
352
353 LWIP_ASSERT("netconn_bind: invalid conn", (conn != NULL));
354
355 if (conn->type != NETCONN_TCP && conn->recvmbox == SYS_MBOX_NULL) {
356 if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {
357 return ERR_MEM;
358 }
359 }
360
361 msg.function = do_bind;
362 msg.msg.conn = conn;
363 msg.msg.msg.bc.ipaddr = addr;
364 msg.msg.msg.bc.port = port;
365 tcpip_apimsg(&msg);
366 return conn->err;
367 }
368
369
370 err_t
371 netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port)
372 {
373 struct api_msg msg;
374
375 LWIP_ASSERT("netconn_connect: invalid conn", (conn != NULL));
376
377 if (conn->recvmbox == SYS_MBOX_NULL) {
378 if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {
379 return ERR_MEM;
380 }
381 }
382
383 msg.function = do_connect;
384 msg.msg.conn = conn;
385 msg.msg.msg.bc.ipaddr = addr;
386 msg.msg.msg.bc.port = port;
387 tcpip_apimsg(&msg);
388 return conn->err;
389 }
390
391 err_t
392 netconn_disconnect(struct netconn *conn)
393 {
394 struct api_msg msg;
395
396 LWIP_ASSERT("netconn_disconnect: invalid conn", (conn != NULL));
397
398 msg.function = do_disconnect;
399 msg.msg.conn = conn;
400 tcpip_apimsg(&msg);
401 return conn->err;
402
403 }
404
405 err_t
406 netconn_listen(struct netconn *conn)
407 {
408 struct api_msg msg;
409
410 LWIP_ASSERT("netconn_listen: invalid conn", (conn != NULL));
411
412 msg.function = do_listen;
413 msg.msg.conn = conn;
414 tcpip_apimsg(&msg);
415 return conn->err;
416 }
417
418 struct netconn *
419 netconn_accept(struct netconn *conn)
420 {
421 struct netconn *newconn;
422
423 LWIP_ASSERT("netconn_accept: invalid conn", (conn != NULL));
424 LWIP_ASSERT("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL));
425
426 #if LWIP_SO_RCVTIMEO
427 if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
428 newconn = NULL;
429 }
430 #else
431 sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0);
432 #endif /* LWIP_SO_RCVTIMEO*/
433
434 /* Register event with callback */
435 if (conn->callback)
436 (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, 0);
437
438 return newconn;
439 }
440
441 struct netbuf *
442 netconn_recv(struct netconn *conn)
443 {
444 struct api_msg msg;
445 struct netbuf *buf = NULL;
446 struct pbuf *p;
447 u16_t len;
448
449 LWIP_ASSERT("netconn_recv: invalid conn", (conn != NULL));
450
451 if (conn->recvmbox == SYS_MBOX_NULL) {
452 if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {
453 conn->err = ERR_CONN;
454 return NULL;
455 }
456 }
457
458 if (conn->err != ERR_OK) {
459 return NULL;
460 }
461
462 if (conn->type == NETCONN_TCP) {
463 #if LWIP_TCP
464 if (conn->pcb.tcp->state == LISTEN) {
465 conn->err = ERR_CONN;
466 return NULL;
467 }
468
469 buf = memp_malloc(MEMP_NETBUF);
470
471 if (buf == NULL) {
472 conn->err = ERR_MEM;
473 return NULL;
474 }
475
476 #if LWIP_SO_RCVTIMEO
477 if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
478 p = NULL;
479 }
480 #else
481 sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0);
482 #endif /* LWIP_SO_RCVTIMEO*/
483
484 if (p != NULL) {
485 len = p->tot_len;
486 conn->recv_avail -= len;
487 } else {
488 len = 0;
489 }
490
491 /* Register event with callback */
492 if (conn->callback)
493 (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, len);
494
495 /* If we are closed, we indicate that we no longer wish to use the socket */
496 if (p == NULL) {
497 memp_free(MEMP_NETBUF, buf);
498 conn->err = ERR_CLSD;
499 return NULL;
500 }
501
502 buf->p = p;
503 buf->ptr = p;
504 buf->port = 0;
505 buf->addr = NULL;
506
507 /* Let the stack know that we have taken the data. */
508 msg.function = do_recv;
509 msg.msg.conn = conn;
510 if (buf != NULL) {
511 msg.msg.msg.r.len = buf->p->tot_len;
512 } else {
513 msg.msg.msg.r.len = 1;
514 }
515 tcpip_apimsg(&msg);
516 #endif /* LWIP_TCP */
517 } else {
518 #if (LWIP_UDP || LWIP_RAW)
519 #if LWIP_SO_RCVTIMEO
520 if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
521 buf = NULL;
522 }
523 #else
524 sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, 0);
525 #endif /* LWIP_SO_RCVTIMEO*/
526 if (buf!=NULL) {
527 conn->recv_avail -= buf->p->tot_len;
528 /* Register event with callback */
529 if (conn->callback)
530 (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);
531 }
532 #endif /* (LWIP_UDP || LWIP_RAW) */
533 }
534
535 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));
536
537 return buf;
538 }
539
540 err_t
541 netconn_sendto(struct netconn *conn, struct netbuf *buf, struct ip_addr *addr, u16_t port)
542 { if (buf!=NULL) {
543 buf->addr = addr;
544 buf->port = port;
545 return netconn_send( conn, buf);
546 }
547 return ERR_VAL;
548 }
549
550 err_t
551 netconn_send(struct netconn *conn, struct netbuf *buf)
552 {
553 struct api_msg msg;
554
555 LWIP_ASSERT("netconn_send: invalid conn", (conn != NULL));
556
557 if (conn->err != ERR_OK) {
558 return conn->err;
559 }
560
561 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len));
562 msg.function = do_send;
563 msg.msg.conn = conn;
564 msg.msg.msg.b = buf;
565 tcpip_apimsg(&msg);
566 return conn->err;
567 }
568
569 err_t
570 netconn_write(struct netconn *conn, const void *dataptr, u16_t size, u8_t copy)
571 {
572 struct api_msg msg;
573 u16_t len, sndbuf;
574
575 LWIP_ASSERT("netconn_write: invalid conn", (conn != NULL));
576
577 if (conn->err != ERR_OK) {
578 return conn->err;
579 }
580
581 msg.function = do_write;
582 msg.msg.conn = conn;
583
584 conn->state = NETCONN_WRITE;
585 while (conn->err == ERR_OK && size > 0) {
586 msg.msg.msg.w.dataptr = dataptr;
587 msg.msg.msg.w.copy = copy;
588
589 if (conn->type == NETCONN_TCP) {
590 while ((sndbuf = tcp_sndbuf(conn->pcb.tcp)) == 0) {
591 sys_sem_wait(conn->sem);
592 if (conn->err != ERR_OK) {
593 goto ret;
594 }
595 }
596 if (size > sndbuf) {
597 /* We cannot send more than one send buffer's worth of data at a time. */
598 len = sndbuf;
599 } else {
600 len = size;
601 }
602 } else {
603 len = size;
604 }
605
606 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_write: writing %d bytes (%d)\n", len, copy));
607 msg.msg.msg.w.len = len;
608 tcpip_apimsg(&msg);
609 if (conn->err == ERR_OK) {
610 dataptr = (void *)((u8_t *)dataptr + len);
611 size -= len;
612 } else if (conn->err == ERR_MEM) {
613 conn->err = ERR_OK;
614 sys_sem_wait(conn->sem);
615 } else {
616 goto ret;
617 }
618 }
619 ret:
620 conn->state = NETCONN_NONE;
621
622 return conn->err;
623 }
624
625 err_t
626 netconn_close(struct netconn *conn)
627 {
628 struct api_msg msg;
629
630 LWIP_ASSERT("netconn_close: invalid conn", (conn != NULL));
631
632 conn->state = NETCONN_CLOSE;
633 again:
634 msg.function = do_close;
635 msg.msg.conn = conn;
636 tcpip_apimsg(&msg);
637 if (conn->err == ERR_MEM && conn->sem != SYS_SEM_NULL) {
638 sys_sem_wait(conn->sem);
639 goto again;
640 }
641 conn->state = NETCONN_NONE;
642 return conn->err;
643 }
644
645 #if LWIP_IGMP
646 err_t
647 netconn_join_leave_group (struct netconn *conn,
648 struct ip_addr *multiaddr,
649 struct ip_addr *interface,
650 enum netconn_igmp join_or_leave)
651 {
652 struct api_msg msg;
653
654 LWIP_ASSERT("netconn_join_leave_group: invalid conn", (conn != NULL));
655
656 if (conn->err != ERR_OK) {
657 return conn->err;
658 }
659
660 msg.function = do_join_leave_group;
661 msg.msg.conn = conn;
662 msg.msg.msg.jl.multiaddr = multiaddr;
663 msg.msg.msg.jl.interface = interface;
664 msg.msg.msg.jl.join_or_leave = join_or_leave;
665 tcpip_apimsg(&msg);
666 return conn->err;
667 }
668 #endif /* LWIP_IGMP */
669
670 err_t
671 netconn_err(struct netconn *conn)
672 {
673 return conn->err;
674 }
675
676 #endif /* !NO_SYS */

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26