Blame tests/dtls/dtls-stress.c

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