All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michael Roth <mdroth@linux.vnet.ibm.com>
To: Amos Kong <akong@redhat.com>
Cc: aliguori@us.ibm.com, kvm@vger.kernel.org, quintela@redhat.com,
	jasowang@redhat.com, qemu-devel@nongnu.org, owasserm@redhat.com,
	laine@redhat.com
Subject: Re: [PATCH v5 3/4] sockets: pass back errors in inet_listen()
Date: Tue, 27 Mar 2012 18:15:00 -0500	[thread overview]
Message-ID: <20120327231500.GA31300@illuin> (raw)
In-Reply-To: <20120322035254.2431.12215.stgit@dhcp-8-167.nay.redhat.com>

On Thu, Mar 22, 2012 at 11:52:54AM +0800, Amos Kong wrote:
> Use set_socket_error() to restore real erron,
> set errno to EINVAL for parse error.
> 
> Signed-off-by: Amos Kong <akong@redhat.com>
> ---
>  qemu-sockets.c |   21 ++++++++++++++++-----
>  1 files changed, 16 insertions(+), 5 deletions(-)
> 
> diff --git a/qemu-sockets.c b/qemu-sockets.c
> index 908479e..f1c6524 100644
> --- a/qemu-sockets.c
> +++ b/qemu-sockets.c
> @@ -110,7 +110,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
>      char port[33];
>      char uaddr[INET6_ADDRSTRLEN+1];
>      char uport[33];
> -    int slisten, rc, to, port_min, port_max, p;
> +    int slisten, rc, to, port_min, port_max, p, err;
> 
>      memset(&ai,0, sizeof(ai));
>      ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
> @@ -120,7 +120,8 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
>      if ((qemu_opt_get(opts, "host") == NULL) ||
>          (qemu_opt_get(opts, "port") == NULL)) {
>          fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__);
> -        return -1;
> +        err = -EINVAL;
> +        goto err;
>      }
>      pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
>      addr = qemu_opt_get(opts, "host");
> @@ -138,7 +139,8 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
>      if (rc != 0) {
>          fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
>                  gai_strerror(rc));
> -        return -1;
> +        err = -EINVAL;
> +        goto err;
>      }
> 
>      /* create socket + bind */
> @@ -150,6 +152,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
>          if (slisten < 0) {
>              fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
>                      inet_strfamily(e->ai_family), strerror(errno));
> +            err = -socket_error();
>              continue;
>          }
> 
> @@ -169,6 +172,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
>              if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
>                  goto listen;
>              }
> +            err = -socket_error();
>              if (p == port_max) {
>                  fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
>                          inet_strfamily(e->ai_family), uaddr, inet_getport(e),
> @@ -179,14 +183,15 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
>      }
>      fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
>      freeaddrinfo(res);
> -    return -1;
> +    goto err;
> 
>  listen:
>      if (listen(slisten,1) != 0) {
> +        err = -socket_error();
>          perror("listen");
>          closesocket(slisten);
>          freeaddrinfo(res);
> -        return -1;
> +        goto err;
>      }
>      snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset);
>      qemu_opt_set(opts, "host", uaddr);
> @@ -195,6 +200,10 @@ listen:
>      qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off");
>      freeaddrinfo(res);
>      return slisten;
> +
> +err:
> +    set_socket_error(-err);
> +    return -1;

Sorry I didn't see this sooner. On the last series where I suggested you
switch to using Error, I was referring to the error propagation stuff in
Error.c, namely error_set(Error *err)

I don't it's clear to users when socket_error() should be used as
opposed to errno (or nothing at all), especially in a utility function like
this that makes a lot of system calls. errno actually gets used
explicitly in a few spots in qemu-sockets.c, for w32, ironically, so
it's missed completely by socket_error()/WSAGetLastError() checks.

Unfortunately, creating distinct error classes for every permutation of
bind/listen/connect/socket and EINPROGRESS/EWOULDBLOCK/EINTR/EXXX is too
much.

