* [Qemu-devel] [PATCH v3 0/3] ipv6 and autoport patches. @ 2008-11-03 16:42 Gerd Hoffmann 2008-11-03 16:42 ` [Qemu-devel] [PATCH 1/3] sockets: helper functions for qemu Gerd Hoffmann ` (2 more replies) 0 siblings, 3 replies; 12+ messages in thread From: Gerd Hoffmann @ 2008-11-03 16:42 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann Hi, This patch series starts adding support for auto-allocating tcp ports and for ipv6 to qemu. It adds a new "info chardev" command (needed to query the auto-allocated ports), adds socket helper functiond with ipv6 support and finally switches chardevs and vnc over to the new socket helpers. Individual patches have more vebose descriptions. New in v3: * killed global -ipv[46] switches, made them per connection. * killed qemu-sockets.h, using existing qemu_socket.h instead. * fixup a few more things pointed out in review (if style, ...). * "info chardev" patch disappeared due to being merged. * rebased patches latest svn, fixup qemu-char.c creation fallout. New in v2: * address review comments from Daniel P. Berrange and Blue Swirl. * fixed windows build (mingw32 crosscompiler). * added -ipv4 and -ipv6 switches to the help text. cheers, Gerd ^ permalink raw reply [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH 1/3] sockets: helper functions for qemu. 2008-11-03 16:42 [Qemu-devel] [PATCH v3 0/3] ipv6 and autoport patches Gerd Hoffmann @ 2008-11-03 16:42 ` Gerd Hoffmann 2008-11-04 12:42 ` [Qemu-devel] " Gerd Hoffmann ` (2 more replies) 2008-11-03 16:42 ` [Qemu-devel] [PATCH 2/3] sockets: switch vnc to new code, support vnc port auto-allocation Gerd Hoffmann 2008-11-03 16:42 ` [Qemu-devel] [PATCH 3/3] sockets: switch over tcp/telnet/unix serial line to new helper functions Gerd Hoffmann 2 siblings, 3 replies; 12+ messages in thread From: Gerd Hoffmann @ 2008-11-03 16:42 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann This patch creates a new source file qemu-sockets.c with a bunch of helper functions to create listening and connected sockets. New features of this code are (a) support for searching for a free port in a given range and (b) support for IPv6. The following patches put that code into use. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- Makefile.target | 2 +- qemu-common.h | 1 + qemu-sockets.c | 400 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu_socket.h | 16 ++- 4 files changed, 415 insertions(+), 4 deletions(-) create mode 100644 qemu-sockets.c diff --git a/Makefile.target b/Makefile.target index 3bad292..06ea1da 100644 --- a/Makefile.target +++ b/Makefile.target @@ -580,7 +580,7 @@ ifndef CONFIG_USER_ONLY OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o net-checksum.o OBJS+=fw_cfg.o aio.o buffered_file.o migration.o migration-tcp.o qemu-char.o -OBJS+=net.o +OBJS+=net.o qemu-sockets.o ifdef CONFIG_WIN32 OBJS+=block-raw-win32.o else diff --git a/qemu-common.h b/qemu-common.h index f23d7b4..142182b 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -29,6 +29,7 @@ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN +#define WINVER 0x0501 /* needed for ipv6 bits */ #include <windows.h> #define fsync _commit #define lseek _lseeki64 diff --git a/qemu-sockets.c b/qemu-sockets.c new file mode 100644 index 0000000..a5499a6 --- /dev/null +++ b/qemu-sockets.c @@ -0,0 +1,400 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <unistd.h> + +#include "qemu_socket.h" + +#ifndef AI_ADDRCONFIG +# define AI_ADDRCONFIG 0 +#endif + +static int sockets_debug = 0; +static const int on=1, off=0; + +static int inet_getport(struct addrinfo *e) +{ + struct sockaddr_in *i4; + struct sockaddr_in6 *i6; + + switch (e->ai_family) { + case PF_INET6: + i6 = (void*)e->ai_addr; + return ntohs(i6->sin6_port); + case PF_INET: + i4 = (void*)e->ai_addr; + return ntohs(i4->sin_port); + default: + return 0; + } +} + +static void inet_setport(struct addrinfo *e, int port) +{ + struct sockaddr_in *i4; + struct sockaddr_in6 *i6; + + switch (e->ai_family) { + case PF_INET6: + i6 = (void*)e->ai_addr; + i6->sin6_port = htons(port); + break; + case PF_INET: + i4 = (void*)e->ai_addr; + i4->sin_port = htons(port); + break; + } +} + +static const char *inet_strfamily(int family) +{ + switch (family) { + case PF_INET6: return "ipv6"; + case PF_INET: return "ipv4"; + case PF_UNIX: return "unix"; + } + return "????"; +} + +static void inet_print_addrinfo(const char *tag, struct addrinfo *res) +{ + struct addrinfo *e; + char uaddr[INET6_ADDRSTRLEN+1]; + char uport[33]; + + for (e = res; e != NULL; e = e->ai_next) { + getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, + uaddr,INET6_ADDRSTRLEN,uport,32, + NI_NUMERICHOST | NI_NUMERICSERV); + fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n", + tag, inet_strfamily(e->ai_family), uaddr, uport); + } +} + +int inet_listen(const char *str, char *ostr, int olen, + int socktype, int port_offset) +{ + struct addrinfo ai,*res,*e; + char addr[64]; + char port[33]; + char uaddr[INET6_ADDRSTRLEN+1]; + char uport[33]; + const char *opts, *h; + int slisten,rc,pos,to,try_next; + + memset(&ai,0, sizeof(ai)); + ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + ai.ai_family = PF_UNSPEC; + ai.ai_socktype = socktype; + + /* parse address */ + if (str[0] == ':') { + /* no host given */ + strcpy(addr,""); + if (1 != sscanf(str,":%32[^,]%n",port,&pos)) { + fprintf(stderr, "%s: portonly parse error (%s)\n", + __FUNCTION__, str); + return -1; + } + } else if (str[0] == '[') { + /* IPv6 addr */ + if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) { + fprintf(stderr, "%s: ipv6 parse error (%s)\n", + __FUNCTION__, str); + return -1; + } + ai.ai_family = PF_INET6; + } else if (isdigit(str[0])) { + /* IPv4 addr */ + if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { + fprintf(stderr, "%s: ipv4 parse error (%s)\n", + __FUNCTION__, str); + return -1; + } + ai.ai_family = PF_INET; + } else { + /* hostname */ + if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { + fprintf(stderr, "%s: hostname parse error (%s)\n", + __FUNCTION__, str); + return -1; + } + } + + /* parse options */ + opts = str + pos; + h = strstr(opts, ",to="); + to = h ? atoi(h+4) : 0; + if (strstr(opts, ",ipv4")) + ai.ai_family = PF_INET; + if (strstr(opts, ",ipv6")) + ai.ai_family = PF_INET6; + + /* lookup */ + if (port_offset) + snprintf(port, sizeof(port), "%d", atoi(port) + port_offset); + rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); + if (rc != 0) { + fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__, + addr, port, gai_strerror(rc)); + return -1; + } + if (sockets_debug) + inet_print_addrinfo(__FUNCTION__, res); + + /* create socket + bind */ + for (e = res; e != NULL; e = e->ai_next) { + getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, + uaddr,INET6_ADDRSTRLEN,uport,32, + NI_NUMERICHOST | NI_NUMERICSERV); + slisten = socket(e->ai_family, e->ai_socktype, e->ai_protocol); + if (slisten < 0) { + fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, + inet_strfamily(e->ai_family), strerror(errno)); + continue; + } + + 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)); + } +#endif + + for (;;) { + if (bind(slisten, e->ai_addr, e->ai_addrlen) != 0) { + if (sockets_debug) + fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, + inet_strfamily(e->ai_family), uaddr, inet_getport(e)); + goto listen; + } + try_next = to && (inet_getport(e) <= to + port_offset); + if (!try_next || sockets_debug) + fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__, + inet_strfamily(e->ai_family), uaddr, inet_getport(e), + strerror(errno)); + if (try_next) { + inet_setport(e, inet_getport(e) + 1); + continue; + } + break; + } + closesocket(slisten); + } + fprintf(stderr, "%s: FAILED\n", __FUNCTION__); + freeaddrinfo(res); + return -1; + +listen: + if (listen(slisten,1) != 0) { + perror("listen"); + closesocket(slisten); + return -1; + } + if (ostr) { + if (e->ai_family == PF_INET6) { + snprintf(ostr, olen, "[%s]:%d%s", uaddr, + inet_getport(e) - port_offset, opts); + } else { + snprintf(ostr, olen, "%s:%d%s", uaddr, + inet_getport(e) - port_offset, opts); + } + } + freeaddrinfo(res); + return slisten; +} + +int inet_connect(const char *str, int socktype) +{ + struct addrinfo ai,*res,*e; + char addr[64]; + char port[33]; + char uaddr[INET6_ADDRSTRLEN+1]; + char uport[33]; + int sock,rc; + + memset(&ai,0, sizeof(ai)); + ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; + ai.ai_family = PF_UNSPEC; + ai.ai_socktype = socktype; + + /* parse address */ + if (str[0] == '[') { + /* IPv6 addr */ + if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) { + fprintf(stderr, "%s: ipv6 parse error (%s)\n", + __FUNCTION__, str); + return -1; + } + ai.ai_family = PF_INET6; + } else if (isdigit(str[0])) { + /* IPv4 addr */ + if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) { + fprintf(stderr, "%s: ipv4 parse error (%s)\n", + __FUNCTION__, str); + return -1; + } + ai.ai_family = PF_INET; + } else { + /* hostname */ + if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) { + fprintf(stderr, "%s: hostname parse error (%s)\n", + __FUNCTION__, str); + return -1; + } + } + + /* parse options */ + if (strstr(str, ",ipv4")) + ai.ai_family = PF_INET; + if (strstr(str, ",ipv6")) + ai.ai_family = PF_INET6; + + /* lookup */ + if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) { + fprintf(stderr,"getaddrinfo(%s,%s): %s\n", gai_strerror(rc), + addr, port); + return -1; + } + if (sockets_debug) + inet_print_addrinfo(__FUNCTION__, res); + + for (e = res; e != NULL; e = e->ai_next) { + if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, + uaddr,INET6_ADDRSTRLEN,uport,32, + NI_NUMERICHOST | NI_NUMERICSERV) != 0) { + fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); + continue; + } + sock = socket(e->ai_family, e->ai_socktype, e->ai_protocol); + if (sock < 0) { + fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, + inet_strfamily(e->ai_family), strerror(errno)); + continue; + } + setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); + + /* connect to peer */ + if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) { + if (sockets_debug || NULL == e->ai_next) + fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, + inet_strfamily(e->ai_family), + e->ai_canonname, uaddr, uport, strerror(errno)); + closesocket(sock); + continue; + } + if (sockets_debug) + fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__, + inet_strfamily(e->ai_family), + e->ai_canonname, uaddr, uport); + freeaddrinfo(res); + return sock; + } + freeaddrinfo(res); + return -1; +} + +#ifndef _WIN32 + +int unix_listen(const char *str, char *ostr, int olen) +{ + struct sockaddr_un un; + char *path, *opts; + int sock, fd, len; + + sock = socket(PF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + perror("socket(unix)"); + return -1; + } + + opts = strchr(str, ','); + if (opts) { + len = opts - str; + path = malloc(len+1); + snprintf(path, len+1, "%.*s", len, str); + } else + path = strdup(str); + + memset(&un, 0, sizeof(un)); + un.sun_family = AF_UNIX; + if (path && strlen(path)) { + snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); + } else { + char *tmpdir = getenv("TMPDIR"); + snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX", + tmpdir ? tmpdir : "/tmp"); + /* + * This dummy fd usage silences the mktemp() unsecure warning. + * Using mkstemp() doesn't make things more secure here + * though. bind() complains about existing files, so we have + * to unlink first and thus re-open the race window. The + * worst case possible is bind() failing, i.e. a DoS attack. + */ + fd = mkstemp(un.sun_path); close(fd); + } + snprintf(ostr, olen, "%s%s", un.sun_path, opts ? opts : ""); + + unlink(un.sun_path); + if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { + fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno)); + goto err; + } + if (listen(sock, 1) < 0) { + fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno)); + goto err; + } + + if (sockets_debug) + fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path); + free(path); + return sock; + +err: + free(path); + closesocket(sock); + return -1; +} + +int unix_connect(const char *path) +{ + struct sockaddr_un un; + int sock; + + sock = socket(PF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + perror("socket(unix)"); + return -1; + } + + memset(&un, 0, sizeof(un)); + un.sun_family = AF_UNIX; + snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); + if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { + fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno)); + return -1; + } + + if (sockets_debug) + fprintf(stderr, "connect(unix:%s): OK\n", path); + return sock; +} + +#else + +int unix_listen(const char *path, char *ostr, int olen) +{ + fprintf(stderr, "unix sockets are not available on windows\n"); + return -1; +} + +int unix_connect(const char *path) +{ + fprintf(stderr, "unix sockets are not available on windows\n"); + return -1; +} + +#endif diff --git a/qemu_socket.h b/qemu_socket.h index 18488dd..43a27b0 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -4,6 +4,7 @@ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN +#define WINVER 0x0501 /* needed for ipv6 bits */ #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> @@ -28,15 +29,24 @@ int inet_aton(const char *cp, struct in_addr *ia); #define socket_error() errno #define closesocket(s) close(s) -int parse_unix_path(struct sockaddr_un *uaddr, const char *str); - #endif /* !_WIN32 */ +/* misc helpers */ void socket_set_nonblock(int fd); +int send_all(int fd, const uint8_t *buf, int len1); + +/* New, ipv6-ready socket helper functions, see qemu-sockets.c */ +int inet_listen(const char *str, char *ostr, int olen, + int socktype, int port_offset); +int inet_connect(const char *str, int socktype); + +int unix_listen(const char *path, char *ostr, int olen); +int unix_connect(const char *path); + +/* Old, ipv4 only bits. Don't use for new code. */ int parse_host_port(struct sockaddr_in *saddr, const char *str); int parse_host_src_port(struct sockaddr_in *haddr, struct sockaddr_in *saddr, const char *str); -int send_all(int fd, const uint8_t *buf, int len1); #endif /* QEMU_SOCKET_H */ -- 1.5.6.5 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] Re: [PATCH 1/3] sockets: helper functions for qemu. 2008-11-03 16:42 ` [Qemu-devel] [PATCH 1/3] sockets: helper functions for qemu Gerd Hoffmann @ 2008-11-04 12:42 ` Gerd Hoffmann 2008-11-11 20:41 ` [Qemu-devel] " Anthony Liguori 2008-11-11 20:47 ` Anthony Liguori 2 siblings, 0 replies; 12+ messages in thread From: Gerd Hoffmann @ 2008-11-04 12:42 UTC (permalink / raw) To: qemu-devel [-- Attachment #1: Type: text/plain, Size: 618 bytes --] Hi, > + > + for (;;) { > + if (bind(slisten, e->ai_addr, e->ai_addrlen) != 0) { > + if (sockets_debug) > + fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, > + inet_strfamily(e->ai_family), uaddr, inet_getport(e)); > + goto listen; > + } Oops. Fixing up if() coding style with not enough care added a bug here. Unlike in most other cases where we catch errors this way this if() actually tests for bind() *success* to hop out of the "find free port" loop. Incremental fix attached. cheers, Gerd [-- Attachment #2: 0042-sockets-fix-bind-return-value-check.patch --] [-- Type: text/plain, Size: 901 bytes --] >From 63d0d91d213ae3c84f1d3f82dd6879b43ec35bbc Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann <kraxel@redhat.com> Date: Tue, 4 Nov 2008 13:35:07 +0100 Subject: [PATCH] sockets: fix bind return value check. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- qemu-sockets.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/qemu-sockets.c b/qemu-sockets.c index a5499a6..77d9921 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -165,7 +165,7 @@ int inet_listen(const char *str, char *ostr, int olen, #endif for (;;) { - if (bind(slisten, e->ai_addr, e->ai_addrlen) != 0) { + if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { if (sockets_debug) fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, inet_strfamily(e->ai_family), uaddr, inet_getport(e)); -- 1.5.6.5 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH 1/3] sockets: helper functions for qemu. 2008-11-03 16:42 ` [Qemu-devel] [PATCH 1/3] sockets: helper functions for qemu Gerd Hoffmann 2008-11-04 12:42 ` [Qemu-devel] " Gerd Hoffmann @ 2008-11-11 20:41 ` Anthony Liguori 2008-11-11 21:14 ` Gerd Hoffmann 2008-11-11 20:47 ` Anthony Liguori 2 siblings, 1 reply; 12+ messages in thread From: Anthony Liguori @ 2008-11-11 20:41 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann Gerd Hoffmann wrote: > This patch creates a new source file qemu-sockets.c with a bunch of > helper functions to create listening and connected sockets. > > New features of this code are (a) support for searching for a free > port in a given range and (b) support for IPv6. > > The following patches put that code into use. > I'm going to apply this series but can you follow up with copyright/licenses for each of the files you add? Regards, Anthony Liguori > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> > --- > Makefile.target | 2 +- > qemu-common.h | 1 + > qemu-sockets.c | 400 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > qemu_socket.h | 16 ++- > 4 files changed, 415 insertions(+), 4 deletions(-) > create mode 100644 qemu-sockets.c > > diff --git a/Makefile.target b/Makefile.target > index 3bad292..06ea1da 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -580,7 +580,7 @@ ifndef CONFIG_USER_ONLY > > OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o net-checksum.o > OBJS+=fw_cfg.o aio.o buffered_file.o migration.o migration-tcp.o qemu-char.o > -OBJS+=net.o > +OBJS+=net.o qemu-sockets.o > ifdef CONFIG_WIN32 > OBJS+=block-raw-win32.o > else > diff --git a/qemu-common.h b/qemu-common.h > index f23d7b4..142182b 100644 > --- a/qemu-common.h > +++ b/qemu-common.h > @@ -29,6 +29,7 @@ > > #ifdef _WIN32 > #define WIN32_LEAN_AND_MEAN > +#define WINVER 0x0501 /* needed for ipv6 bits */ > #include <windows.h> > #define fsync _commit > #define lseek _lseeki64 > diff --git a/qemu-sockets.c b/qemu-sockets.c > new file mode 100644 > index 0000000..a5499a6 > --- /dev/null > +++ b/qemu-sockets.c > @@ -0,0 +1,400 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <ctype.h> > +#include <errno.h> > +#include <unistd.h> > + > +#include "qemu_socket.h" > + > +#ifndef AI_ADDRCONFIG > +# define AI_ADDRCONFIG 0 > +#endif > + > +static int sockets_debug = 0; > +static const int on=1, off=0; > + > +static int inet_getport(struct addrinfo *e) > +{ > + struct sockaddr_in *i4; > + struct sockaddr_in6 *i6; > + > + switch (e->ai_family) { > + case PF_INET6: > + i6 = (void*)e->ai_addr; > + return ntohs(i6->sin6_port); > + case PF_INET: > + i4 = (void*)e->ai_addr; > + return ntohs(i4->sin_port); > + default: > + return 0; > + } > +} > + > +static void inet_setport(struct addrinfo *e, int port) > +{ > + struct sockaddr_in *i4; > + struct sockaddr_in6 *i6; > + > + switch (e->ai_family) { > + case PF_INET6: > + i6 = (void*)e->ai_addr; > + i6->sin6_port = htons(port); > + break; > + case PF_INET: > + i4 = (void*)e->ai_addr; > + i4->sin_port = htons(port); > + break; > + } > +} > + > +static const char *inet_strfamily(int family) > +{ > + switch (family) { > + case PF_INET6: return "ipv6"; > + case PF_INET: return "ipv4"; > + case PF_UNIX: return "unix"; > + } > + return "????"; > +} > + > +static void inet_print_addrinfo(const char *tag, struct addrinfo *res) > +{ > + struct addrinfo *e; > + char uaddr[INET6_ADDRSTRLEN+1]; > + char uport[33]; > + > + for (e = res; e != NULL; e = e->ai_next) { > + getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, > + uaddr,INET6_ADDRSTRLEN,uport,32, > + NI_NUMERICHOST | NI_NUMERICSERV); > + fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n", > + tag, inet_strfamily(e->ai_family), uaddr, uport); > + } > +} > + > +int inet_listen(const char *str, char *ostr, int olen, > + int socktype, int port_offset) > +{ > + struct addrinfo ai,*res,*e; > + char addr[64]; > + char port[33]; > + char uaddr[INET6_ADDRSTRLEN+1]; > + char uport[33]; > + const char *opts, *h; > + int slisten,rc,pos,to,try_next; > + > + memset(&ai,0, sizeof(ai)); > + ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; > + ai.ai_family = PF_UNSPEC; > + ai.ai_socktype = socktype; > + > + /* parse address */ > + if (str[0] == ':') { > + /* no host given */ > + strcpy(addr,""); > + if (1 != sscanf(str,":%32[^,]%n",port,&pos)) { > + fprintf(stderr, "%s: portonly parse error (%s)\n", > + __FUNCTION__, str); > + return -1; > + } > + } else if (str[0] == '[') { > + /* IPv6 addr */ > + if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) { > + fprintf(stderr, "%s: ipv6 parse error (%s)\n", > + __FUNCTION__, str); > + return -1; > + } > + ai.ai_family = PF_INET6; > + } else if (isdigit(str[0])) { > + /* IPv4 addr */ > + if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { > + fprintf(stderr, "%s: ipv4 parse error (%s)\n", > + __FUNCTION__, str); > + return -1; > + } > + ai.ai_family = PF_INET; > + } else { > + /* hostname */ > + if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { > + fprintf(stderr, "%s: hostname parse error (%s)\n", > + __FUNCTION__, str); > + return -1; > + } > + } > + > + /* parse options */ > + opts = str + pos; > + h = strstr(opts, ",to="); > + to = h ? atoi(h+4) : 0; > + if (strstr(opts, ",ipv4")) > + ai.ai_family = PF_INET; > + if (strstr(opts, ",ipv6")) > + ai.ai_family = PF_INET6; > + > + /* lookup */ > + if (port_offset) > + snprintf(port, sizeof(port), "%d", atoi(port) + port_offset); > + rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); > + if (rc != 0) { > + fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__, > + addr, port, gai_strerror(rc)); > + return -1; > + } > + if (sockets_debug) > + inet_print_addrinfo(__FUNCTION__, res); > + > + /* create socket + bind */ > + for (e = res; e != NULL; e = e->ai_next) { > + getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, > + uaddr,INET6_ADDRSTRLEN,uport,32, > + NI_NUMERICHOST | NI_NUMERICSERV); > + slisten = socket(e->ai_family, e->ai_socktype, e->ai_protocol); > + if (slisten < 0) { > + fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, > + inet_strfamily(e->ai_family), strerror(errno)); > + continue; > + } > + > + 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)); > + } > +#endif > + > + for (;;) { > + if (bind(slisten, e->ai_addr, e->ai_addrlen) != 0) { > + if (sockets_debug) > + fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, > + inet_strfamily(e->ai_family), uaddr, inet_getport(e)); > + goto listen; > + } > + try_next = to && (inet_getport(e) <= to + port_offset); > + if (!try_next || sockets_debug) > + fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__, > + inet_strfamily(e->ai_family), uaddr, inet_getport(e), > + strerror(errno)); > + if (try_next) { > + inet_setport(e, inet_getport(e) + 1); > + continue; > + } > + break; > + } > + closesocket(slisten); > + } > + fprintf(stderr, "%s: FAILED\n", __FUNCTION__); > + freeaddrinfo(res); > + return -1; > + > +listen: > + if (listen(slisten,1) != 0) { > + perror("listen"); > + closesocket(slisten); > + return -1; > + } > + if (ostr) { > + if (e->ai_family == PF_INET6) { > + snprintf(ostr, olen, "[%s]:%d%s", uaddr, > + inet_getport(e) - port_offset, opts); > + } else { > + snprintf(ostr, olen, "%s:%d%s", uaddr, > + inet_getport(e) - port_offset, opts); > + } > + } > + freeaddrinfo(res); > + return slisten; > +} > + > +int inet_connect(const char *str, int socktype) > +{ > + struct addrinfo ai,*res,*e; > + char addr[64]; > + char port[33]; > + char uaddr[INET6_ADDRSTRLEN+1]; > + char uport[33]; > + int sock,rc; > + > + memset(&ai,0, sizeof(ai)); > + ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; > + ai.ai_family = PF_UNSPEC; > + ai.ai_socktype = socktype; > + > + /* parse address */ > + if (str[0] == '[') { > + /* IPv6 addr */ > + if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) { > + fprintf(stderr, "%s: ipv6 parse error (%s)\n", > + __FUNCTION__, str); > + return -1; > + } > + ai.ai_family = PF_INET6; > + } else if (isdigit(str[0])) { > + /* IPv4 addr */ > + if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) { > + fprintf(stderr, "%s: ipv4 parse error (%s)\n", > + __FUNCTION__, str); > + return -1; > + } > + ai.ai_family = PF_INET; > + } else { > + /* hostname */ > + if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) { > + fprintf(stderr, "%s: hostname parse error (%s)\n", > + __FUNCTION__, str); > + return -1; > + } > + } > + > + /* parse options */ > + if (strstr(str, ",ipv4")) > + ai.ai_family = PF_INET; > + if (strstr(str, ",ipv6")) > + ai.ai_family = PF_INET6; > + > + /* lookup */ > + if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) { > + fprintf(stderr,"getaddrinfo(%s,%s): %s\n", gai_strerror(rc), > + addr, port); > + return -1; > + } > + if (sockets_debug) > + inet_print_addrinfo(__FUNCTION__, res); > + > + for (e = res; e != NULL; e = e->ai_next) { > + if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, > + uaddr,INET6_ADDRSTRLEN,uport,32, > + NI_NUMERICHOST | NI_NUMERICSERV) != 0) { > + fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); > + continue; > + } > + sock = socket(e->ai_family, e->ai_socktype, e->ai_protocol); > + if (sock < 0) { > + fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, > + inet_strfamily(e->ai_family), strerror(errno)); > + continue; > + } > + setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); > + > + /* connect to peer */ > + if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) { > + if (sockets_debug || NULL == e->ai_next) > + fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, > + inet_strfamily(e->ai_family), > + e->ai_canonname, uaddr, uport, strerror(errno)); > + closesocket(sock); > + continue; > + } > + if (sockets_debug) > + fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__, > + inet_strfamily(e->ai_family), > + e->ai_canonname, uaddr, uport); > + freeaddrinfo(res); > + return sock; > + } > + freeaddrinfo(res); > + return -1; > +} > + > +#ifndef _WIN32 > + > +int unix_listen(const char *str, char *ostr, int olen) > +{ > + struct sockaddr_un un; > + char *path, *opts; > + int sock, fd, len; > + > + sock = socket(PF_UNIX, SOCK_STREAM, 0); > + if (sock < 0) { > + perror("socket(unix)"); > + return -1; > + } > + > + opts = strchr(str, ','); > + if (opts) { > + len = opts - str; > + path = malloc(len+1); > + snprintf(path, len+1, "%.*s", len, str); > + } else > + path = strdup(str); > + > + memset(&un, 0, sizeof(un)); > + un.sun_family = AF_UNIX; > + if (path && strlen(path)) { > + snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); > + } else { > + char *tmpdir = getenv("TMPDIR"); > + snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX", > + tmpdir ? tmpdir : "/tmp"); > + /* > + * This dummy fd usage silences the mktemp() unsecure warning. > + * Using mkstemp() doesn't make things more secure here > + * though. bind() complains about existing files, so we have > + * to unlink first and thus re-open the race window. The > + * worst case possible is bind() failing, i.e. a DoS attack. > + */ > + fd = mkstemp(un.sun_path); close(fd); > + } > + snprintf(ostr, olen, "%s%s", un.sun_path, opts ? opts : ""); > + > + unlink(un.sun_path); > + if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { > + fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno)); > + goto err; > + } > + if (listen(sock, 1) < 0) { > + fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno)); > + goto err; > + } > + > + if (sockets_debug) > + fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path); > + free(path); > + return sock; > + > +err: > + free(path); > + closesocket(sock); > + return -1; > +} > + > +int unix_connect(const char *path) > +{ > + struct sockaddr_un un; > + int sock; > + > + sock = socket(PF_UNIX, SOCK_STREAM, 0); > + if (sock < 0) { > + perror("socket(unix)"); > + return -1; > + } > + > + memset(&un, 0, sizeof(un)); > + un.sun_family = AF_UNIX; > + snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); > + if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { > + fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno)); > + return -1; > + } > + > + if (sockets_debug) > + fprintf(stderr, "connect(unix:%s): OK\n", path); > + return sock; > +} > + > +#else > + > +int unix_listen(const char *path, char *ostr, int olen) > +{ > + fprintf(stderr, "unix sockets are not available on windows\n"); > + return -1; > +} > + > +int unix_connect(const char *path) > +{ > + fprintf(stderr, "unix sockets are not available on windows\n"); > + return -1; > +} > + > +#endif > diff --git a/qemu_socket.h b/qemu_socket.h > index 18488dd..43a27b0 100644 > --- a/qemu_socket.h > +++ b/qemu_socket.h > @@ -4,6 +4,7 @@ > > #ifdef _WIN32 > #define WIN32_LEAN_AND_MEAN > +#define WINVER 0x0501 /* needed for ipv6 bits */ > #include <windows.h> > #include <winsock2.h> > #include <ws2tcpip.h> > @@ -28,15 +29,24 @@ int inet_aton(const char *cp, struct in_addr *ia); > #define socket_error() errno > #define closesocket(s) close(s) > > -int parse_unix_path(struct sockaddr_un *uaddr, const char *str); > - > #endif /* !_WIN32 */ > > +/* misc helpers */ > void socket_set_nonblock(int fd); > +int send_all(int fd, const uint8_t *buf, int len1); > + > +/* New, ipv6-ready socket helper functions, see qemu-sockets.c */ > +int inet_listen(const char *str, char *ostr, int olen, > + int socktype, int port_offset); > +int inet_connect(const char *str, int socktype); > + > +int unix_listen(const char *path, char *ostr, int olen); > +int unix_connect(const char *path); > + > +/* Old, ipv4 only bits. Don't use for new code. */ > int parse_host_port(struct sockaddr_in *saddr, const char *str); > int parse_host_src_port(struct sockaddr_in *haddr, > struct sockaddr_in *saddr, > const char *str); > -int send_all(int fd, const uint8_t *buf, int len1); > > #endif /* QEMU_SOCKET_H */ > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH 1/3] sockets: helper functions for qemu. 2008-11-11 20:41 ` [Qemu-devel] " Anthony Liguori @ 2008-11-11 21:14 ` Gerd Hoffmann 0 siblings, 0 replies; 12+ messages in thread From: Gerd Hoffmann @ 2008-11-11 21:14 UTC (permalink / raw) To: Anthony Liguori; +Cc: qemu-devel [-- Attachment #1: Type: text/plain, Size: 531 bytes --] Anthony Liguori wrote: > Gerd Hoffmann wrote: >> This patch creates a new source file qemu-sockets.c with a bunch of >> helper functions to create listening and connected sockets. >> >> New features of this code are (a) support for searching for a free >> port in a given range and (b) support for IPv6. >> >> The following patches put that code into use. >> > > I'm going to apply this series but can you follow up with > copyright/licenses for each of the files you add? It is just one new file, here we go. thanks, Gerd [-- Attachment #2: 0052-sockets-add-copyright-and-license.patch --] [-- Type: text/plain, Size: 1140 bytes --] >From 43d430ad432bc05c8a3e1b63d1d4822b8e781e6a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann <kraxel@redhat.com> Date: Tue, 11 Nov 2008 21:58:41 +0100 Subject: [PATCH] sockets: add copyright and license. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- qemu-sockets.c | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) diff --git a/qemu-sockets.c b/qemu-sockets.c index 77d9921..509d2a5 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -1,3 +1,17 @@ +/* + * inet and unix socket functions for qemu + * + * (c) 2008 Gerd Hoffmann <kraxel@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ #include <stdio.h> #include <stdlib.h> #include <string.h> -- 1.5.6.5 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH 1/3] sockets: helper functions for qemu. 2008-11-03 16:42 ` [Qemu-devel] [PATCH 1/3] sockets: helper functions for qemu Gerd Hoffmann 2008-11-04 12:42 ` [Qemu-devel] " Gerd Hoffmann 2008-11-11 20:41 ` [Qemu-devel] " Anthony Liguori @ 2008-11-11 20:47 ` Anthony Liguori 2 siblings, 0 replies; 12+ messages in thread From: Anthony Liguori @ 2008-11-11 20:47 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann Gerd Hoffmann wrote: > This patch creates a new source file qemu-sockets.c with a bunch of > helper functions to create listening and connected sockets. > > New features of this code are (a) support for searching for a free > port in a given range and (b) support for IPv6. > > The following patches put that code into use. > > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com > Applied. Thanks. With a small fixup so that it would build on Windows. net.h does not include stdint so moving send_all() to it failed with Windows. I changed send_all() to take a void *, which makes more sense anyway. Regards, Anthony Liguori ^ permalink raw reply [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH 2/3] sockets: switch vnc to new code, support vnc port auto-allocation. 2008-11-03 16:42 [Qemu-devel] [PATCH v3 0/3] ipv6 and autoport patches Gerd Hoffmann 2008-11-03 16:42 ` [Qemu-devel] [PATCH 1/3] sockets: helper functions for qemu Gerd Hoffmann @ 2008-11-03 16:42 ` Gerd Hoffmann 2008-11-11 20:52 ` Anthony Liguori 2008-11-26 23:25 ` Ryan Harper 2008-11-03 16:42 ` [Qemu-devel] [PATCH 3/3] sockets: switch over tcp/telnet/unix serial line to new helper functions Gerd Hoffmann 2 siblings, 2 replies; 12+ messages in thread From: Gerd Hoffmann @ 2008-11-03 16:42 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann 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> --- vnc.c | 113 +++++++++++++++-------------------------------------------------- 1 files changed, 26 insertions(+), 87 deletions(-) diff --git a/vnc.c b/vnc.c index 9df4dbe..f0ebebd 100644 --- a/vnc.c +++ b/vnc.c @@ -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) { VncState *vs; @@ -2291,18 +2289,11 @@ int vnc_display_password(DisplayState *ds, const char *password) 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; const char *options; int password = 0; int reverse = 0; + int to_port = 0; #ifdef CONFIG_VNC_TLS int tls = 0, x509 = 0; #endif @@ -2321,6 +2312,8 @@ int vnc_display_open(DisplayState *ds, const char *display) password = 1; /* Require password auth */ } else if (strncmp(options, "reverse", 7) == 0) { reverse = 1; + } else if (strncmp(options, "to=", 3) == 0) { + to_port = atoi(options+3) + 5900; #ifdef CONFIG_VNC_TLS } else if (strncmp(options, "tls", 3) == 0) { tls = 1; /* Require TLS */ @@ -2398,67 +2391,14 @@ int vnc_display_open(DisplayState *ds, const char *display) } #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 (connect(vs->lsock, addr, addrlen) == -1) { - fprintf(stderr, "Connection to VNC client failed\n"); - close(vs->lsock); - vs->lsock = -1; + /* connect to viewer */ + if (strncmp(display, "unix:", 5) == 0) + vs->lsock = unix_connect(display+5); + else + vs->lsock = inet_connect(display, SOCK_STREAM); + if (-1 == vs->lsock) { free(vs->display); vs->display = NULL; return -1; @@ -2466,26 +2406,25 @@ int vnc_display_open(DisplayState *ds, const char *display) 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); - vs->lsock = -1; - free(vs->display); - vs->display = NULL; - return -1; - } + return 0; - if (listen(vs->lsock, 1) == -1) { - fprintf(stderr, "listen() failed\n"); - close(vs->lsock); - vs->lsock = -1; - free(vs->display); - vs->display = NULL; - return -1; + } else { + /* listen for connects */ + char *dpy; + dpy = qemu_malloc(256); + if (strncmp(display, "unix:", 5) == 0) { + strcpy(dpy, "unix:"); + vs->lsock = unix_listen(display, dpy+5, 256-5); + } else { + vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900); + } + if (-1 == vs->lsock) { + free(dpy); + } else { + free(vs->display); + vs->display = dpy; + } } return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs); -- 1.5.6.5 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH 2/3] sockets: switch vnc to new code, support vnc port auto-allocation. 2008-11-03 16:42 ` [Qemu-devel] [PATCH 2/3] sockets: switch vnc to new code, support vnc port auto-allocation Gerd Hoffmann @ 2008-11-11 20:52 ` Anthony Liguori 2008-11-26 23:25 ` Ryan Harper 1 sibling, 0 replies; 12+ messages in thread From: Anthony Liguori @ 2008-11-11 20:52 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann Gerd Hoffmann wrote: > 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> Applied. Thanks. Regards, Anthony Liguori ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH 2/3] sockets: switch vnc to new code, support vnc port auto-allocation. 2008-11-03 16:42 ` [Qemu-devel] [PATCH 2/3] sockets: switch vnc to new code, support vnc port auto-allocation Gerd Hoffmann 2008-11-11 20:52 ` Anthony Liguori @ 2008-11-26 23:25 ` Ryan Harper 2008-11-27 9:11 ` Gerd Hoffmann 1 sibling, 1 reply; 12+ messages in thread From: Ryan Harper @ 2008-11-26 23:25 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann * Gerd Hoffmann <kraxel@redhat.com> [2008-11-03 10:57]: > 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. When using an existing unix file like: -vnc unix:/tmp/file1Y2nY2 qemu fails to bind a unix socket because the vnc call to unix_listen includes the unix: prefix, and stores that in the unix.sun_path. Like the qemu-char handler, don't pass in unix: for the filename. This fixes -vnc unix:<file> for me. Haven't tested all cases of -vnc, so, double check that this is the right fix. -- Ryan Harper Software Engineer; Linux Technology Center IBM Corp., Austin, Tx ryanh@us.ibm.com diffstat output: vnc.c | 2 +- 1 files changed, 1 insertion(+), 1 deletion(-) Signed-off-by: Ryan Harper <ryanh@us.ibm.com> --- diff --git a/vnc.c b/vnc.c index f663b38..c0e591c 100644 --- a/vnc.c +++ b/vnc.c @@ -2413,7 +2413,7 @@ int vnc_display_open(DisplayState *ds, const char *display) dpy = qemu_malloc(256); if (strncmp(display, "unix:", 5) == 0) { strcpy(dpy, "unix:"); - vs->lsock = unix_listen(display, dpy+5, 256-5); + vs->lsock = unix_listen(display+5, dpy+5, 256-5); } else { vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900); } ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH 2/3] sockets: switch vnc to new code, support vnc port auto-allocation. 2008-11-26 23:25 ` Ryan Harper @ 2008-11-27 9:11 ` Gerd Hoffmann 0 siblings, 0 replies; 12+ messages in thread From: Gerd Hoffmann @ 2008-11-27 9:11 UTC (permalink / raw) To: Ryan Harper; +Cc: qemu-devel Ryan Harper wrote: > * Gerd Hoffmann <kraxel@redhat.com> [2008-11-03 10:57]: > When using an existing unix file like: > > -vnc unix:/tmp/file1Y2nY2 > > qemu fails to bind a unix socket because the vnc call to unix_listen > includes the unix: prefix, and stores that in the unix.sun_path. Oops. > Haven't tested all cases of -vnc, so, double check that this is the > right fix. Yep, fix is fine. thanks, Gerd ^ permalink raw reply [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH 3/3] sockets: switch over tcp/telnet/unix serial line to new helper functions. 2008-11-03 16:42 [Qemu-devel] [PATCH v3 0/3] ipv6 and autoport patches Gerd Hoffmann 2008-11-03 16:42 ` [Qemu-devel] [PATCH 1/3] sockets: helper functions for qemu Gerd Hoffmann 2008-11-03 16:42 ` [Qemu-devel] [PATCH 2/3] sockets: switch vnc to new code, support vnc port auto-allocation Gerd Hoffmann @ 2008-11-03 16:42 ` Gerd Hoffmann 2008-11-11 20:54 ` Anthony Liguori 2 siblings, 1 reply; 12+ messages in thread From: Gerd Hoffmann @ 2008-11-03 16:42 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann This switches the tcp, telnet and unix socket support for character devices (serial/parallel, ...) to the new socket helpers. Thereby they gain IPv6 support and also get ability to search for a free tcp port. Syntax is the same as for vnc, using a to= option, like this: -serial tcp:localhost:5000,to=5099,server This will check the 5000 -> 5099 port range (inclusive) for a free tcp port. Likewise you can get auto-allocated unix sockets by specifying an empty path: -serial unix:,server qemu will create a randomly named socket in $TMPDIR then. tcp also got new "ipv4" and "ipv6" options to make qemu try only the specified internet protocol version. You can use the "info chardev" command added by the first patch in this series to figure the tcp port / unix socket actually allocated. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- qemu-char.c | 106 ++++++++++++++++++----------------------------------------- 1 files changed, 32 insertions(+), 74 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index ceffbed..906e817 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1951,32 +1951,11 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, { CharDriverState *chr = NULL; TCPCharDriver *s = NULL; - int fd = -1, ret, err, val; + int fd = -1, offset = 0; int is_listen = 0; int is_waitconnect = 1; int do_nodelay = 0; const char *ptr; - struct sockaddr_in saddr; -#ifndef _WIN32 - struct sockaddr_un uaddr; -#endif - struct sockaddr *addr; - socklen_t addrlen; - -#ifndef _WIN32 - if (is_unix) { - addr = (struct sockaddr *)&uaddr; - addrlen = sizeof(uaddr); - if (parse_unix_path(&uaddr, host_str) < 0) - goto fail; - } else -#endif - { - addr = (struct sockaddr *)&saddr; - addrlen = sizeof(saddr); - if (parse_host_port(&saddr, host_str) < 0) - goto fail; - } ptr = host_str; while((ptr = strchr(ptr,','))) { @@ -1987,6 +1966,8 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, is_waitconnect = 0; } else if (!strncmp(ptr,"nodelay",6)) { do_nodelay = 1; + } else if (!strncmp(ptr,"to=",3)) { + /* nothing, inet_listen() parses this one */; } else { printf("Unknown option: %s\n", ptr); goto fail; @@ -2002,13 +1983,31 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, if (!s) goto fail; -#ifndef _WIN32 - if (is_unix) - fd = socket(PF_UNIX, SOCK_STREAM, 0); - else -#endif - fd = socket(PF_INET, SOCK_STREAM, 0); - + if (is_listen) { + chr->filename = qemu_malloc(256); + if (is_unix) { + strcpy(chr->filename, "unix:"); + } else if (is_telnet) { + strcpy(chr->filename, "telnet:"); + } else { + strcpy(chr->filename, "tcp:"); + } + offset = strlen(chr->filename); + } + if (is_unix) { + if (is_listen) { + fd = unix_listen(host_str, chr->filename + offset, 256 - offset); + } else { + fd = unix_connect(host_str); + } + } else { + if (is_listen) { + fd = inet_listen(host_str, chr->filename + offset, 256 - offset, + SOCK_STREAM, 0); + } else { + fd = inet_connect(host_str, SOCK_STREAM); + } + } if (fd < 0) goto fail; @@ -2026,61 +2025,20 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, chr->chr_close = tcp_chr_close; if (is_listen) { - /* allow fast reuse */ -#ifndef _WIN32 - if (is_unix) { - char path[109]; - pstrcpy(path, sizeof(path), uaddr.sun_path); - unlink(path); - } else -#endif - { - val = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); - } - - ret = bind(fd, addr, addrlen); - if (ret < 0) - goto fail; - - ret = listen(fd, 0); - if (ret < 0) - goto fail; - s->listen_fd = fd; qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); if (is_telnet) s->do_telnetopt = 1; } else { - for(;;) { - ret = connect(fd, addr, addrlen); - if (ret < 0) { - err = socket_error(); - if (err == EINTR || err == EWOULDBLOCK) { - } else if (err == EINPROGRESS) { - break; -#ifdef _WIN32 - } else if (err == WSAEALREADY) { - break; -#endif - } else { - goto fail; - } - } else { - s->connected = 1; - break; - } - } + s->connected = 1; s->fd = fd; socket_set_nodelay(fd); - if (s->connected) - tcp_chr_connect(chr); - else - qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr); + tcp_chr_connect(chr); } if (is_listen && is_waitconnect) { - printf("QEMU waiting for connection on: %s\n", host_str); + printf("QEMU waiting for connection on: %s\n", + chr->filename ? chr->filename : host_str); tcp_chr_accept(chr); socket_set_nonblock(s->listen_fd); } -- 1.5.6.5 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH 3/3] sockets: switch over tcp/telnet/unix serial line to new helper functions. 2008-11-03 16:42 ` [Qemu-devel] [PATCH 3/3] sockets: switch over tcp/telnet/unix serial line to new helper functions Gerd Hoffmann @ 2008-11-11 20:54 ` Anthony Liguori 0 siblings, 0 replies; 12+ messages in thread From: Anthony Liguori @ 2008-11-11 20:54 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann Gerd Hoffmann wrote: > This switches the tcp, telnet and unix socket support for character > devices (serial/parallel, ...) to the new socket helpers. Thereby they > gain IPv6 support and also get ability to search for a free tcp port. > Syntax is the same as for vnc, using a to= option, like this: > > -serial tcp:localhost:5000,to=5099,server > > This will check the 5000 -> 5099 port range (inclusive) for a free tcp > port. Likewise you can get auto-allocated unix sockets by specifying an > empty path: > > -serial unix:,server > > qemu will create a randomly named socket in $TMPDIR then. > > tcp also got new "ipv4" and "ipv6" options to make qemu try only the > specified internet protocol version. > > You can use the "info chardev" command added by the first patch in this > series to figure the tcp port / unix socket actually allocated. > > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> > > Applied. Thanks. Regards, Anthony Liguori ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2008-11-27 9:11 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-11-03 16:42 [Qemu-devel] [PATCH v3 0/3] ipv6 and autoport patches Gerd Hoffmann 2008-11-03 16:42 ` [Qemu-devel] [PATCH 1/3] sockets: helper functions for qemu Gerd Hoffmann 2008-11-04 12:42 ` [Qemu-devel] " Gerd Hoffmann 2008-11-11 20:41 ` [Qemu-devel] " Anthony Liguori 2008-11-11 21:14 ` Gerd Hoffmann 2008-11-11 20:47 ` Anthony Liguori 2008-11-03 16:42 ` [Qemu-devel] [PATCH 2/3] sockets: switch vnc to new code, support vnc port auto-allocation Gerd Hoffmann 2008-11-11 20:52 ` Anthony Liguori 2008-11-26 23:25 ` Ryan Harper 2008-11-27 9:11 ` Gerd Hoffmann 2008-11-03 16:42 ` [Qemu-devel] [PATCH 3/3] sockets: switch over tcp/telnet/unix serial line to new helper functions Gerd Hoffmann 2008-11-11 20:54 ` Anthony Liguori
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).