From b93dc15833a1e5c5f44695ace09a2143541727fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 4 Jul 2016 20:54:06 +0200 Subject: [PATCH 3/5] sockets: add helpers for creating SocketAddress from a socket MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RH-Author: Marc-André Lureau Message-id: <20160704205408.26004-4-marcandre.lureau@redhat.com> Patchwork-id: 70934 O-Subject: [RHEV-7.2.z qemu-kvm-rhev PATCH v2 3/5] sockets: add helpers for creating SocketAddress from a socket Bugzilla: 1351892 RH-Acked-by: Victor Kaplansky RH-Acked-by: Xiao Wang RH-Acked-by: Paolo Bonzini From: "Daniel P. Berrange" 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 (cherry picked from commit 17c55decec2a516cf7f290ec8a5f4f207531e8b4) Signed-off-by: Marc-André Lureau Signed-off-by: Miroslav Rezanina --- include/qemu/sockets.h | 30 ++++++++++++++ util/qemu-sockets.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index 7992ece..dd562f4 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -89,4 +89,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 87c9bc6..ddc48cf 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -1003,3 +1003,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", + 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->has_ipv4 = addr->inet->ipv4 = true; + } else { + addr->inet->has_ipv6 = 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); +} -- 1.8.3.1