static void tcp_chr_telnet_init(Chardev *chr) { SocketChardev *s = SOCKET_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; \ 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 void qio_channel_websock_set_watch(QIOChannelWebsock *ioc) { GIOCondition cond = 0; qio_channel_websock_unset_watch(ioc); if (ioc->io_err) { return; } if (ioc->encoutput.offset) { cond |= G_IO_OUT; } if (ioc->encinput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER && !ioc->io_eof) { cond |= G_IO_IN; } if (cond) { object_ref(OBJECT(ioc)); ioc->io_tag = qio_channel_add_watch(ioc->master, cond, qio_channel_websock_flush, ioc, qio_channel_websock_flush_free); } }
static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc, GIOCondition condition, gpointer user_data) { QIOTask *task = user_data; QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK( qio_task_get_source(task)); Error *err = NULL; int ret; ret = qio_channel_websock_handshake_read(wioc, &err); if (ret < 0) { trace_qio_channel_websock_handshake_fail(ioc); qio_task_abort(task, err); error_free(err); return FALSE; } if (ret == 0) { trace_qio_channel_websock_handshake_pending(ioc, G_IO_IN); /* need more data still */ return TRUE; } object_ref(OBJECT(task)); trace_qio_channel_websock_handshake_reply(ioc); qio_channel_add_watch( wioc->master, G_IO_OUT, qio_channel_websock_handshake_send, task, (GDestroyNotify)object_unref); return FALSE; }
long vnc_client_write_sasl(VncState *vs) { long ret; VNC_DEBUG("Write SASL: Pending output %p size %zd offset %zd " "Encoded: %p size %d offset %d\n", vs->output.buffer, vs->output.capacity, vs->output.offset, vs->sasl.encoded, vs->sasl.encodedLength, vs->sasl.encodedOffset); if (!vs->sasl.encoded) { int err; err = sasl_encode(vs->sasl.conn, (char *)vs->output.buffer, vs->output.offset, (const char **)&vs->sasl.encoded, &vs->sasl.encodedLength); if (err != SASL_OK) return vnc_client_io_error(vs, -1, NULL); vs->sasl.encodedOffset = 0; } ret = vnc_client_write_buf(vs, vs->sasl.encoded + vs->sasl.encodedOffset, vs->sasl.encodedLength - vs->sasl.encodedOffset); if (!ret) return 0; vs->sasl.encodedOffset += ret; if (vs->sasl.encodedOffset == vs->sasl.encodedLength) { vs->output.offset = 0; vs->sasl.encoded = NULL; vs->sasl.encodedOffset = vs->sasl.encodedLength = 0; } /* Can't merge this block with one above, because * someone might have written more unencrypted * data in vs->output while we were processing * SASL encoded output */ if (vs->output.offset == 0) { if (vs->ioc_tag) { g_source_remove(vs->ioc_tag); } vs->ioc_tag = qio_channel_add_watch( vs->ioc, G_IO_IN, vnc_client_io, vs, NULL); } return ret; }
static void vncws_tls_handshake_done(Object *source, Error *err, gpointer user_data) { VncState *vs = user_data; if (err) { VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err)); vnc_client_error(vs); } else { VNC_DEBUG("TLS handshake complete, starting websocket handshake\n"); vs->ioc_tag = qio_channel_add_watch( QIO_CHANNEL(vs->ioc), G_IO_IN, vncws_handshake_io, vs, NULL); } }
void coroutine_fn qio_channel_yield(QIOChannel *ioc, GIOCondition condition) { QIOChannelYieldData data; assert(qemu_in_coroutine()); data.ioc = ioc; data.co = qemu_coroutine_self(); qio_channel_add_watch(ioc, condition, qio_channel_yield_enter, &data, NULL); qemu_coroutine_yield(); }
static void vnc_tls_handshake_done(Object *source, Error *err, gpointer user_data) { VncState *vs = user_data; if (err) { VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err)); vnc_client_error(vs); } else { vs->ioc_tag = qio_channel_add_watch( vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL); start_auth_vencrypt_subauth(vs); } }
static void nbd_update_server_watch(void) { if (nbd_can_accept()) { if (server_watch == -1) { server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc), G_IO_IN, nbd_accept, NULL, NULL); } } else { if (server_watch != -1) { g_source_remove(server_watch); server_watch = -1; } } }
void qmp_nbd_server_start(SocketAddress *addr, bool has_tls_creds, const char *tls_creds, Error **errp) { if (nbd_server) { error_setg(errp, "NBD server already running"); return; } nbd_server = g_new0(NBDServerData, 1); nbd_server->watch = -1; nbd_server->listen_ioc = qio_channel_socket_new(); qio_channel_set_name(QIO_CHANNEL(nbd_server->listen_ioc), "nbd-listener"); if (qio_channel_socket_listen_sync( nbd_server->listen_ioc, addr, errp) < 0) { goto error; } if (has_tls_creds) { nbd_server->tlscreds = nbd_get_tls_creds(tls_creds, errp); if (!nbd_server->tlscreds) { goto error; } /* TODO SOCKET_ADDRESS_KIND_FD where fd has AF_INET or AF_INET6 */ if (addr->type != SOCKET_ADDRESS_KIND_INET) { error_setg(errp, "TLS is only supported with IPv4/IPv6"); goto error; } } nbd_server->watch = qio_channel_add_watch( QIO_CHANNEL(nbd_server->listen_ioc), G_IO_IN, nbd_accept, NULL, NULL); return; error: nbd_server_free(nbd_server); nbd_server = NULL; }
static void vncws_tls_handshake_done(QIOTask *task, gpointer user_data) { VncState *vs = user_data; Error *err = NULL; if (qio_task_propagate_error(task, &err)) { VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err)); vnc_client_error(vs); error_free(err); } else { VNC_DEBUG("TLS handshake complete, starting websocket handshake\n"); if (vs->ioc_tag) { g_source_remove(vs->ioc_tag); } vs->ioc_tag = qio_channel_add_watch( QIO_CHANNEL(vs->ioc), G_IO_IN, vncws_handshake_io, vs, NULL); } }
static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc, QIOTask *task) { Error *err = NULL; QCryptoTLSSessionHandshakeStatus status; if (qcrypto_tls_session_handshake(ioc->session, &err) < 0) { trace_qio_channel_tls_handshake_fail(ioc); qio_task_abort(task, err); goto cleanup; } status = qcrypto_tls_session_get_handshake_status(ioc->session); if (status == QCRYPTO_TLS_HANDSHAKE_COMPLETE) { trace_qio_channel_tls_handshake_complete(ioc); if (qcrypto_tls_session_check_credentials(ioc->session, &err) < 0) { trace_qio_channel_tls_credentials_deny(ioc); qio_task_abort(task, err); goto cleanup; } trace_qio_channel_tls_credentials_allow(ioc); qio_task_complete(task); } else { GIOCondition condition; if (status == QCRYPTO_TLS_HANDSHAKE_SENDING) { condition = G_IO_OUT; } else { condition = G_IO_IN; } trace_qio_channel_tls_handshake_pending(ioc, status); qio_channel_add_watch(ioc->master, condition, qio_channel_tls_handshake_io, task, NULL); } cleanup: error_free(err); }
void exec_start_incoming_migration(const char *command, Error **errp) { QIOChannel *ioc; const char *argv[] = { "/bin/sh", "-c", command, NULL }; trace_migration_exec_incoming(command); ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv, O_RDONLY, errp)); if (!ioc) { return; } qio_channel_set_name(ioc, "migration-exec-incoming"); qio_channel_add_watch(ioc, G_IO_IN, exec_accept_incoming_migration, NULL, NULL); }
static void tcp_chr_disconnect(Chardev *chr) { SocketChardev *s = SOCKET_CHARDEV(chr); if (!s->connected) { return; } tcp_chr_free_connection(chr); if (s->listen_ioc) { s->listen_tag = qio_channel_add_watch( QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL); } update_disconnected_filename(s); qemu_chr_be_event(chr, CHR_EVENT_CLOSED); if (s->reconnect_time) { qemu_chr_socket_restart_timer(chr); } }
static void vnc_tls_handshake_done(QIOTask *task, gpointer user_data) { VncState *vs = user_data; Error *err = NULL; if (qio_task_propagate_error(task, &err)) { trace_vnc_auth_fail(vs, vs->auth, "TLS handshake failed", error_get_pretty(err)); vnc_client_error(vs); error_free(err); } else { if (vs->ioc_tag) { g_source_remove(vs->ioc_tag); } vs->ioc_tag = qio_channel_add_watch( vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL); start_auth_vencrypt_subauth(vs); } }
void qio_channel_websock_handshake(QIOChannelWebsock *ioc, QIOTaskFunc func, gpointer opaque, GDestroyNotify destroy) { QIOTask *task; task = qio_task_new(OBJECT(ioc), func, opaque, destroy); trace_qio_channel_websock_handshake_start(ioc); trace_qio_channel_websock_handshake_pending(ioc, G_IO_IN); qio_channel_add_watch(ioc->master, G_IO_IN, qio_channel_websock_handshake_io, task, NULL); }
static void tcp_chr_telnet_init(Chardev *chr) { SocketChardev *s = SOCKET_CHARDEV(chr); TCPChardevTelnetInit *init = g_new0(TCPChardevTelnetInit, 1); size_t n = 0; #define IACSET(x, a, b, c) \ do { \ x[n++] = a; \ x[n++] = b; \ x[n++] = c; \ } while (0) 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 qio_channel_add_watch( s->ioc, G_IO_OUT, tcp_chr_telnet_init_io, init, NULL); }
static void tcp_chr_disconnect(Chardev *chr) { SocketChardev *s = SOCKET_CHARDEV(chr); if (!s->connected) { return; } tcp_chr_free_connection(chr); if (s->listen_ioc) { s->listen_tag = qio_channel_add_watch( QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL); } chr->filename = SocketAddress_to_str("disconnected:", s->addr, s->is_listen, s->is_telnet); qemu_chr_be_event(chr, CHR_EVENT_CLOSED); if (s->reconnect_time) { qemu_chr_socket_restart_timer(chr); } }
void fd_start_incoming_migration(const char *infd, Error **errp) { QIOChannel *ioc; int fd; fd = strtol(infd, NULL, 0); trace_migration_fd_incoming(fd); ioc = qio_channel_new_fd(fd, errp); if (!ioc) { close(fd); return; } qio_channel_set_name(QIO_CHANNEL(ioc), "migration-fd-incoming"); qio_channel_add_watch(ioc, G_IO_IN, fd_accept_incoming_migration, NULL, NULL); }
static void socket_start_incoming_migration(SocketAddress *saddr, Error **errp) { QIOChannelSocket *listen_ioc = qio_channel_socket_new(); qio_channel_set_name(QIO_CHANNEL(listen_ioc), "migration-socket-listener"); if (qio_channel_socket_listen_sync(listen_ioc, saddr, errp) < 0) { object_unref(OBJECT(listen_ioc)); qapi_free_SocketAddress(saddr); return; } qio_channel_add_watch(QIO_CHANNEL(listen_ioc), G_IO_IN, socket_accept_incoming_migration, listen_ioc, (GDestroyNotify)object_unref); qapi_free_SocketAddress(saddr); }
static void qmp_chardev_open_socket(Chardev *chr, ChardevBackend *backend, bool *be_opened, Error **errp) { SocketChardev *s = SOCKET_CHARDEV(chr); ChardevSocket *sock = backend->u.socket.data; SocketAddress *addr = sock->addr; 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_waitconnect = sock->has_wait ? sock->wait : false; int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0; QIOChannelSocket *sioc = NULL; s->is_unix = addr->type == SOCKET_ADDRESS_KIND_UNIX; s->is_listen = is_listen; s->is_telnet = is_telnet; s->do_nodelay = do_nodelay; if (sock->tls_creds) { Object *creds; creds = object_resolve_path_component( object_get_objects_root(), sock->tls_creds); if (!creds) { error_setg(errp, "No TLS credentials with id '%s'", sock->tls_creds); goto error; } s->tls_creds = (QCryptoTLSCreds *) object_dynamic_cast(creds, TYPE_QCRYPTO_TLS_CREDS); if (!s->tls_creds) { error_setg(errp, "Object with id '%s' is not TLS credentials", sock->tls_creds); goto error; } object_ref(OBJECT(s->tls_creds)); if (is_listen) { if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { error_setg(errp, "%s", "Expected TLS credentials for server endpoint"); goto error; } } else { if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) { error_setg(errp, "%s", "Expected TLS credentials for client endpoint"); goto error; } } } s->addr = QAPI_CLONE(SocketAddress, sock->addr); qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE); if (s->is_unix) { qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS); } /* be isn't opened until we get a connection */ *be_opened = false; chr->filename = SocketAddress_to_str("disconnected:", addr, is_listen, is_telnet); if (is_listen) { if (is_telnet) { s->do_telnetopt = 1; } } else if (reconnect > 0) { s->reconnect_time = reconnect; } if (s->reconnect_time) { sioc = qio_channel_socket_new(); tcp_chr_set_client_ioc_name(chr, sioc); qio_channel_socket_connect_async(sioc, s->addr, qemu_chr_socket_connected, chr, NULL); } else { if (s->is_listen) { char *name; sioc = qio_channel_socket_new(); name = g_strdup_printf("chardev-tcp-listener-%s", chr->label); qio_channel_set_name(QIO_CHANNEL(sioc), name); g_free(name); if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) { goto error; } s->listen_ioc = sioc; if (is_waitconnect && qemu_chr_wait_connected(chr, errp) < 0) { return; } if (!s->ioc) { s->listen_tag = qio_channel_add_watch( QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL); } } else if (qemu_chr_wait_connected(chr, errp) < 0) { goto error; } } return; error: if (sioc) { object_unref(OBJECT(sioc)); } }