diff --git a/qemu-doc.texi b/qemu-doc.texi index 9f80f47ad9..f9924d286f 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -421,21 +421,21 @@ syntax for the @var{display} is @table @code -@item @var{interface}:@var{d} +@item @var{host}:@var{d} -TCP connections will only be allowed from @var{interface} on display @var{d}. -By convention the TCP port is 5900+@var{d}. Optionally, @var{interface} can -be omitted in which case the server will bind to all interfaces. +TCP connections will only be allowed from @var{host} on display @var{d}. +By convention the TCP port is 5900+@var{d}. Optionally, @var{host} can +be omitted in which case the server will accept connections from any host. -@item @var{unix}:@var{path} +@item @code{unix}:@var{path} Connections will be allowed over UNIX domain sockets where @var{path} is the location of a unix socket to listen for connections on. @item none -VNC is initialized by not started. The monitor @code{change} command can be used -to later start the VNC server. +VNC is initialized but not started. The monitor @code{change} command +can be used to later start the VNC server. @end table @@ -444,6 +444,13 @@ separated by commas. Valid options are @table @code +@item reverse + +Connect to a listening VNC client via a ``reverse'' connection. The +client is specified by the @var{display}. For reverse network +connections (@var{host}:@var{d},@code{reverse}), the @var{d} argument +is a TCP port number, not a display number. + @item password Require that password based authentication is used for client connections. diff --git a/vnc.c b/vnc.c index 64889de5a6..e7f3255c88 100644 --- a/vnc.c +++ b/vnc.c @@ -1898,6 +1898,22 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len) return 0; } +static void vnc_connect(VncState *vs) +{ + VNC_DEBUG("New client on socket %d\n", vs->csock); + socket_set_nonblock(vs->csock); + qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); + vnc_write(vs, "RFB 003.008\n", 12); + vnc_flush(vs); + vnc_read_when(vs, protocol_version, 12); + memset(vs->old_data, 0, vs->ds->linesize * vs->ds->height); + memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); + vs->has_resize = 0; + vs->has_hextile = 0; + vs->ds->dpy_copy = NULL; + vnc_update_client(vs); +} + static void vnc_listen_read(void *opaque) { VncState *vs = opaque; @@ -1909,18 +1925,7 @@ static void vnc_listen_read(void *opaque) vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); if (vs->csock != -1) { - VNC_DEBUG("New client on socket %d\n", vs->csock); - socket_set_nonblock(vs->csock); - qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque); - vnc_write(vs, "RFB 003.008\n", 12); - vnc_flush(vs); - vnc_read_when(vs, protocol_version, 12); - memset(vs->old_data, 0, vs->ds->linesize * vs->ds->height); - memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); - vs->has_resize = 0; - vs->has_hextile = 0; - vs->ds->dpy_copy = NULL; - vnc_update_client(vs); + vnc_connect(vs); } } @@ -2087,6 +2092,7 @@ int vnc_display_open(DisplayState *ds, const char *display) VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; const char *options; int password = 0; + int reverse = 0; #if CONFIG_VNC_TLS int tls = 0, x509 = 0; #endif @@ -2103,6 +2109,8 @@ int vnc_display_open(DisplayState *ds, const char *display) options++; if (strncmp(options, "password", 8) == 0) { password = 1; /* Require password auth */ + } else if (strncmp(options, "reverse", 7) == 0) { + reverse = 1; #if CONFIG_VNC_TLS } else if (strncmp(options, "tls", 3) == 0) { tls = 1; /* Require TLS */ @@ -2196,7 +2204,9 @@ int vnc_display_open(DisplayState *ds, const char *display) memset(uaddr.sun_path, 0, 108); snprintf(uaddr.sun_path, 108, "%s", p); - unlink(uaddr.sun_path); + if (!reverse) { + unlink(uaddr.sun_path); + } } else #endif { @@ -2210,7 +2220,7 @@ int vnc_display_open(DisplayState *ds, const char *display) return -1; } - iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900); + iaddr.sin_port = htons(ntohs(iaddr.sin_port) + (reverse ? 0 : 5900)); vs->lsock = socket(PF_INET, SOCK_STREAM, 0); if (vs->lsock == -1) { @@ -2233,6 +2243,22 @@ int vnc_display_open(DisplayState *ds, const char *display) } } + if (reverse) { + if (connect(vs->lsock, addr, addrlen) == -1) { + fprintf(stderr, "Connection to VNC client failed\n"); + close(vs->lsock); + vs->lsock = -1; + free(vs->display); + vs->display = NULL; + return -1; + } else { + vs->csock = vs->lsock; + vs->lsock = -1; + vnc_connect(vs); + return 0; + } + } + if (bind(vs->lsock, addr, addrlen) == -1) { fprintf(stderr, "bind() failed\n"); close(vs->lsock);