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:
parent
c14e42d7a4
commit
17c55decec
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user