qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [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] [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

* [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

* [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-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

* 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 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

* 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 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

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).