Blame tests/dtls/dtls-stress.c

Packit 549fdc
/*
Packit 549fdc
 * Copyright (C) 2012-2016 Sean Buckheister
Packit 549fdc
 * Copyright (C) 2016 Nikos Mavrogiannopoulos
Packit 549fdc
 * Copyright (C) 2016 Red Hat, Inc.
Packit 549fdc
 *
Packit 549fdc
 * This file is part of GnuTLS.
Packit 549fdc
 *
Packit 549fdc
 * GnuTLS is free software; you can redistribute it and/or modify it
Packit 549fdc
 * under the terms of the GNU General Public License as published by
Packit 549fdc
 * the Free Software Foundation; either version 3 of the License, or
Packit 549fdc
 * (at your option) any later version.
Packit 549fdc
 *
Packit 549fdc
 * GnuTLS is distributed in the hope that it will be useful, but
Packit 549fdc
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 549fdc
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 549fdc
 * General Public License for more details.
Packit 549fdc
 *
Packit 549fdc
 * You should have received a copy of the GNU General Public License
Packit 549fdc
 * along with GnuTLS; if not, write to the Free Software Foundation,
Packit 549fdc
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Packit 549fdc
 */
Packit 549fdc
Packit 549fdc
/*
Packit 549fdc
 * DTLS stress test utility
Packit 549fdc
 *
Packit 549fdc
 * **** Available parameters ****
Packit 549fdc
 *
Packit 549fdc
 *	-nb		 enable nonblocking operations on sessions
Packit 549fdc
 *	-batch	      read test identifiers from stdin and run them
Packit 549fdc
 *	-d		  increase debug level by one
Packit 549fdc
 *	-r		  replay messages (very crude replay mechanism)
Packit 549fdc
 *	-d <n>	      set debug level to <n>
Packit 549fdc
 *	-die		don't start new tests after the first detected failure
Packit 549fdc
 *	-timeout <n>	set handshake timeout to <n> seconds. Tests that don't make progress
Packit 549fdc
 *			    within twice this time will be forcibly killed. (default: 120)
Packit 549fdc
 *	-retransmit <n>     set retransmit timeout to <n> milliseconds (default: 100)
Packit 549fdc
 *	-j <n>	      run up to <n> tests in parallel
Packit 549fdc
 *	-full	       use full handshake with mutual certificate authentication
Packit 549fdc
 *	-resume	     use resumed handshake
Packit 549fdc
 *	-shello <perm>      run only one test, with the server hello flight permuted as <perm>
Packit 549fdc
 *	-sfinished <perm>   run only one test, with the server finished flight permuted as <perm>
Packit 549fdc
 *	-cfinished <perm>   run only one test, with the client finished flight permuted as <perm>
Packit 549fdc
 *	<packet name>       run only one test, drop <packet name> three times
Packit 549fdc
 *			    valid values for <packet name> are:
Packit 549fdc
 *				SHello, SCertificate, SKeyExchange, SCertificateRequest, SHelloDone,
Packit 549fdc
 *				CCertificate, CKeyExchange, CCertificateVerify, CChangeCipherSpec,
Packit 549fdc
 *				CFinished, SChangeCipherSpec, SFinished
Packit 549fdc
 *			    using *Certificate* without -full will yield unexpected results
Packit 549fdc
 *
Packit 549fdc
 * 
Packit 549fdc
 * **** Permutation handling ****
Packit 549fdc
 *
Packit 549fdc
 * Flight length for -sfinished is 2, for -shello and -cfinished they are 5 with -full, 3 otherwise.
Packit 549fdc
 * Permutations are given with base 0 and specify the order in which reordered packets are transmitted.
Packit 549fdc
 * For example, -full -shello 42130 will transmit server hello flight packets in the order
Packit 549fdc
 * SHelloDone, SKeyExchange, SCertificate, SCertificateRequest, SHello
Packit 549fdc
 *
Packit 549fdc
 * When -resume is specified the -sfinished flight length is 3 (same as shello), cfinished is 2.
Packit 549fdc
 * The -resume option has to be combined with sfinished or cfinished.
Packit 549fdc
 *
Packit 549fdc
 * **** Output format ****
Packit 549fdc
 *
Packit 549fdc
 * Every line printed for any given test is prefixed by a unique id for that test. See run_test_by_id for
Packit 549fdc
 * exact composition. Errors encountered during execution are printed, with one status line after test
Packit 549fdc
 * completen. The format for this line is as follows:
Packit 549fdc
 *
Packit 549fdc
 * <id> <status> SHello(<shperm>), SFinished(<sfinperm>), CFinished(<cfinperm>) :- <drops>
Packit 549fdc
 *
Packit 549fdc
 * The format for error lines is <id> <role>| <text>, with <role> being the role of the child process
Packit 549fdc
 * that encountered the error, and <text> being obvious.
Packit 549fdc
 *
Packit 549fdc
 * <id> is the unique id for the test, it can be used as input to -batch.
Packit 549fdc
 * <status> can be ++ for a successful test, -- for a failure, TT for a deadlock timeout killed test,
Packit 549fdc
 *     or !! for a test has died due to some unforeseen circumstances like syscall failures.
Packit 549fdc
 * <shperm>, <sfinperm>, <cfinperm> show the permutation for the respective flights used.
Packit 549fdc
 *    They can be used as input to -shello, -sfinished, and -cfinished, respectively.
Packit 549fdc
 * <drops> is a comma separated list of <packet name>, one for every packet dropped thrice
Packit 549fdc
 *
Packit 549fdc
 *
Packit 549fdc
 * **** Exit status ****
Packit 549fdc
 *
Packit 549fdc
 * 0    all tests have passed
Packit 549fdc
 * 1    some tests have failed
Packit 549fdc
 * 4    the master processed has encountered unexpected errors
Packit 549fdc
 * 8    error parsing command line
Packit 549fdc
 */
