static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc, GIOCondition cond G_GNUC_UNUSED, gpointer user_data) { TCPChardevTelnetInit *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 gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) { Chardev *chr = CHARDEV(opaque); SocketChardev *s = SOCKET_CHARDEV(opaque); uint8_t buf[CHR_READ_BUF_LEN]; int len, size; if (!s->connected || s->max_size <= 0) { return TRUE; } len = sizeof(buf); if (len > s->max_size) { len = s->max_size; } size = tcp_chr_recv(chr, (void *)buf, len); if (size == 0 || size == -1) { /* connection closed */ tcp_chr_disconnect(chr); } else if (size > 0) { if (s->do_telnetopt) { tcp_chr_process_IAC_bytes(chr, s, buf, &size); } if (size > 0) { qemu_chr_be_write(chr, buf, size); } } return TRUE; }
/* Called with chr_write_lock held. */ static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len) { SocketChardev *s = SOCKET_CHARDEV(chr); if (s->connected) { int ret = io_channel_send_full(s->ioc, buf, len, s->write_msgfds, s->write_msgfds_num); /* free the written msgfds, no matter what */ if (s->write_msgfds_num) { g_free(s->write_msgfds); s->write_msgfds = 0; s->write_msgfds_num = 0; } if (ret < 0 && errno != EAGAIN) { if (tcp_chr_read_poll(chr) <= 0) { tcp_chr_disconnect(chr); return len; } /* else let the read handler finish it properly */ } return ret; } else { /* XXX: indicate an error ? */ return len; } }
static void tcp_chr_tls_handshake(QIOTask *task, gpointer user_data) { Chardev *chr = user_data; SocketChardev *s = user_data; if (qio_task_propagate_error(task, NULL)) { tcp_chr_disconnect(chr); } else { if (s->do_telnetopt) { tcp_chr_telnet_init(chr); } else { tcp_chr_connect(chr); } } }
static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len) { SocketChardev *s = SOCKET_CHARDEV(chr); int size; if (!s->connected) { return 0; } size = tcp_chr_recv(chr, (void *) buf, len); if (size == 0) { /* connection closed */ tcp_chr_disconnect(chr); } return size; }
static void tcp_chr_tls_handshake(QIOTask *task, gpointer user_data) { Chardev *chr = user_data; SocketChardev *s = user_data; if (qio_task_propagate_error(task, NULL)) { tcp_chr_disconnect(chr); } else { /* tn3270 does not support TLS yet */ if (s->do_telnetopt && !s->is_tn3270) { tcp_chr_telnet_init(chr); } else { tcp_chr_connect(chr); } } }
static void tcp_chr_tls_init(Chardev *chr) { SocketChardev *s = SOCKET_CHARDEV(chr); QIOChannelTLS *tioc; Error *err = NULL; gchar *name; if (s->is_listen) { tioc = qio_channel_tls_new_server( s->ioc, s->tls_creds, NULL, /* XXX Use an ACL */ &err); } else { tioc = qio_channel_tls_new_client( s->ioc, s->tls_creds, s->addr->u.inet.data->host, &err); } if (tioc == NULL) { error_free(err); tcp_chr_disconnect(chr); return; } name = g_strdup_printf("chardev-tls-%s-%s", s->is_listen ? "server" : "client", chr->label); qio_channel_set_name(QIO_CHANNEL(tioc), name); g_free(name); object_unref(OBJECT(s->ioc)); s->ioc = QIO_CHANNEL(tioc); qio_channel_tls_handshake(tioc, tcp_chr_tls_handshake, chr, NULL); }