qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/4] ipv6 and autoport patches.
@ 2008-10-28 12:55 Gerd Hoffmann
  2008-10-28 12:55 ` [Qemu-devel] [PATCH 1/4] Implement "info chardev" command Gerd Hoffmann
                   ` (4 more replies)
  0 siblings, 5 replies; 20+ messages in thread
From: Gerd Hoffmann @ 2008-10-28 12:55 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.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 1/4] Implement "info chardev" command.
  2008-10-28 12:55 [Qemu-devel] [PATCH 0/4] ipv6 and autoport patches Gerd Hoffmann
@ 2008-10-28 12:55 ` Gerd Hoffmann
  2008-10-28 17:08   ` Blue Swirl
  2008-10-28 20:19   ` Daniel P. Berrange
  2008-10-28 12:55 ` [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu Gerd Hoffmann
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 20+ messages in thread
From: Gerd Hoffmann @ 2008-10-28 12:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This patch makes qemu keep track of the character devices in use and
implements a "info chardev" monitor command to print a list.

qemu_chr_open() sticks the devices into a linked list now.  It got a new
argument (label), so there is a name for each device.  It also assigns a
filename to each character device.  By default it just copyes the
filename passed in.  Individual drivers can fill in something else
though.  qemu_chr_open_pty() sets the filename to name of the pseudo tty
allocated.

Output looks like this:

  (qemu) info chardev
  monitor: filename=unix:/tmp/run.sh-26827/monitor,server,nowait
  serial0: filename=unix:/tmp/run.sh-26827/console,server
  serial1: filename=pty:/dev/pts/5
  parallel0: filename=vc:640x480

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 gdbstub.c       |    2 +-
 hw/usb-serial.c |    5 ++-
 monitor.c       |    2 +
 qemu-char.h     |    7 +++-
 vl.c            |   98 ++++++++++++++++++++++++++++++++++++------------------
 5 files changed, 78 insertions(+), 36 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 1a85eda..15d38f0 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1852,7 +1852,7 @@ int gdbserver_start(const char *port)
         port = gdbstub_port_name;
     }
 
-    chr = qemu_chr_open(port);
+    chr = qemu_chr_open("gdb", port);
     if (!chr)
         return -1;
 
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 40d04cb..a6a756d 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -521,6 +521,8 @@ USBDevice *usb_serial_init(const char *filename)
     USBSerialState *s;
     CharDriverState *cdrv;
     unsigned short vendorid = 0x0403, productid = 0x6001;
+    char label[32];
+    static int index;
 
     while (*filename && *filename != ':') {
         const char *p;
@@ -555,7 +557,8 @@ USBDevice *usb_serial_init(const char *filename)
     if (!s)
         return NULL;
 
-    cdrv = qemu_chr_open(filename);
+    snprintf(label, sizeof(label), "usbserial%d", index++);
+    cdrv = qemu_chr_open(label, filename);
     if (!cdrv)
         goto fail;
     s->cs = cdrv;
diff --git a/monitor.c b/monitor.c
index ae034e2..611bde5 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1470,6 +1470,8 @@ static const term_cmd_t info_cmds[] = {
       "", "show the version of qemu" },
     { "network", "", do_info_network,
       "", "show the network state" },
+    { "chardev", "", qemu_chr_info,
+      "", "show the character devices" },
     { "block", "", do_info_block,
       "", "show the block devices" },
     { "blockstats", "", do_info_blockstats,
diff --git a/qemu-char.h b/qemu-char.h
index 05d6899..55d81cb 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -1,6 +1,7 @@
 #ifndef QEMU_CHAR_H
 #define QEMU_CHAR_H
 
+#include "sys-queue.h"
 /* character device */
 
 #define CHR_EVENT_BREAK 0 /* serial break char */
@@ -55,9 +56,12 @@ struct CharDriverState {
     void *opaque;
     int focus;
     QEMUBH *bh;
+    char *label;
+    char *filename;
+    TAILQ_ENTRY(CharDriverState) next;
 };
 
-CharDriverState *qemu_chr_open(const char *filename);
+CharDriverState *qemu_chr_open(const char *label, const char *filename);
 void qemu_chr_close(CharDriverState *chr);
 void qemu_chr_printf(CharDriverState *s, const char *fmt, ...);
 int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len);
@@ -72,6 +76,7 @@ void qemu_chr_reset(CharDriverState *s);
 int qemu_chr_can_read(CharDriverState *s);
 void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len);
 void qemu_chr_accept_input(CharDriverState *s);
+void qemu_chr_info(void);
 
 /* async I/O support */
 
diff --git a/vl.c b/vl.c
index d870d0f..114f6db 100644
--- a/vl.c
+++ b/vl.c
@@ -2582,7 +2582,7 @@ static CharDriverState *qemu_chr_open_pty(void)
     CharDriverState *chr;
     PtyCharDriver *s;
     struct termios tty;
-    int slave_fd;
+    int slave_fd, len;
 #if defined(__OpenBSD__)
     char pty_name[PATH_MAX];
 #define q_ptsname(x) pty_name
@@ -2609,6 +2609,9 @@ static CharDriverState *qemu_chr_open_pty(void)
     tcsetattr(slave_fd, TCSAFLUSH, &tty);
     close(slave_fd);
 
+    len = strlen(q_ptsname(s->fd)) + 5;
+    chr->filename = qemu_malloc(len);
+    snprintf(chr->filename, len, "pty:%s", q_ptsname(s->fd));
     fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd));
 
     chr->opaque = s;
@@ -3768,90 +3771,115 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
     return NULL;
 }
 
