mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-28 21:03:54 -06:00

With the default TCP stack configuration, it could be even 2 hours before the connection times out due to the other side not being reachable. However, in some cases, the application needs to be aware of a connection issue much sooner. This is the case, for example, for postcopy live migration. If there is no traffic from the migration destination guest (server-side) to the migration source guest (client-side), the destination keeps waiting for pages indefinitely and does not switch to the postcopy-paused state. This can happen, for example, if the destination QEMU instance is started with the '-S' command line option and the machine is not started yet, or if the machine is idle and produces no new page faults for not-yet-migrated pages. This patch introduces new inet socket parameters that control count, idle period, and interval of TCP keep-alive packets before the connection is considered broken. These parameters are available on systems where the respective TCP socket options are defined, that includes Linux, Windows, macOS, but not OpenBSD. Additionally, macOS defines TCP_KEEPIDLE as TCP_KEEPALIVE instead, so the patch supplies its own definition. The default value for all is 0, which means the system configuration is used. Signed-off-by: Juraj Marcin <jmarcin@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
617 lines
17 KiB
C
617 lines
17 KiB
C
/*
|
|
* Tests for util/qemu-sockets.c
|
|
*
|
|
* Copyright 2018 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 library; if not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "qemu/sockets.h"
|
|
#include "qapi/error.h"
|
|
#include "socket-helpers.h"
|
|
#include "monitor/monitor.h"
|
|
|
|
static void test_fd_is_socket_bad(void)
|
|
{
|
|
char *tmp = g_strdup("qemu-test-util-sockets-XXXXXX");
|
|
int fd = mkstemp(tmp);
|
|
if (fd != 0) {
|
|
unlink(tmp);
|
|
}
|
|
g_free(tmp);
|
|
|
|
g_assert(fd >= 0);
|
|
|
|
g_assert(!fd_is_socket(fd));
|
|
close(fd);
|
|
}
|
|
|
|
static void test_fd_is_socket_good(void)
|
|
{
|
|
int fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
|
|
|
|
g_assert(fd >= 0);
|
|
|
|
g_assert(fd_is_socket(fd));
|
|
close(fd);
|
|
}
|
|
|
|
static int mon_fd = -1;
|
|
static const char *mon_fdname;
|
|
__thread Monitor *cur_mon;
|
|
|
|
int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
|
|
{
|
|
g_assert(cur_mon);
|
|
g_assert(mon == cur_mon);
|
|
if (mon_fd == -1 || !g_str_equal(mon_fdname, fdname)) {
|
|
error_setg(errp, "No fd named %s", fdname);
|
|
return -1;
|
|
}
|
|
return dup(mon_fd);
|
|
}
|
|
|
|
/*
|
|
* Syms of stubs in libqemuutil.a are discarded at .o file
|
|
* granularity. To replace monitor_get_fd() and monitor_cur(), we
|
|
* must ensure that we also replace any other symbol that is used in
|
|
* the binary and would be taken from the same stub object file,
|
|
* otherwise we get duplicate syms at link time.
|
|
*/
|
|
Monitor *monitor_cur(void) { return cur_mon; }
|
|
Monitor *monitor_set_cur(Coroutine *co, Monitor *mon) { abort(); }
|
|
int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); }
|
|
|
|
#ifndef _WIN32
|
|
static void test_socket_fd_pass_name_good(void)
|
|
{
|
|
SocketAddress addr;
|
|
int fd;
|
|
|
|
cur_mon = g_malloc(1); /* Fake a monitor */
|
|
mon_fdname = "myfd";
|
|
mon_fd = qemu_socket(AF_INET, SOCK_STREAM, 0);
|
|
g_assert_cmpint(mon_fd, >, STDERR_FILENO);
|
|
|
|
addr.type = SOCKET_ADDRESS_TYPE_FD;
|
|
addr.u.fd.str = g_strdup(mon_fdname);
|
|
|
|
fd = socket_connect(&addr, &error_abort);
|
|
g_assert_cmpint(fd, !=, -1);
|
|
g_assert_cmpint(fd, !=, mon_fd);
|
|
close(fd);
|
|
|
|
fd = socket_listen(&addr, 1, &error_abort);
|
|
g_assert_cmpint(fd, !=, -1);
|
|
g_assert_cmpint(fd, !=, mon_fd);
|
|
close(fd);
|
|
|
|
g_free(addr.u.fd.str);
|
|
mon_fdname = NULL;
|
|
close(mon_fd);
|
|
mon_fd = -1;
|
|
g_free(cur_mon);
|
|
cur_mon = NULL;
|
|
}
|
|
|
|
static void test_socket_fd_pass_name_bad(void)
|
|
{
|
|
SocketAddress addr;
|
|
Error *err = NULL;
|
|
int fd;
|
|
|
|
cur_mon = g_malloc(1); /* Fake a monitor */
|
|
mon_fdname = "myfd";
|
|
mon_fd = dup(STDOUT_FILENO);
|
|
g_assert_cmpint(mon_fd, >, STDERR_FILENO);
|
|
|
|
addr.type = SOCKET_ADDRESS_TYPE_FD;
|
|
addr.u.fd.str = g_strdup(mon_fdname);
|
|
|
|
fd = socket_connect(&addr, &err);
|
|
g_assert_cmpint(fd, ==, -1);
|
|
error_free_or_abort(&err);
|
|
|
|
fd = socket_listen(&addr, 1, &err);
|
|
g_assert_cmpint(fd, ==, -1);
|
|
error_free_or_abort(&err);
|
|
|
|
g_free(addr.u.fd.str);
|
|
mon_fdname = NULL;
|
|
close(mon_fd);
|
|
mon_fd = -1;
|
|
g_free(cur_mon);
|
|
cur_mon = NULL;
|
|
}
|
|
|
|
static void test_socket_fd_pass_name_nomon(void)
|
|
{
|
|
SocketAddress addr;
|
|
Error *err = NULL;
|
|
int fd;
|
|
|
|
g_assert(cur_mon == NULL);
|
|
|
|
addr.type = SOCKET_ADDRESS_TYPE_FD;
|
|
addr.u.fd.str = g_strdup("myfd");
|
|
|
|
fd = socket_connect(&addr, &err);
|
|
g_assert_cmpint(fd, ==, -1);
|
|
error_free_or_abort(&err);
|
|
|
|
fd = socket_listen(&addr, 1, &err);
|
|
g_assert_cmpint(fd, ==, -1);
|
|
error_free_or_abort(&err);
|
|
|
|
g_free(addr.u.fd.str);
|
|
}
|
|
|
|
|
|
static void test_socket_fd_pass_num_good(void)
|
|
{
|
|
SocketAddress addr;
|
|
int fd, sfd;
|
|
|
|
g_assert(cur_mon == NULL);
|
|
sfd = qemu_socket(AF_INET, SOCK_STREAM, 0);
|
|
g_assert_cmpint(sfd, >, STDERR_FILENO);
|
|
|
|
addr.type = SOCKET_ADDRESS_TYPE_FD;
|
|
addr.u.fd.str = g_strdup_printf("%d", sfd);
|
|
|
|
fd = socket_connect(&addr, &error_abort);
|
|
g_assert_cmpint(fd, ==, sfd);
|
|
|
|
fd = socket_listen(&addr, 1, &error_abort);
|
|
g_assert_cmpint(fd, ==, sfd);
|
|
|
|
g_free(addr.u.fd.str);
|
|
close(sfd);
|
|
}
|
|
|
|
static void test_socket_fd_pass_num_bad(void)
|
|
{
|
|
SocketAddress addr;
|
|
Error *err = NULL;
|
|
int fd, sfd;
|
|
|
|
g_assert(cur_mon == NULL);
|
|
sfd = dup(STDOUT_FILENO);
|
|
|
|
addr.type = SOCKET_ADDRESS_TYPE_FD;
|
|
addr.u.fd.str = g_strdup_printf("%d", sfd);
|
|
|
|
fd = socket_connect(&addr, &err);
|
|
g_assert_cmpint(fd, ==, -1);
|
|
error_free_or_abort(&err);
|
|
|
|
fd = socket_listen(&addr, 1, &err);
|
|
g_assert_cmpint(fd, ==, -1);
|
|
error_free_or_abort(&err);
|
|
|
|
g_free(addr.u.fd.str);
|
|
close(sfd);
|
|
}
|
|
|
|
static void test_socket_fd_pass_num_nocli(void)
|
|
{
|
|
SocketAddress addr;
|
|
Error *err = NULL;
|
|
int fd;
|
|
|
|
cur_mon = g_malloc(1); /* Fake a monitor */
|
|
|
|
addr.type = SOCKET_ADDRESS_TYPE_FD;
|
|
addr.u.fd.str = g_strdup_printf("%d", STDOUT_FILENO);
|
|
|
|
fd = socket_connect(&addr, &err);
|
|
g_assert_cmpint(fd, ==, -1);
|
|
error_free_or_abort(&err);
|
|
|
|
fd = socket_listen(&addr, 1, &err);
|
|
g_assert_cmpint(fd, ==, -1);
|
|
error_free_or_abort(&err);
|
|
|
|
g_free(addr.u.fd.str);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_LINUX
|
|
|
|
#define ABSTRACT_SOCKET_VARIANTS 3
|
|
|
|
typedef struct {
|
|
SocketAddress *server, *client[ABSTRACT_SOCKET_VARIANTS];
|
|
bool expect_connect[ABSTRACT_SOCKET_VARIANTS];
|
|
} abstract_socket_matrix_row;
|
|
|
|
static gpointer unix_client_thread_func(gpointer user_data)
|
|
{
|
|
abstract_socket_matrix_row *row = user_data;
|
|
Error *err = NULL;
|
|
int i, fd;
|
|
|
|
for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) {
|
|
if (row->expect_connect[i]) {
|
|
fd = socket_connect(row->client[i], &error_abort);
|
|
g_assert_cmpint(fd, >=, 0);
|
|
} else {
|
|
fd = socket_connect(row->client[i], &err);
|
|
g_assert_cmpint(fd, ==, -1);
|
|
error_free_or_abort(&err);
|
|
}
|
|
close(fd);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void test_socket_unix_abstract_row(abstract_socket_matrix_row *test)
|
|
{
|
|
int fd, connfd, i;
|
|
GThread *cli;
|
|
struct sockaddr_un un;
|
|
socklen_t len = sizeof(un);
|
|
|
|
/* Last one must connect, or else accept() below hangs */
|
|
assert(test->expect_connect[ABSTRACT_SOCKET_VARIANTS - 1]);
|
|
|
|
fd = socket_listen(test->server, 1, &error_abort);
|
|
g_assert_cmpint(fd, >=, 0);
|
|
g_assert(fd_is_socket(fd));
|
|
|
|
cli = g_thread_new("abstract_unix_client",
|
|
unix_client_thread_func,
|
|
test);
|
|
|
|
for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) {
|
|
if (test->expect_connect[i]) {
|
|
connfd = accept(fd, (struct sockaddr *)&un, &len);
|
|
g_assert_cmpint(connfd, !=, -1);
|
|
close(connfd);
|
|
}
|
|
}
|
|
|
|
close(fd);
|
|
g_thread_join(cli);
|
|
}
|
|
|
|
static void test_socket_unix_abstract(void)
|
|
{
|
|
SocketAddress addr, addr_tight, addr_padded;
|
|
abstract_socket_matrix_row matrix[ABSTRACT_SOCKET_VARIANTS] = {
|
|
{ &addr,
|
|
{ &addr_tight, &addr_padded, &addr },
|
|
{ true, false, true } },
|
|
{ &addr_tight,
|
|
{ &addr_padded, &addr, &addr_tight },
|
|
{ false, true, true } },
|
|
{ &addr_padded,
|
|
{ &addr, &addr_tight, &addr_padded },
|
|
{ false, false, true } }
|
|
};
|
|
int i;
|
|
|
|
i = g_file_open_tmp("unix-XXXXXX", &addr.u.q_unix.path, NULL);
|
|
g_assert_true(i >= 0);
|
|
close(i);
|
|
|
|
addr.type = SOCKET_ADDRESS_TYPE_UNIX;
|
|
addr.u.q_unix.has_abstract = true;
|
|
addr.u.q_unix.abstract = true;
|
|
addr.u.q_unix.has_tight = false;
|
|
addr.u.q_unix.tight = false;
|
|
|
|
addr_tight = addr;
|
|
addr_tight.u.q_unix.has_tight = true;
|
|
addr_tight.u.q_unix.tight = true;
|
|
|
|
addr_padded = addr;
|
|
addr_padded.u.q_unix.has_tight = true;
|
|
addr_padded.u.q_unix.tight = false;
|
|
|
|
for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) {
|
|
test_socket_unix_abstract_row(&matrix[i]);
|
|
}
|
|
|
|
unlink(addr.u.q_unix.path);
|
|
g_free(addr.u.q_unix.path);
|
|
}
|
|
|
|
#endif /* CONFIG_LINUX */
|
|
|
|
static void inet_parse_test_helper(const char *str,
|
|
InetSocketAddress *exp_addr, bool success)
|
|
{
|
|
InetSocketAddress addr;
|
|
Error *error = NULL;
|
|
|
|
int rc = inet_parse(&addr, str, &error);
|
|
|
|
if (success) {
|
|
g_assert_cmpint(rc, ==, 0);
|
|
} else {
|
|
g_assert_cmpint(rc, <, 0);
|
|
}
|
|
if (exp_addr != NULL) {
|
|
g_assert_cmpstr(addr.host, ==, exp_addr->host);
|
|
g_assert_cmpstr(addr.port, ==, exp_addr->port);
|
|
/* Own members: */
|
|
g_assert_cmpint(addr.has_numeric, ==, exp_addr->has_numeric);
|
|
g_assert_cmpint(addr.numeric, ==, exp_addr->numeric);
|
|
g_assert_cmpint(addr.has_to, ==, exp_addr->has_to);
|
|
g_assert_cmpint(addr.to, ==, exp_addr->to);
|
|
g_assert_cmpint(addr.has_ipv4, ==, exp_addr->has_ipv4);
|
|
g_assert_cmpint(addr.ipv4, ==, exp_addr->ipv4);
|
|
g_assert_cmpint(addr.has_ipv6, ==, exp_addr->has_ipv6);
|
|
g_assert_cmpint(addr.ipv6, ==, exp_addr->ipv6);
|
|
g_assert_cmpint(addr.has_keep_alive, ==, exp_addr->has_keep_alive);
|
|
g_assert_cmpint(addr.keep_alive, ==, exp_addr->keep_alive);
|
|
#ifdef HAVE_TCP_KEEPCNT
|
|
g_assert_cmpint(addr.has_keep_alive_count, ==,
|
|
exp_addr->has_keep_alive_count);
|
|
g_assert_cmpint(addr.keep_alive_count, ==,
|
|
exp_addr->keep_alive_count);
|
|
#endif
|
|
#ifdef HAVE_TCP_KEEPIDLE
|
|
g_assert_cmpint(addr.has_keep_alive_idle, ==,
|
|
exp_addr->has_keep_alive_idle);
|
|
g_assert_cmpint(addr.keep_alive_idle, ==,
|
|
exp_addr->keep_alive_idle);
|
|
#endif
|
|
#ifdef HAVE_TCP_KEEPINTVL
|
|
g_assert_cmpint(addr.has_keep_alive_interval, ==,
|
|
exp_addr->has_keep_alive_interval);
|
|
g_assert_cmpint(addr.keep_alive_interval, ==,
|
|
exp_addr->keep_alive_interval);
|
|
#endif
|
|
#ifdef HAVE_IPPROTO_MPTCP
|
|
g_assert_cmpint(addr.has_mptcp, ==, exp_addr->has_mptcp);
|
|
g_assert_cmpint(addr.mptcp, ==, exp_addr->mptcp);
|
|
#endif
|
|
}
|
|
|
|
g_free(addr.host);
|
|
g_free(addr.port);
|
|
}
|
|
|
|
static void test_inet_parse_nohost_good(void)
|
|
{
|
|
char host[] = "";
|
|
char port[] = "5000";
|
|
InetSocketAddress exp_addr = {
|
|
.host = host,
|
|
.port = port,
|
|
};
|
|
inet_parse_test_helper(":5000", &exp_addr, true);
|
|
}
|
|
|
|
static void test_inet_parse_empty_bad(void)
|
|
{
|
|
inet_parse_test_helper("", NULL, false);
|
|
}
|
|
|
|
static void test_inet_parse_only_colon_bad(void)
|
|
{
|
|
inet_parse_test_helper(":", NULL, false);
|
|
}
|
|
|
|
static void test_inet_parse_ipv4_good(void)
|
|
{
|
|
char host[] = "127.0.0.1";
|
|
char port[] = "5000";
|
|
InetSocketAddress exp_addr = {
|
|
.host = host,
|
|
.port = port,
|
|
};
|
|
inet_parse_test_helper("127.0.0.1:5000", &exp_addr, true);
|
|
}
|
|
|
|
static void test_inet_parse_ipv4_noport_bad(void)
|
|
{
|
|
inet_parse_test_helper("127.0.0.1", NULL, false);
|
|
}
|
|
|
|
static void test_inet_parse_ipv6_good(void)
|
|
{
|
|
char host[] = "::1";
|
|
char port[] = "5000";
|
|
InetSocketAddress exp_addr = {
|
|
.host = host,
|
|
.port = port,
|
|
};
|
|
inet_parse_test_helper("[::1]:5000", &exp_addr, true);
|
|
}
|
|
|
|
static void test_inet_parse_ipv6_noend_bad(void)
|
|
{
|
|
inet_parse_test_helper("[::1", NULL, false);
|
|
}
|
|
|
|
static void test_inet_parse_ipv6_noport_bad(void)
|
|
{
|
|
inet_parse_test_helper("[::1]:", NULL, false);
|
|
}
|
|
|
|
static void test_inet_parse_ipv6_empty_bad(void)
|
|
{
|
|
inet_parse_test_helper("[]:5000", NULL, false);
|
|
}
|
|
|
|
static void test_inet_parse_hostname_good(void)
|
|
{
|
|
char host[] = "localhost";
|
|
char port[] = "5000";
|
|
InetSocketAddress exp_addr = {
|
|
.host = host,
|
|
.port = port,
|
|
};
|
|
inet_parse_test_helper("localhost:5000", &exp_addr, true);
|
|
}
|
|
|
|
static void test_inet_parse_all_options_good(void)
|
|
{
|
|
char host[] = "::1";
|
|
char port[] = "5000";
|
|
InetSocketAddress exp_addr = {
|
|
.host = host,
|
|
.port = port,
|
|
.has_numeric = true,
|
|
.numeric = true,
|
|
.has_to = true,
|
|
.to = 5006,
|
|
.has_ipv4 = true,
|
|
.ipv4 = false,
|
|
.has_ipv6 = true,
|
|
.ipv6 = true,
|
|
.has_keep_alive = true,
|
|
.keep_alive = true,
|
|
#ifdef HAVE_TCP_KEEPCNT
|
|
.has_keep_alive_count = true,
|
|
.keep_alive_count = 10,
|
|
#endif
|
|
#ifdef HAVE_TCP_KEEPIDLE
|
|
.has_keep_alive_idle = true,
|
|
.keep_alive_idle = 60,
|
|
#endif
|
|
#ifdef HAVE_TCP_KEEPINTVL
|
|
.has_keep_alive_interval = true,
|
|
.keep_alive_interval = 30,
|
|
#endif
|
|
#ifdef HAVE_IPPROTO_MPTCP
|
|
.has_mptcp = true,
|
|
.mptcp = false,
|
|
#endif
|
|
};
|
|
inet_parse_test_helper(
|
|
"[::1]:5000,numeric=on,to=5006,ipv4=off,ipv6=on,keep-alive=on"
|
|
#ifdef HAVE_TCP_KEEPCNT
|
|
",keep-alive-count=10"
|
|
#endif
|
|
#ifdef HAVE_TCP_KEEPIDLE
|
|
",keep-alive-idle=60"
|
|
#endif
|
|
#ifdef HAVE_TCP_KEEPINTVL
|
|
",keep-alive-interval=30"
|
|
#endif
|
|
#ifdef HAVE_IPPROTO_MPTCP
|
|
",mptcp=off"
|
|
#endif
|
|
, &exp_addr, true);
|
|
}
|
|
|
|
static void test_inet_parse_all_implicit_bool_good(void)
|
|
{
|
|
char host[] = "::1";
|
|
char port[] = "5000";
|
|
InetSocketAddress exp_addr = {
|
|
.host = host,
|
|
.port = port,
|
|
.has_numeric = true,
|
|
.numeric = true,
|
|
.has_to = true,
|
|
.to = 5006,
|
|
.has_ipv4 = true,
|
|
.ipv4 = true,
|
|
.has_ipv6 = true,
|
|
.ipv6 = true,
|
|
.has_keep_alive = true,
|
|
.keep_alive = true,
|
|
#ifdef HAVE_IPPROTO_MPTCP
|
|
.has_mptcp = true,
|
|
.mptcp = true,
|
|
#endif
|
|
};
|
|
inet_parse_test_helper(
|
|
"[::1]:5000,numeric,to=5006,ipv4,ipv6,keep-alive"
|
|
#ifdef HAVE_IPPROTO_MPTCP
|
|
",mptcp"
|
|
#endif
|
|
, &exp_addr, true);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
bool has_ipv4, has_ipv6;
|
|
|
|
qemu_init_main_loop(&error_abort);
|
|
socket_init();
|
|
|
|
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 (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
|
|
g_printerr("socket_check_protocol_support() failed\n");
|
|
goto end;
|
|
}
|
|
|
|
if (has_ipv4) {
|
|
g_test_add_func("/util/socket/is-socket/bad",
|
|
test_fd_is_socket_bad);
|
|
g_test_add_func("/util/socket/is-socket/good",
|
|
test_fd_is_socket_good);
|
|
#ifndef _WIN32
|
|
g_test_add_func("/socket/fd-pass/name/good",
|
|
test_socket_fd_pass_name_good);
|
|
g_test_add_func("/socket/fd-pass/name/bad",
|
|
test_socket_fd_pass_name_bad);
|
|
g_test_add_func("/socket/fd-pass/name/nomon",
|
|
test_socket_fd_pass_name_nomon);
|
|
g_test_add_func("/socket/fd-pass/num/good",
|
|
test_socket_fd_pass_num_good);
|
|
g_test_add_func("/socket/fd-pass/num/bad",
|
|
test_socket_fd_pass_num_bad);
|
|
g_test_add_func("/socket/fd-pass/num/nocli",
|
|
test_socket_fd_pass_num_nocli);
|
|
#endif
|
|
}
|
|
|
|
#ifdef CONFIG_LINUX
|
|
g_test_add_func("/util/socket/unix-abstract",
|
|
test_socket_unix_abstract);
|
|
#endif
|
|
|
|
g_test_add_func("/util/socket/inet-parse/nohost-good",
|
|
test_inet_parse_nohost_good);
|
|
g_test_add_func("/util/socket/inet-parse/empty-bad",
|
|
test_inet_parse_empty_bad);
|
|
g_test_add_func("/util/socket/inet-parse/only-colon-bad",
|
|
test_inet_parse_only_colon_bad);
|
|
g_test_add_func("/util/socket/inet-parse/ipv4-good",
|
|
test_inet_parse_ipv4_good);
|
|
g_test_add_func("/util/socket/inet-parse/ipv4-noport-bad",
|
|
test_inet_parse_ipv4_noport_bad);
|
|
g_test_add_func("/util/socket/inet-parse/ipv6-good",
|
|
test_inet_parse_ipv6_good);
|
|
g_test_add_func("/util/socket/inet-parse/ipv6-noend-bad",
|
|
test_inet_parse_ipv6_noend_bad);
|
|
g_test_add_func("/util/socket/inet-parse/ipv6-noport-bad",
|
|
test_inet_parse_ipv6_noport_bad);
|
|
g_test_add_func("/util/socket/inet-parse/ipv6-empty-bad",
|
|
test_inet_parse_ipv6_empty_bad);
|
|
g_test_add_func("/util/socket/inet-parse/hostname-good",
|
|
test_inet_parse_hostname_good);
|
|
g_test_add_func("/util/socket/inet-parse/all-options-good",
|
|
test_inet_parse_all_options_good);
|
|
g_test_add_func("/util/socket/inet-parse/all-bare-bool-good",
|
|
test_inet_parse_all_implicit_bool_good);
|
|
|
|
end:
|
|
return g_test_run();
|
|
}
|