[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v2 for-2.10 1/8] chardev: Basic support for TN32
From: |
Cornelia Huck |
Subject: |
Re: [Qemu-devel] [PATCH v2 for-2.10 1/8] chardev: Basic support for TN3270 |
Date: |
Mon, 24 Apr 2017 12:38:50 +0200 |
On Fri, 7 Apr 2017 13:18:44 +0200
Cornelia Huck <address@hidden> wrote:
> From: Jing Liu <address@hidden>
>
> This introduces basic support for TN3270, which needs to negotiate
> three Telnet options during handshake:
> - End of Record
> - Binary Transmission
> - Terminal-Type
>
> As a basic implementation, this simply ignores NOP and Interrupt
> Process(IP) commands. More work should be done for them later.
>
> For more details, please refer to RFC 854 and 1576.
>
> Signed-off-by: Jing Liu <address@hidden>
> Signed-off-by: Yang Chen <address@hidden>
> Reviewed-by: QingFeng Hao <address@hidden>
> Acked-by: Dong Jia Shi <address@hidden>
> Signed-off-by: Cornelia Huck <address@hidden>
> ---
> chardev/char-socket.c | 76
> +++++++++++++++++++++++++++++++++++++--------------
> chardev/char.c | 11 ++++++--
> include/sysemu/char.h | 8 ++++++
> qapi-schema.json | 3 ++
> 4 files changed, 76 insertions(+), 22 deletions(-)
ping for some acks for the telnet changes
>
> diff --git a/chardev/char-socket.c b/chardev/char-socket.c
> index 36ab0d633a..175fb8c3ec 100644
> --- a/chardev/char-socket.c
> +++ b/chardev/char-socket.c
> @@ -55,6 +55,7 @@ typedef struct {
> SocketAddress *addr;
> bool is_listen;
> bool is_telnet;
> + bool is_tn3270;
>
> guint reconnect_timer;
> int64_t reconnect_time;
> @@ -141,19 +142,25 @@ static int tcp_chr_read_poll(void *opaque)
> return s->max_size;
> }
>
> -#define IAC 255
> -#define IAC_BREAK 243
> static void tcp_chr_process_IAC_bytes(Chardev *chr,
> SocketChardev *s,
> uint8_t *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.
> + /* Handle any telnet or tn3270 client's basic IAC options.
> + * For telnet options, it satisfies char by char mode with no echo.
> + * For tn3270 options, it satisfies binary mode with EOR.
> + * All IAC options will be removed from the buf and the do_opt
> + * pointer 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.
> + * RFC854: "All TELNET commands consist of at least a two byte sequence.
> + * The commands dealing with option negotiation are three byte sequences,
> + * the third byte being the code for the option referenced."
> + * "IAC BREAK", "IAC IP", "IAC NOP" and the double IAC are two bytes.
> + * "IAC SB", "IAC SE" and "IAC EOR" are saved to split up data boundary
> + * for tn3270.
> + * NOP, Break and Interrupt Process(IP) might be encountered during a
> TN3270
> + * session, and NOP and IP need to be done later.
> */
>
> int i;
> @@ -174,6 +181,18 @@ static void tcp_chr_process_IAC_bytes(Chardev *chr,
> /* Handle IAC break commands by sending a serial break */
> qemu_chr_be_event(chr, CHR_EVENT_BREAK);
> s->do_telnetopt++;
> + } else if (s->is_tn3270 && ((unsigned char)buf[i] == IAC_EOR
> + || (unsigned char)buf[i] == IAC_SB
> + || (unsigned char)buf[i] == IAC_SE)
> + && s->do_telnetopt == 2) {
> + buf[j++] = IAC;
> + buf[j++] = buf[i];
> + s->do_telnetopt++;
> + } else if (s->is_tn3270 && ((unsigned char)buf[i] == IAC_IP
> + || (unsigned char)buf[i] == IAC_NOP)
> + && s->do_telnetopt == 2) {
> + /* TODO: IP and NOP need to be implemented later. */
> + s->do_telnetopt++;
> }
> s->do_telnetopt++;
> }
> @@ -512,7 +531,7 @@ static void tcp_chr_update_read_handler(Chardev *chr,
>
> typedef struct {
> Chardev *chr;
> - char buf[12];
> + char buf[21];
> size_t buflen;
> } TCPChardevTelnetInit;
>
> @@ -550,9 +569,6 @@ static void tcp_chr_telnet_init(Chardev *chr)
> TCPChardevTelnetInit *init = g_new0(TCPChardevTelnetInit, 1);
> size_t n = 0;
>
> - init->chr = chr;
> - init->buflen = 12;
> -
> #define IACSET(x, a, b, c) \
> do { \
> x[n++] = a; \
> @@ -560,12 +576,26 @@ static void tcp_chr_telnet_init(Chardev *chr)
> 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 */
> + init->chr = chr;
> + if (!s->is_tn3270) {
> + init->buflen = 12;
> + /* 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 */
> + } else {
> + init->buflen = 21;
> + /* Prep the TN3270 negotion based on RFC1576 */
> + IACSET(init->buf, 0xff, 0xfd, 0x19); /* IAC DO EOR */
> + IACSET(init->buf, 0xff, 0xfb, 0x19); /* IAC WILL EOR */
> + IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO BINARY */
> + IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL BINARY */
> + IACSET(init->buf, 0xff, 0xfd, 0x18); /* IAC DO TERMINAL TYPE */
> + IACSET(init->buf, 0xff, 0xfa, 0x18); /* IAC SB TERMINAL TYPE */
> + IACSET(init->buf, 0x01, 0xff, 0xf0); /* SEND IAC SE */
> + }
>
> #undef IACSET
>
> @@ -585,7 +615,8 @@ static void tcp_chr_tls_handshake(QIOTask *task,
> if (qio_task_propagate_error(task, NULL)) {
> tcp_chr_disconnect(chr);
> } else {
> - if (s->do_telnetopt) {
> + /* tn3270 does not support TLS yet */
> + if (s->do_telnetopt && !s->is_tn3270) {
> tcp_chr_telnet_init(chr);
> } else {
> tcp_chr_connect(chr);
> @@ -824,12 +855,14 @@ static void qmp_chardev_open_socket(Chardev *chr,
> bool do_nodelay = sock->has_nodelay ? sock->nodelay : false;
> bool is_listen = sock->has_server ? sock->server : true;
> bool is_telnet = sock->has_telnet ? sock->telnet : false;
> + bool is_tn3270 = sock->has_tn3270 ? sock->tn3270 : false;
> bool is_waitconnect = sock->has_wait ? sock->wait : false;
> int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
> QIOChannelSocket *sioc = NULL;
>
> s->is_listen = is_listen;
> s->is_telnet = is_telnet;
> + s->is_tn3270 = is_tn3270;
> s->do_nodelay = do_nodelay;
> if (sock->tls_creds) {
> Object *creds;
> @@ -879,7 +912,7 @@ static void qmp_chardev_open_socket(Chardev *chr,
> addr, is_listen, is_telnet);
>
> if (is_listen) {
> - if (is_telnet) {
> + if (is_telnet || is_tn3270) {
> s->do_telnetopt = 1;
> }
> } else if (reconnect > 0) {
> @@ -933,6 +966,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts,
> ChardevBackend *backend,
> bool is_listen = qemu_opt_get_bool(opts, "server", false);
> bool is_waitconnect = is_listen && qemu_opt_get_bool(opts, "wait", true);
> bool is_telnet = qemu_opt_get_bool(opts, "telnet", false);
> + bool is_tn3270 = qemu_opt_get_bool(opts, "tn3270", false);
> bool do_nodelay = !qemu_opt_get_bool(opts, "delay", true);
> int64_t reconnect = qemu_opt_get_number(opts, "reconnect", 0);
> const char *path = qemu_opt_get(opts, "path");
> @@ -968,6 +1002,8 @@ static void qemu_chr_parse_socket(QemuOpts *opts,
> ChardevBackend *backend,
> sock->server = is_listen;
> sock->has_telnet = true;
> sock->telnet = is_telnet;
> + sock->has_tn3270 = true;
> + sock->tn3270 = is_tn3270;
> sock->has_wait = true;
> sock->wait = is_waitconnect;
> sock->has_reconnect = true;
> diff --git a/chardev/char.c b/chardev/char.c
> index 3df116350b..309734f2b7 100644
> --- a/chardev/char.c
> +++ b/chardev/char.c
> @@ -696,7 +696,8 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const
> char *filename)
> return opts;
> }
> if (strstart(filename, "tcp:", &p) ||
> - strstart(filename, "telnet:", &p)) {
> + strstart(filename, "telnet:", &p) ||
> + strstart(filename, "tn3270:", &p)) {
> if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
> host[0] = 0;
> if (sscanf(p, ":%32[^,]%n", port, &pos) < 1)
> @@ -712,8 +713,11 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const
> char *filename)
> goto fail;
> }
> }
> - if (strstart(filename, "telnet:", &p))
> + if (strstart(filename, "telnet:", &p)) {
> qemu_opt_set(opts, "telnet", "on", &error_abort);
> + } else if (strstart(filename, "tn3270:", &p)) {
> + qemu_opt_set(opts, "tn3270", "on", &error_abort);
> + }
> return opts;
> }
> if (strstart(filename, "udp:", &p)) {
> @@ -1177,6 +1181,9 @@ QemuOptsList qemu_chardev_opts = {
> .name = "telnet",
> .type = QEMU_OPT_BOOL,
> },{
> + .name = "tn3270",
> + .type = QEMU_OPT_BOOL,
> + },{
> .name = "tls-creds",
> .type = QEMU_OPT_STRING,
> },{
> diff --git a/include/sysemu/char.h b/include/sysemu/char.h
> index 450881d42c..f6d5cd0c9b 100644
> --- a/include/sysemu/char.h
> +++ b/include/sysemu/char.h
> @@ -7,6 +7,14 @@
> #include "qemu/bitmap.h"
> #include "qom/object.h"
>
> +#define IAC_EOR 239
> +#define IAC_SE 240
> +#define IAC_NOP 241
> +#define IAC_BREAK 243
> +#define IAC_IP 244
> +#define IAC_SB 250
> +#define IAC 255
> +
> /* character device */
>
> typedef enum {
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 250e4dc49b..f0302958ce 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -4874,6 +4874,8 @@
> # @nodelay: set TCP_NODELAY socket option (default: false)
> # @telnet: enable telnet protocol on server
> # sockets (default: false)
> +# @tn3270: enable tn3270 protocol on server
> +# sockets (default: false) (Since: 2.10)
> # @reconnect: For a client socket, if a socket is disconnected,
> # then attempt a reconnect after the given number of seconds.
> # Setting this to zero disables this function. (default: 0)
> @@ -4887,6 +4889,7 @@
> '*wait' : 'bool',
> '*nodelay' : 'bool',
> '*telnet' : 'bool',
> + '*tn3270' : 'bool',
> '*reconnect' : 'int' },
> 'base': 'ChardevCommon' }
>
- [Qemu-devel] [PATCH v2 for-2.10 0/8] s390x: Basic support for 3270 devices, Cornelia Huck, 2017/04/07
- [Qemu-devel] [PATCH v2 for-2.10 1/8] chardev: Basic support for TN3270, Cornelia Huck, 2017/04/07
- [Qemu-devel] [PATCH v2 for-2.10 4/8] s390x/3270: Add emulated terminal3270 device, Cornelia Huck, 2017/04/07
- [Qemu-devel] [PATCH v2 for-2.10 3/8] s390x/3270: Add abstract emulated ccw-attached 3270 device, Cornelia Huck, 2017/04/07
- [Qemu-devel] [PATCH v2 for-2.10 5/8] s390x/3270: 3270 data stream handling, Cornelia Huck, 2017/04/07
- [Qemu-devel] [PATCH v2 for-2.10 6/8] s390x/3270: Add the TCP socket events handler for 3270, Cornelia Huck, 2017/04/07
- [Qemu-devel] [PATCH v2 for-2.10 7/8] s390x/3270: Detect for continued presence of a 3270 client, Cornelia Huck, 2017/04/07
- [Qemu-devel] [PATCH v2 for-2.10 8/8] s390x/3270: Mark non-migratable and enable the device, Cornelia Huck, 2017/04/07
- [Qemu-devel] [PATCH v2 for-2.10 2/8] s390x/css: Add an algorithm to find a free chpid, Cornelia Huck, 2017/04/07