5 changed files with 447 additions and 171 deletions
@ -0,0 +1,334 @@
|
||||
/**
|
||||
* @file |
||||
* API functions for name resolving |
||||
* |
||||
*/ |
||||
|
||||
/*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met: |
||||
* |
||||
* 1. Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, |
||||
* this list of conditions and the following disclaimer in the documentation |
||||
* and/or other materials provided with the distribution. |
||||
* 3. The name of the author may not be used to endorse or promote products |
||||
* derived from this software without specific prior written permission.
|
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE. |
||||
* |
||||
* This file is part of the lwIP TCP/IP stack. |
||||
*
|
||||
* Author: Simon Goldschmidt |
||||
* |
||||
*/ |
||||
|
||||
#include "lwip/netdb.h" |
||||
|
||||
#if LWIP_DNS && LWIP_SOCKET |
||||
|
||||
#include "lwip/err.h" |
||||
#include "lwip/mem.h" |
||||
#include "lwip/ip_addr.h" |
||||
#include "lwip/api.h" |
||||
|
||||
/** helper struct for gethostbyname_r to access the char* buffer */ |
||||
struct gethostbyname_r_helper { |
||||
struct ip_addr *addrs; |
||||
struct ip_addr addr; |
||||
char *aliases; |
||||
}; |
||||
|
||||
/** h_errno is exported in netdb.h for access by applications. */ |
||||
#if LWIP_DNS_API_DECLARE_H_ERRNO |
||||
int h_errno; |
||||
#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */ |
||||
|
||||
/* static buffer variables for lwip_gethostbyname() */ |
||||
static struct hostent s_hostent; |
||||
static char *s_aliases; |
||||
static struct ip_addr s_hostent_addr; |
||||
static struct ip_addr *s_phostent_addr; |
||||
|
||||
/**
|
||||
* Returns an entry containing addresses of address family AF_INET |
||||
* for the host with name name. |
||||
* Due to dns_gethostbyname limitations, only one address is returned. |
||||
* |
||||
* @param name the hostname to resolve |
||||
* @return an entry containing addresses of address family AF_INET |
||||
* for the host with name name |
||||
*/ |
||||
struct hostent* |
||||
lwip_gethostbyname(const char *name) |
||||
{ |
||||
err_t err; |
||||
struct ip_addr addr; |
||||
|
||||
/* query host IP address */ |
||||
err = netconn_gethostbyname(name, &addr); |
||||
if (err != ERR_OK) { |
||||
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); |
||||
h_errno = HOST_NOT_FOUND; |
||||
return NULL; |
||||
} |
||||
|
||||
/* fill hostent */ |
||||
s_hostent_addr = addr; |
||||
s_phostent_addr = &s_hostent_addr; |
||||
s_hostent.h_name = (char*)name; |
||||
s_hostent.h_aliases = &s_aliases; |
||||
s_hostent.h_addrtype = AF_INET; |
||||
s_hostent.h_length = sizeof(struct ip_addr); |
||||
s_hostent.h_addr_list = (char**)&s_phostent_addr; |
||||
|
||||
#if DNS_DEBUG |
||||
/* dump hostent */ |
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name)); |
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == 0x%08lX\n",(u32_t)(s_hostent.h_aliases))); |
||||
if (s_hostent.h_aliases != NULL) { |
||||
u8_t idx; |
||||
for ( idx=0; s_hostent.h_aliases[idx]; idx++) { |
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == 0x%08lX\n", idx, s_hostent.h_aliases[idx])); |
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx])); |
||||
} |
||||
} |
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %lu\n", (u32_t)(s_hostent.h_addrtype))); |
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %lu\n", (u32_t)(s_hostent.h_length))); |
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == 0x%08lX\n", s_hostent.h_addr_list)); |
||||
if (s_hostent.h_addr_list != NULL) { |
||||
u8_t idx; |
||||
for ( idx=0; s_hostent.h_addr_list[idx]; idx++) { |
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == 0x%08lX\n", idx, s_hostent.h_addr_list[idx])); |
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, inet_ntoa(*((struct in_addr*)(s_hostent.h_addr_list[idx]))))); |
||||
} |
||||
} |
||||
#endif /* DNS_DEBUG */ |
||||
|
||||
return &s_hostent; |
||||
} |
||||
|
||||
/**
|
||||
* Thread-safe variant of lwip_gethostbyname: instead of using a static |
||||
* buffer, this function takes buffer and errno pointers as arguments |
||||
* and uses these for the result. |
||||
* |
||||
* @param name the hostname to resolve |
||||
* @param ret pre-allocated struct where to store the result |
||||
* @param buf pre-allocated buffer where to store additional data |
||||
* @param buflen the size of buf |
||||
* @param result pointer to a hostent pointer that is set to ret on success |
||||
* and set to zero on error |
||||
* @param h_errnop pointer to an int where to store errors (instead of modifying |
||||
* the global h_errno) |
||||
* @return 0 on success, non-zero on error, additional error information |
||||
* is stored in *h_errnop instead of h_errno to be thread-safe |
||||
*/ |
||||
int |
||||
lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, |
||||
size_t buflen, struct hostent **result, int *h_errnop) |
||||
{ |
||||
err_t err; |
||||
struct gethostbyname_r_helper *h; |
||||
char *hostname; |
||||
size_t namelen; |
||||
int lh_errno; |
||||
|
||||
if (h_errnop == NULL) { |
||||
/* ensure h_errnop is never NULL */ |
||||
h_errnop = &lh_errno; |
||||
} |
||||
|
||||
if (result == NULL) { |
||||
/* not all arguments given */ |
||||
*h_errnop = EINVAL; |
||||
return -1; |
||||
} |
||||
/* first thing to do: set *result to nothing */ |
||||
*result = NULL; |
||||
if ((name == NULL) || (ret == NULL) || (buf == 0)) { |
||||
/* not all arguments given */ |
||||
*h_errnop = EINVAL; |
||||
return -1; |
||||
} |
||||
|
||||
namelen = strlen(name); |
||||
if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) { |
||||
/* buf can't hold the data needed + a copy of name */ |
||||
*h_errnop = ERANGE; |
||||
return -1; |
||||
} |
||||
|
||||
h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf); |
||||
hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper); |
||||
|
||||
/* query host IP address */ |
||||
err = netconn_gethostbyname(name, &(h->addr)); |
||||
if (err != ERR_OK) { |
||||
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); |
||||
*h_errnop = ENSRNOTFOUND; |
||||
return -1; |
||||
} |
||||
|
||||
/* copy the hostname into buf */ |
||||
memcpy(hostname, name, namelen); |
||||
hostname[namelen] = 0; |
||||
|
||||
/* fill hostent */ |
||||
h->addrs = &(h->addr); |
||||
h->aliases = NULL; |
||||
ret->h_name = (char*)hostname; |
||||
ret->h_aliases = &(h->aliases); |
||||
ret->h_addrtype = AF_INET; |
||||
ret->h_length = sizeof(struct ip_addr); |
||||
ret->h_addr_list = (char**)&(h->addrs); |
||||
|
||||
/* set result != NULL */ |
||||
*result = ret; |
||||
|
||||
/* return success */ |
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* Frees one or more addrinfo structures returned by getaddrinfo(), along with |
||||
* any additional storage associated with those structures. If the ai_next field |
||||
* of the structure is not null, the entire list of structures is freed. |
||||
* |
||||
* @param ai struct addrinfo to free |
||||
*/ |
||||
void |
||||
lwip_freeaddrinfo(struct addrinfo *ai) |
||||
{ |
||||
struct addrinfo *next; |
||||
|
||||
while (ai != NULL) { |
||||
if (ai->ai_addr != NULL) { |
||||
mem_free(ai->ai_addr); |
||||
} |
||||
if (ai->ai_canonname != NULL) { |
||||
mem_free(ai->ai_canonname); |
||||
} |
||||
next = ai->ai_next; |
||||
mem_free(ai); |
||||
ai = next; |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* Translates the name of a service location (for example, a host name) and/or |
||||
* a service name and returns a set of socket addresses and associated |
||||
* information to be used in creating a socket with which to address the |
||||
* specified service. |
||||
* Memory for the result is allocated internally and must be freed by calling |
||||
* lwip_freeaddrinfo()! |
||||
* |
||||
* Due to a limitation in dns_gethostbyname, only the first address of a |
||||
* host is returned. |
||||
* Also, service names are not supported (only port numbers)! |
||||
* |
||||
* @param nodename descriptive name or address string of the host |
||||
* (may be NULL -> local address) |
||||
* @param servname port number as string of NULL
|
||||
* @param hints structure containing input values that set socktype and protocol |
||||
* @param res pointer to a pointer where to store the result (set to NULL on failure) |
||||
* @return 0 on success, non-zero on failure |
||||
*/ |
||||
int |
||||
lwip_getaddrinfo(const char *nodename, const char *servname, |
||||
const struct addrinfo *hints, struct addrinfo **res) |
||||
{ |
||||
err_t err; |
||||
struct ip_addr addr; |
||||
struct addrinfo *ai; |
||||
struct sockaddr_in *sa; |
||||
int port_nr = 0; |
||||
|
||||
if (res == NULL) { |
||||
return EAI_FAIL; |
||||
} |
||||
*res = NULL; |
||||
if ((nodename == NULL) && (servname == NULL)) { |
||||
return EAI_NONAME; |
||||
} |
||||
|
||||
if (servname != NULL) { |
||||
/* service name specified: convert to port number
|
||||
* @todo?: currently, only ASCII integers (port numbers) are supported! */ |
||||
port_nr = atoi(servname); |
||||
if ((port_nr <= 0) || (port_nr > 0xffff)) { |
||||
return EAI_SERVICE; |
||||
} |
||||
} |
||||
|
||||
if (nodename != NULL) { |
||||
/* service location specified, try to resolve */ |
||||
err = netconn_gethostbyname(nodename, &addr); |
||||
if (err != ERR_OK) { |
||||
return EAI_FAIL; |
||||
} |
||||
} else { |
||||
/* service location specified, use loopback address */ |
||||
addr.addr = INADDR_LOOPBACK; |
||||
} |
||||
|
||||
ai = mem_malloc(sizeof(struct addrinfo)); |
||||
if (ai == NULL) { |
||||
goto memerr; |
||||
} |
||||
memset(ai, 0, sizeof(struct addrinfo)); |
||||
sa = mem_malloc(sizeof(struct sockaddr_in)); |
||||
if (sa == NULL) { |
||||
goto memerr; |
||||
} |
||||
memset(sa, 0, sizeof(struct sockaddr_in)); |
||||
/* set up sockaddr */ |
||||
sa->sin_addr.s_addr = addr.addr; |
||||
sa->sin_family = AF_INET; |
||||
sa->sin_len = sizeof(struct sockaddr_in); |
||||
sa->sin_port = htons(port_nr); |
||||
|
||||
/* set up addrinfo */ |
||||
ai->ai_family = AF_INET; |
||||
if (hints != NULL) { |
||||
/* copy socktype & protocol from hints if specified */ |
||||
ai->ai_socktype = hints->ai_socktype; |
||||
ai->ai_protocol = hints->ai_protocol; |
||||
} |
||||
if (nodename != NULL) { |
||||
/* copy nodename to canonname if specified */ |
||||
size_t namelen = strlen(nodename); |
||||
ai->ai_canonname = mem_malloc(namelen + 1); |
||||
if (ai->ai_canonname == NULL) { |
||||
goto memerr; |
||||
} |
||||
memcpy(ai->ai_canonname, nodename, namelen); |
||||
ai->ai_canonname[namelen] = 0; |
||||
} |
||||
ai->ai_addrlen = sizeof(struct sockaddr_in); |
||||
ai->ai_addr = (struct sockaddr*)sa; |
||||
|
||||
*res = ai; |
||||
|
||||
return 0; |
||||
memerr: |
||||
if (ai != NULL) { |
||||
mem_free(ai); |
||||
} |
||||
if (sa != NULL) { |
||||
mem_free(sa); |
||||
} |
||||
return EAI_MEMORY; |
||||
} |
||||
|
||||
#endif /* LWIP_DNS && LWIP_SOCKET */ |
||||
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met: |
||||
* |
||||
* 1. Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, |
||||
* this list of conditions and the following disclaimer in the documentation |
||||
* and/or other materials provided with the distribution. |
||||
* 3. The name of the author may not be used to endorse or promote products |
||||
* derived from this software without specific prior written permission.
|
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE. |
||||
* |
||||
* This file is part of the lwIP TCP/IP stack. |
||||
*
|
||||
* Author: Simon Goldschmidt |
||||
* |
||||
*/ |
||||
|
||||
#include "lwip/opt.h" |
||||
|
||||
#if LWIP_DNS && LWIP_SOCKET |
||||
|
||||
#include "lwip/sockets.h" |
||||
|
||||
/* some rarely used options */ |
||||
#ifndef LWIP_DNS_API_DECLARE_H_ERRNO |
||||
#define LWIP_DNS_API_DECLARE_H_ERRNO 1 |
||||
#endif |
||||
|
||||
#ifndef LWIP_DNS_API_DEFINE_ERRORS |
||||
#define LWIP_DNS_API_DEFINE_ERRORS 1 |
||||
#endif |
||||
|
||||
#ifndef LWIP_DNS_API_DECLARE_STRUCTS |
||||
#define LWIP_DNS_API_DECLARE_STRUCTS 1 |
||||
#endif |
||||
|
||||
#if LWIP_DNS_API_DEFINE_ERRORS |
||||
/** Errors used by the DNS API functions, h_errno can be one of them */ |
||||
#define EAI_NONAME 200 |
||||
#define EAI_SERVICE 201 |
||||
#define EAI_FAIL 202 |
||||
#define EAI_MEMORY 203 |
||||
|
||||
#define HOST_NOT_FOUND 210 |
||||
#define NO_DATA 211 |
||||
#define NO_RECOVERY 212 |
||||
#define TRY_AGAIN 213 |
||||
#endif /* LWIP_DNS_API_DEFINE_ERRORS */ |
||||
|
||||
#if LWIP_DNS_API_DECLARE_STRUCTS |
||||
struct hostent { |
||||
char *h_name; /* Official name of the host. */ |
||||
char **h_aliases; /* A pointer to an array of pointers to alternative host names,
|
||||
terminated by a null pointer. */ |
||||
int h_addrtype; /* Address type. */ |
||||
int h_length; /* The length, in bytes, of the address. */ |
||||
char **h_addr_list; /* A pointer to an array of pointers to network addresses (in
|
||||
network byte order) for the host, terminated by a null pointer. */ |
||||
#define h_addr h_addr_list[0] /* for backward compatibility */ |
||||
}; |
||||
|
||||
struct addrinfo { |
||||
int ai_flags; /* Input flags. */ |
||||
int ai_family; /* Address family of socket. */ |
||||
int ai_socktype; /* Socket type. */ |
||||
int ai_protocol; /* Protocol of socket. */ |
||||
socklen_t ai_addrlen; /* Length of socket address. */ |
||||
struct sockaddr *ai_addr; /* Socket address of socket. */ |
||||
char *ai_canonname; /* Canonical name of service location. */ |
||||
struct addrinfo *ai_next; /* Pointer to next in list. */ |
||||
}; |
||||
#endif /* LWIP_DNS_API_DECLARE_STRUCTS */ |
||||
|
||||
#if LWIP_DNS_API_DECLARE_H_ERRNO |
||||
/* application accessable error code set by the DNS API functions */ |
||||
extern int h_errno; |
||||
#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/ |
||||
|
||||
struct hostent *lwip_gethostbyname(const char *name); |
||||
int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, |
||||
size_t buflen, struct hostent **result, int *h_errnop); |
||||
void lwip_freeaddrinfo(struct addrinfo *ai); |
||||
int lwip_getaddrinfo(const char *nodename, |
||||
const char *servname, |
||||
const struct addrinfo *hints, |
||||
struct addrinfo **res); |
||||
|
||||
#if LWIP_COMPAT_SOCKETS |
||||
#define gethostbyname(name) lwip_gethostbyname(name) |
||||
#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ |
||||
lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop) |
||||
#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(a) |
||||
#define getaddrinfo(nodname, servname, hints, res) \ |
||||
lwip_getaddrinfo(nodname, servname, hints, res) |
||||
#endif /* LWIP_COMPAT_SOCKETS */ |
||||
|
||||
#endif /* LWIP_DNS && LWIP_SOCKET */ |
||||
Loading…
Reference in new issue