* [Qemu-devel] [PATCH 1/4] Implement "info chardev" command.
2008-10-31 12:47 [Qemu-devel] [PATCH v2 0/4] ipv6 and autoport patches Gerd Hoffmann
@ 2008-10-31 12:47 ` Gerd Hoffmann
2008-10-31 17:32 ` Anthony Liguori
2008-10-31 12:47 ` [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu Gerd Hoffmann
` (2 subsequent siblings)
3 siblings, 1 reply; 18+ messages in thread
From: Gerd Hoffmann @ 2008-10-31 12:47 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 0278101..a9fae17 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 */
@@ -9719,7 +9747,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);
@@ -9730,7 +9758,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);
@@ -9744,7 +9774,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] 18+ messages in thread
* Re: [Qemu-devel] [PATCH 1/4] Implement "info chardev" command.
2008-10-31 12:47 ` [Qemu-devel] [PATCH 1/4] Implement "info chardev" command Gerd Hoffmann
@ 2008-10-31 17:32 ` Anthony Liguori
0 siblings, 0 replies; 18+ messages in thread
From: Anthony Liguori @ 2008-10-31 17:32 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
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
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
>
Applied. Thanks.
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu.
2008-10-31 12:47 [Qemu-devel] [PATCH v2 0/4] ipv6 and autoport patches Gerd Hoffmann
2008-10-31 12:47 ` [Qemu-devel] [PATCH 1/4] Implement "info chardev" command Gerd Hoffmann
@ 2008-10-31 12:47 ` Gerd Hoffmann
2008-10-31 17:37 ` Anthony Liguori
2008-10-31 12:47 ` [Qemu-devel] [PATCH 3/4] sockets: switch vnc to new code, support vnc port auto-allocation 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
3 siblings, 1 reply; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ messages in thread
* [Qemu-devel] [PATCH 3/4] sockets: switch vnc to new code, support vnc port auto-allocation.
2008-10-31 12:47 [Qemu-devel] [PATCH v2 0/4] ipv6 and autoport patches Gerd Hoffmann
2008-10-31 12:47 ` [Qemu-devel] [PATCH 1/4] Implement "info chardev" command Gerd Hoffmann
2008-10-31 12:47 ` [Qemu-devel] [PATCH 2/4] sockets: helper functions for qemu Gerd Hoffmann
@ 2008-10-31 12:47 ` 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
3 siblings, 0 replies; 18+ messages in thread
From: Gerd Hoffmann @ 2008-10-31 12:47 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>
---
vl.c | 1 +
vnc.c | 114 +++++++++++++++-------------------------------------------------
2 files changed, 28 insertions(+), 87 deletions(-)
diff --git a/vl.c b/vl.c
index e9fe478..e4648f9 100644
--- a/vl.c
+++ b/vl.c
@@ -8284,6 +8284,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"
"\n"
"Linux boot specific:\n"
"-kernel bzImage use 'bzImage' as kernel image\n"
diff --git a/vnc.c b/vnc.c
index 9df4dbe..9aeaaa0 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,18 +2290,11 @@ int vnc_display_password(DisplayState *ds, const char *password)
int vnc_display_open(DisplayState *ds, const char *display)
{
- struct sockaddr *addr;
- struct sockaddr_in iaddr;
-#ifndef _WIN32
- struct sockaddr_un uaddr;
- const char *p;
-#endif
- int reuse_addr, ret;
- socklen_t addrlen;
VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
const char *options;
int password = 0;
int reverse = 0;
+ int to_port = 0;
#ifdef CONFIG_VNC_TLS
int tls = 0, x509 = 0;
#endif
@@ -2321,6 +2313,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 +2392,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 +2407,25 @@ int vnc_display_open(DisplayState *ds, const char *display)
vs->csock = vs->lsock;
vs->lsock = -1;
vnc_connect(vs);
- return 0;
}
- }
-
- if (bind(vs->lsock, addr, addrlen) == -1) {
- fprintf(stderr, "bind() failed\n");
- close(vs->lsock);
- vs->lsock = -1;
- free(vs->display);
- vs->display = NULL;
- return -1;
- }
+ return 0;
- if (listen(vs->lsock, 1) == -1) {
- fprintf(stderr, "listen() failed\n");
- close(vs->lsock);
- vs->lsock = -1;
- free(vs->display);
- vs->display = NULL;
- return -1;
+ } else {
+ /* listen for connects */
+ char *dpy;
+ dpy = qemu_malloc(256);
+ if (strncmp(display, "unix:", 5) == 0) {
+ strcpy(dpy, "unix:");
+ vs->lsock = unix_listen(display, dpy+5, 256-5);
+ } else {
+ vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
+ }
+ if (-1 == vs->lsock) {
+ free(dpy);
+ } else {
+ free(vs->display);
+ vs->display = dpy;
+ }
}
return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);
--
1.5.6.5
^ permalink raw reply related [flat|nested] 18+ 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 0/4] ipv6 and autoport patches Gerd Hoffmann
` (2 preceding siblings ...)
2008-10-31 12:47 ` [Qemu-devel] [PATCH 3/4] sockets: switch vnc to new code, support vnc port auto-allocation Gerd Hoffmann
@ 2008-10-31 12:47 ` Gerd Hoffmann
3 siblings, 0 replies; 18+ 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] 18+ 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
0 siblings, 2 replies; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ messages in thread