-CharDriverState *qemu_chr_open(const char *filename)
+static TAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs
+= TAILQ_HEAD_INITIALIZER(chardevs);
+
+CharDriverState *qemu_chr_open(const char *label, const char *filename)
 {
     const char *p;
+    CharDriverState *chr;
 
     if (!strcmp(filename, "vc")) {
-        return text_console_init(&display_state, 0);
-    } else if (strstart(filename, "vc:", &p)) {
-        return text_console_init(&display_state, p);
-    } else if (!strcmp(filename, "null")) {
-        return qemu_chr_open_null();
+        chr = text_console_init(&display_state, 0);
+    } else
+    if (strstart(filename, "vc:", &p)) {
+        chr = text_console_init(&display_state, p);
+    } else
+    if (!strcmp(filename, "null")) {
+        chr = qemu_chr_open_null();
     } else
     if (strstart(filename, "tcp:", &p)) {
-        return qemu_chr_open_tcp(p, 0, 0);
+        chr = qemu_chr_open_tcp(p, 0, 0);
     } else
     if (strstart(filename, "telnet:", &p)) {
-        return qemu_chr_open_tcp(p, 1, 0);
+        chr = qemu_chr_open_tcp(p, 1, 0);
     } else
     if (strstart(filename, "udp:", &p)) {
-        return qemu_chr_open_udp(p);
+        chr = qemu_chr_open_udp(p);
     } else
     if (strstart(filename, "mon:", &p)) {
-        CharDriverState *drv = qemu_chr_open(p);
-        if (drv) {
-            drv = qemu_chr_open_mux(drv);
-            monitor_init(drv, !nographic);
-            return drv;
+        chr = qemu_chr_open(label, p);
+        if (chr) {
+            chr = qemu_chr_open_mux(chr);
+            monitor_init(chr, !nographic);
+        } else {
+            printf("Unable to open driver: %s\n", p);
         }
-        printf("Unable to open driver: %s\n", p);
-        return 0;
     } else
 #ifndef _WIN32
     if (strstart(filename, "unix:", &p)) {
-	return qemu_chr_open_tcp(p, 0, 1);
+	chr = qemu_chr_open_tcp(p, 0, 1);
     } else if (strstart(filename, "file:", &p)) {
-        return qemu_chr_open_file_out(p);
+        chr = qemu_chr_open_file_out(p);
     } else if (strstart(filename, "pipe:", &p)) {
-        return qemu_chr_open_pipe(p);
+        chr = qemu_chr_open_pipe(p);
     } else if (!strcmp(filename, "pty")) {
-        return qemu_chr_open_pty();
+        chr = qemu_chr_open_pty();
     } else if (!strcmp(filename, "stdio")) {
-        return qemu_chr_open_stdio();
+        chr = qemu_chr_open_stdio();
     } else
 #if defined(__linux__)
     if (strstart(filename, "/dev/parport", NULL)) {
-        return qemu_chr_open_pp(filename);
+        chr = qemu_chr_open_pp(filename);
     } else
 #endif
 #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
     || defined(__NetBSD__) || defined(__OpenBSD__)
     if (strstart(filename, "/dev/", NULL)) {
-        return qemu_chr_open_tty(filename);
+        chr = qemu_chr_open_tty(filename);
     } else
 #endif
 #else /* !_WIN32 */
     if (strstart(filename, "COM", NULL)) {
-        return qemu_chr_open_win(filename);
+        chr = qemu_chr_open_win(filename);
     } else
     if (strstart(filename, "pipe:", &p)) {
-        return qemu_chr_open_win_pipe(p);
+        chr = qemu_chr_open_win_pipe(p);
     } else
     if (strstart(filename, "con:", NULL)) {
-        return qemu_chr_open_win_con(filename);
+        chr = qemu_chr_open_win_con(filename);
     } else
     if (strstart(filename, "file:", &p)) {
-        return qemu_chr_open_win_file_out(p);
+        chr = qemu_chr_open_win_file_out(p);
     } else
 #endif
 #ifdef CONFIG_BRLAPI
     if (!strcmp(filename, "braille")) {
-        return chr_baum_init();
+        chr = chr_baum_init();
     } else
 #endif
     {
-        return NULL;
+        chr = NULL;
+    }
+
+    if (chr) {
+        if (!chr->filename)
+            chr->filename = qemu_strdup(filename);
+        chr->label = qemu_strdup(label);
+        TAILQ_INSERT_TAIL(&chardevs, chr, next);
     }
+    return chr;
 }
 
 void qemu_chr_close(CharDriverState *chr)
 {
+    TAILQ_REMOVE(&chardevs, chr, next);
     if (chr->chr_close)
         chr->chr_close(chr);
+    qemu_free(chr->filename);
+    qemu_free(chr->label);
     qemu_free(chr);
 }
 
+void qemu_chr_info(void)
+{
+    CharDriverState *chr;
+
+    TAILQ_FOREACH(chr, &chardevs, next) {
+        term_printf("%s: filename=%s\n", chr->label, chr->filename);
+    }
+}
+
 /***********************************************************/
 /* network device redirectors */
 
@@ -9718,7 +9746,7 @@ int main(int argc, char **argv)
         }
     }
     if (monitor_device) {
-        monitor_hd = qemu_chr_open(monitor_device);
+        monitor_hd = qemu_chr_open("monitor", monitor_device);
         if (!monitor_hd) {
             fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device);
             exit(1);
@@ -9729,7 +9757,9 @@ int main(int argc, char **argv)
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         const char *devname = serial_devices[i];
         if (devname && strcmp(devname, "none")) {
-            serial_hds[i] = qemu_chr_open(devname);
+            char label[32];
+            snprintf(label, sizeof(label), "serial%d", i);
+            serial_hds[i] = qemu_chr_open(label, devname);
             if (!serial_hds[i]) {
                 fprintf(stderr, "qemu: could not open serial device '%s'\n",
                         devname);
@@ -9743,7 +9773,9 @@ int main(int argc, char **argv)
     for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
         const char *devname = parallel_devices[i];
         if (devname && strcmp(devname, "none")) {
-            parallel_hds[i] = qemu_chr_open(devname);
+            char label[32];
+            snprintf(label, sizeof(label), "parallel%d", i);
+            parallel_hds[i] = qemu_chr_open(label, devname);
             if (!parallel_hds[i]) {
                 fprintf(stderr, "qemu: could not open parallel device '%s'\n",
                         devname);
-- 
1.5.6.5

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu.
  2008-10-28 12:55 [Qemu-devel] [PATCH 0/4] ipv6 and autoport patches Gerd Hoffmann
  2008-10-28 12:55 ` [Qemu-devel] [PATCH 1/4] Implement "info chardev" command Gerd Hoffmann
@ 2008-10-28 12:55 ` Gerd Hoffmann
  2008-10-28 13:15   ` Daniel P. Berrange
  2008-10-28 12:55 ` [Qemu-devel] [PATCH 3/4] sockets: switch vnc to new code, support vnc port auto-allocation Gerd Hoffmann
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 20+ messages in thread
From: Gerd Hoffmann @ 2008-10-28 12:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This patch creates a new source and header file qemu-sockets.[ch] 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 |    1 +
 qemu-sockets.c  |  391 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-sockets.h  |    8 +
 vl.c            |   13 ++
 4 files changed, 413 insertions(+), 0 deletions(-)
 create mode 100644 qemu-sockets.c
 create mode 100644 qemu-sockets.h

diff --git a/Makefile.target b/Makefile.target
index 547ac02..5f71972 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -580,6 +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
+OBJS+=qemu-sockets.o
 ifdef CONFIG_WIN32
 OBJS+=block-raw-win32.o
 else
diff --git a/qemu-sockets.c b/qemu-sockets.c
new file mode 100644
index 0000000..99adcd7
--- /dev/null
+++ b/qemu-sockets.c
@@ -0,0 +1,391 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "qemu-sockets.h"
+
+static int default_family = PF_UNSPEC;
+static int sockets_debug = 1;
+
+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);
+    }
+}
+
+void inet_set_ipv4(void)
+{
+    default_family = PF_INET;
+}
+
+void inet_set_ipv6(void)
+{
+    default_family = PF_INET6;
+}
+
+int inet_listen(const char *str, char *ostr, int olen,
+                int socktype, int port_offset)
+{
+    static const int on=1, off=0;
+    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.ai_family = default_family;
+    ai.ai_socktype = socktype;
+
+    /* parse string */
+    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;
+        }
+    }
+    opts = str + pos;
+    h = strstr(opts, ",to=");
+    to = h ? atoi(h+4) : 0;
+
+    /* lookup */
+    if (port_offset)
+        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
+    if (0 != (rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res))) {
+        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);
+	if (-1 == (slisten = socket(e->ai_family, e->ai_socktype,
+				    e->ai_protocol))) {
+            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
+                    inet_strfamily(e->ai_family), strerror(errno));
+	    continue;
+	}
+
+        setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
+        if (e->ai_family == PF_INET6) {
+            if (default_family == PF_INET6)
+                setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,&on,sizeof(on));
+            else
+                setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,&off,sizeof(off));
+        }
+
+        for (;;) {
+            if (0 == bind(slisten, e->ai_addr, e->ai_addrlen)) {
+                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;
+        }
+        close(slisten);
+    }
+    fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
+    return -1;
+
+listen:
+    if (0 != listen(slisten,1)) {
+        perror("listen");
+        close(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);
+        }
+    }
+    return slisten;
+}
+
+int inet_connect(const char *str, int socktype)
+{
+    static const int on=1;
+    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.ai_family = default_family;
+    ai.ai_socktype = socktype;
+
+    /* parse string */
+    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;
+        }
+    }
+
+    /* 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 (0 != getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
+			     uaddr,INET6_ADDRSTRLEN,uport,32,
+			     NI_NUMERICHOST | NI_NUMERICSERV)) {
+            fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__);
+	    continue;
+	}
+	if (-1 == (sock = socket(e->ai_family, e->ai_socktype,
+				 e->ai_protocol))) {
+            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
+                    inet_strfamily(e->ai_family), strerror(errno));
+	    continue;
+	}
+        setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
+
+	/* connect to peer */
+	if (-1 == connect(sock,e->ai_addr,e->ai_addrlen)) {
+            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));
+            close(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);
+	return sock;
+    }
+    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;
+
+    if (-1 == (sock = socket(PF_UNIX, SOCK_STREAM, 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);
+
+    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)) == -1) {
+        fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
+        goto err;
+    }
+    if (listen(sock, 1) == -1) {
+        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);
+    close(sock);
+    return -1;
+}
+
+int unix_connect(const char *path)
+{
+    struct sockaddr_un un;
+    int sock;
+
+    if (-1 == (sock = socket(PF_UNIX, SOCK_STREAM, 0))) {
+	perror("socket(unix)");
+	return -1;
+    }
+
+    un.sun_family = AF_UNIX;
+    snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
+    if (-1 == connect(sock, (struct sockaddr*) &un, sizeof(un))) {
+        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-sockets.h b/qemu-sockets.h
new file mode 100644
index 0000000..8793af3
--- /dev/null
+++ b/qemu-sockets.h
@@ -0,0 +1,8 @@
+int inet_listen(const char *str, char *ostr, int olen,
+                int socktype, int port_offset);
+int inet_connect(const char *str, int socktype);
+void inet_set_ipv4(void);
+void inet_set_ipv6(void);
+
+int unix_listen(const char *path, char *ostr, int olen);
+int unix_connect(const char *path);
diff --git a/vl.c b/vl.c
index 114f6db..2112585 100644
--- a/vl.c
+++ b/vl.c
@@ -37,6 +37,7 @@
 #include "gdbstub.h"
 #include "qemu-timer.h"
 #include "qemu-char.h"
+#include "qemu-sockets.h"
 #include "block.h"
 #include "audio/audio.h"
 #include "migration.h"
@@ -8386,6 +8387,8 @@ enum {
     QEMU_OPTION_bootp,
     QEMU_OPTION_smb,
     QEMU_OPTION_redir,
+    QEMU_OPTION_ipv4,
+    QEMU_OPTION_ipv6,
 
     QEMU_OPTION_kernel,
     QEMU_OPTION_append,
@@ -8489,6 +8492,10 @@ static const QEMUOption qemu_options[] = {
 #endif
     { "redir", HAS_ARG, QEMU_OPTION_redir },
 #endif
+    { "4", 0, QEMU_OPTION_ipv4 },
+    { "6", 0, QEMU_OPTION_ipv6 },
+    { "ipv4", 0, QEMU_OPTION_ipv4 },
+    { "ipv6", 0, QEMU_OPTION_ipv6 },
 
     { "kernel", HAS_ARG, QEMU_OPTION_kernel },
     { "append", HAS_ARG, QEMU_OPTION_append },
@@ -9151,6 +9158,12 @@ int main(int argc, char **argv)
                 net_slirp_redir(optarg);
                 break;
 #endif
+            case QEMU_OPTION_ipv4:
+                inet_set_ipv4();
+                break;
+            case QEMU_OPTION_ipv6:
+                inet_set_ipv6();
+                break;
 #ifdef HAS_AUDIO
             case QEMU_OPTION_audio_help:
                 AUD_help ();
-- 
1.5.6.5

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 3/4] sockets: switch vnc to new code, support vnc port auto-allocation.
  2008-10-28 12:55 [Qemu-devel] [PATCH 0/4] ipv6 and autoport patches Gerd Hoffmann
  2008-10-28 12:55 ` [Qemu-devel] [PATCH 1/4] Implement "info chardev" command Gerd Hoffmann
  2008-10-28 12:55 ` [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu Gerd Hoffmann
@ 2008-10-28 12:55 ` Gerd Hoffmann
  2008-10-28 17:25   ` Blue Swirl
  2008-10-28 12:55 ` [Qemu-devel] [PATCH 4/4] sockets: switch over tcp/telnet/unix serial line to new helper functions Gerd Hoffmann
  2008-10-28 15:53 ` [Qemu-devel] [PATCH 0/4] ipv6 and autoport patches Anthony Liguori
  4 siblings, 1 reply; 20+ messages in thread
From: Gerd Hoffmann @ 2008-10-28 12:55 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).

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

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 vnc.c |  119 ++++++++++++++++-------------------------------------------------
 1 files changed, 29 insertions(+), 90 deletions(-)

diff --git a/vnc.c b/vnc.c
index 9df4dbe..e3c9478 100644
--- a/vnc.c
+++ b/vnc.c
@@ -28,6 +28,7 @@
 #include "sysemu.h"
 #include "qemu_socket.h"
 #include "qemu-timer.h"
+#include "qemu-sockets.h"
 
 #define VNC_REFRESH_INTERVAL (1000 / 30)
 
@@ -2139,8 +2140,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,28 +2290,20 @@ 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
 
     vnc_display_close(ds);
-    if (strcmp(display, "none") == 0)
-	return 0;
-
     if (!(vs->display = strdup(display)))
 	return -1;
+    if (strcmp(display, "none") == 0)
+	return 0;
 
     options = display;
     while ((options = strchr(options, ','))) {
@@ -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;
         }
-    }
+        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;
-    }
-
-    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] 20+ messages in thread

