diff options
-rw-r--r-- | MAINTAINERS | 13 | ||||
-rw-r--r-- | Makefile.objs | 4 | ||||
-rw-r--r-- | block.c | 2 | ||||
-rw-r--r-- | block/qcow2.h | 2 | ||||
-rw-r--r-- | block/vdi.c | 2 | ||||
-rw-r--r-- | block/write-threshold.c | 2 | ||||
-rw-r--r-- | blockjob.c | 2 | ||||
-rw-r--r-- | hw/9pfs/codir.c | 2 | ||||
-rw-r--r-- | hw/9pfs/cofile.c | 2 | ||||
-rw-r--r-- | hw/9pfs/cofs.c | 2 | ||||
-rw-r--r-- | hw/9pfs/coxattr.c | 2 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p-coth.c | 2 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p-coth.h | 2 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p.h | 2 | ||||
-rw-r--r-- | include/block/block.h | 2 | ||||
-rw-r--r-- | include/block/block_int.h | 2 | ||||
-rw-r--r-- | include/qemu/buffer.h | 118 | ||||
-rw-r--r-- | include/qemu/coroutine.h (renamed from include/block/coroutine.h) | 0 | ||||
-rw-r--r-- | include/qemu/coroutine_int.h (renamed from include/block/coroutine_int.h) | 2 | ||||
-rw-r--r-- | include/qemu/osdep.h | 16 | ||||
-rw-r--r-- | include/qemu/sockets.h | 34 | ||||
-rw-r--r-- | migration/qemu-file-buf.c | 2 | ||||
-rw-r--r-- | migration/qemu-file-stdio.c | 2 | ||||
-rw-r--r-- | migration/qemu-file-unix.c | 2 | ||||
-rw-r--r-- | migration/qemu-file.c | 2 | ||||
-rw-r--r-- | migration/rdma.c | 2 | ||||
-rw-r--r-- | nbd.c | 2 | ||||
-rw-r--r-- | qapi-schema.json | 6 | ||||
-rw-r--r-- | qemu-char.c | 25 | ||||
-rw-r--r-- | tests/test-coroutine.c | 4 | ||||
-rw-r--r-- | tests/test-vmstate.c | 2 | ||||
-rw-r--r-- | thread-pool.c | 2 | ||||
-rw-r--r-- | ui/vnc.c | 203 | ||||
-rw-r--r-- | ui/vnc.h | 16 | ||||
-rw-r--r-- | util/Makefile.objs | 4 | ||||
-rw-r--r-- | util/buffer.c | 65 | ||||
-rw-r--r-- | util/coroutine-gthread.c (renamed from coroutine-gthread.c) | 2 | ||||
-rw-r--r-- | util/coroutine-sigaltstack.c (renamed from coroutine-sigaltstack.c) | 2 | ||||
-rw-r--r-- | util/coroutine-ucontext.c (renamed from coroutine-ucontext.c) | 2 | ||||
-rw-r--r-- | util/coroutine-win32.c (renamed from coroutine-win32.c) | 2 | ||||
-rw-r--r-- | util/oslib-posix.c | 71 | ||||
-rw-r--r-- | util/oslib-win32.c | 9 | ||||
-rw-r--r-- | util/qemu-coroutine-io.c (renamed from qemu-coroutine-io.c) | 2 | ||||
-rw-r--r-- | util/qemu-coroutine-lock.c (renamed from qemu-coroutine-lock.c) | 4 | ||||
-rw-r--r-- | util/qemu-coroutine-sleep.c (renamed from qemu-coroutine-sleep.c) | 2 | ||||
-rw-r--r-- | util/qemu-coroutine.c (renamed from qemu-coroutine.c) | 4 | ||||
-rw-r--r-- | util/qemu-sockets.c | 158 |
47 files changed, 613 insertions, 199 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 01fb6e2..3144113 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1193,6 +1193,19 @@ F: crypto/ F: include/crypto/ F: tests/test-crypto-* +Coroutines +M: Stefan Hajnoczi <stefanha@redhat.com> +M: Kevin Wolf <kwolf@redhat.com> +F: util/*coroutine* +F: include/qemu/coroutine* +F: tests/test-coroutine.c + +Buffers +M: Daniel P. Berrange <berrange@redhat.com> +S: Odd fixes +F: util/buffer.c +F: include/qemu/buffer.h + Usermode Emulation ------------------ Overall diff --git a/Makefile.objs b/Makefile.objs index bc43e5c..ecfe03c 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -15,10 +15,6 @@ block-obj-$(CONFIG_WIN32) += aio-win32.o block-obj-y += block/ block-obj-y += qemu-io-cmds.o -block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o -block-obj-y += qemu-coroutine-sleep.o -block-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o - block-obj-m = block/ ####################################################################### @@ -33,7 +33,7 @@ #include "sysemu/block-backend.h" #include "sysemu/sysemu.h" #include "qemu/notify.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "block/qapi.h" #include "qmp-commands.h" #include "qemu/timer.h" diff --git a/block/qcow2.h b/block/qcow2.h index 3512263..b8c500b 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -26,7 +26,7 @@ #define BLOCK_QCOW2_H #include "crypto/cipher.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" //#define DEBUG_ALLOC //#define DEBUG_ALLOC2 diff --git a/block/vdi.c b/block/vdi.c index 17626d4..17f435f 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -53,7 +53,7 @@ #include "block/block_int.h" #include "qemu/module.h" #include "migration/migration.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #if defined(CONFIG_UUID) #include <uuid/uuid.h> diff --git a/block/write-threshold.c b/block/write-threshold.c index a53c1f5..0fe3891 100644 --- a/block/write-threshold.c +++ b/block/write-threshold.c @@ -11,7 +11,7 @@ */ #include "block/block_int.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "block/write-threshold.h" #include "qemu/notify.h" #include "qapi-event.h" @@ -31,7 +31,7 @@ #include "block/block_int.h" #include "qapi/qmp/qerror.h" #include "qapi/qmp/qjson.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "qmp-commands.h" #include "qemu/timer.h" #include "qapi-event.h" diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c index 65ad329..ec9cc7f 100644 --- a/hw/9pfs/codir.c +++ b/hw/9pfs/codir.c @@ -14,7 +14,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "virtio-9p-coth.h" int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent, diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c index 2efebf3..7cb55ee 100644 --- a/hw/9pfs/cofile.c +++ b/hw/9pfs/cofile.c @@ -14,7 +14,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "virtio-9p-coth.h" int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode, diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c index 42ee614..e1953a9 100644 --- a/hw/9pfs/cofs.c +++ b/hw/9pfs/cofs.c @@ -14,7 +14,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "virtio-9p-coth.h" static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString *buf) diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c index 18ee08d..55c0d23 100644 --- a/hw/9pfs/coxattr.c +++ b/hw/9pfs/coxattr.c @@ -14,7 +14,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "virtio-9p-coth.h" int v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path, void *value, size_t size) diff --git a/hw/9pfs/virtio-9p-coth.c b/hw/9pfs/virtio-9p-coth.c index 8185c53..5057f8d 100644 --- a/hw/9pfs/virtio-9p-coth.c +++ b/hw/9pfs/virtio-9p-coth.c @@ -15,7 +15,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" #include "qemu/event_notifier.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "virtio-9p-coth.h" /* v9fs glib thread pool */ diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h index 4f51b25..0fbe49a 100644 --- a/hw/9pfs/virtio-9p-coth.h +++ b/hw/9pfs/virtio-9p-coth.h @@ -16,7 +16,7 @@ #define _QEMU_VIRTIO_9P_COTH_H #include "qemu/thread.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "virtio-9p.h" #include <glib.h> diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 2e7d488..d7a4dc1 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -13,7 +13,7 @@ #include "fsdev/file-op-9p.h" #include "fsdev/virtio-9p-marshal.h" #include "qemu/thread.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" enum { P9_TLERROR = 6, diff --git a/include/block/block.h b/include/block/block.h index 6d70eb4..84f05ad 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -4,7 +4,7 @@ #include "block/aio.h" #include "qemu-common.h" #include "qemu/option.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "block/accounting.h" #include "qapi/qmp/qobject.h" #include "qapi-types.h" diff --git a/include/block/block_int.h b/include/block/block_int.h index c0e6513..a480f94 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -28,7 +28,7 @@ #include "block/block.h" #include "qemu/option.h" #include "qemu/queue.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "qemu/timer.h" #include "qapi-types.h" #include "qemu/hbitmap.h" diff --git a/include/qemu/buffer.h b/include/qemu/buffer.h new file mode 100644 index 0000000..b380cec --- /dev/null +++ b/include/qemu/buffer.h @@ -0,0 +1,118 @@ +/* + * QEMU generic buffers + * + * 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 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 QEMU_BUFFER_H__ +#define QEMU_BUFFER_H__ + +#include "qemu-common.h" + +typedef struct Buffer Buffer; + +/** + * Buffer: + * + * The Buffer object provides a simple dynamically resizing + * array, with separate tracking of capacity and usage. This + * is typically useful when buffering I/O or processing data. + */ + +struct Buffer { + size_t capacity; + size_t offset; + uint8_t *buffer; +}; + +/** + * buffer_reserve: + * @buffer: the buffer object + * @len: the minimum required free space + * + * Ensure that the buffer has space allocated for at least + * @len bytes. If the current buffer is too small, it will + * be reallocated, possibly to a larger size than requested. + */ +void buffer_reserve(Buffer *buffer, size_t len); + +/** + * buffer_reset: + * @buffer: the buffer object + * + * Reset the length of the stored data to zero, but do + * not free / reallocate the memory buffer + */ +void buffer_reset(Buffer *buffer); + +/** + * buffer_free: + * @buffer: the buffer object + * + * Reset the length of the stored data to zero and also + * free the internal memory buffer + */ +void buffer_free(Buffer *buffer); + +/** + * buffer_append: + * @buffer: the buffer object + * @data: the data block to append + * @len: the length of @data in bytes + * + * Append the contents of @data to the end of the buffer. + * The caller must ensure that the buffer has sufficient + * free space for @len bytes, typically by calling the + * buffer_reserve() method prior to appending. + */ +void buffer_append(Buffer *buffer, const void *data, size_t len); + +/** + * buffer_advance: + * @buffer: the buffer object + * @len: the number of bytes to skip + * + * Remove @len bytes of data from the head of the buffer. + * The internal buffer will not be reallocated, so will + * have at least @len bytes of free space after this + * call completes + */ +void buffer_advance(Buffer *buffer, size_t len); + +/** + * buffer_end: + * @buffer: the buffer object + * + * Get a pointer to the tail end of the internal buffer + * The returned pointer is only valid until the next + * call to buffer_reserve(). + * + * Returns: the tail of the buffer + */ +uint8_t *buffer_end(Buffer *buffer); + +/** + * buffer_empty: + * @buffer: the buffer object + * + * Determine if the buffer contains any current data + * + * Returns: true if the buffer holds data, false otherwise + */ +gboolean buffer_empty(Buffer *buffer); + +#endif /* QEMU_BUFFER_H__ */ diff --git a/include/block/coroutine.h b/include/qemu/coroutine.h index 20c027a..20c027a 100644 --- a/include/block/coroutine.h +++ b/include/qemu/coroutine.h diff --git a/include/block/coroutine_int.h b/include/qemu/coroutine_int.h index 9aa1aae..42d6838 100644 --- a/include/block/coroutine_int.h +++ b/include/qemu/coroutine_int.h @@ -26,7 +26,7 @@ #define QEMU_COROUTINE_INT_H #include "qemu/queue.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" typedef enum { COROUTINE_YIELD = 1, diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index ef21efb..b568424 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -69,6 +69,8 @@ #include "sysemu/os-posix.h" #endif +#include "qapi/error.h" + #if defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10 /* [u]int_fast*_t not in <sys/int_types.h> */ typedef unsigned char uint_fast8_t; @@ -286,4 +288,18 @@ void os_mem_prealloc(int fd, char *area, size_t sz); int qemu_read_password(char *buf, int buf_size); +/** + * qemu_fork: + * + * A version of fork that avoids signal handler race + * conditions that can lead to child process getting + * signals that are otherwise only expected by the + * parent. It also resets all signal handlers to the + * default settings. + * + * Returns 0 to child process, pid number to parent + * or -1 on failure. + */ +pid_t qemu_fork(Error **errp); + #endif diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index c174b5c..5a183c5 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -88,4 +88,38 @@ int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp); int parse_host_port(struct sockaddr_in *saddr, const char *str); int socket_init(void); +/** + * socket_local_address: + * @fd: the socket file handle + * @errp: pointer to uninitialized 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 *socket_local_address(int fd, Error **errp); + +/** + * socket_remote_address: + * @fd: the socket file handle + * @errp: pointer to uninitialized error object + * + * Get the string representation of the remote 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 *socket_remote_address(int fd, Error **errp); + + +void qapi_copy_SocketAddress(SocketAddress **p_dest, + SocketAddress *src); + #endif /* QEMU_SOCKET_H */ diff --git a/migration/qemu-file-buf.c b/migration/qemu-file-buf.c index e3fd085..49516b8 100644 --- a/migration/qemu-file-buf.c +++ b/migration/qemu-file-buf.c @@ -29,7 +29,7 @@ #include "qemu/error-report.h" #include "qemu/iov.h" #include "qemu/sockets.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "migration/migration.h" #include "migration/qemu-file.h" #include "migration/qemu-file-internal.h" diff --git a/migration/qemu-file-stdio.c b/migration/qemu-file-stdio.c index 889ffb3..9bde9db 100644 --- a/migration/qemu-file-stdio.c +++ b/migration/qemu-file-stdio.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "migration/qemu-file.h" typedef struct QEMUFileStdio { diff --git a/migration/qemu-file-unix.c b/migration/qemu-file-unix.c index bf7a0e4..809bf07 100644 --- a/migration/qemu-file-unix.c +++ b/migration/qemu-file-unix.c @@ -24,7 +24,7 @@ #include "qemu-common.h" #include "qemu/iov.h" #include "qemu/sockets.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "migration/qemu-file.h" #include "migration/qemu-file-internal.h" diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 49addf6..df49023 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -26,7 +26,7 @@ #include "qemu/error-report.h" #include "qemu/iov.h" #include "qemu/sockets.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "migration/migration.h" #include "migration/qemu-file.h" #include "migration/qemu-file-internal.h" diff --git a/migration/rdma.c b/migration/rdma.c index 7a7176f..553fbd7 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -19,7 +19,7 @@ #include "qemu/main-loop.h" #include "qemu/sockets.h" #include "qemu/bitmap.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> @@ -19,7 +19,7 @@ #include "block/nbd.h" #include "sysemu/block-backend.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include <errno.h> #include <string.h> diff --git a/qapi-schema.json b/qapi-schema.json index 702b7b5..f60be29 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2614,7 +2614,9 @@ # # @host: host part of the address # -# @port: port part of the address, or lowest port if @to is present +# @port: port part of the address, or lowest port if @to is present. +# Kernel selects a free port if omitted for listener addresses. +# #optional # # @to: highest port to try # @@ -2629,7 +2631,7 @@ { 'struct': 'InetSocketAddress', 'data': { 'host': 'str', - 'port': 'str', + '*port': 'str', '*to': 'uint16', '*ipv4': 'bool', '*ipv6': 'bool' } } diff --git a/qemu-char.c b/qemu-char.c index 13371c4..908e712 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -92,31 +92,6 @@ /***********************************************************/ /* Socket address helpers */ -static void qapi_copy_SocketAddress(SocketAddress **p_dest, - SocketAddress *src) -{ - QmpOutputVisitor *qov; - QmpInputVisitor *qiv; - Visitor *ov, *iv; - QObject *obj; - - *p_dest = NULL; - - qov = qmp_output_visitor_new(); - ov = qmp_output_get_visitor(qov); - visit_type_SocketAddress(ov, &src, NULL, &error_abort); - obj = qmp_output_get_qobject(qov); - qmp_output_visitor_cleanup(qov); - if (!obj) { - return; - } - - qiv = qmp_input_visitor_new(obj); - iv = qmp_input_get_visitor(qiv); - visit_type_SocketAddress(iv, p_dest, NULL, &error_abort); - qmp_input_visitor_cleanup(qiv); - qobject_decref(obj); -} static int SocketAddress_to_str(char *dest, int max_len, const char *prefix, SocketAddress *addr, diff --git a/tests/test-coroutine.c b/tests/test-coroutine.c index b552d9f..f5951cb 100644 --- a/tests/test-coroutine.c +++ b/tests/test-coroutine.c @@ -12,8 +12,8 @@ */ #include <glib.h> -#include "block/coroutine.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine.h" +#include "qemu/coroutine_int.h" /* * Check that qemu_in_coroutine() works diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c index 1d620e0..4d13bd0 100644 --- a/tests/test-vmstate.c +++ b/tests/test-vmstate.c @@ -27,7 +27,7 @@ #include "qemu-common.h" #include "migration/migration.h" #include "migration/vmstate.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" static char temp_file[] = "/tmp/vmst.test.XXXXXX"; static int temp_fd; diff --git a/thread-pool.c b/thread-pool.c index ac909f4..402c778 100644 --- a/thread-pool.c +++ b/thread-pool.c @@ -18,7 +18,7 @@ #include "qemu/queue.h" #include "qemu/thread.h" #include "qemu/osdep.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "trace.h" #include "block/thread-pool.h" #include "qemu/main-loop.h" @@ -647,49 +647,6 @@ void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, vnc_write_s32(vs, encoding); } -void buffer_reserve(Buffer *buffer, size_t len) -{ - if ((buffer->capacity - buffer->offset) < len) { - buffer->capacity += (len + 1024); - buffer->buffer = g_realloc(buffer->buffer, buffer->capacity); - } -} - -static int buffer_empty(Buffer *buffer) -{ - return buffer->offset == 0; -} - -uint8_t *buffer_end(Buffer *buffer) -{ - return buffer->buffer + buffer->offset; -} - -void buffer_reset(Buffer *buffer) -{ - buffer->offset = 0; -} - -void buffer_free(Buffer *buffer) -{ - g_free(buffer->buffer); - buffer->offset = 0; - buffer->capacity = 0; - buffer->buffer = NULL; -} - -void buffer_append(Buffer *buffer, const void *data, size_t len) -{ - memcpy(buffer->buffer + buffer->offset, data, len); - buffer->offset += len; -} - -void buffer_advance(Buffer *buf, size_t len) -{ - memmove(buf->buffer, buf->buffer + len, - (buf->offset - len)); - buf->offset -= len; -} static void vnc_desktop_resize(VncState *vs) { @@ -3506,18 +3463,14 @@ void vnc_display_open(const char *id, Error **errp) { VncDisplay *vs = vnc_display_find(id); QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id); - QemuOpts *sopts, *wsopts; + SocketAddress *saddr = NULL, *wsaddr = NULL; const char *share, *device_id; QemuConsole *con; bool password = false; bool reverse = false; const char *vnc; - const char *has_to; char *h; - bool has_ipv4 = false; - bool has_ipv6 = false; const char *credid; - const char *websocket; bool sasl = false; #ifdef CONFIG_VNC_SASL int saslErr; @@ -3539,44 +3492,83 @@ void vnc_display_open(const char *id, Error **errp) return; } - sopts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); - wsopts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); - h = strrchr(vnc, ':'); if (h) { - char *host; size_t hlen = h - vnc; - if (vnc[0] == '[' && vnc[hlen - 1] == ']') { - host = g_strndup(vnc + 1, hlen - 2); + const char *websocket = qemu_opt_get(opts, "websocket"); + int to = qemu_opt_get_number(opts, "to", 0); + bool has_ipv4 = qemu_opt_get_bool(opts, "ipv4", false); + bool has_ipv6 = qemu_opt_get_bool(opts, "ipv6", false); + + saddr = g_new0(SocketAddress, 1); + if (websocket) { + if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) { + error_setg(errp, + "SHA1 hash support is required for websockets"); + goto fail; + } + + wsaddr = g_new0(SocketAddress, 1); + vs->ws_enabled = true; + } + + if (strncmp(vnc, "unix:", 5) == 0) { + saddr->kind = SOCKET_ADDRESS_KIND_UNIX; + saddr->q_unix = g_new0(UnixSocketAddress, 1); + saddr->q_unix->path = g_strdup(vnc + 5); + + if (vs->ws_enabled) { + error_setg(errp, "UNIX sockets not supported with websock"); + goto fail; + } } else { - host = g_strndup(vnc, hlen); + unsigned long long baseport; + saddr->kind = SOCKET_ADDRESS_KIND_INET; + saddr->inet = g_new0(InetSocketAddress, 1); + if (vnc[0] == '[' && vnc[hlen - 1] == ']') { + saddr->inet->host = g_strndup(vnc + 1, hlen - 2); + } else { + saddr->inet->host = g_strndup(vnc, hlen); + } + if (parse_uint_full(h + 1, &baseport, 10) < 0) { + error_setg(errp, "can't convert to a number: %s", h + 1); + goto fail; + } + if (baseport > 65535 || + baseport + 5900 > 65535) { + error_setg(errp, "port %s out of range", h + 1); + goto fail; + } + saddr->inet->port = g_strdup_printf( + "%d", (int)baseport + 5900); + + if (to) { + saddr->inet->has_to = true; + saddr->inet->to = to; + } + saddr->inet->ipv4 = saddr->inet->has_ipv4 = has_ipv4; + saddr->inet->ipv6 = saddr->inet->has_ipv6 = has_ipv6; + + if (vs->ws_enabled) { + wsaddr->kind = SOCKET_ADDRESS_KIND_INET; + wsaddr->inet = g_new0(InetSocketAddress, 1); + wsaddr->inet->host = g_strdup(saddr->inet->host); + wsaddr->inet->port = g_strdup(websocket); + + if (to) { + wsaddr->inet->has_to = true; + wsaddr->inet->to = to; + } + wsaddr->inet->ipv4 = wsaddr->inet->has_ipv4 = has_ipv4; + wsaddr->inet->ipv6 = wsaddr->inet->has_ipv6 = has_ipv6; + } } - qemu_opt_set(sopts, "host", host, &error_abort); - qemu_opt_set(wsopts, "host", host, &error_abort); - qemu_opt_set(sopts, "port", h+1, &error_abort); - g_free(host); } else { error_setg(errp, "no vnc port specified"); goto fail; } - has_to = qemu_opt_get(opts, "to"); - has_ipv4 = qemu_opt_get_bool(opts, "ipv4", false); - has_ipv6 = qemu_opt_get_bool(opts, "ipv6", false); - if (has_to) { - qemu_opt_set(sopts, "to", has_to, &error_abort); - qemu_opt_set(wsopts, "to", has_to, &error_abort); - } - if (has_ipv4) { - qemu_opt_set(sopts, "ipv4", "on", &error_abort); - qemu_opt_set(wsopts, "ipv4", "on", &error_abort); - } - if (has_ipv6) { - qemu_opt_set(sopts, "ipv6", "on", &error_abort); - qemu_opt_set(wsopts, "ipv6", "on", &error_abort); - } - password = qemu_opt_get_bool(opts, "password", false); if (password) { if (fips_get_state()) { @@ -3682,16 +3674,6 @@ void vnc_display_open(const char *id, Error **errp) } vs->connections_limit = qemu_opt_get_number(opts, "connections", 32); - websocket = qemu_opt_get(opts, "websocket"); - if (websocket) { - vs->ws_enabled = true; - qemu_opt_set(wsopts, "port", websocket, &error_abort); - if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) { - error_setg(errp, "SHA1 hash support is required for websockets"); - goto fail; - } - } - #ifdef CONFIG_VNC_JPEG vs->lossy = qemu_opt_get_bool(opts, "lossy", false); #endif @@ -3725,7 +3707,7 @@ void vnc_display_open(const char *id, Error **errp) } #endif - if (vnc_display_setup_auth(vs, password, sasl, websocket, errp) < 0) { + if (vnc_display_setup_auth(vs, password, sasl, vs->ws_enabled, errp) < 0) { goto fail; } @@ -3770,37 +3752,31 @@ void vnc_display_open(const char *id, Error **errp) int csock; vs->lsock = -1; vs->lwebsock = -1; - if (strncmp(vnc, "unix:", 5) == 0) { - csock = unix_connect(vnc+5, errp); - } else { - csock = inet_connect(vnc, errp); + if (vs->ws_enabled) { + error_setg(errp, "Cannot use websockets in reverse mode"); + goto fail; } + csock = socket_connect(saddr, errp, NULL, NULL); if (csock < 0) { goto fail; } + vs->is_unix = saddr->kind == SOCKET_ADDRESS_KIND_UNIX; vnc_connect(vs, csock, false, false); } else { /* listen for connects */ - if (strncmp(vnc, "unix:", 5) == 0) { - vs->lsock = unix_listen(vnc+5, NULL, 0, errp); - if (vs->lsock < 0) { - goto fail; - } - vs->is_unix = true; - } else { - vs->lsock = inet_listen_opts(sopts, 5900, errp); - if (vs->lsock < 0) { - goto fail; - } - if (vs->ws_enabled) { - vs->lwebsock = inet_listen_opts(wsopts, 0, errp); - if (vs->lwebsock < 0) { - if (vs->lsock != -1) { - close(vs->lsock); - vs->lsock = -1; - } - goto fail; + vs->lsock = socket_listen(saddr, errp); + if (vs->lsock < 0) { + goto fail; + } + vs->is_unix = saddr->kind == SOCKET_ADDRESS_KIND_UNIX; + if (vs->ws_enabled) { + vs->lwebsock = socket_listen(wsaddr, errp); + if (vs->lwebsock < 0) { + if (vs->lsock != -1) { + close(vs->lsock); + vs->lsock = -1; } + goto fail; } } vs->enabled = true; @@ -3810,13 +3786,14 @@ void vnc_display_open(const char *id, Error **errp) NULL, vs); } } - qemu_opts_del(sopts); - qemu_opts_del(wsopts); + + qapi_free_SocketAddress(saddr); + qapi_free_SocketAddress(wsaddr); return; fail: - qemu_opts_del(sopts); - qemu_opts_del(wsopts); + qapi_free_SocketAddress(saddr); + qapi_free_SocketAddress(wsaddr); vs->enabled = false; vs->ws_enabled = false; } @@ -34,6 +34,7 @@ #include "audio/audio.h" #include "qemu/bitmap.h" #include "crypto/tlssession.h" +#include "qemu/buffer.h" #include <zlib.h> #include <stdbool.h> @@ -56,13 +57,6 @@ * *****************************************************************************/ -typedef struct Buffer -{ - size_t capacity; - size_t offset; - uint8_t *buffer; -} Buffer; - typedef struct VncState VncState; typedef struct VncJob VncJob; typedef struct VncRect VncRect; @@ -535,14 +529,6 @@ ssize_t vnc_client_io_error(VncState *vs, ssize_t ret, int last_errno); void start_client_init(VncState *vs); void start_auth_vnc(VncState *vs); -/* Buffer management */ -void buffer_reserve(Buffer *buffer, size_t len); -void buffer_reset(Buffer *buffer); -void buffer_free(Buffer *buffer); -void buffer_append(Buffer *buffer, const void *data, size_t len); -void buffer_advance(Buffer *buf, size_t len); -uint8_t *buffer_end(Buffer *buffer); - /* Misc helpers */ diff --git a/util/Makefile.objs b/util/Makefile.objs index 114d657..1363d1f 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -18,3 +18,7 @@ util-obj-y += getauxval.o util-obj-y += readline.o util-obj-y += rfifolock.o util-obj-y += rcu.o +util-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o +util-obj-y += qemu-coroutine-sleep.o +util-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o +util-obj-y += buffer.o diff --git a/util/buffer.c b/util/buffer.c new file mode 100644 index 0000000..cedd055 --- /dev/null +++ b/util/buffer.c @@ -0,0 +1,65 @@ +/* + * QEMU generic buffers + * + * 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 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/>. + * + */ + +#include "qemu/buffer.h" + +void buffer_reserve(Buffer *buffer, size_t len) +{ + if ((buffer->capacity - buffer->offset) < len) { + buffer->capacity += (len + 1024); + buffer->buffer = g_realloc(buffer->buffer, buffer->capacity); + } +} + +gboolean buffer_empty(Buffer *buffer) +{ + return buffer->offset == 0; +} + +uint8_t *buffer_end(Buffer *buffer) +{ + return buffer->buffer + buffer->offset; +} + +void buffer_reset(Buffer *buffer) +{ + buffer->offset = 0; +} + +void buffer_free(Buffer *buffer) +{ + g_free(buffer->buffer); + buffer->offset = 0; + buffer->capacity = 0; + buffer->buffer = NULL; +} + +void buffer_append(Buffer *buffer, const void *data, size_t len) +{ + memcpy(buffer->buffer + buffer->offset, data, len); + buffer->offset += len; +} + +void buffer_advance(Buffer *buffer, size_t len) +{ + memmove(buffer->buffer, buffer->buffer + len, + (buffer->offset - len)); + buffer->offset -= len; +} diff --git a/coroutine-gthread.c b/util/coroutine-gthread.c index 6bd6d6b..0bcd778 100644 --- a/coroutine-gthread.c +++ b/util/coroutine-gthread.c @@ -20,7 +20,7 @@ #include <glib.h> #include "qemu-common.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine_int.h" typedef struct { Coroutine base; diff --git a/coroutine-sigaltstack.c b/util/coroutine-sigaltstack.c index 63519ff..39842a4 100644 --- a/coroutine-sigaltstack.c +++ b/util/coroutine-sigaltstack.c @@ -31,7 +31,7 @@ #include <pthread.h> #include <signal.h> #include "qemu-common.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine_int.h" typedef struct { Coroutine base; diff --git a/coroutine-ucontext.c b/util/coroutine-ucontext.c index 259fcb4..26cbebb 100644 --- a/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -27,7 +27,7 @@ #include <stdint.h> #include <ucontext.h> #include "qemu-common.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine_int.h" #ifdef CONFIG_VALGRIND_H #include <valgrind/valgrind.h> diff --git a/coroutine-win32.c b/util/coroutine-win32.c index 17ace37..4f922c5 100644 --- a/coroutine-win32.c +++ b/util/coroutine-win32.c @@ -23,7 +23,7 @@ */ #include "qemu-common.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine_int.h" typedef struct { diff --git a/util/oslib-posix.c b/util/oslib-posix.c index a0fcdc2..4024918 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -490,3 +490,74 @@ int qemu_read_password(char *buf, int buf_size) printf("\n"); return ret; } + + +pid_t qemu_fork(Error **errp) +{ + sigset_t oldmask, newmask; + struct sigaction sig_action; + int saved_errno; + pid_t pid; + + /* + * Need to block signals now, so that child process can safely + * kill off caller's signal handlers without a race. + */ + sigfillset(&newmask); + if (pthread_sigmask(SIG_SETMASK, &newmask, &oldmask) != 0) { + error_setg_errno(errp, errno, + "cannot block signals"); + return -1; + } + + pid = fork(); + saved_errno = errno; + + if (pid < 0) { + /* attempt to restore signal mask, but ignore failure, to + * avoid obscuring the fork failure */ + (void)pthread_sigmask(SIG_SETMASK, &oldmask, NULL); + error_setg_errno(errp, saved_errno, + "cannot fork child process"); + errno = saved_errno; + return -1; + } else if (pid) { + /* parent process */ + + /* Restore our original signal mask now that the child is + * safely running. Only documented failures are EFAULT (not + * possible, since we are using just-grabbed mask) or EINVAL + * (not possible, since we are using correct arguments). */ + (void)pthread_sigmask(SIG_SETMASK, &oldmask, NULL); + } else { + /* child process */ + size_t i; + + /* Clear out all signal handlers from parent so nothing + * unexpected can happen in our child once we unblock + * signals */ + sig_action.sa_handler = SIG_DFL; + sig_action.sa_flags = 0; + sigemptyset(&sig_action.sa_mask); + + for (i = 1; i < NSIG; i++) { + /* Only possible errors are EFAULT or EINVAL The former + * won't happen, the latter we expect, so no need to check + * return value */ + (void)sigaction(i, &sig_action, NULL); + } + + /* Unmask all signals in child, since we've no idea what the + * caller's done with their signal mask and don't want to + * propagate that to children */ + sigemptyset(&newmask); + if (pthread_sigmask(SIG_SETMASK, &newmask, NULL) != 0) { + Error *local_err = NULL; + error_setg_errno(&local_err, errno, + "cannot unblock signals"); + error_report_err(local_err); + _exit(1); + } + } + return pid; +} diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 08f5a9c..09f9e98 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -496,3 +496,12 @@ int qemu_read_password(char *buf, int buf_size) buf[i] = '\0'; return 0; } + + +pid_t qemu_fork(Error **errp) +{ + errno = ENOSYS; + error_setg_errno(errp, errno, + "cannot fork child process"); + return -1; +} diff --git a/qemu-coroutine-io.c b/util/qemu-coroutine-io.c index 28dc735..e1eae73 100644 --- a/qemu-coroutine-io.c +++ b/util/qemu-coroutine-io.c @@ -24,7 +24,7 @@ */ #include "qemu-common.h" #include "qemu/sockets.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "qemu/iov.h" #include "qemu/main-loop.h" diff --git a/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index 6b49033..130ee19 100644 --- a/qemu-coroutine-lock.c +++ b/util/qemu-coroutine-lock.c @@ -23,8 +23,8 @@ */ #include "qemu-common.h" -#include "block/coroutine.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine.h" +#include "qemu/coroutine_int.h" #include "qemu/queue.h" #include "trace.h" diff --git a/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c index 9abb7fd..b35db56 100644 --- a/qemu-coroutine-sleep.c +++ b/util/qemu-coroutine-sleep.c @@ -11,7 +11,7 @@ * */ -#include "block/coroutine.h" +#include "qemu/coroutine.h" #include "qemu/timer.h" #include "block/aio.h" diff --git a/qemu-coroutine.c b/util/qemu-coroutine.c index c17a92b..8953560 100644 --- a/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -16,8 +16,8 @@ #include "qemu-common.h" #include "qemu/thread.h" #include "qemu/atomic.h" -#include "block/coroutine.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine.h" +#include "qemu/coroutine_int.h" enum { POOL_BATCH_SIZE = 64, diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 0a041a9..9142917 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -25,6 +25,9 @@ #include "monitor/monitor.h" #include "qemu/sockets.h" #include "qemu/main-loop.h" +#include "qapi/qmp-input-visitor.h" +#include "qapi/qmp-output-visitor.h" +#include "qapi-visit.h" #ifndef AI_ADDRCONFIG # define AI_ADDRCONFIG 0 @@ -125,12 +128,15 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_STREAM; - if ((qemu_opt_get(opts, "host") == NULL) || - (qemu_opt_get(opts, "port") == NULL)) { - error_setg(errp, "host and/or port not specified"); + if ((qemu_opt_get(opts, "host") == NULL)) { + error_setg(errp, "host not specified"); return -1; } - pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port")); + if (qemu_opt_get(opts, "port") != NULL) { + pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port")); + } else { + port[0] = '\0'; + } addr = qemu_opt_get(opts, "host"); to = qemu_opt_get_number(opts, "to", 0); @@ -142,6 +148,10 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) /* lookup */ if (port_offset) { unsigned long long baseport; + if (strlen(port) == 0) { + error_setg(errp, "port not specified"); + return -1; + } if (parse_uint_full(port, &baseport, 10) < 0) { error_setg(errp, "can't convert to a number: %s", port); return -1; @@ -153,7 +163,8 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) } snprintf(port, sizeof(port), "%d", (int)baseport + port_offset); } - rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); + rc = getaddrinfo(strlen(addr) ? addr : NULL, + strlen(port) ? port : NULL, &ai, &res); if (rc != 0) { error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, gai_strerror(rc)); @@ -1018,3 +1029,140 @@ int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp) qemu_opts_del(opts); return fd; } + + +static SocketAddress * +socket_sockaddr_to_address_inet(struct sockaddr_storage *sa, + socklen_t salen, + Error **errp) +{ + char host[NI_MAXHOST]; + char serv[NI_MAXSERV]; + SocketAddress *addr; + int ret; + + ret = getnameinfo((struct sockaddr *)sa, salen, + host, sizeof(host), + serv, sizeof(serv), + NI_NUMERICHOST | NI_NUMERICSERV); + if (ret != 0) { + error_setg(errp, "Cannot format numeric socket address: %s", + gai_strerror(ret)); + return NULL; + } + + addr = g_new0(SocketAddress, 1); + addr->kind = SOCKET_ADDRESS_KIND_INET; + addr->inet = g_new0(InetSocketAddress, 1); + addr->inet->host = g_strdup(host); + addr->inet->port = g_strdup(serv); + if (sa->ss_family == AF_INET) { + addr->inet->has_ipv4 = addr->inet->ipv4 = true; + } else { + addr->inet->has_ipv6 = addr->inet->ipv6 = true; + } + + return addr; +} + + +#ifndef WIN32 +static SocketAddress * +socket_sockaddr_to_address_unix(struct sockaddr_storage *sa, + socklen_t salen, + Error **errp) +{ + SocketAddress *addr; + struct sockaddr_un *su = (struct sockaddr_un *)sa; + + addr = g_new0(SocketAddress, 1); + addr->kind = SOCKET_ADDRESS_KIND_UNIX; + addr->q_unix = g_new0(UnixSocketAddress, 1); + if (su->sun_path[0]) { + addr->q_unix->path = g_strndup(su->sun_path, + sizeof(su->sun_path)); + } + + return addr; +} +#endif /* WIN32 */ + +static SocketAddress * +socket_sockaddr_to_address(struct sockaddr_storage *sa, + socklen_t salen, + Error **errp) +{ + switch (sa->ss_family) { + case AF_INET: + case AF_INET6: + return socket_sockaddr_to_address_inet(sa, salen, errp); + +#ifndef WIN32 + case AF_UNIX: + return socket_sockaddr_to_address_unix(sa, salen, errp); +#endif /* WIN32 */ + + default: + error_setg(errp, "socket family %d unsupported", + sa->ss_family); + return NULL; + } + return 0; +} + + +SocketAddress *socket_local_address(int fd, Error **errp) +{ + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); + + if (getsockname(fd, (struct sockaddr *)&ss, &sslen) < 0) { + error_setg_errno(errp, socket_error(), "%s", + "Unable to query local socket address"); + return NULL; + } + + return socket_sockaddr_to_address(&ss, sslen, errp); +} + + +SocketAddress *socket_remote_address(int fd, Error **errp) +{ + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); + + if (getpeername(fd, (struct sockaddr *)&ss, &sslen) < 0) { + error_setg_errno(errp, socket_error(), "%s", + "Unable to query remote socket address"); + return NULL; + } + + return socket_sockaddr_to_address(&ss, sslen, errp); +} + + +void qapi_copy_SocketAddress(SocketAddress **p_dest, + SocketAddress *src) +{ + QmpOutputVisitor *qov; + QmpInputVisitor *qiv; + Visitor *ov, *iv; + QObject *obj; + + *p_dest = NULL; + + qov = qmp_output_visitor_new(); + ov = qmp_output_get_visitor(qov); + visit_type_SocketAddress(ov, &src, NULL, &error_abort); + obj = qmp_output_get_qobject(qov); + qmp_output_visitor_cleanup(qov); + if (!obj) { + return; + } + + qiv = qmp_input_visitor_new(obj); + iv = qmp_input_get_visitor(qiv); + visit_type_SocketAddress(iv, p_dest, NULL, &error_abort); + qmp_input_visitor_cleanup(qiv); + qobject_decref(obj); +} |