aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--console.h1
-rw-r--r--monitor.c32
-rw-r--r--qemu-char.c30
-rw-r--r--qemu-char.h2
-rw-r--r--qerror.c4
-rw-r--r--qerror.h3
-rw-r--r--qmp-commands.hx27
-rw-r--r--ui/vnc.c7
8 files changed, 100 insertions, 6 deletions
diff --git a/console.h b/console.h
index c09537b861..67d137384e 100644
--- a/console.h
+++ b/console.h
@@ -372,6 +372,7 @@ void cocoa_display_init(DisplayState *ds, int full_screen);
void vnc_display_init(DisplayState *ds);
void vnc_display_close(DisplayState *ds);
int vnc_display_open(DisplayState *ds, const char *display);
+void vnc_display_add_client(DisplayState *ds, int csock, int skipauth);
int vnc_display_disable_login(DisplayState *ds);
char *vnc_display_local_addr(DisplayState *ds);
#ifdef CONFIG_VNC
diff --git a/monitor.c b/monitor.c
index 67ceb46a62..718935b881 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1185,6 +1185,38 @@ static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
return -1;
}
+static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ const char *protocol = qdict_get_str(qdict, "protocol");
+ const char *fdname = qdict_get_str(qdict, "fdname");
+ int skipauth = qdict_get_try_bool(qdict, "skipauth", 0);
+ CharDriverState *s;
+
+ if (strcmp(protocol, "spice") == 0) {
+ if (!using_spice) {
+ /* correct one? spice isn't a device ,,, */
+ qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
+ return -1;
+ }
+ qerror_report(QERR_ADD_CLIENT_FAILED);
+ return -1;
+ } else if (strcmp(protocol, "vnc") == 0) {
+ int fd = monitor_get_fd(mon, fdname);
+ vnc_display_add_client(NULL, fd, skipauth);
+ return 0;
+ } else if ((s = qemu_chr_find(protocol)) != NULL) {
+ int fd = monitor_get_fd(mon, fdname);
+ if (qemu_chr_add_client(s, fd) < 0) {
+ qerror_report(QERR_ADD_CLIENT_FAILED);
+ return -1;
+ }
+ return 0;
+ }
+
+ qerror_report(QERR_INVALID_PARAMETER, "protocol");
+ return -1;
+}
+
static int client_migrate_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *protocol = qdict_get_str(qdict, "protocol");
diff --git a/qemu-char.c b/qemu-char.c
index 926987b98a..dcf706592b 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -168,6 +168,11 @@ int qemu_chr_get_msgfd(CharDriverState *s)
return s->get_msgfd ? s->get_msgfd(s) : -1;
}
+int qemu_chr_add_client(CharDriverState *s, int fd)
+{
+ return s->chr_add_client ? s->chr_add_client(s, fd) : -1;
+}
+
void qemu_chr_accept_input(CharDriverState *s)
{
if (s->chr_accept_input)
@@ -2146,6 +2151,22 @@ static void socket_set_nodelay(int fd)
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
}
+static int tcp_chr_add_client(CharDriverState *chr, int fd)
+{
+ TCPCharDriver *s = chr->opaque;
+ if (s->fd != -1)
+ return -1;
+
+ socket_set_nonblock(fd);
+ if (s->do_nodelay)
+ socket_set_nodelay(fd);
+ s->fd = fd;
+ qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+ tcp_chr_connect(chr);
+
+ return 0;
+}
+
static void tcp_chr_accept(void *opaque)
{
CharDriverState *chr = opaque;
@@ -2178,12 +2199,8 @@ static void tcp_chr_accept(void *opaque)
break;
}
}
- socket_set_nonblock(fd);
- if (s->do_nodelay)
- socket_set_nodelay(fd);
- s->fd = fd;
- qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
- tcp_chr_connect(chr);
+ if (tcp_chr_add_client(chr, fd) < 0)
+ close(fd);
}
static void tcp_chr_close(CharDriverState *chr)
@@ -2256,6 +2273,7 @@ static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr)
chr->chr_write = tcp_chr_write;
chr->chr_close = tcp_chr_close;
chr->get_msgfd = tcp_get_msgfd;
+ chr->chr_add_client = tcp_chr_add_client;
if (is_listen) {
s->listen_fd = fd;
diff --git a/qemu-char.h b/qemu-char.h
index 892c6da9aa..f361c6d281 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -57,6 +57,7 @@ struct CharDriverState {
void (*chr_update_read_handler)(struct CharDriverState *s);
int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg);
int (*get_msgfd)(struct CharDriverState *s);
+ int (*chr_add_client)(struct CharDriverState *chr, int fd);
IOEventHandler *chr_event;
IOCanReadHandler *chr_can_read;
IOReadHandler *chr_read;
@@ -99,6 +100,7 @@ int qemu_chr_can_read(CharDriverState *s);
void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len);
int qemu_chr_get_msgfd(CharDriverState *s);
void qemu_chr_accept_input(CharDriverState *s);
+int qemu_chr_add_client(CharDriverState *s, int fd);
void qemu_chr_info_print(Monitor *mon, const QObject *ret_data);
void qemu_chr_info(Monitor *mon, QObject **ret_data);
CharDriverState *qemu_chr_find(const char *name);
diff --git a/qerror.c b/qerror.c
index 229d0d63e3..69c1bc9af7 100644
--- a/qerror.c
+++ b/qerror.c
@@ -198,6 +198,10 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Could not set password",
},
{
+ .error_fmt = QERR_ADD_CLIENT_FAILED,
+ .desc = "Could not add client",
+ },
+ {
.error_fmt = QERR_TOO_MANY_FILES,
.desc = "Too many open files",
},
diff --git a/qerror.h b/qerror.h
index 7ec0fc12d7..8058456d2e 100644
--- a/qerror.h
+++ b/qerror.h
@@ -166,6 +166,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_SET_PASSWD_FAILED \
"{ 'class': 'SetPasswdFailed', 'data': {} }"
+#define QERR_ADD_CLIENT_FAILED \
+ "{ 'class': 'AddClientFailed', 'data': {} }"
+
#define QERR_TOO_MANY_FILES \
"{ 'class': 'TooManyFiles', 'data': {} }"
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 5d44edf4e7..54e313ce52 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -919,6 +919,33 @@ Example:
EQMP
{
+ .name = "add_client",
+ .args_type = "protocol:s,fdname:s,skipauth:b?",
+ .params = "protocol fdname skipauth",
+ .help = "add a graphics client",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = add_graphics_client,
+ },
+
+SQMP
+add_client
+----------
+
+Add a graphics client
+
+Arguments:
+
+- "protocol": protocol name (json-string)
+- "fdname": file descriptor name (json-string)
+
+Example:
+
+-> { "execute": "add_client", "arguments": { "protocol": "vnc",
+ "fdname": "myclient" } }
+<- { "return": {} }
+
+EQMP
+ {
.name = "qmp_capabilities",
.args_type = "",
.params = "",
diff --git a/ui/vnc.c b/ui/vnc.c
index 39b5b51fa9..8602adc68b 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2924,3 +2924,10 @@ int vnc_display_open(DisplayState *ds, const char *display)
}
return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
}
+
+void vnc_display_add_client(DisplayState *ds, int csock, int skipauth)
+{
+ VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+
+ return vnc_connect(vs, csock, skipauth);
+}