aboutsummaryrefslogtreecommitdiff
path: root/chardev/char-socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'chardev/char-socket.c')
-rw-r--r--chardev/char-socket.c84
1 files changed, 59 insertions, 25 deletions
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 812d7aa..1e83139 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -33,6 +33,7 @@
#include "qapi/clone-visitor.h"
#include "qapi/qapi-visit-sockets.h"
#include "qemu/yank.h"
+#include "trace.h"
#include "chardev/char-io.h"
#include "chardev/char-socket.h"
@@ -73,7 +74,7 @@ static void qemu_chr_socket_restart_timer(Chardev *chr)
assert(!s->reconnect_timer);
name = g_strdup_printf("chardev-socket-reconnect-%s", chr->label);
s->reconnect_timer = qemu_chr_timeout_add_ms(chr,
- s->reconnect_time * 1000,
+ s->reconnect_time_ms,
socket_reconnect_timeout,
chr);
g_source_set_name(s->reconnect_timer, name);
@@ -126,6 +127,7 @@ static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
if (ret < 0 && errno != EAGAIN) {
if (tcp_chr_read_poll(chr) <= 0) {
/* Perform disconnect and return error. */
+ trace_chr_socket_poll_err(chr, chr->label);
tcp_chr_disconnect_locked(chr);
} /* else let the read handler finish it properly */
}
@@ -279,15 +281,16 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
size_t i;
int *msgfds = NULL;
size_t msgfds_num = 0;
+ Error *err = NULL;
if (qio_channel_has_feature(s->ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
ret = qio_channel_readv_full(s->ioc, &iov, 1,
&msgfds, &msgfds_num,
- 0, NULL);
+ 0, &err);
} else {
ret = qio_channel_readv_full(s->ioc, &iov, 1,
NULL, NULL,
- 0, NULL);
+ 0, &err);
}
if (msgfds_num) {
@@ -322,7 +325,11 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
errno = EAGAIN;
ret = -1;
} else if (ret == -1) {
+ trace_chr_socket_recv_err(chr, chr->label, error_get_pretty(err));
+ error_free(err);
errno = EIO;
+ } else if (ret == 0) {
+ trace_chr_socket_recv_eof(chr, chr->label);
}
return ret;
@@ -463,6 +470,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
SocketChardev *s = SOCKET_CHARDEV(chr);
bool emit_close = s->state == TCP_CHARDEV_STATE_CONNECTED;
+ trace_chr_socket_disconnect(chr, chr->label);
tcp_chr_free_connection(chr);
if (s->listener) {
@@ -473,7 +481,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
if (emit_close) {
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
}
- if (s->reconnect_time && !s->reconnect_timer) {
+ if (s->reconnect_time_ms && !s->reconnect_timer) {
qemu_chr_socket_restart_timer(chr);
}
}
@@ -489,7 +497,7 @@ 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];
+ QEMU_UNINITIALIZED uint8_t buf[CHR_READ_BUF_LEN];
int len, size;
if ((s->state != TCP_CHARDEV_STATE_CONNECTED) ||
@@ -521,6 +529,7 @@ static gboolean tcp_chr_hup(QIOChannel *channel,
void *opaque)
{
Chardev *chr = CHARDEV(opaque);
+ trace_chr_socket_hangup(chr, chr->label);
tcp_chr_disconnect(chr);
return G_SOURCE_REMOVE;
}
@@ -562,9 +571,13 @@ static char *qemu_chr_compute_filename(SocketChardev *s)
switch (ss->ss_family) {
case AF_UNIX:
- return g_strdup_printf("unix:%s%s",
- ((struct sockaddr_un *)(ss))->sun_path,
- s->is_listen ? ",server=on" : "");
+ if (s->is_listen) {
+ return g_strdup_printf("unix:%s,server=on",
+ ((struct sockaddr_un *)(ss))->sun_path);
+ } else {
+ return g_strdup_printf("unix:%s",
+ ((struct sockaddr_un *)(ps))->sun_path);
+ }
case AF_INET6:
left = "[";
right = "]";
@@ -672,15 +685,18 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
SocketChardev *s = user_data;
Chardev *chr = CHARDEV(s);
TCPChardevTelnetInit *init = s->telnet_init;
+ Error *err = NULL;
ssize_t ret;
assert(init);
- ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
+ ret = qio_channel_write(ioc, init->buf, init->buflen, &err);
if (ret < 0) {
if (ret == QIO_CHANNEL_ERR_BLOCK) {
ret = 0;
} else {
+ trace_chr_socket_write_err(chr, chr->label, error_get_pretty(err));
+ error_free(err);
tcp_chr_disconnect(chr);
goto end;
}
@@ -765,9 +781,9 @@ static void tcp_chr_websock_handshake(QIOTask *task, gpointer user_data)
Error *err = NULL;
if (qio_task_propagate_error(task, &err)) {
- error_reportf_err(err,
- "websock handshake of character device %s failed: ",
- chr->label);
+ trace_chr_socket_ws_handshake_err(chr, chr->label,
+ error_get_pretty(err));
+ error_free(err);
tcp_chr_disconnect(chr);
} else {
if (s->do_telnetopt) {
@@ -805,9 +821,9 @@ static void tcp_chr_tls_handshake(QIOTask *task,
Error *err = NULL;
if (qio_task_propagate_error(task, &err)) {
- error_reportf_err(err,
- "TLS handshake of character device %s failed: ",
- chr->label);
+ trace_chr_socket_tls_handshake_err(chr, chr->label,
+ error_get_pretty(err));
+ error_free(err);
tcp_chr_disconnect(chr);
} else {
if (s->is_websock) {
@@ -826,19 +842,22 @@ static void tcp_chr_tls_init(Chardev *chr)
SocketChardev *s = SOCKET_CHARDEV(chr);
QIOChannelTLS *tioc;
gchar *name;
+ Error *err = NULL;
if (s->is_listen) {
tioc = qio_channel_tls_new_server(
s->ioc, s->tls_creds,
s->tls_authz,
- NULL);
+ &err);
} else {
tioc = qio_channel_tls_new_client(
s->ioc, s->tls_creds,
s->addr->u.inet.host,
- NULL);
+ &err);
}
if (tioc == NULL) {
+ trace_chr_socket_tls_init_err(chr, chr->label, error_get_pretty(err));
+ error_free(err);
tcp_chr_disconnect(chr);
return;
}
@@ -1065,9 +1084,9 @@ static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
} else {
Error *err = NULL;
if (tcp_chr_connect_client_sync(chr, &err) < 0) {
- if (s->reconnect_time) {
+ if (s->reconnect_time_ms) {
error_free(err);
- g_usleep(s->reconnect_time * 1000ULL * 1000ULL);
+ g_usleep(s->reconnect_time_ms * 1000ULL);
} else {
error_propagate(errp, err);
return -1;
@@ -1252,13 +1271,13 @@ skip_listen:
static int qmp_chardev_open_socket_client(Chardev *chr,
- int64_t reconnect,
+ int64_t reconnect_ms,
Error **errp)
{
SocketChardev *s = SOCKET_CHARDEV(chr);
- if (reconnect > 0) {
- s->reconnect_time = reconnect;
+ if (reconnect_ms > 0) {
+ s->reconnect_time_ms = reconnect_ms;
tcp_chr_connect_client_async(chr);
return 0;
} else {
@@ -1339,6 +1358,12 @@ static bool qmp_chardev_validate_socket(ChardevSocket *sock,
}
}
+ if (sock->has_reconnect_ms && sock->has_reconnect) {
+ error_setg(errp,
+ "'reconnect' and 'reconnect-ms' are mutually exclusive");
+ return false;
+ }
+
return true;
}
@@ -1356,7 +1381,7 @@ static void qmp_chardev_open_socket(Chardev *chr,
bool is_tn3270 = sock->has_tn3270 ? sock->tn3270 : false;
bool is_waitconnect = sock->has_wait ? sock->wait : false;
bool is_websock = sock->has_websocket ? sock->websocket : false;
- int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
+ int64_t reconnect_ms = 0;
SocketAddress *addr;
s->is_listen = is_listen;
@@ -1428,7 +1453,13 @@ static void qmp_chardev_open_socket(Chardev *chr,
return;
}
} else {
- if (qmp_chardev_open_socket_client(chr, reconnect, errp) < 0) {
+ if (sock->has_reconnect) {
+ reconnect_ms = sock->reconnect * 1000ULL;
+ } else if (sock->has_reconnect_ms) {
+ reconnect_ms = sock->reconnect_ms;
+ }
+
+ if (qmp_chardev_open_socket_client(chr, reconnect_ms, errp) < 0) {
return;
}
}
@@ -1494,6 +1525,9 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
sock->wait = qemu_opt_get_bool(opts, "wait", true);
sock->has_reconnect = qemu_opt_find(opts, "reconnect");
sock->reconnect = qemu_opt_get_number(opts, "reconnect", 0);
+ sock->has_reconnect_ms = qemu_opt_find(opts, "reconnect-ms");
+ sock->reconnect_ms = qemu_opt_get_number(opts, "reconnect-ms", 0);
+
sock->tls_creds = g_strdup(qemu_opt_get(opts, "tls-creds"));
sock->tls_authz = g_strdup(qemu_opt_get(opts, "tls-authz"));
@@ -1547,7 +1581,7 @@ char_socket_get_connected(Object *obj, Error **errp)
return s->state == TCP_CHARDEV_STATE_CONNECTED;
}
-static void char_socket_class_init(ObjectClass *oc, void *data)
+static void char_socket_class_init(ObjectClass *oc, const void *data)
{
ChardevClass *cc = CHARDEV_CLASS(oc);