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