* [Qemu-devel] [PATCH 4/4] sockets: switch over tcp/telnet/unix serial line to new helper functions.
  2008-10-28 12:55 [Qemu-devel] [PATCH 0/4] ipv6 and autoport patches Gerd Hoffmann
                   ` (2 preceding siblings ...)
  2008-10-28 12:55 ` [Qemu-devel] [PATCH 3/4] sockets: switch vnc to new code, support vnc port auto-allocation Gerd Hoffmann
@ 2008-10-28 12:55 ` Gerd Hoffmann
  2008-10-28 15:53 ` [Qemu-devel] [PATCH 0/4] ipv6 and autoport patches Anthony Liguori
  4 siblings, 0 replies; 20+ messages in thread
From: Gerd Hoffmann @ 2008-10-28 12:55 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.  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>
---
 vl.c |  129 ++++++++++++++++-------------------------------------------------
 1 files changed, 32 insertions(+), 97 deletions(-)

diff --git a/vl.c b/vl.c
index 2112585..7d45c7f 100644
--- a/vl.c
+++ b/vl.c
@@ -3370,9 +3370,6 @@ static void udp_chr_update_read_handler(CharDriverState *chr)
     }
 }
 
-#ifndef _WIN32
-static int parse_unix_path(struct sockaddr_un *uaddr, const char *str);
-#endif
 int parse_host_src_port(struct sockaddr_in *haddr,
                         struct sockaddr_in *saddr,
                         const char *str);