But really the whole reason we now need error propagation is basically
just to let the new non-blocking users know when a connect() "failure" was
simply EINPROGRESS, right? For other errors the user probably just wants
to know what function failed (and maybe a strerror(errno) but that's
not typically how we use Error/QError currently).

Currently, other than for ENOTSUP which we use errno for, everything in
qemu-sockets.c just prints errors to stderr and returns -1, 0, or a valid fd,
and no current users, AFAICT, check errno/socket_error()/etc.

So we're free to do it up nice and clean, and here's what I'd suggest:

1) Rename the following functions:

inet_listen_opts(...) -> inet_listen_opts_err(..., Error **errp)
inet_connect_opts(...) -> inet_connect_opts_err(..., Error **errp)
unix_listen_opts(...) -> inet_listen_opts_err(..., Error **errp)
unix_connect_opts(...) -> inet_connect_opts_err(..., Error **errp)
inet_dgram_opts(...) -> inet_listen_opts_err(..., Error **errp)

Make wrappers for the originals that call them with errp == NULL.

2) Add the following error classes to qerror.c/qerror.h:

QERR_SOCKET_CONNECT_IN_PROGRESS
QERR_SOCKET_CONNECT_FAILED
QERR_SOCKET_LISTEN_FAILED
QERR_SOCKET_BIND_FAILED
QERR_SOCKET_CREATE_FAILED

And maybe a handful of others that seem worth reporting.
QERR_UNDEFINED_ERROR is probably okay for the more obscure failures.

For inet_*_opts_err(), set these errors alongside where we currently print to
stderr and return -1. Handling errors for the others are probably outside the
scope of your patches and can be done easily enough later, but would be nice to
at least pass back QERR_UNDEFINED_ERROR as a place holder.

3) Add your non-blocking support, document
QERR_SOCKET_CONNECT_IN_PROGRESS as being significant in that the user
should begin select()'ing for completion, checking SO_ERROR, etc.

4) Use it for ipv6 migration.

IMO, anyway. I think the series is basically there otherwise, we just
have some nicer error-handling infrastructure in place since socket_error()
was first added and it makes sense to use if we need to introduce error
propagation to qemu-sockets.c

>  }
> 
>  int inet_connect_opts(QemuOpts *opts)
> @@ -474,6 +483,8 @@ int inet_listen(const char *str, char *ostr, int olen,
>                           optstr ? optstr : "");
>              }
>          }
> +    } else {
> +        set_socket_error(EINVAL);
>      }
>      qemu_opts_del(opts);
>      return sock;
> 

WARNING: multiple messages have this Message-ID (diff)
From: Michael Roth <mdroth@linux.vnet.ibm.com>
To: Amos Kong <akong@redhat.com>
Cc: aliguori@us.ibm.com, kvm@vger.kernel.org, quintela@redhat.com,
	jasowang@redhat.com, qemu-devel@nongnu.org, owasserm@redhat.com,
	laine@redhat.com
Subject: Re: [Qemu-devel] [PATCH v5 3/4] sockets: pass back errors in inet_listen()
Date: Tue, 27 Mar 2012 18:15:00 -0500	[thread overview]
Message-ID: <20120327231500.GA31300@illuin> (raw)
In-Reply-To: <20120322035254.2431.12215.stgit@dhcp-8-167.nay.redhat.com>

