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 / netdb.c
1 /**
2  * @file
3  * API functions for name resolving
4  *
5  */
6
7 /*
8  * Redistribution and use in source and binary forms, with or without modification, 
9  * are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice,
12  *    this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission. 
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
20  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
22  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
24  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
27  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
28  * OF SUCH DAMAGE.
29  *
30  * This file is part of the lwIP TCP/IP stack.
31  * 
32  * Author: Simon Goldschmidt
33  *
34  */
35
36 #include "lwip/netdb.h"
37
38 #if LWIP_DNS && LWIP_SOCKET
39
40 #include "lwip/err.h"
41 #include "lwip/mem.h"
42 #include "lwip/ip_addr.h"
43 #include "lwip/api.h"
44
45 /** helper struct for gethostbyname_r to access the char* buffer */
46 struct gethostbyname_r_helper {
47   struct ip_addr *addrs;
48   struct ip_addr addr;
49   char *aliases;
50 };
51
52 /** h_errno is exported in netdb.h for access by applications. */
53 #if LWIP_DNS_API_DECLARE_H_ERRNO
54 int h_errno;
55 #endif /* LWIP_DNS_API_DECLARE_H_ERRNO */
56
57 /** define "hostent" variables storage: 0 if we use a static (but unprotected)
58  * set of variables for lwip_gethostbyname, 1 if we use a local storage */
59 #ifndef LWIP_DNS_API_HOSTENT_STORAGE
60 #define LWIP_DNS_API_HOSTENT_STORAGE 0
61 #endif
62
63 /** define "hostent" variables storage */
64 #if LWIP_DNS_API_HOSTENT_STORAGE
65 #define HOSTENT_STORAGE
66 #else
67 #define HOSTENT_STORAGE static
68 #endif /* LWIP_DNS_API_STATIC_HOSTENT */
69
70 /**
71  * Returns an entry containing addresses of address family AF_INET
72  * for the host with name name.
73  * Due to dns_gethostbyname limitations, only one address is returned.
74  *
75  * @param name the hostname to resolve
76  * @return an entry containing addresses of address family AF_INET
77  *         for the host with name name
78  */
79 struct hostent*
80 lwip_gethostbyname(const char *name)
81 {
82   err_t err;
83   struct ip_addr addr;
84
85   /* buffer variables for lwip_gethostbyname() */
86   HOSTENT_STORAGE struct hostent s_hostent;
87   HOSTENT_STORAGE char *s_aliases;
88   HOSTENT_STORAGE struct ip_addr s_hostent_addr;
89   HOSTENT_STORAGE struct ip_addr *s_phostent_addr;
90
91   /* query host IP address */
92   err = netconn_gethostbyname(name, &addr);
93   if (err != ERR_OK) {
94     LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
95     h_errno = HOST_NOT_FOUND;
96     return NULL;
97   }
98
99   /* fill hostent */
100   s_hostent_addr = addr;
101   s_phostent_addr = &s_hostent_addr;
102   s_hostent.h_name = (char*)name;
103   s_hostent.h_aliases = &s_aliases;
104   s_hostent.h_addrtype = AF_INET;
105   s_hostent.h_length = sizeof(struct ip_addr);
106   s_hostent.h_addr_list = (char**)&s_phostent_addr;
107
108 #if DNS_DEBUG
109   /* dump hostent */
110   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name           == %s\n",      s_hostent.h_name));
111   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases        == 0x%08lX\n",(u32_t)(s_hostent.h_aliases)));
112   if (s_hostent.h_aliases != NULL) {
113     u8_t idx;
114     for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
115       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == 0x%08lX\n", idx, s_hostent.h_aliases[idx]));
116       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %s\n",      idx, s_hostent.h_aliases[idx]));
117     }
118   }
119   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype       == %lu\n",    (u32_t)(s_hostent.h_addrtype)));
120   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length         == %lu\n",    (u32_t)(s_hostent.h_length)));
121   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list      == 0x%08lX\n", s_hostent.h_addr_list));
122   if (s_hostent.h_addr_list != NULL) {
123     u8_t idx;
124     for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
125       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]   == 0x%08lX\n", idx, s_hostent.h_addr_list[idx]));
126       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n",      idx, inet_ntoa(*((struct in_addr*)(s_hostent.h_addr_list[idx])))));
127     }
128   }
129 #endif /* DNS_DEBUG */
130
131 #if LWIP_DNS_API_HOSTENT_STORAGE
132   /* this function should return the "per-thread" hostent after copy from s_hostent */
133   return sys_thread_hostent(&s_hostent);
134 #else
135   return &s_hostent;
136 #endif /* LWIP_DNS_API_HOSTENT_STORAGE */
137 }
138
139 /**
140  * Thread-safe variant of lwip_gethostbyname: instead of using a static
141  * buffer, this function takes buffer and errno pointers as arguments
142  * and uses these for the result.
143  *
144  * @param name the hostname to resolve
145  * @param ret pre-allocated struct where to store the result
146  * @param buf pre-allocated buffer where to store additional data
147  * @param buflen the size of buf
148  * @param result pointer to a hostent pointer that is set to ret on success
149  *               and set to zero on error
150  * @param h_errnop pointer to an int where to store errors (instead of modifying
151  *                 the global h_errno)
152  * @return 0 on success, non-zero on error, additional error information
153  *         is stored in *h_errnop instead of h_errno to be thread-safe
154  */
155 int
156 lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
157                 size_t buflen, struct hostent **result, int *h_errnop)
158 {
159   err_t err;
160   struct gethostbyname_r_helper *h;
161   char *hostname;
162   size_t namelen;
163   int lh_errno;
164
165   if (h_errnop == NULL) {
166     /* ensure h_errnop is never NULL */
167     h_errnop = &lh_errno;
168   }
169
170   if (result == NULL) {
171     /* not all arguments given */
172     *h_errnop = EINVAL;
173     return -1;
174   }
175   /* first thing to do: set *result to nothing */
176   *result = NULL;
177   if ((name == NULL) || (ret == NULL) || (buf == 0)) {
178     /* not all arguments given */
179     *h_errnop = EINVAL;
180     return -1;
181   }
182
183   namelen = strlen(name);
184   if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) {
185     /* buf can't hold the data needed + a copy of name */
186     *h_errnop = ERANGE;
187     return -1;
188   }
189
190   h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf);
191   hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);
192
193   /* query host IP address */
194   err = netconn_gethostbyname(name, &(h->addr));
195   if (err != ERR_OK) {
196     LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
197     *h_errnop = ENSRNOTFOUND;
198     return -1;
199   }
200
201   /* copy the hostname into buf */
202   MEMCPY(hostname, name, namelen);
203   hostname[namelen] = 0;
204
205   /* fill hostent */
206   h->addrs = &(h->addr);
207   h->aliases = NULL;
208   ret->h_name = (char*)hostname;
209   ret->h_aliases = &(h->aliases);
210   ret->h_addrtype = AF_INET;
211   ret->h_length = sizeof(struct ip_addr);
212   ret->h_addr_list = (char**)&(h->addrs);
213
214   /* set result != NULL */
215   *result = ret;
216
217   /* return success */
218   return 0;
219 }
220
221 /**
222  * Frees one or more addrinfo structures returned by getaddrinfo(), along with
223  * any additional storage associated with those structures. If the ai_next field
224  * of the structure is not null, the entire list of structures is freed.
225  *
226  * @param ai struct addrinfo to free
227  */
228 void
229 lwip_freeaddrinfo(struct addrinfo *ai)
230 {
231   struct addrinfo *next;
232
233   while (ai != NULL) {
234     if (ai->ai_addr != NULL) {
235       mem_free(ai->ai_addr);
236     }
237     if (ai->ai_canonname != NULL) {
238       mem_free(ai->ai_canonname);
239     }
240     next = ai->ai_next;
241     mem_free(ai);
242     ai = next;
243   }
244 }
245
246 /**
247  * Translates the name of a service location (for example, a host name) and/or
248  * a service name and returns a set of socket addresses and associated
249  * information to be used in creating a socket with which to address the
250  * specified service.
251  * Memory for the result is allocated internally and must be freed by calling
252  * lwip_freeaddrinfo()!
253  *
254  * Due to a limitation in dns_gethostbyname, only the first address of a
255  * host is returned.
256  * Also, service names are not supported (only port numbers)!
257  *
258  * @param nodename descriptive name or address string of the host
259  *                 (may be NULL -> local address)
260  * @param servname port number as string of NULL 
261  * @param hints structure containing input values that set socktype and protocol
262  * @param res pointer to a pointer where to store the result (set to NULL on failure)
263  * @return 0 on success, non-zero on failure
264  */
265 int
266 lwip_getaddrinfo(const char *nodename, const char *servname,
267        const struct addrinfo *hints, struct addrinfo **res)
268 {
269   err_t err;
270   struct ip_addr addr;
271   struct addrinfo *ai;
272   struct sockaddr_in *sa = NULL;
273   int port_nr = 0;
274
275   if (res == NULL) {
276     return EAI_FAIL;
277   }
278   *res = NULL;
279   if ((nodename == NULL) && (servname == NULL)) {
280     return EAI_NONAME;
281   }
282
283   if (servname != NULL) {
284     /* service name specified: convert to port number
285      * @todo?: currently, only ASCII integers (port numbers) are supported! */
286     port_nr = atoi(servname);
287     if ((port_nr <= 0) || (port_nr > 0xffff)) {
288       return EAI_SERVICE;
289     }
290   }
291
292   if (nodename != NULL) {
293     /* service location specified, try to resolve */
294     err = netconn_gethostbyname(nodename, &addr);
295     if (err != ERR_OK) {
296       return EAI_FAIL;
297     }
298   } else {
299     /* service location specified, use loopback address */
300     addr.addr = INADDR_LOOPBACK;
301   }
302
303   ai = mem_malloc(sizeof(struct addrinfo));
304   if (ai == NULL) {
305     goto memerr;
306   }
307   memset(ai, 0, sizeof(struct addrinfo));
308   sa = mem_malloc(sizeof(struct sockaddr_in));
309   if (sa == NULL) {
310     goto memerr;
311   }
312   memset(sa, 0, sizeof(struct sockaddr_in));
313   /* set up sockaddr */
314   sa->sin_addr.s_addr = addr.addr;
315   sa->sin_family = AF_INET;
316   sa->sin_len = sizeof(struct sockaddr_in);
317   sa->sin_port = htons(port_nr);
318
319   /* set up addrinfo */
320   ai->ai_family = AF_INET;
321   if (hints != NULL) {
322     /* copy socktype & protocol from hints if specified */
323     ai->ai_socktype = hints->ai_socktype;
324     ai->ai_protocol = hints->ai_protocol;
325   }
326   if (nodename != NULL) {
327     /* copy nodename to canonname if specified */
328     size_t namelen = strlen(nodename);
329     ai->ai_canonname = mem_malloc(namelen + 1);
330     if (ai->ai_canonname == NULL) {
331       goto memerr;
332     }
333     MEMCPY(ai->ai_canonname, nodename, namelen);
334     ai->ai_canonname[namelen] = 0;
335   }
336   ai->ai_addrlen = sizeof(struct sockaddr_in);
337   ai->ai_addr = (struct sockaddr*)sa;
338
339   *res = ai;
340
341   return 0;
342 memerr:
343   if (ai != NULL) {
344     mem_free(ai);
345   }
346   if (sa != NULL) {
347     mem_free(sa);
348   }
349   return EAI_MEMORY;
350 }
351
352 #endif /* LWIP_DNS && LWIP_SOCKET */