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 parse_host_port(struct sockaddr_in *saddr, const char *str);
 | 
				
			||||||
int socket_init(void);
 | 
					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 */
 | 
					#endif /* QEMU_SOCKET_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1018,3 +1018,113 @@ int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp)
 | 
				
			||||||
    qemu_opts_del(opts);
 | 
					    qemu_opts_del(opts);
 | 
				
			||||||
    return fd;
 | 
					    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