* [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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ 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; 25+ 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] 25+ messages in thread
* [Qemu-devel] [PATCH v2 0/4] ipv6 and autoport patches. @ 2008-10-31 12:47 Gerd Hoffmann 2008-10-31 12:47 ` [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu Gerd Hoffmann 0 siblings, 1 reply; 25+ messages in thread From: Gerd Hoffmann @ 2008-10-31 12:47 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 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] 25+ messages in thread
* [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu. 2008-10-31 12:47 [Qemu-devel] [PATCH v2 " Gerd Hoffmann @ 2008-10-31 12:47 ` Gerd Hoffmann 2008-10-31 17:37 ` Anthony Liguori 0 siblings, 1 reply; 25+ messages in thread From: Gerd Hoffmann @ 2008-10-31 12:47 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 | 409 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-sockets.h | 8 + vl.c | 16 ++ 4 files changed, 434 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..9944d42 --- /dev/null +++ b/qemu-sockets.c @@ -0,0 +1,409 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#ifdef _WIN32 +# define WINVER 0x0501 /* needed for ipv6 bits */ +# include <windows.h> +# include <winsock2.h> +# include <ws2tcpip.h> +# define AI_ADDRCONFIG 0 +# define close closesocket +#else +# include <unistd.h> +# include <errno.h> +# include <sys/socket.h> +# include <sys/un.h> +# include <netinet/in.h> +# include <netdb.h> +#endif + +#include "qemu-sockets.h" + +static int default_family = PF_UNSPEC; +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); + } +} + +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) +{ + 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 = 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,(void*)&on,sizeof(on)); +#ifdef IPV6_V6ONLY + if (e->ai_family == PF_INET6) { + if (default_family == PF_INET6) { + /* user specified -ipv6: listen on ipv6 only */ + setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&on,sizeof(on)); + } else { + /* default: listen on both ipv4 and ipv6 */ + setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off,sizeof(off)); + } + } +#endif + + 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__); + freeaddrinfo(res); + 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); + } + } + 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 = 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,(void*)&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); + 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; + + 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 a9fae17..e9fe478 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" @@ -8280,6 +8281,9 @@ static void help(int exitcode) "-redir [tcp|udp]:host-port:[guest-host]:guest-port\n" " redirect TCP or UDP connections from host to guest [-net user]\n" #endif + "-ipv4 Use IPv4 only.\n" + "-ipv6 Use UPv6 only.\n" + " By default qemu uses what is available on your machine.\n" "\n" "Linux boot specific:\n" "-kernel bzImage use 'bzImage' as kernel image\n" @@ -8386,6 +8390,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 +8495,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 +9161,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] 25+ messages in thread
* Re: [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu. 2008-10-31 12:47 ` [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu Gerd Hoffmann @ 2008-10-31 17:37 ` Anthony Liguori 2008-10-31 17:50 ` Daniel P. Berrange 2008-11-03 15:35 ` Gerd Hoffmann 0 siblings, 2 replies; 25+ messages in thread From: Anthony Liguori @ 2008-10-31 17:37 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann 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. > > The following patches put that code into use. > I like this patch, but we already have a qemu_socket.h. Please remove qemu_socket.h if you're going to introduce qemu-sockets.h. > + > +listen: > + if (0 != listen(slisten,1)) { > Please try to avoid this style of if(). > diff --git a/vl.c b/vl.c > index a9fae17..e9fe478 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" > @@ -8280,6 +8281,9 @@ static void help(int exitcode) > "-redir [tcp|udp]:host-port:[guest-host]:guest-port\n" > " redirect TCP or UDP connections from host to guest [-net user]\n" > #endif > + "-ipv4 Use IPv4 only.\n" > + "-ipv6 Use UPv6 only.\n" > + " By default qemu uses what is available on your machine.\n" > "\n" > "Linux boot specific:\n" > "-kernel bzImage use 'bzImage' as kernel image\n" > @@ -8386,6 +8390,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 +8495,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 }, I don't like the idea of aliasing these options. Please just stick with one set of options. And do we really need to have options for this? Can't we just do the right thing? I can't believe that every application has to have an ipv6 switch to be ipv6 enabled. Regards, Anthony Liguori ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu. 2008-10-31 17:37 ` Anthony Liguori @ 2008-10-31 17:50 ` Daniel P. Berrange 2008-10-31 17:58 ` Anthony Liguori 2008-11-03 15:35 ` Gerd Hoffmann 1 sibling, 1 reply; 25+ messages in thread From: Daniel P. Berrange @ 2008-10-31 17:50 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann On Fri, Oct 31, 2008 at 12:37:16PM -0500, Anthony Liguori wrote: > Gerd Hoffmann wrote: > >@@ -8280,6 +8281,9 @@ static void help(int exitcode) > > "-redir [tcp|udp]:host-port:[guest-host]:guest-port\n" > > " redirect TCP or UDP connections from host to > > guest [-net user]\n" > > #endif > >+ "-ipv4 Use IPv4 only.\n" > >+ "-ipv6 Use UPv6 only.\n" > >+ " By default qemu uses what is available on > >your machine.\n" > > "\n" > > "Linux boot specific:\n" > > "-kernel bzImage use 'bzImage' as kernel image\n" > >@@ -8386,6 +8390,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 +8495,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 }, > > I don't like the idea of aliasing these options. Please just stick with > one set of options. > > And do we really need to have options for this? Can't we just do the > right thing? I can't believe that every application has to have an ipv6 > switch to be ipv6 enabled. Gerd's patch does 'do the right thing' for 90% of people - it uses the AI_ADDRCONFIG flag. This means that the getaddrinfo() name lookup will only return an IPv6 address if there is at least one NIC with IPv6 configured, likewise only return an IPv4 address if there is at least one NIC with IPv4 configured. There are still times when it is desirable to restrict it to just IPv4 or just IPv6, regardless of your host NIC config - mostly when needing to interact with other broken apps which are not correctly IPv6 aware. Maybe it would be sufficient to just have it added as a flag to the arg in question though, eg -serial tcp:localhost:123,ipv4 rather than a global -ipv4 flag 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] 25+ messages in thread
* Re: [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu. 2008-10-31 17:50 ` Daniel P. Berrange @ 2008-10-31 17:58 ` Anthony Liguori 2008-10-31 19:44 ` Jamie Lokier 0 siblings, 1 reply; 25+ messages in thread From: Anthony Liguori @ 2008-10-31 17:58 UTC (permalink / raw) To: Daniel P. Berrange, qemu-devel; +Cc: Gerd Hoffmann Daniel P. Berrange wrote: > On Fri, Oct 31, 2008 at 12:37:16PM -0500, Anthony Liguori wrote: > > Gerd's patch does 'do the right thing' for 90% of people - it uses the > AI_ADDRCONFIG flag. This means that the getaddrinfo() name lookup will > only return an IPv6 address if there is at least one NIC with IPv6 > configured, likewise only return an IPv4 address if there is at least > one NIC with IPv4 configured. There are still times when it is desirable > to restrict it to just IPv4 or just IPv6, regardless of your host NIC > config - mostly when needing to interact with other broken apps which are > not correctly IPv6 aware. Maybe it would be sufficient to just have it added > as a flag to the arg in question though, eg -serial tcp:localhost:123,ipv4 > rather than a global -ipv4 flag > Yes, this would be much nicer. I think having the options as a global is likely to confuse users. Regards, Anthony Liguori > Daniel > ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu. 2008-10-31 17:58 ` Anthony Liguori @ 2008-10-31 19:44 ` Jamie Lokier 0 siblings, 0 replies; 25+ messages in thread From: Jamie Lokier @ 2008-10-31 19:44 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann Anthony Liguori wrote: > >Maybe it would be sufficient to just have it added as a flag to the > >arg in question though, eg -serial tcp:localhost:123,ipv4 rather > >than a global -ipv4 flag > > > > Yes, this would be much nicer. I think having the options as a global > is likely to confuse users. Yes. In those few cases where you need to restrict it, a global option would be wrong too: if you have multiple interfaces, and you need to override the automatic default for some reason, there's a fair chance you don't need that on every interface. -- Jamie ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu. 2008-10-31 17:37 ` Anthony Liguori 2008-10-31 17:50 ` Daniel P. Berrange @ 2008-11-03 15:35 ` Gerd Hoffmann 1 sibling, 0 replies; 25+ messages in thread From: Gerd Hoffmann @ 2008-11-03 15:35 UTC (permalink / raw) To: Anthony Liguori; +Cc: qemu-devel Anthony Liguori wrote: > I like this patch, but we already have a qemu_socket.h. Please remove > qemu_socket.h if you're going to introduce qemu-sockets.h. Will fix. >> + >> +listen: >> + if (0 != listen(slisten,1)) { > > Please try to avoid this style of if(). Yea, old habit from the days where gcc didn't warn on "if (a = -1)". Pointless these days. Trying to get rid of it ... >> + { "ipv4", 0, QEMU_OPTION_ipv4 }, >> + { "ipv6", 0, QEMU_OPTION_ipv6 }, > > I don't like the idea of aliasing these options. Please just stick with > one set of options. > And do we really need to have options for this? Yes, we do, unfortunaly. > Can't we just do the > right thing? I can't believe that every application has to have an ipv6 > switch to be ipv6 enabled. 98% of the users should never ever need that. Unfortunaly there are always corner cases where you can't get it right automatically. You can easily check the ipv6 setup on the local machine, but you still don't know how the network is setup and whenever reaching machine $foo via ipv6 actually works. Of course you can just try and in case it doesn't work fallback to ipv4. Which is what the code does btw. But that involves a noticeable delay, waiting for the ipv6 connect attempt time out. Will make that a per-connection option as discussed further down this thread. Respin of the patches will follow later today or tomorrow. cheers, Gerd ^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2008-11-03 15:36 UTC | newest] Thread overview: 25+ 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 2/4] sockets: helper functions for qemu Gerd Hoffmann 2008-10-31 17:37 ` Anthony Liguori 2008-10-31 17:50 ` Daniel P. Berrange 2008-10-31 17:58 ` Anthony Liguori 2008-10-31 19:44 ` Jamie Lokier 2008-11-03 15:35 ` 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).