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;