@@ -3629,32 +3626,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,','))) {
@@ -3665,6 +3641,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;
@@ -3680,13 +3658,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;
 
@@ -3704,61 +3700,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);
     }
@@ -4035,26 +3990,6 @@ int parse_host_port(struct sockaddr_in *saddr, const char *str)
     return 0;
 }
 
-#ifndef _WIN32
-static int parse_unix_path(struct sockaddr_un *uaddr, const char *str)
-{
-    const char *p;
-    int len;
-
-    len = MIN(108, strlen(str));
-    p = strchr(str, ',');
-    if (p)
-	len = MIN(len, p - str);
-
-    memset(uaddr, 0, sizeof(*uaddr));
-
-    uaddr->sun_family = AF_UNIX;
-    memcpy(uaddr->sun_path, str, len);
-
-    return 0;
-}
-#endif
-
 /* find or alloc a new VLAN */
 VLANState *qemu_find_vlan(int id)
 {
-- 
1.5.6.5

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu.
  2008-10-28 12:55 ` [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu Gerd Hoffmann
@ 2008-10-28 13:15   ` Daniel P. Berrange
  2008-10-28 14:22     ` Gerd Hoffmann
  0 siblings, 1 reply; 20+ messages in thread
From: Daniel P. Berrange @ 2008-10-28 13:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

On Tue, Oct 28, 2008 at 01:55:16PM +0100, Gerd Hoffmann wrote:
> This patch creates a new source and header file qemu-sockets.[ch] 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.

This is great - adding IPv6 was on my todo list for ages !

> +
> +int inet_listen(const char *str, char *ostr, int olen,
> +                int socktype, int port_offset)
> +{
> +    static const int on=1, off=0;
> +    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;

You should also set AI_ADDRCONFIG here. This ensure that it only
returns IPv6 addresses if a network interface actally has IPv6
enabled. So if someone's disabled IPv6 on a machine, and DNS still
has IPv6 addrs, AI_ADDRCONFIG will stop QEMU pointlessly attempting
to create IPv6 sockets that won't do anything

> +    ai.ai_family = default_family;
> +    ai.ai_socktype = socktype;
> +
> +    /* parse string */
> +    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;
> +        }
> +    }
> +    opts = str + pos;
> +    h = strstr(opts, ",to=");
> +    to = h ? atoi(h+4) : 0;
> +
> +    /* lookup */
> +    if (port_offset)
> +        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
> +    if (0 != (rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res))) {
> +        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);
> +	if (-1 == (slisten = socket(e->ai_family, e->ai_socktype,
> +				    e->ai_protocol))) {
> +            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
> +                    inet_strfamily(e->ai_family), strerror(errno));
> +	    continue;
> +	}
> +
> +        setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
> +        if (e->ai_family == PF_INET6) {
> +            if (default_family == PF_INET6)
> +                setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,&on,sizeof(on));
> +            else
> +                setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,&off,sizeof(off));
> +        }
> +
> +        for (;;) {
> +            if (0 == bind(slisten, e->ai_addr, e->ai_addrlen)) {
> +                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;
> +        }
> +        close(slisten);
> +    }
> +    fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
> +    return -1;
> +
> +listen:
> +    if (0 != listen(slisten,1)) {
> +        perror("listen");
> +        close(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);
> +        }
> +    }
> +    return slisten;
> +}

One small problem here - for a server you need to expect more than one
socket will be required. This is because some operating systems require
you to bind to IPv4 and IPv6 sockets separately. On Linux by default
a IPv6 socket can accept IPv4 client connections, but this behaviour
can be turned off by sysctl, and other non-Linux OS don't allow this
at all. So we really need an array of server sockets, and attempt to
bind to all addresses returned by getaddrinfo().

There's more info on this here

  http://people.redhat.com/drepper/userapi-ipv6.html

> +int inet_connect(const char *str, int socktype)
> +{
> +    static const int on=1;
> +    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;

This also needs AI_ADDRCONFIG set

> +    ai.ai_family = default_family;
> +    ai.ai_socktype = socktype;
> +
> +    /* parse string */
> +    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;
> +        }
> +    }
> +
> +    /* 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 (0 != getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
> +			     uaddr,INET6_ADDRSTRLEN,uport,32,
> +			     NI_NUMERICHOST | NI_NUMERICSERV)) {
> +            fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__);
> +	    continue;
> +	}
> +	if (-1 == (sock = socket(e->ai_family, e->ai_socktype,
> +				 e->ai_protocol))) {
> +            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
> +                    inet_strfamily(e->ai_family), strerror(errno));
> +	    continue;
> +	}
> +        setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
> +
> +	/* connect to peer */
> +	if (-1 == connect(sock,e->ai_addr,e->ai_addrlen)) {
> +            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));
> +            close(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);
> +	return sock;
> +    }
> +    return -1;
> +}
> +

REgards,
Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu.
  2008-10-28 13:15   ` Daniel P. Berrange
@ 2008-10-28 14:22     ` Gerd Hoffmann
  2008-10-28 14:31       ` Daniel P. Berrange
  0 siblings, 1 reply; 20+ messages in thread
From: Gerd Hoffmann @ 2008-10-28 14:22 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: qemu-devel

Daniel P. Berrange wrote:
>> +    memset(&ai,0, sizeof(ai));
>> +    ai.ai_flags = AI_PASSIVE;
> 
> You should also set AI_ADDRCONFIG here. This ensure that it only
> returns IPv6 addresses if a network interface actally has IPv6
> enabled. So if someone's disabled IPv6 on a machine, and DNS still
> has IPv6 addrs, AI_ADDRCONFIG will stop QEMU pointlessly attempting
> to create IPv6 sockets that won't do anything

Done.

>> +        if (e->ai_family == PF_INET6) {
>> +            if (default_family == PF_INET6)
>> +                setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,&on,sizeof(on));
>> +            else
>> +                setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,&off,sizeof(off));
>> +        }

