All of lore.kernel.org
 help / color / mirror / Atom feed
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

  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.