2015-02-28 00:19:33 +08:00
|
|
|
/*
|
|
|
|
* QEMU I/O channel sockets test
|
|
|
|
*
|
2016-03-04 00:16:48 +08:00
|
|
|
* Copyright (c) 2015-2016 Red Hat, Inc.
|
2015-02-28 00:19:33 +08:00
|
|
|
*
|
|
|
|
* 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/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-02-09 02:08:51 +08:00
|
|
|
#include "qemu/osdep.h"
|
2015-02-28 00:19:33 +08:00
|
|
|
#include "io/channel-socket.h"
|
2016-02-03 22:00:28 +08:00
|
|
|
#include "io/channel-util.h"
|
2015-02-28 00:19:33 +08:00
|
|
|
#include "io-channel-helpers.h"
|
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 16:01:28 +08:00
|
|
|
#include "qapi/error.h"
|
2015-02-28 00:19:33 +08:00
|
|
|
|
2016-03-15 02:15:35 +08:00
|
|
|
#ifndef AI_ADDRCONFIG
|
|
|
|
# define AI_ADDRCONFIG 0
|
|
|
|
#endif
|
|
|
|
#ifndef EAI_ADDRFAMILY
|
|
|
|
# define EAI_ADDRFAMILY 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int check_bind(const char *hostname, bool *has_proto)
|
2015-02-28 00:19:33 +08:00
|
|
|
{
|
2016-03-15 02:15:35 +08:00
|
|
|
int fd = -1;
|
|
|
|
struct addrinfo ai, *res = NULL;
|
|
|
|
int rc;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
memset(&ai, 0, sizeof(ai));
|
2016-04-05 00:22:00 +08:00
|
|
|
ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
|
2016-03-15 02:15:35 +08:00
|
|
|
ai.ai_family = AF_UNSPEC;
|
|
|
|
ai.ai_socktype = SOCK_STREAM;
|
2015-02-28 00:19:33 +08:00
|
|
|
|
2016-03-15 02:15:35 +08:00
|
|
|
/* lookup */
|
|
|
|
rc = getaddrinfo(hostname, NULL, &ai, &res);
|
|
|
|
if (rc != 0) {
|
|
|
|
if (rc == EAI_ADDRFAMILY ||
|
|
|
|
rc == EAI_FAMILY) {
|
|
|
|
*has_proto = false;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
2016-03-08 19:39:36 +08:00
|
|
|
if (fd < 0) {
|
2016-03-15 02:15:35 +08:00
|
|
|
goto cleanup;
|
2015-02-28 00:19:33 +08:00
|
|
|
}
|
|
|
|
|
2016-03-15 02:15:35 +08:00
|
|
|
if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) {
|
2016-03-08 19:39:36 +08:00
|
|
|
if (errno == EADDRNOTAVAIL) {
|
|
|
|
*has_proto = false;
|
2016-03-15 02:15:35 +08:00
|
|
|
goto done;
|
2015-02-28 00:19:33 +08:00
|
|
|
}
|
2016-03-15 02:15:35 +08:00
|
|
|
goto cleanup;
|
2015-02-28 00:19:33 +08:00
|
|
|
}
|
|
|
|
|
2016-03-08 19:39:36 +08:00
|
|
|
*has_proto = true;
|
2016-03-15 02:15:35 +08:00
|
|
|
done:
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (fd != -1) {
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
if (res) {
|
|
|
|
freeaddrinfo(res);
|
|
|
|
}
|
|
|
|
return ret;
|
2016-03-08 19:39:36 +08:00
|
|
|
}
|
2015-02-28 00:19:33 +08:00
|
|
|
|
2016-03-08 19:39:36 +08:00
|
|
|
static int check_protocol_support(bool *has_ipv4, bool *has_ipv6)
|
|
|
|
{
|
2016-03-15 02:15:35 +08:00
|
|
|
if (check_bind("127.0.0.1", has_ipv4) < 0) {
|
2016-03-08 19:39:36 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2016-03-15 02:15:35 +08:00
|
|
|
if (check_bind("::1", has_ipv6) < 0) {
|
2016-03-08 19:39:36 +08:00
|
|
|
return -1;
|
2015-02-28 00:19:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_io_channel_set_socket_bufs(QIOChannel *src,
|
|
|
|
QIOChannel *dst)
|
|
|
|
{
|
|
|
|
int buflen = 64 * 1024;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make the socket buffers small so that we see
|
|
|
|
* the effects of partial reads/writes
|
|
|
|
*/
|
|
|
|
setsockopt(((QIOChannelSocket *)src)->fd,
|
|
|
|
SOL_SOCKET, SO_SNDBUF,
|
|
|
|
(char *)&buflen,
|
|
|
|
sizeof(buflen));
|
|
|
|
|
|
|
|
setsockopt(((QIOChannelSocket *)dst)->fd,
|
|
|
|
SOL_SOCKET, SO_SNDBUF,
|
|
|
|
(char *)&buflen,
|
|
|
|
sizeof(buflen));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_io_channel_setup_sync(SocketAddress *listen_addr,
|
|
|
|
SocketAddress *connect_addr,
|
|
|
|
QIOChannel **src,
|
|
|
|
QIOChannel **dst)
|
|
|
|
{
|
|
|
|
QIOChannelSocket *lioc;
|
|
|
|
|
|
|
|
lioc = qio_channel_socket_new();
|
|
|
|
qio_channel_socket_listen_sync(lioc, listen_addr, &error_abort);
|
|
|
|
|
|
|
|
if (listen_addr->type == SOCKET_ADDRESS_KIND_INET) {
|
|
|
|
SocketAddress *laddr = qio_channel_socket_get_local_address(
|
|
|
|
lioc, &error_abort);
|
|
|
|
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 06:48:37 +08:00
|
|
|
g_free(connect_addr->u.inet.data->port);
|
|
|
|
connect_addr->u.inet.data->port = g_strdup(laddr->u.inet.data->port);
|
2015-02-28 00:19:33 +08:00
|
|
|
|
|
|
|
qapi_free_SocketAddress(laddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
*src = QIO_CHANNEL(qio_channel_socket_new());
|
|
|
|
qio_channel_socket_connect_sync(
|
|
|
|
QIO_CHANNEL_SOCKET(*src), connect_addr, &error_abort);
|
|
|
|
qio_channel_set_delay(*src, false);
|
|
|
|
|
2016-03-08 23:26:39 +08:00
|
|
|
qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
|
2015-02-28 00:19:33 +08:00
|
|
|
*dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
|
|
|
|
g_assert(*dst);
|
|
|
|
|
|
|
|
test_io_channel_set_socket_bufs(*src, *dst);
|
|
|
|
|
|
|
|
object_unref(OBJECT(lioc));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct TestIOChannelData {
|
|
|
|
bool err;
|
|
|
|
GMainLoop *loop;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void test_io_channel_complete(Object *src,
|
|
|
|
Error *err,
|
|
|
|
gpointer opaque)
|
|
|
|
{
|
|
|
|
struct TestIOChannelData *data = opaque;
|
|
|
|
data->err = err != NULL;
|
|
|
|
g_main_loop_quit(data->loop);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_io_channel_setup_async(SocketAddress *listen_addr,
|
|
|
|
SocketAddress *connect_addr,
|
|
|
|
QIOChannel **src,
|
|
|
|
QIOChannel **dst)
|
|
|
|
{
|
|
|
|
QIOChannelSocket *lioc;
|
|
|
|
struct TestIOChannelData data;
|
|
|
|
|
|
|
|
data.loop = g_main_loop_new(g_main_context_default(),
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
lioc = qio_channel_socket_new();
|
|
|
|
qio_channel_socket_listen_async(
|
|
|
|
lioc, listen_addr,
|
|
|
|
test_io_channel_complete, &data, NULL);
|
|
|
|
|
|
|
|
g_main_loop_run(data.loop);
|
|
|
|
g_main_context_iteration(g_main_context_default(), FALSE);
|
|
|
|
|
|
|
|
g_assert(!data.err);
|
|
|
|
|
|
|
|
if (listen_addr->type == SOCKET_ADDRESS_KIND_INET) {
|
|
|
|
SocketAddress *laddr = qio_channel_socket_get_local_address(
|
|
|
|
lioc, &error_abort);
|
|
|
|
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 06:48:37 +08:00
|
|
|
g_free(connect_addr->u.inet.data->port);
|
|
|
|
connect_addr->u.inet.data->port = g_strdup(laddr->u.inet.data->port);
|
2015-02-28 00:19:33 +08:00
|
|
|
|
|
|
|
qapi_free_SocketAddress(laddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
*src = QIO_CHANNEL(qio_channel_socket_new());
|
|
|
|
|
|
|
|
qio_channel_socket_connect_async(
|
|
|
|
QIO_CHANNEL_SOCKET(*src), connect_addr,
|
|
|
|
test_io_channel_complete, &data, NULL);
|
|
|
|
|
|
|
|
g_main_loop_run(data.loop);
|
|
|
|
g_main_context_iteration(g_main_context_default(), FALSE);
|
|
|
|
|
|
|
|
g_assert(!data.err);
|
|
|
|
|
2016-03-08 23:26:39 +08:00
|
|
|
qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
|
2015-02-28 00:19:33 +08:00
|
|
|
*dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
|
|
|
|
g_assert(*dst);
|
|
|
|
|
|
|
|
qio_channel_set_delay(*src, false);
|
|
|
|
test_io_channel_set_socket_bufs(*src, *dst);
|
|
|
|
|
|
|
|
object_unref(OBJECT(lioc));
|
|
|
|
|
|
|
|
g_main_loop_unref(data.loop);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_io_channel(bool async,
|
|
|
|
SocketAddress *listen_addr,
|
2015-12-21 20:04:21 +08:00
|
|
|
SocketAddress *connect_addr,
|
|
|
|
bool passFD)
|
2015-02-28 00:19:33 +08:00
|
|
|
{
|
|
|
|
QIOChannel *src, *dst;
|
|
|
|
QIOChannelTest *test;
|
|
|
|
if (async) {
|
|
|
|
test_io_channel_setup_async(listen_addr, connect_addr, &src, &dst);
|
|
|
|
|
2015-12-21 20:04:21 +08:00
|
|
|
g_assert(!passFD ||
|
|
|
|
qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
|
|
|
|
g_assert(!passFD ||
|
|
|
|
qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
|
|
|
|
|
2015-02-28 00:19:33 +08:00
|
|
|
test = qio_channel_test_new();
|
|
|
|
qio_channel_test_run_threads(test, true, src, dst);
|
|
|
|
qio_channel_test_validate(test);
|
|
|
|
|
|
|
|
object_unref(OBJECT(src));
|
|
|
|
object_unref(OBJECT(dst));
|
|
|
|
|
|
|
|
test_io_channel_setup_async(listen_addr, connect_addr, &src, &dst);
|
|
|
|
|
2015-12-21 20:04:21 +08:00
|
|
|
g_assert(!passFD ||
|
|
|
|
qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
|
|
|
|
g_assert(!passFD ||
|
|
|
|
qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
|
|
|
|
|
2015-02-28 00:19:33 +08:00
|
|
|
test = qio_channel_test_new();
|
|
|
|
qio_channel_test_run_threads(test, false, src, dst);
|
|
|
|
qio_channel_test_validate(test);
|
|
|
|
|
|
|
|
object_unref(OBJECT(src));
|
|
|
|
object_unref(OBJECT(dst));
|
|
|
|
} else {
|
|
|
|
test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst);
|
|
|
|
|
2015-12-21 20:04:21 +08:00
|
|
|
g_assert(!passFD ||
|
|
|
|
qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
|
|
|
|
g_assert(!passFD ||
|
|
|
|
qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
|
|
|
|
|
2015-02-28 00:19:33 +08:00
|
|
|
test = qio_channel_test_new();
|
|
|
|
qio_channel_test_run_threads(test, true, src, dst);
|
|
|
|
qio_channel_test_validate(test);
|
|
|
|
|
|
|
|
object_unref(OBJECT(src));
|
|
|
|
object_unref(OBJECT(dst));
|
|
|
|
|
|
|
|
test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst);
|
|
|
|
|
2015-12-21 20:04:21 +08:00
|
|
|
g_assert(!passFD ||
|
|
|
|
qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
|
|
|
|
g_assert(!passFD ||
|
|
|
|
qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
|
|
|
|
|
2015-02-28 00:19:33 +08:00
|
|
|
test = qio_channel_test_new();
|
|
|
|
qio_channel_test_run_threads(test, false, src, dst);
|
|
|
|
qio_channel_test_validate(test);
|
|
|
|
|
|
|
|
object_unref(OBJECT(src));
|
|
|
|
object_unref(OBJECT(dst));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_io_channel_ipv4(bool async)
|
|
|
|
{
|
|
|
|
SocketAddress *listen_addr = g_new0(SocketAddress, 1);
|
|
|
|
SocketAddress *connect_addr = g_new0(SocketAddress, 1);
|
|
|
|
|
|
|
|
listen_addr->type = SOCKET_ADDRESS_KIND_INET;
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 06:48:37 +08:00
|
|
|
listen_addr->u.inet.data = g_new(InetSocketAddress, 1);
|
|
|
|
*listen_addr->u.inet.data = (InetSocketAddress) {
|
2016-03-04 00:16:48 +08:00
|
|
|
.host = g_strdup("127.0.0.1"),
|
|
|
|
.port = NULL, /* Auto-select */
|
|
|
|
};
|
2015-02-28 00:19:33 +08:00
|
|
|
|
|
|
|
connect_addr->type = SOCKET_ADDRESS_KIND_INET;
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 06:48:37 +08:00
|
|
|
connect_addr->u.inet.data = g_new(InetSocketAddress, 1);
|
|
|
|
*connect_addr->u.inet.data = (InetSocketAddress) {
|
2016-03-04 00:16:48 +08:00
|
|
|
.host = g_strdup("127.0.0.1"),
|
|
|
|
.port = NULL, /* Filled in later */
|
|
|
|
};
|
2015-02-28 00:19:33 +08:00
|
|
|
|
2015-12-21 20:04:21 +08:00
|
|
|
test_io_channel(async, listen_addr, connect_addr, false);
|
2015-02-28 00:19:33 +08:00
|
|
|
|
|
|
|
qapi_free_SocketAddress(listen_addr);
|
|
|
|
qapi_free_SocketAddress(connect_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_io_channel_ipv4_sync(void)
|
|
|
|
{
|
|
|
|
return test_io_channel_ipv4(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_io_channel_ipv4_async(void)
|
|
|
|
{
|
|
|
|
return test_io_channel_ipv4(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_io_channel_ipv6(bool async)
|
|
|
|
{
|
|
|
|
SocketAddress *listen_addr = g_new0(SocketAddress, 1);
|
|
|
|
SocketAddress *connect_addr = g_new0(SocketAddress, 1);
|
|
|
|
|
|
|
|
listen_addr->type = SOCKET_ADDRESS_KIND_INET;
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 06:48:37 +08:00
|
|
|
listen_addr->u.inet.data = g_new(InetSocketAddress, 1);
|
|
|
|
*listen_addr->u.inet.data = (InetSocketAddress) {
|
2016-03-04 00:16:48 +08:00
|
|
|
.host = g_strdup("::1"),
|
|
|
|
.port = NULL, /* Auto-select */
|
|
|
|
};
|
2015-02-28 00:19:33 +08:00
|
|
|
|
|
|
|
connect_addr->type = SOCKET_ADDRESS_KIND_INET;
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 06:48:37 +08:00
|
|
|
connect_addr->u.inet.data = g_new(InetSocketAddress, 1);
|
|
|
|
*connect_addr->u.inet.data = (InetSocketAddress) {
|
2016-03-04 00:16:48 +08:00
|
|
|
.host = g_strdup("::1"),
|
|
|
|
.port = NULL, /* Filled in later */
|
|
|
|
};
|
2015-02-28 00:19:33 +08:00
|
|
|
|
2015-12-21 20:04:21 +08:00
|
|
|
test_io_channel(async, listen_addr, connect_addr, false);
|
2015-02-28 00:19:33 +08:00
|
|
|
|
|
|
|
qapi_free_SocketAddress(listen_addr);
|
|
|
|
qapi_free_SocketAddress(connect_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_io_channel_ipv6_sync(void)
|
|
|
|
{
|
|
|
|
return test_io_channel_ipv6(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_io_channel_ipv6_async(void)
|
|
|
|
{
|
|
|
|
return test_io_channel_ipv6(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
static void test_io_channel_unix(bool async)
|
|
|
|
{
|
|
|
|
SocketAddress *listen_addr = g_new0(SocketAddress, 1);
|
|
|
|
SocketAddress *connect_addr = g_new0(SocketAddress, 1);
|
|
|
|
|
|
|
|
#define TEST_SOCKET "test-io-channel-socket.sock"
|
|
|
|
listen_addr->type = SOCKET_ADDRESS_KIND_UNIX;
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 06:48:37 +08:00
|
|
|
listen_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
|
|
|
|
listen_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
|
2015-02-28 00:19:33 +08:00
|
|
|
|
|
|
|
connect_addr->type = SOCKET_ADDRESS_KIND_UNIX;
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 06:48:37 +08:00
|
|
|
connect_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
|
|
|
|
connect_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
|
2015-02-28 00:19:33 +08:00
|
|
|
|
2015-12-21 20:04:21 +08:00
|
|
|
test_io_channel(async, listen_addr, connect_addr, true);
|
2015-02-28 00:19:33 +08:00
|
|
|
|
|
|
|
qapi_free_SocketAddress(listen_addr);
|
|
|
|
qapi_free_SocketAddress(connect_addr);
|
2016-06-17 03:28:52 +08:00
|
|
|
g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS) == FALSE);
|
2015-02-28 00:19:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_io_channel_unix_sync(void)
|
|
|
|
{
|
|
|
|
return test_io_channel_unix(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_io_channel_unix_async(void)
|
|
|
|
{
|
|
|
|
return test_io_channel_unix(true);
|
|
|
|
}
|
2015-12-21 19:58:51 +08:00
|
|
|
|
|
|
|
static void test_io_channel_unix_fd_pass(void)
|
|
|
|
{
|
|
|
|
SocketAddress *listen_addr = g_new0(SocketAddress, 1);
|
|
|
|
SocketAddress *connect_addr = g_new0(SocketAddress, 1);
|
|
|
|
QIOChannel *src, *dst;
|
|
|
|
int testfd;
|
|
|
|
int fdsend[3];
|
|
|
|
int *fdrecv = NULL;
|
|
|
|
size_t nfdrecv = 0;
|
|
|
|
size_t i;
|
|
|
|
char bufsend[12], bufrecv[12];
|
|
|
|
struct iovec iosend[1], iorecv[1];
|
|
|
|
|
|
|
|
#define TEST_SOCKET "test-io-channel-socket.sock"
|
|
|
|
#define TEST_FILE "test-io-channel-socket.txt"
|
|
|
|
|
|
|
|
testfd = open(TEST_FILE, O_RDWR|O_TRUNC|O_CREAT, 0700);
|
|
|
|
g_assert(testfd != -1);
|
|
|
|
fdsend[0] = testfd;
|
|
|
|
fdsend[1] = testfd;
|
|
|
|
fdsend[2] = testfd;
|
|
|
|
|
|
|
|
listen_addr->type = SOCKET_ADDRESS_KIND_UNIX;
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 06:48:37 +08:00
|
|
|
listen_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
|
|
|
|
listen_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
|
2015-12-21 19:58:51 +08:00
|
|
|
|
|
|
|
connect_addr->type = SOCKET_ADDRESS_KIND_UNIX;
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 06:48:37 +08:00
|
|
|
connect_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
|
|
|
|
connect_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
|
2015-12-21 19:58:51 +08:00
|
|
|
|
|
|
|
test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst);
|
|
|
|
|
|
|
|
memcpy(bufsend, "Hello World", G_N_ELEMENTS(bufsend));
|
|
|
|
|
|
|
|
iosend[0].iov_base = bufsend;
|
|
|
|
iosend[0].iov_len = G_N_ELEMENTS(bufsend);
|
|
|
|
|
|
|
|
iorecv[0].iov_base = bufrecv;
|
|
|
|
iorecv[0].iov_len = G_N_ELEMENTS(bufrecv);
|
|
|
|
|
|
|
|
g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
|
|
|
|
g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
|
|
|
|
|
|
|
|
qio_channel_writev_full(src,
|
|
|
|
iosend,
|
|
|
|
G_N_ELEMENTS(iosend),
|
|
|
|
fdsend,
|
|
|
|
G_N_ELEMENTS(fdsend),
|
|
|
|
&error_abort);
|
|
|
|
|
|
|
|
qio_channel_readv_full(dst,
|
|
|
|
iorecv,
|
|
|
|
G_N_ELEMENTS(iorecv),
|
|
|
|
&fdrecv,
|
|
|
|
&nfdrecv,
|
|
|
|
&error_abort);
|
|
|
|
|
|
|
|
g_assert(nfdrecv == G_N_ELEMENTS(fdsend));
|
|
|
|
/* Each recvd FD should be different from sent FD */
|
|
|
|
for (i = 0; i < nfdrecv; i++) {
|
|
|
|
g_assert_cmpint(fdrecv[i], !=, testfd);
|
|
|
|
}
|
|
|
|
/* Each recvd FD should be different from each other */
|
|
|
|
g_assert_cmpint(fdrecv[0], !=, fdrecv[1]);
|
|
|
|
g_assert_cmpint(fdrecv[0], !=, fdrecv[2]);
|
|
|
|
g_assert_cmpint(fdrecv[1], !=, fdrecv[2]);
|
|
|
|
|
|
|
|
/* Check the I/O buf we sent at the same time matches */
|
|
|
|
g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0);
|
|
|
|
|
|
|
|
/* Write some data into the FD we received */
|
|
|
|
g_assert(write(fdrecv[0], bufsend, G_N_ELEMENTS(bufsend)) ==
|
|
|
|
G_N_ELEMENTS(bufsend));
|
|
|
|
|
|
|
|
/* Read data from the original FD and make sure it matches */
|
|
|
|
memset(bufrecv, 0, G_N_ELEMENTS(bufrecv));
|
|
|
|
g_assert(lseek(testfd, 0, SEEK_SET) == 0);
|
|
|
|
g_assert(read(testfd, bufrecv, G_N_ELEMENTS(bufrecv)) ==
|
|
|
|
G_N_ELEMENTS(bufrecv));
|
|
|
|
g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0);
|
|
|
|
|
|
|
|
object_unref(OBJECT(src));
|
|
|
|
object_unref(OBJECT(dst));
|
|
|
|
qapi_free_SocketAddress(listen_addr);
|
|
|
|
qapi_free_SocketAddress(connect_addr);
|
|
|
|
unlink(TEST_SOCKET);
|
|
|
|
unlink(TEST_FILE);
|
|
|
|
close(testfd);
|
|
|
|
for (i = 0; i < nfdrecv; i++) {
|
|
|
|
close(fdrecv[i]);
|
|
|
|
}
|
|
|
|
g_free(fdrecv);
|
|
|
|
}
|
2016-09-29 23:52:38 +08:00
|
|
|
|
|
|
|
static void test_io_channel_unix_listen_cleanup(void)
|
|
|
|
{
|
|
|
|
QIOChannelSocket *ioc;
|
|
|
|
struct sockaddr_un un;
|
|
|
|
int sock;
|
|
|
|
|
|
|
|
#define TEST_SOCKET "test-io-channel-socket.sock"
|
|
|
|
|
|
|
|
ioc = qio_channel_socket_new();
|
|
|
|
|
|
|
|
/* Manually bind ioc without calling the qio api to avoid setting
|
|
|
|
* the LISTEN feature */
|
|
|
|
sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
|
|
|
|
memset(&un, 0, sizeof(un));
|
|
|
|
un.sun_family = AF_UNIX;
|
|
|
|
snprintf(un.sun_path, sizeof(un.sun_path), "%s", TEST_SOCKET);
|
|
|
|
unlink(TEST_SOCKET);
|
|
|
|
bind(sock, (struct sockaddr *)&un, sizeof(un));
|
|
|
|
ioc->fd = sock;
|
|
|
|
ioc->localAddrLen = sizeof(ioc->localAddr);
|
|
|
|
getsockname(sock, (struct sockaddr *)&ioc->localAddr,
|
|
|
|
&ioc->localAddrLen);
|
|
|
|
|
|
|
|
g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS));
|
|
|
|
object_unref(OBJECT(ioc));
|
|
|
|
g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS));
|
|
|
|
|
|
|
|
unlink(TEST_SOCKET);
|
|
|
|
}
|
|
|
|
|
2015-02-28 00:19:33 +08:00
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
|
|
|
2016-02-03 22:00:28 +08:00
|
|
|
static void test_io_channel_ipv4_fd(void)
|
|
|
|
{
|
|
|
|
QIOChannel *ioc;
|
|
|
|
int fd = -1;
|
2016-03-08 23:27:30 +08:00
|
|
|
struct sockaddr_in sa = {
|
|
|
|
.sin_family = AF_INET,
|
|
|
|
.sin_addr = {
|
|
|
|
.s_addr = htonl(INADDR_LOOPBACK),
|
|
|
|
}
|
|
|
|
/* Leave port unset for auto-assign */
|
|
|
|
};
|
|
|
|
socklen_t salen = sizeof(sa);
|
2016-02-03 22:00:28 +08:00
|
|
|
|
|
|
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
g_assert_cmpint(fd, >, -1);
|
|
|
|
|
2016-03-08 23:27:30 +08:00
|
|
|
g_assert_cmpint(bind(fd, (struct sockaddr *)&sa, salen), ==, 0);
|
|
|
|
|
2016-02-03 22:00:28 +08:00
|
|
|
ioc = qio_channel_new_fd(fd, &error_abort);
|
|
|
|
|
|
|
|
g_assert_cmpstr(object_get_typename(OBJECT(ioc)),
|
|
|
|
==,
|
|
|
|
TYPE_QIO_CHANNEL_SOCKET);
|
|
|
|
|
|
|
|
object_unref(OBJECT(ioc));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-28 00:19:33 +08:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
bool has_ipv4, has_ipv6;
|
|
|
|
|
|
|
|
module_call_init(MODULE_INIT_QOM);
|
2016-03-08 19:44:26 +08:00
|
|
|
socket_init();
|
2015-02-28 00:19:33 +08:00
|
|
|
|
|
|
|
g_test_init(&argc, &argv, NULL);
|
|
|
|
|
|
|
|
/* We're creating actual IPv4/6 sockets, so we should
|
|
|
|
* check if the host running tests actually supports
|
|
|
|
* each protocol to avoid breaking tests on machines
|
|
|
|
* with either IPv4 or IPv6 disabled.
|
|
|
|
*/
|
|
|
|
if (check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (has_ipv4) {
|
|
|
|
g_test_add_func("/io/channel/socket/ipv4-sync",
|
|
|
|
test_io_channel_ipv4_sync);
|
|
|
|
g_test_add_func("/io/channel/socket/ipv4-async",
|
|
|
|
test_io_channel_ipv4_async);
|
2016-02-03 22:00:28 +08:00
|
|
|
g_test_add_func("/io/channel/socket/ipv4-fd",
|
|
|
|
test_io_channel_ipv4_fd);
|
2015-02-28 00:19:33 +08:00
|
|
|
}
|
|
|
|
if (has_ipv6) {
|
|
|
|
g_test_add_func("/io/channel/socket/ipv6-sync",
|
|
|
|
test_io_channel_ipv6_sync);
|
|
|
|
g_test_add_func("/io/channel/socket/ipv6-async",
|
|
|
|
test_io_channel_ipv6_async);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
g_test_add_func("/io/channel/socket/unix-sync",
|
|
|
|
test_io_channel_unix_sync);
|
|
|
|
g_test_add_func("/io/channel/socket/unix-async",
|
|
|
|
test_io_channel_unix_async);
|
2015-12-21 19:58:51 +08:00
|
|
|
g_test_add_func("/io/channel/socket/unix-fd-pass",
|
|
|
|
test_io_channel_unix_fd_pass);
|
2016-09-29 23:52:38 +08:00
|
|
|
g_test_add_func("/io/channel/socket/unix-listen-cleanup",
|
|
|
|
test_io_channel_unix_listen_cleanup);
|
2015-02-28 00:19:33 +08:00
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
|
|
return g_test_run();
|
|
|
|
}
|