> One small problem here - for a server you need to expect more than one
> socket will be required. This is because some operating systems require
> you to bind to IPv4 and IPv6 sockets separately.

Sure?  I've googled a bit on this issue, looked what apache does here.
I've figured this can be changed per socket, with a system-wide default
configurable via sysctl (and different OSes have different default
configs here).

The setsockopt code snippet quoted above should take care about that
issue and turn off the v6only option for the socket (unless the user
explicitly asked for IPv6 using the '-ipv6' command line option).

> So we really need an array of server sockets, and attempt to
> bind to all addresses returned by getaddrinfo().

I'm trying to get around that if possible ...

> There's more info on this here
> 
>   http://people.redhat.com/drepper/userapi-ipv6.html

Hmm, IPV6_V6ONLY not mentioned there ...

>> +    memset(&ai,0, sizeof(ai));
>> +    ai.ai_flags = AI_CANONNAME;
> 
> This also needs AI_ADDRCONFIG set

Done.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu.
  2008-10-28 14:22     ` Gerd Hoffmann
@ 2008-10-28 14:31       ` Daniel P. Berrange
  2008-10-28 15:10         ` Gerd Hoffmann
  0 siblings, 1 reply; 20+ messages in thread
From: Daniel P. Berrange @ 2008-10-28 14:31 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On Tue, Oct 28, 2008 at 03:22:35PM +0100, Gerd Hoffmann wrote:
> Daniel P. Berrange wrote:
> >> +    memset(&ai,0, sizeof(ai));
> >> +    ai.ai_flags = AI_PASSIVE;
> > 
> > You should also set AI_ADDRCONFIG here. This ensure that it only
> > returns IPv6 addresses if a network interface actally has IPv6
> > enabled. So if someone's disabled IPv6 on a machine, and DNS still
> > has IPv6 addrs, AI_ADDRCONFIG will stop QEMU pointlessly attempting
> > to create IPv6 sockets that won't do anything
> 
> Done.
> 
> >> +        if (e->ai_family == PF_INET6) {
> >> +            if (default_family == PF_INET6)
> >> +                setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,&on,sizeof(on));
> >> +            else
> >> +                setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,&off,sizeof(off));
> >> +        }
> 
> > One small problem here - for a server you need to expect more than one
> > socket will be required. This is because some operating systems require
> > you to bind to IPv4 and IPv6 sockets separately.
> 
> Sure?  I've googled a bit on this issue, looked what apache does here.
> I've figured this can be changed per socket, with a system-wide default
> configurable via sysctl (and different OSes have different default
> configs here).

Ah, I was mis-understanding  what  IPV6_V6ONLY was doing here. If that's
portable to BSD like OS too, then I reckon that's sufficient and would
avoid need for separate sockets.

> The setsockopt code snippet quoted above should take care about that
> issue and turn off the v6only option for the socket (unless the user
> explicitly asked for IPv6 using the '-ipv6' command line option).
> 
> > So we really need an array of server sockets, and attempt to
> > bind to all addresses returned by getaddrinfo().
> 
> I'm trying to get around that if possible ...
> 
> > There's more info on this here
> > 
> >   http://people.redhat.com/drepper/userapi-ipv6.html
> 
> Hmm, IPV6_V6ONLY not mentioned there ...

Uli was demonstrating how to achieve total protocol independance
in your code. So if someone invents something better even than
IPv6 your code would still work. If you're happy to limit yourself
to just IPv4 & IPv6, then the IPV6_V6ONLY trick would work.

Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu.
  2008-10-28 14:31       ` Daniel P. Berrange
