sockets: switch vnc to new code, support vnc port auto-allocation (Gerd Hoffman)

This patch switches the vnc code ofer to the new socket helper
functions.

It adds support IPv6 support and for automatically allocating an unused
vnc display port.  The latter is handled ising a to= option, specifying
the upper limit for the display number to try.  Scanning is started at
the display number given in the display specification, i.e. this command
line:

    -vnc localhost:7,to=11

will try displays 7 to 11 (inclusive).

There are also new "ipv4" and "ipv6" options to make qemu try only
the specified internet protocol version.

The display actually allocated can be queried using the "info vnc"
monitor command.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5696 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
aliguori 2008-11-11 20:51:59 +00:00
parent d247d25f18
commit 9712ecaf94
1 changed files with 26 additions and 87 deletions

113
vnc.c
View File

@ -2139,8 +2139,6 @@ static void vnc_listen_read(void *opaque)
} }
} }
extern int parse_host_port(struct sockaddr_in *saddr, const char *str);
void vnc_display_init(DisplayState *ds) void vnc_display_init(DisplayState *ds)
{ {
VncState *vs; VncState *vs;
@ -2291,18 +2289,11 @@ int vnc_display_password(DisplayState *ds, const char *password)
int vnc_display_open(DisplayState *ds, const char *display) int vnc_display_open(DisplayState *ds, const char *display)
{ {
struct sockaddr *addr;
struct sockaddr_in iaddr;
#ifndef _WIN32
struct sockaddr_un uaddr;
const char *p;
#endif
int reuse_addr, ret;
socklen_t addrlen;
VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
const char *options; const char *options;
int password = 0; int password = 0;
int reverse = 0; int reverse = 0;
int to_port = 0;
#ifdef CONFIG_VNC_TLS #ifdef CONFIG_VNC_TLS
int tls = 0, x509 = 0; int tls = 0, x509 = 0;
#endif #endif
@ -2321,6 +2312,8 @@ int vnc_display_open(DisplayState *ds, const char *display)
password = 1; /* Require password auth */ password = 1; /* Require password auth */
} else if (strncmp(options, "reverse", 7) == 0) { } else if (strncmp(options, "reverse", 7) == 0) {
reverse = 1; reverse = 1;
} else if (strncmp(options, "to=", 3) == 0) {
to_port = atoi(options+3) + 5900;
#ifdef CONFIG_VNC_TLS #ifdef CONFIG_VNC_TLS
} else if (strncmp(options, "tls", 3) == 0) { } else if (strncmp(options, "tls", 3) == 0) {
tls = 1; /* Require TLS */ tls = 1; /* Require TLS */
@ -2398,67 +2391,14 @@ int vnc_display_open(DisplayState *ds, const char *display)
} }
#endif #endif
} }
#ifndef _WIN32
if (strstart(display, "unix:", &p)) {
addr = (struct sockaddr *)&uaddr;
addrlen = sizeof(uaddr);
vs->lsock = socket(PF_UNIX, SOCK_STREAM, 0);
if (vs->lsock == -1) {
fprintf(stderr, "Could not create socket\n");
free(vs->display);
vs->display = NULL;
return -1;
}
uaddr.sun_family = AF_UNIX;
memset(uaddr.sun_path, 0, 108);
snprintf(uaddr.sun_path, 108, "%s", p);
if (!reverse) {
unlink(uaddr.sun_path);
}
} else
#endif
{
addr = (struct sockaddr *)&iaddr;
addrlen = sizeof(iaddr);
if (parse_host_port(&iaddr, display) < 0) {
fprintf(stderr, "Could not parse VNC address\n");
free(vs->display);
vs->display = NULL;
return -1;
}
iaddr.sin_port = htons(ntohs(iaddr.sin_port) + (reverse ? 0 : 5900));
vs->lsock = socket(PF_INET, SOCK_STREAM, 0);
if (vs->lsock == -1) {
fprintf(stderr, "Could not create socket\n");
free(vs->display);
vs->display = NULL;
return -1;
}
reuse_addr = 1;
ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR,
(const char *)&reuse_addr, sizeof(reuse_addr));
if (ret == -1) {
fprintf(stderr, "setsockopt() failed\n");
close(vs->lsock);
vs->lsock = -1;
free(vs->display);
vs->display = NULL;
return -1;
}
}
if (reverse) { if (reverse) {
if (connect(vs->lsock, addr, addrlen) == -1) { /* connect to viewer */
fprintf(stderr, "Connection to VNC client failed\n"); if (strncmp(display, "unix:", 5) == 0)
close(vs->lsock); vs->lsock = unix_connect(display+5);
vs->lsock = -1; else
vs->lsock = inet_connect(display, SOCK_STREAM);
if (-1 == vs->lsock) {
free(vs->display); free(vs->display);
vs->display = NULL; vs->display = NULL;
return -1; return -1;
@ -2466,26 +2406,25 @@ int vnc_display_open(DisplayState *ds, const char *display)
vs->csock = vs->lsock; vs->csock = vs->lsock;
vs->lsock = -1; vs->lsock = -1;
vnc_connect(vs); vnc_connect(vs);
return 0;
} }
} return 0;
if (bind(vs->lsock, addr, addrlen) == -1) { } else {
fprintf(stderr, "bind() failed\n"); /* listen for connects */
close(vs->lsock); char *dpy;
vs->lsock = -1; dpy = qemu_malloc(256);
free(vs->display); if (strncmp(display, "unix:", 5) == 0) {
vs->display = NULL; strcpy(dpy, "unix:");
return -1; vs->lsock = unix_listen(display, dpy+5, 256-5);
} } else {
vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
if (listen(vs->lsock, 1) == -1) { }
fprintf(stderr, "listen() failed\n"); if (-1 == vs->lsock) {
close(vs->lsock); free(dpy);
vs->lsock = -1; } else {
free(vs->display); free(vs->display);
vs->display = NULL; vs->display = dpy;
return -1; }
} }
return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs); return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);