From: "Daniel P. Berrange" <berrange@redhat.com>
To: qemu-devel@nongnu.org
Cc: Paolo Bonzini <pbonzini@redhat.com>
Subject: [Qemu-devel] [PATCH v4 3/4] char: don't assume telnet initialization will not block
Date: Tue, 19 Jan 2016 11:14:30 +0000 [thread overview]
Message-ID: <1453202071-10289-4-git-send-email-berrange@redhat.com> (raw)
In-Reply-To: <1453202071-10289-1-git-send-email-berrange@redhat.com>
The current code for doing telnet initialization is writing to
a socket without checking the return status. While it is highly
unlikely to be a problem when writing to a bare socket, as the
buffers are large enough to prevent blocking, this cannot be
assumed safe with TLS sockets. So write the telnet initialization
code into a memory buffer and then use an I/O watch to fully
send the data.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
qemu-char.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 69 insertions(+), 18 deletions(-)
diff --git a/qemu-char.c b/qemu-char.c
index 8e9156a..f0cea8a 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2877,19 +2877,70 @@ static void tcp_chr_update_read_handler(CharDriverState *chr)
}
}
-#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
-static void tcp_chr_telnet_init(QIOChannel *ioc)
+typedef struct {
+ CharDriverState *chr;
+ char buf[12];
+ size_t buflen;
+} TCPCharDriverTelnetInit;
+
+static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
+ GIOCondition cond G_GNUC_UNUSED,
+ gpointer user_data)
+{
+ TCPCharDriverTelnetInit *init = user_data;
+ ssize_t ret;
+
+ ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
+ if (ret < 0) {
+ if (ret == QIO_CHANNEL_ERR_BLOCK) {
+ ret = 0;
+ } else {
+ tcp_chr_disconnect(init->chr);
+ return FALSE;
+ }
+ }
+ init->buflen -= ret;
+
+ if (init->buflen == 0) {
+ tcp_chr_connect(init->chr);
+ return FALSE;
+ }
+
+ memmove(init->buf, init->buf + ret, init->buflen);
+
+ return TRUE;
+}
+
+static void tcp_chr_telnet_init(CharDriverState *chr)
{
- char buf[3];
- /* Send the telnet negotion to put telnet in binary, no echo, single char mode */
- IACSET(buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */
- qio_channel_write(ioc, buf, 3, NULL);
- IACSET(buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
- qio_channel_write(ioc, buf, 3, NULL);
- IACSET(buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */
- qio_channel_write(ioc, buf, 3, NULL);
- IACSET(buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */
- qio_channel_write(ioc, buf, 3, NULL);
+ TCPCharDriver *s = chr->opaque;
+ TCPCharDriverTelnetInit *init =
+ g_new0(TCPCharDriverTelnetInit, 1);
+ size_t n = 0;
+
+ init->chr = chr;
+ init->buflen = 12;
+
+#define IACSET(x, a, b, c) \
+ do { \
+ x[n++] = a; \
+ x[n++] = b; \
+ x[n++] = c; \
+ } while (0)
+
+ /* Prep the telnet negotion to put telnet in binary,
+ * no echo, single char mode */
+ IACSET(init->buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */
+ IACSET(init->buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
+ IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */
+ IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */
+
+#undef IACSET
+
+ qio_channel_add_watch(
+ s->ioc, G_IO_OUT,
+ tcp_chr_telnet_init_io,
+ init, NULL);
}
static int tcp_chr_new_client(CharDriverState *chr, QIOChannelSocket *sioc)
@@ -2909,7 +2960,12 @@ static int tcp_chr_new_client(CharDriverState *chr, QIOChannelSocket *sioc)
g_source_remove(s->listen_tag);
s->listen_tag = 0;
}
- tcp_chr_connect(chr);
+
+ if (s->do_telnetopt) {
+ tcp_chr_telnet_init(chr);
+ } else {
+ tcp_chr_connect(chr);
+ }
return 0;
}
@@ -2935,7 +2991,6 @@ static gboolean tcp_chr_accept(QIOChannel *channel,
void *opaque)
{
CharDriverState *chr = opaque;
- TCPCharDriver *s = chr->opaque;
QIOChannelSocket *sioc;
sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(channel),
@@ -2944,10 +2999,6 @@ static gboolean tcp_chr_accept(QIOChannel *channel,
return TRUE;
}
- if (s->do_telnetopt) {
- tcp_chr_telnet_init(QIO_CHANNEL(sioc));
- }
-
tcp_chr_new_client(chr, sioc);
object_unref(OBJECT(sioc));
--
2.5.0
next prev parent reply other threads:[~2016-01-19 11:14 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-01-19 11:14 [Qemu-devel] [PATCH v4 0/4] Convert chardevs to QIOChannel & add TLS support Daniel P. Berrange
2016-01-19 11:14 ` [Qemu-devel] [PATCH v4 1/4] char: remove fixed length filename allocation Daniel P. Berrange
2016-01-19 11:14 ` [Qemu-devel] [PATCH v4 2/4] char: convert from GIOChannel to QIOChannel Daniel P. Berrange
2016-03-18 16:43 ` Laurent Vivier
2016-03-18 16:56 ` Daniel P. Berrange
2016-03-18 17:10 ` Laurent Vivier
2016-01-19 11:14 ` Daniel P. Berrange [this message]
2016-01-19 11:14 ` [Qemu-devel] [PATCH v4 4/4] char: introduce support for TLS encrypted TCP chardev backend Daniel P. Berrange
2016-01-19 13:14 ` [Qemu-devel] [PATCH v4 0/4] Convert chardevs to QIOChannel & add TLS support Paolo Bonzini
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=1453202071-10289-4-git-send-email-berrange@redhat.com \
--to=berrange@redhat.com \
--cc=pbonzini@redhat.com \
--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.