@ 2008-10-28 15:10         ` Gerd Hoffmann
  0 siblings, 0 replies; 20+ messages in thread
From: Gerd Hoffmann @ 2008-10-28 15:10 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: qemu-devel

Daniel P. Berrange wrote:
> On Tue, Oct 28, 2008 at 03:22:35PM +0100, Gerd Hoffmann wrote:
>> Daniel P. Berrange wrote:
>> Sure?  I've googled a bit on this issue, looked what apache does here.
>> I've figured this can be changed per socket, with a system-wide default
>> configurable via sysctl (and different OSes have different default
>> configs here).
> 
> Ah, I was mis-understanding  what  IPV6_V6ONLY was doing here. If that's
> portable to BSD like OS too, then I reckon that's sufficient and would
> avoid need for separate sockets.

I hope so, but didn't actually test that on something BSDish.  Maybe the
BSD folks on the list can comment/test?

> Uli was demonstrating how to achieve total protocol independance
> in your code. So if someone invents something better even than
> IPv6 your code would still work. If you're happy to limit yourself
> to just IPv4 & IPv6, then the IPV6_V6ONLY trick would work.

Right now there isn't anything else, and I'd prefer to tackle the issue
of other protocols once we have them.  There are also some more ipv4/v6
assumptions in the code, so other protocols wouldn't work out-of-the-box
anyway.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH 0/4] ipv6 and autoport patches.
  2008-10-28 12:55 [Qemu-devel] [PATCH 0/4] ipv6 and autoport patches Gerd Hoffmann
                   ` (3 preceding siblings ...)
  2008-10-28 12:55 ` [Qemu-devel] [PATCH 4/4] sockets: switch over tcp/telnet/unix serial line to new helper functions Gerd Hoffmann
@ 2008-10-28 15:53 ` Anthony Liguori
  4 siblings, 0 replies; 20+ messages in thread
From: Anthony Liguori @ 2008-10-28 15:53 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Gerd Hoffmann wrote:
>   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.
>   

These look good and they make info chardev quite a lot more attractive.

Regards,

Anthony Liguori

> cheers,
>   Gerd
>
>
>
>   

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH 1/4] Implement "info chardev" command.
  2008-10-28 12:55 ` [Qemu-devel] [PATCH 1/4] Implement "info chardev" command Gerd Hoffmann
@ 2008-10-28 17:08   ` Blue Swirl
  2008-10-28 19:58     ` Gerd Hoffmann
  2008-10-28 20:19   ` Daniel P. Berrange
  1 sibling, 1 reply; 20+ messages in thread
From: Blue Swirl @ 2008-10-28 17:08 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

On 10/28/08, Gerd Hoffmann <kraxel@redhat.com> wrote:
> This patch makes qemu keep track of the character devices in use and
>  implements a "info chardev" monitor command to print a list.
>
>  qemu_chr_open() sticks the devices into a linked list now.  It got a new
>  argument (label), so there is a name for each device.  It also assigns a
>  filename to each character device.  By default it just copyes the
>  filename passed in.  Individual drivers can fill in something else
>  though.  qemu_chr_open_pty() sets the filename to name of the pseudo tty
>  allocated.
>
>  Output looks like this:
>
>   (qemu) info chardev
>   monitor: filename=unix:/tmp/run.sh-26827/monitor,server,nowait
>   serial0: filename=unix:/tmp/run.sh-26827/console,server
>   serial1: filename=pty:/dev/pts/5
>   parallel0: filename=vc:640x480

Nice!

>  @@ -55,9 +56,12 @@ struct CharDriverState {
>      void *opaque;
>      int focus;
>      QEMUBH *bh;
>  +    char *label;
>  +    char *filename;

I think you should add 'const' to both above.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH 3/4] sockets: switch vnc to new code, support vnc port auto-allocation.
  2008-10-28 12:55 ` [Qemu-devel] [PATCH 3/4] sockets: switch vnc to new code, support vnc port auto-allocation Gerd Hoffmann
@ 2008-10-28 17:25   ` Blue Swirl
  2008-10-28 19:57     ` Gerd Hoffmann
  0 siblings, 1 reply; 20+ messages in thread
From: Blue Swirl @ 2008-10-28 17:25 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

On 10/28/08, Gerd Hoffmann <kraxel@redhat.com> wrote:
> This patch switches the vnc code ofer to the new socket helper
>  functions.
>  -    if (strcmp(display, "none") == 0)
>  -       return 0;
>  -
>      if (!(vs->display = strdup(display)))
>         return -1;
>  +    if (strcmp(display, "none") == 0)
>  +       return 0;

Why this change? It looks like it will leak memory if display is "none".

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH 3/4] sockets: switch vnc to new code, support vnc port auto-allocation.
  2008-10-28 17:25   ` Blue Swirl
