sockets: add helpers for creating SocketAddress from a socket

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>
This commit is contained in:
Daniel P. Berrange 2015-05-01 17:36:20 +01:00
parent c14e42d7a4
commit 17c55decec
2 changed files with 140 additions and 0 deletions

View File

@ -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 */

View File

@ -1018,3 +1018,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);
}