libc: Add gethostbyname(). Untested on initial commit

This commit is contained in:
Gregory Nutt 2015-07-08 13:40:52 -06:00
parent f94fe747ae
commit 1b1e34e1d5
7 changed files with 1007 additions and 31 deletions

View File

@ -156,6 +156,27 @@
#define EAI_SYSTEM 8
#define EAI_OVERFLOW 9
/* h_errno values that may be returned by gethosbyname(), gethostbyname_r(),
* gethostbyaddr(), or gethostbyaddr_r()
*
* HOST_NOT_FOUND - No such host is known.
*
* NO_DATA - The server recognized the request and the name, but no
* address is available. Another type of request to the name server
* for the domain might return an answer.
*
* NO_RECOVERY - An unexpected server failure occurred which cannot be
* recovered.
*
* TRY_AGAIN - A temporary and possibly transient error occurred, such as
* a failure of a server to respond.
*/
#define HOST_NOT_FOUND 1
#define NO_DATA 2
#define NO_RECOVERY 3
#define TRY_AGAIN 4
/****************************************************************************
* Public Types
****************************************************************************/
@ -215,7 +236,7 @@ struct addrinfo
FAR struct sockaddr *ai_addr; /* Socket address of socket. */
FAR char *ai_canonname; /* Canonical name of service location. */
sFAR truct addrinfo *ai_next; /* Pointer to next in list. */
FAR struct addrinfo *ai_next; /* Pointer to next in list. */
};
/****************************************************************************
@ -235,12 +256,14 @@ extern "C"
* macro or an identifier declared with external linkage.
*/
/* To be provided */
/* REVISIT: This should at least be per-task? */
EXTERN int h_errno;
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifdef CONFIG_LIB_NETDB
#if 0 /* None of these are yet supported */
void endhostent(void);
@ -248,26 +271,30 @@ void endnetent(void);
void endprotoent(void);
void endservent(void);
void freeaddrinfo(FAR struct addrinfo *);
const char *gai_strerror(int);
FAR const char *gai_strerror(int);
int getaddrinfo(FAR const char *restrict,
FAR const char *restrict,
FAR const struct addrinfo *restrict,
FAR struct addrinfo **restrict);
struct hostent *gethostbyaddr(FAR const void *, socklen_t, int);
struct hostent *gethostbyname(FAR const char *);
struct hostent *gethostent(void);
FAR struct hostent *gethostbyaddr(FAR const void *, socklen_t, int);
#endif
FAR struct hostent *gethostbyname(FAR const char *);
#if 0 /* None of these are yet supported */
FAR struct hostent *gethostent(void);
int getnameinfo(FAR const struct sockaddr *restrict, socklen_t,
FAR char *restrict, socklen_t, FAR char *restrict,
socklen_t, int);
struct netent *getnetbyaddr(uint32_t, int);
struct netent *getnetbyname(FAR const char *);
struct netent *getnetent(void);
struct protoent *getprotobyname(FAR const char *);
struct protoent *getprotobynumber(int);
struct protoent *getprotoent(void);
struct servent *getservbyname(FAR const char *, FAR const char *);
struct servent *getservbyport(int, FAR const char *);
struct servent *getservent(void);
FAR struct netent *getnetbyaddr(uint32_t, int);
FAR struct netent *getnetbyname(FAR const char *);
FAR struct netent *getnetent(void);
FAR struct protoent *getprotobyname(FAR const char *);
FAR struct protoent *getprotobynumber(int);
FAR struct protoent *getprotoent(void);
FAR struct servent *getservbyname(FAR const char *, FAR const char *);
FAR struct servent *getservbyport(int, FAR const char *);
FAR struct servent *getservent(void);
void sethostent(int);
void setnetent(int);
void setprotoent(int);
@ -275,6 +302,13 @@ void setservent(int);
#endif /* None of these are yet supported */
/* Non-standard interfaces similar to Glibc 2 interfaces */
int gethostbyname_r(FAR const char *name, FAR struct hostent *host,
FAR char *buf, size_t buflen, int *h_errnop);
#endif /* CONFIG_LIB_NETDB */
#undef EXTERN
#ifdef __cplusplus
}

View File