@ 2008-10-28 19:57     ` Gerd Hoffmann
  2008-10-29 10:46       ` Gerd Hoffmann
  0 siblings, 1 reply; 20+ messages in thread
From: Gerd Hoffmann @ 2008-10-28 19:57 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

Blue Swirl wrote:
> On 10/28/08, Gerd Hoffmann <kraxel@redhat.com> wrote:
>> This patch switches the vnc code ofer to the new socket helper
>>  functions.
>>  -    if (strcmp(display, "none") == 0)
>>  -       return 0;
>>  -
>>      if (!(vs->display = strdup(display)))
>>         return -1;
>>  +    if (strcmp(display, "none") == 0)
>>  +       return 0;
> 
> Why this change?

To keep vs->display and thus the "info vnc" output up-to-date.  Without
this you'll see stale information after "change vnc none".

> It looks like it will leak memory if display is "none".

Oops, yes.  Will fix.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH 1/4] Implement "info chardev" command.
  2008-10-28 17:08   ` Blue Swirl
@ 2008-10-28 19:58     ` Gerd Hoffmann
  2008-10-29 11:02       ` Gerd Hoffmann
  0 siblings, 1 reply; 20+ messages in thread
From: Gerd Hoffmann @ 2008-10-28 19:58 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

  Hi,

>>  @@ -55,9 +56,12 @@ struct CharDriverState {
>>      void *opaque;
>>      int focus;
>>      QEMUBH *bh;
>>  +    char *label;
>>  +    char *filename;
> 
> I think you should add 'const' to both above.

Will do.

thanks,
  Gerd

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH 1/4] Implement "info chardev" command.
  2008-10-28 12:55 ` [Qemu-devel] [PATCH 1/4] Implement "info chardev" command Gerd Hoffmann
  2008-10-28 17:08   ` Blue Swirl
@ 2008-10-28 20:19   ` Daniel P. Berrange
  2008-10-28 21:28     ` Gerd Hoffmann
  1 sibling, 1 reply; 20+ messages in thread
From: Daniel P. Berrange @ 2008-10-28 20:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

On Tue, Oct 28, 2008 at 01:55:15PM +0100, Gerd Hoffmann wrote:
> This patch makes qemu keep track of the character devices in use and
> implements a "info chardev" monitor command to print a list.
> 
> qemu_chr_open() sticks the devices into a linked list now.  It got a new
> argument (label), so there is a name for each device.  It also assigns a
> filename to each character device.  By default it just copyes the
> filename passed in.  Individual drivers can fill in something else
> though.  qemu_chr_open_pty() sets the filename to name of the pseudo tty
> allocated.
> 
> Output looks like this:
> 
>   (qemu) info chardev
>   monitor: filename=unix:/tmp/run.sh-26827/monitor,server,nowait
>   serial0: filename=unix:/tmp/run.sh-26827/console,server
>   serial1: filename=pty:/dev/pts/5
>   parallel0: filename=vc:640x480

Good to have this 'info chardev' support, to avoid need to parse stderr
to try & find PTY device paths :-) 

I don't know if the info is easily available, but for the 'vc' use case,
it might be worth exposing the VC number, so a intelligent client app can
read it, and be able to send 'ctl-alt-NN' in the VNC/SDL console to switch
directly to the char device's VC.


Regards,
Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH 1/4] Implement "info chardev" command.
  2008-10-28 20:19   ` Daniel P. Berrange
@ 2008-10-28 21:28     ` Gerd Hoffmann
  0 siblings, 0 replies; 20+ messages in thread
From: Gerd Hoffmann @ 2008-10-28 21:28 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: qemu-devel

Daniel P. Berrange wrote:
> I don't know if the info is easily available, but for the 'vc' use case,
> it might be worth exposing the VC number, so a intelligent client app can
> read it, and be able to send 'ctl-alt-NN' in the VNC/SDL console to switch
> directly to the char device's VC.

The numbering can change after initialization due to graphic displays
being inserted at screen 0 and moveing any text screens away for that.
Which makes this non-trivial ...

IMHO a management app is better of *not* using vc, but something else
(pty/unix) which then can be linked to and displayed in a vte (gtk
terminal) widget.  One major advantage is that cut&paste works then,
also the qemu terminal emulation on the vc's isn't that great.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH 3/4] sockets: switch vnc to new code, support vnc port auto-allocation.
  2008-10-28 19:57     ` Gerd Hoffmann
@ 2008-10-29 10:46       ` Gerd Hoffmann
  0 siblings, 0 replies; 20+ messages in thread
From: Gerd Hoffmann @ 2008-10-29 10:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Blue Swirl

Gerd Hoffmann wrote:
> Blue Swirl wrote:
>> On 10/28/08, Gerd Hoffmann <kraxel@redhat.com> wrote:
>>> This patch switches the vnc code ofer to the new socket helper
>>>  functions.
>>>  -    if (strcmp(display, "none") == 0)
>>>  -       return 0;
>>>  -
>>>      if (!(vs->display = strdup(display)))
>>>         return -1;
>>>  +    if (strcmp(display, "none") == 0)
>>>  +       return 0;
>> Why this change?
> 
> To keep vs->display and thus the "info vnc" output up-to-date.  Without
> this you'll see stale information after "change vnc none".

Scratch that.  vs->display is released and set to NULL in
vnc_display_close().  So this chunk isn't needed at all, I'll drop it.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH 1/4] Implement "info chardev" command.
  2008-10-28 19:58     ` Gerd Hoffmann
@ 2008-10-29 11:02       ` Gerd Hoffmann
  2008-10-29 18:30         ` Blue Swirl
  0 siblings, 1 reply; 20+ messages in thread
From: Gerd Hoffmann @ 2008-10-29 11:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: Blue Swirl

