static void test_io_channel_setup_sync(SocketAddress *listen_addr, SocketAddress *connect_addr, QIOChannel **src, QIOChannel **dst) { QIOChannelSocket *lioc; lioc = qio_channel_socket_new(); qio_channel_socket_listen_sync(lioc, listen_addr, &error_abort); if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) { SocketAddress *laddr = qio_channel_socket_get_local_address( lioc, &error_abort); g_free(connect_addr->u.inet.port); connect_addr->u.inet.port = g_strdup(laddr->u.inet.port); qapi_free_SocketAddress(laddr); } *src = QIO_CHANNEL(qio_channel_socket_new()); qio_channel_socket_connect_sync( QIO_CHANNEL_SOCKET(*src), connect_addr, &error_abort); qio_channel_set_delay(*src, false); qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN); *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort)); g_assert(*dst); test_io_channel_set_socket_bufs(*src, *dst); object_unref(OBJECT(lioc)); }
static gboolean socket_accept_incoming_migration(QIOChannel *ioc, GIOCondition condition, gpointer opaque) { QIOChannelSocket *sioc; Error *err = NULL; sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), &err); if (!sioc) { error_report("could not accept migration connection (%s)", error_get_pretty(err)); goto out; } trace_migration_socket_incoming_accepted(); qio_channel_set_name(QIO_CHANNEL(sioc), "migration-socket-incoming"); migration_channel_process_incoming(migrate_get_current(), QIO_CHANNEL(sioc)); object_unref(OBJECT(sioc)); out: /* Close listening socket as its no longer needed */ qio_channel_close(ioc, NULL); return FALSE; /* unregister */ }
static int qio_channel_socket_shutdown(QIOChannel *ioc, QIOChannelShutdown how, Error **errp) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); int sockhow; switch (how) { case QIO_CHANNEL_SHUTDOWN_READ: sockhow = SHUT_RD; break; case QIO_CHANNEL_SHUTDOWN_WRITE: sockhow = SHUT_WR; break; case QIO_CHANNEL_SHUTDOWN_BOTH: default: sockhow = SHUT_RDWR; break; } if (shutdown(sioc->fd, sockhow) < 0) { error_setg_errno(errp, errno, "Unable to shutdown socket"); return -1; } return 0; }
static GSource *qio_channel_socket_create_watch(QIOChannel *ioc, GIOCondition condition) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); return qio_channel_create_socket_watch(ioc, sioc->fd, condition); }
static void qio_channel_socket_set_aio_fd_handler(QIOChannel *ioc, AioContext *ctx, IOHandler *io_read, IOHandler *io_write, void *opaque) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); aio_set_fd_handler(ctx, sioc->fd, false, io_read, io_write, NULL, opaque); }
static void qio_channel_socket_set_cork(QIOChannel *ioc, bool enabled) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); int v = enabled ? 1 : 0; socket_set_cork(sioc->fd, v); }
static void qio_channel_socket_listen_worker(QIOTask *task, gpointer opaque) { QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task)); SocketAddress *addr = opaque; Error *err = NULL; qio_channel_socket_listen_sync(ioc, addr, &err); qio_task_set_error(task, err); }
static void qio_channel_socket_finalize(Object *obj) { QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(obj); if (ioc->fd != -1) { #ifdef WIN32 WSAEventSelect(ioc->fd, NULL, 0); #endif closesocket(ioc->fd); ioc->fd = -1; } }
static void qio_channel_socket_set_delay(QIOChannel *ioc, bool enabled) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); int v = enabled ? 0 : 1; qemu_setsockopt(sioc->fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); }
static void test_io_channel_setup_async(SocketAddress *listen_addr, SocketAddress *connect_addr, QIOChannel **srv, QIOChannel **src, QIOChannel **dst) { QIOChannelSocket *lioc; struct TestIOChannelData data; data.loop = g_main_loop_new(g_main_context_default(), TRUE); lioc = qio_channel_socket_new(); qio_channel_socket_listen_async( lioc, listen_addr, test_io_channel_complete, &data, NULL, NULL); g_main_loop_run(data.loop); g_main_context_iteration(g_main_context_default(), FALSE); g_assert(!data.err); if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) { SocketAddress *laddr = qio_channel_socket_get_local_address( lioc, &error_abort); g_free(connect_addr->u.inet.port); connect_addr->u.inet.port = g_strdup(laddr->u.inet.port); qapi_free_SocketAddress(laddr); } *src = QIO_CHANNEL(qio_channel_socket_new()); qio_channel_socket_connect_async( QIO_CHANNEL_SOCKET(*src), connect_addr, test_io_channel_complete, &data, NULL, NULL); g_main_loop_run(data.loop); g_main_context_iteration(g_main_context_default(), FALSE); g_assert(!data.err); qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN); *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort)); g_assert(*dst); qio_channel_set_delay(*src, false); test_io_channel_set_socket_bufs(*src, *dst); *srv = QIO_CHANNEL(lioc); g_main_loop_unref(data.loop); }
static ssize_t qio_channel_socket_writev(QIOChannel *ioc, const struct iovec *iov, size_t niov, int *fds, size_t nfds, Error **errp) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); ssize_t ret; struct msghdr msg = { NULL, }; char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)]; size_t fdsize = sizeof(int) * nfds; struct cmsghdr *cmsg; memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)); msg.msg_iov = (struct iovec *)iov; msg.msg_iovlen = niov; if (nfds) { if (nfds > SOCKET_MAX_FDS) { error_setg_errno(errp, EINVAL, "Only %d FDs can be sent, got %zu", SOCKET_MAX_FDS, nfds); return -1; } msg.msg_control = control; msg.msg_controllen = CMSG_SPACE(sizeof(int) * nfds); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(fdsize); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; memcpy(CMSG_DATA(cmsg), fds, fdsize); } retry: ret = sendmsg(sioc->fd, &msg, 0); if (ret <= 0) { if (errno == EAGAIN) { return QIO_CHANNEL_ERR_BLOCK; } if (errno == EINTR) { goto retry; } error_setg_errno(errp, errno, "Unable to write to socket"); return -1; } return ret; }
static void qio_channel_socket_dgram_worker(QIOTask *task, gpointer opaque) { QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task)); struct QIOChannelSocketDGramWorkerData *data = opaque; Error *err = NULL; /* socket_dgram() blocks in DNS lookups, so we must use a thread */ qio_channel_socket_dgram_sync(ioc, data->localAddr, data->remoteAddr, &err); qio_task_set_error(task, err); }
static int qio_channel_socket_set_blocking(QIOChannel *ioc, bool enabled, Error **errp) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); if (enabled) { qemu_set_block(sioc->fd); } else { qemu_set_nonblock(sioc->fd); } return 0; }
QIOChannelSocket * qio_channel_socket_accept(QIOChannelSocket *ioc, Error **errp) { QIOChannelSocket *cioc; cioc = QIO_CHANNEL_SOCKET(object_new(TYPE_QIO_CHANNEL_SOCKET)); cioc->fd = -1; cioc->remoteAddrLen = sizeof(ioc->remoteAddr); cioc->localAddrLen = sizeof(ioc->localAddr); #ifdef WIN32 QIO_CHANNEL(cioc)->event = CreateEvent(NULL, FALSE, FALSE, NULL); #endif retry: trace_qio_channel_socket_accept(ioc); cioc->fd = qemu_accept(ioc->fd, (struct sockaddr *)&cioc->remoteAddr, &cioc->remoteAddrLen); if (cioc->fd < 0) { trace_qio_channel_socket_accept_fail(ioc); if (errno == EINTR) { goto retry; } goto error; } if (getsockname(cioc->fd, (struct sockaddr *)&cioc->localAddr, &cioc->localAddrLen) < 0) { error_setg_errno(errp, errno, "Unable to query local socket address"); goto error; } #ifndef WIN32 if (cioc->localAddr.ss_family == AF_UNIX) { QIOChannel *ioc_local = QIO_CHANNEL(cioc); qio_channel_set_feature(ioc_local, QIO_CHANNEL_FEATURE_FD_PASS); } #endif /* WIN32 */ trace_qio_channel_socket_accept_complete(ioc, cioc, cioc->fd); return cioc; error: object_unref(OBJECT(cioc)); return NULL; }
static int qio_channel_socket_listen_worker(QIOTask *task, Error **errp, gpointer opaque) { QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task)); SocketAddress *addr = opaque; int ret; ret = qio_channel_socket_listen_sync(ioc, addr, errp); object_unref(OBJECT(ioc)); return ret; }
static ssize_t qio_channel_socket_readv(QIOChannel *ioc, const struct iovec *iov, size_t niov, int **fds, size_t *nfds, Error **errp) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); ssize_t ret; struct msghdr msg = { NULL, }; char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)]; int sflags = 0; memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)); #ifdef MSG_CMSG_CLOEXEC sflags |= MSG_CMSG_CLOEXEC; #endif msg.msg_iov = (struct iovec *)iov; msg.msg_iovlen = niov; if (fds && nfds) { msg.msg_control = control; msg.msg_controllen = sizeof(control); } retry: ret = recvmsg(sioc->fd, &msg, sflags); if (ret < 0) { if (errno == EAGAIN) { return QIO_CHANNEL_ERR_BLOCK; } if (errno == EINTR) { goto retry; } error_setg_errno(errp, errno, "Unable to read from socket"); return -1; } if (fds && nfds) { qio_channel_socket_copy_fds(&msg, fds, nfds); } return ret; }
static int qio_channel_socket_dgram_worker(QIOTask *task, Error **errp, gpointer opaque) { QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task)); struct QIOChannelSocketDGramWorkerData *data = opaque; int ret; /* socket_dgram() blocks in DNS lookups, so we must use a thread */ ret = qio_channel_socket_dgram_sync(ioc, data->localAddr, data->remoteAddr, errp); object_unref(OBJECT(ioc)); return ret; }
static int qio_channel_socket_set_blocking(QIOChannel *ioc, bool enabled, Error **errp) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); if (enabled) { qemu_set_block(sioc->fd); } else { qemu_set_nonblock(sioc->fd); #ifdef WIN32 WSAEventSelect(sioc->fd, ioc->event, FD_READ | FD_ACCEPT | FD_CLOSE | FD_CONNECT | FD_WRITE | FD_OOB); #endif } return 0; }
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 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 int qio_channel_socket_close(QIOChannel *ioc, Error **errp) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); if (sioc->fd != -1) { #ifdef WIN32 WSAEventSelect(sioc->fd, NULL, 0); #endif if (closesocket(sioc->fd) < 0) { sioc->fd = -1; error_setg_errno(errp, errno, "Unable to close socket"); return -1; } sioc->fd = -1; } return 0; }
QIOChannelSocket * qio_channel_socket_new(void) { QIOChannelSocket *sioc; QIOChannel *ioc; sioc = QIO_CHANNEL_SOCKET(object_new(TYPE_QIO_CHANNEL_SOCKET)); sioc->fd = -1; ioc = QIO_CHANNEL(sioc); qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN); #ifdef WIN32 ioc->event = CreateEvent(NULL, FALSE, FALSE, NULL); #endif trace_qio_channel_socket_new(sioc); return sioc; }
static ssize_t qio_channel_socket_writev(QIOChannel *ioc, const struct iovec *iov, size_t niov, int *fds, size_t nfds, Error **errp) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); ssize_t done = 0; ssize_t i; for (i = 0; i < niov; i++) { ssize_t ret; retry: ret = send(sioc->fd, iov[i].iov_base, iov[i].iov_len, 0); if (ret < 0) { if (errno == EAGAIN) { if (done) { return done; } else { return QIO_CHANNEL_ERR_BLOCK; } } else if (errno == EINTR) { goto retry; } else { error_setg_errno(errp, errno, "Unable to write to socket"); return -1; } } done += ret; if (ret < iov[i].iov_len) { return done; } } return done; }
static gboolean nbd_accept(QIOChannel *ioc, GIOCondition condition, gpointer opaque) { QIOChannelSocket *cioc; if (!nbd_server) { return FALSE; } cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), NULL); if (!cioc) { return TRUE; } qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server"); nbd_client_new(NULL, cioc, nbd_server->tlscreds, NULL, nbd_blockdev_client_closed); object_unref(OBJECT(cioc)); return TRUE; }
static void qio_channel_socket_finalize(Object *obj) { QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(obj); if (ioc->fd != -1) { QIOChannel *ioc_local = QIO_CHANNEL(ioc); if (qio_channel_has_feature(ioc_local, QIO_CHANNEL_FEATURE_LISTEN)) { Error *err = NULL; socket_listen_cleanup(ioc->fd, &err); if (err) { error_report_err(err); err = NULL; } } #ifdef WIN32 WSAEventSelect(ioc->fd, NULL, 0); #endif closesocket(ioc->fd); ioc->fd = -1; } }
static gboolean nbd_accept(QIOChannel *ioc, GIOCondition cond, gpointer opaque) { QIOChannelSocket *cioc; cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), NULL); if (!cioc) { return TRUE; } if (state >= TERMINATE) { object_unref(OBJECT(cioc)); return TRUE; } nb_fds++; nbd_update_server_watch(); nbd_client_new(newproto ? NULL : exp, cioc, tlscreds, NULL, nbd_client_closed); object_unref(OBJECT(cioc)); return TRUE; }
static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts) { const char *value; value = qemu_opt_get(opts, "chardev"); if (value) { Error *err = NULL; Chardev *dev = qemu_chr_find(value); if (!dev) { error_report("tpm-emulator: tpm chardev '%s' not found.", value); goto err; } if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) { error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':", value); error_report_err(err); goto err; } tpm_emu->options->chardev = g_strdup(value); } if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) { goto err; } /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used * by passthrough driver, which not yet using GIOChannel. */ if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd, &tpm_emu->tpm_version)) { error_report("'%s' is not emulating TPM device. Error: %s", tpm_emu->options->chardev, strerror(errno)); goto err; } switch (tpm_emu->tpm_version) { case TPM_VERSION_1_2: trace_tpm_emulator_handle_device_opts_tpm12(); break; case TPM_VERSION_2_0: trace_tpm_emulator_handle_device_opts_tpm2(); break; default: trace_tpm_emulator_handle_device_opts_unspec(); } if (tpm_emulator_probe_caps(tpm_emu) || tpm_emulator_check_caps(tpm_emu)) { goto err; } return tpm_emulator_block_migration(tpm_emu); err: trace_tpm_emulator_handle_device_opts_startup_error(); return -1; }
static void qio_channel_socket_init(Object *obj) { QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(obj); ioc->fd = -1; }