Packit 549fdc
Packit 549fdc
#include <config.h>
Packit 549fdc
#include <gnutls/gnutls.h>
Packit 549fdc
#include <gnutls/openpgp.h>
Packit 549fdc
#include <gnutls/dtls.h>
Packit 549fdc
#include <unistd.h>
Packit 549fdc
#include "../utils.h"
Packit 549fdc
#include <sys/socket.h>
Packit 549fdc
#include <sys/types.h>
Packit 549fdc
#include <netinet/in.h>
Packit 549fdc
#include <fcntl.h>
Packit 549fdc
#include <stdio.h>
Packit 549fdc
#include <stdlib.h>
Packit 549fdc
#include <string.h>
Packit 549fdc
#include <errno.h>
Packit 549fdc
#include <poll.h>
Packit 549fdc
#include <time.h>
Packit 549fdc
#include <assert.h>
Packit 549fdc
#include <sys/wait.h>
Packit 549fdc
Packit 549fdc
#if _POSIX_TIMERS && (_POSIX_TIMERS - 200112L) >= 0
Packit 549fdc
Packit 549fdc
// {{{ types
Packit 549fdc
Packit 549fdc
#define log(fmt, ...) \
Packit 549fdc
	if (debug) fprintf(stdout, "%i %s| "fmt, run_id, role_name, ##__VA_ARGS__)
Packit 549fdc
Packit 549fdc
typedef struct {
Packit 549fdc
	int count;
Packit 549fdc
} filter_packet_state_t;
Packit 549fdc
Packit 549fdc
typedef struct {
Packit 549fdc
	const char *name;
Packit 549fdc
	gnutls_datum_t packets[5];
Packit 549fdc
	int *order;
Packit 549fdc
	int count;
Packit 549fdc
} filter_permute_state_t;
Packit 549fdc
Packit 549fdc
typedef void (*filter_fn) (gnutls_transport_ptr_t, const unsigned char *,
Packit 549fdc
			   size_t);
Packit 549fdc
Packit 549fdc
typedef int (*match_fn) (const unsigned char *, size_t);
Packit 549fdc
Packit 549fdc
enum role { SERVER, CLIENT };
Packit 549fdc
Packit 549fdc
// }}}
Packit 549fdc
Packit 549fdc
// {{{ static data
Packit 549fdc
Packit 549fdc
static int permutations2[2][2]
Packit 549fdc
= { {0, 1}, {1, 0} };
Packit 549fdc
Packit 549fdc
static const char *permutation_names2[]
Packit 549fdc
= { "01", "10", 0 };
Packit 549fdc
Packit 549fdc
static int permutations3[6][3]
Packit 549fdc
= { {0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0} };
Packit 549fdc
Packit 549fdc
static const char *permutation_names3[]
Packit 549fdc
= { "012", "021", "102", "120", "201", "210", 0 };
Packit 549fdc
Packit 549fdc
static int permutations5[120][5] = { 
Packit 549fdc
	{0, 1, 2, 3, 4}, {0, 2, 1, 3, 4}, {1, 0, 2, 3, 4}, {1, 2, 0, 3, 4},
Packit 549fdc
	{2, 0, 1, 3, 4}, {2, 1, 0, 3, 4}, {0, 1, 3, 2, 4}, {0, 2, 3, 1, 4},
Packit 549fdc
	{1, 0, 3, 2, 4}, {1, 2, 3, 0, 4}, {2, 0, 3, 1, 4}, {2, 1, 3, 0, 4},
Packit 549fdc
	{0, 3, 1, 2, 4}, {0, 3, 2, 1, 4}, {1, 3, 0, 2, 4}, {1, 3, 2, 0, 4},
Packit 549fdc
	{2, 3, 0, 1, 4}, {2, 3, 1, 0, 4}, {3, 0, 1, 2, 4}, {3, 0, 2, 1, 4},
Packit 549fdc
	{3, 1, 0, 2, 4}, {3, 1, 2, 0, 4}, {3, 2, 0, 1, 4}, {3, 2, 1, 0, 4},
Packit 549fdc
	{0, 1, 2, 4, 3}, {0, 2, 1, 4, 3}, {1, 0, 2, 4, 3}, {1, 2, 0, 4, 3},
Packit 549fdc
	{2, 0, 1, 4, 3}, {2, 1, 0, 4, 3}, {0, 1, 3, 4, 2}, {0, 2, 3, 4, 1},
Packit 549fdc
	{1, 0, 3, 4, 2}, {1, 2, 3, 4, 0}, {2, 0, 3, 4, 1}, {2, 1, 3, 4, 0},
Packit 549fdc
	{0, 3, 1, 4, 2}, {0, 3, 2, 4, 1}, {1, 3, 0, 4, 2}, {1, 3, 2, 4, 0},
Packit 549fdc
	{2, 3, 0, 4, 1}, {2, 3, 1, 4, 0}, {3, 0, 1, 4, 2}, {3, 0, 2, 4, 1},
Packit 549fdc
	{3, 1, 0, 4, 2}, {3, 1, 2, 4, 0}, {3, 2, 0, 4, 1}, {3, 2, 1, 4, 0},
Packit 549fdc
	{0, 1, 4, 2, 3}, {0, 2, 4, 1, 3}, {1, 0, 4, 2, 3}, {1, 2, 4, 0, 3},
Packit 549fdc
	{2, 0, 4, 1, 3}, {2, 1, 4, 0, 3}, {0, 1, 4, 3, 2}, {0, 2, 4, 3, 1},
Packit 549fdc
	{1, 0, 4, 3, 2}, {1, 2, 4, 3, 0}, {2, 0, 4, 3, 1}, {2, 1, 4, 3, 0},
Packit 549fdc
	{0, 3, 4, 1, 2}, {0, 3, 4, 2, 1}, {1, 3, 4, 0, 2}, {1, 3, 4, 2, 0},
Packit 549fdc
	{2, 3, 4, 0, 1}, {2, 3, 4, 1, 0}, {3, 0, 4, 1, 2}, {3, 0, 4, 2, 1},
Packit 549fdc
	{3, 1, 4, 0, 2}, {3, 1, 4, 2, 0}, {3, 2, 4, 0, 1}, {3, 2, 4, 1, 0},
Packit 549fdc
	{0, 4, 1, 2, 3}, {0, 4, 2, 1, 3}, {1, 4, 0, 2, 3}, {1, 4, 2, 0, 3},
Packit 549fdc
	{2, 4, 0, 1, 3}, {2, 4, 1, 0, 3}, {0, 4, 1, 3, 2}, {0, 4, 2, 3, 1},
Packit 549fdc
	{1, 4, 0, 3, 2}, {1, 4, 2, 3, 0}, {2, 4, 0, 3, 1}, {2, 4, 1, 3, 0},
Packit 549fdc
	{0, 4, 3, 1, 2}, {0, 4, 3, 2, 1}, {1, 4, 3, 0, 2}, {1, 4, 3, 2, 0},
Packit 549fdc
	{2, 4, 3, 0, 1}, {2, 4, 3, 1, 0}, {3, 4, 0, 1, 2}, {3, 4, 0, 2, 1},
Packit 549fdc
	{3, 4, 1, 0, 2}, {3, 4, 1, 2, 0}, {3, 4, 2, 0, 1}, {3, 4, 2, 1, 0},
Packit 549fdc
	{4, 0, 1, 2, 3}, {4, 0, 2, 1, 3}, {4, 1, 0, 2, 3}, {4, 1, 2, 0, 3},
Packit 549fdc
	{4, 2, 0, 1, 3}, {4, 2, 1, 0, 3}, {4, 0, 1, 3, 2}, {4, 0, 2, 3, 1},
Packit 549fdc
	{4, 1, 0, 3, 2}, {4, 1, 2, 3, 0}, {4, 2, 0, 3, 1}, {4, 2, 1, 3, 0},
Packit 549fdc
	{4, 0, 3, 1, 2}, {4, 0, 3, 2, 1}, {4, 1, 3, 0, 2}, {4, 1, 3, 2, 0},
Packit 549fdc
	{4, 2, 3, 0, 1}, {4, 2, 3, 1, 0}, {4, 3, 0, 1, 2}, {4, 3, 0, 2, 1},
Packit 549fdc
	{4, 3, 1, 0, 2}, {4, 3, 1, 2, 0}, {4, 3, 2, 0, 1}, {4, 3, 2, 1, 0}
Packit 549fdc
};
Packit 549fdc
Packit 549fdc
static const char *permutation_names5[]
Packit 549fdc
    = { "01234", "02134", "10234", "12034", "20134", "21034", "01324",
Packit 549fdc
	"02314", "10324", "12304", "20314", "21304", "03124", "03214",
Packit 549fdc
	"13024", "13204", "23014", "23104", "30124", "30214", "31024",
Packit 549fdc
	"31204", "32014", "32104", "01243", "02143", "10243", "12043",
Packit 549fdc
	"20143", "21043", "01342", "02341", "10342", "12340", "20341",
Packit 549fdc
	"21340", "03142", "03241", "13042", "13240", "23041", "23140",
Packit 549fdc
	"30142", "30241", "31042", "31240", "32041", "32140", "01423",
Packit 549fdc
	"02413", "10423", "12403", "20413", "21403", "01432", "02431",
Packit 549fdc
	"10432", "12430", "20431", "21430", "03412", "03421", "13402",
Packit 549fdc
	"13420", "23401", "23410", "30412", "30421", "31402", "31420",
Packit 549fdc
	"32401", "32410", "04123", "04213", "14023", "14203", "24013",
Packit 549fdc
	"24103", "04132", "04231", "14032", "14230", "24031", "24130",
Packit 549fdc
	"04312", "04321", "14302", "14320", "24301", "24310", "34012",
Packit 549fdc
	"34021", "34102", "34120", "34201", "34210", "40123", "40213",
Packit 549fdc
	"41023", "41203", "42013", "42103", "40132", "40231", "41032",
Packit 549fdc
	"41230", "42031", "42130", "40312", "40321", "41302", "41320",
Packit 549fdc
	"42301", "42310", "43012", "43021", "43102", "43120", "43201",
Packit 549fdc
	"43210", 0
Packit 549fdc
};
Packit 549fdc
Packit 549fdc
static const char *filter_names[8]
Packit 549fdc
    = { "SHello",
Packit 549fdc
	"SKeyExchange",
Packit 549fdc
	"SHelloDone",
Packit 549fdc
	"CKeyExchange",
Packit 549fdc
	"CChangeCipherSpec",
Packit 549fdc
	"CFinished",
Packit 549fdc
	"SChangeCipherSpec",
Packit 549fdc
	"SFinished"
Packit 549fdc
};
Packit 549fdc
Packit 549fdc
static const char *filter_names_resume[]
Packit 549fdc
    = { "SHello",
Packit 549fdc
	"SChangeCipherSpec",
Packit 549fdc
	"SFinished",
Packit 549fdc
	"CChangeCipherSpec",
Packit 549fdc
	"CFinished"
Packit 549fdc
};
Packit 549fdc
Packit 549fdc
static const char *filter_names_full[12]
Packit 549fdc
    = { "SHello",
Packit 549fdc
	"SCertificate",
Packit 549fdc
	"SKeyExchange",
Packit 549fdc
	"SCertificateRequest",
Packit 549fdc
	"SHelloDone",
Packit 549fdc
	"CCertificate",
Packit 549fdc
	"CKeyExchange",
Packit 549fdc
	"CCertificateVerify",
Packit 549fdc
	"CChangeCipherSpec",
Packit 549fdc
	"CFinished",
Packit 549fdc
	"SChangeCipherSpec",
Packit 549fdc
	"SFinished"
Packit 549fdc
};
Packit 549fdc
Packit 549fdc
#include "cert-common.h"
Packit 549fdc
Packit 549fdc
// }}}
Packit 549fdc
Packit 549fdc
// {{{ other global state
Packit 549fdc
Packit 549fdc
enum role role;
Packit 549fdc
Packit 549fdc
#define role_name (role == SERVER ? "server" : "client")
Packit 549fdc
Packit 549fdc
int debug;
Packit 549fdc
int nonblock;
Packit 549fdc
int replay;
Packit 549fdc
int full;
Packit 549fdc
int resume;
Packit 549fdc
int timeout_seconds;
Packit 549fdc
int retransmit_milliseconds;
Packit 549fdc
int run_to_end;
Packit 549fdc
Packit 549fdc
int run_id;
Packit 549fdc
Packit 549fdc
// }}}
Packit 549fdc
Packit 549fdc
// {{{ logging and error handling
Packit 549fdc
Packit 549fdc
static void logfn(int level, const char *s)
Packit 549fdc
{
Packit 549fdc
	if (debug) {
Packit 549fdc
		fprintf(stdout, "%i %s|<%i> %s", run_id, role_name, level, s);
Packit 549fdc
	}
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static void auditfn(gnutls_session_t session, const char *s)
Packit 549fdc
{
Packit 549fdc
	if (debug) {
Packit 549fdc
		fprintf(stdout, "%i %s| %s", run_id, role_name, s);
Packit 549fdc
	}
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static void drop(const char *packet)
Packit 549fdc
{
Packit 549fdc
	if (debug) {
Packit 549fdc
		log("dropping %s\n", packet);
Packit 549fdc
	}
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int _process_error(int loc, int code, int die)
Packit 549fdc
{
Packit 549fdc
	if (code < 0 && (die || code != GNUTLS_E_AGAIN)) {
Packit 549fdc
		fprintf(stdout, "%i <%s tls> line %i: %s", run_id,
Packit 549fdc
			role_name, loc, gnutls_strerror(code));
Packit 549fdc
		if (gnutls_error_is_fatal(code) || die) {
Packit 549fdc
			fprintf(stdout, " (fatal)\n");
Packit 549fdc
			exit(1);
Packit 549fdc
		} else {
Packit 549fdc
			fprintf(stdout, "\n");
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
	return code;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
#define die_on_error(code) _process_error(__LINE__, code, 1)
Packit 549fdc
#define process_error(code) _process_error(__LINE__, code, 0)
Packit 549fdc
Packit 549fdc
static void _process_error_or_timeout(int loc, int err, time_t tdiff)
Packit 549fdc
{
Packit 549fdc
	if (err < 0) {
Packit 549fdc
		if (err != GNUTLS_E_TIMEDOUT || tdiff >= 60) {
Packit 549fdc
			_process_error(loc, err, 0);
Packit 549fdc
		} else {
Packit 549fdc
			log("line %i: {spurious timeout} (fatal)", loc);
Packit 549fdc
			exit(1);
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
#define process_error_or_timeout(code, tdiff) _process_error_or_timeout(__LINE__, code, tdiff)
Packit 549fdc
Packit 549fdc
static void rperror(const char *name)
Packit 549fdc
{
Packit 549fdc
	fprintf(stdout, "%i %s| %s\n", run_id, role_name, name);
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
// }}}
Packit 549fdc
Packit 549fdc
// {{{ init, shared, and teardown code and data for packet stream filters
Packit 549fdc
Packit 549fdc
filter_packet_state_t state_packet_ServerHello = { 0 };
Packit 549fdc
filter_packet_state_t state_packet_ServerCertificate = { 0 };
Packit 549fdc
filter_packet_state_t state_packet_ServerKeyExchange = { 0 };
Packit 549fdc
filter_packet_state_t state_packet_ServerCertificateRequest = { 0 };
Packit 549fdc
filter_packet_state_t state_packet_ServerHelloDone = { 0 };
Packit 549fdc
filter_packet_state_t state_packet_ClientCertificate = { 0 };
Packit 549fdc
filter_packet_state_t state_packet_ClientKeyExchange = { 0 };
Packit 549fdc
filter_packet_state_t state_packet_ClientCertificateVerify = { 0 };
Packit 549fdc
filter_packet_state_t state_packet_ClientChangeCipherSpec = { 0 };
Packit 549fdc
filter_packet_state_t state_packet_ClientFinished = { 0 };
Packit 549fdc
filter_packet_state_t state_packet_ClientFinishedResume = { 0 };
Packit 549fdc
filter_packet_state_t state_packet_ServerChangeCipherSpec = { 0 };
Packit 549fdc
filter_packet_state_t state_packet_ServerFinished = { 0 };
Packit 549fdc
filter_packet_state_t state_packet_ServerFinishedResume = { 0 };
Packit 549fdc
Packit 549fdc
static filter_permute_state_t state_permute_ServerHello =
Packit 549fdc
    { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
Packit 549fdc
static filter_permute_state_t state_permute_ServerHelloFull =
Packit 549fdc
    { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
Packit 549fdc
static filter_permute_state_t state_permute_ServerFinished =
Packit 549fdc
    { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
Packit 549fdc
static filter_permute_state_t state_permute_ServerFinishedResume =
Packit 549fdc
    { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
Packit 549fdc
static filter_permute_state_t state_permute_ClientFinished =
Packit 549fdc
    { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
Packit 549fdc
static filter_permute_state_t state_permute_ClientFinishedResume =
Packit 549fdc
    { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
Packit 549fdc
static filter_permute_state_t state_permute_ClientFinishedFull =
Packit 549fdc
    { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
Packit 549fdc
Packit 549fdc
filter_fn filter_chain[32];
Packit 549fdc
int filter_current_idx;
Packit 549fdc
Packit 549fdc
static void filter_permute_state_free_buffer(filter_permute_state_t * state)
Packit 549fdc
{
Packit 549fdc
	unsigned int i;
Packit 549fdc
Packit 549fdc
	for (i = 0; i < sizeof(state->packets) / sizeof(state->packets[0]); i++) {
Packit 549fdc
		free(state->packets[i].data);
Packit 549fdc
		state->packets[i].data = NULL;
Packit 549fdc
	}
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static void filter_clear_state(void)
Packit 549fdc
{
Packit 549fdc
	filter_current_idx = 0;
Packit 549fdc
Packit 549fdc
	filter_permute_state_free_buffer(&state_permute_ServerHello);
Packit 549fdc
	filter_permute_state_free_buffer(&state_permute_ServerHelloFull);
Packit 549fdc
	filter_permute_state_free_buffer(&state_permute_ServerFinished);
Packit 549fdc
	filter_permute_state_free_buffer(&state_permute_ServerFinishedResume);
Packit 549fdc
	filter_permute_state_free_buffer(&state_permute_ClientFinished);
Packit 549fdc
	filter_permute_state_free_buffer(&state_permute_ClientFinishedResume);
Packit 549fdc
	filter_permute_state_free_buffer(&state_permute_ClientFinishedFull);
Packit 549fdc
Packit 549fdc
	memset(&state_packet_ServerHello, 0, sizeof(state_packet_ServerHello));
Packit 549fdc
	memset(&state_packet_ServerCertificate, 0,
Packit 549fdc
	       sizeof(state_packet_ServerCertificate));
Packit 549fdc
	memset(&state_packet_ServerKeyExchange, 0,
Packit 549fdc
	       sizeof(state_packet_ServerKeyExchange));
Packit 549fdc
	memset(&state_packet_ServerCertificateRequest, 0,
Packit 549fdc
	       sizeof(state_packet_ServerCertificateRequest));
Packit 549fdc
	memset(&state_packet_ServerHelloDone, 0,
Packit 549fdc
	       sizeof(state_packet_ServerHelloDone));
Packit 549fdc
	memset(&state_packet_ClientCertificate, 0,
Packit 549fdc
	       sizeof(state_packet_ClientCertificate));
Packit 549fdc
	memset(&state_packet_ClientKeyExchange, 0,
Packit 549fdc
	       sizeof(state_packet_ClientKeyExchange));
Packit 549fdc
	memset(&state_packet_ClientCertificateVerify, 0,
Packit 549fdc
	       sizeof(state_packet_ClientCertificateVerify));
Packit 549fdc
	memset(&state_packet_ClientChangeCipherSpec, 0,
Packit 549fdc
	       sizeof(state_packet_ClientChangeCipherSpec));
Packit 549fdc
	memset(&state_packet_ClientFinished, 0,
Packit 549fdc
	       sizeof(state_packet_ClientFinished));
Packit 549fdc
	memset(&state_packet_ClientFinishedResume, 0,
Packit 549fdc
	       sizeof(state_packet_ClientFinishedResume));
Packit 549fdc
	memset(&state_packet_ServerChangeCipherSpec, 0,
Packit 549fdc
	       sizeof(state_packet_ServerChangeCipherSpec));
Packit 549fdc
	memset(&state_packet_ServerFinished, 0,
Packit 549fdc
	       sizeof(state_packet_ServerFinished));
Packit 549fdc
	memset(&state_packet_ServerFinishedResume, 0,
Packit 549fdc
	       sizeof(state_packet_ServerFinishedResume));
Packit 549fdc
	memset(&state_permute_ServerHello, 0,
Packit 549fdc
	       sizeof(state_permute_ServerHello));
Packit 549fdc
	memset(&state_permute_ServerHelloFull, 0,
Packit 549fdc
	       sizeof(state_permute_ServerHelloFull));
Packit 549fdc
	memset(&state_permute_ServerFinished, 0,
Packit 549fdc
	       sizeof(state_permute_ServerFinished));
Packit 549fdc
	memset(&state_permute_ClientFinished, 0,
Packit 549fdc
	       sizeof(state_permute_ClientFinished));
Packit 549fdc
	memset(&state_permute_ClientFinishedResume, 0,
Packit 549fdc
	       sizeof(state_permute_ClientFinishedResume));
Packit 549fdc
	memset(&state_permute_ClientFinishedFull, 0,
Packit 549fdc
	       sizeof(state_permute_ClientFinishedFull));
Packit 549fdc
Packit 549fdc
	state_permute_ServerHello.name = "ServerHello";
Packit 549fdc
	state_permute_ServerHelloFull.name = "ServerHelloFull";
Packit 549fdc
	state_permute_ServerFinished.name = "ServerFinished";
Packit 549fdc
	state_permute_ServerFinishedResume.name = "ServerFinishedResume";
Packit 549fdc
	state_permute_ClientFinished.name = "ClientFinished";
Packit 549fdc
	state_permute_ClientFinishedResume.name = "ClientFinishedResume";
Packit 549fdc
	state_permute_ClientFinishedFull.name = "ClientFinishedFull";
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/* replay buffer */
Packit 549fdc
static int rbuffer[5 * 1024];
Packit 549fdc
unsigned rbuffer_size = 0;
Packit 549fdc
Packit 549fdc
static void filter_run_next(gnutls_transport_ptr_t fd,
Packit 549fdc
			    const unsigned char *buffer, size_t len)
Packit 549fdc
{
Packit 549fdc
	int ret = 0;
Packit 549fdc
	filter_fn fn = filter_chain[filter_current_idx];
Packit 549fdc
	filter_current_idx++;
Packit 549fdc
	if (fn) {
Packit 549fdc
		fn(fd, buffer, len);
Packit 549fdc
	} else {
Packit 549fdc
		ret = send((int)(intptr_t) fd, buffer, len, 0);
Packit 549fdc
	}
Packit 549fdc
	filter_current_idx--;
Packit 549fdc
Packit 549fdc
	if (ret > 0 && replay != 0) {
Packit 549fdc
		if (rbuffer_size == 0 && len < sizeof(rbuffer)) {
Packit 549fdc
			memcpy(rbuffer, buffer, len);
Packit 549fdc
			rbuffer_size = len;
Packit 549fdc
		} else if (rbuffer_size != 0) {
Packit 549fdc
			send((int)(intptr_t) fd, rbuffer, rbuffer_size, 0);
Packit 549fdc
			if (len < sizeof(rbuffer) && len > rbuffer_size) {
Packit 549fdc
				memcpy(rbuffer, buffer, len);
Packit 549fdc
				rbuffer_size = len;
Packit 549fdc
			}
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
// }}}
Packit 549fdc
Packit 549fdc
// {{{ packet match functions
Packit 549fdc
Packit 549fdc
static int match_ServerHello(const unsigned char *buffer, size_t len)
Packit 549fdc
{
Packit 549fdc
	return role == SERVER && len >= 13 + 1 && buffer[0] == 22
Packit 549fdc
	    && buffer[13] == 2;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int match_ServerCertificate(const unsigned char *buffer, size_t len)
Packit 549fdc
{
Packit 549fdc
	return role == SERVER && len >= 13 + 1 && buffer[0] == 22
Packit 549fdc
	    && buffer[13] == 11;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int match_ServerKeyExchange(const unsigned char *buffer, size_t len)
Packit 549fdc
{
Packit 549fdc
	return role == SERVER && len >= 13 + 1 && buffer[0] == 22
Packit 549fdc
	    && buffer[13] == 12;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int match_ServerCertificateRequest(const unsigned char *buffer,
Packit 549fdc
					  size_t len)
Packit 549fdc
{
Packit 549fdc
	return role == SERVER && len >= 13 + 1 && buffer[0] == 22
Packit 549fdc
	    && buffer[13] == 13;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int match_ServerHelloDone(const unsigned char *buffer, size_t len)
Packit 549fdc
{
Packit 549fdc
	return role == SERVER && len >= 13 + 1 && buffer[0] == 22
Packit 549fdc
	    && buffer[13] == 14;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int match_ClientCertificate(const unsigned char *buffer, size_t len)
Packit 549fdc
{
Packit 549fdc
	return role == CLIENT && len >= 13 + 1 && buffer[0] == 22
Packit 549fdc
	    && buffer[13] == 11;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int match_ClientKeyExchange(const unsigned char *buffer, size_t len)
Packit 549fdc
{
Packit 549fdc
	return role == CLIENT && len >= 13 + 1 && buffer[0] == 22
Packit 549fdc
	    && buffer[13] == 16;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int match_ClientCertificateVerify(const unsigned char *buffer,
Packit 549fdc
					 size_t len)
Packit 549fdc
{
Packit 549fdc
	return role == CLIENT && len >= 13 + 1 && buffer[0] == 22
Packit 549fdc
	    && buffer[13] == 15;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int match_ClientChangeCipherSpec(const unsigned char *buffer, size_t len)
Packit 549fdc
{
Packit 549fdc
	return role == CLIENT && len >= 13 && buffer[0] == 20;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int match_ClientFinished(const unsigned char *buffer, size_t len)
Packit 549fdc
{
Packit 549fdc
	return role == CLIENT && len >= 13 && buffer[0] == 22 && buffer[4] == 1;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int match_ServerChangeCipherSpec(const unsigned char *buffer, size_t len)
Packit 549fdc
{
Packit 549fdc
	return role == SERVER && len >= 13 && buffer[0] == 20;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int match_ServerFinished(const unsigned char *buffer, size_t len)
Packit 549fdc
{
Packit 549fdc
	return role == SERVER && len >= 13 && buffer[0] == 22 && buffer[4] == 1;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
// }}}
Packit 549fdc
Packit 549fdc
// {{{ packet drop filters
Packit 549fdc
Packit 549fdc
#define FILTER_DROP_COUNT 3
Packit 549fdc
#define DECLARE_FILTER(packet) \
Packit 549fdc
	static void filter_packet_##packet(gnutls_transport_ptr_t fd, \
Packit 549fdc
			const unsigned char* buffer, size_t len) \
Packit 549fdc
	{ \
Packit 549fdc
		if (match_##packet(buffer, len) && (state_packet_##packet).count++ < FILTER_DROP_COUNT) { \
Packit 549fdc
			drop(#packet); \
Packit 549fdc
		} else { \
Packit 549fdc
			filter_run_next(fd, buffer, len); \
Packit 549fdc
		} \
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
DECLARE_FILTER(ServerHello)
Packit 549fdc
    DECLARE_FILTER(ServerCertificate)
Packit 549fdc
    DECLARE_FILTER(ServerKeyExchange)
Packit 549fdc
    DECLARE_FILTER(ServerCertificateRequest)
Packit 549fdc
    DECLARE_FILTER(ServerHelloDone)
Packit 549fdc
    DECLARE_FILTER(ClientCertificate)
Packit 549fdc
    DECLARE_FILTER(ClientKeyExchange)
Packit 549fdc
    DECLARE_FILTER(ClientCertificateVerify)
Packit 549fdc
    DECLARE_FILTER(ClientChangeCipherSpec)
Packit 549fdc
    DECLARE_FILTER(ClientFinished)
Packit 549fdc
    DECLARE_FILTER(ServerChangeCipherSpec)
Packit 549fdc
    DECLARE_FILTER(ServerFinished)
Packit 549fdc
// }}}
Packit 549fdc
// {{{ flight permutation filters
Packit 549fdc
static void filter_permute_state_run(filter_permute_state_t * state,
Packit 549fdc
				     int packetCount,
Packit 549fdc
				     gnutls_transport_ptr_t fd,
Packit 549fdc
				     const unsigned char *buffer, size_t len)
Packit 549fdc
{
Packit 549fdc
	unsigned char *data = malloc(len);
Packit 549fdc
	int packet = state->order[state->count];
Packit 549fdc
Packit 549fdc
	if (debug > 2)
Packit 549fdc
		log("running permutation for %s/%d/%d\n", state->name, packetCount, state->count);
Packit 549fdc
Packit 549fdc
	memcpy(data, buffer, len);
Packit 549fdc
	state->packets[packet].data = data;
Packit 549fdc
	state->packets[packet].size = len;
Packit 549fdc
	state->count++;
Packit 549fdc
Packit 549fdc
	if (state->count == packetCount) {
Packit 549fdc
		for (packet = 0; packet < packetCount; packet++) {
Packit 549fdc
			filter_run_next(fd, state->packets[packet].data,
Packit 549fdc
					state->packets[packet].size);
Packit 549fdc
		}
Packit 549fdc
		filter_permute_state_free_buffer(state);
Packit 549fdc
		state->count = 0;
Packit 549fdc
	}
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
#define DECLARE_PERMUTE(flight) \
Packit 549fdc
	static void filter_permute_##flight(gnutls_transport_ptr_t fd, \
Packit 549fdc
			const unsigned char* buffer, size_t len) \
Packit 549fdc
	{ \
Packit 549fdc
		int count = sizeof(permute_match_##flight) / sizeof(permute_match_##flight[0]); \
Packit 549fdc
		int i; \
Packit 549fdc
		for (i = 0; i < count; i++) { \
Packit 549fdc
			if (permute_match_##flight[i](buffer, len)) { \
Packit 549fdc
				filter_permute_state_run(&state_permute_##flight, count, fd, buffer, len); \
Packit 549fdc
				return; \
Packit 549fdc
			} \
Packit 549fdc
		} \
Packit 549fdc
		filter_run_next(fd, buffer, len); \
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
static match_fn permute_match_ServerHello[] =
Packit 549fdc
    { match_ServerHello, match_ServerKeyExchange, match_ServerHelloDone };
Packit 549fdc
Packit 549fdc
static match_fn permute_match_ServerHelloFull[] =
Packit 549fdc
    { match_ServerHello, match_ServerCertificate, match_ServerKeyExchange,
Packit 549fdc
	match_ServerCertificateRequest, match_ServerHelloDone
Packit 549fdc
};
Packit 549fdc
Packit 549fdc
static match_fn permute_match_ServerFinished[] =
Packit 549fdc
    { match_ServerChangeCipherSpec, match_ServerFinished };
Packit 549fdc
Packit 549fdc
static match_fn permute_match_ServerFinishedResume[] =
Packit 549fdc
    { match_ServerHello, match_ServerChangeCipherSpec, match_ServerFinished };
Packit 549fdc
Packit 549fdc
static match_fn permute_match_ClientFinished[] =
Packit 549fdc
    { match_ClientKeyExchange, match_ClientChangeCipherSpec,
Packit 549fdc
	match_ClientFinished
Packit 549fdc
};
Packit 549fdc
Packit 549fdc
static match_fn permute_match_ClientFinishedResume[] =
Packit 549fdc
    { match_ClientChangeCipherSpec, match_ClientFinished
Packit 549fdc
};
Packit 549fdc
Packit 549fdc
static match_fn permute_match_ClientFinishedFull[] =
Packit 549fdc
    { match_ClientCertificate, match_ClientKeyExchange,
Packit 549fdc
	match_ClientCertificateVerify, match_ClientChangeCipherSpec,
Packit 549fdc
	match_ClientFinished
Packit 549fdc
};
Packit 549fdc
Packit 549fdc
DECLARE_PERMUTE(ServerHello)
Packit 549fdc
    DECLARE_PERMUTE(ServerHelloFull)
Packit 549fdc
    DECLARE_PERMUTE(ServerFinishedResume)
Packit 549fdc
    DECLARE_PERMUTE(ServerFinished)
Packit 549fdc
    DECLARE_PERMUTE(ClientFinished)
Packit 549fdc
    DECLARE_PERMUTE(ClientFinishedResume)
Packit 549fdc
    DECLARE_PERMUTE(ClientFinishedFull)
Packit 549fdc
// }}}
Packit 549fdc
// {{{ emergency deadlock resolution time bomb
Packit 549fdc
timer_t killtimer_tid = 0;
Packit 549fdc
Packit 549fdc
static void killtimer_set(void)
Packit 549fdc
{
Packit 549fdc
	struct sigevent sig;
Packit 549fdc
	struct itimerspec tout = { {0, 0}, {2 * timeout_seconds, 0} };
Packit 549fdc
Packit 549fdc
	if (killtimer_tid != 0) {
Packit 549fdc
		timer_delete(killtimer_tid);
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	memset(&sig, 0, sizeof(sig));
Packit 549fdc
	sig.sigev_notify = SIGEV_SIGNAL;
Packit 549fdc
	sig.sigev_signo = 15;
Packit 549fdc
	if (timer_create(CLOCK_MONOTONIC, &sig, &killtimer_tid) < 0) {
Packit 549fdc
		rperror("timer_create");
Packit 549fdc
		exit(3);
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	timer_settime(killtimer_tid, 0, &tout, 0);
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
// }}}
Packit 549fdc
Packit 549fdc
// {{{ actual gnutls operations
Packit 549fdc
Packit 549fdc
gnutls_certificate_credentials_t cred;
Packit 549fdc
gnutls_session_t session;
Packit 549fdc
Packit 549fdc
static ssize_t writefn(gnutls_transport_ptr_t fd, const void *buffer,
Packit 549fdc
		       size_t len)
Packit 549fdc
{
Packit 549fdc
	filter_run_next(fd, (const unsigned char *)buffer, len);
Packit 549fdc
	return len;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static void await(int fd, int timeout)
Packit 549fdc
{
Packit 549fdc
	if (nonblock) {
Packit 549fdc
		struct pollfd p = { fd, POLLIN, 0 };
Packit 549fdc
		if (poll(&p, 1, timeout) < 0 && errno != EAGAIN
Packit 549fdc
		    && errno != EINTR) {
Packit 549fdc
			rperror("poll");
Packit 549fdc
			exit(3);
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static void cred_init(void)
Packit 549fdc
{
Packit 549fdc
	assert(gnutls_certificate_allocate_credentials(&cred)>=0);
Packit 549fdc
Packit 549fdc
	gnutls_certificate_set_x509_key_mem(cred, &cli_ca3_cert, &cli_ca3_key,
Packit 549fdc
					       GNUTLS_X509_FMT_PEM);
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static void session_init(int sock, int server)
Packit 549fdc
{
Packit 549fdc
	gnutls_init(&session,
Packit 549fdc
		    GNUTLS_DATAGRAM | (server ? GNUTLS_SERVER : GNUTLS_CLIENT)
Packit 549fdc
		    | GNUTLS_NONBLOCK * nonblock);
Packit 549fdc
	gnutls_priority_set_direct(session,
Packit 549fdc
				   "NORMAL:+ECDHE-RSA:+ANON-ECDH",
Packit 549fdc
				   0);
Packit 549fdc
	gnutls_transport_set_int(session, sock);
Packit 549fdc
Packit 549fdc
	if (full) {
Packit 549fdc
		gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred);
Packit 549fdc
		if (server) {
Packit 549fdc
			gnutls_certificate_server_set_request(session,
Packit 549fdc
							      GNUTLS_CERT_REQUIRE);
Packit 549fdc
		}
Packit 549fdc
	} else if (server) {
Packit 549fdc
		gnutls_anon_server_credentials_t acred;
Packit 549fdc
		assert(gnutls_anon_allocate_server_credentials(&acred)>=0);
Packit 549fdc
		gnutls_credentials_set(session, GNUTLS_CRD_ANON, acred);
Packit 549fdc
	} else {
Packit 549fdc
		gnutls_anon_client_credentials_t acred;
Packit 549fdc
		assert(gnutls_anon_allocate_client_credentials(&acred)>=0);
Packit 549fdc
		gnutls_credentials_set(session, GNUTLS_CRD_ANON, acred);
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	gnutls_dtls_set_mtu(session, 1400);
Packit 549fdc
	gnutls_dtls_set_timeouts(session, retransmit_milliseconds,
Packit 549fdc
				 timeout_seconds * 1000);
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static void client(int sock)
Packit 549fdc
{
Packit 549fdc
	int err = 0;
Packit 549fdc
	time_t started = time(0);
Packit 549fdc
	const char *line = "foobar!";
Packit 549fdc
	char buffer[8192];
Packit 549fdc
	int len, ret;
Packit 549fdc
	gnutls_datum_t data = {NULL, 0};
Packit 549fdc
Packit 549fdc
	session_init(sock, 0);
Packit 549fdc
Packit 549fdc
	killtimer_set();
Packit 549fdc
Packit 549fdc
	if (resume) {
Packit 549fdc
		do {
Packit 549fdc
			err = process_error(gnutls_handshake(session));
Packit 549fdc
			if (err != 0) {
Packit 549fdc
				int t = gnutls_dtls_get_timeout(session);
Packit 549fdc
				await(sock, t ? t : 100);
Packit 549fdc
			}
Packit 549fdc
		} while (err != 0);
Packit 549fdc
		process_error_or_timeout(err, time(0) - started);
Packit 549fdc
Packit 549fdc
		ret = gnutls_session_get_data2(session, &data);
Packit 549fdc
		if (ret < 0) {
Packit 549fdc
			exit(1);
Packit 549fdc
		}
Packit 549fdc
		gnutls_deinit(session);
Packit 549fdc
Packit 549fdc
		session_init(sock, 0);
Packit 549fdc
		gnutls_session_set_data(session, data.data, data.size);
Packit 549fdc
		gnutls_free(data.data);
Packit 549fdc
		data.data = NULL;
Packit 549fdc
Packit 549fdc
		if (debug) {
Packit 549fdc
			fprintf(stdout, "%i %s| initial handshake complete\n", run_id, role_name);
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	gnutls_transport_set_push_function(session, writefn);
Packit 549fdc
Packit 549fdc
	killtimer_set();
Packit 549fdc
	do {
Packit 549fdc
		err = process_error(gnutls_handshake(session));
Packit 549fdc
		if (err != 0) {
Packit 549fdc
			int t = gnutls_dtls_get_timeout(session);
Packit 549fdc
			await(sock, t ? t : 100);
Packit 549fdc
		}
Packit 549fdc
	} while (err != 0);
Packit 549fdc
	process_error_or_timeout(err, time(0) - started);
Packit 549fdc
Packit 549fdc
	if (debug) {
Packit 549fdc
		fprintf(stdout, "%i %s| handshake complete\n", run_id, role_name);
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (resume) {
Packit 549fdc
		killtimer_set();
Packit 549fdc
Packit 549fdc
		do {
Packit 549fdc
			await(sock, -1);
Packit 549fdc
			len =
Packit 549fdc
			    process_error(gnutls_record_recv
Packit 549fdc
					  (session, buffer, sizeof(buffer)));
Packit 549fdc
		} while (len < 0);
Packit 549fdc
Packit 549fdc
		log("received data\n");
Packit 549fdc
Packit 549fdc
		die_on_error(gnutls_record_send(session, buffer, len));
Packit 549fdc
Packit 549fdc
		log("sent data\n");
Packit 549fdc
		exit(0);
Packit 549fdc
Packit 549fdc
	} else {
Packit 549fdc
		killtimer_set();
Packit 549fdc
		die_on_error(gnutls_record_send(session, line, strlen(line)));
Packit 549fdc
Packit 549fdc
		log("sent data\n");
Packit 549fdc
Packit 549fdc
		do {
Packit 549fdc
			await(sock, -1);
Packit 549fdc
			len =
Packit 549fdc
			    process_error(gnutls_record_recv
Packit 549fdc
				  (session, buffer, sizeof(buffer)));
Packit 549fdc
		} while (len < 0);
Packit 549fdc
Packit 549fdc
		log("received data\n");
Packit 549fdc
Packit 549fdc
		if (len > 0 && strncmp(line, buffer, len) == 0) {
Packit 549fdc
			exit(0);
Packit 549fdc
		} else {
Packit 549fdc
			exit(1);
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static gnutls_datum_t saved_data = {NULL, 0};
Packit 549fdc
Packit 549fdc
static gnutls_datum_t db_fetch(void *dbf, gnutls_datum_t key)
Packit 549fdc
{
Packit 549fdc
	gnutls_datum_t t = {NULL, 0};
Packit 549fdc
	t.data = malloc(saved_data.size);
Packit 549fdc
	if (t.data == NULL)
Packit 549fdc
		return t;
Packit 549fdc
	memcpy(t.data, saved_data.data, saved_data.size);
Packit 549fdc
	t.size = saved_data.size;
Packit 549fdc
Packit 549fdc
	return t;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int db_delete(void *dbf, gnutls_datum_t key)
Packit 549fdc
{
Packit 549fdc
	return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int db_store(void *dbf, gnutls_datum_t key, gnutls_datum_t data)
Packit 549fdc
{
Packit 549fdc
	saved_data.data = malloc(data.size);
Packit 549fdc
	if (saved_data.data == NULL)
Packit 549fdc
		return -1;
Packit 549fdc
	memcpy(saved_data.data, data.data, data.size);
Packit 549fdc
	saved_data.size = data.size;
Packit 549fdc
	return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static void server(int sock)
Packit 549fdc
{
Packit 549fdc
	int err;
Packit 549fdc
	const char *line = "server foobar!";
Packit 549fdc
	time_t started = time(0);
Packit 549fdc
	char buffer[8192];
Packit 549fdc
	int len;
Packit 549fdc
Packit 549fdc
	session_init(sock, 1);
Packit 549fdc
Packit 549fdc
	await(sock, -1);
Packit 549fdc
Packit 549fdc
	killtimer_set();
Packit 549fdc
	if (resume) {
Packit 549fdc
		gnutls_db_set_retrieve_function(session, db_fetch);
Packit 549fdc
		gnutls_db_set_store_function(session, db_store);
Packit 549fdc
		gnutls_db_set_remove_function(session, db_delete);
Packit 549fdc
		gnutls_db_set_ptr(session, NULL);
Packit 549fdc
Packit 549fdc
		do {
Packit 549fdc
			err = process_error(gnutls_handshake(session));
Packit 549fdc
			if (err != 0) {
Packit 549fdc
				int t = gnutls_dtls_get_timeout(session);
Packit 549fdc
				await(sock, t ? t : 100);
Packit 549fdc
			}
Packit 549fdc
		} while (err != 0);
Packit 549fdc
		process_error_or_timeout(err, time(0) - started);
Packit 549fdc
Packit 549fdc
		gnutls_deinit(session);
Packit 549fdc
Packit 549fdc
		session_init(sock, 1);
Packit 549fdc
		gnutls_db_set_retrieve_function(session, db_fetch);
Packit 549fdc
		gnutls_db_set_store_function(session, db_store);
Packit 549fdc
		gnutls_db_set_remove_function(session, db_delete);
Packit 549fdc
		gnutls_db_set_ptr(session, NULL);
Packit 549fdc
Packit 549fdc
		if (debug) {
Packit 549fdc
			fprintf(stdout, "%i %s| initial handshake complete\n", run_id, role_name);
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	gnutls_transport_set_push_function(session, writefn);
Packit 549fdc
Packit 549fdc
	await(sock, -1);
Packit 549fdc
Packit 549fdc
	killtimer_set();
Packit 549fdc
	do {
Packit 549fdc
		err = process_error(gnutls_handshake(session));
Packit 549fdc
		if (err != 0) {
Packit 549fdc
			int t = gnutls_dtls_get_timeout(session);
Packit 549fdc
			await(sock, t ? t : 100);
Packit 549fdc
		}
Packit 549fdc
	} while (err != 0);
Packit 549fdc
	process_error_or_timeout(err, time(0) - started);
Packit 549fdc
Packit 549fdc
	log("handshake complete\n");
Packit 549fdc
Packit 549fdc
	if (resume) {
Packit 549fdc
		free(saved_data.data);
Packit 549fdc
		saved_data.data = NULL;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (resume) {
Packit 549fdc
		killtimer_set();
Packit 549fdc
		die_on_error(gnutls_record_send(session, line, strlen(line)));
Packit 549fdc
Packit 549fdc
		log("sent data\n");
Packit 549fdc
Packit 549fdc
		do {
Packit 549fdc
			await(sock, -1);
Packit 549fdc
			len =
Packit 549fdc
			    process_error(gnutls_record_recv
Packit 549fdc
				  (session, buffer, sizeof(buffer)));
Packit 549fdc
		} while (len < 0);
Packit 549fdc
Packit 549fdc
		log("received data\n");
Packit 549fdc
Packit 549fdc
		if (len > 0 && strncmp(line, buffer, len) == 0) {
Packit 549fdc
			exit(0);
Packit 549fdc
		} else {
Packit 549fdc
			exit(1);
Packit 549fdc
		}
Packit 549fdc
	} else {
Packit 549fdc
		killtimer_set();
Packit 549fdc
Packit 549fdc
		do {
Packit 549fdc
			await(sock, -1);
Packit 549fdc
			len =
Packit 549fdc
			    process_error(gnutls_record_recv
Packit 549fdc
					  (session, buffer, sizeof(buffer)));
Packit 549fdc
		} while (len < 0);
Packit 549fdc
Packit 549fdc
		log("received data\n");
Packit 549fdc
Packit 549fdc
		die_on_error(gnutls_record_send(session, buffer, len));
Packit 549fdc
Packit 549fdc
		log("sent data\n");
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	exit(0);
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
// }}}
Packit 549fdc
Packit 549fdc
// {{{ test running/handling itself
Packit 549fdc
Packit 549fdc
#if 0
Packit 549fdc
static void udp_sockpair(int *socks)
Packit 549fdc
{
Packit 549fdc
	struct sockaddr_in6 sa =
Packit 549fdc
	    { AF_INET6, htons(30000), 0, in6addr_loopback, 0 };
Packit 549fdc
	struct sockaddr_in6 sb =
Packit 549fdc
	    { AF_INET6, htons(20000), 0, in6addr_loopback, 0 };
Packit 549fdc
Packit 549fdc
	socks[0] = socket(AF_INET6, SOCK_DGRAM, 0);
Packit 549fdc
	socks[1] = socket(AF_INET6, SOCK_DGRAM, 0);
Packit 549fdc
Packit 549fdc
	bind(socks[0], (struct sockaddr *)&sa, sizeof(sa));
Packit 549fdc
	bind(socks[1], (struct sockaddr *)&sb, sizeof(sb));
Packit 549fdc
Packit 549fdc
	connect(socks[1], (struct sockaddr *)&sa, sizeof(sa));
Packit 549fdc
	connect(socks[0], (struct sockaddr *)&sb, sizeof(sb));
Packit 549fdc
}
Packit 549fdc
#endif
Packit 549fdc
Packit 549fdc
static int run_test(void)
Packit 549fdc
{
Packit 549fdc
	int fds[2];
Packit 549fdc
	int pid1, pid2;
Packit 549fdc
	int status2;
Packit 549fdc
Packit 549fdc
	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) < 0) {
Packit 549fdc
		rperror("socketpair");
Packit 549fdc
		exit(2);
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (nonblock) {
Packit 549fdc
		fcntl(fds[0], F_SETFL, (long)O_NONBLOCK);
Packit 549fdc
		fcntl(fds[1], F_SETFL, (long)O_NONBLOCK);
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (!(pid1 = fork())) {
Packit 549fdc
		role = SERVER;
Packit 549fdc
		server(fds[1]);	// noreturn
Packit 549fdc
	} else if (pid1 < 0) {
Packit 549fdc
		rperror("fork server");
Packit 549fdc
		exit(2);
Packit 549fdc
	}
Packit 549fdc
	if (!(pid2 = fork())) {
Packit 549fdc
		role = CLIENT;
Packit 549fdc
		client(fds[0]);	// noreturn
Packit 549fdc
	} else if (pid2 < 0) {
Packit 549fdc
		rperror("fork client");
Packit 549fdc
		exit(2);
Packit 549fdc
	}
Packit 549fdc
	while (waitpid(pid2, &status2, 0) < 0 && errno == EINTR) ;
Packit 549fdc
	kill(pid1, 15);
Packit 549fdc
	while (waitpid(pid1, 0, 0) < 0 && errno == EINTR) ;
Packit 549fdc
Packit 549fdc
	close(fds[0]);
Packit 549fdc
	close(fds[1]);
Packit 549fdc
Packit 549fdc
	if (!WIFSIGNALED(status2) && WEXITSTATUS(status2) != 3) {
Packit 549fdc
		return ! !WEXITSTATUS(status2);
Packit 549fdc
	} else {
Packit 549fdc
		return 3;
Packit 549fdc
	}
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static filter_fn filters[]
Packit 549fdc
    = { filter_packet_ServerHello,
Packit 549fdc
	filter_packet_ServerKeyExchange,
Packit 549fdc
	filter_packet_ServerHelloDone,
Packit 549fdc
	filter_packet_ClientKeyExchange,
Packit 549fdc
	filter_packet_ClientChangeCipherSpec,
Packit 549fdc
	filter_packet_ClientFinished,
Packit 549fdc
	filter_packet_ServerChangeCipherSpec,
Packit 549fdc
	filter_packet_ServerFinished
Packit 549fdc
};
Packit 549fdc
Packit 549fdc
static filter_fn filters_resume[]
Packit 549fdc
    = { filter_packet_ServerHello,
Packit 549fdc
	filter_packet_ServerChangeCipherSpec,
Packit 549fdc
	filter_packet_ServerFinished,
Packit 549fdc
	filter_packet_ClientChangeCipherSpec,
Packit 549fdc
	filter_packet_ClientFinished
Packit 549fdc
};
Packit 549fdc
Packit 549fdc
static filter_fn filters_full[]
Packit 549fdc
    = { filter_packet_ServerHello,
Packit 549fdc
	filter_packet_ServerCertificate,
Packit 549fdc
	filter_packet_ServerKeyExchange,
Packit 549fdc
	filter_packet_ServerCertificateRequest,
Packit 549fdc
	filter_packet_ServerHelloDone,
Packit 549fdc
	filter_packet_ClientCertificate,
Packit 549fdc
	filter_packet_ClientKeyExchange,
Packit 549fdc
	filter_packet_ClientCertificateVerify,
Packit 549fdc
	filter_packet_ClientChangeCipherSpec,
Packit 549fdc
	filter_packet_ClientFinished,
Packit 549fdc
	filter_packet_ServerChangeCipherSpec,
Packit 549fdc
	filter_packet_ServerFinished
Packit 549fdc
};
Packit 549fdc
Packit 549fdc
static int run_one_test(int dropMode, int serverFinishedPermute,
Packit 549fdc
			int serverHelloPermute, int clientFinishedPermute)
Packit 549fdc
{
Packit 549fdc
	int fnIdx = 0;
Packit 549fdc
	int res, filterIdx;
Packit 549fdc
	filter_fn *local_filters;
Packit 549fdc
	const char **local_filter_names;
Packit 549fdc
	const char **client_finished_permutation_names;
Packit 549fdc
	const char **server_finished_permutation_names;
Packit 549fdc
	const char **server_hello_permutation_names;
Packit 549fdc
	int filter_count;
Packit 549fdc
Packit 549fdc
	if (full) {
Packit 549fdc
		local_filters = filters_full;
Packit 549fdc
		local_filter_names = filter_names_full;
Packit 549fdc
		filter_count = sizeof(filters_full)/sizeof(filters_full[0]);
Packit 549fdc
		client_finished_permutation_names = permutation_names5;
Packit 549fdc
		server_finished_permutation_names = permutation_names2;
Packit 549fdc
		server_hello_permutation_names = permutation_names5;
Packit 549fdc
	} else if (resume) {
Packit 549fdc
		local_filters = filters_resume;
Packit 549fdc
		local_filter_names = filter_names_resume;
Packit 549fdc
		filter_count = sizeof(filters_resume)/sizeof(filters_resume[0]);
Packit 549fdc
		client_finished_permutation_names = permutation_names2;
Packit 549fdc
		server_finished_permutation_names = permutation_names3;
Packit 549fdc
		server_hello_permutation_names = NULL;
Packit 549fdc
	} else {
Packit 549fdc
		local_filters = filters;
Packit 549fdc
		local_filter_names = filter_names;
Packit 549fdc
		filter_count = sizeof(filters)/sizeof(filters[0]);
Packit 549fdc
		client_finished_permutation_names = permutation_names3;
Packit 549fdc
		server_finished_permutation_names = permutation_names2;
Packit 549fdc
		server_hello_permutation_names = permutation_names3;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	run_id =
Packit 549fdc
	    ((dropMode * 2 + serverFinishedPermute) * (full ? 120 : 6) +
Packit 549fdc
	     serverHelloPermute) * (full ? 120 : 6) + clientFinishedPermute;
Packit 549fdc
Packit 549fdc
	filter_clear_state();
Packit 549fdc
Packit 549fdc
	if (full) {
Packit 549fdc
		filter_chain[fnIdx++] = filter_permute_ServerHelloFull;
Packit 549fdc
		state_permute_ServerHelloFull.order =
Packit 549fdc
		    permutations5[serverHelloPermute];
Packit 549fdc
Packit 549fdc
		filter_chain[fnIdx++] = filter_permute_ClientFinishedFull;
Packit 549fdc
		state_permute_ClientFinishedFull.order =
Packit 549fdc
		    permutations5[clientFinishedPermute];
Packit 549fdc
Packit 549fdc
		filter_chain[fnIdx++] = filter_permute_ServerFinished;
Packit 549fdc
		state_permute_ServerFinished.order =
Packit 549fdc
		    permutations2[serverFinishedPermute];
Packit 549fdc
	} else if (resume) {
Packit 549fdc
		filter_chain[fnIdx++] = filter_permute_ServerFinishedResume;
Packit 549fdc
		state_permute_ServerFinishedResume.order =
Packit 549fdc
		    permutations3[serverFinishedPermute];
Packit 549fdc
Packit 549fdc
		filter_chain[fnIdx++] = filter_permute_ClientFinishedResume;
Packit 549fdc
		state_permute_ClientFinishedResume.order =
Packit 549fdc
		    permutations2[clientFinishedPermute];
Packit 549fdc
	} else {
Packit 549fdc
		filter_chain[fnIdx++] = filter_permute_ServerHello;
Packit 549fdc
		state_permute_ServerHello.order =
Packit 549fdc
		    permutations3[serverHelloPermute];
Packit 549fdc
Packit 549fdc
		filter_chain[fnIdx++] = filter_permute_ClientFinished;
Packit 549fdc
		state_permute_ClientFinished.order =
Packit 549fdc
		    permutations3[clientFinishedPermute];
Packit 549fdc
Packit 549fdc
		filter_chain[fnIdx++] = filter_permute_ServerFinished;
Packit 549fdc
		state_permute_ServerFinished.order =
Packit 549fdc
		    permutations2[serverFinishedPermute];
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (dropMode) {
Packit 549fdc
		for (filterIdx = 0; filterIdx < filter_count; filterIdx++) {
Packit 549fdc
			if (dropMode & (1 << filterIdx)) {
Packit 549fdc
				filter_chain[fnIdx++] =
Packit 549fdc
				    local_filters[filterIdx];
Packit 549fdc
			}
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
	filter_chain[fnIdx++] = NULL;
Packit 549fdc
Packit 549fdc
	res = run_test();
Packit 549fdc
Packit 549fdc
	switch (res) {
Packit 549fdc
	case 0:
Packit 549fdc
		fprintf(stdout, "%i ++ ", run_id);
Packit 549fdc
		break;
Packit 549fdc
	case 1:
Packit 549fdc
		fprintf(stdout, "%i -- ", run_id);
Packit 549fdc
		break;
Packit 549fdc
	case 2:
Packit 549fdc
		fprintf(stdout, "%i !! ", run_id);
Packit 549fdc
		break;
Packit 549fdc
	case 3:
Packit 549fdc
		fprintf(stdout, "%i TT ", run_id);
Packit 549fdc
		break;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (!resume)
Packit 549fdc
		fprintf(stdout, "SHello(%s), ", server_hello_permutation_names[serverHelloPermute]);
Packit 549fdc
	fprintf(stdout, "SFinished(%s), ",
Packit 549fdc
		server_finished_permutation_names[serverFinishedPermute]);
Packit 549fdc
	fprintf(stdout, "CFinished(%s) :- ",
Packit 549fdc
		client_finished_permutation_names[clientFinishedPermute]);
Packit 549fdc
	if (dropMode) {
Packit 549fdc
		for (filterIdx = 0; filterIdx < filter_count; filterIdx++) {
Packit 549fdc
			if (dropMode & (1 << filterIdx)) {
Packit 549fdc
				if (dropMode & ((1 << filterIdx) - 1)) {
Packit 549fdc
					fprintf(stdout, ", ");
Packit 549fdc
				}
Packit 549fdc
				fprintf(stdout, "%s",
Packit 549fdc
					local_filter_names[filterIdx]);
Packit 549fdc
			}
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
	fprintf(stdout, "\n");
Packit 549fdc
Packit 549fdc
	return res;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int run_test_by_id(int id)
Packit 549fdc
{
Packit 549fdc
	int pscale = full ? 120 : 6;
Packit 549fdc
	int dropMode, serverFinishedPermute, serverHelloPermute,
Packit 549fdc
	    clientFinishedPermute;
Packit 549fdc
Packit 549fdc
	clientFinishedPermute = id % pscale;
Packit 549fdc
	id /= pscale;
Packit 549fdc
Packit 549fdc
	serverHelloPermute = id % pscale;
Packit 549fdc
	id /= pscale;
Packit 549fdc
Packit 549fdc
	serverFinishedPermute = id % 2;
Packit 549fdc
	id /= 2;
Packit 549fdc
Packit 549fdc
	dropMode = id;
Packit 549fdc
Packit 549fdc
	return run_one_test(dropMode, serverFinishedPermute,
Packit 549fdc
			    serverHelloPermute, clientFinishedPermute);
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
int *job_pids;
Packit 549fdc
int job_limit;
Packit 549fdc
int children = 0;
Packit 549fdc
Packit 549fdc
static void register_child(int pid)
Packit 549fdc
{
Packit 549fdc
	int idx;
Packit 549fdc
Packit 549fdc
	children++;
Packit 549fdc
	for (idx = 0; idx < job_limit; idx++) {
Packit 549fdc
		if (job_pids[idx] == 0) {
Packit 549fdc
			job_pids[idx] = pid;
Packit 549fdc
			return;
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int wait_children(int child_limit)
Packit 549fdc
{
Packit 549fdc
	int fail = 0;
Packit 549fdc
	int result = 1;
Packit 549fdc
Packit 549fdc
	while (children > child_limit) {
Packit 549fdc
		int status;
Packit 549fdc
		int idx;
Packit 549fdc
		int pid = waitpid(0, &status, 0);
Packit 549fdc
		if (pid < 0 && errno == ECHILD) {
Packit 549fdc
			break;
Packit 549fdc
		}
Packit 549fdc
		for (idx = 0; idx < job_limit; idx++) {
Packit 549fdc
			if (job_pids[idx] == pid) {
Packit 549fdc
				children--;
Packit 549fdc
				if (WEXITSTATUS(status)) {
Packit 549fdc
					result = 1;
Packit 549fdc
					if (!run_to_end && !fail) {
Packit 549fdc
						fprintf(stderr,
Packit 549fdc
							"One test failed, waiting for remaining tests\n");
Packit 549fdc
						fail = 1;
Packit 549fdc
						child_limit = 0;
Packit 549fdc
					}
Packit 549fdc
				}
Packit 549fdc
				job_pids[idx] = 0;
Packit 549fdc
				break;
Packit 549fdc
			}
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (fail) {
Packit 549fdc
		exit(1);
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	return result;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int run_tests_from_id_list(int childcount)
Packit 549fdc
{
Packit 549fdc
	int test_id;
Packit 549fdc
	int ret;
Packit 549fdc
	int result = 0;
Packit 549fdc
Packit 549fdc
	while ((ret = fscanf(stdin, "%i\n", &test_id)) > 0) {
Packit 549fdc
		int pid;
Packit 549fdc
		if (test_id < 0
Packit 549fdc
		    || test_id >
Packit 549fdc
		    2 * (full ? 120 * 120 * (1 << 12) : 6 * 6 * 256)) {
Packit 549fdc
			fprintf(stderr, "Invalid test id %i\n", test_id);
Packit 549fdc
			break;
Packit 549fdc
		}
Packit 549fdc
		if (!(pid = fork())) {
Packit 549fdc
			exit(run_test_by_id(test_id));
Packit 549fdc
		} else if (pid < 0) {
Packit 549fdc
			rperror("fork");
Packit 549fdc
			result = 4;
Packit 549fdc
			break;
Packit 549fdc
		} else {
Packit 549fdc
			register_child(pid);
Packit 549fdc
			result |= wait_children(childcount);
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (ret < 0 && ret != EOF) {
Packit 549fdc
		fprintf(stderr, "Error reading test id list\n");
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	result |= wait_children(0);
Packit 549fdc
Packit 549fdc
	return result;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static int run_all_tests(int childcount)
Packit 549fdc
{
Packit 549fdc
	int dropMode, serverFinishedPermute, serverHelloPermute,
Packit 549fdc
	    clientFinishedPermute;
Packit 549fdc
	int result = 0;
Packit 549fdc
Packit 549fdc
	for (dropMode = 0; dropMode != 1 << (full ? 12 : 8); dropMode++)
Packit 549fdc
		for (serverFinishedPermute = 0; serverFinishedPermute < 2;
Packit 549fdc
		     serverFinishedPermute++)
Packit 549fdc
			for (serverHelloPermute = 0;
Packit 549fdc
			     serverHelloPermute < (full ? 120 : 6);
Packit 549fdc
			     serverHelloPermute++)
Packit 549fdc
				for (clientFinishedPermute = 0;
Packit 549fdc
				     clientFinishedPermute <
Packit 549fdc
				     (full ? 120 : 6);
Packit 549fdc
				     clientFinishedPermute++) {
Packit 549fdc
					int pid;
Packit 549fdc
					if (!(pid = fork())) {
Packit 549fdc
						exit(run_one_test
Packit 549fdc
						     (dropMode,
Packit 549fdc
						      serverFinishedPermute,
Packit 549fdc
						      serverHelloPermute,
Packit 549fdc
						      clientFinishedPermute));
Packit 549fdc
					} else if (pid < 0) {
Packit 549fdc
						rperror("fork");
Packit 549fdc
						result = 4;
Packit 549fdc
						break;
Packit 549fdc
					} else {
Packit 549fdc
						register_child(pid);
Packit 549fdc
						result |=
Packit 549fdc
						    wait_children(childcount);
Packit 549fdc
					}
Packit 549fdc
				}
Packit 549fdc
Packit 549fdc
	result |= wait_children(0);
Packit 549fdc
Packit 549fdc
	return result;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
// }}}
Packit 549fdc
Packit 549fdc
static int parse_permutation(const char *arg, const char *permutations[],
Packit 549fdc
			     int *val)
Packit 549fdc
{
Packit 549fdc
	*val = 0;
Packit 549fdc
	while (permutations[*val]) {
Packit 549fdc
		if (strcmp(permutations[*val], arg) == 0) {
Packit 549fdc
			return 1;
Packit 549fdc
		} else {
Packit 549fdc
			*val += 1;
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
	return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
int main(int argc, const char *argv[])
Packit 549fdc
{
Packit 549fdc
	int dropMode = 0;
Packit 549fdc
	int serverFinishedPermute = 0;
Packit 549fdc
	int serverHelloPermute = 0;
Packit 549fdc
	int clientFinishedPermute = 0;
Packit 549fdc
	int batch = 0;
Packit 549fdc
	unsigned single = 0;
Packit 549fdc
	int arg;
Packit 549fdc
Packit 549fdc
	nonblock = 0;
Packit 549fdc
	replay = 0;
Packit 549fdc
	debug = 0;
Packit 549fdc
	timeout_seconds = 120;
Packit 549fdc
	retransmit_milliseconds = 100;
Packit 549fdc
	full = 0;
Packit 549fdc
	run_to_end = 1;
Packit 549fdc
	job_limit = 1;
Packit 549fdc
Packit 549fdc
#define NEXT_ARG(name) \
Packit 549fdc
	do { \
Packit 549fdc
		if (++arg >= argc) { \
Packit 549fdc
			fprintf(stderr, "No argument for -" #name "\n"); \
Packit 549fdc
			exit(8); \
Packit 549fdc
		} \
Packit 549fdc
	} while (0);
Packit 549fdc
#define FAIL_ARG(name) \
Packit 549fdc
	do { \
Packit 549fdc
		fprintf(stderr, "Invalid argument for -" #name "\n"); \
Packit 549fdc
		exit(8); \
Packit 549fdc
	} while (0);
Packit 549fdc
Packit 549fdc
	for (arg = 1; arg < argc; arg++) {
Packit 549fdc
		if (strcmp("-die", argv[arg]) == 0) {
Packit 549fdc
			run_to_end = 0;
Packit 549fdc
		} else if (strcmp("-batch", argv[arg]) == 0) {
Packit 549fdc
			batch = 1;
Packit 549fdc
		} else if (strcmp("-d", argv[arg]) == 0) {
Packit 549fdc
			char *end;
Packit 549fdc
			int level;
Packit 549fdc
Packit 549fdc
			if (arg+1 < argc) {
Packit 549fdc
				level = strtol(argv[arg + 1], &end, 10);
Packit 549fdc
				if (*end == '\0') {
Packit 549fdc
					debug = level;
Packit 549fdc
					arg++;
Packit 549fdc
				} else
Packit 549fdc
					debug++;
Packit 549fdc
			} else {
Packit 549fdc
				debug++;
Packit 549fdc
			}
Packit 549fdc
		} else if (strcmp("-nb", argv[arg]) == 0) {
Packit 549fdc
			nonblock = 1;
Packit 549fdc
		} else if (strcmp("-r", argv[arg]) == 0) {
Packit 549fdc
			replay = 1;
Packit 549fdc
		} else if (strcmp("-timeout", argv[arg]) == 0) {
Packit 549fdc
			char *end;
Packit 549fdc
			int val;
Packit 549fdc
Packit 549fdc
			NEXT_ARG(timeout);
Packit 549fdc
			val = strtol(argv[arg], &end, 10);
Packit 549fdc
			if (*end == '\0') {
Packit 549fdc
				timeout_seconds = val;
Packit 549fdc
			} else {
Packit 549fdc
				FAIL_ARG(timeout);
Packit 549fdc
			}
Packit 549fdc
		} else if (strcmp("-retransmit", argv[arg]) == 0) {
Packit 549fdc
			char *end;
Packit 549fdc
			int val;
Packit 549fdc
Packit 549fdc
			NEXT_ARG(retransmit);
Packit 549fdc
			val = strtol(argv[arg], &end, 10);
Packit 549fdc
			if (*end == '\0') {
Packit 549fdc
				retransmit_milliseconds = val;
Packit 549fdc
			} else {
Packit 549fdc
				FAIL_ARG(retransmit);
Packit 549fdc
			}
Packit 549fdc
		} else if (strcmp("-j", argv[arg]) == 0) {
Packit 549fdc
			char *end;
Packit 549fdc
			int val;
Packit 549fdc
Packit 549fdc
			NEXT_ARG(timeout);
Packit 549fdc
			val = strtol(argv[arg], &end, 10);
Packit 549fdc
			if (*end == '\0') {
Packit 549fdc
				job_limit = val;
Packit 549fdc
			} else {
Packit 549fdc
				FAIL_ARG(j);
Packit 549fdc
			}
Packit 549fdc
		} else if (strcmp("-full", argv[arg]) == 0) {
Packit 549fdc
			if (resume) {
Packit 549fdc
				fprintf(stderr, "You cannot combine full with resume\n");
Packit 549fdc
				exit(1);
Packit 549fdc
			}
Packit 549fdc
Packit 549fdc
			full = 1;
Packit 549fdc
		} else if (strcmp("-resume", argv[arg]) == 0) {
Packit 549fdc
			if (full) {
Packit 549fdc
				fprintf(stderr, "You cannot combine full with resume\n");
Packit 549fdc
				exit(1);
Packit 549fdc
			}
Packit 549fdc
Packit 549fdc
			resume = 1;
Packit 549fdc
		} else if (strcmp("-shello", argv[arg]) == 0) {
Packit 549fdc
			if (resume) {
Packit 549fdc
				fprintf(stderr, "Please use -sfinished instead of -shello\n");
Packit 549fdc
				exit(1);
Packit 549fdc
			}
Packit 549fdc
Packit 549fdc
			NEXT_ARG(shello);
Packit 549fdc
			if (!parse_permutation
Packit 549fdc
			    (argv[arg],
Packit 549fdc
			     full ? permutation_names5 :
Packit 549fdc
			     permutation_names3, &serverHelloPermute)) {
Packit 549fdc
				FAIL_ARG(shell);
Packit 549fdc
			}
Packit 549fdc
			single++;
Packit 549fdc
		} else if (strcmp("-sfinished", argv[arg]) == 0) {
Packit 549fdc
			const char **pname;
Packit 549fdc
			NEXT_ARG(cfinished);
Packit 549fdc
			if (resume) pname = permutation_names3;
Packit 549fdc
			else pname = permutation_names2;
Packit 549fdc
			if (!parse_permutation
Packit 549fdc
			    (argv[arg], pname,
Packit 549fdc
			     &serverFinishedPermute)) {
Packit 549fdc
				FAIL_ARG(cfinished);
Packit 549fdc
			}
Packit 549fdc
			single++;
Packit 549fdc
		} else if (strcmp("-cfinished", argv[arg]) == 0) {
Packit 549fdc
			const char **pname;
Packit 549fdc
			NEXT_ARG(cfinished);
Packit 549fdc
			if (full) pname = permutation_names5;
Packit 549fdc
			else if (resume) pname = permutation_names2;
Packit 549fdc
			else pname = permutation_names3;
Packit 549fdc
			if (!parse_permutation
Packit 549fdc
			    (argv[arg], pname,
Packit 549fdc
			     &clientFinishedPermute)) {
Packit 549fdc
				FAIL_ARG(cfinished);
Packit 549fdc
			}
Packit 549fdc
			single++;
Packit 549fdc
		} else {
Packit 549fdc
			int drop;
Packit 549fdc
			int filter_count;
Packit 549fdc
			const char **local_filter_names;
Packit 549fdc
Packit 549fdc
			if (full) {
Packit 549fdc
				local_filter_names = filter_names_full;
Packit 549fdc
				filter_count = sizeof(filters_full)/sizeof(filters_full[0]);
Packit 549fdc
			} else if (resume) {
Packit 549fdc
				local_filter_names = filter_names_resume;
Packit 549fdc
				filter_count = sizeof(filters_resume)/sizeof(filters_resume[0]);
Packit 549fdc
			} else {
Packit 549fdc
				local_filter_names = filter_names;
Packit 549fdc
				filter_count = sizeof(filters)/sizeof(filters[0]);
Packit 549fdc
			}
Packit 549fdc
Packit 549fdc
			for (drop = 0; drop < filter_count; drop++) {
Packit 549fdc
				if (strcmp
Packit 549fdc
				    (local_filter_names[drop],
Packit 549fdc
				     argv[arg]) == 0) {
Packit 549fdc
					dropMode |= (1 << drop);
Packit 549fdc
					break;
Packit 549fdc
				}
Packit 549fdc
			}
Packit 549fdc
			if (drop == filter_count) {
Packit 549fdc
				fprintf(stderr, "Unknown packet %s\n",
Packit 549fdc
					argv[arg]);
Packit 549fdc
				exit(8);
Packit 549fdc
			}
Packit 549fdc
			single++;
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	setlinebuf(stdout);
Packit 549fdc
	global_init();
Packit 549fdc
	cred_init();
Packit 549fdc
	gnutls_global_set_log_function(logfn);
Packit 549fdc
	gnutls_global_set_audit_log_function(auditfn);
Packit 549fdc
	gnutls_global_set_log_level(debug);
Packit 549fdc
Packit 549fdc
	if (single) {
Packit 549fdc
		if (debug)
Packit 549fdc
			fprintf(stderr, "single test mode\n");
Packit 549fdc
		return run_one_test(dropMode, serverFinishedPermute,
Packit 549fdc
				    serverHelloPermute, clientFinishedPermute);
Packit 549fdc
	} else {
Packit 549fdc
		if (debug)
Packit 549fdc
			fprintf(stderr, "multi test mode\n");
Packit 549fdc
Packit 549fdc
		if (resume) {
Packit 549fdc
			fprintf(stderr, "full run not implemented yet for resumed runs\n");
Packit 549fdc
			exit(5);
Packit 549fdc
		}
Packit 549fdc
Packit 549fdc
		job_pids = calloc(sizeof(int), job_limit);
Packit 549fdc
		if (batch) {
Packit 549fdc
			return run_tests_from_id_list(job_limit);
Packit 549fdc
		} else {
Packit 549fdc
			return run_all_tests(job_limit);
Packit 549fdc
		}
Packit 549fdc
	}
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
// vim: foldmethod=marker
Packit 549fdc
Packit 549fdc
#else				/* NO POSIX TIMERS */
Packit 549fdc
Packit 549fdc
int main(int argc, const char *argv[])
Packit 549fdc
{
Packit 549fdc
	exit(77);
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
#endif