diff options
-rw-r--r-- | hw/char/terminal3270.c | 37 |
1 files changed, 32 insertions, 5 deletions
diff --git a/hw/char/terminal3270.c b/hw/char/terminal3270.c index 450608e3c3..58bcc4be15 100644 --- a/hw/char/terminal3270.c +++ b/hw/char/terminal3270.c @@ -32,6 +32,7 @@ typedef struct Terminal3270 { int in_len; int out_len; bool handshake_done; + guint timer_tag; } Terminal3270; #define TYPE_TERMINAL_3270 "x-terminal3270" @@ -60,6 +61,19 @@ static void TN3270_handshake_done(Terminal3270 *t) } /* + * Called when the interval is timeout to detect + * if the client is still alive by Timing Mark. + */ +static gboolean send_timing_mark_cb(gpointer opaque) +{ + Terminal3270 *t = opaque; + const uint8_t timing[] = {0xff, 0xfd, 0x06}; + + qemu_chr_fe_write_all(&t->chr, timing, sizeof(timing)); + return true; +} + +/* * Receive inbound data from socket. * For data given to guest, drop the data boundary IAC, IAC_EOR. * TODO: @@ -77,6 +91,12 @@ static void terminal_read(void *opaque, const uint8_t *buf, int size) assert(size <= (INPUT_BUFFER_SIZE - t->in_len)); + if (t->timer_tag) { + g_source_remove(t->timer_tag); + t->timer_tag = 0; + } + t->timer_tag = g_timeout_add_seconds(600, send_timing_mark_cb, t); + memcpy(&t->inv[t->in_len], buf, size); t->in_len += size; if (t->in_len < 2) { @@ -127,6 +147,10 @@ static void chr_event(void *opaque, int event) t->in_len = 0; t->out_len = 0; t->handshake_done = false; + if (t->timer_tag) { + g_source_remove(t->timer_tag); + t->timer_tag = 0; + } switch (event) { case CHR_EVENT_OPENED: @@ -135,6 +159,7 @@ static void chr_event(void *opaque, int event) * char-socket.c. Once qemu receives the terminal-type of the * client, mark handshake done and trigger everything rolling again. */ + t->timer_tag = g_timeout_add_seconds(600, send_timing_mark_cb, t); break; case CHR_EVENT_CLOSED: sch->curr_status.scsw.dstat = SCSW_DSTAT_DEVICE_END; @@ -206,11 +231,13 @@ static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd, assert(count <= (OUTPUT_BUFFER_SIZE - 3) / 2); if (!t->handshake_done) { - /* - * Before having finished 3270 negotiation, - * sending outbound data is prohibited. - */ - return 0; + if (!(t->outv[0] == IAC && t->outv[1] != IAC)) { + /* + * Before having finished 3270 negotiation, + * sending outbound data except protocol options is prohibited. + */ + return 0; + } } if (!qemu_chr_fe_get_driver(&t->chr)) { /* We just say we consumed all data if there's no backend. */ |