diff mbox

[v6,3/4] net/net: Convert parse_host_port() to Error

Message ID d7c1b8ff9247a09e54110abe6abe93543d59b8b6.1498654240.git.maozy.fnst@cn.fujitsu.com
State New
Headers show

Commit Message

Mao Zhongyi June 28, 2017, 1:08 p.m. UTC
Cc: berrange@redhat.com
Cc: kraxel@redhat.com
Cc: pbonzini@redhat.com
Cc: jasowang@redhat.com
Cc: armbru@redhat.com
Signed-off-by: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
---
 include/qemu/sockets.h |  3 ++-
 net/net.c              | 23 ++++++++++++++++++-----
 net/socket.c           | 19 ++++++++++++++-----
 3 files changed, 34 insertions(+), 11 deletions(-)

Comments

Daniel P. Berrangé June 28, 2017, 1:23 p.m. UTC | #1
On Wed, Jun 28, 2017 at 09:08:49PM +0800, Mao Zhongyi wrote:
> diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
> index 5c326db..78e2b30 100644
> --- a/include/qemu/sockets.h
> +++ b/include/qemu/sockets.h

>          if (qemu_isdigit(buf[0])) {
> -            if (!inet_aton(buf, &saddr->sin_addr))
> +            if (!inet_aton(buf, &saddr->sin_addr)) {
> +                error_setg(errp, "host address '%s' is not a valid "
> +                           "IPv4 address", buf);
>                  return -1;
> +            }
>          } else {
> -            if ((he = gethostbyname(buf)) == NULL)
> +            he = gethostbyname(buf);
> +            if (he == NULL) {
> +                error_setg(errp, "can't resolve host address '%s': "
> +                           "unknown host", buf);
>                  return - 1;
> +            }

gethostbyname sets  'h_errno' on failure, so you should pass that
into error_setg_errno, instead of hardcoding 'unknown host' as a
message


Regards,
Daniel
Eric Blake June 28, 2017, 2:24 p.m. UTC | #2
On 06/28/2017 08:23 AM, Daniel P. Berrange wrote:
> On Wed, Jun 28, 2017 at 09:08:49PM +0800, Mao Zhongyi wrote:
>> diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
>> index 5c326db..78e2b30 100644
>> --- a/include/qemu/sockets.h
>> +++ b/include/qemu/sockets.h
> 
>>          if (qemu_isdigit(buf[0])) {
>> -            if (!inet_aton(buf, &saddr->sin_addr))
>> +            if (!inet_aton(buf, &saddr->sin_addr)) {
>> +                error_setg(errp, "host address '%s' is not a valid "
>> +                           "IPv4 address", buf);
>>                  return -1;
>> +            }
>>          } else {
>> -            if ((he = gethostbyname(buf)) == NULL)
>> +            he = gethostbyname(buf);
>> +            if (he == NULL) {
>> +                error_setg(errp, "can't resolve host address '%s': "
>> +                           "unknown host", buf);
>>                  return - 1;
>> +            }
> 
> gethostbyname sets  'h_errno' on failure, so you should pass that
> into error_setg_errno, instead of hardcoding 'unknown host' as a
> message

'man gethostbyname' says it is deprecated, and that applications should
use getaddrinfo/getnameinfo instead.  What's our story here?
Daniel P. Berrangé June 28, 2017, 2:28 p.m. UTC | #3
On Wed, Jun 28, 2017 at 09:24:58AM -0500, Eric Blake wrote:
> On 06/28/2017 08:23 AM, Daniel P. Berrange wrote:
> > On Wed, Jun 28, 2017 at 09:08:49PM +0800, Mao Zhongyi wrote:
> >> diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
> >> index 5c326db..78e2b30 100644
> >> --- a/include/qemu/sockets.h
> >> +++ b/include/qemu/sockets.h
> > 
> >>          if (qemu_isdigit(buf[0])) {
> >> -            if (!inet_aton(buf, &saddr->sin_addr))
> >> +            if (!inet_aton(buf, &saddr->sin_addr)) {
> >> +                error_setg(errp, "host address '%s' is not a valid "
> >> +                           "IPv4 address", buf);
> >>                  return -1;
> >> +            }
> >>          } else {
> >> -            if ((he = gethostbyname(buf)) == NULL)
> >> +            he = gethostbyname(buf);
> >> +            if (he == NULL) {
> >> +                error_setg(errp, "can't resolve host address '%s': "
> >> +                           "unknown host", buf);
> >>                  return - 1;
> >> +            }
> > 
> > gethostbyname sets  'h_errno' on failure, so you should pass that
> > into error_setg_errno, instead of hardcoding 'unknown host' as a
> > message
> 
> 'man gethostbyname' says it is deprecated, and that applications should
> use getaddrinfo/getnameinfo instead.  What's our story here?

The real story is to get net/socket.c converted to QIOChannelSocket
and kill this parse_host_port() method in sockets.c It is already
broken by design since it takes a 'struct sockdddr_in' and thus
can't do IPv6.

This patch doesn't make the existing situation worse, so I think
its fine to add this error reporting cleanup now, and not force
immediate conversion to QIOChannelSocket today.  The net/sockets.c
code needs a further refactor before that conversion can be done
in the right way - we've already reverted the wrong way twice ;-)

Regards,
Daniel
Mao Zhongyi June 29, 2017, 3:01 a.m. UTC | #4
Hi, Daniel

On 06/28/2017 09:23 PM, Daniel P. Berrange wrote:
> On Wed, Jun 28, 2017 at 09:08:49PM +0800, Mao Zhongyi wrote:
>> diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
>> index 5c326db..78e2b30 100644
>> --- a/include/qemu/sockets.h
>> +++ b/include/qemu/sockets.h
>
>>          if (qemu_isdigit(buf[0])) {
>> -            if (!inet_aton(buf, &saddr->sin_addr))
>> +            if (!inet_aton(buf, &saddr->sin_addr)) {
>> +                error_setg(errp, "host address '%s' is not a valid "
>> +                           "IPv4 address", buf);
>>                  return -1;
>> +            }
>>          } else {
>> -            if ((he = gethostbyname(buf)) == NULL)
>> +            he = gethostbyname(buf);
>> +            if (he == NULL) {
>> +                error_setg(errp, "can't resolve host address '%s': "
>> +                           "unknown host", buf);
>>                  return - 1;
>> +            }
>
> gethostbyname sets  'h_errno' on failure, so you should pass that
> into error_setg_errno, instead of hardcoding 'unknown host' as a
> message

Yes, 'h_errno' will be seted detailed error message when gethostbyname() failed,
but the value of 'h_errno', as far as I know, can be print by hstrerror(),
herror() and gai_strerror(). I'm not sure 'h_errno' can be parsed correctly
by error_setg_errno(), so I test it like this:

herror("----herror----");
error_report("----hstrerror----%s", hstrerror(h_errno));
error_report("----gai_strerror----%s", gai_strerror(h_errno));
error_setg_errno(errp, h_errno, "can't resolve host address '%s'" ,buf);


result:

----herror----: Unknown host
qemu-system-x86_64: -net socket,listen=hostname:: ----hstrerror----Unknown host
qemu-system-x86_64: -net socket,listen=hostname:: ----gai_strerror----Unknown error
qemu-system-x86_64: -net socket,listen=hostname:: can't resolve host address 'hostname': Operation not permitted


 From the results, obviously the error message is different.
error_setg_errno() prints a uncertain message like "Operation not
permitted", I think that the value of 'h_errno' is treated as a
standard error code for errno. Although they have the same value,
the information contained may not be same.

so is it really appropriate to pass 'h_errno' to error_setg_errno()?

Thanks,
Mao


> Regards,
> Daniel
>
Markus Armbruster June 29, 2017, 7:29 a.m. UTC | #5
"Daniel P. Berrange" <berrange@redhat.com> writes:

> On Wed, Jun 28, 2017 at 09:24:58AM -0500, Eric Blake wrote:
>> On 06/28/2017 08:23 AM, Daniel P. Berrange wrote:
>> > On Wed, Jun 28, 2017 at 09:08:49PM +0800, Mao Zhongyi wrote:
>> >> diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
>> >> index 5c326db..78e2b30 100644
>> >> --- a/include/qemu/sockets.h
>> >> +++ b/include/qemu/sockets.h
>> > 
>> >>          if (qemu_isdigit(buf[0])) {
>> >> -            if (!inet_aton(buf, &saddr->sin_addr))
>> >> +            if (!inet_aton(buf, &saddr->sin_addr)) {
>> >> +                error_setg(errp, "host address '%s' is not a valid "
>> >> +                           "IPv4 address", buf);
>> >>                  return -1;
>> >> +            }
>> >>          } else {
>> >> -            if ((he = gethostbyname(buf)) == NULL)
>> >> +            he = gethostbyname(buf);
>> >> +            if (he == NULL) {
>> >> +                error_setg(errp, "can't resolve host address '%s': "
>> >> +                           "unknown host", buf);
>> >>                  return - 1;
>> >> +            }
>> > 
>> > gethostbyname sets  'h_errno' on failure, so you should pass that
>> > into error_setg_errno, instead of hardcoding 'unknown host' as a
>> > message

'unknown host' is misleading when h_errno != HOST_NOT_FOUND.

>> 'man gethostbyname' says it is deprecated, and that applications should
>> use getaddrinfo/getnameinfo instead.  What's our story here?
>
> The real story is to get net/socket.c converted to QIOChannelSocket
> and kill this parse_host_port() method in sockets.c It is already
> broken by design since it takes a 'struct sockdddr_in' and thus
> can't do IPv6.
>
> This patch doesn't make the existing situation worse, so I think
> its fine to add this error reporting cleanup now, and not force
> immediate conversion to QIOChannelSocket today.  The net/sockets.c
> code needs a further refactor before that conversion can be done
> in the right way - we've already reverted the wrong way twice ;-)

Until then, let's go with a generic error message, as I requested in my
review of v5.  Just drop the misleading ": unknown host" part.
diff mbox

Patch

diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index 5c326db..78e2b30 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -53,7 +53,8 @@  void socket_listen_cleanup(int fd, Error **errp);
 int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp);
 
 /* Old, ipv4 only bits.  Don't use for new code. */
-int parse_host_port(struct sockaddr_in *saddr, const char *str);
+int parse_host_port(struct sockaddr_in *saddr, const char *str,
+                    Error **errp);
 int socket_init(void);
 
 /**
diff --git a/net/net.c b/net/net.c
index 6235aab..29cc7df 100644
--- a/net/net.c
+++ b/net/net.c
@@ -100,7 +100,8 @@  static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
     return 0;
 }
 
-int parse_host_port(struct sockaddr_in *saddr, const char *str)
+int parse_host_port(struct sockaddr_in *saddr, const char *str,
+                    Error **errp)
 {
     char buf[512];
     struct hostent *he;
@@ -108,24 +109,36 @@  int parse_host_port(struct sockaddr_in *saddr, const char *str)
     int port;
 
     p = str;
-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        error_setg(errp, "host address '%s' doesn't contain ':' "
+                   "separating host from port", str);
         return -1;
+    }
     saddr->sin_family = AF_INET;
     if (buf[0] == '\0') {
         saddr->sin_addr.s_addr = 0;
     } else {
         if (qemu_isdigit(buf[0])) {
-            if (!inet_aton(buf, &saddr->sin_addr))
+            if (!inet_aton(buf, &saddr->sin_addr)) {
+                error_setg(errp, "host address '%s' is not a valid "
+                           "IPv4 address", buf);
                 return -1;
+            }
         } else {
-            if ((he = gethostbyname(buf)) == NULL)
+            he = gethostbyname(buf);
+            if (he == NULL) {
+                error_setg(errp, "can't resolve host address '%s': "
+                           "unknown host", buf);
                 return - 1;
+            }
             saddr->sin_addr = *(struct in_addr *)he->h_addr;
         }
     }
     port = strtol(p, (char **)&r, 0);
-    if (r == p)
+    if (r == p) {
+        error_setg(errp, "port number '%s' is invalid", p);
         return -1;
+    }
     saddr->sin_port = htons(port);
     return 0;
 }
diff --git a/net/socket.c b/net/socket.c
index b6bacf4..90dd4c0 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -500,9 +500,12 @@  static int net_socket_listen_init(NetClientState *peer,
     NetSocketState *s;
     struct sockaddr_in saddr;
     int fd, ret;
+    Error *err = NULL;
 
-    if (parse_host_port(&saddr, host_str) < 0)
+    if (parse_host_port(&saddr, host_str, &err) < 0) {
+        error_report_err(err);
         return -1;
+    }
 
     fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
     if (fd < 0) {
@@ -547,8 +550,10 @@  static int net_socket_connect_init(NetClientState *peer,
     struct sockaddr_in saddr;
     Error *err = NULL;
 
-    if (parse_host_port(&saddr, host_str) < 0)
+    if (parse_host_port(&saddr, host_str, &err) < 0) {
+        error_report_err(err);
         return -1;
+    }
 
     fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
     if (fd < 0) {
@@ -600,8 +605,10 @@  static int net_socket_mcast_init(NetClientState *peer,
     struct in_addr localaddr, *param_localaddr;
     Error *err = NULL;
 
-    if (parse_host_port(&saddr, host_str) < 0)
+    if (parse_host_port(&saddr, host_str, &err) < 0) {
+        error_report_err(err);
         return -1;
+    }
 
     if (localaddr_str != NULL) {
         if (inet_aton(localaddr_str, &localaddr) == 0)
@@ -643,11 +650,13 @@  static int net_socket_udp_init(NetClientState *peer,
     struct sockaddr_in laddr, raddr;
     Error *err = NULL;
 
-    if (parse_host_port(&laddr, lhost) < 0) {
+    if (parse_host_port(&laddr, lhost, &err) < 0) {
+        error_report_err(err);
         return -1;
     }
 
-    if (parse_host_port(&raddr, rhost) < 0) {
+    if (parse_host_port(&raddr, rhost, &err) < 0) {
+        error_report_err(err);
         return -1;
     }