diff mbox

[v2,01/16] sockets: add helpers for creating SocketAddress from a socket

Message ID 1444648509-29179-2-git-send-email-berrange@redhat.com
State New
Headers show

Commit Message

Daniel P. Berrangé Oct. 12, 2015, 11:14 a.m. UTC
Add two helper methods that, given a socket file descriptor,
can return a populated SocketAddress struct containing either
the local or remote address information.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/qemu/sockets.h |  30 ++++++++++++++
 util/qemu-sockets.c    | 110 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 140 insertions(+)

Comments

Eric Blake Oct. 19, 2015, 9:43 p.m. UTC | #1
On 10/12/2015 05:14 AM, Daniel P. Berrange wrote:
> Add two helper methods that, given a socket file descriptor,
> can return a populated SocketAddress struct containing either
> the local or remote address information.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  include/qemu/sockets.h |  30 ++++++++++++++
>  util/qemu-sockets.c    | 110 +++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 140 insertions(+)
> 

> +static SocketAddress *
> +socket_sockaddr_to_address_inet(struct sockaddr_storage *sa,
> +                                socklen_t salen,
> +                                Error **errp)
> +{
> +    char host[NI_MAXHOST];
> +    char serv[NI_MAXSERV];
> +    SocketAddress *addr;
> +    int ret;
> +
> +    ret = getnameinfo((struct sockaddr *)sa, salen,
> +                      host, sizeof(host),
> +                      serv, sizeof(serv),
> +                      NI_NUMERICHOST | NI_NUMERICSERV);
> +    if (ret != 0) {
> +        error_setg(errp, "Cannot format numeric socket address: %s\n",
> +                   gai_strerror(ret));

No trailing \n with error_setg(), please.

> +        return NULL;
> +    }
> +
> +    addr = g_new0(SocketAddress, 1);
> +    addr->kind = SOCKET_ADDRESS_KIND_INET;

I've got pending qapi patches that rename this to addr->type,

> +    addr->inet = g_new0(InetSocketAddress, 1);

and this to addr->u.inet.  Whoever merges first gets to watch the other
guy rebase :)

> +    addr->inet->host = g_strdup(host);
> +    addr->inet->port = g_strdup(serv);
> +    if (sa->ss_family == AF_INET) {
> +        addr->inet->ipv4 = true;
> +    } else {
> +        addr->inet->ipv6 = true;
> +    }

Don't we also need to set has_ipv4 and has_ipv6 appropriately?
Daniel P. Berrangé Oct. 20, 2015, 1:20 p.m. UTC | #2
On Mon, Oct 19, 2015 at 03:43:27PM -0600, Eric Blake wrote:
> On 10/12/2015 05:14 AM, Daniel P. Berrange wrote:
> > Add two helper methods that, given a socket file descriptor,
> > can return a populated SocketAddress struct containing either
> > the local or remote address information.
> > 
> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > ---
> >  include/qemu/sockets.h |  30 ++++++++++++++
> >  util/qemu-sockets.c    | 110 +++++++++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 140 insertions(+)
> > 
> 
> > +static SocketAddress *
> > +socket_sockaddr_to_address_inet(struct sockaddr_storage *sa,
> > +                                socklen_t salen,
> > +                                Error **errp)
> > +{
> > +    char host[NI_MAXHOST];
> > +    char serv[NI_MAXSERV];
> > +    SocketAddress *addr;
> > +    int ret;
> > +
> > +    ret = getnameinfo((struct sockaddr *)sa, salen,
> > +                      host, sizeof(host),
> > +                      serv, sizeof(serv),
> > +                      NI_NUMERICHOST | NI_NUMERICSERV);
> > +    if (ret != 0) {
> > +        error_setg(errp, "Cannot format numeric socket address: %s\n",
> > +                   gai_strerror(ret));
> 
> No trailing \n with error_setg(), please.
> 
> > +        return NULL;
> > +    }
> > +
> > +    addr = g_new0(SocketAddress, 1);
> > +    addr->kind = SOCKET_ADDRESS_KIND_INET;
> 
> I've got pending qapi patches that rename this to addr->type,
> 
> > +    addr->inet = g_new0(InetSocketAddress, 1);
> 
> and this to addr->u.inet.  Whoever merges first gets to watch the other
> guy rebase :)
> 
> > +    addr->inet->host = g_strdup(host);
> > +    addr->inet->port = g_strdup(serv);
> > +    if (sa->ss_family == AF_INET) {
> > +        addr->inet->ipv4 = true;
> > +    } else {
> > +        addr->inet->ipv6 = true;
> > +    }
> 
> Don't we also need to set has_ipv4 and has_ipv6 appropriately?

Yes, we do.


Regards,
Daniel
diff mbox

Patch

diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index c174b5c..3ea7cc9 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -88,4 +88,34 @@  int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp);
 int parse_host_port(struct sockaddr_in *saddr, const char *str);
 int socket_init(void);
 
+/**
+ * socket_local_address:
+ * @fd: the socket file handle
+ * @errp: pointer to uninitialized error object
+ *
+ * Get the string representation of the local socket
+ * address. A pointer to the allocated address information
+ * struct will be returned, which the caller is required to
+ * release with a call qapi_free_SocketAddress when no
+ * longer required.
+ *
+ * Returns: the socket address struct, or NULL on error
+ */
+SocketAddress *socket_local_address(int fd, Error **errp);
+
+/**
+ * socket_remote_address:
+ * @fd: the socket file handle
+ * @errp: pointer to uninitialized error object
+ *
+ * Get the string representation of the remote socket
+ * address. A pointer to the allocated address information
+ * struct will be returned, which the caller is required to
+ * release with a call qapi_free_SocketAddress when no
+ * longer required.
+ *
+ * Returns: the socket address struct, or NULL on error
+ */
+SocketAddress *socket_remote_address(int fd, Error **errp);
+
 #endif /* QEMU_SOCKET_H */
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 2add83a..2bdfacf 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -1015,3 +1015,113 @@  int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp)
     qemu_opts_del(opts);
     return fd;
 }
+
+
+static SocketAddress *
+socket_sockaddr_to_address_inet(struct sockaddr_storage *sa,
+                                socklen_t salen,
+                                Error **errp)
+{
+    char host[NI_MAXHOST];
+    char serv[NI_MAXSERV];
+    SocketAddress *addr;
+    int ret;
+
+    ret = getnameinfo((struct sockaddr *)sa, salen,
+                      host, sizeof(host),
+                      serv, sizeof(serv),
+                      NI_NUMERICHOST | NI_NUMERICSERV);
+    if (ret != 0) {
+        error_setg(errp, "Cannot format numeric socket address: %s\n",
+                   gai_strerror(ret));
+        return NULL;
+    }
+
+    addr = g_new0(SocketAddress, 1);
+    addr->kind = SOCKET_ADDRESS_KIND_INET;
+    addr->inet = g_new0(InetSocketAddress, 1);
+    addr->inet->host = g_strdup(host);
+    addr->inet->port = g_strdup(serv);
+    if (sa->ss_family == AF_INET) {
+        addr->inet->ipv4 = true;
+    } else {
+        addr->inet->ipv6 = true;
+    }
+
+    return addr;
+}
+
+
+#ifndef WIN32
+static SocketAddress *
+socket_sockaddr_to_address_unix(struct sockaddr_storage *sa,
+                                socklen_t salen,
+                                Error **errp)
+{
+    SocketAddress *addr;
+    struct sockaddr_un *su = (struct sockaddr_un *)sa;
+
+    addr = g_new0(SocketAddress, 1);
+    addr->kind = SOCKET_ADDRESS_KIND_UNIX;
+    addr->q_unix = g_new0(UnixSocketAddress, 1);
+    if (su->sun_path[0]) {
+        addr->q_unix->path = g_strndup(su->sun_path,
+                                       sizeof(su->sun_path));
+    }
+
+    return addr;
+}
+#endif /* WIN32 */
+
+static SocketAddress *
+socket_sockaddr_to_address(struct sockaddr_storage *sa,
+                           socklen_t salen,
+                           Error **errp)
+{
+    switch (sa->ss_family) {
+    case AF_INET:
+    case AF_INET6:
+        return socket_sockaddr_to_address_inet(sa, salen, errp);
+
+#ifndef WIN32
+    case AF_UNIX:
+        return socket_sockaddr_to_address_unix(sa, salen, errp);
+#endif /* WIN32 */
+
+    default:
+        error_setg(errp, "socket family %d unsupported",
+                   sa->ss_family);
+        return NULL;
+    }
+    return 0;
+}
+
+
+SocketAddress *socket_local_address(int fd, Error **errp)
+{
+    struct sockaddr_storage ss;
+    socklen_t sslen = sizeof(ss);
+
+    if (getsockname(fd, (struct sockaddr *)&ss, &sslen) < 0) {
+        error_setg_errno(errp, socket_error(), "%s",
+                         "Unable to query local socket address");
+        return NULL;
+    }
+
+    return socket_sockaddr_to_address(&ss, sslen, errp);
+}
+
+
+SocketAddress *socket_remote_address(int fd, Error **errp)
+{
+    struct sockaddr_storage ss;
+    socklen_t sslen = sizeof(ss);
+
+    if (getpeername(fd, (struct sockaddr *)&ss, &sslen) < 0) {
+        error_setg_errno(errp, socket_error(), "%s",
+                         "Unable to query remote socket address");
+        return NULL;
+    }
+
+    return socket_sockaddr_to_address(&ss, sslen, errp);
+}