/* Keep track if the char device is open */
switch (event) {
case CHR_EVENT_OPENED:
- s->opened = 1;
+ s->be_open = 1;
break;
case CHR_EVENT_CLOSED:
- s->opened = 0;
+ s->be_open = 0;
break;
}
s->chr_event(s->handler_opaque, event);
}
-static gboolean qemu_chr_generic_open_bh(gpointer opaque)
+static gboolean qemu_chr_be_generic_open_bh(gpointer opaque)
{
CharDriverState *s = opaque;
qemu_chr_be_event(s, CHR_EVENT_OPENED);
return FALSE;
}
-void qemu_chr_generic_open(CharDriverState *s)
+void qemu_chr_be_generic_open(CharDriverState *s)
{
if (s->idle_tag == 0) {
- s->idle_tag = g_idle_add(qemu_chr_generic_open_bh, s);
+ s->idle_tag = g_idle_add(qemu_chr_be_generic_open_bh, s);
}
}
return s->chr_write(s, buf, len);
}
+int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len)
+{
+ int offset = 0;
+ int res;
+
+ while (offset < len) {
+ do {
+ res = s->chr_write(s, buf + offset, len - offset);
+ if (res == -1 && errno == EAGAIN) {
+ g_usleep(100);
+ }
+ } while (res == -1 && errno == EAGAIN);
+
+ if (res == 0) {
+ break;
+ }
+
+ if (res < 0) {
+ return res;
+ }
+
+ offset += res;
+ }
+
+ return offset;
+}
+
int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg)
{
if (!s->chr_ioctl)
IOEventHandler *fd_event,
void *opaque)
{
+ int fe_open;
+
if (!opaque && !fd_can_read && !fd_read && !fd_event) {
- /* chr driver being released. */
- ++s->avail_connections;
+ fe_open = 0;
+ } else {
+ fe_open = 1;
}
s->chr_can_read = fd_can_read;
s->chr_read = fd_read;
if (s->chr_update_read_handler)
s->chr_update_read_handler(s);
+ if (!s->explicit_fe_open) {
+ qemu_chr_fe_set_open(s, fe_open);
+ }
+
/* We're connecting to an already opened device, so let's make sure we
also get the open event */
- if (s->opened) {
- qemu_chr_generic_open(s);
+ if (fe_open && s->be_open) {
+ qemu_chr_be_generic_open(s);
}
}
chr->chr_update_read_handler = mux_chr_update_read_handler;
chr->chr_accept_input = mux_chr_accept_input;
/* Frontend guest-open / -close notification is not support with muxes */
- chr->chr_guest_open = NULL;
- chr->chr_guest_close = NULL;
+ chr->chr_set_fe_open = NULL;
/* Muxes are always open on creation */
- qemu_chr_generic_open(chr);
+ qemu_chr_be_generic_open(chr);
return chr;
}
chr->chr_update_read_handler = fd_chr_update_read_handler;
chr->chr_close = fd_chr_close;
- qemu_chr_generic_open(chr);
+ qemu_chr_be_generic_open(chr);
return chr;
}
pty_chr_rearm_timer(chr, 1000);
} else {
if (!s->connected)
- qemu_chr_generic_open(chr);
+ qemu_chr_be_generic_open(chr);
s->connected = 1;
}
}
chr->chr_close = pp_close;
chr->opaque = drv;
- qemu_chr_generic_open(chr);
+ qemu_chr_be_generic_open(chr);
return chr;
}
g_free(chr);
return NULL;
}
- qemu_chr_generic_open(chr);
+ qemu_chr_be_generic_open(chr);
return chr;
}
g_free(chr);
return NULL;
}
- qemu_chr_generic_open(chr);
+ qemu_chr_be_generic_open(chr);
return chr;
}
s->hcom = fd_out;
chr->opaque = s;
chr->chr_write = win_chr_write;
- qemu_chr_generic_open(chr);
+ qemu_chr_be_generic_open(chr);
return chr;
}
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
}
-static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_udp_fd(int fd)
{
CharDriverState *chr = NULL;
NetCharDriver *s = NULL;
- Error *local_err = NULL;
- int fd = -1;
chr = g_malloc0(sizeof(CharDriverState));
s = g_malloc0(sizeof(NetCharDriver));
- fd = inet_dgram_opts(opts, &local_err);
- if (fd < 0) {
- goto return_err;
- }
-
s->fd = fd;
s->chan = io_channel_from_socket(s->fd);
s->bufcnt = 0;
chr->chr_update_read_handler = udp_chr_update_read_handler;
chr->chr_close = udp_chr_close;
return chr;
+}
-return_err:
- if (local_err) {
- qerror_report_err(local_err);
- error_free(local_err);
- }
- g_free(chr);
- g_free(s);
- if (fd >= 0) {
- closesocket(fd);
+static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
+{
+ Error *local_err = NULL;
+ int fd = -1;
+
+ fd = inet_dgram_opts(opts, &local_err);
+ if (fd < 0) {
+ return NULL;
}
- return NULL;
+ return qemu_chr_open_udp_fd(fd);
}
/***********************************************************/
if (s->chan) {
s->tag = io_add_watch_poll(s->chan, tcp_chr_read_poll, tcp_chr_read, chr);
}
- qemu_chr_generic_open(chr);
+ qemu_chr_be_generic_open(chr);
}
#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
s->do_nodelay = do_nodelay;
getnameinfo((struct sockaddr *) &ss, ss_len, host, sizeof(host),
serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV);
- snprintf(chr->filename, 256, "%s:%s:%s%s%s%s",
+ snprintf(chr->filename, 256, "%s:%s%s%s:%s%s",
is_telnet ? "telnet" : "tcp",
left, host, right, serv,
is_listen ? ",server" : "");
chr->opaque = NULL;
}
-static CharDriverState *qemu_chr_open_ringbuf(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_ringbuf(ChardevRingbuf *opts,
+ Error **errp)
{
CharDriverState *chr;
RingBufCharDriver *d;
chr = g_malloc0(sizeof(CharDriverState));
d = g_malloc(sizeof(*d));
- d->size = qemu_opt_get_size(opts, "size", 0);
- if (d->size == 0) {
- d->size = 65536;
- }
+ d->size = opts->has_size ? opts->size : 65536;
/* The size must be power of 2 */
if (d->size & (d->size - 1)) {
- error_report("size of ringbuf device must be power of two");
+ error_setg(errp, "size of ringbuf chardev must be power of two");
goto fail;
}
backend->pipe->device = g_strdup(device);
}
+static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
+ Error **errp)
+{
+ int val;
+
+ backend->memory = g_new0(ChardevRingbuf, 1);
+
+ val = qemu_opt_get_number(opts, "size", 0);
+ if (val != 0) {
+ backend->memory->has_size = true;
+ backend->memory->size = val;
+ }
+}
+
typedef struct CharDriver {
const char *name;
/* old, pre qapi */
}
}
-void qemu_chr_fe_open(struct CharDriverState *chr)
+void qemu_chr_fe_set_open(struct CharDriverState *chr, int fe_open)
{
- if (chr->chr_guest_open) {
- chr->chr_guest_open(chr);
+ if (chr->fe_open == fe_open) {
+ return;
}
-}
-
-void qemu_chr_fe_close(struct CharDriverState *chr)
-{
- if (chr->chr_guest_close) {
- chr->chr_guest_close(chr);
+ chr->fe_open = fe_open;
+ if (chr->chr_set_fe_open) {
+ chr->chr_set_fe_open(chr, fe_open);
}
}
-guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond,
- GIOFunc func, void *user_data)
+int qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond,
+ GIOFunc func, void *user_data)
{
GSource *src;
guint tag;
is_telnet, is_waitconnect, errp);
}
+static CharDriverState *qmp_chardev_open_dgram(ChardevDgram *dgram,
+ Error **errp)
+{
+ int fd;
+
+ fd = socket_dgram(dgram->remote, dgram->local, errp);
+ if (error_is_set(errp)) {
+ return NULL;
+ }
+ return qemu_chr_open_udp_fd(fd);
+}
+
ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
Error **errp)
{
case CHARDEV_BACKEND_KIND_SOCKET:
chr = qmp_chardev_open_socket(backend->socket, errp);
break;
+ case CHARDEV_BACKEND_KIND_DGRAM:
+ chr = qmp_chardev_open_dgram(backend->dgram, errp);
+ break;
#ifdef HAVE_CHARDEV_TTY
case CHARDEV_BACKEND_KIND_PTY:
chr = qemu_chr_open_pty(id, ret);
chr = qemu_chr_open_win_con();
break;
#endif
+#ifdef CONFIG_SPICE
+ case CHARDEV_BACKEND_KIND_SPICEVMC:
+ chr = qemu_chr_open_spice_vmc(backend->spicevmc->type);
+ break;
+ case CHARDEV_BACKEND_KIND_SPICEPORT:
+ chr = qemu_chr_open_spice_port(backend->spiceport->fqdn);
+ break;
+#endif
+ case CHARDEV_BACKEND_KIND_VC:
+ chr = vc_init(backend->vc);
+ break;
+ case CHARDEV_BACKEND_KIND_MEMORY:
+ chr = qemu_chr_open_ringbuf(backend->memory, errp);
+ break;
default:
error_setg(errp, "unknown chardev backend (%d)", backend->kind);
break;
register_char_driver_qapi("null", CHARDEV_BACKEND_KIND_NULL, NULL);
register_char_driver("socket", qemu_chr_open_socket);
register_char_driver("udp", qemu_chr_open_udp);
- register_char_driver("memory", qemu_chr_open_ringbuf);
+ register_char_driver_qapi("memory", CHARDEV_BACKEND_KIND_MEMORY,
+ qemu_chr_parse_ringbuf);
register_char_driver_qapi("file", CHARDEV_BACKEND_KIND_FILE,
qemu_chr_parse_file_out);
register_char_driver_qapi("stdio", CHARDEV_BACKEND_KIND_STDIO,