From: Jason Wessel <jason.wessel@windriver.com>
To: qemu-devel@nongnu.org, fabrice@bellard.org
Subject: Re: [Qemu-devel] qemu vl.c qemu-doc.texi
Date: Mon, 26 Jun 2006 09:27:42 -0500 [thread overview]
Message-ID: <449FEEDE.8070503@windriver.com> (raw)
In-Reply-To: <E1FuVvk-0005mC-Of@savannah.gnu.org>
[-- Attachment #1: Type: text/plain, Size: 2109 bytes --]
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
> Qemu-devel@nongnu.org
> http://lists.nongnu.org/mailman/listinfo/qemu-devel
>
[-- Attachment #2: telnet_IAC_options.patch --]
[-- Type: text/plain, Size: 7573 bytes --]
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.
+@item wtcpl:host:port
+TCP Net Console: Same as "tcpl", but pause QEMU infinitely waiting for
+the first connection
+
+@item 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.
+@item wtelnet:host:port
+TCP Net Console: Same as "telnet", but pause QEMU infinitely waiting for
+the first connection
+
+
@end table
@item -parallel dev
next prev parent reply other threads:[~2006-06-26 14:28 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-06-25 14:49 [Qemu-devel] qemu vl.c qemu-doc.texi Fabrice Bellard
2006-06-26 14:27 ` Jason Wessel [this message]
-- strict thread matches above, loose matches on Subject: below --
2006-06-27 21:02 Fabrice Bellard
2006-09-03 14:10 Fabrice Bellard
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=449FEEDE.8070503@windriver.com \
--to=jason.wessel@windriver.com \
--cc=fabrice@bellard.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.