/** * Called after processing of default and command-line-specified * chardevs to deliver CHR_EVENT_OPENED events to any FEs attached * to a mux chardev. This is done here to ensure that * output/prompts/banners are only displayed for the FE that has * focus when initial command-line processing/machine init is * completed. * * After this point, any new FE attached to any new or existing * mux will receive CHR_EVENT_OPENED notifications for the BE * immediately. */ static int open_muxes(Object *child, void *opaque) { if (CHARDEV_IS_MUX(child)) { /* send OPENED to all already-attached FEs */ mux_chr_send_all_event(CHARDEV(child), CHR_EVENT_OPENED); /* mark mux as OPENED so any new FEs will immediately receive * OPENED event */ qemu_chr_be_event(CHARDEV(child), CHR_EVENT_OPENED); } return 0; }
static void char_socket_finalize(Object *obj) { Chardev *chr = CHARDEV(obj); SocketChardev *s = SOCKET_CHARDEV(obj); tcp_chr_free_connection(chr); if (s->reconnect_timer) { g_source_remove(s->reconnect_timer); s->reconnect_timer = 0; } qapi_free_SocketAddress(s->addr); if (s->listen_tag) { g_source_remove(s->listen_tag); s->listen_tag = 0; } if (s->listen_ioc) { object_unref(OBJECT(s->listen_ioc)); } if (s->tls_creds) { object_unref(OBJECT(s->tls_creds)); } qemu_chr_be_event(chr, CHR_EVENT_CLOSED); }
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; }
static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) { Chardev *chr = CHARDEV(opaque); PtyChardev *s = PTY_CHARDEV(opaque); gsize len; uint8_t buf[CHR_READ_BUF_LEN]; ssize_t ret; len = sizeof(buf); if (len > s->read_bytes) { len = s->read_bytes; } if (len == 0) { return TRUE; } ret = qio_channel_read(s->ioc, (char *)buf, len, NULL); if (ret <= 0) { pty_chr_state(chr, 0); return FALSE; } else { pty_chr_state(chr, 1); qemu_chr_be_write(chr, buf, ret); } return TRUE; }
static void char_init(Object *obj) { Chardev *chr = CHARDEV(obj); chr->logfd = -1; qemu_mutex_init(&chr->chr_write_lock); }
static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) { Chardev *chr = CHARDEV(opaque); FDChardev *s = FD_CHARDEV(opaque); int len; uint8_t buf[CHR_READ_BUF_LEN]; ssize_t ret; len = sizeof(buf); if (len > s->max_size) { len = s->max_size; } if (len == 0) { return TRUE; } ret = qio_channel_read( chan, (gchar *)buf, len, NULL); if (ret == 0) { remove_fd_in_watch(chr); qemu_chr_be_event(chr, CHR_EVENT_CLOSED); return FALSE; } if (ret > 0) { qemu_chr_be_write(chr, buf, ret); } return TRUE; }
static int fd_chr_read_poll(void *opaque) { Chardev *chr = CHARDEV(opaque); FDChardev *s = FD_CHARDEV(opaque); s->max_size = qemu_chr_be_can_write(chr); return s->max_size; }
static int pty_chr_read_poll(void *opaque) { Chardev *chr = CHARDEV(opaque); PtyChardev *s = PTY_CHARDEV(opaque); s->read_bytes = qemu_chr_be_can_write(chr); return s->read_bytes; }
static void update_disconnected_filename(SocketChardev *s) { Chardev *chr = CHARDEV(s); g_free(chr->filename); chr->filename = SocketAddress_to_str("disconnected:", s->addr, s->is_listen, s->is_telnet); }
static gboolean qemu_chr_be_generic_open_func(gpointer opaque) { Chardev *chr = CHARDEV(opaque); PtyChardev *s = PTY_CHARDEV(opaque); s->open_source = NULL; qemu_chr_be_event(chr, CHR_EVENT_OPENED); return FALSE; }
static int tcp_chr_read_poll(void *opaque) { Chardev *chr = CHARDEV(opaque); SocketChardev *s = SOCKET_CHARDEV(opaque); if (!s->connected) { return 0; } s->max_size = qemu_chr_be_can_write(chr); return s->max_size; }
static void char_pty_finalize(Object *obj) { Chardev *chr = CHARDEV(obj); PtyChardev *s = PTY_CHARDEV(obj); pty_chr_state(chr, 0); object_unref(OBJECT(s->ioc)); pty_chr_timer_cancel(s); qemu_chr_be_event(chr, CHR_EVENT_CLOSED); }
static void wctablet_queue_output(TabletChardev *tablet, uint8_t *buf, int count) { if (tablet->outlen + count > sizeof(tablet->outbuf)) { return; } memcpy(tablet->outbuf + tablet->outlen, buf, count); tablet->outlen += count; wctablet_chr_accept_input(CHARDEV(tablet)); }
static void char_udp_finalize(Object *obj) { Chardev *chr = CHARDEV(obj); UdpChardev *s = UDP_CHARDEV(obj); remove_fd_in_watch(chr); if (s->ioc) { object_unref(OBJECT(s->ioc)); } qemu_chr_be_event(chr, CHR_EVENT_CLOSED); }
static void udp_chr_flush_buffer(UdpChardev *s) { Chardev *chr = CHARDEV(s); while (s->max_size > 0 && s->bufptr < s->bufcnt) { int n = MIN(s->max_size, s->bufcnt - s->bufptr); qemu_chr_be_write(chr, &s->buf[s->bufptr], n); s->bufptr += n; s->max_size = qemu_chr_be_can_write(chr); } }
static gboolean pty_chr_timer(gpointer opaque) { struct Chardev *chr = CHARDEV(opaque); PtyChardev *s = PTY_CHARDEV(opaque); pty_chr_timer_cancel(s); if (!s->connected) { /* Next poll ... */ qemu_chr_be_update_read_handlers(chr, chr->gcontext); } return FALSE; }
static void char_finalize(Object *obj) { Chardev *chr = CHARDEV(obj); if (chr->be) { chr->be->chr = NULL; } g_free(chr->filename); g_free(chr->label); if (chr->logfd != -1) { close(chr->logfd); } qemu_mutex_destroy(&chr->chr_write_lock); }
static int udp_chr_read_poll(void *opaque) { Chardev *chr = CHARDEV(opaque); UdpChardev *s = UDP_CHARDEV(opaque); s->max_size = qemu_chr_be_can_write(chr); /* If there were any stray characters in the queue process them * first */ udp_chr_flush_buffer(s); return s->max_size; }
static void char_fd_finalize(Object *obj) { Chardev *chr = CHARDEV(obj); FDChardev *s = FD_CHARDEV(obj); remove_fd_in_watch(chr); if (s->ioc_in) { object_unref(OBJECT(s->ioc_in)); } if (s->ioc_out) { object_unref(OBJECT(s->ioc_out)); } qemu_chr_be_event(chr, CHR_EVENT_CLOSED); }
static gboolean pty_chr_timer(gpointer opaque) { struct Chardev *chr = CHARDEV(opaque); PtyChardev *s = PTY_CHARDEV(opaque); qemu_mutex_lock(&chr->chr_write_lock); s->timer_src = NULL; g_source_unref(s->open_source); s->open_source = NULL; if (!s->connected) { /* Next poll ... */ pty_chr_update_read_handler_locked(chr); } qemu_mutex_unlock(&chr->chr_write_lock); return FALSE; }
static void qemu_chr_socket_connected(QIOTask *task, void *opaque) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task)); Chardev *chr = CHARDEV(opaque); SocketChardev *s = SOCKET_CHARDEV(chr); Error *err = NULL; if (qio_task_propagate_error(task, &err)) { check_report_connect_error(chr, err); error_free(err); goto cleanup; } s->connect_err_reported = false; tcp_chr_new_client(chr, sioc); cleanup: object_unref(OBJECT(sioc)); }
static gboolean tcp_chr_accept(QIOChannel *channel, GIOCondition cond, void *opaque) { Chardev *chr = CHARDEV(opaque); QIOChannelSocket *sioc; sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(channel), NULL); if (!sioc) { return TRUE; } tcp_chr_new_client(chr, sioc); object_unref(OBJECT(sioc)); return TRUE; }
static void tcp_chr_connect(void *opaque) { Chardev *chr = CHARDEV(opaque); SocketChardev *s = SOCKET_CHARDEV(opaque); g_free(chr->filename); chr->filename = sockaddr_to_str( &s->sioc->localAddr, s->sioc->localAddrLen, &s->sioc->remoteAddr, s->sioc->remoteAddrLen, s->is_listen, s->is_telnet); s->connected = 1; if (s->ioc) { chr->fd_in_tag = io_add_watch_poll(chr, s->ioc, tcp_chr_read_poll, tcp_chr_read, chr, NULL); } qemu_chr_be_generic_open(chr); }
static gboolean socket_reconnect_timeout(gpointer opaque) { Chardev *chr = CHARDEV(opaque); SocketChardev *s = SOCKET_CHARDEV(opaque); QIOChannelSocket *sioc; s->reconnect_timer = 0; if (chr->be_open) { return false; } 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); return false; }
static void tcp_chr_connect(void *opaque) { Chardev *chr = CHARDEV(opaque); SocketChardev *s = SOCKET_CHARDEV(opaque); g_free(chr->filename); chr->filename = sockaddr_to_str( &s->sioc->localAddr, s->sioc->localAddrLen, &s->sioc->remoteAddr, s->sioc->remoteAddrLen, s->is_listen, s->is_telnet); s->connected = 1; if (s->ioc) { chr->gsource = io_add_watch_poll(chr, s->ioc, tcp_chr_read_poll, tcp_chr_read, chr, NULL); } qemu_chr_be_event(chr, CHR_EVENT_OPENED); }
static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) { Chardev *chr = CHARDEV(opaque); UdpChardev *s = UDP_CHARDEV(opaque); ssize_t ret; if (s->max_size == 0) { return TRUE; } ret = qio_channel_read( s->ioc, (char *)s->buf, sizeof(s->buf), NULL); if (ret <= 0) { remove_fd_in_watch(chr); return FALSE; } s->bufcnt = ret; s->bufptr = 0; udp_chr_flush_buffer(s); return TRUE; }
static void mux_chr_read(void *opaque, const uint8_t *buf, int size) { Chardev *chr = CHARDEV(opaque); MuxChardev *d = MUX_CHARDEV(opaque); int m = d->focus; CharBackend *be = d->backends[m]; int i; mux_chr_accept_input(opaque); for (i = 0; i < size; i++) if (mux_proc_byte(chr, d, buf[i])) { if (d->prod[m] == d->cons[m] && be && be->chr_can_read && be->chr_can_read(be->opaque)) { be->chr_read(be->opaque, &buf[i], 1); } else { d->buffer[m][d->prod[m]++ & MUX_BUFFER_MASK] = buf[i]; } } }
static void mux_chr_event(void *opaque, int event) { mux_chr_send_all_event(CHARDEV(opaque), event); }