@ -504,6 +504,27 @@ config ARCH_BZERO
endif # ARCH_OPTIMIZED_FUNCTIONS
menuconfig LIB_NETDB
bool "Network database support"
default n
depends on FS_READABLE
if LIB_NETDB
config NETDB_HOSTCONF_PATH
string "Path to host configuration file"
default "/etc/hosts"
config NETDB_MAX_ALTNAMES
int "Max number of alternate host names"
default 4
config NETDB_BUFSIZE
int "gethostname() buffer size"
default 128
endif # LIB_NETDB
comment "Non-standard Library Support"
if BUILD_PROTECTED || BUILD_KERNEL

View File

@ -216,6 +216,13 @@ double lib_expi(size_t n);
float lib_sqrtapprox(float x);
#endif
/* Defined in lib_parsehostfile.c */
#ifdef CONFIG_LIB_NETDB
ssize_t lib_parse_hostfile(FAR FILE *stream, FAR struct hostent *host,
FAR char *buf, size_t buflen);
#endif
#undef EXTERN
#if defined(__cplusplus)
}

View File

@ -44,6 +44,12 @@ ifeq ($(CONFIG_NET_ROUTE),y)
CSRCS += lib_addroute.c lib_delroute.c
endif
# netdb support
ifeq ($(CONFIG_LIB_NETDB),y)
CSRCS += lib_gethostbyname.c lib_gethostbynamer.c lib_parsehostfile.c
endif
# Add the net directory to the build
DEPPATH += --dep-path net

View File

@ -0,0 +1,106 @@
/****************************************************************************
* net/netdb/lib_gethostbyname.c
*
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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
* COPYRIGHT OWNER OR CONTRIBUTORS 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <netdb.h>
#include <errno.h>
#include "lib_internal.h"
#ifdef CONFIG_LIB_NETDB
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef CONFIG_NETDB_BUFSIZE
# define CONFIG_NETDB_BUFSIZE 128
#endif
/****************************************************************************
* Private Data
****************************************************************************/
static struct hostent g_hostent;
static char g_hostbuffer[CONFIG_NETDB_BUFSIZE];
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: gethostname
*
* Description:
* The gethostbyname() 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
* gethostbyname_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.
*
* 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, gethostbyname() will set h_errno to
* indicate the error
*
****************************************************************************/
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;
}
#endif /* CONFIG_LIB_NETDB */

View File

