diff --git a/include/netdb.h b/include/netdb.h index 5374fe8dfe4..8e044e52485 100644 --- a/include/netdb.h +++ b/include/netdb.h @@ -184,17 +184,14 @@ struct hostent FAR char **h_aliases; /* A pointer to an array of pointers to the * alternative host names, terminated by a * null pointer. */ - FAR int *h_addrtypes; /* A pointer to an array of address type. */ - FAR int *h_lengths; /* A pointer to an array of the length, in bytes, - * of the address. */ + int h_addrtype; /* Address type. */ + int h_length; /* The length, in bytes, of the address. */ FAR 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 */ -#define h_length h_lengths[0] -#define h_addrtype h_addrtypes[0] struct netent { @@ -291,6 +288,7 @@ int getnameinfo(FAR const struct sockaddr *sa, FAR struct hostent *gethostbyaddr(FAR const void *addr, socklen_t len, int type); FAR struct hostent *gethostbyname(FAR const char *name); +FAR struct hostent *gethostbyname2(FAR const char *name, int type); FAR struct servent *getservbyport(int port, FAR const char *proto); FAR struct servent *getservbyname(FAR const char *name, FAR const char *proto); @@ -314,9 +312,16 @@ void setservent(int); int gethostbyaddr_r(FAR const void *addr, socklen_t len, int type, FAR struct hostent *host, FAR char *buf, - size_t buflen, int *h_errnop); -int gethostbyname_r(FAR const char *name, FAR struct hostent *host, - FAR char *buf, size_t buflen, int *h_errnop); + size_t buflen, FAR struct hostent **result, + FAR int *h_errnop); +int gethostbyname_r(FAR const char *name, + FAR struct hostent *host, FAR char *buf, + size_t buflen, FAR struct hostent **result, + FAR int *h_errnop); +int gethostbyname2_r(FAR const char *name, int type, + FAR struct hostent *host, FAR char *buf, + size_t buflen, FAR struct hostent **result, + FAR int *h_errnop); int getservbyport_r(int port, FAR const char *proto, FAR struct servent *result_buf, FAR char *buf, size_t buflen, FAR struct servent **result); diff --git a/libs/libc/netdb/Make.defs b/libs/libc/netdb/Make.defs index 591e21df095..56256bb488d 100644 --- a/libs/libc/netdb/Make.defs +++ b/libs/libc/netdb/Make.defs @@ -38,6 +38,8 @@ ifeq ($(CONFIG_LIBC_NETDB),y) # Add the netdb C files to the build CSRCS += lib_netdb.c lib_gethostbyname.c lib_gethostbynamer.c +CSRCS += lib_gethostbyname2.c lib_gethostbyname2r.c +CSRCS += lib_gethostentbynamer.c CSRCS += lib_gethostbyaddr.c lib_gethostbyaddrr.c CSRCS += lib_getservbyname.c lib_getservbynamer.c CSRCS += lib_getservbyport.c lib_getservbyportr.c diff --git a/libs/libc/netdb/lib_getaddrinfo.c b/libs/libc/netdb/lib_getaddrinfo.c index 88c348240ae..93c2775a692 100644 --- a/libs/libc/netdb/lib_getaddrinfo.c +++ b/libs/libc/netdb/lib_getaddrinfo.c @@ -46,6 +46,7 @@ #include #include "libc.h" +#include "lib_netdb.h" /**************************************************************************** * Private Data Types @@ -123,12 +124,14 @@ int getaddrinfo(FAR const char *hostname, FAR const char *servname, int flags = 0; int proto = 0; int socktype = 0; - FAR struct hostent *hp; + char hostbuffer[CONFIG_NETDB_BUFSIZE]; + FAR struct hostent_s host; FAR struct ai_s *ai; FAR struct ai_s *prev_ai = NULL; const int valid_flags = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV | AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG; + int ret = OK; int i; if (hostname == NULL && servname == NULL) @@ -278,63 +281,60 @@ int getaddrinfo(FAR const char *hostname, FAR const char *servname, /* REVISIT: no check for AI_NUMERICHOST flag. */ - /* REVISIT: use gethostbyname_r with own buffer of refactor all - * public APIs to use internal lookup function. - */ - - hp = gethostbyname(hostname); - if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) + gethostentbyname_r(hostname, &host, + hostbuffer, sizeof(hostbuffer), &ret); + if (ret != OK) { - for (i = 0; hp->h_addr_list[i]; i++) - { - if (family != AF_UNSPEC && hp->h_addrtypes[i] != family) - { - /* Filter by protocol family. */ - - continue; - } - - /* REVISIT: filter by socktype and protocol not implemented. */ - - ai = alloc_ai(hp->h_addrtypes[i], socktype, proto, port, - hp->h_addr_list[i]); - if (ai == NULL) - { - if (*res) - { - freeaddrinfo(*res); - } - - return EAI_MEMORY; - } - - /* REVISIT: grok canonical name. - * - * OpenGroup: "if the canonical name is not available, then - * ai_canonname shall refer to the hostname argument or a string - * with the same contents." - */ - - ai->ai.ai_canonname = (FAR char *)hostname; - - /* Add result to linked list. - * TODO: RFC 3484/6724 destination address sort not implemented. - */ - - if (prev_ai != NULL) - { - prev_ai->ai.ai_next = (FAR struct addrinfo *)ai; - } - else - { - *res = (FAR struct addrinfo *)ai; - } - - prev_ai = ai; - } - - return (*res != NULL) ? OK : EAI_FAMILY; + return ret; } - return h_errno; + for (i = 0; host.h_addr_list[i]; i++) + { + if (family != AF_UNSPEC && host.h_addrtypes[i] != family) + { + /* Filter by protocol family. */ + + continue; + } + + /* REVISIT: filter by socktype and protocol not implemented. */ + + ai = alloc_ai(host.h_addrtypes[i], socktype, proto, port, + host.h_addr_list[i]); + if (ai == NULL) + { + if (*res) + { + freeaddrinfo(*res); + } + + return EAI_MEMORY; + } + + /* REVISIT: grok canonical name. + * + * OpenGroup: "if the canonical name is not available, then + * ai_canonname shall refer to the hostname argument or a string + * with the same contents." + */ + + ai->ai.ai_canonname = (FAR char *)hostname; + + /* Add result to linked list. + * TODO: RFC 3484/6724 destination address sort not implemented. + */ + + if (prev_ai != NULL) + { + prev_ai->ai.ai_next = (FAR struct addrinfo *)ai; + } + else + { + *res = (FAR struct addrinfo *)ai; + } + + prev_ai = ai; + } + + return (*res != NULL) ? OK : EAI_FAMILY; } diff --git a/libs/libc/netdb/lib_gethostbyaddr.c b/libs/libc/netdb/lib_gethostbyaddr.c index 80cc1553224..0f79fcfee93 100644 --- a/libs/libc/netdb/lib_gethostbyaddr.c +++ b/libs/libc/netdb/lib_gethostbyaddr.c @@ -40,9 +40,7 @@ #include #include -#include -#include "libc.h" #include "netdb/lib_netdb.h" #ifdef CONFIG_LIBC_NETDB @@ -80,14 +78,12 @@ FAR struct hostent *gethostbyaddr(FAR const void *addr, socklen_t len, int type) { + FAR struct hostent *res; int ret; - DEBUGASSERT(addr != NULL); - DEBUGASSERT(type == AF_INET || type == AF_INET6); - ret = gethostbyaddr_r(addr, len, type, &g_hostent, g_hostbuffer, - CONFIG_NETDB_BUFSIZE, &h_errno); - return ret == 0 ? &g_hostent : NULL; + CONFIG_NETDB_BUFSIZE, &res, &h_errno); + return ret == 0 ? res : NULL; } #endif /* CONFIG_LIBC_NETDB */ diff --git a/libs/libc/netdb/lib_gethostbyaddrr.c b/libs/libc/netdb/lib_gethostbyaddrr.c index b9115d745d8..062f8b74af2 100644 --- a/libs/libc/netdb/lib_gethostbyaddrr.c +++ b/libs/libc/netdb/lib_gethostbyaddrr.c @@ -48,7 +48,6 @@ #include #include -#include "libc.h" #include "netdb/lib_netdb.h" #ifdef CONFIG_LIBC_NETDB @@ -61,8 +60,8 @@ struct hostent_info_s { - int hi_addrtypes[CONFIG_NETDB_MAX_IPADDR + 1]; - int hi_lengths[CONFIG_NETDB_MAX_IPADDR + 1]; + int hi_addrtypes[CONFIG_NETDB_MAX_IPADDR]; + int hi_lengths[CONFIG_NETDB_MAX_IPADDR]; FAR char *hi_addrlist[CONFIG_NETDB_MAX_IPADDR + 1]; char hi_data[1]; }; @@ -162,7 +161,7 @@ static bool lib_lo_ipv6match(FAR const void *addr, socklen_t len, int type) #ifdef CONFIG_NET_LOOPBACK static int lib_localhost(FAR const void *addr, socklen_t len, int type, - FAR struct hostent *host, FAR char *buf, + FAR struct hostent_s *host, FAR char *buf, size_t buflen) { FAR struct hostent_info_s *info; @@ -180,7 +179,7 @@ static int lib_localhost(FAR const void *addr, socklen_t len, int type, dest = info->hi_data; buflen -= (sizeof(struct hostent_info_s) - 1); - memset(host, 0, sizeof(struct hostent)); + memset(host, 0, sizeof(struct hostent_s)); memset(info, 0, sizeof(struct hostent_info_s)); host->h_addrtypes = info->hi_addrtypes; @@ -192,9 +191,9 @@ static int lib_localhost(FAR const void *addr, socklen_t len, int type, { /* Save the IPv4 address */ - host->h_length = sizeof(struct in_addr); - host->h_addr = (FAR char *)&g_lo_ipv4addr; - host->h_addrtype = AF_INET; + host->h_lengths[0] = sizeof(struct in_addr); + host->h_addr_list[0] = (FAR char *)&g_lo_ipv4addr; + host->h_addrtypes[0] = AF_INET; goto out_copyname; } #endif @@ -204,9 +203,9 @@ static int lib_localhost(FAR const void *addr, socklen_t len, int type, { /* Save the IPv6 address */ - host->h_length = sizeof(struct in6_addr); - host->h_addr = (FAR char *)&g_lo_ipv6addr; - host->h_addrtype = AF_INET6; + host->h_lengths[0] = sizeof(struct in6_addr); + host->h_addr_list[0] = (FAR char *)&g_lo_ipv6addr; + host->h_addrtypes[0] = AF_INET6; goto out_copyname; } #endif @@ -256,8 +255,8 @@ out_copyname: #ifdef CONFIG_NETDB_HOSTFILE int lib_hostfile_lookup(FAR const void *addr, socklen_t len, int type, - FAR struct hostent *host, FAR char *buf, - size_t buflen, int *h_errnop) + FAR struct hostent_s *host, FAR char *buf, + size_t buflen, FAR int *h_errnop) { FAR FILE *stream; int herrnocode; @@ -286,7 +285,7 @@ int lib_hostfile_lookup(FAR const void *addr, socklen_t len, int type, { /* Read the next entry from the hosts file */ - nread = lib_parse_hostfile(stream, host, buf, buflen); + nread = parse_hostfile(stream, host, buf, buflen); if (nread < 0) { /* Possible errors: @@ -305,13 +304,13 @@ int lib_hostfile_lookup(FAR const void *addr, socklen_t len, int type, goto errorout_with_stream; } } - else if (len == host->h_length && type == host->h_addrtype) + else if (len == host->h_lengths[0] && type == host->h_addrtypes[0]) { /* We successfully read the entry and the type and size of the * address is good. Now compare the addresses: */ - FAR char *hostaddr = host->h_addr; + FAR char *hostaddr = host->h_addr_list[0]; if (hostaddr != NULL) { ninfo("Comparing addresses...\n"); @@ -371,6 +370,7 @@ errorout_with_herrnocode: * buf - Caller provided buffer to hold string data associated with the * host data. * buflen - The size of the caller-provided buffer + * result - There host entry returned in the event of a success. * h_errnop - There h_errno value returned in the event of a failure. * * Returned Value: @@ -381,11 +381,19 @@ errorout_with_herrnocode: int gethostbyaddr_r(FAR const void *addr, socklen_t len, int type, FAR struct hostent *host, FAR char *buf, - size_t buflen, int *h_errnop) + size_t buflen, FAR struct hostent **result, + FAR int *h_errnop) { + struct hostent_s tmp; + int ret; + DEBUGASSERT(addr != NULL && host != NULL && buf != NULL); DEBUGASSERT(type == AF_INET || type == AF_INET6); + /* Linux man page says result must be NULL in case of failure. */ + + *result = NULL; + /* Make sure that the h_errno has a non-error code */ if (h_errnop) @@ -396,10 +404,13 @@ int gethostbyaddr_r(FAR const void *addr, socklen_t len, int type, #ifdef CONFIG_NET_LOOPBACK /* Check for the local loopback address */ - if (lib_localhost(addr, len, type, host, buf, buflen) == 0) + ret = lib_localhost(addr, len, type, &tmp, buf, buflen); + if (ret == OK) { /* Yes.. we are done */ + convert_hostent(&tmp, AF_UNSPEC, host); + *result = host; return OK; } #endif @@ -416,8 +427,13 @@ int gethostbyaddr_r(FAR const void *addr, socklen_t len, int type, #ifdef CONFIG_NETDB_HOSTFILE /* Search the hosts file for a match */ - return lib_hostfile_lookup(addr, len, type, host, buf, buflen, h_errnop); - + ret = lib_hostfile_lookup(addr, len, type, &tmp, buf, buflen, h_errnop); + if (ret == OK) + { + convert_hostent(&tmp, AF_UNSPEC, host); + *result = host; + return OK; + } #else /* The host file file is not supported. The host address mapping was not * found from any lookup heuristic @@ -428,8 +444,10 @@ int gethostbyaddr_r(FAR const void *addr, socklen_t len, int type, *h_errnop = HOST_NOT_FOUND; } - return ERROR; + ret = ERROR; #endif + + return ret; } #endif /* CONFIG_LIBC_NETDB */ diff --git a/libs/libc/netdb/lib_gethostbyname.c b/libs/libc/netdb/lib_gethostbyname.c index f16fd3acebe..85c33f3a793 100644 --- a/libs/libc/netdb/lib_gethostbyname.c +++ b/libs/libc/netdb/lib_gethostbyname.c @@ -40,10 +40,6 @@ #include #include -#include - -#include "libc.h" -#include "netdb/lib_netdb.h" #ifdef CONFIG_LIBC_NETDB @@ -81,12 +77,7 @@ FAR struct hostent *gethostbyname(FAR const char *name) { - int ret; - - DEBUGASSERT(name != NULL); - ret = gethostbyname_r(name, &g_hostent, g_hostbuffer, CONFIG_NETDB_BUFSIZE, - &h_errno); - return ret == 0 ? &g_hostent : NULL; + return gethostbyname2(name, AF_UNSPEC); } #endif /* CONFIG_LIBC_NETDB */ diff --git a/libs/libc/netdb/lib_gethostbyname2.c b/libs/libc/netdb/lib_gethostbyname2.c new file mode 100644 index 00000000000..93b5fd38815 --- /dev/null +++ b/libs/libc/netdb/lib_gethostbyname2.c @@ -0,0 +1,76 @@ +/**************************************************************************** + * libs/libc/netdb/lib_gethostbyname2.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "netdb/lib_netdb.h" + +#ifdef CONFIG_LIBC_NETDB + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: gethostbyname2 + * + * Description: + * The gethostbyname2() function returns a structure of type hostent for + * the given host name. Here name is either a hostname, or an IPv4 address + * in standard dot notation (as for inet_addr(3)), or an IPv6 address in + * colon (and possibly dot) notation. + * + * If name is an IPv4 or IPv6 address, no lookup is performed and + * gethostbyname2_r() simply copies name into the h_name field + * and its struct in_addr equivalent into the h_addr_list[0] field of the + * returned hostent structure. + * + * Input Parameters: + * name - The name of the host to find. + * type - The type of the address to find. + * + * Returned Value: + * Upon successful completion, this function will return a pointer to a + * hostent structure if the requested entry was found, and a null pointer + * if the end of the database was reached or the requested entry was not + * found. + * + * Upon unsuccessful completion, gethostbyname2() will set h_errno to + * indicate the error + * + ****************************************************************************/ + +FAR struct hostent *gethostbyname2(FAR const char *name, int type) +{ + FAR struct hostent *res; + int ret; + + ret = gethostbyname2_r(name, type, &g_hostent, g_hostbuffer, + CONFIG_NETDB_BUFSIZE, &res, &h_errno); + return ret == 0 ? res : NULL; +} + +#endif /* CONFIG_LIBC_NETDB */ diff --git a/libs/libc/netdb/lib_gethostbyname2r.c b/libs/libc/netdb/lib_gethostbyname2r.c new file mode 100644 index 00000000000..a0e0ce30951 --- /dev/null +++ b/libs/libc/netdb/lib_gethostbyname2r.c @@ -0,0 +1,107 @@ +/**************************************************************************** + * libs/libc/netdb/lib_gethostbyname2r.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "netdb/lib_netdb.h" + +#ifdef CONFIG_LIBC_NETDB + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: gethostbyname2_r + * + * Description: + * The gethostbyname2_r() function returns a structure of type hostent for + * the given host name. Here name is either a hostname, or an IPv4 address + * in standard dot notation (as for inet_addr(3)), or an IPv6 address in + * colon (and possibly dot) notation. + * + * If name is an IPv4 or IPv6 address, no lookup is performed and + * gethostbyname2_r() simply copies name into the h_name field + * and its struct in_addr equivalent into the h_addr_list[0] field of the + * returned hostent structure. + * + * gethostname2_r() is *not* POSIX but is similar to a Glibc extension and + * is used internally by NuttX to implement the POSIX gethostname(). + * + * Input Parameters: + * name - The name of the host to find. + * type - The type of the address to find. + * host - Caller provided location to return the host data. + * buf - Caller provided buffer to hold string data associated with the + * host data. + * buflen - The size of the caller-provided buffer + * result - There host entry returned in the event of a success. + * h_errnop - There h_errno value returned in the event of a failure. + * + * Returned Value: + * Zero (OK) is returned on success, -1 (ERROR) is returned on a failure + * with the returned h_errno value provided the reason for the failure. + * + ****************************************************************************/ + +int gethostbyname2_r(FAR const char *name, int type, + FAR struct hostent *host, FAR char *buf, + size_t buflen, FAR struct hostent **result, + FAR int *h_errnop) +{ + struct hostent_s tmp; + int ret; + + /* Linux man page says result must be NULL in case of failure. */ + + *result = NULL; + + ret = gethostentbyname_r(name, &tmp, buf, buflen, h_errnop); + if (ret == OK) + { + if (convert_hostent(&tmp, type, host)) + { + *result = host; + } + else + { + if (h_errnop) + { + *h_errnop = HOST_NOT_FOUND; + } + + ret = ERROR; + } + } + + return ret; +} + +#endif /* CONFIG_LIBC_NETDB */ diff --git a/libs/libc/netdb/lib_gethostbynamer.c b/libs/libc/netdb/lib_gethostbynamer.c index b8846556b37..8df1aa9e85c 100644 --- a/libs/libc/netdb/lib_gethostbynamer.c +++ b/libs/libc/netdb/lib_gethostbynamer.c @@ -39,687 +39,10 @@ #include -#include -#include - -#include -#include #include -#include -#include - -#include - -#include -#include - -#include "libc.h" -#include "netdb/lib_dns.h" #ifdef CONFIG_LIBC_NETDB -/**************************************************************************** - * Private Type Definitions - ****************************************************************************/ - -/* This is the layout of the caller provided memory area */ - -struct hostent_info_s -{ - int hi_addrtypes[CONFIG_NETDB_MAX_IPADDR + 1]; - int hi_lengths[CONFIG_NETDB_MAX_IPADDR + 1]; - FAR char *hi_addrlist[CONFIG_NETDB_MAX_IPADDR + 1]; - char hi_data[1]; -}; - -/**************************************************************************** - * Private functions - ****************************************************************************/ - -/**************************************************************************** - * Name: lib_numeric_address - * - * Description: - * Check if the name is a numeric IP address. In this case, simply copy - * name into the h_name field and its struct in_addr equivalent into the - * h_addr_list[0] field of the returned hostent structure. - * - * Input Parameters: - * name - The name of the host to find. - * host - Caller provided location to return the host data. - * buf - Caller provided buffer to hold string data associated with the - * host data. - * buflen - The size of the caller-provided buffer - * - * Returned Value: - * Zero (0) is returned if the name is an numeric IP address. - * - ****************************************************************************/ - -static int lib_numeric_address(FAR const char *name, - FAR struct hostent *host, - FAR char *buf, size_t buflen) -{ - FAR struct hostent_info_s *info; - FAR char *ptr; - socklen_t addrlen; - int namelen; - int ret; - - /* Verify that we have a buffer big enough to get started (it still may not - * be big enough). - */ - - if (buflen <= sizeof(struct hostent_info_s)) - { - return -ERANGE; - } - - info = (FAR struct hostent_info_s *)buf; - ptr = info->hi_data; - buflen -= (sizeof(struct hostent_info_s) - 1); - - memset(host, 0, sizeof(struct hostent)); - memset(info, 0, sizeof(struct hostent_info_s)); - - host->h_addrtypes = info->hi_addrtypes; - host->h_lengths = info->hi_lengths; - host->h_addr_list = info->hi_addrlist; - - /* If the address contains a colon, then it might be a numeric IPv6 - * address - */ - - if (strchr(name, ':') != NULL) - { - /* Make sure that space remains to hold the IPv6 address */ - - addrlen = sizeof(struct in6_addr); - if (buflen < addrlen) - { - return -ERANGE; - } - - ret = inet_pton(AF_INET6, name, ptr); - - /* The inet_pton() function returns 1 if the conversion succeeds. It - * will return 0 if the input is not a valid IP address string, or -1 - * if the address family argument is unsupported. - */ - - if (ret < 1) - { - /* Conversion failed. Must not be a IPv6 address */ - - return 1; - } - - host->h_addrtype = AF_INET6; - } - - /* If the address contains a colon, then it might be a numeric IPv6 - * address. - */ - - else if (strchr(name, '.') != NULL) - { - /* Make sure that space remains to hold the IPv4 address */ - - addrlen = sizeof(struct in_addr); - if (buflen < addrlen) - { - return -ERANGE; - } - - ret = inet_pton(AF_INET, name, ptr); - - /* The inet_pton() function returns 1 if the conversion succeeds. It - * will return 0 if the input is not a valid IP address string, or -1 - * if the address family argument is unsupported. - */ - - if (ret < 1) - { - /* Conversion failed. Must not be an IPv4 address */ - - return 1; - } - - host->h_addrtype = AF_INET; - } - - /* No colon? No period? Can't be a numeric address */ - - else - { - return 1; - } - - host->h_addr = ptr; - host->h_length = addrlen; - - ptr += addrlen; - buflen -= addrlen; - - /* And copy name */ - - namelen = strlen(name); - if ((namelen + 1) > buflen) - { - return -ERANGE; - } - - strncpy(ptr, name, buflen); - - /* Set the address to h_name */ - - host->h_name = ptr; - return 0; -} - -/**************************************************************************** - * Name: lib_localhost - * - * Description: - * Check if the name is the reserved name for the local loopback device. - * - * Input Parameters: - * name - The name of the host to find. - * host - Caller provided location to return the host data. - * buf - Caller provided buffer to hold string data associated with the - * host data. - * buflen - The size of the caller-provided buffer - * - * Returned Value: - * Zero (0) is returned if the name is the loopback device. - * - ****************************************************************************/ - -#ifdef CONFIG_NET_LOOPBACK -static int lib_localhost(FAR const char *name, FAR struct hostent *host, - FAR char *buf, size_t buflen) -{ - FAR struct hostent_info_s *info; - FAR char *dest; - int namelen; - int i = 0; - - if (strcmp(name, g_lo_hostname) == 0) - { - /* Yes.. it is the localhost */ - - /* Make sure that space remains to hold the hostent structure */ - - if (buflen <= sizeof(struct hostent_info_s)) - { - return -ERANGE; - } - - info = (FAR struct hostent_info_s *)buf; - dest = info->hi_data; - buflen -= (sizeof(struct hostent_info_s) - 1); - - memset(host, 0, sizeof(struct hostent)); - memset(info, 0, sizeof(struct hostent_info_s)); - - host->h_addrtypes = info->hi_addrtypes; - host->h_lengths = info->hi_lengths; - host->h_addr_list = info->hi_addrlist; - -#ifdef CONFIG_NET_IPv4 - /* Save the IPv4 address */ - - info->hi_addrtypes[i] = AF_INET; - info->hi_lengths[i] = sizeof(struct in_addr); - info->hi_addrlist[i] = (FAR char *)&g_lo_ipv4addr; - i++; -#endif - -#ifdef CONFIG_NET_IPv6 - /* Save the IPv6 address */ - - info->hi_addrtypes[i] = AF_INET6; - info->hi_lengths[i] = sizeof(struct in6_addr); - info->hi_addrlist[i] = (FAR char *)&g_lo_ipv6addr; - i++; -#endif - - /* And copy name */ - - namelen = strlen(name); - if ((namelen + 1) > buflen) - { - return -ERANGE; - } - - strncpy(dest, name, buflen); - - /* Set the address to h_name */ - - host->h_name = dest; - return 0; - } - - return 1; -} -#endif - -/**************************************************************************** - * Name: lib_find_answer - * - * Description: - * Check if we previously resolved this hostname and if that resolved - * address is already available in the DNS cache. - * - * Input Parameters: - * name - The name of the host to find. - * host - Caller provided location to return the host data. - * buf - Caller provided buffer to hold string data associated with the - * host data. - * buflen - The size of the caller-provided buffer - * - * Returned Value: - * Zero (0) is returned if the DNS lookup was successful. - * - ****************************************************************************/ - -#ifdef CONFIG_NETDB_DNSCLIENT -#if CONFIG_NETDB_DNSCLIENT_ENTRIES > 0 -static int lib_find_answer(FAR const char *name, FAR struct hostent *host, - FAR char *buf, size_t buflen) -{ - FAR struct hostent_info_s *info; - FAR char *ptr; - FAR void *addrdata; - socklen_t addrlen; - int naddr; - int addrtype; - int namelen; - int ret; - int i; - - /* Verify that we have a buffer big enough to get started (it still may not - * be big enough). - */ - - if (buflen <= sizeof(struct hostent_info_s)) - { - return -ERANGE; - } - - /* Initialize buffers */ - - info = (FAR struct hostent_info_s *)buf; - ptr = info->hi_data; - buflen -= (sizeof(struct hostent_info_s) - 1); - - /* Verify again that there is space for at least one address. */ - - if (buflen < sizeof(union dns_addr_u)) - { - return -ERANGE; - } - - memset(host, 0, sizeof(struct hostent)); - memset(info, 0, sizeof(struct hostent_info_s)); - - host->h_addrtypes = info->hi_addrtypes; - host->h_lengths = info->hi_lengths; - host->h_addr_list = info->hi_addrlist; - - /* Try to get the host address using the DNS name server */ - - naddr = buflen / sizeof(union dns_addr_u); - ret = dns_find_answer(name, (FAR union dns_addr_u *)ptr, &naddr); - if (ret < 0) - { - /* No, nothing found in the cache */ - - return ret; - } - - DEBUGASSERT(naddr <= CONFIG_NETDB_MAX_IPADDR); - - /* Get the address type. */ - - for (i = 0; i < naddr; i++) - { -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - if (((FAR struct sockaddr_in *)ptr)->sin_family == AF_INET) -#endif - { - addrlen = sizeof(struct in_addr); - addrtype = AF_INET; - addrdata = &((FAR struct sockaddr_in *)ptr)->sin_addr; - } -#endif - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - else -#endif - { - addrlen = sizeof(struct in6_addr); - addrtype = AF_INET6; - addrdata = &((FAR struct sockaddr_in6 *)ptr)->sin6_addr; - } -#endif - - info->hi_addrtypes[i] = addrtype; - info->hi_lengths[i] = addrlen; - info->hi_addrlist[i] = addrdata; - - ptr += sizeof(union dns_addr_u); - buflen -= sizeof(union dns_addr_u); - } - - /* And copy name */ - - namelen = strlen(name); - if ((namelen + 1) > buflen) - { - return -ERANGE; - } - - strncpy(ptr, name, buflen); - - /* Set the address to h_name */ - - host->h_name = ptr; - return OK; -} -#endif -#endif /* CONFIG_NETDB_DNSCLIENT */ - -/**************************************************************************** - * Name: lib_dns_query - * - * Description: - * Combines the operations of dns_bind(), dns_query(), and dns_free() to - * obtain the IP address ('ipaddr') associated with the 'hostname' in one - * operation. - * - ****************************************************************************/ - -#ifdef CONFIG_NETDB_DNSCLIENT -static int lib_dns_query(FAR const char *hostname, - FAR union dns_addr_u *addr, int *naddr) -{ - int sd; - int ret; - - /* Create and bind a socket to the DNS server */ - - sd = dns_bind(); - if (sd < 0) - { - return sd; - } - - /* Perform the query to get the IP address */ - - ret = dns_query(sd, hostname, addr, naddr); - - /* Release the socket */ - - close(sd); - return ret; -} -#endif /* CONFIG_NETDB_DNSCLIENT */ - -/**************************************************************************** - * Name: lib_dns_lookup - * - * Description: - * Try to look-up the host name from the DNS server - * - * Input Parameters: - * name - The name of the host to find. - * host - Caller provided location to return the host data. - * buf - Caller provided buffer to hold string data associated with the - * host data. - * buflen - The size of the caller-provided buffer - * - * Returned Value: - * Zero (0) is returned if the DNS lookup was successful. - * - ****************************************************************************/ - -#ifdef CONFIG_NETDB_DNSCLIENT -static int lib_dns_lookup(FAR const char *name, FAR struct hostent *host, - FAR char *buf, size_t buflen) -{ - FAR struct hostent_info_s *info; - FAR char *ptr; - FAR void *addrdata; - socklen_t addrlen; - int naddr; - int addrtype; - int namelen; - int ret; - int i; - - /* Verify that we have a buffer big enough to get started (it still may not - * be big enough). - */ - - if (buflen <= sizeof(struct hostent_info_s)) - { - return -ERANGE; - } - - /* Initialize buffers */ - - info = (FAR struct hostent_info_s *)buf; - ptr = info->hi_data; - buflen -= (sizeof(struct hostent_info_s) - 1); - - /* Verify again that there is space for at least one address. */ - - if (buflen < sizeof(union dns_addr_u)) - { - return -ERANGE; - } - - memset(host, 0, sizeof(struct hostent)); - memset(info, 0, sizeof(struct hostent_info_s)); - - host->h_addrtypes = info->hi_addrtypes; - host->h_lengths = info->hi_lengths; - host->h_addr_list = info->hi_addrlist; - - /* Try to get the host address using the DNS name server */ - - naddr = buflen / sizeof(union dns_addr_u); - ret = lib_dns_query(name, (FAR union dns_addr_u *)ptr, &naddr); - if (ret < 0) - { - return ret; - } - - /* We can read more than maximum, limit here. */ - - naddr = MIN(naddr, CONFIG_NETDB_MAX_IPADDR); - - for (i = 0; i < naddr; i++) - { -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - if (((FAR struct sockaddr_in *)ptr)->sin_family == AF_INET) -#endif - { - addrlen = sizeof(struct in_addr); - addrtype = AF_INET; - addrdata = &((FAR struct sockaddr_in *)ptr)->sin_addr; - } -#endif - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - else -#endif - { - addrlen = sizeof(struct in6_addr); - addrtype = AF_INET6; - addrdata = &((FAR struct sockaddr_in6 *)ptr)->sin6_addr; - } -#endif - - info->hi_addrtypes[i] = addrtype; - info->hi_lengths[i] = addrlen; - info->hi_addrlist[i] = addrdata; - - ptr += sizeof(union dns_addr_u); - buflen -= sizeof(union dns_addr_u); - } - - /* And copy name */ - - namelen = strlen(name); - if ((namelen + 1) > buflen) - { - return -ERANGE; - } - - strncpy(ptr, name, buflen); - - /* Set the address to h_name */ - - host->h_name = ptr; - - return OK; -} -#endif /* CONFIG_NETDB_DNSCLIENT */ - -/**************************************************************************** - * Name: lib_hostfile_lookup - * - * Description: - * Try to look-up the host name from the network host file - * - * Input Parameters: - * name - The name of the host to find. - * host - Caller provided location to return the host data. - * buf - Caller provided buffer to hold string data associated with the - * host data. - * buflen - The size of the caller-provided buffer - * - * Returned Value: - * Zero (0) is returned if the host file lookup was successful. - * - ****************************************************************************/ - -#ifdef CONFIG_NETDB_HOSTFILE -static int lib_hostfile_lookup(FAR const char *name, - FAR struct hostent *host, - FAR char *buf, size_t buflen, - FAR int *h_errnop) -{ - FAR FILE *stream; - int herrnocode; - int nread; - - /* Search the hosts file for a match */ - - stream = fopen(CONFIG_NETDB_HOSTCONF_PATH, "r"); - if (stream == NULL) - { - int errcode = -errno; - - nerr("ERROR: Failed to open the hosts file %s: %d\n", - CONFIG_NETDB_HOSTCONF_PATH, errcode); - UNUSED(errcode); - - herrnocode = NO_RECOVERY; - goto errorout_with_herrnocode; - } - - /* Loop reading entries from the hosts file until a match is found or - * until we hit the end-of-file. - */ - - do - { - /* Read the next entry from the hosts file */ - - nread = lib_parse_hostfile(stream, host, buf, buflen); - if (nread < 0) - { - /* Possible errors: - * ERANGE - Buffer not big enough - * ESPIPE - End of file (or possibly a read error). - * EAGAIN - Error parsing the line (E.g., missing hostname) - */ - - if (nread == -ESPIPE) - { - nread = 0; - } - else if (nread != -EAGAIN) - { - herrnocode = NO_RECOVERY; - goto errorout_with_stream; - } - } - else if (nread > 0) - { - /* We successfully read the entry */ - - ninfo("Comparing %s to %s\n", name, host->h_name); - - /* Check for a host name match */ - - if (strcmp(name, host->h_name) == 0) - { - /* We have a match */ - - fclose(stream); - return OK; - } - - /* For a match with any host alias */ - - if (host->h_aliases != NULL) - { - FAR char **alias; - - for (alias = host->h_aliases; *alias != NULL; alias++) - { - /* Check for a host alias match */ - - if (strcmp(name, *alias) == 0) - { - /* We have a match */ - - fclose(stream); - return OK; - } - } - } - } - } - while (nread != 0); - - /* We get here when the end of the hosts file is encountered without - * finding the hostname. - */ - - herrnocode = HOST_NOT_FOUND; - -errorout_with_stream: - fclose(stream); - -errorout_with_herrnocode: - if (h_errnop) - { - *h_errnop = herrnocode; - } - - return ERROR; -} -#endif /* CONFIG_NETDB_HOSTFILE */ - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -747,6 +70,7 @@ errorout_with_herrnocode: * buf - Caller provided buffer to hold string data associated with the * host data. * buflen - The size of the caller-provided buffer + * result - There host entry returned in the event of a success. * h_errnop - There h_errno value returned in the event of a failure. * * Returned Value: @@ -755,79 +79,13 @@ errorout_with_herrnocode: * ****************************************************************************/ -int gethostbyname_r(FAR const char *name, FAR struct hostent *host, - FAR char *buf, size_t buflen, int *h_errnop) +int gethostbyname_r(FAR const char *name, + FAR struct hostent *host, FAR char *buf, + size_t buflen, FAR struct hostent **result, + FAR int *h_errnop) { - DEBUGASSERT(name != NULL && host != NULL && buf != NULL); - - /* Make sure that the h_errno has a non-error code */ - - if (h_errnop) - { - *h_errnop = 0; - } - - /* Check for a numeric hostname */ - - if (lib_numeric_address(name, host, buf, buflen) == 0) - { - /* Yes.. we are done */ - - return OK; - } - -#ifdef CONFIG_NET_LOOPBACK - /* Check for the local loopback host name */ - - if (lib_localhost(name, host, buf, buflen) == 0) - { - /* Yes.. we are done */ - - return OK; - } -#endif - - /* Try to find the name in the HOSTALIASES environment variable */ - -#ifdef CONFIG_NETDB_DNSCLIENT -#if CONFIG_NETDB_DNSCLIENT_ENTRIES > 0 - /* Check if we already have this hostname mapping cached */ - - if (lib_find_answer(name, host, buf, buflen) >= 0) - { - /* Found the address mapping in the cache */ - - return OK; - } -#endif - - /* Try to get the host address using the DNS name server */ - - if (lib_dns_lookup(name, host, buf, buflen) >= 0) - { - /* Successful DNS lookup! */ - - return OK; - } -#endif /* CONFIG_NETDB_DNSCLIENT */ - -#ifdef CONFIG_NETDB_HOSTFILE - /* Search the hosts file for a match */ - - return lib_hostfile_lookup(name, host, buf, buflen, h_errnop); - -#else - /* The host file file is not supported. The host name mapping was not - * found from any lookup heuristic - */ - - if (h_errnop) - { - *h_errnop = HOST_NOT_FOUND; - } - - return ERROR; -#endif + return gethostbyname2_r(name, AF_UNSPEC, + host, buf, buflen, result, h_errnop); } #endif /* CONFIG_LIBC_NETDB */ diff --git a/libs/libc/netdb/lib_gethostentbynamer.c b/libs/libc/netdb/lib_gethostentbynamer.c new file mode 100644 index 00000000000..8c21930e9f5 --- /dev/null +++ b/libs/libc/netdb/lib_gethostentbynamer.c @@ -0,0 +1,815 @@ +/**************************************************************************** + * libs/libc/netdb/lib_gethostentbynamer.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "netdb/lib_dns.h" +#include "netdb/lib_netdb.h" + +#ifdef CONFIG_LIBC_NETDB + +/**************************************************************************** + * Private Type Definitions + ****************************************************************************/ + +/* This is the layout of the caller provided memory area */ + +struct hostent_info_s +{ + int hi_addrtypes[CONFIG_NETDB_MAX_IPADDR + 1]; + int hi_lengths[CONFIG_NETDB_MAX_IPADDR + 1]; + FAR char *hi_addrlist[CONFIG_NETDB_MAX_IPADDR + 1]; + char hi_data[1]; +}; + +/**************************************************************************** + * Private functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lib_numeric_address + * + * Description: + * Check if the name is a numeric IP address. In this case, simply copy + * name into the h_name field and its struct in_addr equivalent into the + * h_addr_list[0] field of the returned hostent structure. + * + * Input Parameters: + * name - The name of the host to find. + * host - Caller provided location to return the host data. + * buf - Caller provided buffer to hold string data associated with the + * host data. + * buflen - The size of the caller-provided buffer + * + * Returned Value: + * Zero (0) is returned if the name is an numeric IP address. + * + ****************************************************************************/ + +static int lib_numeric_address(FAR const char *name, + FAR struct hostent_s *host, + FAR char *buf, size_t buflen) +{ + FAR struct hostent_info_s *info; + FAR char *ptr; + socklen_t addrlen; + int namelen; + int ret; + + /* Verify that we have a buffer big enough to get started (it still may not + * be big enough). + */ + + if (buflen <= sizeof(struct hostent_info_s)) + { + return -ERANGE; + } + + info = (FAR struct hostent_info_s *)buf; + ptr = info->hi_data; + buflen -= (sizeof(struct hostent_info_s) - 1); + + memset(host, 0, sizeof(struct hostent_s)); + memset(info, 0, sizeof(struct hostent_info_s)); + + host->h_addrtypes = info->hi_addrtypes; + host->h_lengths = info->hi_lengths; + host->h_addr_list = info->hi_addrlist; + + /* If the address contains a colon, then it might be a numeric IPv6 + * address + */ + + if (strchr(name, ':') != NULL) + { + /* Make sure that space remains to hold the IPv6 address */ + + addrlen = sizeof(struct in6_addr); + if (buflen < addrlen) + { + return -ERANGE; + } + + ret = inet_pton(AF_INET6, name, ptr); + + /* The inet_pton() function returns 1 if the conversion succeeds. It + * will return 0 if the input is not a valid IP address string, or -1 + * if the address family argument is unsupported. + */ + + if (ret < 1) + { + /* Conversion failed. Must not be a IPv6 address */ + + return 1; + } + + host->h_addrtypes[0] = AF_INET6; + } + + /* If the address contains a colon, then it might be a numeric IPv6 + * address. + */ + + else if (strchr(name, '.') != NULL) + { + /* Make sure that space remains to hold the IPv4 address */ + + addrlen = sizeof(struct in_addr); + if (buflen < addrlen) + { + return -ERANGE; + } + + ret = inet_pton(AF_INET, name, ptr); + + /* The inet_pton() function returns 1 if the conversion succeeds. It + * will return 0 if the input is not a valid IP address string, or -1 + * if the address family argument is unsupported. + */ + + if (ret < 1) + { + /* Conversion failed. Must not be an IPv4 address */ + + return 1; + } + + host->h_addrtypes[0] = AF_INET; + } + + /* No colon? No period? Can't be a numeric address */ + + else + { + return 1; + } + + host->h_addr_list[0] = ptr; + host->h_lengths[0] = addrlen; + + ptr += addrlen; + buflen -= addrlen; + + /* And copy name */ + + namelen = strlen(name); + if ((namelen + 1) > buflen) + { + return -ERANGE; + } + + strncpy(ptr, name, buflen); + + /* Set the address to h_name */ + + host->h_name = ptr; + return 0; +} + +/**************************************************************************** + * Name: lib_localhost + * + * Description: + * Check if the name is the reserved name for the local loopback device. + * + * Input Parameters: + * name - The name of the host to find. + * host - Caller provided location to return the host data. + * buf - Caller provided buffer to hold string data associated with the + * host data. + * buflen - The size of the caller-provided buffer + * + * Returned Value: + * Zero (0) is returned if the name is the loopback device. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_LOOPBACK +static int lib_localhost(FAR const char *name, FAR struct hostent_s *host, + FAR char *buf, size_t buflen) +{ + FAR struct hostent_info_s *info; + FAR char *dest; + int namelen; + int i = 0; + + if (strcmp(name, g_lo_hostname) == 0) + { + /* Yes.. it is the localhost */ + + /* Make sure that space remains to hold the hostent structure */ + + if (buflen <= sizeof(struct hostent_info_s)) + { + return -ERANGE; + } + + info = (FAR struct hostent_info_s *)buf; + dest = info->hi_data; + buflen -= (sizeof(struct hostent_info_s) - 1); + + memset(host, 0, sizeof(struct hostent_s)); + memset(info, 0, sizeof(struct hostent_info_s)); + + host->h_addrtypes = info->hi_addrtypes; + host->h_lengths = info->hi_lengths; + host->h_addr_list = info->hi_addrlist; + +#ifdef CONFIG_NET_IPv4 + /* Save the IPv4 address */ + + info->hi_addrtypes[i] = AF_INET; + info->hi_lengths[i] = sizeof(struct in_addr); + info->hi_addrlist[i] = (FAR char *)&g_lo_ipv4addr; + i++; +#endif + +#ifdef CONFIG_NET_IPv6 + /* Save the IPv6 address */ + + info->hi_addrtypes[i] = AF_INET6; + info->hi_lengths[i] = sizeof(struct in6_addr); + info->hi_addrlist[i] = (FAR char *)&g_lo_ipv6addr; + i++; +#endif + + /* And copy name */ + + namelen = strlen(name); + if ((namelen + 1) > buflen) + { + return -ERANGE; + } + + strncpy(dest, name, buflen); + + /* Set the address to h_name */ + + host->h_name = dest; + return 0; + } + + return 1; +} +#endif + +/**************************************************************************** + * Name: lib_find_answer + * + * Description: + * Check if we previously resolved this hostname and if that resolved + * address is already available in the DNS cache. + * + * Input Parameters: + * name - The name of the host to find. + * host - Caller provided location to return the host data. + * buf - Caller provided buffer to hold string data associated with the + * host data. + * buflen - The size of the caller-provided buffer + * + * Returned Value: + * Zero (0) is returned if the DNS lookup was successful. + * + ****************************************************************************/ + +#ifdef CONFIG_NETDB_DNSCLIENT +#if CONFIG_NETDB_DNSCLIENT_ENTRIES > 0 +static int lib_find_answer(FAR const char *name, FAR struct hostent_s *host, + FAR char *buf, size_t buflen) +{ + FAR struct hostent_info_s *info; + FAR char *ptr; + FAR void *addrdata; + socklen_t addrlen; + int naddr; + int addrtype; + int namelen; + int ret; + int i; + + /* Verify that we have a buffer big enough to get started (it still may not + * be big enough). + */ + + if (buflen <= sizeof(struct hostent_info_s)) + { + return -ERANGE; + } + + /* Initialize buffers */ + + info = (FAR struct hostent_info_s *)buf; + ptr = info->hi_data; + buflen -= (sizeof(struct hostent_info_s) - 1); + + /* Verify again that there is space for at least one address. */ + + if (buflen < sizeof(union dns_addr_u)) + { + return -ERANGE; + } + + memset(host, 0, sizeof(struct hostent_s)); + memset(info, 0, sizeof(struct hostent_info_s)); + + host->h_addrtypes = info->hi_addrtypes; + host->h_lengths = info->hi_lengths; + host->h_addr_list = info->hi_addrlist; + + /* Try to get the host address using the DNS name server */ + + naddr = buflen / sizeof(union dns_addr_u); + ret = dns_find_answer(name, (FAR union dns_addr_u *)ptr, &naddr); + if (ret < 0) + { + /* No, nothing found in the cache */ + + return ret; + } + + DEBUGASSERT(naddr <= CONFIG_NETDB_MAX_IPADDR); + + /* Get the address type. */ + + for (i = 0; i < naddr; i++) + { +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if (((FAR struct sockaddr_in *)ptr)->sin_family == AF_INET) +#endif + { + addrlen = sizeof(struct in_addr); + addrtype = AF_INET; + addrdata = &((FAR struct sockaddr_in *)ptr)->sin_addr; + } +#endif + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { + addrlen = sizeof(struct in6_addr); + addrtype = AF_INET6; + addrdata = &((FAR struct sockaddr_in6 *)ptr)->sin6_addr; + } +#endif + + info->hi_addrtypes[i] = addrtype; + info->hi_lengths[i] = addrlen; + info->hi_addrlist[i] = addrdata; + + ptr += sizeof(union dns_addr_u); + buflen -= sizeof(union dns_addr_u); + } + + /* And copy name */ + + namelen = strlen(name); + if ((namelen + 1) > buflen) + { + return -ERANGE; + } + + strncpy(ptr, name, buflen); + + /* Set the address to h_name */ + + host->h_name = ptr; + return OK; +} +#endif +#endif /* CONFIG_NETDB_DNSCLIENT */ + +/**************************************************************************** + * Name: lib_dns_query + * + * Description: + * Combines the operations of dns_bind(), dns_query(), and dns_free() to + * obtain the IP address ('ipaddr') associated with the 'hostname' in one + * operation. + * + ****************************************************************************/ + +#ifdef CONFIG_NETDB_DNSCLIENT +static int lib_dns_query(FAR const char *hostname, + FAR union dns_addr_u *addr, int *naddr) +{ + int sd; + int ret; + + /* Create and bind a socket to the DNS server */ + + sd = dns_bind(); + if (sd < 0) + { + return sd; + } + + /* Perform the query to get the IP address */ + + ret = dns_query(sd, hostname, addr, naddr); + + /* Release the socket */ + + close(sd); + return ret; +} +#endif /* CONFIG_NETDB_DNSCLIENT */ + +/**************************************************************************** + * Name: lib_dns_lookup + * + * Description: + * Try to look-up the host name from the DNS server + * + * Input Parameters: + * name - The name of the host to find. + * host - Caller provided location to return the host data. + * buf - Caller provided buffer to hold string data associated with the + * host data. + * buflen - The size of the caller-provided buffer + * + * Returned Value: + * Zero (0) is returned if the DNS lookup was successful. + * + ****************************************************************************/ + +#ifdef CONFIG_NETDB_DNSCLIENT +static int lib_dns_lookup(FAR const char *name, FAR struct hostent_s *host, + FAR char *buf, size_t buflen) +{ + FAR struct hostent_info_s *info; + FAR char *ptr; + FAR void *addrdata; + socklen_t addrlen; + int naddr; + int addrtype; + int namelen; + int ret; + int i; + + /* Verify that we have a buffer big enough to get started (it still may not + * be big enough). + */ + + if (buflen <= sizeof(struct hostent_info_s)) + { + return -ERANGE; + } + + /* Initialize buffers */ + + info = (FAR struct hostent_info_s *)buf; + ptr = info->hi_data; + buflen -= (sizeof(struct hostent_info_s) - 1); + + /* Verify again that there is space for at least one address. */ + + if (buflen < sizeof(union dns_addr_u)) + { + return -ERANGE; + } + + memset(host, 0, sizeof(struct hostent_s)); + memset(info, 0, sizeof(struct hostent_info_s)); + + host->h_addrtypes = info->hi_addrtypes; + host->h_lengths = info->hi_lengths; + host->h_addr_list = info->hi_addrlist; + + /* Try to get the host address using the DNS name server */ + + naddr = buflen / sizeof(union dns_addr_u); + ret = lib_dns_query(name, (FAR union dns_addr_u *)ptr, &naddr); + if (ret < 0) + { + return ret; + } + + /* We can read more than maximum, limit here. */ + + naddr = MIN(naddr, CONFIG_NETDB_MAX_IPADDR); + + for (i = 0; i < naddr; i++) + { +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if (((FAR struct sockaddr_in *)ptr)->sin_family == AF_INET) +#endif + { + addrlen = sizeof(struct in_addr); + addrtype = AF_INET; + addrdata = &((FAR struct sockaddr_in *)ptr)->sin_addr; + } +#endif + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { + addrlen = sizeof(struct in6_addr); + addrtype = AF_INET6; + addrdata = &((FAR struct sockaddr_in6 *)ptr)->sin6_addr; + } +#endif + + info->hi_addrtypes[i] = addrtype; + info->hi_lengths[i] = addrlen; + info->hi_addrlist[i] = addrdata; + + ptr += sizeof(union dns_addr_u); + buflen -= sizeof(union dns_addr_u); + } + + /* And copy name */ + + namelen = strlen(name); + if ((namelen + 1) > buflen) + { + return -ERANGE; + } + + strncpy(ptr, name, buflen); + + /* Set the address to h_name */ + + host->h_name = ptr; + + return OK; +} +#endif /* CONFIG_NETDB_DNSCLIENT */ + +/**************************************************************************** + * Name: lib_hostfile_lookup + * + * Description: + * Try to look-up the host name from the network host file + * + * Input Parameters: + * name - The name of the host to find. + * host - Caller provided location to return the host data. + * buf - Caller provided buffer to hold string data associated with the + * host data. + * buflen - The size of the caller-provided buffer + * + * Returned Value: + * Zero (0) is returned if the host file lookup was successful. + * + ****************************************************************************/ + +#ifdef CONFIG_NETDB_HOSTFILE +static int lib_hostfile_lookup(FAR const char *name, + FAR struct hostent_s *host, FAR char *buf, + size_t buflen, FAR int *h_errnop) +{ + FAR FILE *stream; + int herrnocode; + int nread; + + /* Search the hosts file for a match */ + + stream = fopen(CONFIG_NETDB_HOSTCONF_PATH, "r"); + if (stream == NULL) + { + int errcode = -errno; + + nerr("ERROR: Failed to open the hosts file %s: %d\n", + CONFIG_NETDB_HOSTCONF_PATH, errcode); + UNUSED(errcode); + + herrnocode = NO_RECOVERY; + goto errorout_with_herrnocode; + } + + /* Loop reading entries from the hosts file until a match is found or + * until we hit the end-of-file. + */ + + do + { + /* Read the next entry from the hosts file */ + + nread = parse_hostfile(stream, host, buf, buflen); + if (nread < 0) + { + /* Possible errors: + * ERANGE - Buffer not big enough + * ESPIPE - End of file (or possibly a read error). + * EAGAIN - Error parsing the line (E.g., missing hostname) + */ + + if (nread == -ESPIPE) + { + nread = 0; + } + else if (nread != -EAGAIN) + { + herrnocode = NO_RECOVERY; + goto errorout_with_stream; + } + } + else if (nread > 0) + { + /* We successfully read the entry */ + + ninfo("Comparing %s to %s\n", name, host->h_name); + + /* Check for a host name match */ + + if (strcmp(name, host->h_name) == 0) + { + /* We have a match */ + + fclose(stream); + return OK; + } + + /* For a match with any host alias */ + + if (host->h_aliases != NULL) + { + FAR char **alias; + + for (alias = host->h_aliases; *alias != NULL; alias++) + { + /* Check for a host alias match */ + + if (strcmp(name, *alias) == 0) + { + /* We have a match */ + + fclose(stream); + return OK; + } + } + } + } + } + while (nread != 0); + + /* We get here when the end of the hosts file is encountered without + * finding the hostname. + */ + + herrnocode = HOST_NOT_FOUND; + +errorout_with_stream: + fclose(stream); + +errorout_with_herrnocode: + if (h_errnop) + { + *h_errnop = herrnocode; + } + + return ERROR; +} +#endif /* CONFIG_NETDB_HOSTFILE */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: gethostentbyname_r + * + * Description: + * The gethostentbyname_r() function returns a structure of type hostent_s + * for the given host name. Here name is either a hostname, or an IPv4 + * address in standard dot notation (as for inet_addr(3)), or an IPv6 + * address in colon (and possibly dot) notation. + * + * If name is an IPv4 or IPv6 address, no lookup is performed and + * gethostentbyname_r() simply copies name into the h_name field + * and its struct in_addr equivalent into the h_addr_list[0] field of the + * returned hostent structure. + * + * Input Parameters: + * name - The name of the host to find. + * host - Caller provided location to return the host data. + * buf - Caller provided buffer to hold string data associated with the + * host data. + * buflen - The size of the caller-provided buffer + * h_errnop - There h_errno value returned in the event of a failure. + * + * Returned Value: + * Zero (OK) is returned on success, -1 (ERROR) is returned on a failure + * with the returned h_errno value provided the reason for the failure. + * + ****************************************************************************/ + +int gethostentbyname_r(FAR const char *name, + FAR struct hostent_s *host, FAR char *buf, + size_t buflen, FAR int *h_errnop) +{ + DEBUGASSERT(name != NULL && host != NULL && buf != NULL); + + /* Make sure that the h_errno has a non-error code */ + + if (h_errnop) + { + *h_errnop = 0; + } + + /* Check for a numeric hostname */ + + if (lib_numeric_address(name, host, buf, buflen) == 0) + { + /* Yes.. we are done */ + + return OK; + } + +#ifdef CONFIG_NET_LOOPBACK + /* Check for the local loopback host name */ + + if (lib_localhost(name, host, buf, buflen) == 0) + { + /* Yes.. we are done */ + + return OK; + } +#endif + + /* Try to find the name in the HOSTALIASES environment variable */ + +#ifdef CONFIG_NETDB_DNSCLIENT +#if CONFIG_NETDB_DNSCLIENT_ENTRIES > 0 + /* Check if we already have this hostname mapping cached */ + + if (lib_find_answer(name, host, buf, buflen) >= 0) + { + /* Found the address mapping in the cache */ + + return OK; + } +#endif + + /* Try to get the host address using the DNS name server */ + + if (lib_dns_lookup(name, host, buf, buflen) >= 0) + { + /* Successful DNS lookup! */ + + return OK; + } +#endif /* CONFIG_NETDB_DNSCLIENT */ + +#ifdef CONFIG_NETDB_HOSTFILE + /* Search the hosts file for a match */ + + return lib_hostfile_lookup(name, host, buf, buflen, h_errnop); + +#else + /* The host file file is not supported. The host name mapping was not + * found from any lookup heuristic + */ + + if (h_errnop) + { + *h_errnop = HOST_NOT_FOUND; + } + + return ERROR; +#endif +} + +#endif /* CONFIG_LIBC_NETDB */ diff --git a/libs/libc/netdb/lib_getnameinfo.c b/libs/libc/netdb/lib_getnameinfo.c index 31ad660fcfb..d31b592adf3 100644 --- a/libs/libc/netdb/lib_getnameinfo.c +++ b/libs/libc/netdb/lib_getnameinfo.c @@ -46,7 +46,6 @@ #include #include -#include "libc.h" #include "netdb/lib_netdb.h" #ifdef CONFIG_LIBC_NETDB @@ -98,22 +97,23 @@ int getnameinfo(FAR const struct sockaddr *addr, socklen_t addrlen, if (host && !(flags & NI_NUMERICHOST)) { struct hostent hostent; + FAR struct hostent *res; int h_errno; ret = gethostbyaddr_r(saddr, saddr_len, addr->sa_family, &hostent, - host, hostlen, &h_errno); + host, hostlen, &res, &h_errno); if (ret == OK) { - size_t sz = strlen(hostent.h_name) + 1; + size_t sz = strlen(res->h_name) + 1; if (sz <= hostlen) { - memmove(host, hostent.h_name, sz); + memmove(host, res->h_name, sz); } else { - memmove(host, hostent.h_name, hostlen); + memmove(host, res->h_name, hostlen); host[hostlen - 1] = '\0'; } } diff --git a/libs/libc/netdb/lib_getservbyname.c b/libs/libc/netdb/lib_getservbyname.c index a8ac68be511..7187b700b8e 100644 --- a/libs/libc/netdb/lib_getservbyname.c +++ b/libs/libc/netdb/lib_getservbyname.c @@ -55,7 +55,7 @@ FAR struct servent *getservbyname(FAR const char *name, FAR const char *proto) { static struct servent ent; - struct servent *res; + FAR struct servent *res; int ret; ret = getservbyname_r(name, proto, &ent, NULL, 0, &res); diff --git a/libs/libc/netdb/lib_getservbyport.c b/libs/libc/netdb/lib_getservbyport.c index b0ecf5ae7d5..02930fad8c5 100644 --- a/libs/libc/netdb/lib_getservbyport.c +++ b/libs/libc/netdb/lib_getservbyport.c @@ -58,7 +58,7 @@ FAR struct servent *getservbyport(int port, FAR const char *proto) { static struct servent ent; - struct servent *res; + FAR struct servent *res; int ret; ret = getservbyport_r(port, proto, &ent, NULL, 0, &res); diff --git a/libs/libc/netdb/lib_netdb.c b/libs/libc/netdb/lib_netdb.c index c90e80a3484..f93b30a9b52 100644 --- a/libs/libc/netdb/lib_netdb.c +++ b/libs/libc/netdb/lib_netdb.c @@ -63,4 +63,49 @@ int h_errno; * Public Functions ****************************************************************************/ +bool convert_hostent(const FAR struct hostent_s *in, + int type, FAR struct hostent *out) +{ + int i; + int j; + + /* Initialize the ouptut of hostent */ + + out->h_name = in->h_name; + out->h_aliases = in->h_aliases; + if (type != AF_UNSPEC) + { + out->h_addrtype = type; + if (type == AF_INET) + { + out->h_length = sizeof(struct in_addr); + } + else + { + out->h_length = sizeof(struct in6_addr); + } + } + else + { + type = in->h_addrtypes[0]; + out->h_addrtype = in->h_addrtypes[0]; + out->h_length = in->h_lengths[0]; + } + + out->h_addr_list = in->h_addr_list; + + /* Remove different type from list */ + + for (i = j = 0; in->h_addr_list[i]; i++) + { + if (type == in->h_addrtypes[i]) + { + in->h_addr_list[j++] = in->h_addr_list[i]; + } + } + + in->h_addr_list[j] = NULL; + return j != 0; +} + #endif /* CONFIG_LIBC_NETDB */ diff --git a/libs/libc/netdb/lib_netdb.h b/libs/libc/netdb/lib_netdb.h index f29e4d64afe..ce025201dbf 100644 --- a/libs/libc/netdb/lib_netdb.h +++ b/libs/libc/netdb/lib_netdb.h @@ -43,6 +43,7 @@ #include #include +#include #ifdef CONFIG_LIBC_NETDB @@ -78,6 +79,20 @@ * Public Types ****************************************************************************/ +struct hostent_s +{ + FAR char *h_name; /* Official name of the host. */ + FAR char **h_aliases; /* A pointer to an array of pointers to the + * alternative host names, terminated by a + * null pointer. */ + FAR int *h_addrtypes; /* A pointer to an array of address type. */ + FAR int *h_lengths; /* A pointer to an array of the length, in bytes, + * of the address. */ + FAR 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. */ +}; + struct services_db_s { FAR const char *s_name; @@ -105,6 +120,16 @@ EXTERN const struct services_db_s g_services_db[]; * Public Function Prototypes ****************************************************************************/ +bool convert_hostent(const FAR struct hostent_s *in, + int type, FAR struct hostent *out); + +ssize_t parse_hostfile(FAR FILE *stream, FAR struct hostent_s *host, + FAR char *buf, size_t buflen); + +int gethostentbyname_r(FAR const char *name, + FAR struct hostent_s *host, FAR char *buf, + size_t buflen, FAR int *h_errnop); + #undef EXTERN #ifdef __cplusplus } diff --git a/libs/libc/netdb/lib_parsehostfile.c b/libs/libc/netdb/lib_parsehostfile.c index d48f9a92dd7..4507b8c091c 100644 --- a/libs/libc/netdb/lib_parsehostfile.c +++ b/libs/libc/netdb/lib_parsehostfile.c @@ -50,7 +50,7 @@ #include -#include "libc.h" +#include "lib_netdb.h" #ifdef CONFIG_NETDB_HOSTFILE @@ -72,8 +72,8 @@ struct hostent_info_s { FAR char *hi_aliases[CONFIG_NETDB_MAX_ALTNAMES + 1]; - int hi_addrtypes[2]; - int hi_lengths[2]; + int hi_addrtypes[1]; + int hi_lengths[1]; FAR char *hi_addrlist[2]; char hi_data[1]; }; @@ -239,7 +239,7 @@ static ssize_t lib_copystring(FAR FILE *stream, FAR char *ptr, ****************************************************************************/ /**************************************************************************** - * Name: lib_parse_hostfile + * Name: parse_hostfile * * Description: * Parse the next line from the hosts file. @@ -264,8 +264,8 @@ static ssize_t lib_copystring(FAR FILE *stream, FAR char *ptr, * ****************************************************************************/ -ssize_t lib_parse_hostfile(FAR FILE *stream, FAR struct hostent *host, - FAR char *buf, size_t buflen) +ssize_t parse_hostfile(FAR FILE *stream, FAR struct hostent_s *host, + FAR char *buf, size_t buflen) { FAR struct hostent_info_s *info; FAR char addrstring[48]; @@ -291,7 +291,7 @@ ssize_t lib_parse_hostfile(FAR FILE *stream, FAR struct hostent *host, ptr = info->hi_data; buflen -= (sizeof(struct hostent_info_s) - 1); - memset(host, 0, sizeof(struct hostent)); + memset(host, 0, sizeof(struct hostent_s)); memset(info, 0, sizeof(struct hostent_info_s)); host->h_addrtypes = info->hi_addrtypes; @@ -361,7 +361,7 @@ ssize_t lib_parse_hostfile(FAR FILE *stream, FAR struct hostent *host, return -EAGAIN; } - host->h_addrtype = AF_INET6; + host->h_addrtypes[0] = AF_INET6; } else { @@ -382,14 +382,14 @@ ssize_t lib_parse_hostfile(FAR FILE *stream, FAR struct hostent *host, return -EAGAIN; } - host->h_addrtype = AF_INET; + host->h_addrtypes[0] = AF_INET; } - host->h_addr = ptr; - host->h_length = addrlen; + host->h_addr_list[0] = ptr; + host->h_lengths[0] = addrlen; - ptr += addrlen; - buflen -= addrlen; + ptr += addrlen; + buflen -= addrlen; /* Skip over any additional whitespace */