qemu-ga patch queue for 2.8
* add guest-fstrim support for w32 * add support for using virtio-vsock as the communication channel -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJYF+gMAAoJEDNTyc7xCLWEeIAH/Agsx3ILwHSIknRY3xvO9zy3 F19ZU/pIVK0L8ykAP1vTSl/2M9REbs1koqLxpP56os0vXiibwwVAxeWGVGiBWzXk +/VUz31Tfg1OvxiBtmsUAWmBP7lE6V+C5EQJsA+fNcXRnmCLtUBFpZTru/ZAJev1 EEA4EYeM0tqqPsXOe1N9APEDzeCNh8zFiPkC1Xqpsx19rAC44bFMZNincfJ6BwKs 84kuoQ12owK+cJFqu8ovBEjfs8cdKSbsFgtqkNpzaR7NMQSUvBDYE1RMcmPQoU+Y W5glfrehsfyC+FR2fSHspfXiRkzKWedZslY0G7s8WTgnZryDiePZOPVGycMJbPY= =w0WU -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/mdroth/tags/qga-pull-2016-10-31-tag' into staging qemu-ga patch queue for 2.8 * add guest-fstrim support for w32 * add support for using virtio-vsock as the communication channel # gpg: Signature made Tue 01 Nov 2016 00:55:40 GMT # gpg: using RSA key 0x3353C9CEF108B584 # gpg: Good signature from "Michael Roth <flukshun@gmail.com>" # gpg: aka "Michael Roth <mdroth@utexas.edu>" # gpg: aka "Michael Roth <mdroth@linux.vnet.ibm.com>" # Primary key fingerprint: CEAC C9E1 5534 EBAB B82D 3FA0 3353 C9CE F108 B584 * remotes/mdroth/tags/qga-pull-2016-10-31-tag: qga: add vsock-listen method sockets: add AF_VSOCK support qga: drop unnecessary GA_CHANNEL_UNIX_LISTEN checks qga: drop unused sockaddr in accept(2) call qga: minimal support for fstrim for Windows guests Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
38ab359644
31
configure
vendored
31
configure
vendored
@ -4674,6 +4674,33 @@ if compile_prog "" "" ; then
|
|||||||
have_rtnetlink=yes
|
have_rtnetlink=yes
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# check for usable AF_VSOCK environment
|
||||||
|
have_af_vsock=no
|
||||||
|
cat > $TMPC << EOF
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#if !defined(AF_VSOCK)
|
||||||
|
# error missing AF_VSOCK flag
|
||||||
|
#endif
|
||||||
|
#include <linux/vm_sockets.h>
|
||||||
|
int main(void) {
|
||||||
|
int sock, ret;
|
||||||
|
struct sockaddr_vm svm;
|
||||||
|
socklen_t len = sizeof(svm);
|
||||||
|
sock = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||||
|
ret = getpeername(sock, (struct sockaddr *)&svm, &len);
|
||||||
|
if ((ret == -1) && (errno == ENOTCONN)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
if compile_prog "" "" ; then
|
||||||
|
have_af_vsock=yes
|
||||||
|
fi
|
||||||
|
|
||||||
#################################################
|
#################################################
|
||||||
# Sparc implicitly links with --relax, which is
|
# Sparc implicitly links with --relax, which is
|
||||||
# incompatible with -r, so --no-relax should be
|
# incompatible with -r, so --no-relax should be
|
||||||
@ -5662,6 +5689,10 @@ if test "$replication" = "yes" ; then
|
|||||||
echo "CONFIG_REPLICATION=y" >> $config_host_mak
|
echo "CONFIG_REPLICATION=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "$have_af_vsock" = "yes" ; then
|
||||||
|
echo "CONFIG_AF_VSOCK=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
|
||||||
# Hold two types of flag:
|
# Hold two types of flag:
|
||||||
# CONFIG_THREAD_SETNAME_BYTHREAD - we've got a way of setting the name on
|
# CONFIG_THREAD_SETNAME_BYTHREAD - we've got a way of setting the name on
|
||||||
# a thread we have a handle to
|
# a thread we have a handle to
|
||||||
|
@ -1063,12 +1063,14 @@
|
|||||||
#
|
#
|
||||||
# @unix: unix socket
|
# @unix: unix socket
|
||||||
#
|
#
|
||||||
|
# @vsock: vsock family (since 2.8)
|
||||||
|
#
|
||||||
# @unknown: otherwise
|
# @unknown: otherwise
|
||||||
#
|
#
|
||||||
# Since: 2.1
|
# Since: 2.1
|
||||||
##
|
##
|
||||||
{ 'enum': 'NetworkAddressFamily',
|
{ 'enum': 'NetworkAddressFamily',
|
||||||
'data': [ 'ipv4', 'ipv6', 'unix', 'unknown' ] }
|
'data': [ 'ipv4', 'ipv6', 'unix', 'vsock', 'unknown' ] }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @VncBasicInfo
|
# @VncBasicInfo
|
||||||
@ -3094,6 +3096,24 @@
|
|||||||
'data': {
|
'data': {
|
||||||
'path': 'str' } }
|
'path': 'str' } }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @VsockSocketAddress
|
||||||
|
#
|
||||||
|
# Captures a socket address in the vsock namespace.
|
||||||
|
#
|
||||||
|
# @cid: unique host identifier
|
||||||
|
# @port: port
|
||||||
|
#
|
||||||
|
# Note that string types are used to allow for possible future hostname or
|
||||||
|
# service resolution support.
|
||||||
|
#
|
||||||
|
# Since 2.8
|
||||||
|
##
|
||||||
|
{ 'struct': 'VsockSocketAddress',
|
||||||
|
'data': {
|
||||||
|
'cid': 'str',
|
||||||
|
'port': 'str' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @SocketAddress
|
# @SocketAddress
|
||||||
#
|
#
|
||||||
@ -3105,6 +3125,7 @@
|
|||||||
'data': {
|
'data': {
|
||||||
'inet': 'InetSocketAddress',
|
'inet': 'InetSocketAddress',
|
||||||
'unix': 'UnixSocketAddress',
|
'unix': 'UnixSocketAddress',
|
||||||
|
'vsock': 'VsockSocketAddress',
|
||||||
'fd': 'String' } }
|
'fd': 'String' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -26,13 +26,10 @@ static gboolean ga_channel_listen_accept(GIOChannel *channel,
|
|||||||
GAChannel *c = data;
|
GAChannel *c = data;
|
||||||
int ret, client_fd;
|
int ret, client_fd;
|
||||||
bool accepted = false;
|
bool accepted = false;
|
||||||
struct sockaddr_un addr;
|
|
||||||
socklen_t addrlen = sizeof(addr);
|
|
||||||
|
|
||||||
g_assert(channel != NULL);
|
g_assert(channel != NULL);
|
||||||
|
|
||||||
client_fd = qemu_accept(g_io_channel_unix_get_fd(channel),
|
client_fd = qemu_accept(g_io_channel_unix_get_fd(channel), NULL, NULL);
|
||||||
(struct sockaddr *)&addr, &addrlen);
|
|
||||||
if (client_fd == -1) {
|
if (client_fd == -1) {
|
||||||
g_warning("error converting fd to gsocket: %s", strerror(errno));
|
g_warning("error converting fd to gsocket: %s", strerror(errno));
|
||||||
goto out;
|
goto out;
|
||||||
@ -64,7 +61,6 @@ static void ga_channel_listen_add(GAChannel *c, int listen_fd, bool create)
|
|||||||
|
|
||||||
static void ga_channel_listen_close(GAChannel *c)
|
static void ga_channel_listen_close(GAChannel *c)
|
||||||
{
|
{
|
||||||
g_assert(c->method == GA_CHANNEL_UNIX_LISTEN);
|
|
||||||
g_assert(c->listen_channel);
|
g_assert(c->listen_channel);
|
||||||
g_io_channel_shutdown(c->listen_channel, true, NULL);
|
g_io_channel_shutdown(c->listen_channel, true, NULL);
|
||||||
g_io_channel_unref(c->listen_channel);
|
g_io_channel_unref(c->listen_channel);
|
||||||
@ -80,7 +76,7 @@ static void ga_channel_client_close(GAChannel *c)
|
|||||||
g_io_channel_shutdown(c->client_channel, true, NULL);
|
g_io_channel_shutdown(c->client_channel, true, NULL);
|
||||||
g_io_channel_unref(c->client_channel);
|
g_io_channel_unref(c->client_channel);
|
||||||
c->client_channel = NULL;
|
c->client_channel = NULL;
|
||||||
if (c->method == GA_CHANNEL_UNIX_LISTEN && c->listen_channel) {
|
if (c->listen_channel) {
|
||||||
ga_channel_listen_add(c, 0, false);
|
ga_channel_listen_add(c, 0, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,6 +193,31 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod
|
|||||||
ga_channel_listen_add(c, fd, true);
|
ga_channel_listen_add(c, fd, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case GA_CHANNEL_VSOCK_LISTEN: {
|
||||||
|
Error *local_err = NULL;
|
||||||
|
SocketAddress *addr;
|
||||||
|
char *addr_str;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
addr_str = g_strdup_printf("vsock:%s", path);
|
||||||
|
addr = socket_parse(addr_str, &local_err);
|
||||||
|
g_free(addr_str);
|
||||||
|
if (local_err != NULL) {
|
||||||
|
g_critical("%s", error_get_pretty(local_err));
|
||||||
|
error_free(local_err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = socket_listen(addr, &local_err);
|
||||||
|
qapi_free_SocketAddress(addr);
|
||||||
|
if (local_err != NULL) {
|
||||||
|
g_critical("%s", error_get_pretty(local_err));
|
||||||
|
error_free(local_err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ga_channel_listen_add(c, fd, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
g_critical("error binding/listening to specified socket");
|
g_critical("error binding/listening to specified socket");
|
||||||
return false;
|
return false;
|
||||||
@ -258,8 +279,7 @@ GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
|
|||||||
|
|
||||||
void ga_channel_free(GAChannel *c)
|
void ga_channel_free(GAChannel *c)
|
||||||
{
|
{
|
||||||
if (c->method == GA_CHANNEL_UNIX_LISTEN
|
if (c->listen_channel) {
|
||||||
&& c->listen_channel) {
|
|
||||||
ga_channel_listen_close(c);
|
ga_channel_listen_close(c);
|
||||||
}
|
}
|
||||||
if (c->client_channel) {
|
if (c->client_channel) {
|
||||||
|
@ -19,6 +19,7 @@ typedef enum {
|
|||||||
GA_CHANNEL_VIRTIO_SERIAL,
|
GA_CHANNEL_VIRTIO_SERIAL,
|
||||||
GA_CHANNEL_ISA_SERIAL,
|
GA_CHANNEL_ISA_SERIAL,
|
||||||
GA_CHANNEL_UNIX_LISTEN,
|
GA_CHANNEL_UNIX_LISTEN,
|
||||||
|
GA_CHANNEL_VSOCK_LISTEN,
|
||||||
} GAChannelMethod;
|
} GAChannelMethod;
|
||||||
|
|
||||||
typedef gboolean (*GAChannelCallback)(GIOCondition condition, gpointer opaque);
|
typedef gboolean (*GAChannelCallback)(GIOCondition condition, gpointer opaque);
|
||||||
|
@ -840,8 +840,99 @@ static void guest_fsfreeze_cleanup(void)
|
|||||||
GuestFilesystemTrimResponse *
|
GuestFilesystemTrimResponse *
|
||||||
qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
|
qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
|
||||||
{
|
{
|
||||||
error_setg(errp, QERR_UNSUPPORTED);
|
GuestFilesystemTrimResponse *resp;
|
||||||
return NULL;
|
HANDLE handle;
|
||||||
|
WCHAR guid[MAX_PATH] = L"";
|
||||||
|
|
||||||
|
handle = FindFirstVolumeW(guid, ARRAYSIZE(guid));
|
||||||
|
if (handle == INVALID_HANDLE_VALUE) {
|
||||||
|
error_setg_win32(errp, GetLastError(), "failed to find any volume");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = g_new0(GuestFilesystemTrimResponse, 1);
|
||||||
|
|
||||||
|
do {
|
||||||
|
GuestFilesystemTrimResult *res;
|
||||||
|
GuestFilesystemTrimResultList *list;
|
||||||
|
PWCHAR uc_path;
|
||||||
|
DWORD char_count = 0;
|
||||||
|
char *path, *out;
|
||||||
|
GError *gerr = NULL;
|
||||||
|
gchar * argv[4];
|
||||||
|
|
||||||
|
GetVolumePathNamesForVolumeNameW(guid, NULL, 0, &char_count);
|
||||||
|
|
||||||
|
if (GetLastError() != ERROR_MORE_DATA) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (GetDriveTypeW(guid) != DRIVE_FIXED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uc_path = g_malloc(sizeof(WCHAR) * char_count);
|
||||||
|
if (!GetVolumePathNamesForVolumeNameW(guid, uc_path, char_count,
|
||||||
|
&char_count) || !*uc_path) {
|
||||||
|
/* strange, but this condition could be faced even with size == 2 */
|
||||||
|
g_free(uc_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = g_new0(GuestFilesystemTrimResult, 1);
|
||||||
|
|
||||||
|
path = g_utf16_to_utf8(uc_path, char_count, NULL, NULL, &gerr);
|
||||||
|
|
||||||
|
g_free(uc_path);
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
res->has_error = true;
|
||||||
|
res->error = g_strdup(gerr->message);
|
||||||
|
g_error_free(gerr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res->path = path;
|
||||||
|
|
||||||
|
list = g_new0(GuestFilesystemTrimResultList, 1);
|
||||||
|
list->value = res;
|
||||||
|
list->next = resp->paths;
|
||||||
|
|
||||||
|
resp->paths = list;
|
||||||
|
|
||||||
|
memset(argv, 0, sizeof(argv));
|
||||||
|
argv[0] = (gchar *)"defrag.exe";
|
||||||
|
argv[1] = (gchar *)"/L";
|
||||||
|
argv[2] = path;
|
||||||
|
|
||||||
|
if (!g_spawn_sync(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
|
||||||
|
&out /* stdout */, NULL /* stdin */,
|
||||||
|
NULL, &gerr)) {
|
||||||
|
res->has_error = true;
|
||||||
|
res->error = g_strdup(gerr->message);
|
||||||
|
g_error_free(gerr);
|
||||||
|
} else {
|
||||||
|
/* defrag.exe is UGLY. Exit code is ALWAYS zero.
|
||||||
|
Error is reported in the output with something like
|
||||||
|
(x89000020) etc code in the stdout */
|
||||||
|
|
||||||
|
int i;
|
||||||
|
gchar **lines = g_strsplit(out, "\r\n", 0);
|
||||||
|
g_free(out);
|
||||||
|
|
||||||
|
for (i = 0; lines[i] != NULL; i++) {
|
||||||
|
if (g_strstr_len(lines[i], -1, "(0x") == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
res->has_error = true;
|
||||||
|
res->error = g_strdup(lines[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
g_strfreev(lines);
|
||||||
|
}
|
||||||
|
} while (FindNextVolumeW(handle, guid, ARRAYSIZE(guid)));
|
||||||
|
|
||||||
|
FindVolumeClose(handle);
|
||||||
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -1416,7 +1507,7 @@ GList *ga_command_blacklist_init(GList *blacklist)
|
|||||||
"guest-get-memory-blocks", "guest-set-memory-blocks",
|
"guest-get-memory-blocks", "guest-set-memory-blocks",
|
||||||
"guest-get-memory-block-size",
|
"guest-get-memory-block-size",
|
||||||
"guest-fsfreeze-freeze-list",
|
"guest-fsfreeze-freeze-list",
|
||||||
"guest-fstrim", NULL};
|
NULL};
|
||||||
char **p = (char **)list_unsupported;
|
char **p = (char **)list_unsupported;
|
||||||
|
|
||||||
while (*p) {
|
while (*p) {
|
||||||
|
@ -190,8 +190,8 @@ static void usage(const char *cmd)
|
|||||||
"Usage: %s [-m <method> -p <path>] [<options>]\n"
|
"Usage: %s [-m <method> -p <path>] [<options>]\n"
|
||||||
"QEMU Guest Agent %s\n"
|
"QEMU Guest Agent %s\n"
|
||||||
"\n"
|
"\n"
|
||||||
" -m, --method transport method: one of unix-listen, virtio-serial, or\n"
|
" -m, --method transport method: one of unix-listen, virtio-serial,\n"
|
||||||
" isa-serial (virtio-serial is the default)\n"
|
" isa-serial, or vsock-listen (virtio-serial is the default)\n"
|
||||||
" -p, --path device/socket path (the default for virtio-serial is:\n"
|
" -p, --path device/socket path (the default for virtio-serial is:\n"
|
||||||
" %s,\n"
|
" %s,\n"
|
||||||
" the default for isa-serial is:\n"
|
" the default for isa-serial is:\n"
|
||||||
@ -659,6 +659,8 @@ static gboolean channel_init(GAState *s, const gchar *method, const gchar *path)
|
|||||||
channel_method = GA_CHANNEL_ISA_SERIAL;
|
channel_method = GA_CHANNEL_ISA_SERIAL;
|
||||||
} else if (strcmp(method, "unix-listen") == 0) {
|
} else if (strcmp(method, "unix-listen") == 0) {
|
||||||
channel_method = GA_CHANNEL_UNIX_LISTEN;
|
channel_method = GA_CHANNEL_UNIX_LISTEN;
|
||||||
|
} else if (strcmp(method, "vsock-listen") == 0) {
|
||||||
|
channel_method = GA_CHANNEL_VSOCK_LISTEN;
|
||||||
} else {
|
} else {
|
||||||
g_critical("unsupported channel method/type: %s", method);
|
g_critical("unsupported channel method/type: %s", method);
|
||||||
return false;
|
return false;
|
||||||
|
@ -17,6 +17,10 @@
|
|||||||
*/
|
*/
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_AF_VSOCK
|
||||||
|
#include <linux/vm_sockets.h>
|
||||||
|
#endif /* CONFIG_AF_VSOCK */
|
||||||
|
|
||||||
#include "monitor/monitor.h"
|
#include "monitor/monitor.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qemu/sockets.h"
|
#include "qemu/sockets.h"
|
||||||
@ -75,6 +79,9 @@ NetworkAddressFamily inet_netfamily(int family)
|
|||||||
case PF_INET6: return NETWORK_ADDRESS_FAMILY_IPV6;
|
case PF_INET6: return NETWORK_ADDRESS_FAMILY_IPV6;
|
||||||
case PF_INET: return NETWORK_ADDRESS_FAMILY_IPV4;
|
case PF_INET: return NETWORK_ADDRESS_FAMILY_IPV4;
|
||||||
case PF_UNIX: return NETWORK_ADDRESS_FAMILY_UNIX;
|
case PF_UNIX: return NETWORK_ADDRESS_FAMILY_UNIX;
|
||||||
|
#ifdef CONFIG_AF_VSOCK
|
||||||
|
case PF_VSOCK: return NETWORK_ADDRESS_FAMILY_VSOCK;
|
||||||
|
#endif /* CONFIG_AF_VSOCK */
|
||||||
}
|
}
|
||||||
return NETWORK_ADDRESS_FAMILY_UNKNOWN;
|
return NETWORK_ADDRESS_FAMILY_UNKNOWN;
|
||||||
}
|
}
|
||||||
@ -650,6 +657,181 @@ int inet_connect(const char *str, Error **errp)
|
|||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_AF_VSOCK
|
||||||
|
static bool vsock_parse_vaddr_to_sockaddr(const VsockSocketAddress *vaddr,
|
||||||
|
struct sockaddr_vm *svm,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
unsigned long long val;
|
||||||
|
|
||||||
|
memset(svm, 0, sizeof(*svm));
|
||||||
|
svm->svm_family = AF_VSOCK;
|
||||||
|
|
||||||
|
if (parse_uint_full(vaddr->cid, &val, 10) < 0 ||
|
||||||
|
val > UINT32_MAX) {
|
||||||
|
error_setg(errp, "Failed to parse cid '%s'", vaddr->cid);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
svm->svm_cid = val;
|
||||||
|
|
||||||
|
if (parse_uint_full(vaddr->port, &val, 10) < 0 ||
|
||||||
|
val > UINT32_MAX) {
|
||||||
|
error_setg(errp, "Failed to parse port '%s'", vaddr->port);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
svm->svm_port = val;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vsock_connect_addr(const struct sockaddr_vm *svm, bool *in_progress,
|
||||||
|
ConnectState *connect_state, Error **errp)
|
||||||
|
{
|
||||||
|
int sock, rc;
|
||||||
|
|
||||||
|
*in_progress = false;
|
||||||
|
|
||||||
|
sock = qemu_socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to create socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (connect_state != NULL) {
|
||||||
|
qemu_set_nonblock(sock);
|
||||||
|
}
|
||||||
|
/* connect to peer */
|
||||||
|
do {
|
||||||
|
rc = 0;
|
||||||
|
if (connect(sock, (const struct sockaddr *)svm, sizeof(*svm)) < 0) {
|
||||||
|
rc = -errno;
|
||||||
|
}
|
||||||
|
} while (rc == -EINTR);
|
||||||
|
|
||||||
|
if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) {
|
||||||
|
connect_state->fd = sock;
|
||||||
|
qemu_set_fd_handler(sock, NULL, wait_for_connect, connect_state);
|
||||||
|
*in_progress = true;
|
||||||
|
} else if (rc < 0) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to connect socket");
|
||||||
|
closesocket(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vsock_connect_saddr(VsockSocketAddress *vaddr, Error **errp,
|
||||||
|
NonBlockingConnectHandler *callback,
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
struct sockaddr_vm svm;
|
||||||
|
int sock = -1;
|
||||||
|
bool in_progress;
|
||||||
|
ConnectState *connect_state = NULL;
|
||||||
|
|
||||||
|
if (!vsock_parse_vaddr_to_sockaddr(vaddr, &svm, errp)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback != NULL) {
|
||||||
|
connect_state = g_malloc0(sizeof(*connect_state));
|
||||||
|
connect_state->callback = callback;
|
||||||
|
connect_state->opaque = opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock = vsock_connect_addr(&svm, &in_progress, connect_state, errp);
|
||||||
|
if (sock < 0) {
|
||||||
|
/* do nothing */
|
||||||
|
} else if (in_progress) {
|
||||||
|
/* wait_for_connect() will do the rest */
|
||||||
|
return sock;
|
||||||
|
} else {
|
||||||
|
if (callback) {
|
||||||
|
callback(sock, NULL, opaque);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_free(connect_state);
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vsock_listen_saddr(VsockSocketAddress *vaddr,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
struct sockaddr_vm svm;
|
||||||
|
int slisten;
|
||||||
|
|
||||||
|
if (!vsock_parse_vaddr_to_sockaddr(vaddr, &svm, errp)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
slisten = qemu_socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||||
|
if (slisten < 0) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to create socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(slisten, (const struct sockaddr *)&svm, sizeof(svm)) != 0) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to bind socket");
|
||||||
|
closesocket(slisten);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(slisten, 1) != 0) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to listen on socket");
|
||||||
|
closesocket(slisten);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return slisten;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VsockSocketAddress *vsock_parse(const char *str, Error **errp)
|
||||||
|
{
|
||||||
|
VsockSocketAddress *addr = NULL;
|
||||||
|
char cid[33];
|
||||||
|
char port[33];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (sscanf(str, "%32[^:]:%32[^,]%n", cid, port, &n) != 2) {
|
||||||
|
error_setg(errp, "error parsing address '%s'", str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (str[n] != '\0') {
|
||||||
|
error_setg(errp, "trailing characters in address '%s'", str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = g_new0(VsockSocketAddress, 1);
|
||||||
|
addr->cid = g_strdup(cid);
|
||||||
|
addr->port = g_strdup(port);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void vsock_unsupported(Error **errp)
|
||||||
|
{
|
||||||
|
error_setg(errp, "socket family AF_VSOCK unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vsock_connect_saddr(VsockSocketAddress *vaddr, Error **errp,
|
||||||
|
NonBlockingConnectHandler *callback,
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
vsock_unsupported(errp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vsock_listen_saddr(VsockSocketAddress *vaddr,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
vsock_unsupported(errp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VsockSocketAddress *vsock_parse(const char *str, Error **errp)
|
||||||
|
{
|
||||||
|
vsock_unsupported(errp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_AF_VSOCK */
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
|
||||||
static int unix_listen_saddr(UnixSocketAddress *saddr,
|
static int unix_listen_saddr(UnixSocketAddress *saddr,
|
||||||
@ -864,6 +1046,12 @@ SocketAddress *socket_parse(const char *str, Error **errp)
|
|||||||
addr->u.fd.data = g_new(String, 1);
|
addr->u.fd.data = g_new(String, 1);
|
||||||
addr->u.fd.data->str = g_strdup(str + 3);
|
addr->u.fd.data->str = g_strdup(str + 3);
|
||||||
}
|
}
|
||||||
|
} else if (strstart(str, "vsock:", NULL)) {
|
||||||
|
addr->type = SOCKET_ADDRESS_KIND_VSOCK;
|
||||||
|
addr->u.vsock.data = vsock_parse(str + strlen("vsock:"), errp);
|
||||||
|
if (addr->u.vsock.data == NULL) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
addr->type = SOCKET_ADDRESS_KIND_INET;
|
addr->type = SOCKET_ADDRESS_KIND_INET;
|
||||||
addr->u.inet.data = inet_parse(str, errp);
|
addr->u.inet.data = inet_parse(str, errp);
|
||||||
@ -900,6 +1088,10 @@ int socket_connect(SocketAddress *addr, Error **errp,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SOCKET_ADDRESS_KIND_VSOCK:
|
||||||
|
fd = vsock_connect_saddr(addr->u.vsock.data, errp, callback, opaque);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@ -923,6 +1115,10 @@ int socket_listen(SocketAddress *addr, Error **errp)
|
|||||||
fd = monitor_get_fd(cur_mon, addr->u.fd.data->str, errp);
|
fd = monitor_get_fd(cur_mon, addr->u.fd.data->str, errp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SOCKET_ADDRESS_KIND_VSOCK:
|
||||||
|
fd = vsock_listen_saddr(addr->u.vsock.data, errp);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@ -1022,6 +1218,26 @@ socket_sockaddr_to_address_unix(struct sockaddr_storage *sa,
|
|||||||
}
|
}
|
||||||
#endif /* WIN32 */
|
#endif /* WIN32 */
|
||||||
|
|
||||||
|
#ifdef CONFIG_AF_VSOCK
|
||||||
|
static SocketAddress *
|
||||||
|
socket_sockaddr_to_address_vsock(struct sockaddr_storage *sa,
|
||||||
|
socklen_t salen,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
SocketAddress *addr;
|
||||||
|
VsockSocketAddress *vaddr;
|
||||||
|
struct sockaddr_vm *svm = (struct sockaddr_vm *)sa;
|
||||||
|
|
||||||
|
addr = g_new0(SocketAddress, 1);
|
||||||
|
addr->type = SOCKET_ADDRESS_KIND_VSOCK;
|
||||||
|
addr->u.vsock.data = vaddr = g_new0(VsockSocketAddress, 1);
|
||||||
|
vaddr->cid = g_strdup_printf("%u", svm->svm_cid);
|
||||||
|
vaddr->port = g_strdup_printf("%u", svm->svm_port);
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_AF_VSOCK */
|
||||||
|
|
||||||
SocketAddress *
|
SocketAddress *
|
||||||
socket_sockaddr_to_address(struct sockaddr_storage *sa,
|
socket_sockaddr_to_address(struct sockaddr_storage *sa,
|
||||||
socklen_t salen,
|
socklen_t salen,
|
||||||
@ -1037,6 +1253,11 @@ socket_sockaddr_to_address(struct sockaddr_storage *sa,
|
|||||||
return socket_sockaddr_to_address_unix(sa, salen, errp);
|
return socket_sockaddr_to_address_unix(sa, salen, errp);
|
||||||
#endif /* WIN32 */
|
#endif /* WIN32 */
|
||||||
|
|
||||||
|
#ifdef CONFIG_AF_VSOCK
|
||||||
|
case AF_VSOCK:
|
||||||
|
return socket_sockaddr_to_address_vsock(sa, salen, errp);
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error_setg(errp, "socket family %d unsupported",
|
error_setg(errp, "socket family %d unsupported",
|
||||||
sa->ss_family);
|
sa->ss_family);
|
||||||
@ -1103,6 +1324,12 @@ char *socket_address_to_string(struct SocketAddress *addr, Error **errp)
|
|||||||
buf = g_strdup(addr->u.fd.data->str);
|
buf = g_strdup(addr->u.fd.data->str);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SOCKET_ADDRESS_KIND_VSOCK:
|
||||||
|
buf = g_strdup_printf("%s:%s",
|
||||||
|
addr->u.vsock.data->cid,
|
||||||
|
addr->u.vsock.data->port);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error_setg(errp, "socket family %d unsupported",
|
error_setg(errp, "socket family %d unsupported",
|
||||||
addr->type);
|
addr->type);
|
||||||
|
Loading…
Reference in New Issue
Block a user