Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / lwip / api / api_lib.c
1 /**
2  * @file
3  * Sequential API External 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 /* This is the part of the API that is linked with
40    the application */
41
42 #include "lwip/opt.h"
43
44 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
45
46 #include "lwip/api.h"
47 #include "lwip/tcpip.h"
48 #include "lwip/memp.h"
49
50 #include "lwip/ip.h"
51 #include "lwip/raw.h"
52 #include "lwip/udp.h"
53 #include "lwip/tcp.h"
54
55 #include <string.h>
56
57 /**
58  * Create a new netconn (of a specific type) that has a callback function.
59  * The corresponding pcb is also created.
60  *
61  * @param t the type of 'connection' to create (@see enum netconn_type)
62  * @param proto the IP protocol for RAW IP pcbs
63  * @param callback a function to call on status changes (RX available, TX'ed)
64  * @return a newly allocated struct netconn or
65  *         NULL on memory error
66  */
67 struct netconn*
68 netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
69 {
70   struct netconn *conn;
71   struct api_msg msg;
72
73   conn = netconn_alloc(t, callback);
74   if (conn != NULL ) {
75     msg.function = do_newconn;
76     msg.msg.msg.n.proto = proto;
77     msg.msg.conn = conn;
78     TCPIP_APIMSG(&msg);
79
80     if (conn->err != ERR_OK) {
81       LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
82       LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL);
83       LWIP_ASSERT("conn has no recvmbox", conn->recvmbox != SYS_MBOX_NULL);
84       LWIP_ASSERT("conn->acceptmbox shouldn't exist", conn->acceptmbox == SYS_MBOX_NULL);
85       sys_sem_free(conn->op_completed);
86       sys_mbox_free(conn->recvmbox);
87       memp_free(MEMP_NETCONN, conn);
88       return NULL;
89     }
90   }
91   return conn;
92 }
93
94 /**
95  * Close a netconn 'connection' and free its resources.
96  * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
97  * after this returns.
98  *
99  * @param conn the netconn to delete
100  * @return ERR_OK if the connection was deleted
101  */
102 err_t
103 netconn_delete(struct netconn *conn)
104 {
105   struct api_msg msg;
106
107   /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
108   if (conn == NULL) {
109     return ERR_OK;
110   }
111
112   msg.function = do_delconn;
113   msg.msg.conn = conn;
114   tcpip_apimsg(&msg);
115
116   conn->pcb.tcp = NULL;
117   netconn_free(conn);
118
119   return ERR_OK;
120 }
121
122 /**
123  * Get the type of a netconn (as enum netconn_type).
124  *
125  * @param conn the netconn of which to get the type
126  * @return the netconn_type of conn
127  */
128 enum netconn_type
129 netconn_type(struct netconn *conn)
130 {
131   LWIP_ERROR("netconn_type: invalid conn", (conn != NULL), return NETCONN_INVALID;);
132   return conn->type;
133 }
134
135 /**
136  * Get the local or remote IP address and port of a netconn.
137  * For RAW netconns, this returns the protocol instead of a port!
138  *
139  * @param conn the netconn to query
140  * @param addr a pointer to which to save the IP address
141  * @param port a pointer to which to save the port (or protocol for RAW)
142  * @param local 1 to get the local IP address, 0 to get the remote one
143  * @return ERR_CONN for invalid connections
144  *         ERR_OK if the information was retrieved
145  */
146 err_t
147 netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t local)
148 {
149   struct api_msg msg;
150
151   LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
152   LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
153   LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
154
155   msg.function = do_getaddr;
156   msg.msg.conn = conn;
157   msg.msg.msg.ad.ipaddr = addr;
158   msg.msg.msg.ad.port = port;
159   msg.msg.msg.ad.local = local;
160   TCPIP_APIMSG(&msg);
161
162   return conn->err;
163 }
164
165 /**
166  * Bind a netconn to a specific local IP address and port.
167  * Binding one netconn twice might not always be checked correctly!
168  *
169  * @param conn the netconn to bind
170  * @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY
171  *             to bind to all addresses)
172  * @param port the local port to bind the netconn to (not used for RAW)
173  * @return ERR_OK if bound, any other err_t on failure
174  */
175 err_t
176 netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port)
177 {
178   struct api_msg msg;
179
180   LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
181
182   msg.function = do_bind;
183   msg.msg.conn = conn;
184   msg.msg.msg.bc.ipaddr = addr;
185   msg.msg.msg.bc.port = port;
186   TCPIP_APIMSG(&msg);
187   return conn->err;
188 }
189
190 /**
191  * Connect a netconn to a specific remote IP address and port.
192  *
193  * @param conn the netconn to connect
194  * @param addr the remote IP address to connect to
195  * @param port the remote port to connect to (no used for RAW)
196  * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
197  */
198 err_t
199 netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port)
200 {
201   struct api_msg msg;
202
203   LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
204
205   msg.function = do_connect;
206   msg.msg.conn = conn;
207   msg.msg.msg.bc.ipaddr = addr;
208   msg.msg.msg.bc.port = port;
209   /* This is the only function which need to not block tcpip_thread */
210   tcpip_apimsg(&msg);
211   return conn->err;
212 }
213
214 /**
215  * Disconnect a netconn from its current peer (only valid for UDP netconns).
216  *
217  * @param conn the netconn to disconnect
218  * @return TODO: return value is not set here...
219  */
220 err_t
221 netconn_disconnect(struct netconn *conn)
222 {
223   struct api_msg msg;
224
225   LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
226
227   msg.function = do_disconnect;
228   msg.msg.conn = conn;
229   TCPIP_APIMSG(&msg);
230   return conn->err;
231 }
232
233 /**
234  * Set a TCP netconn into listen mode
235  *
236  * @param conn the tcp netconn to set to listen mode
237  * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
238  * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
239  *         don't return any error (yet?))
240  */
241 err_t
242 netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
243 {
244   struct api_msg msg;
245
246   /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
247   LWIP_UNUSED_ARG(backlog);
248
249   LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
250
251   msg.function = do_listen;
252   msg.msg.conn = conn;
253 #if TCP_LISTEN_BACKLOG
254   msg.msg.msg.lb.backlog = backlog;
255 #endif /* TCP_LISTEN_BACKLOG */
256   TCPIP_APIMSG(&msg);
257   return conn->err;
258 }
259
260 /**
261  * Accept a new connection on a TCP listening netconn.
262  *
263  * @param conn the TCP listen netconn
264  * @return the newly accepted netconn or NULL on timeout
265  */
266 struct netconn *
267 netconn_accept(struct netconn *conn)
268 {
269   struct netconn *newconn;
270
271   LWIP_ERROR("netconn_accept: invalid conn",       (conn != NULL),                      return NULL;);
272   LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return NULL;);
273
274 #if LWIP_SO_RCVTIMEO
275   if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
276     newconn = NULL;
277   } else
278 #else
279   sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0);
280 #endif /* LWIP_SO_RCVTIMEO*/
281   {
282     /* Register event with callback */
283     API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
284
285 #if TCP_LISTEN_BACKLOG
286     if (newconn != NULL) {
287       /* Let the stack know that we have accepted the connection. */
288       struct api_msg msg;
289       msg.function = do_recv;
290       msg.msg.conn = conn;
291       TCPIP_APIMSG(&msg);
292     }
293 #endif /* TCP_LISTEN_BACKLOG */
294   }
295
296   return newconn;
297 }
298
299 /**
300  * Receive data (in form of a netbuf containing a packet buffer) from a netconn
301  *
302  * @param conn the netconn from which to receive data
303  * @return a new netbuf containing received data or NULL on memory error or timeout
304  */
305 struct netbuf *
306 netconn_recv(struct netconn *conn)
307 {
308   struct api_msg msg;
309   struct netbuf *buf = NULL;
310   struct pbuf *p;
311   u16_t len;
312
313   LWIP_ERROR("netconn_recv: invalid conn",  (conn != NULL), return NULL;);
314
315   if (conn->recvmbox == SYS_MBOX_NULL) {
316     /* @todo: should calling netconn_recv on a TCP listen conn be fatal (ERR_CONN)?? */
317     /* TCP listen conns don't have a recvmbox! */
318     conn->err = ERR_CONN;
319     return NULL;
320   }
321
322   if (ERR_IS_FATAL(conn->err)) {
323     return NULL;
324   }
325
326   if (conn->type == NETCONN_TCP) {
327 #if LWIP_TCP
328     if (conn->state == NETCONN_LISTEN) {
329       /* @todo: should calling netconn_recv on a TCP listen conn be fatal?? */
330       conn->err = ERR_CONN;
331       return NULL;
332     }
333
334     buf = memp_malloc(MEMP_NETBUF);
335
336     if (buf == NULL) {
337       conn->err = ERR_MEM;
338       return NULL;
339     }
340
341 #if LWIP_SO_RCVTIMEO
342     if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
343       conn->err = ERR_TIMEOUT;
344       p = NULL;
345     }
346 #else
347     sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0);
348 #endif /* LWIP_SO_RCVTIMEO*/
349
350     if (p != NULL) {
351       len = p->tot_len;
352       SYS_ARCH_DEC(conn->recv_avail, len);
353     } else {
354       len = 0;
355     }
356
357     /* Register event with callback */
358     API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
359
360     /* If we are closed, we indicate that we no longer wish to use the socket */
361     if (p == NULL) {
362       memp_free(MEMP_NETBUF, buf);
363       /* Avoid to lose any previous error code */
364       if (conn->err == ERR_OK) {
365         conn->err = ERR_CLSD;
366       }
367       return NULL;
368     }
369
370     buf->p = p;
371     buf->ptr = p;
372     buf->port = 0;
373     buf->addr = NULL;
374
375     /* Let the stack know that we have taken the data. */
376     msg.function = do_recv;
377     msg.msg.conn = conn;
378     if (buf != NULL) {
379       msg.msg.msg.r.len = buf->p->tot_len;
380     } else {
381       msg.msg.msg.r.len = 1;
382     }
383     TCPIP_APIMSG(&msg);
384 #endif /* LWIP_TCP */
385   } else {
386 #if (LWIP_UDP || LWIP_RAW)
387 #if LWIP_SO_RCVTIMEO
388     if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
389       buf = NULL;
390     }
391 #else
392     sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, 0);
393 #endif /* LWIP_SO_RCVTIMEO*/
394     if (buf!=NULL) {
395       SYS_ARCH_DEC(conn->recv_avail, buf->p->tot_len);
396       /* Register event with callback */
397       API_EVENT(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);
398     }
399 #endif /* (LWIP_UDP || LWIP_RAW) */
400   }
401
402   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));
403
404   return buf;
405 }
406
407 /**
408  * Send data (in form of a netbuf) to a specific remote IP address and port.
409  * Only to be used for UDP and RAW netconns (not TCP).
410  *
411  * @param conn the netconn over which to send data
412  * @param buf a netbuf containing the data to send
413  * @param addr the remote IP address to which to send the data
414  * @param port the remote port to which to send the data
415  * @return ERR_OK if data was sent, any other err_t on error
416  */
417 err_t
418 netconn_sendto(struct netconn *conn, struct netbuf *buf, struct ip_addr *addr, u16_t port)
419 {
420   if (buf != NULL) {
421     buf->addr = addr;
422     buf->port = port;
423     return netconn_send(conn, buf);
424   }
425   return ERR_VAL;
426 }
427
428 /**
429  * Send data over a UDP or RAW netconn (that is already connected).
430  *
431  * @param conn the UDP or RAW netconn over which to send data
432  * @param buf a netbuf containing the data to send
433  * @return ERR_OK if data was sent, any other err_t on error
434  */
435 err_t
436 netconn_send(struct netconn *conn, struct netbuf *buf)
437 {
438   struct api_msg msg;
439
440   LWIP_ERROR("netconn_send: invalid conn",  (conn != NULL), return ERR_ARG;);
441
442   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len));
443   msg.function = do_send;
444   msg.msg.conn = conn;
445   msg.msg.msg.b = buf;
446   TCPIP_APIMSG(&msg);
447   return conn->err;
448 }
449
450 /**
451  * Send data over a TCP netconn.
452  *
453  * @param conn the TCP netconn over which to send data
454  * @param dataptr pointer to the application buffer that contains the data to send
455  * @param size size of the application data to send
456  * @param apiflags combination of following flags :
457  * - NETCONN_COPY (0x01) data will be copied into memory belonging to the stack
458  * - NETCONN_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent
459  * @return ERR_OK if data was sent, any other err_t on error
460  */
461 err_t
462 netconn_write(struct netconn *conn, const void *dataptr, int size, u8_t apiflags)
463 {
464   struct api_msg msg;
465
466   LWIP_ERROR("netconn_write: invalid conn",  (conn != NULL), return ERR_ARG;);
467   LWIP_ERROR("netconn_write: invalid conn->type",  (conn->type == NETCONN_TCP), return ERR_VAL;);
468
469   msg.function = do_write;
470   msg.msg.conn = conn;
471   msg.msg.msg.w.dataptr = dataptr;
472   msg.msg.msg.w.apiflags = apiflags;
473   msg.msg.msg.w.len = size;
474   /* For locking the core: this _can_ be delayed on low memory/low send buffer,
475      but if it is, this is done inside api_msg.c:do_write(), so we can use the
476      non-blocking version here. */
477   TCPIP_APIMSG(&msg);
478   return conn->err;
479 }
480
481 /**
482  * Close a TCP netconn (doesn't delete it).
483  *
484  * @param conn the TCP netconn to close
485  * @return ERR_OK if the netconn was closed, any other err_t on error
486  */
487 err_t
488 netconn_close(struct netconn *conn)
489 {
490   struct api_msg msg;
491
492   LWIP_ERROR("netconn_close: invalid conn",  (conn != NULL), return ERR_ARG;);
493
494   msg.function = do_close;
495   msg.msg.conn = conn;
496   tcpip_apimsg(&msg);
497   return conn->err;
498 }
499
500 #if LWIP_IGMP
501 /**
502  * Join multicast groups for UDP netconns.
503  *
504  * @param conn the UDP netconn for which to change multicast addresses
505  * @param multiaddr IP address of the multicast group to join or leave
506  * @param interface the IP address of the network interface on which to send
507  *                  the igmp message
508  * @param join_or_leave flag whether to send a join- or leave-message
509  * @return ERR_OK if the action was taken, any err_t on error
510  */
511 err_t
512 netconn_join_leave_group(struct netconn *conn,
513                          struct ip_addr *multiaddr,
514                          struct ip_addr *interface,
515                          enum netconn_igmp join_or_leave)
516 {
517   struct api_msg msg;
518
519   LWIP_ERROR("netconn_join_leave_group: invalid conn",  (conn != NULL), return ERR_ARG;);
520
521   msg.function = do_join_leave_group;
522   msg.msg.conn = conn;
523   msg.msg.msg.jl.multiaddr = multiaddr;
524   msg.msg.msg.jl.interface = interface;
525   msg.msg.msg.jl.join_or_leave = join_or_leave;
526   TCPIP_APIMSG(&msg);
527   return conn->err;
528 }
529 #endif /* LWIP_IGMP */
530
531 #if LWIP_DNS
532 /**
533  * Execute a DNS query, only one IP address is returned
534  *
535  * @param name a string representation of the DNS host name to query
536  * @param addr a preallocated struct ip_addr where to store the resolved IP address
537  * @return ERR_OK: resolving succeeded
538  *         ERR_MEM: memory error, try again later
539  *         ERR_ARG: dns client not initialized or invalid hostname
540  *         ERR_VAL: dns server response was invalid
541  */
542 err_t
543 netconn_gethostbyname(const char *name, struct ip_addr *addr)
544 {
545   struct dns_api_msg msg;
546   err_t err;
547   sys_sem_t sem;
548
549   LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
550   LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
551
552   sem = sys_sem_new(0);
553   if (sem == SYS_SEM_NULL) {
554     return ERR_MEM;
555   }
556
557   msg.name = name;
558   msg.addr = addr;
559   msg.err = &err;
560   msg.sem = sem;
561
562   tcpip_callback(do_gethostbyname, &msg);
563   sys_sem_wait(sem);
564   sys_sem_free(sem);
565
566   return err;
567 }
568 #endif /* LWIP_DNS*/
569
570 #endif /* LWIP_NETCONN */