@@ -1915,7 +1915,8 @@ return_err:
/* TCP Net console */
typedef struct {
- int fd, listen_fd;
+ int fd;
+ FdList *listen_fds;
int connected;
int max_size;
int do_telnetopt;
@@ -2068,6 +2069,7 @@ static void tcp_chr_read(void *opaque)
TCPCharDriver *s = chr->opaque;
uint8_t buf[READ_BUF_LEN];
int len, size;
+ FdList *fdl;
if (!s->connected || s->max_size <= 0)
return;
@@ -2078,9 +2080,8 @@ static void tcp_chr_read(void *opaque)
if (size == 0) {
/* connection closed */
s->connected = 0;
- if (s->listen_fd >= 0) {
- qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
- }
+ for (fdl = s->listen_fds; fdl != NULL; fdl = fdl->next)
+ qemu_set_fd_handler(fdl->fd, tcp_chr_accept, NULL, fdl);
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
closesocket(s->fd);
s->fd = -1;
@@ -2127,7 +2128,8 @@ static void socket_set_nodelay(int fd)
static void tcp_chr_accept(void *opaque)
{
- CharDriverState *chr = opaque;
+ FdList *fds = opaque;
+ CharDriverState *chr = fds->opaque;
TCPCharDriver *s = chr->opaque;
struct sockaddr_in saddr;
#ifndef _WIN32
@@ -2148,7 +2150,7 @@ static void tcp_chr_accept(void *opaque)
len = sizeof(saddr);
addr = (struct sockaddr *)&saddr;
}
- fd = qemu_accept(s->listen_fd, addr, &len);
+ fd = qemu_accept(fds->fd, addr, &len);
if (fd < 0 && errno != EINTR) {
return;
} else if (fd >= 0) {
@@ -2161,21 +2163,24 @@ static void tcp_chr_accept(void *opaque)
if (s->do_nodelay)
socket_set_nodelay(fd);
s->fd = fd;
- qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+ for (fds = s->listen_fds; fds != NULL; fds = fds->next)
+ qemu_set_fd_handler(fds->fd, NULL, NULL, NULL);
tcp_chr_connect(chr);
}
static void tcp_chr_close(CharDriverState *chr)
{
TCPCharDriver *s = chr->opaque;
+ FdList *fds;
if (s->fd >= 0) {
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
closesocket(s->fd);
}
- if (s->listen_fd >= 0) {
- qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
- closesocket(s->listen_fd);
+ for (fds = s->listen_fds; fds != NULL; fds = fds->next) {
+ qemu_set_fd_handler(fds->fd, NULL, NULL, NULL);
+ closesocket(fds->fd);
}
+ fdlist_free(fds);
qemu_free(s);
qemu_chr_event(chr, CHR_EVENT_CLOSED);
}
@@ -2190,6 +2195,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
int do_nodelay;
int is_unix;
int is_telnet;
+ FdList *socks = NULL;
is_listen = qemu_opt_get_bool(opts, "server", 0);
is_waitconnect = qemu_opt_get_bool(opts, "wait", 1);
@@ -2205,17 +2211,20 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
if (is_unix) {
if (is_listen) {
fd = unix_listen_opts(opts);
+ if (fd <= 0)
+ socks = fdlist_new(fd);
} else {
fd = unix_connect_opts(opts);
}
} else {
if (is_listen) {
- fd = inet_listen_opts(opts, 0);
+ socks = inet_listen_opts(opts, 0);
} else {
fd = inet_connect_opts(opts);
}
}
- if (fd < 0)
+
+ if (socks == NULL && fd < 0)
goto fail;
if (!is_waitconnect)
@@ -2223,7 +2232,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
s->connected = 0;
s->fd = -1;
- s->listen_fd = -1;
+ s->listen_fds = NULL;
s->msgfd = -1;
s->is_unix = is_unix;
s->do_nodelay = do_nodelay && !is_unix;
@@ -2234,8 +2243,11 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
chr->get_msgfd = tcp_get_msgfd;
if (is_listen) {
- s->listen_fd = fd;
- qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+ s->listen_fds = socks;
+ for (; socks != NULL; socks = socks->next) {
+ socks->opaque = chr;
+ qemu_set_fd_handler(socks->fd, tcp_chr_accept, NULL, socks);
+ }
if (is_telnet)
s->do_telnetopt = 1;
@@ -2266,7 +2278,9 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
printf("QEMU waiting for connection on: %s\n",
chr->filename);
tcp_chr_accept(chr);
- socket_set_nonblock(s->listen_fd);
+ for (socks = s->listen_fds; socks != NULL; socks = socks->next) {
+ socket_set_nonblock(socks->fd);
+ }
}
return chr;
@@ -2275,6 +2289,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
closesocket(fd);
qemu_free(s);
qemu_free(chr);
+ fdlist_free(socks);
return NULL;
}
@@ -57,6 +57,25 @@ static QemuOptsList dummy_opts = {
},
};
+FdList* fdlist_new(int fd)
+{
+ FdList *new = malloc(sizeof(FdList));
+ new->fd = fd;
+ new->opaque = NULL;
+ new->next = NULL;
+ return new;
+}
+
+void fdlist_free(FdList *fds)
+{
+ FdList *tmp;
+ while (fds) {
+ tmp = fds->next;
+ free(fds);
+ fds = tmp;
+ }
+}
+
static int inet_getport(struct addrinfo *e)
{
struct sockaddr_in *i4;
@@ -116,14 +135,15 @@ static void inet_print_addrinfo(const char *tag, struct addrinfo *res)
}
}
-int inet_listen_opts(QemuOpts *opts, int port_offset)
+FdList *inet_listen_opts(QemuOpts *opts, int port_offset)
{
- struct addrinfo ai,*res,*e;
+ struct addrinfo ai,*res,*e,*last=NULL;
const char *addr;
char port[33];
char uaddr[INET6_ADDRSTRLEN+1];
char uport[33];
int slisten,rc,to,try_next;
+ FdList *fds = NULL, *newfd;
memset(&ai,0, sizeof(ai));
ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
@@ -132,7 +152,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
if (qemu_opt_get(opts, "port") == NULL) {
fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__);
- return -1;
+ return NULL;
}
pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
addr = qemu_opt_get(opts, "host");
@@ -150,7 +170,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
if (rc != 0) {
fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
gai_strerror(rc));
- return -1;
+ return NULL;
}
if (sockets_debug)
inet_print_addrinfo(__FUNCTION__, res);
@@ -170,9 +190,9 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
#ifdef IPV6_V6ONLY
if (e->ai_family == PF_INET6) {
- /* listen on both ipv4 and ipv6 */
- setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off,
- sizeof(off));
+ /* listen on IPv6 only, IPv4 is handled by a separate socket */
+ setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&on,
+ sizeof(on));
}
#endif
@@ -181,9 +201,19 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
if (sockets_debug)
fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
inet_strfamily(e->ai_family), uaddr, inet_getport(e));
- goto listen;
+ if (listen(slisten, 1) != 0) {
+ closesocket(slisten);
+ } else {
+ fprintf(stderr, "slisten= %d\n", slisten);
+ newfd = fdlist_new(slisten);
+ newfd->next = fds;
+ fds = newfd;
+ last = e;
+ }
+ break;
}
try_next = to && (inet_getport(e) <= to + port_offset);
+ /* FIXME: should make sure that all sockets get the same port */
if (!try_next || sockets_debug)
fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
inet_strfamily(e->ai_family), uaddr, inet_getport(e),
@@ -192,28 +222,23 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
inet_setport(e, inet_getport(e) + 1);
continue;
}
+ closesocket(slisten);
break;
}
- closesocket(slisten);
}
+ if (fds == NULL) {
fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
- freeaddrinfo(res);
- return -1;
-
-listen:
- if (listen(slisten,1) != 0) {
- perror("listen");
- closesocket(slisten);
- freeaddrinfo(res);
- return -1;
- }
- snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset);
+ } else {
+ /* FIXME: should save all addresses here, not just the last one */
+ snprintf(uport, sizeof(uport), "%d", inet_getport(last) - port_offset);
qemu_opt_set(opts, "host", uaddr);
qemu_opt_set(opts, "port", uport);
- qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off");
- qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off");
+ qemu_opt_set(opts, "ipv6", (last->ai_family == PF_INET6) ? "on" : "off");
+ qemu_opt_set(opts, "ipv4", (last->ai_family != PF_INET6) ? "on" : "off");
+ }
freeaddrinfo(res);
- return slisten;
+ fprintf (stderr, "fds=%p\n", fds);
+ return fds;
}
int inet_connect_opts(QemuOpts *opts)
@@ -456,17 +481,17 @@ static int inet_parse(QemuOpts *opts, const char *str)
return 0;
}
-int inet_listen(const char *str, char *ostr, int olen,
+FdList* inet_listen(const char *str, char *ostr, int olen,
int socktype, int port_offset)
{
QemuOpts *opts;
char *optstr;
- int sock = -1;
+ FdList *socks = NULL;
opts = qemu_opts_create(&dummy_opts, NULL, 0);
if (inet_parse(opts, str) == 0) {
- sock = inet_listen_opts(opts, port_offset);
- if (sock != -1 && ostr) {
+ socks = inet_listen_opts(opts, port_offset);
+ if (socks != NULL && ostr) {
optstr = strchr(str, ',');
if (qemu_opt_get_bool(opts, "ipv6", 0)) {
snprintf(ostr, olen, "[%s]:%s%s",
@@ -482,7 +507,7 @@ int inet_listen(const char *str, char *ostr, int olen,
}
}
qemu_opts_del(opts);
- return sock;
+ return socks;
}
int inet_connect(const char *str, int socktype)
@@ -29,6 +29,13 @@ int inet_aton(const char *cp, struct in_addr *ia);
#endif /* !_WIN32 */
+struct FdList;
+typedef struct FdList {
+ int fd;
+ void *opaque;
+ struct FdList *next;
+} FdList;
+
#include "qemu-option.h"
/* misc helpers */
@@ -36,10 +43,12 @@ int qemu_socket(int domain, int type, int protocol);
int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
void socket_set_nonblock(int fd);
int send_all(int fd, const void *buf, int len1);
+FdList *fdlist_new(int fd);
+void fdlist_free(FdList *fds);
/* New, ipv6-ready socket helper functions, see qemu-sockets.c */
-int inet_listen_opts(QemuOpts *opts, int port_offset);
-int inet_listen(const char *str, char *ostr, int olen,
+FdList *inet_listen_opts(QemuOpts *opts, int port_offset);
+FdList *inet_listen(const char *str, char *ostr, int olen,
int socktype, int port_offset);
int inet_connect_opts(QemuOpts *opts);
int inet_connect(const char *str, int socktype);
@@ -26,7 +26,6 @@
#include "vnc.h"
#include "sysemu.h"
-#include "qemu_socket.h"
#include "qemu-timer.h"
#include "acl.h"
#include "qemu-objects.h"
@@ -202,7 +201,8 @@ static const char *vnc_auth_name(VncDisplay *vd) {
static int vnc_server_info_put(QDict *qdict)
{
- if (vnc_server_addr_put(qdict, vnc_display->lsock) < 0) {
+ /* FIXME: need to consider all sockets here, not just the first one */
+ if (vnc_server_addr_put(qdict, vnc_display->lsocks->fd) < 0) {
return -1;
}
@@ -2247,14 +2247,15 @@ static void vnc_connect(VncDisplay *vd, int csock)
static void vnc_listen_read(void *opaque)
{
- VncDisplay *vs = opaque;
+ FdList *sock = opaque;
+ VncDisplay *vs = sock->opaque;
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
/* Catch-up */
vga_hw_update();
- int csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
+ int csock = qemu_accept(sock->fd, (struct sockaddr *)&addr, &addrlen);
if (csock != -1) {
vnc_connect(vs, csock);
}
@@ -2270,7 +2271,7 @@ void vnc_display_init(DisplayState *ds)
dcl->idle = 1;
vnc_display = vs;
- vs->lsock = -1;
+ vs->lsocks = NULL;
vs->ds = ds;
QTAILQ_INIT(&vs->clients);
@@ -2294,6 +2295,7 @@ void vnc_display_init(DisplayState *ds)
void vnc_display_close(DisplayState *ds)
{
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+ FdList *fds, *fdtmp;
if (!vs)
return;
@@ -2301,11 +2303,13 @@ void vnc_display_close(DisplayState *ds)
qemu_free(vs->display);
vs->display = NULL;
}
- if (vs->lsock != -1) {
- qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
- close(vs->lsock);
- vs->lsock = -1;
+ for (fds = vs->lsocks; fds != NULL; fds = fdtmp) {
+ fdtmp = fds->next;
+ qemu_set_fd_handler2(fds->fd, NULL, NULL, NULL, NULL);
+ close(fds->fd);
+ free(fds);
}
+ vs->lsocks = NULL;
vs->auth = VNC_AUTH_INVALID;
#ifdef CONFIG_VNC_TLS
vs->subauth = VNC_AUTH_INVALID;
@@ -2342,7 +2346,8 @@ char *vnc_display_local_addr(DisplayState *ds)
{
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
- return vnc_socket_local_addr("%s:%s", vs->lsock);
+ /* FIXME: should return all addresses */
+ return vnc_socket_local_addr("%s:%s", vs->lsocks->fd);
}
int vnc_display_open(DisplayState *ds, const char *display)
@@ -2527,39 +2532,49 @@ int vnc_display_open(DisplayState *ds, const char *display)
vs->lock_key_sync = lock_key_sync;
if (reverse) {
+ int sock;
/* connect to viewer */
if (strncmp(display, "unix:", 5) == 0)
- vs->lsock = unix_connect(display+5);
+ sock = unix_connect(display+5);
else
- vs->lsock = inet_connect(display, SOCK_STREAM);
- if (-1 == vs->lsock) {
+ sock = inet_connect(display, SOCK_STREAM);
+ if (-1 == sock) {
free(vs->display);
vs->display = NULL;
return -1;
} else {
- int csock = vs->lsock;
- vs->lsock = -1;
- vnc_connect(vs, csock);
+ vnc_connect(vs, sock);
}
return 0;
} else {
/* listen for connects */
char *dpy;
+ int fd;
+ FdList *socks = NULL;
+
dpy = qemu_malloc(256);
if (strncmp(display, "unix:", 5) == 0) {
pstrcpy(dpy, 256, "unix:");
- vs->lsock = unix_listen(display+5, dpy+5, 256-5);
+ fd = unix_listen(display+5, dpy+5, 256-5);
+ if (fd >= 0)
+ socks = fdlist_new(fd);
} else {
- vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
+ socks = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
}
- if (-1 == vs->lsock) {
+
+ if (socks == NULL) {
free(dpy);
return -1;
} else {
+ vs->lsocks = socks;
free(vs->display);
vs->display = dpy;
}
+ for (; socks != NULL; socks = socks->next) {
+ socks->opaque = vs;
+ qemu_set_fd_handler2(socks->fd, NULL, vnc_listen_read, NULL, socks);
+ }
+ return 0;
}
- return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
}
@@ -28,6 +28,7 @@
#define __QEMU_VNC_H
#include "qemu-common.h"
+#include "qemu_socket.h"
#include "qemu-queue.h"
#include "console.h"
#include "monitor.h"
@@ -96,7 +97,7 @@ struct VncDisplay
QTAILQ_HEAD(, VncState) clients;
QEMUTimer *timer;
int timer_interval;
- int lsock;
+ FdList *lsocks;
DisplayState *ds;
kbd_layout_t *kbd_layout;
int lock_key_sync;