[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] qemu vl.c qemu-doc.texi
From: |
Jason Wessel |
Subject: |
Re: [Qemu-devel] qemu vl.c qemu-doc.texi |
Date: |
Mon, 26 Jun 2006 09:27:42 -0500 |
User-agent: |
Thunderbird 1.5.0.2 (Windows/20060308) |
Hi Fabrice,
We ought to collaborate more about the intent to code something. I had
already implemented the TCP net console as well. Since the code was
similar I patched in the difference in functionality from my code into
yours as well as further changing the docs.
I fixed a small defect in the TCP net console where it did not accept
only a port for the "tcpl" option. I added the following features with
the attached patch which I had been using in my TCP net console version.
wtcpl - Wait infinitely for the first connection so that you can get
the console from the very start
telnet - This allows you to fully make use of telnet in "char by char"
mode. It also supports sending the telnet break which translates to
sending a serial break just like you would do if you used a terminal
server. This is frequently used to activate MAGIC_SYSRQ support in a
kernel.
wtelnet - Same as telnet, but wait infinitely for the first connect.
The reason for having a separate tcpl vs telnet is to separate out the
IAC option negotiation because it can mess up clients that are not
expecting it.
Question:
If I resubmit the -mserial option would it stand a chance of being
accepted?
Please let me know if there is some change you might like to get that
patch accepted as well. I will re-create the patch against the current
CVS anyway because I still need the functionality of having the monitor
and serial port redirected to the same remote socket.
Thanks,
Jason.
Fabrice Bellard wrote:
CVSROOT: /sources/qemu
Module name: qemu
Changes by: Fabrice Bellard <bellard> 06/06/25 14:49:44
Modified files:
. : vl.c qemu-doc.texi
Log message:
UDP char device (initial patch by Jason Wessel) - TCP char device
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/qemu/vl.c?cvsroot=qemu&r1=1.190&r2=1.191
http://cvs.savannah.gnu.org/viewcvs/qemu/qemu-doc.texi?cvsroot=qemu&r1=1.96&r2=1.97
_______________________________________________
Qemu-devel mailing list
address@hidden
http://lists.nongnu.org/mailman/listinfo/qemu-devel
Index: qemu/vl.c
===================================================================
--- qemu.orig/vl.c
+++ qemu/vl.c
@@ -2312,6 +2312,7 @@ typedef struct {
int fd, listen_fd;
int connected;
int max_size;
+ int do_telnetopt;
} TCPCharDriver;
static void tcp_chr_accept(void *opaque);
@@ -2337,6 +2338,56 @@ static int tcp_chr_read_poll(void *opaqu
return s->max_size;
}
+#define IAC 255
+#define IAC_BREAK 243
+static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
+ TCPCharDriver *s,
+ char *buf, int *size)
+{
+ /* Handle any telnet client's basic IAC options to satisfy char by
+ * char mode with no echo. All IAC options will be removed from
+ * the buf and the do_telnetopt variable will be used to track the
+ * state of the width of the IAC information.
+ *
+ * IAC commands come in sets of 3 bytes with the exception of the
+ * "IAC BREAK" command and the double IAC.
+ */
+
+ int i;
+ int j = 0;
+
+ for (i = 0; i < *size; i++) {
+ if (s->do_telnetopt > 1) {
+ if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
+ /* Double IAC means send an IAC */
+ if (j != i)
+ buf[j] = buf[i];
+ j++;
+ s->do_telnetopt = 1;
+ } else {
+ if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt ==
2) {
+ /* Handle IAC break commands by sending a serial break */
+ chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK);
+ s->do_telnetopt++;
+ }
+ s->do_telnetopt++;
+ }
+ if (s->do_telnetopt >= 4) {
+ s->do_telnetopt = 1;
+ }
+ } else {
+ if ((unsigned char)buf[i] == IAC) {
+ s->do_telnetopt = 2;
+ } else {
+ if (j != i)
+ buf[j] = buf[i];
+ j++;
+ }
+ }
+ }
+ *size = j;
+}
+
static void tcp_chr_read(void *opaque)
{
CharDriverState *chr = opaque;
@@ -2360,7 +2411,10 @@ static void tcp_chr_read(void *opaque)
closesocket(s->fd);
s->fd = -1;
} else if (size > 0) {
- s->fd_read(s->fd_opaque, buf, size);
+ if (s->do_telnetopt)
+ tcp_chr_process_IAC_bytes(chr, s, buf, &size);
+ if (size > 0)
+ s->fd_read(s->fd_opaque, buf, size);
}
}
@@ -2385,6 +2439,20 @@ static void tcp_chr_connect(void *opaque
tcp_chr_read, NULL, chr);
}
+static void tcp_chr_telnet_init(int fd)
+{
+ char buf[3];
+ /* Send the telnet negotion to put telnet in binary, no echo, single char
mode */
+ sprintf(buf,"%c%c%c",0xff, 0xfb, 0x01); /* IAC WILL ECHO */
+ send(fd, (char *)buf, 3, 0);
+ sprintf(buf,"%c%c%c",0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
+ send(fd, (char *)buf, 3, 0);
+ sprintf(buf,"%c%c%c",0xff, 0xfb, 0x00); /* IAC WILL Binary */
+ send(fd, (char *)buf, 3, 0);
+ sprintf(buf,"%c%c%c",0xff, 0xfd, 0x00); /* IAC DO Binary */
+ send(fd, (char *)buf, 3, 0);
+}
+
static void tcp_chr_accept(void *opaque)
{
CharDriverState *chr = opaque;
@@ -2399,6 +2467,8 @@ static void tcp_chr_accept(void *opaque)
if (fd < 0 && errno != EINTR) {
return;
} else if (fd >= 0) {
+ if (s->do_telnetopt)
+ tcp_chr_telnet_init(fd);
break;
}
}
@@ -2419,15 +2489,30 @@ static void tcp_chr_close(CharDriverStat
}
static CharDriverState *qemu_chr_open_tcp(const char *host_str,
- int is_listen)
+ int is_listen,
+ int is_waitconnect)
{
CharDriverState *chr = NULL;
TCPCharDriver *s = NULL;
int fd = -1, ret, err, val;
struct sockaddr_in saddr;
- if (parse_host_port(&saddr, host_str) < 0)
- goto fail;
+ if (parse_host_port(&saddr, host_str) < 0) {
+ if (!strchr(host_str, ':')) {
+ unsigned long port;
+ char *r;
+ port = strtol(host_str, (char **)&r, 0);
+ if (r == host_str) {
+ fprintf(stderr, "Error parsing port number\n");
+ goto fail;
+ }
+
+ memset(&saddr,0,sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = htons((short)port);
+ } else
+ goto fail;
+ }
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
@@ -2439,7 +2524,8 @@ static CharDriverState *qemu_chr_open_tc
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0)
goto fail;
- socket_set_nonblock(fd);
+ if (!is_waitconnect)
+ socket_set_nonblock(fd);
s->connected = 0;
s->fd = -1;
@@ -2457,6 +2543,8 @@ static CharDriverState *qemu_chr_open_tc
goto fail;
s->listen_fd = fd;
qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+ /* If is_listen > 1 then turn on telnet option negotiation */
+ s->do_telnetopt = 1;
} else {
for(;;) {
ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
@@ -2484,6 +2572,12 @@ static CharDriverState *qemu_chr_open_tc
chr->chr_write = tcp_chr_write;
chr->chr_add_read_handler = tcp_chr_add_read_handler;
chr->chr_close = tcp_chr_close;
+ if (is_waitconnect) {
+ printf("QEMU waiting for connection on: %s\n", host_str);
+ tcp_chr_accept(chr);
+ socket_set_nonblock(s->listen_fd);
+ }
+
return chr;
fail:
if (fd >= 0)
@@ -2503,10 +2597,19 @@ CharDriverState *qemu_chr_open(const cha
return qemu_chr_open_null();
} else
if (strstart(filename, "tcp:", &p)) {
- return qemu_chr_open_tcp(p, 0);
+ return qemu_chr_open_tcp(p, 0, 0);
} else
if (strstart(filename, "tcpl:", &p)) {
- return qemu_chr_open_tcp(p, 1);
+ return qemu_chr_open_tcp(p, 1, 0);
+ } else
+ if (strstart(filename, "wtcpl:", &p)) {
+ return qemu_chr_open_tcp(p, 1, 1);
+ } else
+ if (strstart(filename, "telnet:", &p)) {
+ return qemu_chr_open_tcp(p, 2, 0);
+ } else
+ if (strstart(filename, "wtelnet:", &p)) {
+ return qemu_chr_open_tcp(p, 2, 1);
} else
if (strstart(filename, "udp:", &p)) {
return qemu_chr_open_udp(p);
Index: qemu/qemu-doc.texi
===================================================================
--- qemu.orig/qemu-doc.texi
+++ qemu/qemu-doc.texi
@@ -562,6 +562,21 @@ TCP Net Console: wait for connection on
@var{port}. If host is omitted, 0.0.0.0 is assumed. Only one TCP
connection at a time is accepted. You can use @code{telnet} to connect
to the corresponding character device.
address@hidden wtcpl:host:port
+TCP Net Console: Same as "tcpl", but pause QEMU infinitely waiting for
+the first connection
+
address@hidden telnet:host:port
+TCP Net Console: Use telnet option negotiation to put telnet into
+character mode. This will also allow you to send the MAGIC_SYSRQ
+sequence if you use a telnet that supports sending the break sequence.
+Typically in unix telnet you do it with Control-] and then type "send
+break" followed by pressing the enter key.
address@hidden wtelnet:host:port
+TCP Net Console: Same as "telnet", but pause QEMU infinitely waiting for
+the first connection
+
+
@end table
@item -parallel dev