test-http-client-errors.c revision f48fad9712ec943ee3d492298350f97851c8034e
/* Copyright (c) 2016-2017 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "str.h"
#include "hostpid.h"
#include "ioloop.h"
#include "istream.h"
#include "istream-chain.h"
#include "ostream.h"
#include "time-util.h"
#include "connection.h"
#include "test-common.h"
#include "http-url.h"
#include "http-request.h"
#include "http-client.h"
#include <signal.h>
#include <unistd.h>
/*
* Types
*/
struct server_connection {
struct connection conn;
};
typedef void (*test_server_init_t)(unsigned int index);
typedef bool (*test_client_init_t)
(const struct http_client_settings *client_set);
typedef void (*test_dns_init_t)(void);
/*
* State
*/
/* common */
static in_port_t *bind_ports = 0;
/* dns */
/* server */
static int fd_listen = -1;
static unsigned int server_pids_count = 0;
static struct connection_list *server_conn_list;
static size_t server_read_max = 0;
static unsigned int server_index;
/* client */
/*
* Forward declarations
*/
/* server */
static void test_server_run(unsigned int index);
static void
/* client */
static void
static void test_client_deinit(void);
/* test*/
static void test_run_client_server(
const struct http_client_settings *client_set,
unsigned int server_tests_count,
ATTR_NULL(3);
/*
* Unconfigured SSL
*/
/* client */
struct _unconfigured_ssl {
unsigned int count;
};
static void
const struct http_response *resp,
struct _unconfigured_ssl *ctx)
{
if (debug)
}
}
static bool
{
struct http_client_request *hreq;
struct _unconfigured_ssl *ctx;
return TRUE;
}
/* test */
static void test_unconfigured_ssl(void)
{
struct http_client_settings http_client_set;
test_begin("unconfigured ssl");
test_end();
}
/*
* Unconfigured SSL abort
*/
/* client */
struct _unconfigured_ssl_abort {
unsigned int count;
};
static void
const struct http_response *resp,
{
if (debug)
}
static void
const struct http_response *resp,
struct _unconfigured_ssl_abort *ctx)
{
if (debug)
}
static bool
{
struct http_client_request *hreq;
struct _unconfigured_ssl_abort *ctx;
return TRUE;
}
/* test */
static void test_unconfigured_ssl_abort(void)
{
struct http_client_settings http_client_set;
test_begin("unconfigured ssl abort");
test_end();
}
/*
* Invalid URL
*/
/* client */
struct _invalid_url {
unsigned int count;
};
static void
const struct http_response *resp,
struct _invalid_url *ctx)
{
if (debug)
}
}
static bool
{
struct http_client_request *hreq;
struct _invalid_url *ctx;
"GET", "imap://example.com/INBOX",
"GET", "http:/www.example.com",
return TRUE;
}
/* test */
static void test_invalid_url(void)
{
struct http_client_settings http_client_set;
test_begin("invalid url");
test_end();
}
/*
* Host lookup failed
*/
/* client */
struct _host_lookup_failed {
unsigned int count;
};
static void
const struct http_response *resp,
struct _host_lookup_failed *ctx)
{
if (debug)
}
}
static bool
{
struct http_client_request *hreq;
struct _host_lookup_failed *ctx;
return TRUE;
}
/* test */
static void test_host_lookup_failed(void)
{
struct http_client_settings http_client_set;
test_begin("host lookup failed");
test_end();
}
/*
* Connection refused
*/
/* server */
static void
{
}
/* client */
struct _connection_refused {
unsigned int count;
};
static void
const struct http_response *resp,
struct _connection_refused *ctx)
{
if (debug)
}
}
static void
{
if (debug)
i_debug("TIMEOUT (ok)");
}
static bool
{
struct http_client_request *hreq;
struct _connection_refused *ctx;
if (client_set->max_connect_attempts > 0) {
}
return TRUE;
}
/* test */
static void test_connection_refused(void)
{
struct http_client_settings http_client_set;
test_begin("connection refused");
NULL);
test_end();
test_begin("connection refused backoff");
NULL);
test_end();
}
/*
* Connection lost prematurely
*/
/* server */
static void
{
}
static void
test_server_connection_lost_prematurely(unsigned int index)
{
}
/* client */
struct _connection_lost_prematurely {
unsigned int count;
};
static void
const struct http_response *resp,
struct _connection_lost_prematurely *ctx)
{
if (debug)
}
}
static void
struct _connection_lost_prematurely *ctx)
{
if (debug)
i_debug("TIMEOUT (ok)");
}
static bool
{
struct http_client_request *hreq;
struct _connection_lost_prematurely *ctx;
return TRUE;
}
/* test */
static void test_connection_lost_prematurely(void)
{
struct http_client_settings http_client_set;
test_begin("connection lost prematurely");
NULL);
test_end();
}
/*
* Connection timed out
*/
/* client */
struct _connection_timed_out {
unsigned int count;
};
static void
const struct http_response *resp,
struct _connection_timed_out *ctx)
{
if (debug)
}
}
static bool
const struct http_client_settings *client_set)
{
struct http_client_request *hreq;
struct _connection_timed_out *ctx;
return TRUE;
}
/* test */
static void test_connection_timed_out(void)
{
struct http_client_settings http_client_set;
test_begin("connection timed out");
test_end();
}
/*
* Invalid redirect
*/
/* server */
/* -> not accepted */
static void
{
static const char *resp =
"HTTP/1.1 302 Redirect\r\n"
"Location: http://localhost:4444\r\n"
"\r\n";
}
static void test_server_invalid_redirect1(unsigned int index)
{
}
/* -> bad location */
static void
{
static const char *resp =
"HTTP/1.1 302 Redirect\r\n"
"Location: unix:/var/run/dovecot/auth-master\r\n"
"\r\n";
}
static void test_server_invalid_redirect2(unsigned int index)
{
}
/* -> too many */
static void
{
"HTTP/1.1 302 Redirect\r\n"
"Location: http://%s:%u/friep.txt\r\n"
"\r\n",
}
static void test_server_invalid_redirect3(unsigned int index)
{
}
/* client */
static void
const struct http_response *resp,
void *context ATTR_UNUSED)
{
if (debug)
}
static bool
{
struct http_client_request *hreq;
return TRUE;
}
/* test */
static void test_invalid_redirect(void)
{
struct http_client_settings http_client_set;
test_begin("invalid redirect: not accepted");
NULL);
test_end();
test_begin("invalid redirect: bad location");
NULL);
test_end();
test_begin("invalid redirect: too many");
NULL);
test_end();
}
/*
* Unseekable redirect
*/
/* server */
static void
{
"HTTP/1.1 302 Redirect\r\n"
"Location: http://%s:%u/frml.txt\r\n"
"\r\n",
}
static void test_server_unseekable_redirect(unsigned int index)
{
}
/* client */
static void
const struct http_response *resp,
void *context ATTR_UNUSED)
{
if (debug)
}
static bool
{
struct http_client_request *hreq;
return TRUE;
}
/* test */
static void test_unseekable_redirect(void)
{
struct http_client_settings http_client_set;
test_begin("unseekable redirect");
NULL);
test_end();
}
/*
* Unseekable retry
*/
/* server */
static void
{
}
static void test_server_unseekable_retry(unsigned int index)
{
}
/* client */
static void
const struct http_response *resp,
void *context ATTR_UNUSED)
{
if (debug)
}
static bool
{
struct http_client_request *hreq;
return TRUE;
}
/* test */
static void test_unseekable_retry(void)
{
struct http_client_settings http_client_set;
test_begin("unseekable retry");
NULL);
test_end();
}
/*
* Broken payload
*/
/* server */
static void
{
static const char *resp =
"HTTP/1.1 200 OK\r\n"
"Content-Length: 18\r\n"
"\r\n"
"Everything is OK\r\n";
}
static void test_server_broken_payload(unsigned int index)
{
}
/* client */
static void
const struct http_response *resp,
void *context ATTR_UNUSED)
{
if (debug)
}
static bool
{
struct http_client_request *hreq;
return TRUE;
}
/* test */
static void test_broken_payload(void)
{
struct http_client_settings http_client_set;
test_begin("broken payload");
NULL);
test_end();
}
/*
* Connection lost
*/
/* server */
static void
{
if (server_read_max == 0) {
return;
}
if (ret == -2) {
return;
}
if (ret < 0) {
i_fatal("server: Client stream ended prematurely");
else
i_fatal("server: Stream error: %s",
}
}
static void test_server_connection_lost(unsigned int index)
{
}
/* client */
struct _connection_lost_ctx {
unsigned int count;
};
struct _connection_lost_request_ctx {
struct _connection_lost_ctx *ctx;
struct http_client_request *req;
};
static void
const struct http_response *resp,
struct _connection_lost_request_ctx *rctx)
{
if (debug)
if (debug)
i_debug("retrying");
return;
}
}
}
static bool
{
static const char payload[] =
"This is a useless payload that only serves as a means to give the "
"server the opportunity to close the connection before the payload "
"is finished.";
struct _connection_lost_ctx *ctx;
struct _connection_lost_request_ctx *rctx;
struct http_client_request *hreq;
return TRUE;
}
/* test */
static void test_connection_lost(void)
{
struct http_client_settings http_client_set;
server_read_max = 0;
test_begin("connection lost: one attempt");
NULL);
test_end();
test_begin("connection lost: two attempts");
NULL);
test_end();
test_begin("connection lost: three attempts");
NULL);
test_end();
test_begin("connection lost: manual retry");
NULL);
test_end();
}
/*
* Connection lost after 100-continue
*/
/* server */
static void
{
static const char *resp =
"HTTP/1.1 100 Continue\r\n"
"\r\n";
}
static void test_server_connection_lost_100(unsigned int index)
{
}
/* client */
struct _connection_lost_100_ctx {
unsigned int count;
};
static void
const struct http_response *resp,
struct _connection_lost_100_ctx *ctx)
{
if (debug)
}
}
static bool
const struct http_client_settings *client_set)
{
static const char payload[] =
"This is a useless payload that only serves as a means to give the "
"server the opportunity to close the connection before the payload "
"is finished.";
struct _connection_lost_100_ctx *ctx;
struct http_client_request *hreq;
return TRUE;
}
/* test */
static void test_connection_lost_100(void)
{
struct http_client_settings http_client_set;
server_read_max = 0;
test_begin("connection lost after 100-continue");
NULL);
test_end();
}
/*
* Connection lost in sub-ioloop
*/
/* server */
static void
{
static const char *resp =
"HTTP/1.1 200 OK\r\n"
"Content-Length: 0\r\n"
"\r\n";
}
static void test_server_connection_lost_sub_ioloop(unsigned int index)
{
}
/* client */
struct _connection_lost_sub_ioloop_ctx {
unsigned int count;
};
static void
const struct http_response *resp,
struct ioloop *sub_ioloop)
{
if (debug)
}
static void
const struct http_response *resp,
struct _connection_lost_sub_ioloop_ctx *ctx)
{
struct http_client_request *hreq;
struct ioloop *sub_ioloop;
if (debug)
sub_ioloop = io_loop_create();
}
}
static bool
const struct http_client_settings *client_set)
{
static const char payload[] =
"This is a useless payload that only serves as a means to give the "
"server the opportunity to close the connection before the payload "
"is finished.";
struct _connection_lost_sub_ioloop_ctx *ctx;
struct http_client_request *hreq;
return TRUE;
}
/* test */
static void test_connection_lost_sub_ioloop(void)
{
struct http_client_settings http_client_set;
server_read_max = 0;
test_begin("connection lost while running sub-ioloop");
NULL);
test_end();
}
/*
* Early success
*/
/* server */
static void
{
static const char *resp =
"HTTP/1.1 200 OK\r\n"
"Content-Length: 18\r\n"
"\r\n"
"Everything is OK\r\n";
usleep(200000);
}
static void test_server_early_success(unsigned int index)
{
}
/* client */
struct _early_success_ctx {
unsigned int count;
};
static void
const struct http_response *resp,
struct _early_success_ctx *ctx)
{
if (debug)
else
}
}
static bool
{
struct http_client_request *hreq;
struct _early_success_ctx *ctx;
unsigned int i;
T_BEGIN {
struct istream_chain *chain;
for (i = 0; i < 3000; i++) {
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n");
}
} T_END;
return TRUE;
}
/* test */
static void test_early_success(void)
{
struct http_client_settings http_client_set;
test_begin("early succes");
NULL);
test_end();
}
/*
* Bad response
*/
/* server */
static void
{
static const char *resp =
"HTTP/1.1 666 Really bad response\r\n"
"\r\n";
}
static void test_server_bad_response(unsigned int index)
{
}
/* client */
struct _bad_response_ctx {
unsigned int count;
};
static void
const struct http_response *resp,
struct _bad_response_ctx *ctx)
{
if (debug)
}
}
static bool
{
struct http_client_request *hreq;
struct _bad_response_ctx *ctx;
return TRUE;
}
/* test */
static void test_bad_response(void)
{
struct http_client_settings http_client_set;
test_begin("bad response");
NULL);
test_end();
}
/*
* Request timed out
*/
/* server */
static void
{
/* do nothing */
}
static void test_server_request_timed_out(unsigned int index)
{
}
/* client */
struct _request_timed_out1_ctx {
unsigned int count;
};
static void
const struct http_response *resp,
struct _request_timed_out1_ctx *ctx)
{
if (debug)
}
}
static bool
{
struct http_client_request *hreq;
struct _request_timed_out1_ctx *ctx;
return TRUE;
}
struct _request_timed_out2_ctx {
unsigned int count;
unsigned int max_parallel_connections;
};
static void
struct _request_timed_out2_ctx *ctx)
{
i_debug("TIMEOUT");
}
static void
const struct http_response *resp,
struct _request_timed_out2_ctx *ctx)
{
if (debug)
} else {
}
}
static bool
{
struct http_client_request *hreq;
struct _request_timed_out2_ctx *ctx;
return TRUE;
}
/* test */
static void test_request_timed_out(void)
{
struct http_client_settings http_client_set;
test_begin("request timed out: one attempt");
NULL);
test_end();
test_begin("request timed out: two attempts");
NULL);
test_end();
test_begin("request absolutely timed out");
NULL);
test_end();
test_begin("request double timed out");
NULL);
test_end();
test_begin("request timed out: specific timeout");
NULL);
test_end();
test_begin("request timed out: specific timeout (parallel)");
NULL);
test_end();
}
/*
* Request aborted early
*/
/* server */
static void
{
static const char *resp =
"HTTP/1.1 404 Not Found\r\n"
"\r\n";
/* wait one second to respon */
sleep(1);
/* respond */
}
static void test_server_request_aborted_early(unsigned int index)
{
}
/* client */
struct _request_aborted_early_ctx {
};
static void
const struct http_response *resp,
{
if (debug)
/* abort does not trigger callback */
}
static void
struct _request_aborted_early_ctx *ctx)
{
/* abort early */
/* wait a little for server to actually respond to an
already aborted request */
} else {
/* all done */
}
}
static bool
const struct http_client_settings *client_set)
{
struct http_client_request *hreq;
struct _request_aborted_early_ctx *ctx;
return TRUE;
}
/* test */
static void test_request_aborted_early(void)
{
struct http_client_settings http_client_set;
test_begin("request aborted early");
NULL);
test_end();
}
/*
* Request failed blocking
*/
/* server */
static void
{
static const char *resp =
"HTTP/1.1 500 Internal Server Error\r\n"
"\r\n";
/* respond */
sleep(10);
}
static void test_server_request_failed_blocking(unsigned int index)
{
}
/* client */
struct _request_failed_blocking_ctx {
struct http_client_request *req;
};
static void
const struct http_response *resp,
{
if (debug)
}
static bool
const struct http_client_settings *client_set)
{
static const char *payload = "This a test payload!";
struct http_client_request *hreq;
struct _request_failed_blocking_ctx *ctx;
unsigned int n;
for (n = 0; n < 50000; n++)
return FALSE;
}
/* test */
static void test_request_failed_blocking(void)
{
struct http_client_settings http_client_set;
test_begin("request failed blocking");
NULL);
test_end();
}
/*
* Client deinit early
*/
/* server */
static void
{
static const char *resp =
"HTTP/1.1 404 Not Found\r\n"
"\r\n";
/* wait one second to respon */
sleep(1);
/* respond */
}
static void test_server_client_deinit_early(unsigned int index)
{
}
/* client */
struct _client_deinit_early_ctx {
};
static void
const struct http_response *resp,
{
if (debug)
/* abort does not trigger callback */
}
static void
struct _client_deinit_early_ctx *ctx)
{
/* deinit early */
/* all done */
}
static bool
{
struct http_client_request *hreq;
struct _client_deinit_early_ctx *ctx;
return TRUE;
}
/* test */
static void test_client_deinit_early(void)
{
struct http_client_settings http_client_set;
test_begin("client deinit early");
NULL);
test_end();
}
/*
* Retry with delay
*/
/* server */
static void
{
"HTTP/1.1 500 Internal Server Error\r\n"
"\r\n");
}
static void test_server_retry_with_delay(unsigned int index)
{
}
/* client */
struct _client_retry_with_delay_ctx {
struct http_client_request *req;
unsigned int retries;
};
static void
const struct http_response *resp,
struct _client_retry_with_delay_ctx *ctx)
{
int real_delay, exp_delay;
if (debug)
/* check delay */
i_fatal("Retry delay is too short %d < %d",
}
}
if (debug)
i_debug("retrying");
return;
}
}
static bool
{
struct http_client_request *hreq;
struct _client_retry_with_delay_ctx *ctx;
return TRUE;
}
/* test */
static void test_retry_with_delay(void)
{
struct http_client_settings http_client_set;
test_begin("retry with delay");
NULL);
test_end();
}
/*
* DNS service failure
*/
/* client */
struct _dns_service_failure {
unsigned int count;
};
static void
const struct http_response *resp,
struct _dns_service_failure *ctx)
{
if (debug)
}
}
static bool
{
struct http_client_request *hreq;
struct _dns_service_failure *ctx;
return TRUE;
}
/* test */
static void test_dns_service_failure(void)
{
struct http_client_settings http_client_set;
test_begin("dns service failure");
test_end();
}
/*
* DNS timeout
*/
/* dns */
static void
{
/* hang */
sleep(100);
}
static void test_dns_dns_timeout(void)
{
test_server_run(0);
}
/* client */
struct _dns_timeout {
unsigned int count;
};
static void
const struct http_response *resp,
struct _dns_timeout *ctx)
{
if (debug)
}
}
static bool
{
struct http_client_request *hreq;
struct _dns_timeout *ctx;
return TRUE;
}
/* test */
static void test_dns_timeout(void)
{
struct http_client_settings http_client_set;
test_begin("dns timeout");
NULL, 0,
test_end();
}
/*
* DNS lookup failure
*/
/* dns */
static void
{
}
static void test_dns_dns_lookup_failure(void)
{
test_server_run(0);
}
/* client */
struct _dns_lookup_failure {
unsigned int count;
};
static void
const struct http_response *resp,
struct _dns_lookup_failure *ctx)
{
if (debug)
}
}
static bool
{
struct http_client_request *hreq;
struct _dns_lookup_failure *ctx;
return TRUE;
}
/* test */
static void test_dns_lookup_failure(void)
{
struct http_client_settings http_client_set;
test_begin("dns lookup failure");
NULL, 0,
test_end();
}
/*
* DNS lookup ttl
*/
/* dns */
static void
{
static unsigned int count = 0;
const char *line;
if (debug)
if (count == 0) {
"0 1\n127.0.0.1\n");
} else {
if (count > 4) {
return;
}
}
count++;
}
}
static void test_dns_dns_lookup_ttl(void)
{
test_server_run(0);
}
/* server */
static void
{
"HTTP/1.1 200 OK\r\n"
"Connection: close\r\n"
"\r\n");
}
static void test_server_dns_lookup_ttl(unsigned int index)
{
}
/* client */
struct _dns_lookup_ttl {
struct http_client *client;
unsigned int count;
};
static void
const struct http_response *resp,
struct _dns_lookup_ttl *ctx)
{
if (debug)
}
}
static void
{
struct http_client_request *hreq;
}
static void
const struct http_response *resp,
struct _dns_lookup_ttl *ctx)
{
if (debug)
}
}
static bool
{
struct http_client_request *hreq;
struct _dns_lookup_ttl *ctx;
return TRUE;
}
/* test */
static void test_dns_lookup_ttl(void)
{
struct http_client_settings http_client_set;
test_begin("dns lookup ttl");
test_end();
}
/*
* Peer reuse failure
*/
/* server */
static void
{
static unsigned int seq = 0;
static const char *resp =
"HTTP/1.1 200 OK\r\n"
"\r\n";
if (seq++ > 2) {
}
}
static void test_server_peer_reuse_failure(unsigned int index)
{
}
/* client */
struct _peer_reuse_failure {
bool first:1;
};
static void
const struct http_response *resp,
struct _peer_reuse_failure *ctx)
{
if (debug)
}
static void
{
struct http_client_request *hreq;
}
static void
const struct http_response *resp,
struct _peer_reuse_failure *ctx)
{
if (debug)
} else {
}
}
static bool
{
struct http_client_request *hreq;
struct _peer_reuse_failure *ctx;
return TRUE;
}
/* test */
static void test_peer_reuse_failure(void)
{
struct http_client_settings http_client_set;
test_begin("peer reuse failure");
NULL);
test_end();
}
/*
* Reconnect failure
*/
/* dns */
static void
{
static unsigned int count = 0;
const char *line;
if (debug)
if (count == 0) {
"0 1\n127.0.0.1\n");
} else {
if (count > 4) {
return;
}
}
count++;
}
}
static void test_dns_reconnect_failure(void)
{
test_server_run(0);
}
/* server */
static void
{
static const char *resp =
"HTTP/1.1 200 OK\r\n"
"Content-Length: 18\r\n"
"\r\n"
"Everything is OK\r\n";
sleep(500);
}
static void test_server_reconnect_failure(unsigned int index)
{
}
/* client */
struct _reconnect_failure_ctx {
};
static void
const struct http_response *resp,
struct _reconnect_failure_ctx *ctx)
{
if (debug)
}
static void
struct _reconnect_failure_ctx *ctx)
{
struct http_client_request *hreq;
if (debug)
i_debug("NEXT REQUEST");
}
static void
const struct http_response *resp,
struct _reconnect_failure_ctx *ctx)
{
if (debug)
}
static bool
{
struct http_client_request *hreq;
struct _reconnect_failure_ctx *ctx;
return TRUE;
}
/* test */
static void test_reconnect_failure(void)
{
struct http_client_settings http_client_set;
test_begin("reconnect failure");
test_end();
}
/*
* All tests
*/
static void (*const test_functions[])(void) = {
};
/*
* Test client
*/
static void
{
/* client settings */
http_set->max_redirects = 0;
}
static void test_client_deinit(void)
{
if (http_client != NULL)
http_client = NULL;
}
/*
* Test server
*/
/* client connection */
static void
{
}
static void
server_connection_init(int fd)
{
struct server_connection *conn;
}
static void
{
}
static void
{
struct server_connection *conn =
(struct server_connection *)_conn;
}
static void
{
int fd;
/* accept new client */
if (fd == -1)
return;
if (fd == -2) {
i_fatal("test server: accept() failed: %m");
}
}
/* */
static struct connection_settings server_connection_set = {
};
static const struct connection_vfuncs server_connection_vfuncs = {
};
static void test_server_run(unsigned int index)
{
/* open server socket */
/* close server socket */
}
/*
* Tests
*/
{
if (debug)
if (fd == -1) {
i_fatal("listen(%s:%u) failed: %m",
}
return fd;
}
static void test_servers_kill_all(void)
{
unsigned int i;
if (server_pids_count > 0) {
for (i = 0; i < server_pids_count; i++) {
server_pids[i] = -1;
}
}
}
server_pids_count = 0;
}
}
static void test_run_client_server(
const struct http_client_settings *client_set,
unsigned int server_tests_count,
{
unsigned int i;
server_pids = NULL;
server_pids_count = 0;
if (server_tests_count > 0) {
int fds[server_tests_count];
for (i = 0; i < server_tests_count; i++)
for (i = 0; i < server_tests_count; i++)
for (i = 0; i < server_tests_count; i++) {
i_fatal("fork() failed: %m");
if (server_pids[i] == 0) {
server_pids_count = 0;
hostpid_init();
if (debug)
/* child: server */
ioloop = io_loop_create();
server_test(i);
/* wait for it to be killed; this way, valgrind will not
object to this process going away inelegantly. */
sleep(60);
exit(1);
}
}
if (debug)
}
int fd;
i_unlink_if_exists("./dns-test");
if (fd == -1) {
i_fatal("listen(./dns-test) failed: %m");
}
i_fatal("fork() failed: %m");
if (dns_pid == 0) {
hostpid_init();
if (debug)
/* child: server */
ioloop = io_loop_create();
dns_test();
/* wait for it to be killed; this way, valgrind will not
object to this process going away inelegantly. */
sleep(60);
exit(1);
}
}
/* parent: client */
ioloop = io_loop_create();
if (client_test(client_set))
i_unlink_if_exists("./dns-test");
}
/*
* Main
*/
volatile sig_atomic_t terminating = 0;
static void
test_signal_handler(int signo)
{
if (terminating != 0)
terminating = 1;
/* make sure we don't leave any pesky children alive */
}
static void test_atexit(void)
{
}
{
int c;
switch (c) {
case 'D':
break;
default:
}
}
/* listen on localhost */
}