aboutsummaryrefslogtreecommitdiff
path: root/io
diff options
context:
space:
mode:
Diffstat (limited to 'io')
-rw-r--r--io/channel-buffer.c2
-rw-r--r--io/channel-command.c11
-rw-r--r--io/channel-file.c5
-rw-r--r--io/channel-null.c2
-rw-r--r--io/channel-socket.c82
-rw-r--r--io/channel-tls.c30
-rw-r--r--io/channel-watch.c6
-rw-r--r--io/channel-websock.c5
-rw-r--r--io/channel.c4
-rw-r--r--io/dns-resolver.c21
10 files changed, 115 insertions, 53 deletions
diff --git a/io/channel-buffer.c b/io/channel-buffer.c
index 8096180..189fa67 100644
--- a/io/channel-buffer.c
+++ b/io/channel-buffer.c
@@ -225,7 +225,7 @@ static GSource *qio_channel_buffer_create_watch(QIOChannel *ioc,
static void qio_channel_buffer_class_init(ObjectClass *klass,
- void *class_data G_GNUC_UNUSED)
+ const void *class_data G_GNUC_UNUSED)
{
QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
diff --git a/io/channel-command.c b/io/channel-command.c
index 6d5f64e..8ae9a02 100644
--- a/io/channel-command.c
+++ b/io/channel-command.c
@@ -277,9 +277,12 @@ static int qio_channel_command_set_blocking(QIOChannel *ioc,
cioc->blocking = enabled;
#else
- if ((cioc->writefd >= 0 && !g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL)) ||
- (cioc->readfd >= 0 && !g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL))) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (cioc->writefd >= 0 &&
+ !qemu_set_blocking(cioc->writefd, enabled, errp)) {
+ return -1;
+ }
+ if (cioc->readfd >= 0 &&
+ !qemu_set_blocking(cioc->readfd, enabled, errp)) {
return -1;
}
#endif
@@ -358,7 +361,7 @@ static GSource *qio_channel_command_create_watch(QIOChannel *ioc,
static void qio_channel_command_class_init(ObjectClass *klass,
- void *class_data G_GNUC_UNUSED)
+ const void *class_data G_GNUC_UNUSED)
{
QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
diff --git a/io/channel-file.c b/io/channel-file.c
index 2ea8d08..5cef75a 100644
--- a/io/channel-file.c
+++ b/io/channel-file.c
@@ -223,8 +223,7 @@ static int qio_channel_file_set_blocking(QIOChannel *ioc,
#else
QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
- if (!g_unix_set_fd_nonblocking(fioc->fd, !enabled, NULL)) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (!qemu_set_blocking(fioc->fd, enabled, errp)) {
return -1;
}
return 0;
@@ -290,7 +289,7 @@ static GSource *qio_channel_file_create_watch(QIOChannel *ioc,
}
static void qio_channel_file_class_init(ObjectClass *klass,
- void *class_data G_GNUC_UNUSED)
+ const void *class_data G_GNUC_UNUSED)
{
QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
diff --git a/io/channel-null.c b/io/channel-null.c
index ef99586..49f1c80 100644
--- a/io/channel-null.c
+++ b/io/channel-null.c
@@ -207,7 +207,7 @@ qio_channel_null_create_watch(QIOChannel *ioc,
static void
qio_channel_null_class_init(ObjectClass *klass,
- void *class_data G_GNUC_UNUSED)
+ const void *class_data G_GNUC_UNUSED)
{
QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
diff --git a/io/channel-socket.c b/io/channel-socket.c
index 608bcf0..712b793 100644
--- a/io/channel-socket.c
+++ b/io/channel-socket.c
@@ -78,6 +78,17 @@ qio_channel_socket_new(void)
return sioc;
}
+int qio_channel_socket_set_send_buffer(QIOChannelSocket *ioc,
+ size_t size,
+ Error **errp)
+{
+ if (setsockopt(ioc->fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0) {
+ error_setg_errno(errp, errno, "Unable to set socket send buffer size");
+ return -1;
+ }
+
+ return 0;
+}
static int
qio_channel_socket_set_fd(QIOChannelSocket *sioc,
@@ -443,7 +454,7 @@ static void qio_channel_socket_finalize(Object *obj)
}
}
#ifdef WIN32
- qemu_socket_unselect(ioc->fd, NULL);
+ qemu_socket_unselect_nofail(ioc->fd);
#endif
close(ioc->fd);
ioc->fd = -1;
@@ -461,7 +472,7 @@ static void qio_channel_socket_copy_fds(struct msghdr *msg,
*fds = NULL;
for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
- int fd_size, i;
+ int fd_size;
int gotfds;
if (cmsg->cmsg_len < CMSG_LEN(sizeof(int)) ||
@@ -479,22 +490,53 @@ static void qio_channel_socket_copy_fds(struct msghdr *msg,
gotfds = fd_size / sizeof(int);
*fds = g_renew(int, *fds, *nfds + gotfds);
memcpy(*fds + *nfds, CMSG_DATA(cmsg), fd_size);
+ *nfds += gotfds;
+ }
+}
- for (i = 0; i < gotfds; i++) {
- int fd = (*fds)[*nfds + i];
- if (fd < 0) {
- continue;
- }
+static bool qio_channel_handle_fds(int *fds, size_t nfds,
+ bool preserve_blocking, Error **errp)
+{
+ int *end = fds + nfds, *fd;
+
+#ifdef MSG_CMSG_CLOEXEC
+ if (preserve_blocking) {
+ /* Nothing to do */
+ return true;
+ }
+#endif
+
+ for (fd = fds; fd != end; fd++) {
+ if (*fd < 0) {
+ continue;
+ }
+ if (!preserve_blocking) {
/* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
- qemu_socket_set_block(fd);
+ if (!qemu_set_blocking(*fd, true, errp)) {
+ return false;
+ }
+ }
#ifndef MSG_CMSG_CLOEXEC
- qemu_set_cloexec(fd);
+ qemu_set_cloexec(*fd);
#endif
+ }
+
+ return true;
+}
+
+static void qio_channel_cleanup_fds(int **fds, size_t *nfds)
+{
+ for (size_t i = 0; i < *nfds; i++) {
+ if ((*fds)[i] < 0) {
+ continue;
}
- *nfds += gotfds;
+ close((*fds)[i]);
}
+
+ g_clear_pointer(fds, g_free);
+ *nfds = 0;
}
@@ -545,7 +587,16 @@ static ssize_t qio_channel_socket_readv(QIOChannel *ioc,
}
if (fds && nfds) {
+ bool preserve_blocking =
+ flags & QIO_CHANNEL_READ_FLAG_FD_PRESERVE_BLOCKING;
+
qio_channel_socket_copy_fds(&msg, fds, nfds);
+
+ if (!qio_channel_handle_fds(*fds, *nfds,
+ preserve_blocking, errp)) {
+ qio_channel_cleanup_fds(fds, nfds);
+ return -1;
+ }
}
return ret;
@@ -809,11 +860,10 @@ qio_channel_socket_set_blocking(QIOChannel *ioc,
{
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
- if (enabled) {
- qemu_socket_set_block(sioc->fd);
- } else {
- qemu_socket_set_nonblock(sioc->fd);
+ if (!qemu_set_blocking(sioc->fd, enabled, errp)) {
+ return -1;
}
+
return 0;
}
@@ -879,7 +929,7 @@ qio_channel_socket_close(QIOChannel *ioc,
if (sioc->fd != -1) {
#ifdef WIN32
- qemu_socket_unselect(sioc->fd, NULL);
+ qemu_socket_unselect_nofail(sioc->fd);
#endif
if (qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_LISTEN)) {
socket_listen_cleanup(sioc->fd, errp);
@@ -949,7 +999,7 @@ static GSource *qio_channel_socket_create_watch(QIOChannel *ioc,
}
static void qio_channel_socket_class_init(ObjectClass *klass,
- void *class_data G_GNUC_UNUSED)
+ const void *class_data G_GNUC_UNUSED)
{
QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
diff --git a/io/channel-tls.c b/io/channel-tls.c
index caf8301..1fbed4b 100644
--- a/io/channel-tls.c
+++ b/io/channel-tls.c
@@ -241,6 +241,11 @@ void qio_channel_tls_handshake(QIOChannelTLS *ioc,
{
QIOTask *task;
+ if (qio_channel_has_feature(QIO_CHANNEL(ioc),
+ QIO_CHANNEL_FEATURE_CONCURRENT_IO)) {
+ qcrypto_tls_session_require_thread_safety(ioc->session);
+ }
+
task = qio_task_new(OBJECT(ioc),
func, opaque, destroy);
@@ -341,6 +346,19 @@ static void qio_channel_tls_finalize(Object *obj)
qcrypto_tls_session_free(ioc->session);
}
+static bool
+qio_channel_tls_allow_premature_termination(QIOChannelTLS *tioc, int flags)
+{
+ if (flags & QIO_CHANNEL_READ_FLAG_RELAXED_EOF) {
+ return true;
+ }
+
+ if (qatomic_read(&tioc->shutdown) & QIO_CHANNEL_SHUTDOWN_READ) {
+ return true;
+ }
+
+ return false;
+}
static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
const struct iovec *iov,
@@ -359,8 +377,6 @@ static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
tioc->session,
iov[i].iov_base,
iov[i].iov_len,
- flags & QIO_CHANNEL_READ_FLAG_RELAXED_EOF ||
- qatomic_load_acquire(&tioc->shutdown) & QIO_CHANNEL_SHUTDOWN_READ,
errp);
if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
if (got) {
@@ -368,6 +384,12 @@ static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
} else {
return QIO_CHANNEL_ERR_BLOCK;
}
+ } else if (ret == QCRYPTO_TLS_SESSION_PREMATURE_TERMINATION) {
+ if (qio_channel_tls_allow_premature_termination(tioc, flags)) {
+ ret = 0;
+ } else {
+ return -1;
+ }
} else if (ret < 0) {
return -1;
}
@@ -420,7 +442,7 @@ static int qio_channel_tls_set_blocking(QIOChannel *ioc,
{
QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
- return qio_channel_set_blocking(tioc->master, enabled, errp);
+ return qio_channel_set_blocking(tioc->master, enabled, errp) ? 0 : -1;
}
static void qio_channel_tls_set_delay(QIOChannel *ioc,
@@ -561,7 +583,7 @@ qio_channel_tls_get_session(QIOChannelTLS *ioc)
}
static void qio_channel_tls_class_init(ObjectClass *klass,
- void *class_data G_GNUC_UNUSED)
+ const void *class_data G_GNUC_UNUSED)
{
QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
diff --git a/io/channel-watch.c b/io/channel-watch.c
index 64b486e..018648b 100644
--- a/io/channel-watch.c
+++ b/io/channel-watch.c
@@ -281,9 +281,9 @@ GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
GSource *source;
QIOChannelSocketSource *ssource;
- qemu_socket_select(sockfd, ioc->event,
- FD_READ | FD_ACCEPT | FD_CLOSE |
- FD_CONNECT | FD_WRITE | FD_OOB, NULL);
+ qemu_socket_select_nofail(sockfd, ioc->event,
+ FD_READ | FD_ACCEPT | FD_CLOSE |
+ FD_CONNECT | FD_WRITE | FD_OOB);
source = g_source_new(&qio_channel_socket_source_funcs,
sizeof(QIOChannelSocketSource));
diff --git a/io/channel-websock.c b/io/channel-websock.c
index 55192b7..0a8c5c4 100644
--- a/io/channel-websock.c
+++ b/io/channel-websock.c
@@ -1184,8 +1184,7 @@ static int qio_channel_websock_set_blocking(QIOChannel *ioc,
{
QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
- qio_channel_set_blocking(wioc->master, enabled, errp);
- return 0;
+ return qio_channel_set_blocking(wioc->master, enabled, errp) ? 0 : -1;
}
static void qio_channel_websock_set_delay(QIOChannel *ioc,
@@ -1308,7 +1307,7 @@ static GSource *qio_channel_websock_create_watch(QIOChannel *ioc,
}
static void qio_channel_websock_class_init(ObjectClass *klass,
- void *class_data G_GNUC_UNUSED)
+ const void *class_data G_GNUC_UNUSED)
{
QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
diff --git a/io/channel.c b/io/channel.c
index ebd9322..852e684 100644
--- a/io/channel.c
+++ b/io/channel.c
@@ -359,12 +359,12 @@ int coroutine_mixed_fn qio_channel_write_all(QIOChannel *ioc,
}
-int qio_channel_set_blocking(QIOChannel *ioc,
+bool qio_channel_set_blocking(QIOChannel *ioc,
bool enabled,
Error **errp)
{
QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
- return klass->io_set_blocking(ioc, enabled, errp);
+ return klass->io_set_blocking(ioc, enabled, errp) == 0;
}
diff --git a/io/dns-resolver.c b/io/dns-resolver.c
index 53b0e84..3712438 100644
--- a/io/dns-resolver.c
+++ b/io/dns-resolver.c
@@ -111,22 +111,11 @@ static int qio_dns_resolver_lookup_sync_inet(QIODNSResolver *resolver,
uaddr, INET6_ADDRSTRLEN, uport, 32,
NI_NUMERICHOST | NI_NUMERICSERV);
- newaddr->u.inet = (InetSocketAddress){
- .host = g_strdup(uaddr),
- .port = g_strdup(uport),
- .has_numeric = true,
- .numeric = true,
- .has_to = iaddr->has_to,
- .to = iaddr->to,
- .has_ipv4 = iaddr->has_ipv4,
- .ipv4 = iaddr->ipv4,
- .has_ipv6 = iaddr->has_ipv6,
- .ipv6 = iaddr->ipv6,
-#ifdef HAVE_IPPROTO_MPTCP
- .has_mptcp = iaddr->has_mptcp,
- .mptcp = iaddr->mptcp,
-#endif
- };
+ newaddr->u.inet = *iaddr;
+ newaddr->u.inet.host = g_strdup(uaddr),
+ newaddr->u.inet.port = g_strdup(uport),
+ newaddr->u.inet.has_numeric = true,
+ newaddr->u.inet.numeric = true,
(*addrs)[i] = newaddr;
}