You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/04/23 15:29:47 UTC
[incubator-nuttx-apps] 01/02: webclient: use getaddrinfo to get
IPv4 addresses on dual stack systems
This is an automated email from the ASF dual-hosted git repository.
gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx-apps.git
commit f8f16975a9697e07b4a17f3fa1b93ab12fbf442c
Author: Juha Niskanen <ju...@haltian.com>
AuthorDate: Wed Apr 22 11:29:02 2020 +0300
webclient: use getaddrinfo to get IPv4 addresses on dual stack systems
Signed-off-by: Juha Niskanen <ju...@haltian.com>
---
include/netutils/webclient.h | 13 +--
netutils/ping/icmp_ping.c | 8 +-
netutils/ping/icmpv6_ping.c | 6 +-
netutils/webclient/webclient.c | 175 ++++++++++++++++++++++-------------------
4 files changed, 105 insertions(+), 97 deletions(-)
diff --git a/include/netutils/webclient.h b/include/netutils/webclient.h
index 3e49cfd..0eb448e 100644
--- a/include/netutils/webclient.h
+++ b/include/netutils/webclient.h
@@ -1,5 +1,5 @@
/****************************************************************************
- * apps/include/netutils/webclient.h
+ * apps/include/netutils/webclient.h
* Header file for the HTTP client
*
* Copyright (C) 2007, 2009, 2011, 2015 Gregory Nutt. All rights reserved.
@@ -46,9 +46,7 @@
* Included Files
****************************************************************************/
-#ifndef CONFIG_WEBCLIENT_HOST
-# include <nuttx/config.h>
-#endif
+#include <nuttx/config.h>
#include <sys/types.h>
/****************************************************************************
@@ -93,6 +91,7 @@
* of valid bytes is datend - offset.
* buflen - A pointer to the length of the buffer. If the callee wishes
* to change the size of the buffer, it may write to buflen.
+ * arg - User argument passed to callback.
*/
typedef void (*wget_callback_t)(FAR char **buffer, int offset,
@@ -125,12 +124,6 @@ int web_posts_strlen(FAR char **name, FAR char **value, int len);
* Description:
* Obtain the requested file from an HTTP server using the GET method.
*
- * Note: If the function is passed a host name, it must already be in
- * the resolver cache in order for the function to connect to the web
- * server. It is therefore up to the calling module to implement the
- * resolver calls and the signal handler used for reporting a resolve
- * query answer.
- *
* Input Parameters
* url - A pointer to a string containing either the full URL to
* the file to get (e.g., http://www.nutt.org/index.html, or
diff --git a/netutils/ping/icmp_ping.c b/netutils/ping/icmp_ping.c
index fffcc09..61b570c 100644
--- a/netutils/ping/icmp_ping.c
+++ b/netutils/ping/icmp_ping.c
@@ -99,14 +99,14 @@ static inline uint16_t ping_newid(void)
* Name: ping_gethostip
*
* Description:
- * Call gethostbyname() to get the IP address associated with a hostname.
+ * Call getaddrinfo() to get the IP address associated with a hostname.
*
* Input Parameters
* hostname - The host name to use in the nslookup.
- * ipv4addr - The location to return the IPv4 address.
+ * destr - The location to return the IPv4 address.
*
* Returned Value:
- * Zero (OK) on success; a negated errno value on failure.
+ * Zero (OK) on success; ERROR on failure.
*
****************************************************************************/
@@ -136,7 +136,7 @@ static int ping_gethostip(FAR const char *hostname, FAR struct in_addr *dest)
#else /* CONFIG_LIBC_NETDB */
/* No host name support */
- /* Convert strings to numeric IPv6 address */
+ /* Convert strings to numeric IPv4 address */
int ret = inet_pton(AF_INET, hostname, dest);
diff --git a/netutils/ping/icmpv6_ping.c b/netutils/ping/icmpv6_ping.c
index 522d093..eca1913 100644
--- a/netutils/ping/icmpv6_ping.c
+++ b/netutils/ping/icmpv6_ping.c
@@ -98,14 +98,14 @@ static inline uint16_t ping6_newid(void)
* Name: ping6_gethostip
*
* Description:
- * Call gethostbyname() to get the IP address associated with a hostname.
+ * Call getaddrinfo() to get the IP address associated with a hostname.
*
* Input Parameters
* hostname - The host name to use in the nslookup.
- * ipv4addr - The location to return the IPv4 address.
+ * dest - The location to return the IPv6 address.
*
* Returned Value:
- * Zero (OK) on success; a negated errno value on failure.
+ * Zero (OK) on success; ERROR on failure.
*
****************************************************************************/
diff --git a/netutils/webclient/webclient.c b/netutils/webclient/webclient.c
index a7c0850..31f644e 100644
--- a/netutils/webclient/webclient.c
+++ b/netutils/webclient/webclient.c
@@ -48,11 +48,9 @@
* Included Files
****************************************************************************/
-#ifndef CONFIG_WEBCLIENT_HOST
-# include <nuttx/config.h>
-# include <nuttx/compiler.h>
-# include <debug.h>
-#endif
+#include <nuttx/config.h>
+#include <nuttx/compiler.h>
+#include <debug.h>
#include <sys/socket.h>
#include <sys/time.h>
@@ -62,6 +60,7 @@
#include <unistd.h>
#include <netdb.h>
#include <strings.h>
+#include <stdlib.h>
#include <errno.h>
#include <arpa/inet.h>
@@ -188,10 +187,6 @@ static const char g_httpcontsize[] = "Content-Length: ";
****************************************************************************/
/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
* Name: wget_strcpy
****************************************************************************/
@@ -286,7 +281,7 @@ static inline int wget_parsestatus(struct wget_s *ws)
}
/****************************************************************************
- * Name: wget_parsestatus
+ * Name: wget_parseheaders
****************************************************************************/
static inline int wget_parseheaders(struct wget_s *ws)
@@ -378,36 +373,54 @@ exit:
* Name: wget_gethostip
*
* Description:
- * Call gethostbyname() to get the IPv4 address associated with a hostname.
+ * Call getaddrinfo() to get the IPv4 address associated with a hostname.
*
* Input Parameters
* hostname - The host name to use in the nslookup.
- * ipv4addr - The location to return the IPv4 address.
+ *
+ * Output Parameters
+ * dest - The location to return the IPv4 address.
*
* Returned Value:
- * Zero (OK) on success; a negated errno value on failure.
+ * Zero (OK) on success; ERROR on failure.
*
****************************************************************************/
-static int wget_gethostip(FAR char *hostname, in_addr_t *ipv4addr)
+static int wget_gethostip(FAR char *hostname, FAR struct in_addr *dest)
{
- FAR struct hostent *he;
+#ifdef CONFIG_LIBC_NETDB
+ FAR struct addrinfo hint;
+ FAR struct addrinfo *info;
+ FAR struct sockaddr_in *addr;
- he = gethostbyname(hostname);
- if (he == NULL)
- {
- nwarn("WARNING: gethostbyname failed: %d\n", h_errno);
- return -ENOENT;
- }
- else if (he->h_addrtype != AF_INET)
+ memset(&hint, 0, sizeof(hint));
+ hint.ai_family = AF_INET;
+
+ if (getaddrinfo(hostname, NULL, &hint, &info) != OK)
{
- nwarn("WARNING: gethostbyname returned an address of type: %d\n",
- he->h_addrtype);
- return -ENOEXEC;
+ return ERROR;
}
- memcpy(ipv4addr, he->h_addr, sizeof(in_addr_t));
+ addr = (FAR struct sockaddr_in *)info->ai_addr;
+ memcpy(dest, &addr->sin_addr, sizeof(struct in_addr));
+
+ freeaddrinfo(info);
return OK;
+#else
+ /* No host name support */
+
+ /* Convert strings to numeric IPv4 address */
+
+ int ret = inet_pton(AF_INET, hostname, dest);
+
+ /* The inet_pton() function returns 1 if the conversion succeeds. It will
+ * return 0 if the input is not a valid IPv4 dotted-decimal string or -1
+ * with errno set to EAFNOSUPPORT if the address family argument is
+ * unsupported.
+ */
+
+ return (ret > 0) ? OK : ERROR;
+#endif
}
/****************************************************************************
@@ -416,12 +429,6 @@ static int wget_gethostip(FAR char *hostname, in_addr_t *ipv4addr)
* Description:
* Obtain the requested file from an HTTP server using the GET method.
*
- * Note: If the function is passed a host name, it must already be in
- * the resolver cache in order for the function to connect to the web
- * server. It is therefore up to the calling module to implement the
- * resolver calls and the signal handler used for reporting a resolv
- * query answer.
- *
* Input Parameters
* url - A pointer to a string containing either the full URL to
* the file to get (e.g., http://www.nutt.org/index.html, or
@@ -431,6 +438,7 @@ static int wget_gethostip(FAR char *hostname, in_addr_t *ipv4addr)
* buflen - The size of the user provided buffer
* callback - As data is obtained from the host, this function is
* to dispose of each block of file data as it is received.
+ * arg - User argument passed to callback.
* mode - Indicates GET or POST modes
*
* Returned Value:
@@ -444,34 +452,40 @@ static int wget_base(FAR const char *url, FAR char *buffer, int buflen,
FAR const char *posts, uint8_t mode)
{
struct sockaddr_in server;
- struct wget_s ws;
+ struct wget_s *ws;
struct timeval tv;
bool redirected;
- char *dest,post_size[8];
+ char *dest;
int sockfd;
- int len,post_len;
+ int len;
int ret;
/* Initialize the state structure */
- memset(&ws, 0, sizeof(struct wget_s));
- ws.buffer = buffer;
- ws.buflen = buflen;
- ws.port = 80;
+ ws = calloc(1, sizeof(struct wget_s));
+ if (!ws)
+ {
+ return ERROR;
+ }
+
+ ws->buffer = buffer;
+ ws->buflen = buflen;
+ ws->port = 80;
/* Parse the hostname (with optional port number) and filename from the URL */
- ret = netlib_parsehttpurl(url, &ws.port,
- ws.hostname, CONFIG_WEBCLIENT_MAXHOSTNAME,
- ws.filename, CONFIG_WEBCLIENT_MAXFILENAME);
+ ret = netlib_parsehttpurl(url, &ws->port,
+ ws->hostname, CONFIG_WEBCLIENT_MAXHOSTNAME,
+ ws->filename, CONFIG_WEBCLIENT_MAXFILENAME);
if (ret != 0)
{
nwarn("WARNING: Malformed HTTP URL: %s\n", url);
+ free(ws);
set_errno(-ret);
return ERROR;
}
- ninfo("hostname='%s' filename='%s'\n", ws.hostname, ws.filename);
+ ninfo("hostname='%s' filename='%s'\n", ws->hostname, ws->filename);
/* The following sequence may repeat indefinitely if we are redirected */
@@ -482,10 +496,10 @@ static int wget_base(FAR const char *url, FAR char *buffer, int buflen,
* persist with the new connection.
*/
- ws.httpstatus = HTTPSTATUS_NONE;
- ws.offset = 0;
- ws.datend = 0;
- ws.ndx = 0;
+ ws->httpstatus = HTTPSTATUS_NONE;
+ ws->offset = 0;
+ ws->datend = 0;
+ ws->ndx = 0;
/* Create a socket */
@@ -495,6 +509,7 @@ static int wget_base(FAR const char *url, FAR char *buffer, int buflen,
/* socket failed. It will set the errno appropriately */
nerr("ERROR: socket failed: %d\n", errno);
+ free(ws);
return ERROR;
}
@@ -511,8 +526,8 @@ static int wget_base(FAR const char *url, FAR char *buffer, int buflen,
/* Get the server address from the host name */
server.sin_family = AF_INET;
- server.sin_port = htons(ws.port);
- ret = wget_gethostip(ws.hostname, &server.sin_addr.s_addr);
+ server.sin_port = htons(ws->port);
+ ret = wget_gethostip(ws->hostname, &server.sin_addr);
if (ret < 0)
{
/* Could not resolve host (or malformed IP address) */
@@ -536,7 +551,7 @@ static int wget_base(FAR const char *url, FAR char *buffer, int buflen,
/* Send the GET request */
- dest = ws.buffer;
+ dest = ws->buffer;
if (mode == WGET_MODE_POST)
{
dest = wget_strcpy(dest, g_httppost);
@@ -547,21 +562,24 @@ static int wget_base(FAR const char *url, FAR char *buffer, int buflen,
}
#ifndef WGET_USE_URLENCODE
- dest = wget_strcpy(dest, ws.filename);
+ dest = wget_strcpy(dest, ws->filename);
#else
- //dest = wget_urlencode_strcpy(dest, ws.filename);
- dest = wget_strcpy(dest, ws.filename);
+ //dest = wget_urlencode_strcpy(dest, ws->filename);
+ dest = wget_strcpy(dest, ws->filename);
#endif
*dest++ = ISO_space;
dest = wget_strcpy(dest, g_http10);
dest = wget_strcpy(dest, g_httpcrnl);
dest = wget_strcpy(dest, g_httphost);
- dest = wget_strcpy(dest, ws.hostname);
+ dest = wget_strcpy(dest, ws->hostname);
dest = wget_strcpy(dest, g_httpcrnl);
if (mode == WGET_MODE_POST)
{
+ int post_len;
+ char post_size[8];
+
dest = wget_strcpy(dest, g_httpform);
dest = wget_strcpy(dest, g_httpcrnl);
dest = wget_strcpy(dest, g_httpcontsize);
@@ -569,7 +587,7 @@ static int wget_base(FAR const char *url, FAR char *buffer, int buflen,
/* Post content size */
post_len = strlen((char *)posts);
- sprintf(post_size,"%d", post_len);
+ sprintf(post_size, "%d", post_len);
dest = wget_strcpy(dest, post_size);
dest = wget_strcpy(dest, g_httpcrnl);
}
@@ -594,18 +612,18 @@ static int wget_base(FAR const char *url, FAR char *buffer, int buflen,
* or until we detect that we have been redirected.
*/
- ws.state = WEBCLIENT_STATE_STATUSLINE;
+ ws->state = WEBCLIENT_STATE_STATUSLINE;
redirected = false;
for (;;)
{
- ws.datend = recv(sockfd, ws.buffer, ws.buflen, 0);
- if (ws.datend < 0)
+ ws->datend = recv(sockfd, ws->buffer, ws->buflen, 0);
+ if (ws->datend < 0)
{
nerr("ERROR: recv failed: %d\n", errno);
- ret = ws.datend;
+ ret = ws->datend;
goto errout_with_errno;
}
- else if (ws.datend == 0)
+ else if (ws->datend == 0)
{
ninfo("Connection lost\n");
close(sockfd);
@@ -614,10 +632,10 @@ static int wget_base(FAR const char *url, FAR char *buffer, int buflen,
/* Handle initial parsing of the status line */
- ws.offset = 0;
- if (ws.state == WEBCLIENT_STATE_STATUSLINE)
+ ws->offset = 0;
+ if (ws->state == WEBCLIENT_STATE_STATUSLINE)
{
- ret = wget_parsestatus(&ws);
+ ret = wget_parsestatus(ws);
if (ret < 0)
{
goto errout_with_errno;
@@ -626,9 +644,9 @@ static int wget_base(FAR const char *url, FAR char *buffer, int buflen,
/* Parse the HTTP data */
- if (ws.state == WEBCLIENT_STATE_HEADERS)
+ if (ws->state == WEBCLIENT_STATE_HEADERS)
{
- ret = wget_parseheaders(&ws);
+ ret = wget_parseheaders(ws);
if (ret < 0)
{
goto errout_with_errno;
@@ -637,13 +655,13 @@ static int wget_base(FAR const char *url, FAR char *buffer, int buflen,
/* Dispose of the data payload */
- if (ws.state == WEBCLIENT_STATE_DATA)
+ if (ws->state == WEBCLIENT_STATE_DATA)
{
- if (ws.httpstatus != HTTPSTATUS_MOVED)
+ if (ws->httpstatus != HTTPSTATUS_MOVED)
{
/* Let the client decide what to do with the received file */
- callback(&ws.buffer, ws.offset, ws.datend, &buflen, arg);
+ callback(&ws->buffer, ws->offset, ws->datend, &buflen, arg);
}
else
{
@@ -656,12 +674,14 @@ static int wget_base(FAR const char *url, FAR char *buffer, int buflen,
}
while (redirected);
+ free(ws);
return OK;
errout_with_errno:
set_errno(-ret);
errout:
close(sockfd);
+ free(ws);
return ERROR;
}
@@ -677,10 +697,10 @@ errout:
char *web_post_str(FAR char *buffer, int *size, FAR char *name,
FAR char *value)
{
- char *dst=buffer;
- buffer = wget_strcpy(buffer,name);
+ char *dst = buffer;
+ buffer = wget_strcpy(buffer, name);
buffer = wget_strcpy(buffer, "=");
- buffer = wget_urlencode_strcpy(buffer,value);
+ buffer = wget_urlencode_strcpy(buffer, value);
*size = buffer - dst;
return dst;
}
@@ -693,7 +713,7 @@ char *web_post_str(FAR char *buffer, int *size, FAR char *name,
#ifdef WGET_USE_URLENCODE
int web_post_strlen(FAR char *name, FAR char *value)
{
- return strlen(name) + urlencode_len(value,strlen(value)) + 1;
+ return strlen(name) + urlencode_len(value, strlen(value)) + 1;
}
#endif
@@ -705,7 +725,7 @@ int web_post_strlen(FAR char *name, FAR char *value)
char *web_posts_str(FAR char *buffer, int *size, FAR char **name,
FAR char **value, int len)
{
- char *dst=buffer;
+ char *dst = buffer;
int wlen;
int i;
@@ -721,7 +741,7 @@ char *web_posts_str(FAR char *buffer, int *size, FAR char **name,
buffer += wlen;
}
- *size=buffer-dst;
+ *size = buffer - dst;
return dst;
}
#endif
@@ -751,12 +771,6 @@ int web_posts_strlen(FAR char **name, FAR char **value, int len)
* Description:
* Obtain the requested file from an HTTP server using the GET method.
*
- * Note: If the function is passed a host name, it must already be in
- * the resolver cache in order for the function to connect to the web
- * server. It is therefore up to the calling module to implement the
- * resolver calls and the signal handler used for reporting a resolv
- * query answer.
- *
* Input Parameters
* url - A pointer to a string containing either the full URL to
* the file to get (e.g., http://www.nutt.org/index.html, or
@@ -766,6 +780,7 @@ int web_posts_strlen(FAR char **name, FAR char **value, int len)
* buflen - The size of the user provided buffer
* callback - As data is obtained from the host, this function is
* to dispose of each block of file data as it is received.
+ * arg - User argument passed to callback.
*
* Returned Value:
* 0: if the GET operation completed successfully;