diff options
Diffstat (limited to 'qemu-char.c')
-rw-r--r-- | qemu-char.c | 360 |
1 files changed, 220 insertions, 140 deletions
diff --git a/qemu-char.c b/qemu-char.c index e0147f3e8b..b597ee19ca 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -23,8 +23,10 @@ */ #include "qemu/osdep.h" #include "qemu-common.h" +#include "qemu/cutils.h" #include "monitor/monitor.h" #include "sysemu/sysemu.h" +#include "sysemu/block-backend.h" #include "qemu/error-report.h" #include "qemu/timer.h" #include "sysemu/char.h" @@ -37,6 +39,7 @@ #include "io/channel-socket.h" #include "io/channel-file.h" #include "io/channel-tls.h" +#include "sysemu/replay.h" #include <zlib.h> @@ -96,16 +99,18 @@ static char *SocketAddress_to_str(const char *prefix, SocketAddress *addr, switch (addr->type) { case SOCKET_ADDRESS_KIND_INET: return g_strdup_printf("%s%s:%s:%s%s", prefix, - is_telnet ? "telnet" : "tcp", addr->u.inet->host, - addr->u.inet->port, is_listen ? ",server" : ""); + is_telnet ? "telnet" : "tcp", + addr->u.inet.data->host, + addr->u.inet.data->port, + is_listen ? ",server" : ""); break; case SOCKET_ADDRESS_KIND_UNIX: return g_strdup_printf("%sunix:%s%s", prefix, - addr->u.q_unix->path, + addr->u.q_unix.data->path, is_listen ? ",server" : ""); break; case SOCKET_ADDRESS_KIND_FD: - return g_strdup_printf("%sfd:%s%s", prefix, addr->u.fd->str, + return g_strdup_printf("%sfd:%s%s", prefix, addr->u.fd.data->str, is_listen ? ",server" : ""); break; default: @@ -220,12 +225,12 @@ static void qemu_chr_fe_write_log(CharDriverState *s, } while (done < len) { - do { - ret = write(s->logfd, buf + done, len - done); - if (ret == -1 && errno == EAGAIN) { - g_usleep(100); - } - } while (ret == -1 && errno == EAGAIN); + retry: + ret = write(s->logfd, buf + done, len - done); + if (ret == -1 && errno == EAGAIN) { + g_usleep(100); + goto retry; + } if (ret <= 0) { return; @@ -234,10 +239,46 @@ static void qemu_chr_fe_write_log(CharDriverState *s, } } +static int qemu_chr_fe_write_buffer(CharDriverState *s, const uint8_t *buf, int len, int *offset) +{ + int res = 0; + *offset = 0; + + qemu_mutex_lock(&s->chr_write_lock); + while (*offset < len) { + retry: + res = s->chr_write(s, buf + *offset, len - *offset); + if (res < 0 && errno == EAGAIN) { + g_usleep(100); + goto retry; + } + + if (res <= 0) { + break; + } + + *offset += res; + } + if (*offset > 0) { + qemu_chr_fe_write_log(s, buf, *offset); + } + qemu_mutex_unlock(&s->chr_write_lock); + + return res; +} + int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len) { int ret; + if (s->replay && replay_mode == REPLAY_MODE_PLAY) { + int offset; + replay_char_write_event_load(&ret, &offset); + assert(offset <= len); + qemu_chr_fe_write_buffer(s, buf, offset, &offset); + return ret; + } + qemu_mutex_lock(&s->chr_write_lock); ret = s->chr_write(s, buf, len); @@ -246,35 +287,32 @@ int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len) } qemu_mutex_unlock(&s->chr_write_lock); + + if (s->replay && replay_mode == REPLAY_MODE_RECORD) { + replay_char_write_event_save(ret, ret < 0 ? 0 : ret); + } + return ret; } int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len) { - int offset = 0; - int res = 0; + int offset; + int res; - qemu_mutex_lock(&s->chr_write_lock); - 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 (s->replay && replay_mode == REPLAY_MODE_PLAY) { + replay_char_write_event_load(&res, &offset); + assert(offset <= len); + qemu_chr_fe_write_buffer(s, buf, offset, &offset); + return res; + } - if (res <= 0) { - break; - } + res = qemu_chr_fe_write_buffer(s, buf, len, &offset); - offset += res; - } - if (offset > 0) { - qemu_chr_fe_write_log(s, buf, offset); + if (s->replay && replay_mode == REPLAY_MODE_RECORD) { + replay_char_write_event_save(res, offset); } - qemu_mutex_unlock(&s->chr_write_lock); - if (res < 0) { return res; } @@ -289,20 +327,27 @@ int qemu_chr_fe_read_all(CharDriverState *s, uint8_t *buf, int len) if (!s->chr_sync_read) { return 0; } + + if (s->replay && replay_mode == REPLAY_MODE_PLAY) { + return replay_char_read_all_load(buf); + } while (offset < len) { - do { - res = s->chr_sync_read(s, buf + offset, len - offset); - if (res == -1 && errno == EAGAIN) { - g_usleep(100); - } - } while (res == -1 && errno == EAGAIN); + retry: + res = s->chr_sync_read(s, buf + offset, len - offset); + if (res == -1 && errno == EAGAIN) { + g_usleep(100); + goto retry; + } if (res == 0) { break; } if (res < 0) { + if (s->replay && replay_mode == REPLAY_MODE_RECORD) { + replay_char_read_all_save_error(res); + } return res; } @@ -313,14 +358,22 @@ int qemu_chr_fe_read_all(CharDriverState *s, uint8_t *buf, int len) } } + if (s->replay && replay_mode == REPLAY_MODE_RECORD) { + replay_char_read_all_save_buf(buf, offset); + } return offset; } int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg) { - if (!s->chr_ioctl) - return -ENOTSUP; - return s->chr_ioctl(s, cmd, arg); + int res; + if (!s->chr_ioctl || s->replay) { + res = -ENOTSUP; + } else { + res = s->chr_ioctl(s, cmd, arg); + } + + return res; } int qemu_chr_be_can_write(CharDriverState *s) @@ -330,17 +383,35 @@ int qemu_chr_be_can_write(CharDriverState *s) return s->chr_can_read(s->handler_opaque); } -void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len) +void qemu_chr_be_write_impl(CharDriverState *s, uint8_t *buf, int len) { if (s->chr_read) { s->chr_read(s->handler_opaque, buf, len); } } +void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len) +{ + if (s->replay) { + if (replay_mode == REPLAY_MODE_PLAY) { + return; + } + replay_chr_be_write(s, buf, len); + } else { + qemu_chr_be_write_impl(s, buf, len); + } +} + int qemu_chr_fe_get_msgfd(CharDriverState *s) { int fd; - return (qemu_chr_fe_get_msgfds(s, &fd, 1) == 1) ? fd : -1; + int res = (qemu_chr_fe_get_msgfds(s, &fd, 1) == 1) ? fd : -1; + if (s->replay) { + fprintf(stderr, + "Replay: get msgfd is not supported for serial devices yet\n"); + exit(1); + } + return res; } int qemu_chr_fe_get_msgfds(CharDriverState *s, int *fds, int len) @@ -420,7 +491,7 @@ static CharDriverState *qemu_chr_open_null(const char *id, Error **errp) { CharDriverState *chr; - ChardevCommon *common = backend->u.null; + ChardevCommon *common = backend->u.null.data; chr = qemu_chr_alloc(common, errp); if (!chr) { @@ -561,7 +632,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) break; } case 's': - bdrv_commit_all(); + blk_commit_all(); break; case 'b': qemu_chr_be_event(chr, CHR_EVENT_BREAK); @@ -721,7 +792,7 @@ static CharDriverState *qemu_chr_open_mux(const char *id, ChardevBackend *backend, ChardevReturn *ret, Error **errp) { - ChardevMux *mux = backend->u.mux; + ChardevMux *mux = backend->u.mux.data; CharDriverState *chr, *drv; MuxDriver *d; ChardevCommon *common = qapi_ChardevMux_base(mux); @@ -1038,7 +1109,7 @@ static CharDriverState *qemu_chr_open_pipe(const char *id, ChardevReturn *ret, Error **errp) { - ChardevHostdev *opts = backend->u.pipe; + ChardevHostdev *opts = backend->u.pipe.data; int fd_in, fd_out; char *filename_in; char *filename_out; @@ -1120,7 +1191,7 @@ static CharDriverState *qemu_chr_open_stdio(const char *id, ChardevReturn *ret, Error **errp) { - ChardevStdio *opts = backend->u.stdio; + ChardevStdio *opts = backend->u.stdio.data; CharDriverState *chr; struct sigaction act; ChardevCommon *common = qapi_ChardevStdio_base(opts); @@ -1366,7 +1437,7 @@ static CharDriverState *qemu_chr_open_pty(const char *id, PtyCharDriver *s; int master_fd, slave_fd; char pty_name[PATH_MAX]; - ChardevCommon *common = backend->u.pty; + ChardevCommon *common = backend->u.pty.data; master_fd = qemu_openpty_raw(&slave_fd, pty_name); if (master_fd < 0) { @@ -2137,7 +2208,7 @@ static CharDriverState *qemu_chr_open_pipe(const char *id, ChardevReturn *ret, Error **errp) { - ChardevHostdev *opts = backend->u.pipe; + ChardevHostdev *opts = backend->u.pipe.data; const char *filename = opts->device; CharDriverState *chr; WinCharState *s; @@ -2183,7 +2254,7 @@ static CharDriverState *qemu_chr_open_win_con(const char *id, ChardevReturn *ret, Error **errp) { - ChardevCommon *common = backend->u.console; + ChardevCommon *common = backend->u.console.data; return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE), common, errp); } @@ -2333,7 +2404,7 @@ static CharDriverState *qemu_chr_open_stdio(const char *id, WinStdioCharState *stdio; DWORD dwMode; int is_console = 0; - ChardevCommon *common = qapi_ChardevStdio_base(backend->u.stdio); + ChardevCommon *common = qapi_ChardevStdio_base(backend->u.stdio.data); chr = qemu_chr_alloc(common, errp); if (!chr) { @@ -2697,6 +2768,7 @@ static int tcp_set_msgfds(CharDriverState *chr, int *fds, int num) } /* clear old pending fd array */ g_free(s->write_msgfds); + s->write_msgfds = NULL; if (num) { s->write_msgfds = g_new(int, num); @@ -2727,6 +2799,13 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len) NULL); } + if (ret == QIO_CHANNEL_ERR_BLOCK) { + errno = EAGAIN; + ret = -1; + } else if (ret == -1) { + errno = EIO; + } + if (msgfds_num) { /* close and clean read_msgfds */ for (i = 0; i < s->read_msgfds_num; i++) { @@ -2768,11 +2847,16 @@ static void tcp_chr_disconnect(CharDriverState *chr) { TCPCharDriver *s = chr->opaque; + if (!s->connected) { + return; + } + s->connected = 0; if (s->listen_ioc) { s->listen_tag = qio_channel_add_watch( QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL); } + tcp_set_msgfds(chr, NULL, 0); remove_fd_in_watch(chr); object_unref(OBJECT(s->sioc)); s->sioc = NULL; @@ -2968,7 +3052,7 @@ static void tcp_chr_tls_init(CharDriverState *chr) } else { tioc = qio_channel_tls_new_client( s->ioc, s->tls_creds, - s->addr->u.inet->host, + s->addr->u.inet.data->host, &err); } if (tioc == NULL) { @@ -2997,6 +3081,8 @@ static int tcp_chr_new_client(CharDriverState *chr, QIOChannelSocket *sioc) s->sioc = sioc; object_ref(OBJECT(sioc)); + qio_channel_set_blocking(s->ioc, false, NULL); + if (s->do_nodelay) { qio_channel_set_delay(s->ioc, false); } @@ -3028,7 +3114,6 @@ static int tcp_chr_add_client(CharDriverState *chr, int fd) if (!sioc) { return -1; } - qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL); ret = tcp_chr_new_client(chr, sioc); object_unref(OBJECT(sioc)); return ret; @@ -3091,20 +3176,6 @@ static void tcp_chr_close(CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static void qemu_chr_finish_socket_connection(CharDriverState *chr, - QIOChannelSocket *sioc) -{ - TCPCharDriver *s = chr->opaque; - - if (s->is_listen) { - s->listen_ioc = sioc; - s->listen_tag = qio_channel_add_watch( - QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL); - } else { - tcp_chr_new_client(chr, sioc); - object_unref(OBJECT(sioc)); - } -} static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque) { @@ -3119,37 +3190,11 @@ static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque) } s->connect_err_reported = false; - qemu_chr_finish_socket_connection(chr, sioc); -} - -static bool qemu_chr_open_socket_fd(CharDriverState *chr, Error **errp) -{ - TCPCharDriver *s = chr->opaque; - QIOChannelSocket *sioc = qio_channel_socket_new(); - - if (s->is_listen) { - if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) { - goto fail; - } - qemu_chr_finish_socket_connection(chr, sioc); - } else if (s->reconnect_time) { - qio_channel_socket_connect_async(sioc, s->addr, - qemu_chr_socket_connected, - chr, NULL); - } else { - if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) { - goto fail; - } - qemu_chr_finish_socket_connection(chr, sioc); - } - - return true; - - fail: + tcp_chr_new_client(chr, sioc); object_unref(OBJECT(sioc)); - return false; } + /*********************************************************/ /* Ring buffer chardev */ @@ -3215,7 +3260,7 @@ static CharDriverState *qemu_chr_open_ringbuf(const char *id, ChardevReturn *ret, Error **errp) { - ChardevRingbuf *opts = backend->u.ringbuf; + ChardevRingbuf *opts = backend->u.ringbuf.data; ChardevCommon *common = qapi_ChardevRingbuf_base(opts); CharDriverState *chr; RingBufCharDriver *d; @@ -3512,7 +3557,7 @@ static void qemu_chr_parse_file_out(QemuOpts *opts, ChardevBackend *backend, error_setg(errp, "chardev: file: no filename given"); return; } - file = backend->u.file = g_new0(ChardevFile, 1); + file = backend->u.file.data = g_new0(ChardevFile, 1); qemu_chr_parse_common(opts, qapi_ChardevFile_base(file)); file->out = g_strdup(path); @@ -3525,7 +3570,7 @@ static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend, { ChardevStdio *stdio; - stdio = backend->u.stdio = g_new0(ChardevStdio, 1); + stdio = backend->u.stdio.data = g_new0(ChardevStdio, 1); qemu_chr_parse_common(opts, qapi_ChardevStdio_base(stdio)); stdio->has_signal = true; stdio->signal = qemu_opt_get_bool(opts, "signal", true); @@ -3542,7 +3587,7 @@ static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend, error_setg(errp, "chardev: serial/tty: no device path given"); return; } - serial = backend->u.serial = g_new0(ChardevHostdev, 1); + serial = backend->u.serial.data = g_new0(ChardevHostdev, 1); qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial)); serial->device = g_strdup(device); } @@ -3559,7 +3604,7 @@ static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend, error_setg(errp, "chardev: parallel: no device path given"); return; } - parallel = backend->u.parallel = g_new0(ChardevHostdev, 1); + parallel = backend->u.parallel.data = g_new0(ChardevHostdev, 1); qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(parallel)); parallel->device = g_strdup(device); } @@ -3575,7 +3620,7 @@ static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend, error_setg(errp, "chardev: pipe: no device path given"); return; } - dev = backend->u.pipe = g_new0(ChardevHostdev, 1); + dev = backend->u.pipe.data = g_new0(ChardevHostdev, 1); qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(dev)); dev->device = g_strdup(device); } @@ -3586,7 +3631,7 @@ static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend, int val; ChardevRingbuf *ringbuf; - ringbuf = backend->u.ringbuf = g_new0(ChardevRingbuf, 1); + ringbuf = backend->u.ringbuf.data = g_new0(ChardevRingbuf, 1); qemu_chr_parse_common(opts, qapi_ChardevRingbuf_base(ringbuf)); val = qemu_opt_get_size(opts, "size", 0); @@ -3606,7 +3651,7 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend, error_setg(errp, "chardev: mux: no chardev given"); return; } - mux = backend->u.mux = g_new0(ChardevMux, 1); + mux = backend->u.mux.data = g_new0(ChardevMux, 1); qemu_chr_parse_common(opts, qapi_ChardevMux_base(mux)); mux->chardev = g_strdup(chardev); } @@ -3642,7 +3687,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, } } - sock = backend->u.socket = g_new0(ChardevSocket, 1); + sock = backend->u.socket.data = g_new0(ChardevSocket, 1); qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock)); sock->has_nodelay = true; @@ -3661,12 +3706,12 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, if (path) { UnixSocketAddress *q_unix; addr->type = SOCKET_ADDRESS_KIND_UNIX; - q_unix = addr->u.q_unix = g_new0(UnixSocketAddress, 1); + q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1); q_unix->path = g_strdup(path); } else { addr->type = SOCKET_ADDRESS_KIND_INET; - addr->u.inet = g_new(InetSocketAddress, 1); - *addr->u.inet = (InetSocketAddress) { + addr->u.inet.data = g_new(InetSocketAddress, 1); + *addr->u.inet.data = (InetSocketAddress) { .host = g_strdup(host), .port = g_strdup(port), .has_to = qemu_opt_get(opts, "to"), @@ -3709,13 +3754,13 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, has_local = true; } - udp = backend->u.udp = g_new0(ChardevUdp, 1); + udp = backend->u.udp.data = g_new0(ChardevUdp, 1); qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp)); addr = g_new0(SocketAddress, 1); addr->type = SOCKET_ADDRESS_KIND_INET; - addr->u.inet = g_new(InetSocketAddress, 1); - *addr->u.inet = (InetSocketAddress) { + addr->u.inet.data = g_new(InetSocketAddress, 1); + *addr->u.inet.data = (InetSocketAddress) { .host = g_strdup(host), .port = g_strdup(port), .has_ipv4 = qemu_opt_get(opts, "ipv4"), @@ -3729,8 +3774,8 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, udp->has_local = true; addr = g_new0(SocketAddress, 1); addr->type = SOCKET_ADDRESS_KIND_INET; - addr->u.inet = g_new(InetSocketAddress, 1); - *addr->u.inet = (InetSocketAddress) { + addr->u.inet.data = g_new(InetSocketAddress, 1); + *addr->u.inet.data = (InetSocketAddress) { .host = g_strdup(localaddr), .port = g_strdup(localport), }; @@ -3817,7 +3862,7 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, } else { ChardevCommon *cc = g_new0(ChardevCommon, 1); qemu_chr_parse_common(opts, cc); - backend->u.null = cc; /* Any ChardevCommon member would work */ + backend->u.null.data = cc; /* Any ChardevCommon member would work */ } ret = qmp_chardev_add(bid ? bid : id, backend, errp); @@ -3829,9 +3874,9 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, qapi_free_ChardevBackend(backend); qapi_free_ChardevReturn(ret); backend = g_new0(ChardevBackend, 1); - backend->u.mux = g_new0(ChardevMux, 1); + backend->u.mux.data = g_new0(ChardevMux, 1); backend->type = CHARDEV_BACKEND_KIND_MUX; - backend->u.mux->chardev = g_strdup(bid); + backend->u.mux.data->chardev = g_strdup(bid); ret = qmp_chardev_add(id, backend, errp); if (!ret) { chr = qemu_chr_find(bid); @@ -3855,7 +3900,8 @@ err: return NULL; } -CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*init)(struct CharDriverState *s)) +CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename, + void (*init)(struct CharDriverState *s)) { const char *p; CharDriverState *chr; @@ -3881,6 +3927,21 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*in return chr; } +CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*init)(struct CharDriverState *s)) +{ + CharDriverState *chr; + chr = qemu_chr_new_noreplay(label, filename, init); + if (chr) { + chr->replay = replay_mode != REPLAY_MODE_NONE; + if (chr->replay && chr->chr_ioctl) { + fprintf(stderr, + "Replay: ioctl is not supported for serial devices yet\n"); + } + replay_register_char_driver(chr); + } + return chr; +} + void qemu_chr_fe_set_echo(struct CharDriverState *chr, bool echo) { if (chr->chr_set_echo) { @@ -4144,7 +4205,7 @@ static CharDriverState *qmp_chardev_open_file(const char *id, ChardevReturn *ret, Error **errp) { - ChardevFile *file = backend->u.file; + ChardevFile *file = backend->u.file.data; ChardevCommon *common = qapi_ChardevFile_base(file); HANDLE out; @@ -4167,7 +4228,7 @@ static CharDriverState *qmp_chardev_open_serial(const char *id, ChardevReturn *ret, Error **errp) { - ChardevHostdev *serial = backend->u.serial; + ChardevHostdev *serial = backend->u.serial.data; ChardevCommon *common = qapi_ChardevHostdev_base(serial); return qemu_chr_open_win_path(serial->device, common, errp); } @@ -4191,7 +4252,7 @@ static CharDriverState *qmp_chardev_open_file(const char *id, ChardevReturn *ret, Error **errp) { - ChardevFile *file = backend->u.file; + ChardevFile *file = backend->u.file.data; ChardevCommon *common = qapi_ChardevFile_base(file); int flags, in = -1, out; @@ -4225,7 +4286,7 @@ static CharDriverState *qmp_chardev_open_serial(const char *id, ChardevReturn *ret, Error **errp) { - ChardevHostdev *serial = backend->u.serial; + ChardevHostdev *serial = backend->u.serial.data; ChardevCommon *common = qapi_ChardevHostdev_base(serial); int fd; @@ -4244,7 +4305,7 @@ static CharDriverState *qmp_chardev_open_parallel(const char *id, ChardevReturn *ret, Error **errp) { - ChardevHostdev *parallel = backend->u.parallel; + ChardevHostdev *parallel = backend->u.parallel.data; ChardevCommon *common = qapi_ChardevHostdev_base(parallel); int fd; @@ -4258,19 +4319,11 @@ static CharDriverState *qmp_chardev_open_parallel(const char *id, #endif /* WIN32 */ -static void socket_try_connect(CharDriverState *chr) -{ - Error *err = NULL; - - if (!qemu_chr_open_socket_fd(chr, &err)) { - check_report_connect_error(chr, err); - } -} - static gboolean socket_reconnect_timeout(gpointer opaque) { CharDriverState *chr = opaque; TCPCharDriver *s = chr->opaque; + QIOChannelSocket *sioc; s->reconnect_timer = 0; @@ -4278,7 +4331,10 @@ static gboolean socket_reconnect_timeout(gpointer opaque) return false; } - socket_try_connect(chr); + sioc = qio_channel_socket_new(); + qio_channel_socket_connect_async(sioc, s->addr, + qemu_chr_socket_connected, + chr, NULL); return false; } @@ -4290,7 +4346,7 @@ static CharDriverState *qmp_chardev_open_socket(const char *id, { CharDriverState *chr; TCPCharDriver *s; - ChardevSocket *sock = backend->u.socket; + 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; @@ -4298,6 +4354,7 @@ static CharDriverState *qmp_chardev_open_socket(const char *id, bool is_waitconnect = sock->has_wait ? sock->wait : false; int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0; ChardevCommon *common = qapi_ChardevSocket_base(sock); + QIOChannelSocket *sioc = NULL; chr = qemu_chr_alloc(common, errp); if (!chr) { @@ -4367,22 +4424,40 @@ static CharDriverState *qmp_chardev_open_socket(const char *id, s->reconnect_time = reconnect; } + sioc = qio_channel_socket_new(); if (s->reconnect_time) { - socket_try_connect(chr); - } else if (!qemu_chr_open_socket_fd(chr, errp)) { - goto error; - } - - if (is_listen && is_waitconnect) { - fprintf(stderr, "QEMU waiting for connection on: %s\n", - chr->filename); - tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr); + qio_channel_socket_connect_async(sioc, s->addr, + qemu_chr_socket_connected, + chr, NULL); + } else if (s->is_listen) { + if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) { + goto error; + } + s->listen_ioc = sioc; + if (is_waitconnect) { + fprintf(stderr, "QEMU waiting for connection on: %s\n", + chr->filename); + tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr); + } qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL); + 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 (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) { + goto error; + } + tcp_chr_new_client(chr, sioc); + object_unref(OBJECT(sioc)); } return chr; error: + if (sioc) { + object_unref(OBJECT(sioc)); + } if (s->tls_creds) { object_unref(OBJECT(s->tls_creds)); } @@ -4396,7 +4471,7 @@ static CharDriverState *qmp_chardev_open_udp(const char *id, ChardevReturn *ret, Error **errp) { - ChardevUdp *udp = backend->u.udp; + ChardevUdp *udp = backend->u.udp.data; ChardevCommon *common = qapi_ChardevUdp_base(udp); QIOChannelSocket *sioc = qio_channel_socket_new(); @@ -4475,6 +4550,11 @@ void qmp_chardev_remove(const char *id, Error **errp) error_setg(errp, "Chardev '%s' is busy", id); return; } + if (chr->replay) { + error_setg(errp, + "Chardev '%s' cannot be unplugged in record/replay mode", id); + return; + } qemu_chr_delete(chr); } |