On Thu, Mar 22, 2012 at 11:52:54AM +0800, Amos Kong wrote:
> Use set_socket_error() to restore real erron,
> set errno to EINVAL for parse error.
> 
> Signed-off-by: Amos Kong <akong@redhat.com>
> ---
>  qemu-sockets.c |   21 ++++++++++++++++-----
>  1 files changed, 16 insertions(+), 5 deletions(-)
> 
> diff --git a/qemu-sockets.c b/qemu-sockets.c
> index 908479e..f1c6524 100644
> --- a/qemu-sockets.c
> +++ b/qemu-sockets.c
> @@ -110,7 +110,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
>      char port[33];
>      char uaddr[INET6_ADDRSTRLEN+1];
>      char uport[33];
> -    int slisten, rc, to, port_min, port_max, p;
> +    int slisten, rc, to, port_min, port_max, p, err;
> 
>      memset(&ai,0, sizeof(ai));
>      ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
> @@ -120,7 +120,8 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
>      if ((qemu_opt_get(opts, "host") == NULL) ||
>          (qemu_opt_get(opts, "port") == NULL)) {
>          fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__);
> -        return -1;
> +        err = -EINVAL;
> +        goto err;
>      }
>      pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
>      addr = qemu_opt_get(opts, "host");
> @@ -138,7 +139,8 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
>      if (rc != 0) {
>          fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
>                  gai_strerror(rc));
> -        return -1;
> +        err = -EINVAL;
> +        goto err;
>      }
> 
>      /* create socket + bind */
> @@ -150,6 +152,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
>          if (slisten < 0) {
>              fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
>                      inet_strfamily(e->ai_family), strerror(errno));
> +            err = -socket_error();
>              continue;
>          }
> 
> @@ -169,6 +172,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
>              if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
>                  goto listen;
>              }
> +            err = -socket_error();
>              if (p == port_max) {
>                  fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
>                          inet_strfamily(e->ai_family), uaddr, inet_getport(e),
> @@ -179,14 +183,15 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
>      }
>      fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
>      freeaddrinfo(res);
> -    return -1;
> +    goto err;
> 
>  listen:
>      if (listen(slisten,1) != 0) {
> +        err = -socket_error();
>          perror("listen");
>          closesocket(slisten);
>          freeaddrinfo(res);
> -        return -1;
> +        goto err;
>      }
>      snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset);
>      qemu_opt_set(opts, "host", uaddr);
> @@ -195,6 +200,10 @@ listen:
>      qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off");
>      freeaddrinfo(res);
>      return slisten;
> +
> +err:
> +    set_socket_error(-err);
> +    return -1;

Sorry I didn't see this sooner. On the last series where I suggested you
switch to using Error, I was referring to the error propagation stuff in
Error.c, namely error_set(Error *err)

I don't it's clear to users when socket_error() should be used as
opposed to errno (or nothing at all), especially in a utility function like
this that makes a lot of system calls. errno actually gets used
explicitly in a few spots in qemu-sockets.c, for w32, ironically, so
it's missed completely by socket_error()/WSAGetLastError() checks.

Unfortunately, creating distinct error classes for every permutation of
bind/listen/connect/socket and EINPROGRESS/EWOULDBLOCK/EINTR/EXXX is too
much.

But really the whole reason we now need error propagation is basically
just to let the new non-blocking users know when a connect() "failure" was
simply EINPROGRESS, right? For other errors the user probably just wants
to know what function failed (and maybe a strerror(errno) but that's
not typically how we use Error/QError currently).

Currently, other than for ENOTSUP which we use errno for, everything in
qemu-sockets.c just prints errors to stderr and returns -1, 0, or a valid fd,
and no current users, AFAICT, check errno/socket_error()/etc.

So we're free to do it up nice and clean, and here's what I'd suggest:

1) Rename the following functions:

inet_listen_opts(...) -> inet_listen_opts_err(..., Error **errp)
inet_connect_opts(...) -> inet_connect_opts_err(..., Error **errp)
unix_listen_opts(...) -> inet_listen_opts_err(..., Error **errp)
unix_connect_opts(...) -> inet_connect_opts_err(..., Error **errp)
inet_dgram_opts(...) -> inet_listen_opts_err(..., Error **errp)

Make wrappers for the originals that call them with errp == NULL.

2) Add the following error classes to qerror.c/qerror.h:

QERR_SOCKET_CONNECT_IN_PROGRESS
QERR_SOCKET_CONNECT_FAILED
QERR_SOCKET_LISTEN_FAILED
QERR_SOCKET_BIND_FAILED
QERR_SOCKET_CREATE_FAILED

