diff options
Diffstat (limited to 'include/io')
-rw-r--r-- | include/io/channel-buffer.h | 59 | ||||
-rw-r--r-- | include/io/channel-command.h | 90 | ||||
-rw-r--r-- | include/io/channel-file.h | 92 | ||||
-rw-r--r-- | include/io/channel-socket.h | 263 | ||||
-rw-r--r-- | include/io/channel-tls.h | 145 | ||||
-rw-r--r-- | include/io/channel-util.h | 52 | ||||
-rw-r--r-- | include/io/channel-watch.h | 90 | ||||
-rw-r--r-- | include/io/channel-websock.h | 108 | ||||
-rw-r--r-- | include/io/channel.h | 858 | ||||
-rw-r--r-- | include/io/dns-resolver.h | 219 | ||||
-rw-r--r-- | include/io/net-listener.h | 186 | ||||
-rw-r--r-- | include/io/task.h | 350 |
12 files changed, 2512 insertions, 0 deletions
diff --git a/include/io/channel-buffer.h b/include/io/channel-buffer.h new file mode 100644 index 000000000..c9463ee65 --- /dev/null +++ b/include/io/channel-buffer.h @@ -0,0 +1,59 @@ +/* + * QEMU I/O channels memory buffer driver + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QIO_CHANNEL_BUFFER_H +#define QIO_CHANNEL_BUFFER_H + +#include "io/channel.h" +#include "qom/object.h" + +#define TYPE_QIO_CHANNEL_BUFFER "qio-channel-buffer" +OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelBuffer, QIO_CHANNEL_BUFFER) + + +/** + * QIOChannelBuffer: + * + * The QIOChannelBuffer object provides a channel implementation + * that is able to perform I/O to/from a memory buffer. + * + */ + +struct QIOChannelBuffer { + QIOChannel parent; + size_t capacity; /* Total allocated memory */ + size_t usage; /* Current size of data */ + size_t offset; /* Offset for future I/O ops */ + uint8_t *data; +}; + + +/** + * qio_channel_buffer_new: + * @capacity: the initial buffer capacity to allocate + * + * Allocate a new buffer which is initially empty + * + * Returns: the new channel object + */ +QIOChannelBuffer * +qio_channel_buffer_new(size_t capacity); + +#endif /* QIO_CHANNEL_BUFFER_H */ diff --git a/include/io/channel-command.h b/include/io/channel-command.h new file mode 100644 index 000000000..27e42bdad --- /dev/null +++ b/include/io/channel-command.h @@ -0,0 +1,90 @@ +/* + * QEMU I/O channels external command driver + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QIO_CHANNEL_COMMAND_H +#define QIO_CHANNEL_COMMAND_H + +#include "io/channel.h" +#include "qom/object.h" + +#define TYPE_QIO_CHANNEL_COMMAND "qio-channel-command" +OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelCommand, QIO_CHANNEL_COMMAND) + + + +/** + * QIOChannelCommand: + * + * The QIOChannelCommand class provides a channel implementation + * that can transport data with an externally running command + * via its stdio streams. + */ + +struct QIOChannelCommand { + QIOChannel parent; + int writefd; + int readfd; + pid_t pid; +}; + + +/** + * qio_channel_command_new_pid: + * @writefd: the FD connected to the command's stdin + * @readfd: the FD connected to the command's stdout + * @pid: the PID of the running child command + * @errp: pointer to a NULL-initialized error object + * + * Create a channel for performing I/O with the + * previously spawned command identified by @pid. + * The two file descriptors provide the connection + * to command's stdio streams, either one or which + * may be -1 to indicate that stream is not open. + * + * The channel will take ownership of the process + * @pid and will kill it when closing the channel. + * Similarly it will take responsibility for + * closing the file descriptors @writefd and @readfd. + * + * Returns: the command channel object, or NULL on error + */ +QIOChannelCommand * +qio_channel_command_new_pid(int writefd, + int readfd, + pid_t pid); + +/** + * qio_channel_command_new_spawn: + * @argv: the NULL terminated list of command arguments + * @flags: the I/O mode, one of O_RDONLY, O_WRONLY, O_RDWR + * @errp: pointer to a NULL-initialized error object + * + * Create a channel for performing I/O with the + * command to be spawned with arguments @argv. + * + * Returns: the command channel object, or NULL on error + */ +QIOChannelCommand * +qio_channel_command_new_spawn(const char *const argv[], + int flags, + Error **errp); + + +#endif /* QIO_CHANNEL_COMMAND_H */ diff --git a/include/io/channel-file.h b/include/io/channel-file.h new file mode 100644 index 000000000..50e8eb113 --- /dev/null +++ b/include/io/channel-file.h @@ -0,0 +1,92 @@ +/* + * QEMU I/O channels files driver + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QIO_CHANNEL_FILE_H +#define QIO_CHANNEL_FILE_H + +#include "io/channel.h" +#include "qom/object.h" + +#define TYPE_QIO_CHANNEL_FILE "qio-channel-file" +OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelFile, QIO_CHANNEL_FILE) + + +/** + * QIOChannelFile: + * + * The QIOChannelFile object provides a channel implementation + * that is able to perform I/O on block devices, character + * devices, FIFOs, pipes and plain files. While it is technically + * able to work on sockets too on the UNIX platform, this is not + * portable to Windows and lacks some extra sockets specific + * functionality. So the QIOChannelSocket object is recommended + * for that use case. + * + */ + +struct QIOChannelFile { + QIOChannel parent; + int fd; +}; + + +/** + * qio_channel_file_new_fd: + * @fd: the file descriptor + * + * Create a new IO channel object for a file represented + * by the @fd parameter. @fd can be associated with a + * block device, character device, fifo, pipe, or a + * regular file. For sockets, the QIOChannelSocket class + * should be used instead, as this provides greater + * functionality and cross platform portability. + * + * The channel will own the passed in file descriptor + * and will take responsibility for closing it, so the + * caller must not close it. If appropriate the caller + * should dup() its FD before opening the channel. + * + * Returns: the new channel object + */ +QIOChannelFile * +qio_channel_file_new_fd(int fd); + +/** + * qio_channel_file_new_path: + * @path: the file path + * @flags: the open flags (O_RDONLY|O_WRONLY|O_RDWR, etc) + * @mode: the file creation mode if O_CREAT is set in @flags + * @errp: pointer to initialized error object + * + * Create a new IO channel object for a file represented + * by the @path parameter. @path can point to any + * type of file on which sequential I/O can be + * performed, whether it be a plain file, character + * device or block device. + * + * Returns: the new channel object + */ +QIOChannelFile * +qio_channel_file_new_path(const char *path, + int flags, + mode_t mode, + Error **errp); + +#endif /* QIO_CHANNEL_FILE_H */ diff --git a/include/io/channel-socket.h b/include/io/channel-socket.h new file mode 100644 index 000000000..e747e6351 --- /dev/null +++ b/include/io/channel-socket.h @@ -0,0 +1,263 @@ +/* + * QEMU I/O channels sockets driver + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QIO_CHANNEL_SOCKET_H +#define QIO_CHANNEL_SOCKET_H + +#include "io/channel.h" +#include "io/task.h" +#include "qemu/sockets.h" +#include "qom/object.h" + +#define TYPE_QIO_CHANNEL_SOCKET "qio-channel-socket" +OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelSocket, QIO_CHANNEL_SOCKET) + + +/** + * QIOChannelSocket: + * + * The QIOChannelSocket class provides a channel implementation + * that can transport data over a UNIX socket or TCP socket. + * Beyond the core channel API, it also provides functionality + * for accepting client connections, tuning some socket + * parameters and getting socket address strings. + */ + +struct QIOChannelSocket { + QIOChannel parent; + int fd; + struct sockaddr_storage localAddr; + socklen_t localAddrLen; + struct sockaddr_storage remoteAddr; + socklen_t remoteAddrLen; +}; + + +/** + * qio_channel_socket_new: + * + * Create a channel for performing I/O on a socket + * connection, that is initially closed. After + * creating the socket, it must be setup as a client + * connection or server. + * + * Returns: the socket channel object + */ +QIOChannelSocket * +qio_channel_socket_new(void); + +/** + * qio_channel_socket_new_fd: + * @fd: the socket file descriptor + * @errp: pointer to a NULL-initialized error object + * + * Create a channel for performing I/O on the socket + * connection represented by the file descriptor @fd. + * + * Returns: the socket channel object, or NULL on error + */ +QIOChannelSocket * +qio_channel_socket_new_fd(int fd, + Error **errp); + + +/** + * qio_channel_socket_connect_sync: + * @ioc: the socket channel object + * @addr: the address to connect to + * @errp: pointer to a NULL-initialized error object + * + * Attempt to connect to the address @addr. This method + * will run in the foreground so the caller will not regain + * execution control until the connection is established or + * an error occurs. + */ +int qio_channel_socket_connect_sync(QIOChannelSocket *ioc, + SocketAddress *addr, + Error **errp); + +/** + * qio_channel_socket_connect_async: + * @ioc: the socket channel object + * @addr: the address to connect to + * @callback: the function to invoke on completion + * @opaque: user data to pass to @callback + * @destroy: the function to free @opaque + * @context: the context to run the async task. If %NULL, the default + * context will be used. + * + * Attempt to connect to the address @addr. This method + * will run in the background so the caller will regain + * execution control immediately. The function @callback + * will be invoked on completion or failure. The @addr + * parameter will be copied, so may be freed as soon + * as this function returns without waiting for completion. + */ +void qio_channel_socket_connect_async(QIOChannelSocket *ioc, + SocketAddress *addr, + QIOTaskFunc callback, + gpointer opaque, + GDestroyNotify destroy, + GMainContext *context); + + +/** + * qio_channel_socket_listen_sync: + * @ioc: the socket channel object + * @addr: the address to listen to + * @num: the expected ammount of connections + * @errp: pointer to a NULL-initialized error object + * + * Attempt to listen to the address @addr. This method + * will run in the foreground so the caller will not regain + * execution control until the connection is established or + * an error occurs. + */ +int qio_channel_socket_listen_sync(QIOChannelSocket *ioc, + SocketAddress *addr, + int num, + Error **errp); + +/** + * qio_channel_socket_listen_async: + * @ioc: the socket channel object + * @addr: the address to listen to + * @num: the expected ammount of connections + * @callback: the function to invoke on completion + * @opaque: user data to pass to @callback + * @destroy: the function to free @opaque + * @context: the context to run the async task. If %NULL, the default + * context will be used. + * + * Attempt to listen to the address @addr. This method + * will run in the background so the caller will regain + * execution control immediately. The function @callback + * will be invoked on completion or failure. The @addr + * parameter will be copied, so may be freed as soon + * as this function returns without waiting for completion. + */ +void qio_channel_socket_listen_async(QIOChannelSocket *ioc, + SocketAddress *addr, + int num, + QIOTaskFunc callback, + gpointer opaque, + GDestroyNotify destroy, + GMainContext *context); + + +/** + * qio_channel_socket_dgram_sync: + * @ioc: the socket channel object + * @localAddr: the address to local bind address + * @remoteAddr: the address to remote peer address + * @errp: pointer to a NULL-initialized error object + * + * Attempt to initialize a datagram socket bound to + * @localAddr and communicating with peer @remoteAddr. + * This method will run in the foreground so the caller + * will not regain execution control until the socket + * is established or an error occurs. + */ +int qio_channel_socket_dgram_sync(QIOChannelSocket *ioc, + SocketAddress *localAddr, + SocketAddress *remoteAddr, + Error **errp); + +/** + * qio_channel_socket_dgram_async: + * @ioc: the socket channel object + * @localAddr: the address to local bind address + * @remoteAddr: the address to remote peer address + * @callback: the function to invoke on completion + * @opaque: user data to pass to @callback + * @destroy: the function to free @opaque + * @context: the context to run the async task. If %NULL, the default + * context will be used. + * + * Attempt to initialize a datagram socket bound to + * @localAddr and communicating with peer @remoteAddr. + * This method will run in the background so the caller + * will regain execution control immediately. The function + * @callback will be invoked on completion or failure. + * The @localAddr and @remoteAddr parameters will be copied, + * so may be freed as soon as this function returns without + * waiting for completion. + */ +void qio_channel_socket_dgram_async(QIOChannelSocket *ioc, + SocketAddress *localAddr, + SocketAddress *remoteAddr, + QIOTaskFunc callback, + gpointer opaque, + GDestroyNotify destroy, + GMainContext *context); + + +/** + * qio_channel_socket_get_local_address: + * @ioc: the socket channel object + * @errp: pointer to a NULL-initialized error object + * + * Get the string representation of the local socket + * address. A pointer to the allocated address information + * struct will be returned, which the caller is required to + * release with a call qapi_free_SocketAddress() when no + * longer required. + * + * Returns: 0 on success, -1 on error + */ +SocketAddress * +qio_channel_socket_get_local_address(QIOChannelSocket *ioc, + Error **errp); + +/** + * qio_channel_socket_get_remote_address: + * @ioc: the socket channel object + * @errp: pointer to a NULL-initialized error object + * + * Get the string representation of the local socket + * address. A pointer to the allocated address information + * struct will be returned, which the caller is required to + * release with a call qapi_free_SocketAddress() when no + * longer required. + * + * Returns: the socket address struct, or NULL on error + */ +SocketAddress * +qio_channel_socket_get_remote_address(QIOChannelSocket *ioc, + Error **errp); + + +/** + * qio_channel_socket_accept: + * @ioc: the socket channel object + * @errp: pointer to a NULL-initialized error object + * + * If the socket represents a server, then this accepts + * a new client connection. The returned channel will + * represent the connected client socket. + * + * Returns: the new client channel, or NULL on error + */ +QIOChannelSocket * +qio_channel_socket_accept(QIOChannelSocket *ioc, + Error **errp); + + +#endif /* QIO_CHANNEL_SOCKET_H */ diff --git a/include/io/channel-tls.h b/include/io/channel-tls.h new file mode 100644 index 000000000..5672479e9 --- /dev/null +++ b/include/io/channel-tls.h @@ -0,0 +1,145 @@ +/* + * QEMU I/O channels TLS driver + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QIO_CHANNEL_TLS_H +#define QIO_CHANNEL_TLS_H + +#include "io/channel.h" +#include "io/task.h" +#include "crypto/tlssession.h" +#include "qom/object.h" + +#define TYPE_QIO_CHANNEL_TLS "qio-channel-tls" +OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelTLS, QIO_CHANNEL_TLS) + + +/** + * QIOChannelTLS + * + * The QIOChannelTLS class provides a channel wrapper which + * can transparently run the TLS encryption protocol. It is + * usually used over a TCP socket, but there is actually no + * technical restriction on which type of master channel is + * used as the transport. + * + * This channel object is capable of running as either a + * TLS server or TLS client. + */ + +struct QIOChannelTLS { + QIOChannel parent; + QIOChannel *master; + QCryptoTLSSession *session; + QIOChannelShutdown shutdown; +}; + +/** + * qio_channel_tls_new_server: + * @master: the underlying channel object + * @creds: the credentials to use for TLS handshake + * @aclname: the access control list for validating clients + * @errp: pointer to a NULL-initialized error object + * + * Create a new TLS channel that runs the server side of + * a TLS session. The TLS session handshake will use the + * credentials provided in @creds. If the @aclname parameter + * is non-NULL, then the client will have to provide + * credentials (ie a x509 client certificate) which will + * then be validated against the ACL. + * + * After creating the channel, it is mandatory to call + * the qio_channel_tls_handshake() method before attempting + * todo any I/O on the channel. + * + * Once the handshake has completed, all I/O should be done + * via the new TLS channel object and not the original + * master channel + * + * Returns: the new TLS channel object, or NULL + */ +QIOChannelTLS * +qio_channel_tls_new_server(QIOChannel *master, + QCryptoTLSCreds *creds, + const char *aclname, + Error **errp); + +/** + * qio_channel_tls_new_client: + * @master: the underlying channel object + * @creds: the credentials to use for TLS handshake + * @hostname: the user specified server hostname + * @errp: pointer to a NULL-initialized error object + * + * Create a new TLS channel that runs the client side of + * a TLS session. The TLS session handshake will use the + * credentials provided in @creds. The @hostname parameter + * should provide the user specified hostname of the server + * and will be validated against the server's credentials + * (ie CommonName of the x509 certificate) + * + * After creating the channel, it is mandatory to call + * the qio_channel_tls_handshake() method before attempting + * todo any I/O on the channel. + * + * Once the handshake has completed, all I/O should be done + * via the new TLS channel object and not the original + * master channel + * + * Returns: the new TLS channel object, or NULL + */ +QIOChannelTLS * +qio_channel_tls_new_client(QIOChannel *master, + QCryptoTLSCreds *creds, + const char *hostname, + Error **errp); + +/** + * qio_channel_tls_handshake: + * @ioc: the TLS channel object + * @func: the callback to invoke when completed + * @opaque: opaque data to pass to @func + * @destroy: optional callback to free @opaque + * @context: the context that TLS handshake will run with. If %NULL, + * the default context will be used + * + * Perform the TLS session handshake. This method + * will return immediately and the handshake will + * continue in the background, provided the main + * loop is running. When the handshake is complete, + * or fails, the @func callback will be invoked. + */ +void qio_channel_tls_handshake(QIOChannelTLS *ioc, + QIOTaskFunc func, + gpointer opaque, + GDestroyNotify destroy, + GMainContext *context); + +/** + * qio_channel_tls_get_session: + * @ioc: the TLS channel object + * + * Get the TLS session used by the channel. + * + * Returns: the TLS session + */ +QCryptoTLSSession * +qio_channel_tls_get_session(QIOChannelTLS *ioc); + +#endif /* QIO_CHANNEL_TLS_H */ diff --git a/include/io/channel-util.h b/include/io/channel-util.h new file mode 100644 index 000000000..a5d720d9a --- /dev/null +++ b/include/io/channel-util.h @@ -0,0 +1,52 @@ +/* + * QEMU I/O channels utility APIs + * + * Copyright (c) 2016 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QIO_CHANNEL_UTIL_H +#define QIO_CHANNEL_UTIL_H + +#include "io/channel.h" + +/* + * This module provides helper functions that are useful when dealing + * with QIOChannel objects + */ + + +/** + * qio_channel_new_fd: + * @fd: the file descriptor + * @errp: pointer to a NULL-initialized error object + * + * Create a channel for performing I/O on the file + * descriptor @fd. The particular subclass of QIOChannel + * that is returned will depend on what underlying object + * the file descriptor is associated with. It may be either + * a QIOChannelSocket or a QIOChannelFile instance. Upon + * success, the returned QIOChannel instance will own + * the @fd file descriptor, and take responsibility for + * closing it when no longer required. On failure, the + * caller is responsible for closing @fd. + * + * Returns: the channel object, or NULL on error + */ +QIOChannel *qio_channel_new_fd(int fd, + Error **errp); + +#endif /* QIO_CHANNEL_UTIL_H */ diff --git a/include/io/channel-watch.h b/include/io/channel-watch.h new file mode 100644 index 000000000..a36aab8f8 --- /dev/null +++ b/include/io/channel-watch.h @@ -0,0 +1,90 @@ +/* + * QEMU I/O channels watch helper APIs + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QIO_CHANNEL_WATCH_H +#define QIO_CHANNEL_WATCH_H + +#include "io/channel.h" + +/* + * This module provides helper functions that will be needed by + * the various QIOChannel implementations, for creating watches + * on file descriptors / sockets + */ + +/** + * qio_channel_create_fd_watch: + * @ioc: the channel object + * @fd: the file descriptor + * @condition: the I/O condition + * + * Create a new main loop source that is able to + * monitor the file descriptor @fd for the + * I/O conditions in @condition. This is able + * monitor block devices, character devices, + * pipes but not plain files or, on Win32, sockets. + * + * Returns: the new main loop source + */ +GSource *qio_channel_create_fd_watch(QIOChannel *ioc, + int fd, + GIOCondition condition); + +/** + * qio_channel_create_socket_watch: + * @ioc: the channel object + * @fd: the file descriptor + * @condition: the I/O condition + * + * Create a new main loop source that is able to + * monitor the file descriptor @fd for the + * I/O conditions in @condition. This is equivalent + * to qio_channel_create_fd_watch on POSIX systems + * but not on Windows. + * + * Returns: the new main loop source + */ +GSource *qio_channel_create_socket_watch(QIOChannel *ioc, + int fd, + GIOCondition condition); + +/** + * qio_channel_create_fd_pair_watch: + * @ioc: the channel object + * @fdread: the file descriptor for reading + * @fdwrite: the file descriptor for writing + * @condition: the I/O condition + * + * Create a new main loop source that is able to + * monitor the pair of file descriptors @fdread + * and @fdwrite for the I/O conditions in @condition. + * This is intended for monitoring unidirectional + * file descriptors such as pipes, where a pair + * of descriptors is required for bidirectional + * I/O + * + * Returns: the new main loop source + */ +GSource *qio_channel_create_fd_pair_watch(QIOChannel *ioc, + int fdread, + int fdwrite, + GIOCondition condition); + +#endif /* QIO_CHANNEL_WATCH_H */ diff --git a/include/io/channel-websock.h b/include/io/channel-websock.h new file mode 100644 index 000000000..e180827c5 --- /dev/null +++ b/include/io/channel-websock.h @@ -0,0 +1,108 @@ +/* + * QEMU I/O channels driver websockets + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QIO_CHANNEL_WEBSOCK_H +#define QIO_CHANNEL_WEBSOCK_H + +#include "io/channel.h" +#include "qemu/buffer.h" +#include "io/task.h" +#include "qom/object.h" + +#define TYPE_QIO_CHANNEL_WEBSOCK "qio-channel-websock" +OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelWebsock, QIO_CHANNEL_WEBSOCK) + +typedef union QIOChannelWebsockMask QIOChannelWebsockMask; + +union QIOChannelWebsockMask { + char c[4]; + uint32_t u; +}; + +/** + * QIOChannelWebsock + * + * The QIOChannelWebsock class provides a channel wrapper which + * can transparently run the HTTP websockets protocol. This is + * usually used over a TCP socket, but there is actually no + * technical restriction on which type of master channel is + * used as the transport. + * + * This channel object is currently only capable of running as + * a websocket server and is a pretty crude implementation + * of it, not supporting the full websockets protocol feature + * set. It is sufficient to use with a simple websockets + * client for encapsulating VNC for noVNC in-browser client. + */ + +struct QIOChannelWebsock { + QIOChannel parent; + QIOChannel *master; + Buffer encinput; + Buffer encoutput; + Buffer rawinput; + size_t payload_remain; + size_t pong_remain; + QIOChannelWebsockMask mask; + guint io_tag; + Error *io_err; + gboolean io_eof; + uint8_t opcode; +}; + +/** + * qio_channel_websock_new_server: + * @master: the underlying channel object + * + * Create a new websockets channel that runs the server + * side of the protocol. + * + * After creating the channel, it is mandatory to call + * the qio_channel_websock_handshake() method before attempting + * todo any I/O on the channel. + * + * Once the handshake has completed, all I/O should be done + * via the new websocket channel object and not the original + * master channel + * + * Returns: the new websockets channel object + */ +QIOChannelWebsock * +qio_channel_websock_new_server(QIOChannel *master); + +/** + * qio_channel_websock_handshake: + * @ioc: the websocket channel object + * @func: the callback to invoke when completed + * @opaque: opaque data to pass to @func + * @destroy: optional callback to free @opaque + * + * Perform the websocket handshake. This method + * will return immediately and the handshake will + * continue in the background, provided the main + * loop is running. When the handshake is complete, + * or fails, the @func callback will be invoked. + */ +void qio_channel_websock_handshake(QIOChannelWebsock *ioc, + QIOTaskFunc func, + gpointer opaque, + GDestroyNotify destroy); + +#endif /* QIO_CHANNEL_WEBSOCK_H */ diff --git a/include/io/channel.h b/include/io/channel.h new file mode 100644 index 000000000..88988979f --- /dev/null +++ b/include/io/channel.h @@ -0,0 +1,858 @@ +/* + * QEMU I/O channels + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QIO_CHANNEL_H +#define QIO_CHANNEL_H + +#include "qom/object.h" +#include "qemu/coroutine.h" +#include "block/aio.h" + +#define TYPE_QIO_CHANNEL "qio-channel" +OBJECT_DECLARE_TYPE(QIOChannel, QIOChannelClass, + QIO_CHANNEL) + + +#define QIO_CHANNEL_ERR_BLOCK -2 + +typedef enum QIOChannelFeature QIOChannelFeature; + +enum QIOChannelFeature { + QIO_CHANNEL_FEATURE_FD_PASS, + QIO_CHANNEL_FEATURE_SHUTDOWN, + QIO_CHANNEL_FEATURE_LISTEN, +}; + + +typedef enum QIOChannelShutdown QIOChannelShutdown; + +enum QIOChannelShutdown { + QIO_CHANNEL_SHUTDOWN_READ = 1, + QIO_CHANNEL_SHUTDOWN_WRITE = 2, + QIO_CHANNEL_SHUTDOWN_BOTH = 3, +}; + +typedef gboolean (*QIOChannelFunc)(QIOChannel *ioc, + GIOCondition condition, + gpointer data); + +/** + * QIOChannel: + * + * The QIOChannel defines the core API for a generic I/O channel + * class hierarchy. It is inspired by GIOChannel, but has the + * following differences + * + * - Use QOM to properly support arbitrary subclassing + * - Support use of iovecs for efficient I/O with multiple blocks + * - None of the character set translation, binary data exclusively + * - Direct support for QEMU Error object reporting + * - File descriptor passing + * + * This base class is abstract so cannot be instantiated. There + * will be subclasses for dealing with sockets, files, and higher + * level protocols such as TLS, WebSocket, etc. + */ + +struct QIOChannel { + Object parent; + unsigned int features; /* bitmask of QIOChannelFeatures */ + char *name; + AioContext *ctx; + Coroutine *read_coroutine; + Coroutine *write_coroutine; +#ifdef _WIN32 + HANDLE event; /* For use with GSource on Win32 */ +#endif +}; + +/** + * QIOChannelClass: + * + * This class defines the contract that all subclasses + * must follow to provide specific channel implementations. + * The first five callbacks are mandatory to support, others + * provide additional optional features. + * + * Consult the corresponding public API docs for a description + * of the semantics of each callback. io_shutdown in particular + * must be thread-safe, terminate quickly and must not block. + */ +struct QIOChannelClass { + ObjectClass parent; + + /* Mandatory callbacks */ + ssize_t (*io_writev)(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int *fds, + size_t nfds, + Error **errp); + ssize_t (*io_readv)(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int **fds, + size_t *nfds, + Error **errp); + int (*io_close)(QIOChannel *ioc, + Error **errp); + GSource * (*io_create_watch)(QIOChannel *ioc, + GIOCondition condition); + int (*io_set_blocking)(QIOChannel *ioc, + bool enabled, + Error **errp); + + /* Optional callbacks */ + int (*io_shutdown)(QIOChannel *ioc, + QIOChannelShutdown how, + Error **errp); + void (*io_set_cork)(QIOChannel *ioc, + bool enabled); + void (*io_set_delay)(QIOChannel *ioc, + bool enabled); + off_t (*io_seek)(QIOChannel *ioc, + off_t offset, + int whence, + Error **errp); + void (*io_set_aio_fd_handler)(QIOChannel *ioc, + AioContext *ctx, + IOHandler *io_read, + IOHandler *io_write, + void *opaque); +}; + +/* General I/O handling functions */ + +/** + * qio_channel_has_feature: + * @ioc: the channel object + * @feature: the feature to check support of + * + * Determine whether the channel implementation supports + * the optional feature named in @feature. + * + * Returns: true if supported, false otherwise. + */ +bool qio_channel_has_feature(QIOChannel *ioc, + QIOChannelFeature feature); + +/** + * qio_channel_set_feature: + * @ioc: the channel object + * @feature: the feature to set support for + * + * Add channel support for the feature named in @feature. + */ +void qio_channel_set_feature(QIOChannel *ioc, + QIOChannelFeature feature); + +/** + * qio_channel_set_name: + * @ioc: the channel object + * @name: the name of the channel + * + * Sets the name of the channel, which serves as an aid + * to debugging. The name is used when creating GSource + * watches for this channel. + */ +void qio_channel_set_name(QIOChannel *ioc, + const char *name); + +/** + * qio_channel_readv_full: + * @ioc: the channel object + * @iov: the array of memory regions to read data into + * @niov: the length of the @iov array + * @fds: pointer to an array that will received file handles + * @nfds: pointer filled with number of elements in @fds on return + * @errp: pointer to a NULL-initialized error object + * + * Read data from the IO channel, storing it in the + * memory regions referenced by @iov. Each element + * in the @iov will be fully populated with data + * before the next one is used. The @niov parameter + * specifies the total number of elements in @iov. + * + * It is not required for all @iov to be filled with + * data. If the channel is in blocking mode, at least + * one byte of data will be read, but no more is + * guaranteed. If the channel is non-blocking and no + * data is available, it will return QIO_CHANNEL_ERR_BLOCK + * + * If the channel has passed any file descriptors, + * the @fds array pointer will be allocated and + * the elements filled with the received file + * descriptors. The @nfds pointer will be updated + * to indicate the size of the @fds array that + * was allocated. It is the callers responsibility + * to call close() on each file descriptor and to + * call g_free() on the array pointer in @fds. + * + * It is an error to pass a non-NULL @fds parameter + * unless qio_channel_has_feature() returns a true + * value for the QIO_CHANNEL_FEATURE_FD_PASS constant. + * + * Returns: the number of bytes read, or -1 on error, + * or QIO_CHANNEL_ERR_BLOCK if no data is available + * and the channel is non-blocking + */ +ssize_t qio_channel_readv_full(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int **fds, + size_t *nfds, + Error **errp); + + +/** + * qio_channel_writev_full: + * @ioc: the channel object + * @iov: the array of memory regions to write data from + * @niov: the length of the @iov array + * @fds: an array of file handles to send + * @nfds: number of file handles in @fds + * @errp: pointer to a NULL-initialized error object + * + * Write data to the IO channel, reading it from the + * memory regions referenced by @iov. Each element + * in the @iov will be fully sent, before the next + * one is used. The @niov parameter specifies the + * total number of elements in @iov. + * + * It is not required for all @iov data to be fully + * sent. If the channel is in blocking mode, at least + * one byte of data will be sent, but no more is + * guaranteed. If the channel is non-blocking and no + * data can be sent, it will return QIO_CHANNEL_ERR_BLOCK + * + * If there are file descriptors to send, the @fds + * array should be non-NULL and provide the handles. + * All file descriptors will be sent if at least one + * byte of data was sent. + * + * It is an error to pass a non-NULL @fds parameter + * unless qio_channel_has_feature() returns a true + * value for the QIO_CHANNEL_FEATURE_FD_PASS constant. + * + * Returns: the number of bytes sent, or -1 on error, + * or QIO_CHANNEL_ERR_BLOCK if no data is can be sent + * and the channel is non-blocking + */ +ssize_t qio_channel_writev_full(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int *fds, + size_t nfds, + Error **errp); + +/** + * qio_channel_readv_all_eof: + * @ioc: the channel object + * @iov: the array of memory regions to read data into + * @niov: the length of the @iov array + * @errp: pointer to a NULL-initialized error object + * + * Read data from the IO channel, storing it in the + * memory regions referenced by @iov. Each element + * in the @iov will be fully populated with data + * before the next one is used. The @niov parameter + * specifies the total number of elements in @iov. + * + * The function will wait for all requested data + * to be read, yielding from the current coroutine + * if required. + * + * If end-of-file occurs before any data is read, + * no error is reported; otherwise, if it occurs + * before all requested data has been read, an error + * will be reported. + * + * Returns: 1 if all bytes were read, 0 if end-of-file + * occurs without data, or -1 on error + */ +int qio_channel_readv_all_eof(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + Error **errp); + +/** + * qio_channel_readv_all: + * @ioc: the channel object + * @iov: the array of memory regions to read data into + * @niov: the length of the @iov array + * @errp: pointer to a NULL-initialized error object + * + * Read data from the IO channel, storing it in the + * memory regions referenced by @iov. Each element + * in the @iov will be fully populated with data + * before the next one is used. The @niov parameter + * specifies the total number of elements in @iov. + * + * The function will wait for all requested data + * to be read, yielding from the current coroutine + * if required. + * + * If end-of-file occurs before all requested data + * has been read, an error will be reported. + * + * Returns: 0 if all bytes were read, or -1 on error + */ +int qio_channel_readv_all(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + Error **errp); + + +/** + * qio_channel_writev_all: + * @ioc: the channel object + * @iov: the array of memory regions to write data from + * @niov: the length of the @iov array + * @errp: pointer to a NULL-initialized error object + * + * Write data to the IO channel, reading it from the + * memory regions referenced by @iov. Each element + * in the @iov will be fully sent, before the next + * one is used. The @niov parameter specifies the + * total number of elements in @iov. + * + * The function will wait for all requested data + * to be written, yielding from the current coroutine + * if required. + * + * Returns: 0 if all bytes were written, or -1 on error + */ +int qio_channel_writev_all(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + Error **erp); + +/** + * qio_channel_readv: + * @ioc: the channel object + * @iov: the array of memory regions to read data into + * @niov: the length of the @iov array + * @errp: pointer to a NULL-initialized error object + * + * Behaves as qio_channel_readv_full() but does not support + * receiving of file handles. + */ +ssize_t qio_channel_readv(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + Error **errp); + +/** + * qio_channel_writev: + * @ioc: the channel object + * @iov: the array of memory regions to write data from + * @niov: the length of the @iov array + * @errp: pointer to a NULL-initialized error object + * + * Behaves as qio_channel_writev_full() but does not support + * sending of file handles. + */ +ssize_t qio_channel_writev(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + Error **errp); + +/** + * qio_channel_read: + * @ioc: the channel object + * @buf: the memory region to read data into + * @buflen: the length of @buf + * @errp: pointer to a NULL-initialized error object + * + * Behaves as qio_channel_readv_full() but does not support + * receiving of file handles, and only supports reading into + * a single memory region. + */ +ssize_t qio_channel_read(QIOChannel *ioc, + char *buf, + size_t buflen, + Error **errp); + +/** + * qio_channel_write: + * @ioc: the channel object + * @buf: the memory regions to send data from + * @buflen: the length of @buf + * @errp: pointer to a NULL-initialized error object + * + * Behaves as qio_channel_writev_full() but does not support + * sending of file handles, and only supports writing from a + * single memory region. + */ +ssize_t qio_channel_write(QIOChannel *ioc, + const char *buf, + size_t buflen, + Error **errp); + +/** + * qio_channel_read_all_eof: + * @ioc: the channel object + * @buf: the memory region to read data into + * @buflen: the number of bytes to @buf + * @errp: pointer to a NULL-initialized error object + * + * Reads @buflen bytes into @buf, possibly blocking or (if the + * channel is non-blocking) yielding from the current coroutine + * multiple times until the entire content is read. If end-of-file + * occurs immediately it is not an error, but if it occurs after + * data has been read it will return an error rather than a + * short-read. Otherwise behaves as qio_channel_read(). + * + * Returns: 1 if all bytes were read, 0 if end-of-file occurs + * without data, or -1 on error + */ +int qio_channel_read_all_eof(QIOChannel *ioc, + char *buf, + size_t buflen, + Error **errp); + +/** + * qio_channel_read_all: + * @ioc: the channel object + * @buf: the memory region to read data into + * @buflen: the number of bytes to @buf + * @errp: pointer to a NULL-initialized error object + * + * Reads @buflen bytes into @buf, possibly blocking or (if the + * channel is non-blocking) yielding from the current coroutine + * multiple times until the entire content is read. If end-of-file + * occurs it will return an error rather than a short-read. Otherwise + * behaves as qio_channel_read(). + * + * Returns: 0 if all bytes were read, or -1 on error + */ +int qio_channel_read_all(QIOChannel *ioc, + char *buf, + size_t buflen, + Error **errp); + +/** + * qio_channel_write_all: + * @ioc: the channel object + * @buf: the memory region to write data into + * @buflen: the number of bytes to @buf + * @errp: pointer to a NULL-initialized error object + * + * Writes @buflen bytes from @buf, possibly blocking or (if the + * channel is non-blocking) yielding from the current coroutine + * multiple times until the entire content is written. Otherwise + * behaves as qio_channel_write(). + * + * Returns: 0 if all bytes were written, or -1 on error + */ +int qio_channel_write_all(QIOChannel *ioc, + const char *buf, + size_t buflen, + Error **errp); + +/** + * qio_channel_set_blocking: + * @ioc: the channel object + * @enabled: the blocking flag state + * @errp: pointer to a NULL-initialized error object + * + * If @enabled is true, then the channel is put into + * blocking mode, otherwise it will be non-blocking. + * + * In non-blocking mode, read/write operations may + * return QIO_CHANNEL_ERR_BLOCK if they would otherwise + * block on I/O + */ +int qio_channel_set_blocking(QIOChannel *ioc, + bool enabled, + Error **errp); + +/** + * qio_channel_close: + * @ioc: the channel object + * @errp: pointer to a NULL-initialized error object + * + * Close the channel, flushing any pending I/O + * + * Returns: 0 on success, -1 on error + */ +int qio_channel_close(QIOChannel *ioc, + Error **errp); + +/** + * qio_channel_shutdown: + * @ioc: the channel object + * @how: the direction to shutdown + * @errp: pointer to a NULL-initialized error object + * + * Shutdowns transmission and/or receiving of data + * without closing the underlying transport. + * + * Not all implementations will support this facility, + * so may report an error. To avoid errors, the + * caller may check for the feature flag + * QIO_CHANNEL_FEATURE_SHUTDOWN prior to calling + * this method. + * + * This function is thread-safe, terminates quickly and does not block. + * + * Returns: 0 on success, -1 on error + */ +int qio_channel_shutdown(QIOChannel *ioc, + QIOChannelShutdown how, + Error **errp); + +/** + * qio_channel_set_delay: + * @ioc: the channel object + * @enabled: the new flag state + * + * Controls whether the underlying transport is + * permitted to delay writes in order to merge + * small packets. If @enabled is true, then the + * writes may be delayed in order to opportunistically + * merge small packets into larger ones. If @enabled + * is false, writes are dispatched immediately with + * no delay. + * + * When @enabled is false, applications may wish to + * use the qio_channel_set_cork() method to explicitly + * control write merging. + * + * On channels which are backed by a socket, this + * API corresponds to the inverse of TCP_NODELAY flag, + * controlling whether the Nagle algorithm is active. + * + * This setting is merely a hint, so implementations are + * free to ignore this without it being considered an + * error. + */ +void qio_channel_set_delay(QIOChannel *ioc, + bool enabled); + +/** + * qio_channel_set_cork: + * @ioc: the channel object + * @enabled: the new flag state + * + * Controls whether the underlying transport is + * permitted to dispatch data that is written. + * If @enabled is true, then any data written will + * be queued in local buffers until @enabled is + * set to false once again. + * + * This feature is typically used when the automatic + * write coalescing facility is disabled via the + * qio_channel_set_delay() method. + * + * On channels which are backed by a socket, this + * API corresponds to the TCP_CORK flag. + * + * This setting is merely a hint, so implementations are + * free to ignore this without it being considered an + * error. + */ +void qio_channel_set_cork(QIOChannel *ioc, + bool enabled); + + +/** + * qio_channel_seek: + * @ioc: the channel object + * @offset: the position to seek to, relative to @whence + * @whence: one of the (POSIX) SEEK_* constants listed below + * @errp: pointer to a NULL-initialized error object + * + * Moves the current I/O position within the channel + * @ioc, to be @offset. The value of @offset is + * interpreted relative to @whence: + * + * SEEK_SET - the position is set to @offset bytes + * SEEK_CUR - the position is moved by @offset bytes + * SEEK_END - the position is set to end of the file plus @offset bytes + * + * Not all implementations will support this facility, + * so may report an error. + * + * Returns: the new position on success, (off_t)-1 on failure + */ +off_t qio_channel_io_seek(QIOChannel *ioc, + off_t offset, + int whence, + Error **errp); + + +/** + * qio_channel_create_watch: + * @ioc: the channel object + * @condition: the I/O condition to monitor + * + * Create a new main loop source that is used to watch + * for the I/O condition @condition. Typically the + * qio_channel_add_watch() method would be used instead + * of this, since it directly attaches a callback to + * the source + * + * Returns: the new main loop source. + */ +GSource *qio_channel_create_watch(QIOChannel *ioc, + GIOCondition condition); + +/** + * qio_channel_add_watch: + * @ioc: the channel object + * @condition: the I/O condition to monitor + * @func: callback to invoke when the source becomes ready + * @user_data: opaque data to pass to @func + * @notify: callback to free @user_data + * + * Create a new main loop source that is used to watch + * for the I/O condition @condition. The callback @func + * will be registered against the source, to be invoked + * when the source becomes ready. The optional @user_data + * will be passed to @func when it is invoked. The @notify + * callback will be used to free @user_data when the + * watch is deleted + * + * The returned source ID can be used with g_source_remove() + * to remove and free the source when no longer required. + * Alternatively the @func callback can return a FALSE + * value. + * + * Returns: the source ID + */ +guint qio_channel_add_watch(QIOChannel *ioc, + GIOCondition condition, + QIOChannelFunc func, + gpointer user_data, + GDestroyNotify notify); + +/** + * qio_channel_add_watch_full: + * @ioc: the channel object + * @condition: the I/O condition to monitor + * @func: callback to invoke when the source becomes ready + * @user_data: opaque data to pass to @func + * @notify: callback to free @user_data + * @context: the context to run the watch source + * + * Similar as qio_channel_add_watch(), but allows to specify context + * to run the watch source. + * + * Returns: the source ID + */ +guint qio_channel_add_watch_full(QIOChannel *ioc, + GIOCondition condition, + QIOChannelFunc func, + gpointer user_data, + GDestroyNotify notify, + GMainContext *context); + +/** + * qio_channel_add_watch_source: + * @ioc: the channel object + * @condition: the I/O condition to monitor + * @func: callback to invoke when the source becomes ready + * @user_data: opaque data to pass to @func + * @notify: callback to free @user_data + * @context: gcontext to bind the source to + * + * Similar as qio_channel_add_watch(), but allows to specify context + * to run the watch source, meanwhile return the GSource object + * instead of tag ID, with the GSource referenced already. + * + * Note: callers is responsible to unref the source when not needed. + * + * Returns: the source pointer + */ +GSource *qio_channel_add_watch_source(QIOChannel *ioc, + GIOCondition condition, + QIOChannelFunc func, + gpointer user_data, + GDestroyNotify notify, + GMainContext *context); + +/** + * qio_channel_attach_aio_context: + * @ioc: the channel object + * @ctx: the #AioContext to set the handlers on + * + * Request that qio_channel_yield() sets I/O handlers on + * the given #AioContext. If @ctx is %NULL, qio_channel_yield() + * uses QEMU's main thread event loop. + * + * You can move a #QIOChannel from one #AioContext to another even if + * I/O handlers are set for a coroutine. However, #QIOChannel provides + * no synchronization between the calls to qio_channel_yield() and + * qio_channel_attach_aio_context(). + * + * Therefore you should first call qio_channel_detach_aio_context() + * to ensure that the coroutine is not entered concurrently. Then, + * while the coroutine has yielded, call qio_channel_attach_aio_context(), + * and then aio_co_schedule() to place the coroutine on the new + * #AioContext. The calls to qio_channel_detach_aio_context() + * and qio_channel_attach_aio_context() should be protected with + * aio_context_acquire() and aio_context_release(). + */ +void qio_channel_attach_aio_context(QIOChannel *ioc, + AioContext *ctx); + +/** + * qio_channel_detach_aio_context: + * @ioc: the channel object + * + * Disable any I/O handlers set by qio_channel_yield(). With the + * help of aio_co_schedule(), this allows moving a coroutine that was + * paused by qio_channel_yield() to another context. + */ +void qio_channel_detach_aio_context(QIOChannel *ioc); + +/** + * qio_channel_yield: + * @ioc: the channel object + * @condition: the I/O condition to wait for + * + * Yields execution from the current coroutine until the condition + * indicated by @condition becomes available. @condition must + * be either %G_IO_IN or %G_IO_OUT; it cannot contain both. In + * addition, no two coroutine can be waiting on the same condition + * and channel at the same time. + * + * This must only be called from coroutine context. It is safe to + * reenter the coroutine externally while it is waiting; in this + * case the function will return even if @condition is not yet + * available. + */ +void coroutine_fn qio_channel_yield(QIOChannel *ioc, + GIOCondition condition); + +/** + * qio_channel_wait: + * @ioc: the channel object + * @condition: the I/O condition to wait for + * + * Block execution from the current thread until + * the condition indicated by @condition becomes + * available. + * + * This will enter a nested event loop to perform + * the wait. + */ +void qio_channel_wait(QIOChannel *ioc, + GIOCondition condition); + +/** + * qio_channel_set_aio_fd_handler: + * @ioc: the channel object + * @ctx: the AioContext to set the handlers on + * @io_read: the read handler + * @io_write: the write handler + * @opaque: the opaque value passed to the handler + * + * This is used internally by qio_channel_yield(). It can + * be used by channel implementations to forward the handlers + * to another channel (e.g. from #QIOChannelTLS to the + * underlying socket). + */ +void qio_channel_set_aio_fd_handler(QIOChannel *ioc, + AioContext *ctx, + IOHandler *io_read, + IOHandler *io_write, + void *opaque); + +/** + * qio_channel_readv_full_all_eof: + * @ioc: the channel object + * @iov: the array of memory regions to read data to + * @niov: the length of the @iov array + * @fds: an array of file handles to read + * @nfds: number of file handles in @fds + * @errp: pointer to a NULL-initialized error object + * + * + * Performs same function as qio_channel_readv_all_eof. + * Additionally, attempts to read file descriptors shared + * over the channel. The function will wait for all + * requested data to be read, yielding from the current + * coroutine if required. data refers to both file + * descriptors and the iovs. + * + * Returns: 1 if all bytes were read, 0 if end-of-file + * occurs without data, or -1 on error + */ + +int qio_channel_readv_full_all_eof(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int **fds, size_t *nfds, + Error **errp); + +/** + * qio_channel_readv_full_all: + * @ioc: the channel object + * @iov: the array of memory regions to read data to + * @niov: the length of the @iov array + * @fds: an array of file handles to read + * @nfds: number of file handles in @fds + * @errp: pointer to a NULL-initialized error object + * + * + * Performs same function as qio_channel_readv_all_eof. + * Additionally, attempts to read file descriptors shared + * over the channel. The function will wait for all + * requested data to be read, yielding from the current + * coroutine if required. data refers to both file + * descriptors and the iovs. + * + * Returns: 0 if all bytes were read, or -1 on error + */ + +int qio_channel_readv_full_all(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int **fds, size_t *nfds, + Error **errp); + +/** + * qio_channel_writev_full_all: + * @ioc: the channel object + * @iov: the array of memory regions to write data from + * @niov: the length of the @iov array + * @fds: an array of file handles to send + * @nfds: number of file handles in @fds + * @errp: pointer to a NULL-initialized error object + * + * + * Behaves like qio_channel_writev_full but will attempt + * to send all data passed (file handles and memory regions). + * The function will wait for all requested data + * to be written, yielding from the current coroutine + * if required. + * + * Returns: 0 if all bytes were written, or -1 on error + */ + +int qio_channel_writev_full_all(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int *fds, size_t nfds, + Error **errp); + +#endif /* QIO_CHANNEL_H */ diff --git a/include/io/dns-resolver.h b/include/io/dns-resolver.h new file mode 100644 index 000000000..558ea517d --- /dev/null +++ b/include/io/dns-resolver.h @@ -0,0 +1,219 @@ +/* + * QEMU DNS resolver + * + * Copyright (c) 2016-2017 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QIO_DNS_RESOLVER_H +#define QIO_DNS_RESOLVER_H + +#include "qapi/qapi-types-sockets.h" +#include "qom/object.h" +#include "io/task.h" + +#define TYPE_QIO_DNS_RESOLVER "qio-dns-resolver" +OBJECT_DECLARE_SIMPLE_TYPE(QIODNSResolver, + QIO_DNS_RESOLVER) + + +/** + * QIODNSResolver: + * + * The QIODNSResolver class provides a framework for doing + * DNS resolution on SocketAddress objects, independently + * of socket creation. + * + * <example> + * <title>Resolving addresses synchronously</title> + * <programlisting> + * int mylisten(SocketAddress *addr, Error **errp) { + * QIODNSResolver *resolver = qio_dns_resolver_get_instance(); + * SocketAddress **rawaddrs = NULL; + * size_t nrawaddrs = 0; + * Error *err = NULL; + * QIOChannel **socks = NULL; + * size_t nsocks = 0; + * + * if (qio_dns_resolver_lookup_sync(dns, addr, &nrawaddrs, + * &rawaddrs, errp) < 0) { + * return -1; + * } + * + * for (i = 0; i < nrawaddrs; i++) { + * QIOChannel *sock = qio_channel_new(); + * Error *local_err = NULL; + * qio_channel_listen_sync(sock, rawaddrs[i], &local_err); + * if (local_err) { + * error_propagate(&err, local_err); + * } else { + * socks = g_renew(QIOChannelSocket *, socks, nsocks + 1); + * socks[nsocks++] = sock; + * } + * qapi_free_SocketAddress(rawaddrs[i]); + * } + * g_free(rawaddrs); + * + * if (nsocks == 0) { + * error_propagate(errp, err); + * } else { + * error_free(err); + * } + * } + * </programlisting> + * </example> + * + * <example> + * <title>Resolving addresses asynchronously</title> + * <programlisting> + * typedef struct MyListenData { + * Error *err; + * QIOChannelSocket **socks; + * size_t nsocks; + * } MyListenData; + * + * void mylistenresult(QIOTask *task, void *opaque) { + * MyListenData *data = opaque; + * QIODNSResolver *resolver = + * QIO_DNS_RESOLVER(qio_task_get_source(task); + * SocketAddress **rawaddrs = NULL; + * size_t nrawaddrs = 0; + * Error *err = NULL; + * + * if (qio_task_propagate_error(task, &data->err)) { + * return; + * } + * + * qio_dns_resolver_lookup_result(resolver, task, + * &nrawaddrs, &rawaddrs); + * + * for (i = 0; i < nrawaddrs; i++) { + * QIOChannel *sock = qio_channel_new(); + * Error *local_err = NULL; + * qio_channel_listen_sync(sock, rawaddrs[i], &local_err); + * if (local_err) { + * error_propagate(&err, local_err); + * } else { + * socks = g_renew(QIOChannelSocket *, socks, nsocks + 1); + * socks[nsocks++] = sock; + * } + * qapi_free_SocketAddress(rawaddrs[i]); + * } + * g_free(rawaddrs); + * + * if (nsocks == 0) { + * error_propagate(&data->err, err); + * } else { + * error_free(err); + * } + * } + * + * void mylisten(SocketAddress *addr, MyListenData *data) { + * QIODNSResolver *resolver = qio_dns_resolver_get_instance(); + * qio_dns_resolver_lookup_async(dns, addr, + * mylistenresult, data, NULL); + * } + * </programlisting> + * </example> + */ +struct QIODNSResolver { + Object parent; +}; + + + +/** + * qio_dns_resolver_get_instance: + * + * Get the singleton dns resolver instance. The caller + * does not own a reference on the returned object. + * + * Returns: the single dns resolver instance + */ +QIODNSResolver *qio_dns_resolver_get_instance(void); + +/** + * qio_dns_resolver_lookup_sync: + * @resolver: the DNS resolver instance + * @addr: the address to resolve + * @naddr: pointer to hold number of resolved addresses + * @addrs: pointer to hold resolved addresses + * @errp: pointer to NULL initialized error object + * + * This will attempt to resolve the address provided + * in @addr. If resolution succeeds, @addrs will be filled + * with all the resolved addresses. @naddrs will specify + * the number of entries allocated in @addrs. The caller + * is responsible for freeing each entry in @addrs, as + * well as @addrs itself. @naddrs is guaranteed to be + * greater than zero on success. + * + * DNS resolution will be done synchronously so execution + * of the caller may be blocked for an arbitrary length + * of time. + * + * Returns: 0 if resolution was successful, -1 on error + */ +int qio_dns_resolver_lookup_sync(QIODNSResolver *resolver, + SocketAddress *addr, + size_t *naddrs, + SocketAddress ***addrs, + Error **errp); + +/** + * qio_dns_resolver_lookup_async: + * @resolver: the DNS resolver instance + * @addr: the address to resolve + * @func: the callback to invoke on lookup completion + * @opaque: data blob to pass to @func + * @notify: the callback to free @opaque, or NULL + * + * This will attempt to resolve the address provided + * in @addr. The callback @func will be invoked when + * resolution has either completed or failed. On + * success, the @func should call the method + * qio_dns_resolver_lookup_result() to obtain the + * results. + * + * DNS resolution will be done asynchronously so execution + * of the caller will not be blocked. + */ +void qio_dns_resolver_lookup_async(QIODNSResolver *resolver, + SocketAddress *addr, + QIOTaskFunc func, + gpointer opaque, + GDestroyNotify notify); + +/** + * qio_dns_resolver_lookup_result: + * @resolver: the DNS resolver instance + * @task: the task object to get results for + * @naddr: pointer to hold number of resolved addresses + * @addrs: pointer to hold resolved addresses + * + * This method should be called from the callback passed + * to qio_dns_resolver_lookup_async() in order to obtain + * results. @addrs will be filled with all the resolved + * addresses. @naddrs will specify the number of entries + * allocated in @addrs. The caller is responsible for + * freeing each entry in @addrs, as well as @addrs itself. + */ +void qio_dns_resolver_lookup_result(QIODNSResolver *resolver, + QIOTask *task, + size_t *naddrs, + SocketAddress ***addrs); + +#endif /* QIO_DNS_RESOLVER_H */ diff --git a/include/io/net-listener.h b/include/io/net-listener.h new file mode 100644 index 000000000..ab9f291ed --- /dev/null +++ b/include/io/net-listener.h @@ -0,0 +1,186 @@ +/* + * QEMU network listener + * + * Copyright (c) 2016-2017 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QIO_NET_LISTENER_H +#define QIO_NET_LISTENER_H + +#include "io/channel-socket.h" +#include "qom/object.h" + +#define TYPE_QIO_NET_LISTENER "qio-net-listener" +OBJECT_DECLARE_SIMPLE_TYPE(QIONetListener, + QIO_NET_LISTENER) + + +typedef void (*QIONetListenerClientFunc)(QIONetListener *listener, + QIOChannelSocket *sioc, + gpointer data); + +/** + * QIONetListener: + * + * The QIONetListener object encapsulates the management of a + * listening socket. It is able to listen on multiple sockets + * concurrently, to deal with the scenario where IPv4 / IPv6 + * needs separate sockets, or there is a need to listen on a + * subset of interface IP addresses, instead of the wildcard + * address. + */ +struct QIONetListener { + Object parent; + + char *name; + QIOChannelSocket **sioc; + GSource **io_source; + size_t nsioc; + + bool connected; + + QIONetListenerClientFunc io_func; + gpointer io_data; + GDestroyNotify io_notify; +}; + + + +/** + * qio_net_listener_new: + * + * Create a new network listener service, which is not + * listening on any sockets initially. + * + * Returns: the new listener + */ +QIONetListener *qio_net_listener_new(void); + + +/** + * qio_net_listener_set_name: + * @listener: the network listener object + * @name: the listener name + * + * Set the name of the listener. This is used as a debugging + * aid, to set names on any GSource instances associated + * with the listener + */ +void qio_net_listener_set_name(QIONetListener *listener, + const char *name); + +/** + * qio_net_listener_open_sync: + * @listener: the network listener object + * @addr: the address to listen on + * @num: the amount of expected connections + * @errp: pointer to a NULL initialized error object + * + * Synchronously open a listening connection on all + * addresses associated with @addr. This method may + * also be invoked multiple times, in order to have a + * single listener on multiple distinct addresses. + */ +int qio_net_listener_open_sync(QIONetListener *listener, + SocketAddress *addr, + int num, + Error **errp); + +/** + * qio_net_listener_add: + * @listener: the network listener object + * @sioc: the socket I/O channel + * + * Associate a listening socket I/O channel with the + * listener. The listener will acquire a new reference + * on @sioc, so the caller should release its own reference + * if it no longer requires the object. + */ +void qio_net_listener_add(QIONetListener *listener, + QIOChannelSocket *sioc); + +/** + * qio_net_listener_set_client_func_full: + * @listener: the network listener object + * @func: the callback function + * @data: opaque data to pass to @func + * @notify: callback to free @data + * @context: the context that the sources will be bound to. If %NULL, + * the default context will be used. + * + * Register @func to be invoked whenever a new client + * connects to the listener. @func will be invoked + * passing in the QIOChannelSocket instance for the + * client. + */ +void qio_net_listener_set_client_func_full(QIONetListener *listener, + QIONetListenerClientFunc func, + gpointer data, + GDestroyNotify notify, + GMainContext *context); + +/** + * qio_net_listener_set_client_func: + * @listener: the network listener object + * @func: the callback function + * @data: opaque data to pass to @func + * @notify: callback to free @data + * + * Wrapper of qio_net_listener_set_client_func_full(), only that the + * sources will always be bound to default main context. + */ +void qio_net_listener_set_client_func(QIONetListener *listener, + QIONetListenerClientFunc func, + gpointer data, + GDestroyNotify notify); + +/** + * qio_net_listener_wait_client: + * @listener: the network listener object + * + * Block execution of the caller until a new client arrives + * on one of the listening sockets. If there was previously + * a callback registered with qio_net_listener_set_client_func + * it will be temporarily disabled, and re-enabled afterwards. + * + * Returns: the new client socket + */ +QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener); + + +/** + * qio_net_listener_disconnect: + * @listener: the network listener object + * + * Disconnect the listener, removing all I/O callback + * watches and closing the socket channels. + */ +void qio_net_listener_disconnect(QIONetListener *listener); + + +/** + * qio_net_listener_is_connected: + * @listener: the network listener object + * + * Determine if the listener is connected to any socket + * channels + * + * Returns: true if connected, false otherwise + */ +bool qio_net_listener_is_connected(QIONetListener *listener); + +#endif /* QIO_NET_LISTENER_H */ diff --git a/include/io/task.h b/include/io/task.h new file mode 100644 index 000000000..beec4f5cf --- /dev/null +++ b/include/io/task.h @@ -0,0 +1,350 @@ +/* + * QEMU I/O task + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QIO_TASK_H +#define QIO_TASK_H + +typedef struct QIOTask QIOTask; + +typedef void (*QIOTaskFunc)(QIOTask *task, + gpointer opaque); + +typedef void (*QIOTaskWorker)(QIOTask *task, + gpointer opaque); + +/** + * QIOTask: + * + * The QIOTask object provides a simple mechanism for reporting + * success / failure of long running background operations. + * + * A object on which the operation is to be performed could have + * a public API which accepts a task callback: + * + * <example> + * <title>Task function signature</title> + * <programlisting> + * void myobject_operation(QMyObject *obj, + * QIOTaskFunc *func, + * gpointer opaque, + * GDestroyNotify notify); + * </programlisting> + * </example> + * + * The 'func' parameter is the callback to be invoked, and 'opaque' + * is data to pass to it. The optional 'notify' function is used + * to free 'opaque' when no longer needed. + * + * When the operation completes, the 'func' callback will be + * invoked, allowing the calling code to determine the result + * of the operation. An example QIOTaskFunc implementation may + * look like + * + * <example> + * <title>Task callback implementation</title> + * <programlisting> + * static void myobject_operation_notify(QIOTask *task, + * gpointer opaque) + * { + * Error *err = NULL; + * if (qio_task_propagate_error(task, &err)) { + * ...deal with the failure... + * error_free(err); + * } else { + * QMyObject *src = QMY_OBJECT(qio_task_get_source(task)); + * ...deal with the completion... + * } + * } + * </programlisting> + * </example> + * + * Now, lets say the implementation of the method using the + * task wants to set a timer to run once a second checking + * for completion of some activity. It would do something + * like + * + * <example> + * <title>Task function implementation</title> + * <programlisting> + * void myobject_operation(QMyObject *obj, + * QIOTaskFunc *func, + * gpointer opaque, + * GDestroyNotify notify) + * { + * QIOTask *task; + * + * task = qio_task_new(OBJECT(obj), func, opaque, notify); + * + * g_timeout_add_full(G_PRIORITY_DEFAULT, + * 1000, + * myobject_operation_timer, + * task, + * NULL); + * } + * </programlisting> + * </example> + * + * It could equally have setup a watch on a file descriptor or + * created a background thread, or something else entirely. + * Notice that the source object is passed to the task, and + * QIOTask will hold a reference on that. This ensure that + * the QMyObject instance cannot be garbage collected while + * the async task is still in progress. + * + * In this case, myobject_operation_timer will fire after + * 3 secs and do + * + * <example> + * <title>Task timer function</title> + * <programlisting> + * gboolean myobject_operation_timer(gpointer opaque) + * { + * QIOTask *task = QIO_TASK(opaque); + * Error *err = NULL; + * + * ...check something important... + * if (err) { + * qio_task_set_error(task, err); + * qio_task_complete(task); + * return FALSE; + * } else if (...work is completed ...) { + * qio_task_complete(task); + * return FALSE; + * } + * ...carry on polling ... + * return TRUE; + * } + * </programlisting> + * </example> + * + * The 'qio_task_complete' call in this method will trigger + * the callback func 'myobject_operation_notify' shown + * earlier to deal with the results. + * + * Once this function returns false, object_unref will be called + * automatically on the task causing it to be released and the + * ref on QMyObject dropped too. + * + * The QIOTask module can also be used to perform operations + * in a background thread context, while still reporting the + * results in the main event thread. This allows code which + * cannot easily be rewritten to be asychronous (such as DNS + * lookups) to be easily run non-blocking. Reporting the + * results in the main thread context means that the caller + * typically does not need to be concerned about thread + * safety wrt the QEMU global mutex. + * + * For example, the socket_listen() method will block the caller + * while DNS lookups take place if given a name, instead of IP + * address. The C library often do not provide a practical async + * DNS API, so the to get non-blocking DNS lookups in a portable + * manner requires use of a thread. So achieve a non-blocking + * socket listen using QIOTask would require: + * + * <example> + * static void myobject_listen_worker(QIOTask *task, + * gpointer opaque) + * { + * QMyObject obj = QMY_OBJECT(qio_task_get_source(task)); + * SocketAddress *addr = opaque; + * Error *err = NULL; + * + * obj->fd = socket_listen(addr, &err); + * + qio_task_set_error(task, err); + * } + * + * void myobject_listen_async(QMyObject *obj, + * SocketAddress *addr, + * QIOTaskFunc *func, + * gpointer opaque, + * GDestroyNotify notify) + * { + * QIOTask *task; + * SocketAddress *addrCopy; + * + * addrCopy = QAPI_CLONE(SocketAddress, addr); + * task = qio_task_new(OBJECT(obj), func, opaque, notify); + * + * qio_task_run_in_thread(task, myobject_listen_worker, + * addrCopy, + * qapi_free_SocketAddress); + * } + * </example> + * + * NB, The 'func' callback passed into myobject_listen_async + * will be invoked from the main event thread, despite the + * actual operation being performed in a different thread. + */ + +/** + * qio_task_new: + * @source: the object on which the operation is invoked + * @func: the callback to invoke when the task completes + * @opaque: opaque data to pass to @func when invoked + * @destroy: optional callback to free @opaque + * + * Creates a new task struct to track completion of a + * background operation running on the object @source. + * When the operation completes or fails, the callback + * @func will be invoked. The callback can access the + * 'err' attribute in the task object to determine if + * the operation was successful or not. + * + * The returned task will be released when qio_task_complete() + * is invoked. + * + * Returns: the task struct + */ +QIOTask *qio_task_new(Object *source, + QIOTaskFunc func, + gpointer opaque, + GDestroyNotify destroy); + +/** + * qio_task_run_in_thread: + * @task: the task struct + * @worker: the function to invoke in a thread + * @opaque: opaque data to pass to @worker + * @destroy: function to free @opaque + * @context: the context to run the complete hook. If %NULL, the + * default context will be used. + * + * Run a task in a background thread. When @worker + * returns it will call qio_task_complete() in + * the thread that is running the main loop associated + * with @context. + */ +void qio_task_run_in_thread(QIOTask *task, + QIOTaskWorker worker, + gpointer opaque, + GDestroyNotify destroy, + GMainContext *context); + + +/** + * qio_task_wait_thread: + * @task: the task struct + * + * Wait for completion of a task that was previously + * invoked using qio_task_run_in_thread. This MUST + * ONLY be invoked if the task has not already + * completed, since after the completion callback + * is invoked, @task will have been freed. + * + * To avoid racing with execution of the completion + * callback provided with qio_task_new, this method + * MUST ONLY be invoked from the thread that is + * running the main loop associated with @context + * parameter to qio_task_run_in_thread. + * + * When the thread has completed, the completion + * callback provided to qio_task_new will be invoked. + * When that callback returns @task will be freed, + * so @task must not be referenced after this + * method completes. + */ +void qio_task_wait_thread(QIOTask *task); + + +/** + * qio_task_complete: + * @task: the task struct + * + * Invoke the completion callback for @task and + * then free its memory. + */ +void qio_task_complete(QIOTask *task); + + +/** + * qio_task_set_error: + * @task: the task struct + * @err: pointer to the error, or NULL + * + * Associate an error with the task, which can later + * be retrieved with the qio_task_propagate_error() + * method. This method takes ownership of @err, so + * it is not valid to access it after this call + * completes. If @err is NULL this is a no-op. If + * this is call multiple times, only the first + * provided @err will be recorded, later ones will + * be discarded and freed. + */ +void qio_task_set_error(QIOTask *task, + Error *err); + + +/** + * qio_task_propagate_error: + * @task: the task struct + * @errp: pointer to a NULL-initialized error object + * + * Propagate the error associated with @task + * into @errp. + * + * Returns: true if an error was propagated, false otherwise + */ +bool qio_task_propagate_error(QIOTask *task, + Error **errp); + + +/** + * qio_task_set_result_pointer: + * @task: the task struct + * @result: pointer to the result data + * + * Associate an opaque result with the task, + * which can later be retrieved with the + * qio_task_get_result_pointer() method + * + */ +void qio_task_set_result_pointer(QIOTask *task, + gpointer result, + GDestroyNotify notify); + + +/** + * qio_task_get_result_pointer: + * @task: the task struct + * + * Retrieve the opaque result data associated + * with the task, if any. + * + * Returns: the task result, or NULL + */ +gpointer qio_task_get_result_pointer(QIOTask *task); + + +/** + * qio_task_get_source: + * @task: the task struct + * + * Get the source object associated with the background + * task. The caller does not own a reference on the + * returned Object, and so should call object_ref() + * if it wants to keep the object pointer outside the + * lifetime of the QIOTask object. + * + * Returns: the source object + */ +Object *qio_task_get_source(QIOTask *task); + +#endif /* QIO_TASK_H */ |