@ -0,0 +1,345 @@
/****************************************************************************
* net/netdb/lib_gethostbynamer.c
*
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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
* COPYRIGHT OWNER OR CONTRIBUTORS 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <arpa/inet.h>
#include "lib_internal.h"
#ifdef CONFIG_LIB_NETDB
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Type Definitions
****************************************************************************/
/* This is the maximum number of alternate host names supported by this
* implementation:
*/
#ifndef CONFIG_NETDB_MAX_ALTNAMES
# define CONFIG_NETDB_MAX_ALTNAMES 4
#endif
#ifndef CONFIG_NETDB_HOSTCONF_PATH
# define CONFIG_NETDB_HOSTCONF_PATH "/etc/hosts"
#endif
/* This is the layout of the caller provided memory area */
struct hostent_info_s
{
FAR char *hi_addrlist[2];
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 paramters:
* stream - File stream of the opened hosts file with the file pointer
* positioned at the beginning of the next host entry.
* 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;
size_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));
/* If the address contains a colon, then it might be a numeric IPv6 */
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);
if (ret < 0)
{
/* 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 */
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);
if (ret < 0)
{
/* 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;
}
info->hi_addrlist[0] = ptr;
host->h_addr_list = info->hi_addrlist;
host->h_length = addrlen;
ptr += addrlen;
buflen -= addrlen;
/* And copy name */
namelen = strlen(name);
if (addrlen + namelen + 1 > buflen)
{
return -ERANGE;
}
strncpy(ptr, name, buflen);
return 0;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: gethostname_r
*
* Description:
* The gethostbyname_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
* gethostbyname_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.
*
* gethostname_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.
* 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 gethostbyname_r(FAR const char *name, FAR struct hostent *host,
FAR char *buf, size_t buflen, int *h_errnop)
{
FAR FILE *stream;
int herrnocode;
int nread;
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;
}
/* Try to find the name in the HOSTALIASES environment variable */
/* REVISIT: Not implemented */
/* Try to get the host address using the DNS name server */
/* REVISIT: Not implemented */
/* Search the hosts file for a match */
stream = fopen(CONFIG_NETDB_HOSTCONF_PATH, "r");
if (stream == NULL)
{
int errcode = errno;
ndbg("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 (ESPIPE)
{
nread = 0;
}
else if (ERANGE)
{
herrnocode = NO_RECOVERY;
goto errorout_with_stream;
}
}
else if (nread > 0)
{
/* We successfully read the entry */
nvdbg("Comparing %s to %s\n", name, host->h_name);
if (strcmp(name, host->h_name) == 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_LIB_NETDB */

View File

@ -0,0 +1,457 @@
/****************************************************************************
* net/netdb/lib_parsehostile.c
*
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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
* COPYRIGHT OWNER OR CONTRIBUTORS 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <arpa/inet.h>
#include "lib_internal.h"
#ifdef CONFIG_LIB_NETDB
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* This is the maximum number of alternate host names supported by this
* implementation:
*/
#ifndef CONFIG_NETDB_MAX_ALTNAMES
# define CONFIG_NETDB_MAX_ALTNAMES 4
#endif
/* Check if character is any kind of white space (except for newline) */
#define lib_isspace(c) \
((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\f' || c== '\v')
/****************************************************************************
* Private Type Definitions
****************************************************************************/
/* This is the layout of the caller provided memory area */
struct hostent_info_s
{
FAR char *hi_aliases[CONFIG_NETDB_MAX_ALTNAMES + 1];
FAR char *hi_addrlist[2];
char hi_data[1];
};
/****************************************************************************
* Public Data
****************************************************************************/
/* When the <netdb.h> header is included, h_errno shall be available as a
* modifiable lvalue of type int. It is unspecified whether h_errno is a
* macro or an identifier declared with external linkage.
*/
/* REVISIT: This should at least be per-task? */
int h_errno;
/****************************************************************************
* Private functions
****************************************************************************/
/****************************************************************************
* Name: lib_skipspaces
****************************************************************************/
static int lib_skipspaces(FAR FILE *stream, FAR size_t *nread)
{
int ch;
/* Skip over most white space (but not newline) */
do
{
ch = fgetc(stream);
if (ch != EOF)
{
(*nread)++;
}
}
while (lib_isspace(ch));
return ch;
}
/****************************************************************************
* Name: lib_skipline
****************************************************************************/
static int lib_skipline(FAR FILE *stream, FAR size_t *nread)
{
int ch;
/* Skip over all characters until we encounter a newline or end-of-file */
do
{
ch = fgetc(stream);
if (ch != EOF)
{
(*nread)++;
}
}
while (ch != EOF && ch != '\n');
return ch;
}
/****************************************************************************
* Name: lib_copystring
*
* Returned Value:
* Number of bytes written to the buffer on success. 0 if the end of
* file is encountered (or a read error occurs). A negated errno value on
* any failure:
*
* -ERANGE - Insufficient buffer space
*
****************************************************************************/
static ssize_t lib_copystring(FAR FILE *stream, FAR char *ptr, FAR size_t *nread,
size_t buflen, FAR int *terminator)
{
size_t nwritten = 0;
int ch;
/* Copy the string from the file until any whitepace delimiter is
* encountered
*/
for(;;)
{
/* Read the next character from the file */
ch = fgetc(stream);
if (ch != EOF)
{
(*nread)++;
}
/* Check for whitepace (including \n') or EOF terminating the string */
if (isspace(ch) || ch == EOF)
{
/* Remeber what terminated the string */
*terminator = ch;
/* Add NUL termination */
*ptr++ = '\0';
/* Return EOF if nothing has written */
return nwritten == 0 ? 0 : nwritten + 1;
}
/* Write the next string to the buffer */
*ptr++ = ch;
nwritten++;
/* There there space to buffer one more character? */
if (nwritten >= buflen)
{
return -ERANGE;
}
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: lib_parse_hostfile
*
* Description:
* Parse the next line from the hosts file.
*
* Input Parameters:
* stream - File stream of the opened hosts file with the file pointer
* positioned at the beginning of the next host entry.
* 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:
* The non-zero number of bytes read from the hosts file is returned if
* the host entry was successfully read. Zero is returned if the end
* of the host file has been reached. A negated errno value is return
* in the event a failure:
*
* ERANGE - Buffer not big enough
* ESPIPE - End of file (or possibly a read error).
* EAGAIN - Error parsing the line (E.g., missing hostname)
*
****************************************************************************/
ssize_t lib_parse_hostfile(FAR FILE *stream, FAR struct hostent *host,
FAR char *buf, size_t buflen)
{
FAR struct hostent_info_s *info;
FAR char addrstring[48];
FAR char *ptr;
FAR char *start;
size_t addrlen;
size_t nread = 0;
ssize_t nwritten;
int ret;
int ch;
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;
}
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));
/* Skip over any leading spaces */
do
{
ch = lib_skipspaces(stream, &nread);
if (ch == EOF)
{
return -EPIPE;
}
/* Skip comment lines beginning with '#' */
if (ch == '#')
{
/* Skip to the end of line. */
ch = lib_skipline(stream, &nread);
if (ch == EOF)
{
return -EPIPE;
}
}
}
while (ch == '\n');
/* Parse the IP address */
addrstring[0] = ch;
nwritten = lib_copystring(stream, addrstring, &nread, 48, &ch);
if (nwritten <= 0)
{
return nwritten;
}
if (!lib_isspace(ch))
{
/* The string was terminated with a newline of EOF */
return -EAGAIN;
}
/* If the address contains a colon, say it is IPv6 */
if (strchr(addrstring, ':') != 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, addrstring, ptr);
if (ret < 0)
{
/* Conversion failed. Entry is corrupted */
(void)lib_skipline(stream, &nread);
return -EAGAIN;
}
host->h_addrtype = AF_INET6;
}
else
{
/* 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, addrstring, ptr);
if (ret < 0)
{
/* Conversion failed. Entry is corrupted */
(void)lib_skipline(stream, &nread);
return -EAGAIN;
}
host->h_addrtype = AF_INET;
}
info->hi_addrlist[0] = ptr;
host->h_addr_list = info->hi_addrlist;
host->h_length = addrlen;
ptr += addrlen;
buflen -= addrlen;
/* Skip over any additional whitespace */
ch = lib_skipspaces(stream, &nread);
if (ch == EOF)
{
return -EPIPE;
}
else if (ch == '\n')
{
return -EAGAIN;
}
/* Parse the host name */
start = ptr;
*ptr++ = ch;
buflen--;
nwritten = lib_copystring(stream, ptr, &nread, buflen, &ch);
if (nwritten <= 0)
{
return nwritten;
}
host->h_name = start;
if (!lib_isspace(ch))
{
/* The string was terminated with a newline or EOF */
return nread;
}
ptr += nwritten;
buflen -= nwritten;
/* Parse any host name aliases */
for (i = 0; i < CONFIG_NETDB_MAX_ALTNAMES; i++)
{
/* Skip over any leading whitespace */
ch = lib_skipspaces(stream, &nread);
if (ch == EOF || ch == '\n')
{
/* No further aliases on the line */
return nread;
}
/* Parse the next alias */
start = ptr;
*ptr++ = ch;
buflen--;
nwritten = lib_copystring(stream, ptr, &nread, buflen, &ch);
if (nwritten < 0)
{
return nwritten;
}
else if (nwritten == 0)
{
return nread;
}
/* Save the pointer to the beginning of the next alias */
info->hi_aliases[i] = start;
if (host->h_aliases == NULL)
{
host->h_aliases = info->hi_aliases;
}
if (!lib_isspace(ch))
{
/* The string was terminated with a newline of EOF */
return nread;
}
ptr += nwritten;
buflen -= nwritten;
}
/* We get here only if there are more than CONFIG_NETDB_MAX_ALTNAMES
* aliases on the line. Skip to the endof the line, ignoring any
* additional aliases.
*/
(void)lib_skipline(stream, &nread);
return nread;
}
#endif /* CONFIG_LIB_NETDB */