And maybe a handful of others that seem worth reporting.
QERR_UNDEFINED_ERROR is probably okay for the more obscure failures.

For inet_*_opts_err(), set these errors alongside where we currently print to
stderr and return -1. Handling errors for the others are probably outside the
scope of your patches and can be done easily enough later, but would be nice to
at least pass back QERR_UNDEFINED_ERROR as a place holder.

3) Add your non-blocking support, document
QERR_SOCKET_CONNECT_IN_PROGRESS as being significant in that the user
should begin select()'ing for completion, checking SO_ERROR, etc.

4) Use it for ipv6 migration.

IMO, anyway. I think the series is basically there otherwise, we just
have some nicer error-handling infrastructure in place since socket_error()
was first added and it makes sense to use if we need to introduce error
propagation to qemu-sockets.c

>  }
> 
>  int inet_connect_opts(QemuOpts *opts)
> @@ -474,6 +483,8 @@ int inet_listen(const char *str, char *ostr, int olen,
>                           optstr ? optstr : "");
>              }
>          }
> +    } else {
> +        set_socket_error(EINVAL);
>      }
>      qemu_opts_del(opts);
>      return sock;
> 

  reply	other threads:[~2012-03-27 23:15 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-19 14:11 [PATCH v4 0/2] support to migrate with IPv6 address Amos Kong
2012-03-19 14:11 ` [Qemu-devel] " Amos Kong
2012-03-19 14:11 ` [PATCH v4 1/2] qemu-socket: change inet_connect() to to support nonblock socket Amos Kong
2012-03-19 14:11   ` [Qemu-devel] " Amos Kong
2012-03-20 10:58   ` Orit Wasserman
2012-03-21 23:46   ` Michael Roth
2012-03-21 23:46     ` [Qemu-devel] " Michael Roth
2012-03-22  3:13     ` Amos Kong
2012-03-22  3:13       ` [Qemu-devel] " Amos Kong
2012-03-22  3:52     ` [PATCH v5 0/2] support to migrate with IPv6 address Amos Kong
2012-03-22  3:52       ` [Qemu-devel] " Amos Kong
2012-03-22  3:52       ` [PATCH v5 1/4] sockets: introduce set_socket_error() Amos Kong
2012-03-22  3:52         ` [Qemu-devel] " Amos Kong
2012-03-27 13:00         ` Orit Wasserman
2012-03-27 13:00           ` [Qemu-devel] " Orit Wasserman
2012-03-27 14:56           ` [PATCH v6 " Amos Kong
2012-03-27 14:56             ` [Qemu-devel] " Amos Kong
2012-03-22  3:52       ` [PATCH v5 2/4] qemu-socket: change inet_connect() to to support nonblock socket Amos Kong
2012-03-22  3:52         ` [Qemu-devel] " Amos Kong
2012-03-27 15:29         ` Orit Wasserman
2012-03-27 16:14           ` Amos Kong
2012-03-28  2:36             ` Amos Kong
2012-03-22  3:52       ` [PATCH v5 3/4] sockets: pass back errors in inet_listen() Amos Kong
2012-03-22  3:52         ` [Qemu-devel] " Amos Kong
2012-03-27 23:15         ` Michael Roth [this message]
2012-03-27 23:15           ` Michael Roth
2012-03-22  3:53       ` [PATCH v5 4/4] use inet_listen()/inet_connect() to support ipv6 migration Amos Kong
2012-03-22  3:53         ` [Qemu-devel] " Amos Kong
2012-03-19 14:12 ` [PATCH v4 2/2] " Amos Kong
2012-03-19 14:12   ` [Qemu-devel] " Amos Kong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120327231500.GA31300@illuin \
    --to=mdroth@linux.vnet.ibm.com \
    --cc=akong@redhat.com \
    --cc=aliguori@us.ibm.com \
    --cc=jasowang@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=laine@redhat.com \
    --cc=owasserm@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=quintela@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.