ui: convert VNC startup code to use SocketAddress

The VNC code is currently using QemuOpts to configure the
sockets connections / listeners it needs. Convert it to
use SocketAddress to bring it in line with modern QAPI
based code elsewhere in QEMU.

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
master
Daniel P. Berrange 2015-08-14 18:56:44 +01:00
parent 0983f5e6af
commit e0d03b8ceb
1 changed files with 91 additions and 71 deletions

162
ui/vnc.c
View File

@ -3506,18 +3506,14 @@ void vnc_display_open(const char *id, Error **errp)
{ {
VncDisplay *vs = vnc_display_find(id); VncDisplay *vs = vnc_display_find(id);
QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id); QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
QemuOpts *sopts, *wsopts; SocketAddress *saddr = NULL, *wsaddr = NULL;
const char *share, *device_id; const char *share, *device_id;
QemuConsole *con; QemuConsole *con;
bool password = false; bool password = false;
bool reverse = false; bool reverse = false;
const char *vnc; const char *vnc;
const char *has_to;
char *h; char *h;
bool has_ipv4 = false;
bool has_ipv6 = false;
const char *credid; const char *credid;
const char *websocket;
bool sasl = false; bool sasl = false;
#ifdef CONFIG_VNC_SASL #ifdef CONFIG_VNC_SASL
int saslErr; int saslErr;
@ -3539,44 +3535,83 @@ void vnc_display_open(const char *id, Error **errp)
return; return;
} }
sopts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
wsopts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
h = strrchr(vnc, ':'); h = strrchr(vnc, ':');
if (h) { if (h) {
char *host;
size_t hlen = h - vnc; size_t hlen = h - vnc;
if (vnc[0] == '[' && vnc[hlen - 1] == ']') { const char *websocket = qemu_opt_get(opts, "websocket");
host = g_strndup(vnc + 1, hlen - 2); int to = qemu_opt_get_number(opts, "to", 0);
} else { bool has_ipv4 = qemu_opt_get_bool(opts, "ipv4", false);
host = g_strndup(vnc, hlen); bool has_ipv6 = qemu_opt_get_bool(opts, "ipv6", false);
saddr = g_new0(SocketAddress, 1);
if (websocket) {
if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) {
error_setg(errp,
"SHA1 hash support is required for websockets");
goto fail;
}
wsaddr = g_new0(SocketAddress, 1);
vs->ws_enabled = true;
}
if (strncmp(vnc, "unix:", 5) == 0) {
saddr->kind = SOCKET_ADDRESS_KIND_UNIX;
saddr->q_unix = g_new0(UnixSocketAddress, 1);
saddr->q_unix->path = g_strdup(vnc + 5);
if (vs->ws_enabled) {
error_setg(errp, "UNIX sockets not supported with websock");
goto fail;
}
} else {
unsigned long long baseport;
saddr->kind = SOCKET_ADDRESS_KIND_INET;
saddr->inet = g_new0(InetSocketAddress, 1);
if (vnc[0] == '[' && vnc[hlen - 1] == ']') {
saddr->inet->host = g_strndup(vnc + 1, hlen - 2);
} else {
saddr->inet->host = g_strndup(vnc, hlen);
}
if (parse_uint_full(h + 1, &baseport, 10) < 0) {
error_setg(errp, "can't convert to a number: %s", h + 1);
goto fail;
}
if (baseport > 65535 ||
baseport + 5900 > 65535) {
error_setg(errp, "port %s out of range", h + 1);
goto fail;
}
saddr->inet->port = g_strdup_printf(
"%d", (int)baseport + 5900);
if (to) {
saddr->inet->has_to = true;
saddr->inet->to = to;
}
saddr->inet->ipv4 = saddr->inet->has_ipv4 = has_ipv4;
saddr->inet->ipv6 = saddr->inet->has_ipv6 = has_ipv6;
if (vs->ws_enabled) {
wsaddr->kind = SOCKET_ADDRESS_KIND_INET;
wsaddr->inet = g_new0(InetSocketAddress, 1);
wsaddr->inet->host = g_strdup(saddr->inet->host);
wsaddr->inet->port = g_strdup(websocket);
if (to) {
wsaddr->inet->has_to = true;
wsaddr->inet->to = to;
}
wsaddr->inet->ipv4 = wsaddr->inet->has_ipv4 = has_ipv4;
wsaddr->inet->ipv6 = wsaddr->inet->has_ipv6 = has_ipv6;
}
} }
qemu_opt_set(sopts, "host", host, &error_abort);
qemu_opt_set(wsopts, "host", host, &error_abort);
qemu_opt_set(sopts, "port", h+1, &error_abort);
g_free(host);
} else { } else {
error_setg(errp, "no vnc port specified"); error_setg(errp, "no vnc port specified");
goto fail; goto fail;
} }
has_to = qemu_opt_get(opts, "to");
has_ipv4 = qemu_opt_get_bool(opts, "ipv4", false);
has_ipv6 = qemu_opt_get_bool(opts, "ipv6", false);
if (has_to) {
qemu_opt_set(sopts, "to", has_to, &error_abort);
qemu_opt_set(wsopts, "to", has_to, &error_abort);
}
if (has_ipv4) {
qemu_opt_set(sopts, "ipv4", "on", &error_abort);
qemu_opt_set(wsopts, "ipv4", "on", &error_abort);
}
if (has_ipv6) {
qemu_opt_set(sopts, "ipv6", "on", &error_abort);
qemu_opt_set(wsopts, "ipv6", "on", &error_abort);
}
password = qemu_opt_get_bool(opts, "password", false); password = qemu_opt_get_bool(opts, "password", false);
if (password) { if (password) {
if (fips_get_state()) { if (fips_get_state()) {
@ -3682,16 +3717,6 @@ void vnc_display_open(const char *id, Error **errp)
} }
vs->connections_limit = qemu_opt_get_number(opts, "connections", 32); vs->connections_limit = qemu_opt_get_number(opts, "connections", 32);
websocket = qemu_opt_get(opts, "websocket");
if (websocket) {
vs->ws_enabled = true;
qemu_opt_set(wsopts, "port", websocket, &error_abort);
if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) {
error_setg(errp, "SHA1 hash support is required for websockets");
goto fail;
}
}
#ifdef CONFIG_VNC_JPEG #ifdef CONFIG_VNC_JPEG
vs->lossy = qemu_opt_get_bool(opts, "lossy", false); vs->lossy = qemu_opt_get_bool(opts, "lossy", false);
#endif #endif
@ -3725,7 +3750,7 @@ void vnc_display_open(const char *id, Error **errp)
} }
#endif #endif
if (vnc_display_setup_auth(vs, password, sasl, websocket, errp) < 0) { if (vnc_display_setup_auth(vs, password, sasl, vs->ws_enabled, errp) < 0) {
goto fail; goto fail;
} }
@ -3770,37 +3795,31 @@ void vnc_display_open(const char *id, Error **errp)
int csock; int csock;
vs->lsock = -1; vs->lsock = -1;
vs->lwebsock = -1; vs->lwebsock = -1;
if (strncmp(vnc, "unix:", 5) == 0) { if (vs->ws_enabled) {
csock = unix_connect(vnc+5, errp); error_setg(errp, "Cannot use websockets in reverse mode");
} else { goto fail;
csock = inet_connect(vnc, errp);
} }
csock = socket_connect(saddr, errp, NULL, NULL);
if (csock < 0) { if (csock < 0) {
goto fail; goto fail;
} }
vs->is_unix = saddr->kind == SOCKET_ADDRESS_KIND_UNIX;
vnc_connect(vs, csock, false, false); vnc_connect(vs, csock, false, false);
} else { } else {
/* listen for connects */ /* listen for connects */
if (strncmp(vnc, "unix:", 5) == 0) { vs->lsock = socket_listen(saddr, errp);
vs->lsock = unix_listen(vnc+5, NULL, 0, errp); if (vs->lsock < 0) {
if (vs->lsock < 0) { goto fail;
goto fail; }
} vs->is_unix = saddr->kind == SOCKET_ADDRESS_KIND_UNIX;
vs->is_unix = true; if (vs->ws_enabled) {
} else { vs->lwebsock = socket_listen(wsaddr, errp);
vs->lsock = inet_listen_opts(sopts, 5900, errp); if (vs->lwebsock < 0) {
if (vs->lsock < 0) { if (vs->lsock != -1) {
goto fail; close(vs->lsock);
} vs->lsock = -1;
if (vs->ws_enabled) {
vs->lwebsock = inet_listen_opts(wsopts, 0, errp);
if (vs->lwebsock < 0) {
if (vs->lsock != -1) {
close(vs->lsock);
vs->lsock = -1;
}
goto fail;
} }
goto fail;
} }
} }
vs->enabled = true; vs->enabled = true;
@ -3810,13 +3829,14 @@ void vnc_display_open(const char *id, Error **errp)
NULL, vs); NULL, vs);
} }
} }
qemu_opts_del(sopts);
qemu_opts_del(wsopts); qapi_free_SocketAddress(saddr);
qapi_free_SocketAddress(wsaddr);
return; return;
fail: fail:
qemu_opts_del(sopts); qapi_free_SocketAddress(saddr);
qemu_opts_del(wsopts); qapi_free_SocketAddress(wsaddr);
vs->enabled = false; vs->enabled = false;
vs->ws_enabled = false; vs->ws_enabled = false;
} }