UbixOS V2  2.0
netdb.c
Go to the documentation of this file.
1 
9 /*
10  * Redistribution and use in source and binary forms, with or without modification,
11  * are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright notice,
14  * this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  * derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30  * OF SUCH DAMAGE.
31  *
32  * This file is part of the lwIP TCP/IP stack.
33  *
34  * Author: Simon Goldschmidt
35  *
36  */
37 
38 #include "lwip/netdb.h"
39 
40 #if LWIP_DNS && LWIP_SOCKET
41 
42 #include "lwip/err.h"
43 #include "lwip/mem.h"
44 #include "lwip/memp.h"
45 #include "lwip/ip_addr.h"
46 #include "lwip/api.h"
47 #include "lwip/dns.h"
48 
49 #include <string.h> /* memset */
50 #include <stdlib.h> /* atoi */
51 
53 struct gethostbyname_r_helper {
54  ip_addr_t *addr_list[2];
55  ip_addr_t addr;
56  char *aliases;
57 };
58 
60 #if LWIP_DNS_API_DECLARE_H_ERRNO
61 int h_errno;
62 #endif /* LWIP_DNS_API_DECLARE_H_ERRNO */
63 
66 #ifndef LWIP_DNS_API_HOSTENT_STORAGE
67 #define LWIP_DNS_API_HOSTENT_STORAGE 0
68 #endif
69 
71 #if LWIP_DNS_API_HOSTENT_STORAGE
72 #define HOSTENT_STORAGE
73 #else
74 #define HOSTENT_STORAGE static
75 #endif /* LWIP_DNS_API_STATIC_HOSTENT */
76 
86 struct hostent*
87 lwip_gethostbyname(const char *name)
88 {
89  err_t err;
90  ip_addr_t addr;
91 
92  /* buffer variables for lwip_gethostbyname() */
93  HOSTENT_STORAGE struct hostent s_hostent;
94  HOSTENT_STORAGE char *s_aliases;
95  HOSTENT_STORAGE ip_addr_t s_hostent_addr;
96  HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];
97  HOSTENT_STORAGE char s_hostname[DNS_MAX_NAME_LENGTH + 1];
98 
99  /* query host IP address */
100  err = netconn_gethostbyname(name, &addr);
101  if (err != ERR_OK) {
102  LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
103  h_errno = HOST_NOT_FOUND;
104  return NULL;
105  }
106 
107  /* fill hostent */
108  s_hostent_addr = addr;
109  s_phostent_addr[0] = &s_hostent_addr;
110  s_phostent_addr[1] = NULL;
111  strncpy(s_hostname, name, DNS_MAX_NAME_LENGTH);
112  s_hostname[DNS_MAX_NAME_LENGTH] = 0;
113  s_hostent.h_name = s_hostname;
114  s_aliases = NULL;
115  s_hostent.h_aliases = &s_aliases;
116  s_hostent.h_addrtype = AF_INET;
117  s_hostent.h_length = sizeof(ip_addr_t);
118  s_hostent.h_addr_list = (char**)&s_phostent_addr;
119 
120 #if DNS_DEBUG
121  /* dump hostent */
122  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
123  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", (void*)s_hostent.h_aliases));
124  /* h_aliases are always empty */
125  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype));
126  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length));
127  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", (void*)s_hostent.h_addr_list));
128  if (s_hostent.h_addr_list != NULL) {
129  u8_t idx;
130  for (idx=0; s_hostent.h_addr_list[idx]; idx++) {
131  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx]));
132  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ipaddr_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx])));
133  }
134  }
135 #endif /* DNS_DEBUG */
136 
137 #if LWIP_DNS_API_HOSTENT_STORAGE
138  /* this function should return the "per-thread" hostent after copy from s_hostent */
139  return sys_thread_hostent(&s_hostent);
140 #else
141  return &s_hostent;
142 #endif /* LWIP_DNS_API_HOSTENT_STORAGE */
143 }
144 
161 int
162 lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
163  size_t buflen, struct hostent **result, int *h_errnop)
164 {
165  err_t err;
166  struct gethostbyname_r_helper *h;
167  char *hostname;
168  size_t namelen;
169  int lh_errno;
170 
171  if (h_errnop == NULL) {
172  /* ensure h_errnop is never NULL */
173  h_errnop = &lh_errno;
174  }
175 
176  if (result == NULL) {
177  /* not all arguments given */
178  *h_errnop = EINVAL;
179  return -1;
180  }
181  /* first thing to do: set *result to nothing */
182  *result = NULL;
183  if ((name == NULL) || (ret == NULL) || (buf == NULL)) {
184  /* not all arguments given */
185  *h_errnop = EINVAL;
186  return -1;
187  }
188 
189  namelen = strlen(name);
190  if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) {
191  /* buf can't hold the data needed + a copy of name */
192  *h_errnop = ERANGE;
193  return -1;
194  }
195 
196  h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf);
197  hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);
198 
199  /* query host IP address */
200  err = netconn_gethostbyname(name, &h->addr);
201  if (err != ERR_OK) {
202  LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
203  *h_errnop = HOST_NOT_FOUND;
204  return -1;
205  }
206 
207  /* copy the hostname into buf */
208  MEMCPY(hostname, name, namelen);
209  hostname[namelen] = 0;
210 
211  /* fill hostent */
212  h->addr_list[0] = &h->addr;
213  h->addr_list[1] = NULL;
214  h->aliases = NULL;
215  ret->h_name = hostname;
216  ret->h_aliases = &h->aliases;
217  ret->h_addrtype = AF_INET;
218  ret->h_length = sizeof(ip_addr_t);
219  ret->h_addr_list = (char**)&h->addr_list;
220 
221  /* set result != NULL */
222  *result = ret;
223 
224  /* return success */
225  return 0;
226 }
227 
235 void
236 lwip_freeaddrinfo(struct addrinfo *ai)
237 {
238  struct addrinfo *next;
239 
240  while (ai != NULL) {
241  next = ai->ai_next;
242  memp_free(MEMP_NETDB, ai);
243  ai = next;
244  }
245 }
246 
268 int
269 lwip_getaddrinfo(const char *nodename, const char *servname,
270  const struct addrinfo *hints, struct addrinfo **res)
271 {
272  err_t err;
273  ip_addr_t addr;
274  struct addrinfo *ai;
275  struct sockaddr_storage *sa = NULL;
276  int port_nr = 0;
277  size_t total_size;
278  size_t namelen = 0;
279  int ai_family;
280 
281  if (res == NULL) {
282  return EAI_FAIL;
283  }
284  *res = NULL;
285  if ((nodename == NULL) && (servname == NULL)) {
286  return EAI_NONAME;
287  }
288 
289  if (hints != NULL) {
290  ai_family = hints->ai_family;
291  if ((ai_family != AF_UNSPEC)
292 #if LWIP_IPV4
293  && (ai_family != AF_INET)
294 #endif /* LWIP_IPV4 */
295 #if LWIP_IPV6
296  && (ai_family != AF_INET6)
297 #endif /* LWIP_IPV6 */
298  ) {
299  return EAI_FAMILY;
300  }
301  } else {
302  ai_family = AF_UNSPEC;
303  }
304 
305  if (servname != NULL) {
306  /* service name specified: convert to port number
307  * @todo?: currently, only ASCII integers (port numbers) are supported (AI_NUMERICSERV)! */
308  port_nr = atoi(servname);
309  if ((port_nr <= 0) || (port_nr > 0xffff)) {
310  return EAI_SERVICE;
311  }
312  }
313 
314  if (nodename != NULL) {
315  /* service location specified, try to resolve */
316  if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) {
317  /* no DNS lookup, just parse for an address string */
318  if (!ipaddr_aton(nodename, &addr)) {
319  return EAI_NONAME;
320  }
321 #if LWIP_IPV4 && LWIP_IPV6
322  if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) ||
323  (IP_IS_V4_VAL(addr) && ai_family == AF_INET6)) {
324  return EAI_NONAME;
325  }
326 #endif /* LWIP_IPV4 && LWIP_IPV6 */
327  } else {
328 #if LWIP_IPV4 && LWIP_IPV6
329  /* AF_UNSPEC: prefer IPv4 */
330  u8_t type = NETCONN_DNS_IPV4_IPV6;
331  if (ai_family == AF_INET) {
332  type = NETCONN_DNS_IPV4;
333  } else if (ai_family == AF_INET6) {
334  type = NETCONN_DNS_IPV6;
335  }
336 #endif /* LWIP_IPV4 && LWIP_IPV6 */
337  err = netconn_gethostbyname_addrtype(nodename, &addr, type);
338  if (err != ERR_OK) {
339  return EAI_FAIL;
340  }
341  }
342  } else {
343  /* service location specified, use loopback address */
344  if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) {
345  ip_addr_set_any(ai_family == AF_INET6, &addr);
346  } else {
347  ip_addr_set_loopback(ai_family == AF_INET6, &addr);
348  }
349  }
350 
351  total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage);
352  if (nodename != NULL) {
353  namelen = strlen(nodename);
354  if (namelen > DNS_MAX_NAME_LENGTH) {
355  /* invalid name length */
356  return EAI_FAIL;
357  }
358  LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size);
359  total_size += namelen + 1;
360  }
361  /* If this fails, please report to lwip-devel! :-) */
362  LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
363  total_size <= NETDB_ELEM_SIZE);
364  ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
365  if (ai == NULL) {
366  return EAI_MEMORY;
367  }
368  memset(ai, 0, total_size);
369  /* cast through void* to get rid of alignment warnings */
370  sa = (struct sockaddr_storage *)(void*)((u8_t*)ai + sizeof(struct addrinfo));
371  if (IP_IS_V6_VAL(addr)) {
372 #if LWIP_IPV6
373  struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)sa;
374  /* set up sockaddr */
375  inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr));
376  sa6->sin6_family = AF_INET6;
377  sa6->sin6_len = sizeof(struct sockaddr_in6);
378  sa6->sin6_port = lwip_htons((u16_t)port_nr);
379  ai->ai_family = AF_INET6;
380 #endif /* LWIP_IPV6 */
381  } else {
382 #if LWIP_IPV4
383  struct sockaddr_in *sa4 = (struct sockaddr_in*)sa;
384  /* set up sockaddr */
385  inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr));
386  sa4->sin_family = AF_INET;
387  sa4->sin_len = sizeof(struct sockaddr_in);
388  sa4->sin_port = lwip_htons((u16_t)port_nr);
389  ai->ai_family = AF_INET;
390 #endif /* LWIP_IPV4 */
391  }
392 
393  /* set up addrinfo */
394  if (hints != NULL) {
395  /* copy socktype & protocol from hints if specified */
396  ai->ai_socktype = hints->ai_socktype;
397  ai->ai_protocol = hints->ai_protocol;
398  }
399  if (nodename != NULL) {
400  /* copy nodename to canonname if specified */
401  ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage));
402  MEMCPY(ai->ai_canonname, nodename, namelen);
403  ai->ai_canonname[namelen] = 0;
404  }
405  ai->ai_addrlen = sizeof(struct sockaddr_storage);
406  ai->ai_addr = (struct sockaddr*)sa;
407 
408  *res = ai;
409 
410  return 0;
411 }
412 
413 #endif /* LWIP_DNS && LWIP_SOCKET */
DNS_MAX_NAME_LENGTH
#define DNS_MAX_NAME_LENGTH
Definition: lwipopts.h:159
IP_IS_V6_VAL
#define IP_IS_V6_VAL(ipaddr)
Definition: ip_addr.h:294
LWIP_ASSERT
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
LWIP_IPV6
#define LWIP_IPV6
Definition: lwipopts.h:366
u16_t
uint16_t u16_t
Definition: arch.h:124
string.h
ip_addr_set_loopback
#define ip_addr_set_loopback(is_ipv6, ipaddr)
Definition: ip_addr.h:312
strncpy
char * strncpy(char *__restrict, const char *__restrict, size_t)
strlen
int strlen(const char *str)
Definition: strlen.c:55
memp_malloc
void * memp_malloc(memp_t type)
Definition: memp.c:385
ERANGE
#define ERANGE
Definition: errno.h:70
memp_free
void memp_free(memp_t type, void *mem)
Definition: memp.c:469
u8_t
uint8_t u8_t
Definition: arch.h:122
ip_addr_t
ip6_addr_t ip_addr_t
Definition: ip_addr.h:290
buf
Definition: buf.h:35
ipaddr_aton
#define ipaddr_aton(cp, addr)
Definition: ip_addr.h:327
ip_addr_set_any
#define ip_addr_set_any(is_ipv6, ipaddr)
Definition: ip_addr.h:311
ip_2_ip6
#define ip_2_ip6(ipaddr)
Definition: ip_addr.h:301
lwip_htons
u16_t lwip_htons(u16_t n)
Definition: def.c:75
MEM_ALIGNMENT
#define MEM_ALIGNMENT
Definition: lwipopts.h:54
IP_IS_V4_VAL
#define IP_IS_V4_VAL(ipaddr)
Definition: ip_addr.h:293
LWIP_MEM_ALIGN
#define LWIP_MEM_ALIGN(addr)
Definition: arch.h:236
ERR_OK
Definition: err.h:63
err_t
s8_t err_t
Definition: err.h:57
name
const char * name
Definition: pci.c:37
MEMCPY
#define MEMCPY(dst, src, len)
Definition: lwipopts.h:43
memset
void * memset(void *dst, int c, size_t length)
ipaddr_ntoa
#define ipaddr_ntoa(ipaddr)
Definition: ip_addr.h:325
LWIP_IPV4
#define LWIP_IPV4
Definition: lwipopts.h:109
LWIP_DEBUGF
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:164
EINVAL
#define EINVAL
Definition: errno.h:55
DNS_DEBUG
#define DNS_DEBUG
Definition: lwipopts.h:486
NULL
#define NULL
Definition: fat_string.h:17