Gerd Hoffmann wrote:
>   Hi,
> 
>>>  @@ -55,9 +56,12 @@ struct CharDriverState {
>>>      void *opaque;
>>>      int focus;
>>>      QEMUBH *bh;
>>>  +    char *label;
>>>  +    char *filename;
>> I think you should add 'const' to both above.
> 
> Will do.

Well, no.  filename is modified by (some) qemu_chr_open_*() functions,
so it's pointless IMHO.  label never ever changes after the first
assignment and it works fine except for this warning:

passing arg 1 of `qemu_free' discards qualifiers from pointer target type.

Hmm.  I don't feel like casting that one away.  And constifying the
qemu_free() argument doesn't look sane either.  Other suggestions?

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH 1/4] Implement "info chardev" command.
  2008-10-29 11:02       ` Gerd Hoffmann
@ 2008-10-29 18:30         ` Blue Swirl
  0 siblings, 0 replies; 20+ messages in thread
From: Blue Swirl @ 2008-10-29 18:30 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On 10/29/08, Gerd Hoffmann <kraxel@redhat.com> wrote:
> Gerd Hoffmann wrote:
>  >   Hi,
>  >
>  >>>  @@ -55,9 +56,12 @@ struct CharDriverState {
>  >>>      void *opaque;
>  >>>      int focus;
>  >>>      QEMUBH *bh;
>  >>>  +    char *label;
>  >>>  +    char *filename;
>  >> I think you should add 'const' to both above.
>  >
>  > Will do.
>
>
> Well, no.  filename is modified by (some) qemu_chr_open_*() functions,
>  so it's pointless IMHO.  label never ever changes after the first
>  assignment and it works fine except for this warning:
>
>  passing arg 1 of `qemu_free' discards qualifiers from pointer target type.
>
>  Hmm.  I don't feel like casting that one away.  And constifying the
>  qemu_free() argument doesn't look sane either.  Other suggestions?

Drop 'const'? Sorry for the trouble.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 4/4] sockets: switch over tcp/telnet/unix serial line to new helper functions.
  2008-10-31 12:47 [Qemu-devel] [PATCH v2 " Gerd Hoffmann
@ 2008-10-31 12:47 ` Gerd Hoffmann
  0 siblings, 0 replies; 20+ messages in thread
From: Gerd Hoffmann @ 2008-10-31 12:47 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.  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>
---
 vl.c |  131 +++++++++++++++++-------------------------------------------------
 1 files changed, 33 insertions(+), 98 deletions(-)

diff --git a/vl.c b/vl.c
index e4648f9..b6c61be 100644
--- a/vl.c
+++ b/vl.c
@@ -3370,9 +3370,6 @@ static void udp_chr_update_read_handler(CharDriverState *chr)
     }
 }
 
-#ifndef _WIN32
-static int parse_unix_path(struct sockaddr_un *uaddr, const char *str);
-#endif
 int parse_host_src_port(struct sockaddr_in *haddr,
                         struct sockaddr_in *saddr,
                         const char *str);
@@ -3629,32 +3626,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,','))) {
@@ -3665,6 +3641,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;
@@ -3680,13 +3658,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;
 
@@ -3704,61 +3700,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);
     }
@@ -4035,26 +3990,6 @@ int parse_host_port(struct sockaddr_in *saddr, const char *str)
     return 0;
 }
 
-#ifndef _WIN32
-static int parse_unix_path(struct sockaddr_un *uaddr, const char *str)
-{
-    const char *p;
-    int len;
-
-    len = MIN(108, strlen(str));
-    p = strchr(str, ',');
-    if (p)
-	len = MIN(len, p - str);
-
-    memset(uaddr, 0, sizeof(*uaddr));
-
-    uaddr->sun_family = AF_UNIX;
-    memcpy(uaddr->sun_path, str, len);
-
-    return 0;
-}
-#endif
-
 /* find or alloc a new VLAN */
 VLANState *qemu_find_vlan(int id)
 {
@@ -8284,7 +8219,7 @@ static void help(int exitcode)
            "-ipv4           Use IPv4 only.\n"
            "-ipv6           Use UPv6 only.\n"
            "                By default qemu uses what is available on your machine.\n"
-           "                Applies to -vnc.\n"
+           "                Applies to -vnc and -serial tcp.\n"
            "\n"
            "Linux boot specific:\n"
            "-kernel bzImage use 'bzImage' as kernel image\n"
-- 
1.5.6.5

^ permalink raw reply related	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2008-10-31 12:49 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-10-28 12:55 [Qemu-devel] [PATCH 0/4] ipv6 and autoport patches Gerd Hoffmann
2008-10-28 12:55 ` [Qemu-devel] [PATCH 1/4] Implement "info chardev" command Gerd Hoffmann
2008-10-28 17:08   ` Blue Swirl
2008-10-28 19:58     ` Gerd Hoffmann
2008-10-29 11:02       ` Gerd Hoffmann
2008-10-29 18:30         ` Blue Swirl
2008-10-28 20:19   ` Daniel P. Berrange
2008-10-28 21:28     ` Gerd Hoffmann
2008-10-28 12:55 ` [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu Gerd Hoffmann
2008-10-28 13:15   ` Daniel P. Berrange
2008-10-28 14:22     ` Gerd Hoffmann
2008-10-28 14:31       ` Daniel P. Berrange
2008-10-28 15:10         ` Gerd Hoffmann
2008-10-28 12:55 ` [Qemu-devel] [PATCH 3/4] sockets: switch vnc to new code, support vnc port auto-allocation Gerd Hoffmann
2008-10-28 17:25   ` Blue Swirl
2008-10-28 19:57     ` Gerd Hoffmann
2008-10-29 10:46       ` Gerd Hoffmann
2008-10-28 12:55 ` [Qemu-devel] [PATCH 4/4] sockets: switch over tcp/telnet/unix serial line to new helper functions Gerd Hoffmann
2008-10-28 15:53 ` [Qemu-devel] [PATCH 0/4] ipv6 and autoport patches Anthony Liguori
  -- strict thread matches above, loose matches on Subject: below --
2008-10-31 12:47 [Qemu-devel] [PATCH v2 " Gerd Hoffmann
2008-10-31 12:47 ` [Qemu-devel] [PATCH 4/4] sockets: switch over tcp/telnet/unix serial line to new helper functions Gerd Hoffmann

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