gnutls-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU gnutls branch, master, updated. gnutls_3_0_13-5-gf13b70b


From: Nikos Mavrogiannopoulos
Subject: [SCM] GNU gnutls branch, master, updated. gnutls_3_0_13-5-gf13b70b
Date: Sun, 19 Feb 2012 11:03:12 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU gnutls".

http://git.savannah.gnu.org/cgit/gnutls.git/commit/?id=f13b70b7176424c0c78d69972c105b2065643b3f

The branch, master has been updated
       via  f13b70b7176424c0c78d69972c105b2065643b3f (commit)
       via  b42b212ea3fdec56f75e4fcefe6c79a6813d8e06 (commit)
      from  5c05181a979d4ddd92ec03a90ce19fb1e17628cd (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit f13b70b7176424c0c78d69972c105b2065643b3f
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun Feb 19 12:08:29 2012 +0100

    Added more tests.

commit b42b212ea3fdec56f75e4fcefe6c79a6813d8e06
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun Feb 19 12:04:32 2012 +0100

    Added new dtls-stress.c by Sean

-----------------------------------------------------------------------

Summary of changes:
 tests/dtls/dtls          |    7 +-
 tests/dtls/dtls-nb       |    7 +-
 tests/dtls/dtls-stress.c | 1225 +++++++++++++++++++++++++++++-----------------
 3 files changed, 791 insertions(+), 448 deletions(-)

diff --git a/tests/dtls/dtls b/tests/dtls/dtls
index d63979e..4e841c9 100755
--- a/tests/dtls/dtls
+++ b/tests/dtls/dtls
@@ -1,8 +1,8 @@
 #!/bin/sh
 
-# Copyright (C) 2006-2008, 2010, 2012 Free Software Foundation, Inc.
+# Copyright (C) 2012 Free Software Foundation, Inc.
 #
-# Author: Simon Josefsson
+# Author: Nikos Mavrogiannopoulos
 #
 # This file is part of GnuTLS.
 #
@@ -35,4 +35,7 @@ fi
 ./dtls-stress -shello 021 -sfinished 10 -cfinished 210 SHello SHelloDone 
SChangeCipherSpec CChangeCipherSpec CFinished
 ./dtls-stress -shello 210 -sfinished 10 -cfinished 210 SHello SKeyExchange 
SHelloDone CKeyExchange CChangeCipherSpec CFinished SChangeCipherSpec SFinished
 
+./dtls-stress -full -shello 42130 -sfinished 10 -cfinished 43210 SHello 
SKeyExchange SHelloDone CKeyExchange CChangeCipherSpec CFinished 
SChangeCipherSpec SCertificate SFinished
+./dtls-stress -full -shello 12430 -sfinished 01 -cfinished 01324 SHello 
SKeyExchange SHelloDone CKeyExchange CChangeCipherSpec CFinished SCertificate 
SFinished
+
 exit 0
diff --git a/tests/dtls/dtls-nb b/tests/dtls/dtls-nb
index 915a4bc..7ba2f33 100755
--- a/tests/dtls/dtls-nb
+++ b/tests/dtls/dtls-nb
@@ -1,8 +1,8 @@
 #!/bin/sh
 
-# Copyright (C) 2006-2008, 2010, 2012 Free Software Foundation, Inc.
+# Copyright (C) 2012 Free Software Foundation, Inc.
 #
-# Author: Simon Josefsson
+# Author: Nikos Mavrogiannopoulos
 #
 # This file is part of GnuTLS.
 #
@@ -35,4 +35,7 @@ fi
 ./dtls-stress -nb -shello 021 -sfinished 10 -cfinished 210 SHello SHelloDone 
SChangeCipherSpec CChangeCipherSpec CFinished
 ./dtls-stress -shello 210 -sfinished 10 -cfinished 210 SHello SKeyExchange 
SHelloDone CKeyExchange CChangeCipherSpec CFinished SChangeCipherSpec SFinished
 
+./dtls-stress -nb -full -shello 42130 -sfinished 10 -cfinished 43210 SHello 
SKeyExchange SHelloDone CKeyExchange CChangeCipherSpec CFinished 
SChangeCipherSpec SCertificate SFinished
+./dtls-stress -nb -full -shello 12430 -sfinished 01 -cfinished 01324 SHello 
SKeyExchange SHelloDone CKeyExchange CChangeCipherSpec CFinished SCertificate 
SFinished
+
 exit 0
diff --git a/tests/dtls/dtls-stress.c b/tests/dtls/dtls-stress.c
index b7be231..4daf934 100644
--- a/tests/dtls/dtls-stress.c
+++ b/tests/dtls/dtls-stress.c
@@ -18,7 +18,70 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+/*
+ * DTLS stress test utility
+ *
+ * **** Available parameters ****
+ *
+ *     -nb                 enable nonblocking operations on sessions
+ *     -batch              read test identifiers from stdin and run them
+ *     -d                  increase debug level by one
+ *     -d <n>              set debug level to <n>
+ *     -die                don't start new tests after the first detected 
failure
+ *     -timeout <n>        set handshake timeout to <n> seconds. Tests that 
don't make progress
+ *                         within twice this time will be forcibly killed. 
(default: 120)
+ *     -retransmit <n>     set retransmit timeout to <n> milliseconds 
(default: 100)
+ *     -j <n>              run up to <n> tests in parallel
+ *     -full               use full handshake with mutual certificate 
authentication
+ *     -shello <perm>      run only one test, with the server hello flight 
permuted as <perm>
+ *     -sfinished <perm>   run only one test, with the server finished flight 
permuted as <perm>
+ *     -cfinished <perm>   run only one test, with the client finished flight 
permuted as <perm>
+ *     <packet name>       run only one test, drop <packet name> three times
+ *                         valid values for <packet name> are:
+ *                             SHello, SCertificate, SKeyExchange, 
SCertificateRequest, SHelloDone,
+ *                             CCertificate, CKeyExchange, CCertificateVerify, 
CChangeCipherSpec,
+ *                             CFinished, SChangeCipherSpec, SFinished
+ *                         using *Certificate* without -full will yield 
unexpected results
+ *
+ * 
+ * **** Permutation handling ****
+ *
+ * Flight length for -sfinished is 2, for -shello and -cfinished they are 5 
with -full, 3 otherwise.
+ * Permutations are given with base 0 and specify the order in which reordered 
packets are transmitted.
+ * For example, -full -shello 42130 will transmit server hello flight packets 
in the order
+ * SHelloDone, SKeyExchange, SCertificate, SCertificateRequest, SHello
+ *
+ *
+ * **** Output format ****
+ *
+ * Every line printed for any given test is prefixed by a unique id for that 
test. See run_test_by_id for
+ * exact composition. Errors encountered during execution are printed, with 
one status line after test
+ * completen. The format for this line is as follows:
+ *
+ * <id> <status> SHello(<shperm>), SFinished(<sfinperm>), 
CFinished(<cfinperm>) :- <drops>
+ *
+ * The format for error lines is <id> <role>| <text>, with <role> being the 
role of the child process
+ * that encountered the error, and <text> being obvious.
+ *
+ * <id> is the unique id for the test, it can be used as input to -batch.
+ * <status> can be ++ for a successful test, -- for a failure, TT for a 
deadlock timeout killed test,
+ *     or !! for a test has died due to some unforeseen circumstances like 
syscall failures.
+ * <shperm>, <sfinperm>, <cfinperm> show the permutation for the respective 
flights used.
+ *    They can be used as input to -shello, -sfinished, and -cfinished, 
respectively.
+ * <drops> is a comma separated list of <packet name>, one for every packet 
dropped thrice
+ *
+ *
+ * **** Exit status ****
+ *
+ * 0    all tests have passed
+ * 1    some tests have failed
+ * 4    the master processed has encountered unexpected errors
+ * 8    error parsing command line
+ */
+
+
 #include <gnutls/gnutls.h>
+#include <gnutls/openpgp.h>
 #include <gnutls/dtls.h>
 #include <unistd.h>
 #include <sys/socket.h>
@@ -33,102 +96,293 @@
 #include <time.h>
 #include <wait.h>
 
-enum role {
-       SERVER,
-       CLIENT
-} role;
+// {{{ types
+
+typedef struct {
+       int count;
+} filter_packet_state_t;
+
+typedef struct {
+       gnutls_datum_t packets[5];
+       int* order;
+       int count;
+} filter_permute_state_t;
+
+typedef void (*filter_fn)(gnutls_transport_ptr_t, const unsigned char*, 
size_t);
+
+typedef int (*match_fn)(const unsigned char*, size_t);
+
+enum role { SERVER, CLIENT };
+
+// }}}
+
+// {{{ static data
+
+static int permutations2[2][2]
+       = { { 0, 1 }, { 1, 0 } };
+
+static const char* permutation_names2[]
+       = { "01", "10", 0 };
+
+static int permutations3[6][3]
+       = { { 0, 1, 2 }, { 0, 2, 1 }, { 1, 0, 2 }, { 1, 2, 0 }, { 2, 0, 1 }, { 
2, 1, 0 } };
+
+static const char* permutation_names3[]
+       = { "012", "021", "102", "120", "201", "210", 0 };
+
+static int permutations5[120][5]
+       = { { 0, 1, 2, 3, 4 }, { 0, 2, 1, 3, 4 }, { 1, 0, 2, 3, 4 }, { 1, 2, 0, 
3, 4 }, { 2, 0, 1, 3, 4 }, { 2, 1, 0, 3, 4 },
+               { 0, 1, 3, 2, 4 }, { 0, 2, 3, 1, 4 }, { 1, 0, 3, 2, 4 }, { 1, 
2, 3, 0, 4 }, { 2, 0, 3, 1, 4 }, { 2, 1, 3, 0, 4 },
+               { 0, 3, 1, 2, 4 }, { 0, 3, 2, 1, 4 }, { 1, 3, 0, 2, 4 }, { 1, 
3, 2, 0, 4 }, { 2, 3, 0, 1, 4 }, { 2, 3, 1, 0, 4 },
+               { 3, 0, 1, 2, 4 }, { 3, 0, 2, 1, 4 }, { 3, 1, 0, 2, 4 }, { 3, 
1, 2, 0, 4 }, { 3, 2, 0, 1, 4 }, { 3, 2, 1, 0, 4 },
+               { 0, 1, 2, 4, 3 }, { 0, 2, 1, 4, 3 }, { 1, 0, 2, 4, 3 }, { 1, 
2, 0, 4, 3 }, { 2, 0, 1, 4, 3 }, { 2, 1, 0, 4, 3 },
+               { 0, 1, 3, 4, 2 }, { 0, 2, 3, 4, 1 }, { 1, 0, 3, 4, 2 }, { 1, 
2, 3, 4, 0 }, { 2, 0, 3, 4, 1 }, { 2, 1, 3, 4, 0 },
+               { 0, 3, 1, 4, 2 }, { 0, 3, 2, 4, 1 }, { 1, 3, 0, 4, 2 }, { 1, 
3, 2, 4, 0 }, { 2, 3, 0, 4, 1 }, { 2, 3, 1, 4, 0 },
+               { 3, 0, 1, 4, 2 }, { 3, 0, 2, 4, 1 }, { 3, 1, 0, 4, 2 }, { 3, 
1, 2, 4, 0 }, { 3, 2, 0, 4, 1 }, { 3, 2, 1, 4, 0 },
+               { 0, 1, 4, 2, 3 }, { 0, 2, 4, 1, 3 }, { 1, 0, 4, 2, 3 }, { 1, 
2, 4, 0, 3 }, { 2, 0, 4, 1, 3 }, { 2, 1, 4, 0, 3 },
+               { 0, 1, 4, 3, 2 }, { 0, 2, 4, 3, 1 }, { 1, 0, 4, 3, 2 }, { 1, 
2, 4, 3, 0 }, { 2, 0, 4, 3, 1 }, { 2, 1, 4, 3, 0 },
+               { 0, 3, 4, 1, 2 }, { 0, 3, 4, 2, 1 }, { 1, 3, 4, 0, 2 }, { 1, 
3, 4, 2, 0 }, { 2, 3, 4, 0, 1 }, { 2, 3, 4, 1, 0 },
+               { 3, 0, 4, 1, 2 }, { 3, 0, 4, 2, 1 }, { 3, 1, 4, 0, 2 }, { 3, 
1, 4, 2, 0 }, { 3, 2, 4, 0, 1 }, { 3, 2, 4, 1, 0 },
+               { 0, 4, 1, 2, 3 }, { 0, 4, 2, 1, 3 }, { 1, 4, 0, 2, 3 }, { 1, 
4, 2, 0, 3 }, { 2, 4, 0, 1, 3 }, { 2, 4, 1, 0, 3 },
+               { 0, 4, 1, 3, 2 }, { 0, 4, 2, 3, 1 }, { 1, 4, 0, 3, 2 }, { 1, 
4, 2, 3, 0 }, { 2, 4, 0, 3, 1 }, { 2, 4, 1, 3, 0 },
+               { 0, 4, 3, 1, 2 }, { 0, 4, 3, 2, 1 }, { 1, 4, 3, 0, 2 }, { 1, 
4, 3, 2, 0 }, { 2, 4, 3, 0, 1 }, { 2, 4, 3, 1, 0 },
+               { 3, 4, 0, 1, 2 }, { 3, 4, 0, 2, 1 }, { 3, 4, 1, 0, 2 }, { 3, 
4, 1, 2, 0 }, { 3, 4, 2, 0, 1 }, { 3, 4, 2, 1, 0 },
+               { 4, 0, 1, 2, 3 }, { 4, 0, 2, 1, 3 }, { 4, 1, 0, 2, 3 }, { 4, 
1, 2, 0, 3 }, { 4, 2, 0, 1, 3 }, { 4, 2, 1, 0, 3 },
+               { 4, 0, 1, 3, 2 }, { 4, 0, 2, 3, 1 }, { 4, 1, 0, 3, 2 }, { 4, 
1, 2, 3, 0 }, { 4, 2, 0, 3, 1 }, { 4, 2, 1, 3, 0 },
+               { 4, 0, 3, 1, 2 }, { 4, 0, 3, 2, 1 }, { 4, 1, 3, 0, 2 }, { 4, 
1, 3, 2, 0 }, { 4, 2, 3, 0, 1 }, { 4, 2, 3, 1, 0 },
+               { 4, 3, 0, 1, 2 }, { 4, 3, 0, 2, 1 }, { 4, 3, 1, 0, 2 }, { 4, 
3, 1, 2, 0 }, { 4, 3, 2, 0, 1 }, { 4, 3, 2, 1, 0 } };
+
+static const char* permutation_names5[]
+       = { "01234", "02134", "10234", "12034", "20134", "21034", "01324", 
"02314", "10324", "12304", "20314", "21304",
+               "03124", "03214", "13024", "13204", "23014", "23104", "30124", 
"30214", "31024", "31204", "32014", "32104",
+               "01243", "02143", "10243", "12043", "20143", "21043", "01342", 
"02341", "10342", "12340", "20341", "21340",
+               "03142", "03241", "13042", "13240", "23041", "23140", "30142", 
"30241", "31042", "31240", "32041", "32140",
+               "01423", "02413", "10423", "12403", "20413", "21403", "01432", 
"02431", "10432", "12430", "20431", "21430",
+               "03412", "03421", "13402", "13420", "23401", "23410", "30412", 
"30421", "31402", "31420", "32401", "32410",
+               "04123", "04213", "14023", "14203", "24013", "24103", "04132", 
"04231", "14032", "14230", "24031", "24130",
+               "04312", "04321", "14302", "14320", "24301", "24310", "34012", 
"34021", "34102", "34120", "34201", "34210",
+               "40123", "40213", "41023", "41203", "42013", "42103", "40132", 
"40231", "41032", "41230", "42031", "42130",
+               "40312", "40321", "41302", "41320", "42301", "42310", "43012", 
"43021", "43102", "43120", "43201", "43210", 0 };
+
+static const char* filter_names[8]
+       = { "SHello",
+               "SKeyExchange",
+               "SHelloDone",
+               "CKeyExchange",
+               "CChangeCipherSpec",
+               "CFinished",
+               "SChangeCipherSpec",
+               "SFinished" };
+
+static const char* filter_names_full[12]
+       = { "SHello",
+               "SCertificate",
+               "SKeyExchange",
+               "SCertificateRequest",
+               "SHelloDone",
+               "CCertificate",
+               "CKeyExchange",
+               "CCertificateVerify",
+               "CChangeCipherSpec",
+               "CFinished",
+               "SChangeCipherSpec",
+               "SFinished" };
+
+static const unsigned char PUBKEY[] =
+       "-----BEGIN PGP PUBLIC KEY BLOCK-----\n"
+       "\n"
+       "mI0ETz0XRAEEAKXSU/tg2yGvoKf/r1pdzj7dnfPHeS+BRiT34763uUhibAbTgMkp\n"
+       "v44OlBPiAaZ54uuXVkz8e4pgvrBgQwIRtNp3xPaWF1CfC4F+V4LdZV8l8IG+AfES\n"
+       "K0GbfUS4q8vjnPJ0TyxnXE2KtbcRdzZzWBshJ8KChKwbH2vvrMrlmEeZABEBAAG0\n"
+       "CHRlc3Qga2V5iLgEEwECACIFAk89F0QCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4B\n"
+       "AheAAAoJEMNjhmkfkLY9J/YD+wYZ2BD/0/c5gkkDP2NlVvrLGyFmEwQcR7DcaQYB\n"
+       "P3/Teq2gnscZ5Xm/z1qgGEpwmaVfVHY8mfEj8bYI8jAu0v1C1jCtJPUTmxf9tmkZ\n"
+       "QYFNR8T+F5Xae2XseOH70lSN/AEiW02BEBFlGBx0a3T30muFfqi/KawaE7KKn2e4\n"
+       "uNWvuI0ETz0XRAEEAKgZExsb7Lf9P3DmwJSvNVdkGVny7wr4/M1s0CDX20NkO7Y1\n"
+       "Ao9g+qFo5MlCOEuzjVaEYmM+rro7qyxmDKsaNIzZF1VN5UeYgPFyLcBK7C+QwUqw\n"
+       "1PUl/w4dFq8neQyqIPUVGRwQPlwpkkabRPNT3t/7KgDJvYzV9uu+cXCyfqErABEB\n"
+       "AAGInwQYAQIACQUCTz0XRAIbDAAKCRDDY4ZpH5C2PTBtBACVsR6l4HtuzQb5WFQt\n"
+       "sD/lQEk6BEY9aVfK957Oj+A4alGEGObToqVJFo/nq+P7aWExIXucJQRL8lYnC7u+\n"
+       "GjPVCun5TYzKMiryxHPkQr9NBx4hh8JjkDCc8nAgI3il49uPYkmsv70CgqJFFtT8\n"
+       "NfM+8fS537I+XA+hfjt20NUFIA==\n"
+       "=oD3a\n"
+       "-----END PGP PUBLIC KEY BLOCK-----\n";
+
+static const unsigned char PRIVKEY[] = 
+       "-----BEGIN PGP PRIVATE KEY BLOCK-----\n"
+       "\n"
+       "lQHYBE89F0QBBACl0lP7YNshr6Cn/69aXc4+3Z3zx3kvgUYk9+O+t7lIYmwG04DJ\n"
+       "Kb+ODpQT4gGmeeLrl1ZM/HuKYL6wYEMCEbTad8T2lhdQnwuBfleC3WVfJfCBvgHx\n"
+       "EitBm31EuKvL45zydE8sZ1xNirW3EXc2c1gbISfCgoSsGx9r76zK5ZhHmQARAQAB\n"
+       "AAP6A6VhRVi22MHE1YzQrTr8yvMSgwayynGcOjndHxdpEodferLx1Pp/BL+bT+ib\n"
+       "Qq7RZ363Xg/7I2rHJpenQYdkI5SI4KrXIV57p8G+isyTtsxU38SY84WoB5os8sfT\n"
+       "YhxG+edoTfDzXkRSWFB8EUjRaLa2b//nvLpxNRyqDSzzUxECAMtEnL5H/8gHbpZf\n"
+       "D98TSJVxdAl9rBAQaVMgrFgcU/IlmxCyVEh9eh/P261tefgOnyVcGFYHxdZvJ3td\n"
+       "miM+DNUCANDW1S9t7IiqflDpQIS2wGTZ/rLKPoE1F3285EaYAd0FQUq0O4/Nu31D\n"
+       "5pz/S7D+PfXn9oEZH3Dvl3EVIDyq4bUB+QEzFc3BsH2uueD3g42RoBfMGl6m3LI9\n"
+       "yWOnrUmIW+h9Fu8W9mcU6y82Q1G7OPIxA1me/Qtzo20lGQa8jAyzLhuit7QIdGVz\n"
+       "dCBrZXmIuAQTAQIAIgUCTz0XRAIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA\n"
+       "CgkQw2OGaR+Qtj0n9gP7BhnYEP/T9zmCSQM/Y2VW+ssbIWYTBBxHsNxpBgE/f9N6\n"
+       "raCexxnleb/PWqAYSnCZpV9UdjyZ8SPxtgjyMC7S/ULWMK0k9RObF/22aRlBgU1H\n"
+       "xP4Xldp7Zex44fvSVI38ASJbTYEQEWUYHHRrdPfSa4V+qL8prBoTsoqfZ7i41a+d\n"
+       "AdgETz0XRAEEAKgZExsb7Lf9P3DmwJSvNVdkGVny7wr4/M1s0CDX20NkO7Y1Ao9g\n"
+       "+qFo5MlCOEuzjVaEYmM+rro7qyxmDKsaNIzZF1VN5UeYgPFyLcBK7C+QwUqw1PUl\n"
+       "/w4dFq8neQyqIPUVGRwQPlwpkkabRPNT3t/7KgDJvYzV9uu+cXCyfqErABEBAAEA\n"
+       "A/4wX+brqkGZQTv8lateHn3PRHM3O34nPjgiNeo/SV9EKZg1e1PdRx9ZTAJrGK9y\n"
+       "uZ03BKn7vZIy7fD4ufVzV/s/BaypVmvwjZud8fdMgsMQAJYtoMhozbOtUelCFpja\n"
+       "I1xAbDBx1PAAbS8Sh022/0jvOGnZhvkgZMG90z7AEANUYQIAwzywU087TcJk8Bzd\n"
+       "37JGWyE4f3iYFGA+r8BoIOrxvvgfUHKxdhG0gaT8SDeRAwNY6D43dCBZkG7Uel1F\n"
+       "x9MlLQIA3Goaz58hEN0fdm4TM7A8crtMB+f8/h87EneBgMl+Yj/3sklhyahR6Itm\n"
+       "lGuAAGTAOmD7i8OmS/a1ac5MtHAGtwH6A0B5GjaL8VnLQo4vFnuR7JuCQaLqGadV\n"
+       "mBmKxVHElduLf/VauBQPD5KZA+egpg+laJ4JLVXMmKIZGqRzopcIWZnKiJ8EGAEC\n"
+       "AAkFAk89F0QCGwwACgkQw2OGaR+Qtj0wbQQAlbEepeB7bs0G+VhULbA/5UBJOgRG\n"
+       "PWlXyveezo/gOGpRhBjm06KlSRaP56vj+2lhMSF7nCUES/JWJwu7vhoz1Qrp+U2M\n"
+       "yjIq8sRz5EK/TQceIYfCY5AwnPJwICN4pePbj2JJrL+9AoKiRRbU/DXzPvH0ud+y\n"
+       "PlwPoX47dtDVBSA=\n"
+       "=EVlv\n"
+       "-----END PGP PRIVATE KEY BLOCK-----\n";
+
+// }}}
+
+// {{{ other global state
+
+enum role role;
+
+#define role_name (role == SERVER ? "server" : "client")
 
 int debug;
 int nonblock;
+int full;
+int timeout_seconds;
+int retransmit_milliseconds;
+int run_to_end;
 
 int run_id;
 
-static const char* role_to_name(enum role role)
-{
-       if (role == SERVER) {
-               return "server";
-       } else {
-               return "client";
-       }
-}
+// }}}
+
+// {{{ logging and error handling
 
 static void logfn(int level, const char* s)
 {
        if (debug) {
-               fprintf(stdout, "%i %s|<%i> %s", run_id, role_to_name(role), 
level, s);
+               fprintf(stdout, "%i %s|<%i> %s", run_id, role_name, level, s);
        }
 }
 
 static void auditfn(gnutls_session_t session, const char* s)
 {
        if (debug) {
-               fprintf(stdout, "%i %s| %s", run_id, role_to_name(role), s);
+               fprintf(stdout, "%i %s| %s", run_id, role_name, s);
        }
 }
 
 static void drop(const char* packet)
 {
        if (debug) {
-               fprintf(stdout, "%i %s| dropping %s\n", run_id, 
role_to_name(role), packet);
+               fprintf(stdout, "%i %s| dropping %s\n", run_id, role_name, 
packet);
        }
 }
 
+static int _process_error(int loc, int code, int die)
+{
+       if (code < 0 && (die || code != GNUTLS_E_AGAIN)) {
+               fprintf(stdout, "%i <%s tls> line %i: %s", run_id, role_name, 
loc, gnutls_strerror(code));
+               if (gnutls_error_is_fatal(code) || die) {
+                       fprintf(stdout, " (fatal)\n");
+                       exit(1);
+               } else {
+                       fprintf(stdout, "\n");
+               }
+       }
+       return code;
+}
 
-typedef struct {
-       int count;
-} filter_packet_state_t;
+#define die_on_error(code) _process_error(__LINE__, code, 1)
+#define process_error(code) _process_error(__LINE__, code, 0)
+
+static void _process_error_or_timeout(int loc, int err, time_t tdiff)
+{
+       if (err < 0) {
+               if (err != GNUTLS_E_TIMEDOUT || tdiff >= 60) {
+                       _process_error(loc, err, 0);
+               } else {
+                       fprintf(stdout, "%i %s| line %i: {spurious timeout} 
(fatal)", run_id, role_name, loc);
+                       exit(1);
+               }
+       }
+}
+
+#define process_error_or_timeout(code, tdiff) 
_process_error_or_timeout(__LINE__, code, tdiff)
+
+static void rperror(const char* name)
+{
+       fprintf(stdout, "%i %s| %s: %s\n", run_id, role_name, name, 
strerror(errno));
+}
+
+// }}}
+
+// {{{ init, shared, and teardown code and data for packet stream filters
 
 filter_packet_state_t state_packet_ServerHello = { 0 };
+filter_packet_state_t state_packet_ServerCertificate = { 0 };
 filter_packet_state_t state_packet_ServerKeyExchange = { 0 };
+filter_packet_state_t state_packet_ServerCertificateRequest = { 0 };
 filter_packet_state_t state_packet_ServerHelloDone = { 0 };
+filter_packet_state_t state_packet_ClientCertificate = { 0 };
 filter_packet_state_t state_packet_ClientKeyExchange = { 0 };
+filter_packet_state_t state_packet_ClientCertificateVerify = { 0 };
 filter_packet_state_t state_packet_ClientChangeCipherSpec = { 0 };
 filter_packet_state_t state_packet_ClientFinished = { 0 };
 filter_packet_state_t state_packet_ServerChangeCipherSpec = { 0 };
 filter_packet_state_t state_packet_ServerFinished = { 0 };
 
-typedef struct {
-       gnutls_datum_t packets[3];
-       int* order;
-       int count;
-} filter_permute_state_t;
-
-filter_permute_state_t state_permute_ServerHello = { { { 0, 0 }, { 0, 0 }, { 
0, 0 } }, 0, 0 };
-filter_permute_state_t state_permute_ServerFinished = { { { 0, 0 }, { 0, 0 }, 
{ 0, 0 } }, 0, 0 };
-filter_permute_state_t state_permute_ClientFinished = { { { 0, 0 }, { 0, 0 }, 
{ 0, 0 } }, 0, 0 };
-
-typedef void (*filter_fn)(gnutls_transport_ptr_t, const unsigned char*, 
size_t);
+filter_permute_state_t state_permute_ServerHello = { { { 0, 0 }, { 0, 0 }, { 
0, 0 }, { 0, 0 }, { 0, 0 } }, 0, 0 };
+filter_permute_state_t state_permute_ServerHelloFull = { { { 0, 0 }, { 0, 0 }, 
{ 0, 0 }, { 0, 0 }, { 0, 0 } }, 0, 0 };
+filter_permute_state_t state_permute_ServerFinished = { { { 0, 0 }, { 0, 0 }, 
{ 0, 0 }, { 0, 0 }, { 0, 0 } }, 0, 0 };
+filter_permute_state_t state_permute_ClientFinished = { { { 0, 0 }, { 0, 0 }, 
{ 0, 0 }, { 0, 0 }, { 0, 0 } }, 0, 0 };
+filter_permute_state_t state_permute_ClientFinishedFull = { { { 0, 0 }, { 0, 0 
}, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 0, 0 };
 
 filter_fn filter_chain[32];
 int filter_current_idx;
 
+static void filter_permute_state_free_buffer(filter_permute_state_t* state)
+{
+       unsigned int i;
+
+       for (i = 0; i < sizeof(state->packets) / sizeof(state->packets[0]); 
i++) {
+               free(state->packets[i].data);
+               state->packets[i].data = NULL;
+       }
+}
+
 static void filter_clear_state(void)
 {
-int i;
+       filter_current_idx = 0;
+
+       filter_permute_state_free_buffer(&state_permute_ServerHello);
+       filter_permute_state_free_buffer(&state_permute_ServerHelloFull);
+       filter_permute_state_free_buffer(&state_permute_ServerFinished);
+       filter_permute_state_free_buffer(&state_permute_ClientFinished);
+       filter_permute_state_free_buffer(&state_permute_ClientFinishedFull);
 
        memset(&state_packet_ServerHello, 0, sizeof(state_packet_ServerHello));
+       memset(&state_packet_ServerCertificate, 0, 
sizeof(state_packet_ServerCertificate));
        memset(&state_packet_ServerKeyExchange, 0, 
sizeof(state_packet_ServerKeyExchange));
+       memset(&state_packet_ServerCertificateRequest, 0, 
sizeof(state_packet_ServerCertificateRequest));
        memset(&state_packet_ServerHelloDone, 0, 
sizeof(state_packet_ServerHelloDone));
+       memset(&state_packet_ClientCertificate, 0, 
sizeof(state_packet_ClientCertificate));
        memset(&state_packet_ClientKeyExchange, 0, 
sizeof(state_packet_ClientKeyExchange));
+       memset(&state_packet_ClientCertificateVerify, 0, 
sizeof(state_packet_ClientCertificateVerify));
        memset(&state_packet_ClientChangeCipherSpec, 0, 
sizeof(state_packet_ClientChangeCipherSpec));
+       memset(&state_packet_ClientFinished, 0, 
sizeof(state_packet_ClientFinished));
        memset(&state_packet_ServerChangeCipherSpec, 0, 
sizeof(state_packet_ServerChangeCipherSpec));
        memset(&state_packet_ServerFinished, 0, 
sizeof(state_packet_ServerFinished));
-
-       for (i = 0; i < 3; i++) {
-               if (state_permute_ServerHello.packets[i].data) {
-                       free(state_permute_ServerHello.packets[i].data);
-               }
-               if (state_permute_ServerFinished.packets[i].data) {
-                       free(state_permute_ServerFinished.packets[i].data);
-               }
-               if (state_permute_ClientFinished.packets[i].data) {
-                       free(state_permute_ClientFinished.packets[i].data);
-               }
-       }
-
        memset(&state_permute_ServerHello, 0, 
sizeof(state_permute_ServerHello));
+       memset(&state_permute_ServerHelloFull, 0, 
sizeof(state_permute_ServerHelloFull));
        memset(&state_permute_ServerFinished, 0, 
sizeof(state_permute_ServerFinished));
        memset(&state_permute_ClientFinished, 0, 
sizeof(state_permute_ClientFinished));
+       memset(&state_permute_ClientFinishedFull, 0, 
sizeof(state_permute_ClientFinishedFull));
 }
 
 static void filter_run_next(gnutls_transport_ptr_t fd,
@@ -139,26 +393,23 @@ static void filter_run_next(gnutls_transport_ptr_t fd,
        if (fn) {
                fn(fd, buffer, len);
        } else {
-               send((long int) fd, buffer, len, 0);
+               send((intptr_t) fd, buffer, len, 0);
        }
        filter_current_idx--;
 }
 
+// }}}
 
+// {{{ packet match functions
 
 static int match_ServerHello(const unsigned char* buffer, size_t len)
 {
        return role == SERVER && len >= 13 + 1 && buffer[0] == 22 && buffer[13] 
== 2;
 }
 
-static void filter_packet_ServerHello(gnutls_transport_ptr_t fd,
-               const unsigned char* buffer, size_t len)
+static int match_ServerCertificate(const unsigned char* buffer, size_t len)
 {
-       if (match_ServerHello(buffer, len) && state_packet_ServerHello.count++ 
< 3) {
-               drop("Server Hello");
-       } else {
-               filter_run_next(fd, buffer, len);
-       }
+       return role == SERVER && len >= 13 + 1 && buffer[0] == 22 && buffer[13] 
== 11;
 }
 
 static int match_ServerKeyExchange(const unsigned char* buffer, size_t len)
@@ -166,14 +417,9 @@ static int match_ServerKeyExchange(const unsigned char* 
buffer, size_t len)
        return role == SERVER && len >= 13 + 1 && buffer[0] == 22 && buffer[13] 
== 12;
 }
 
-static void filter_packet_ServerKeyExchange(gnutls_transport_ptr_t fd,
-               const unsigned char* buffer, size_t len)
+static int match_ServerCertificateRequest(const unsigned char* buffer, size_t 
len)
 {
-       if (match_ServerKeyExchange(buffer, len) && 
state_packet_ServerKeyExchange.count++ < 3) {
-               drop("Server Key Exchange");
-       } else {
-               filter_run_next(fd, buffer, len);
-       }
+       return role == SERVER && len >= 13 + 1 && buffer[0] == 22 && buffer[13] 
== 13;
 }
 
 static int match_ServerHelloDone(const unsigned char* buffer, size_t len)
@@ -181,116 +427,75 @@ static int match_ServerHelloDone(const unsigned char* 
buffer, size_t len)
        return role == SERVER && len >= 13 + 1 && buffer[0] == 22 && buffer[13] 
== 14;
 }
 
-static 
-void filter_packet_ServerHelloDone(gnutls_transport_ptr_t fd,
-               const unsigned char* buffer, size_t len)
+static int match_ClientCertificate(const unsigned char* buffer, size_t len)
 {
-       if (match_ServerHelloDone(buffer, len) && 
state_packet_ServerHelloDone.count++ < 3) {
-               drop("Server Hello Done");
-       } else {
-               filter_run_next(fd, buffer, len);
-       }
+       return role == CLIENT && len >= 13 + 1 && buffer[0] == 22 && buffer[13] 
== 11;
 }
 
-static
-int match_ClientKeyExchange(const unsigned char* buffer, size_t len)
+static int match_ClientKeyExchange(const unsigned char* buffer, size_t len)
 {
        return role == CLIENT && len >= 13 + 1 && buffer[0] == 22 && buffer[13] 
== 16;
 }
 
-static
-void filter_packet_ClientKeyExchange(gnutls_transport_ptr_t fd,
-               const unsigned char* buffer, size_t len)
+static int match_ClientCertificateVerify(const unsigned char* buffer, size_t 
len)
 {
-       if (match_ClientKeyExchange(buffer, len) && 
state_packet_ClientKeyExchange.count++ < 3) {
-               drop("Client Key Exchange");
-       } else {
-               filter_run_next(fd, buffer, len);
-       }
+       return role == CLIENT && len >= 13 + 1 && buffer[0] == 22 && buffer[13] 
== 15;
 }
 
-static
-int match_ClientChangeCipherSpec(const unsigned char* buffer, size_t len)
+static int match_ClientChangeCipherSpec(const unsigned char* buffer, size_t 
len)
 {
        return role == CLIENT && len >= 13 && buffer[0] == 20;
 }
 
-static
-void filter_packet_ClientChangeCipherSpec(gnutls_transport_ptr_t fd,
-               const unsigned char* buffer, size_t len)
-{
-       if (match_ClientChangeCipherSpec(buffer, len) && 
state_packet_ClientChangeCipherSpec.count++ < 3) {
-               drop("Client Change Cipher Spec");
-       } else {
-               filter_run_next(fd, buffer, len);
-       }
-}
-
-static
-int match_ClientFinished(const unsigned char* buffer, size_t len)
+static int match_ClientFinished(const unsigned char* buffer, size_t len)
 {
        return role == CLIENT && len >= 13 && buffer[0] == 22 && buffer[4] == 1;
 }
 
-static
-void filter_packet_ClientFinished(gnutls_transport_ptr_t fd,
-               const unsigned char* buffer, size_t len)
-{
-       if (match_ClientFinished(buffer, len) && 
state_packet_ClientFinished.count++ < 3) {
-               drop("Client Finished");
-       } else {
-               filter_run_next(fd, buffer, len);
-       }
-}
-
-static
-int match_ServerChangeCipherSpec(const unsigned char* buffer, size_t len)
+static int match_ServerChangeCipherSpec(const unsigned char* buffer, size_t 
len)
 {
        return role == SERVER && len >= 13 && buffer[0] == 20;
 }
 
-static
-void filter_packet_ServerChangeCipherSpec(gnutls_transport_ptr_t fd,
-               const unsigned char* buffer, size_t len)
-{
-       if (match_ServerChangeCipherSpec(buffer, len) && 
state_packet_ServerChangeCipherSpec.count++ < 3) {
-               drop("Server Change Cipher Spec");
-       } else {
-               filter_run_next(fd, buffer, len);
-       }
-}
-
-static
-int match_ServerFinished(const unsigned char* buffer, size_t len)
+static int match_ServerFinished(const unsigned char* buffer, size_t len)
 {
        return role == SERVER && len >= 13 && buffer[0] == 22 && buffer[4] == 1;
 }
 
-static
-void filter_packet_ServerFinished(gnutls_transport_ptr_t fd,
-               const unsigned char* buffer, size_t len)
-{
-       if (match_ServerFinished(buffer, len) && 
state_packet_ServerFinished.count++ < 3) {
-               drop("Server Finished");
-       } else {
-               filter_run_next(fd, buffer, len);
-       }
-}
+// }}}
 
-static
-void filter_permutete_state_free_buffer(filter_permute_state_t* state)
-{
-       int i;
+// {{{ packet drop filters
 
-       for (i = 0; i < 3; i++) {
-               if (state->packets[i].data) {
-                       free(state->packets[i].data);
-               }
+#define FILTER_DROP_COUNT 3
+#define DECLARE_FILTER(packet) \
+       static void filter_packet_##packet(gnutls_transport_ptr_t fd, \
+                       const unsigned char* buffer, size_t len) \
+       { \
+               if (match_##packet(buffer, len) && 
(state_packet_##packet).count++ < FILTER_DROP_COUNT) { \
+                       drop(#packet); \
+               } else { \
+                       filter_run_next(fd, buffer, len); \
+               } \
        }
-}
 
-static
-void filter_permute_state_run(filter_permute_state_t* state, int packetCount,
+DECLARE_FILTER(ServerHello)
+DECLARE_FILTER(ServerCertificate)
+DECLARE_FILTER(ServerKeyExchange)
+DECLARE_FILTER(ServerCertificateRequest)
+DECLARE_FILTER(ServerHelloDone)
+DECLARE_FILTER(ClientCertificate)
+DECLARE_FILTER(ClientKeyExchange)
+DECLARE_FILTER(ClientCertificateVerify)
+DECLARE_FILTER(ClientChangeCipherSpec)
+DECLARE_FILTER(ClientFinished)
+DECLARE_FILTER(ServerChangeCipherSpec)
+DECLARE_FILTER(ServerFinished)
+
+// }}}
+
+// {{{ flight permutation filters
+
+static void filter_permute_state_run(filter_permute_state_t* state, int 
packetCount,
                gnutls_transport_ptr_t fd, const unsigned char* buffer, size_t 
len)
 {
        unsigned char* data = malloc(len);
@@ -306,233 +511,200 @@ void filter_permute_state_run(filter_permute_state_t* 
state, int packetCount,
                        filter_run_next(fd, state->packets[packet].data,
                                        state->packets[packet].size);
                }
-               filter_permutete_state_free_buffer(state);
+               filter_permute_state_free_buffer(state);
                state->count = 0;
        }
 }
 
-static
-void filter_permute_ServerHello(gnutls_transport_ptr_t fd,
-               const unsigned char* buffer, size_t len)
-{
-       if (match_ServerHello(buffer, len)
-                       || match_ServerKeyExchange(buffer, len)
-                       || match_ServerHelloDone(buffer, len)) {
-               filter_permute_state_run(&state_permute_ServerHello, 3, fd, 
buffer, len);
-       } else {
-               filter_run_next(fd, buffer, len);
+#define DECLARE_PERMUTE(flight) \
+       static void filter_permute_##flight(gnutls_transport_ptr_t fd, \
+                       const unsigned char* buffer, size_t len) \
+       { \
+               int count = sizeof(permute_match_##flight) / 
sizeof(permute_match_##flight[0]); \
+               int i; \
+               for (i = 0; i < count; i++) { \
+                       if (permute_match_##flight[i](buffer, len)) { \
+                               
filter_permute_state_run(&state_permute_##flight, count, fd, buffer, len); \
+                               return; \
+                       } \
+               } \
+               filter_run_next(fd, buffer, len); \
        }
-}
 
-static
-void filter_permute_ServerFinished(gnutls_transport_ptr_t fd,
-               const unsigned char* buffer, size_t len)
+static match_fn permute_match_ServerHello[] = { match_ServerHello, 
match_ServerKeyExchange, match_ServerHelloDone };
+static match_fn permute_match_ServerHelloFull[] = { match_ServerHello, 
match_ServerCertificate, match_ServerKeyExchange,
+       match_ServerCertificateRequest, match_ServerHelloDone };
+static match_fn permute_match_ServerFinished[] = { 
match_ServerChangeCipherSpec, match_ServerFinished };
+static match_fn permute_match_ClientFinished[] = { match_ClientKeyExchange, 
match_ClientChangeCipherSpec, match_ClientFinished };
+static match_fn permute_match_ClientFinishedFull[] = { 
match_ClientCertificate, match_ClientKeyExchange,
+       match_ClientCertificateVerify, match_ClientChangeCipherSpec, 
match_ClientFinished };
+
+DECLARE_PERMUTE(ServerHello)
+DECLARE_PERMUTE(ServerHelloFull)
+DECLARE_PERMUTE(ServerFinished)
+DECLARE_PERMUTE(ClientFinished)
+DECLARE_PERMUTE(ClientFinishedFull)
+       
+// }}}
+
+// {{{ emergency deadlock resolution time bomb
+
+timer_t killtimer_tid = 0;
+
+static void killtimer_set(void)
 {
-       if (match_ServerChangeCipherSpec(buffer, len)
-                       || match_ServerFinished(buffer, len)) {
-               filter_permute_state_run(&state_permute_ServerFinished, 2, fd, 
buffer, len);
-       } else {
-               filter_run_next(fd, buffer, len);
+       struct sigevent sig;
+       struct itimerspec tout = { { 0, 0 }, { 2 * timeout_seconds, 0 } };
+
+       if (killtimer_tid != 0) {
+               timer_delete(killtimer_tid);
        }
-}
 
-static
-void filter_permute_ClientFinished(gnutls_transport_ptr_t fd,
-               const unsigned char* buffer, size_t len)
-{
-       if (match_ClientKeyExchange(buffer, len)
-                       || match_ClientChangeCipherSpec(buffer, len)
-                       || match_ClientFinished(buffer, len)) {
-               filter_permute_state_run(&state_permute_ClientFinished, 3, fd, 
buffer, len);
-       } else {
-               filter_run_next(fd, buffer, len);
+       memset(&sig, 0, sizeof(sig));
+       sig.sigev_notify = SIGEV_SIGNAL;
+       sig.sigev_signo = 15;
+       if (timer_create(CLOCK_MONOTONIC, &sig, &killtimer_tid) < 0) {
+               rperror("timer_create");
+               exit(3);
        }
+
+       timer_settime(killtimer_tid, 0, &tout, 0);
 }
 
+// }}}
 
-static
-ssize_t writefn(gnutls_transport_ptr_t fd, const void* buffer, size_t len)
+// {{{ actual gnutls operations
+
+gnutls_certificate_credentials_t cred;
+gnutls_session_t session;
+
+static ssize_t writefn(gnutls_transport_ptr_t fd, const void* buffer, size_t 
len)
 {
-       filter_current_idx = 0;
        filter_run_next(fd, (const unsigned char*) buffer, len);
        return len;
 }
 
-static
-void await(int fd)
+static void await(int fd, int timeout)
 {
        if (nonblock) {
                struct pollfd p = { fd, POLLIN, 0 };
-               poll(&p, 1, 100);
+               if (poll(&p, 1, timeout) < 0 && errno != EAGAIN && errno != 
EINTR) {
+                       rperror("poll");
+                       exit(3);
+               }
        }
 }
 
+static void cred_init(void)
+{
+       gnutls_datum_t key = { (unsigned char*) PUBKEY, sizeof(PUBKEY) };
+       gnutls_datum_t sec = { (unsigned char*) PRIVKEY, sizeof(PRIVKEY) };
 
+       gnutls_certificate_allocate_credentials(&cred);
 
+       gnutls_certificate_set_openpgp_key_mem(cred, &key, &sec, 
GNUTLS_OPENPGP_FMT_BASE64);
+}
 
-static
-gnutls_session_t session(int sock, int server)
+static void session_init(int sock, int server)
 {
-       gnutls_session_t r;
-
-       gnutls_init(&r, GNUTLS_DATAGRAM | (server ? GNUTLS_SERVER : 
GNUTLS_CLIENT)
+       gnutls_init(&session, GNUTLS_DATAGRAM | (server ? GNUTLS_SERVER : 
GNUTLS_CLIENT)
                        | GNUTLS_NONBLOCK * nonblock);
-       gnutls_priority_set_direct(r, "NORMAL:+ANON-ECDH", 0);
-       gnutls_transport_set_ptr(r, (gnutls_transport_ptr_t) sock);
+       gnutls_priority_set_direct(session, 
"+CTYPE-OPENPGP:+CIPHER-ALL:+MAC-ALL:+ECDHE-RSA:+ANON-ECDH", 0);
+       gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) (intptr_t) 
sock);
 
-       if (server) {
+       if (full) {
+               gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred);
+               if (server) {
+                       gnutls_certificate_server_set_request(session, 
GNUTLS_CERT_REQUIRE);
+               }
+       } else if (server) {
                gnutls_anon_server_credentials_t cred;
                gnutls_anon_allocate_server_credentials(&cred);
-               gnutls_credentials_set(r, GNUTLS_CRD_ANON, cred);
+               gnutls_credentials_set(session, GNUTLS_CRD_ANON, cred);
        } else {
                gnutls_anon_client_credentials_t cred;
                gnutls_anon_allocate_client_credentials(&cred);
-               gnutls_credentials_set(r, GNUTLS_CRD_ANON, cred);
+               gnutls_credentials_set(session, GNUTLS_CRD_ANON, cred);
        }
 
-       gnutls_transport_set_push_function(r, writefn);
+       gnutls_transport_set_push_function(session, writefn);
 
-       gnutls_dtls_set_mtu(r, 1400);
-       
-       /* The cases tested here might exceed the normal DTLS
-        * timers */
-       gnutls_dtls_set_timeouts(r, 1000, 120000);
-
-       return r;
+       gnutls_dtls_set_mtu(session, 1400);
+       gnutls_dtls_set_timeouts(session, retransmit_milliseconds, 
timeout_seconds * 1000);
 }
 
-static
-int log_error(int code)
+static void client(int sock)
 {
-       if (code < 0 && code != GNUTLS_E_AGAIN) {
-               fprintf(stdout, "%i <%s tls> %s", run_id, role_to_name(role), 
gnutls_strerror(code));
-               if (gnutls_error_is_fatal(code)) {
-                       fprintf(stdout, " (fatal)\n");
-                       exit(1);
-               } else {
-                       fprintf(stdout, "\n");
-               }
-       }
-       return code;
-}
-
-timer_t killtimer_tid;
-
-static
-void reset_killtimer(void)
-{
-struct itimerspec tout = { { 0, 0 }, { 120, 0 } };
-
-       if (nonblock) {
-               return;
-       }
-       timer_settime(killtimer_tid, 0, &tout, 0);
-}
-
-static
-void setup_killtimer(void)
-{
-       struct sigevent sig;
-       struct itimerspec tout = { { 0, 0 }, { 240, 0 } };
-
-       memset(&sig, 0, sizeof(sig));
-       sig.sigev_notify = SIGEV_SIGNAL;
-       sig.sigev_signo = 15;
-       timer_create(CLOCK_MONOTONIC, &sig, &killtimer_tid);
-
-       timer_settime(killtimer_tid, 0, &tout, 0);
-}
-
-static
-void log_error_with_time(int err, time_t started)
-{
-       if (err < 0) {
-               if (err != GNUTLS_E_TIMEDOUT || (time(0) - started) >= 60) {
-                       log_error(err);
-               } else {
-                       fprintf(stdout, "{spurious}");
-                       log_error(err);
-               }
-               if (gnutls_error_is_fatal(err)) {
-                       exit(1);
-               }
-       }
-}
-
-static
-void client(int sock)
-{
-       gnutls_session_t s = session(sock, 0);
        int err = 0;
        time_t started = time(0);
        const char* line = "foobar!";
        char buffer[8192];
        int len;
 
-       setup_killtimer();
+       session_init(sock, 0);
 
+       killtimer_set();
        do {
-               await(sock);
-               err = log_error(gnutls_handshake(s));
-               reset_killtimer();
-       } while (err != 0 && !gnutls_error_is_fatal(err));
-       log_error_with_time(err, started);
+               err = process_error(gnutls_handshake(session));
+               if (err != 0) {
+                       int t = gnutls_dtls_get_timeout(session);
+                       await(sock, t ? t : 100);
+               }
+       } while (err != 0);
+       process_error_or_timeout(err, time(0) - started);
        
-       started = time(0);
-       do {
-               err = gnutls_record_send(s, line, strlen(line));
-               reset_killtimer();
-       } while (err < 0 && !gnutls_error_is_fatal(err));
-       log_error_with_time(err, started);
+       killtimer_set();
+       die_on_error(gnutls_record_send(session, line, strlen(line)));
        
        do {
-               await(sock);
-               len = gnutls_record_recv(s, buffer, sizeof(buffer));
-       } while (len < 0 && !gnutls_error_is_fatal(len));
+               await(sock, -1);
+               len = process_error(gnutls_record_recv(session, buffer, 
sizeof(buffer)));
+       } while (len < 0);
+
        if (len > 0 && strcmp(line, buffer) == 0) {
                exit(0);
        } else {
-               log_error(len);
                exit(1);
        }
 }
 
-static
-void server(int sock)
+static void server(int sock)
 { 
-       gnutls_session_t s = session(sock, 1);
        int err;
        time_t started = time(0);
+       char buffer[8192];
+       int len;
 
-       write(sock, &sock, 1);
+       session_init(sock, 1);
 
-       setup_killtimer();
+       await(sock, -1);
 
+       killtimer_set();
        do {
-               await(sock);
-               err = log_error(gnutls_handshake(s));
-               reset_killtimer();
-       } while (err != 0 && !gnutls_error_is_fatal(err));
-       log_error_with_time(err, started);
-
-       for (;;) {
-               char buffer[8192];
-               int len;
-               do {
-                       await(sock);
-                       len = gnutls_record_recv(s, buffer, sizeof(buffer));
-                       reset_killtimer();
-               } while (len < 0 && !gnutls_error_is_fatal(len));
-               log_error_with_time(len, started);
-
-               gnutls_record_send(s, buffer, len);
-               exit(0);
-       }
+               err = process_error(gnutls_handshake(session));
+               if (err != 0) {
+                       int t = gnutls_dtls_get_timeout(session);
+                       await(sock, t ? t : 100);
+               }
+       } while (err != 0);
+       process_error_or_timeout(err, time(0) - started);
+
+       killtimer_set();
+       do {
+               await(sock, -1);
+               len = process_error(gnutls_record_recv(session, buffer, 
sizeof(buffer)));
+       } while (len < 0);
+
+       die_on_error(gnutls_record_send(session, buffer, len));
+       exit(0);
 }
 
+// }}}
+
+// {{{ test running/handling itself
+
 #if 0
-static
-void udp_sockpair(int* socks)
+static void udp_sockpair(int* socks)
 {
        struct sockaddr_in6 sa = { AF_INET6, htons(30000), 0, in6addr_loopback, 
0 };
        struct sockaddr_in6 sb = { AF_INET6, htons(20000), 0, in6addr_loopback, 
0 };
@@ -548,14 +720,16 @@ void udp_sockpair(int* socks)
 }
 #endif
 
-static
-int run_test(void)
+static int run_test(void)
 {
        int fds[2];
        int pid1, pid2;
        int status2;
 
-       socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+       if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds) < 0) {
+               rperror("socketpair");
+               exit(2);
+       }
 
        if (nonblock) {
                fcntl(fds[0], F_SETFL, (long) O_NONBLOCK);
@@ -563,40 +737,33 @@ int run_test(void)
        }
 
        if (!(pid1 = fork())) {
-               setpgrp();
                role = SERVER;
-               server(fds[1]);
+               server(fds[1]); // noreturn
+       } else if (pid1 < 0) {
+               rperror("fork server");
+               exit(2);
        }
-       read(fds[0], &status2, sizeof(status2));
        if (!(pid2 = fork())) {
-               setpgrp();
                role = CLIENT;
-               client(fds[0]);
+               client(fds[0]); // noreturn
+       } else if (pid2 < 0) {
+               rperror("fork client");
+               exit(2);
        }
-       waitpid(pid2, &status2, 0);
+       while (waitpid(pid2, &status2, 0) < 0 && errno == EINTR);
        kill(pid1, 15);
-       waitpid(pid1, 0, 0);
+       while (waitpid(pid1, 0, 0) < 0 && errno == EINTR);
 
        close(fds[0]);
        close(fds[1]);
 
-       if (WIFEXITED(status2)) {
+       if (!WIFSIGNALED(status2) && WEXITSTATUS(status2) != 3) {
                return !!WEXITSTATUS(status2);
        } else {
-               return 2;
+               return 3;
        }
 }
 
-static int permutations2[2][2]
-       = { { 0, 1 }, { 1, 0 } };
-static const char* permutations2names[2]
-       = { "01", "10" };
-static int permutations3[6][3]
-       = { { 0, 1, 2 }, { 0, 2, 1 },
-               { 1, 0, 2 }, { 1, 2, 0 },
-               { 2, 0, 1 }, { 2, 1, 0 } };
-static const char* permutations3names[6]
-       = { "012", "021", "102", "120", "201", "210" };
 static filter_fn filters[8]
        = { filter_packet_ServerHello,
                filter_packet_ServerKeyExchange,
@@ -606,38 +773,54 @@ static filter_fn filters[8]
                filter_packet_ClientFinished,
                filter_packet_ServerChangeCipherSpec,
                filter_packet_ServerFinished };
-static const char* filter_names[8]
-       = { "SHello",
-               "SKeyExchange",
-               "SHelloDone",
-               "CKeyExchange",
-               "CChangeCipherSpec",
-               "CFinished",
-               "SChangeCipherSpec",
-               "SFinished" };
 
-static
-int run_one_test(int dropMode, int serverFinishedPermute, int 
serverHelloPermute, int clientFinishedPermute)
+static filter_fn filters_full[12]
+       = { filter_packet_ServerHello,
+               filter_packet_ServerCertificate,
+               filter_packet_ServerKeyExchange,
+               filter_packet_ServerCertificateRequest,
+               filter_packet_ServerHelloDone,
+               filter_packet_ClientCertificate,
+               filter_packet_ClientKeyExchange,
+               filter_packet_ClientCertificateVerify,
+               filter_packet_ClientChangeCipherSpec,
+               filter_packet_ClientFinished,
+               filter_packet_ServerChangeCipherSpec,
+               filter_packet_ServerFinished };
+
+static int run_one_test(int dropMode, int serverFinishedPermute, int 
serverHelloPermute, int clientFinishedPermute)
 {
        int fnIdx = 0;
-       int filterIdx, res;
-       run_id = ((dropMode * 2 + serverFinishedPermute) * 6 + 
serverHelloPermute) * 6 + clientFinishedPermute;
+       int res, filterIdx;
+       filter_fn* local_filters = full ? filters_full : filters;
+       const char** local_filter_names = full ? filter_names_full : 
filter_names;
+       const char** permutation_namesX = full ? permutation_names5 : 
permutation_names3;
+       int filter_count = full ? 12 : 8;
+       run_id = ((dropMode * 2 + serverFinishedPermute) * (full ? 120 : 6) + 
serverHelloPermute) * (full ? 120 : 6) + clientFinishedPermute;
 
        filter_clear_state();
 
-       filter_chain[fnIdx++] = filter_permute_ServerHello;
-       state_permute_ServerHello.order = permutations3[serverHelloPermute];
+       if (full) {
+               filter_chain[fnIdx++] = filter_permute_ServerHelloFull;
+               state_permute_ServerHelloFull.order = 
permutations5[serverHelloPermute];
+
+               filter_chain[fnIdx++] = filter_permute_ClientFinishedFull;
+               state_permute_ClientFinishedFull.order = 
permutations5[clientFinishedPermute];
+       } else {
+               filter_chain[fnIdx++] = filter_permute_ServerHello;
+               state_permute_ServerHello.order = 
permutations3[serverHelloPermute];
+
+               filter_chain[fnIdx++] = filter_permute_ClientFinished;
+               state_permute_ClientFinished.order = 
permutations3[clientFinishedPermute];
+       }
 
        filter_chain[fnIdx++] = filter_permute_ServerFinished;
        state_permute_ServerFinished.order = 
permutations2[serverFinishedPermute];
-       
-       filter_chain[fnIdx++] = filter_permute_ClientFinished;
-       state_permute_ClientFinished.order = 
permutations3[clientFinishedPermute];
 
        if (dropMode) {
-               for (filterIdx = 0; filterIdx < 8; filterIdx++) {
+               for (filterIdx = 0; filterIdx < filter_count; filterIdx++) {
                        if (dropMode & (1 << filterIdx)) {
-                               filter_chain[fnIdx++] = filters[filterIdx];
+                               filter_chain[fnIdx++] = 
local_filters[filterIdx];
                        }
                }
        }
@@ -655,152 +838,306 @@ int run_one_test(int dropMode, int 
serverFinishedPermute, int serverHelloPermute
                case 2:
                        fprintf(stdout, "%i !! ", run_id);
                        break;
+               case 3:
+                       fprintf(stdout, "%i TT ", run_id);
+                       break;
        }
 
-       fprintf(stdout, "SHello(%s), ", permutations3names[serverHelloPermute]);
-       fprintf(stdout, "SFinished(%s), ", 
permutations2names[serverFinishedPermute]);
-       fprintf(stdout, "CFinished(%s) :- ", 
permutations3names[clientFinishedPermute]);
+       fprintf(stdout, "SHello(%s), ", permutation_namesX[serverHelloPermute]);
+       fprintf(stdout, "SFinished(%s), ", 
permutation_names2[serverFinishedPermute]);
+       fprintf(stdout, "CFinished(%s) :- ", 
permutation_namesX[clientFinishedPermute]);
        if (dropMode) {
-               for (filterIdx = 0; filterIdx < 8; filterIdx++) {
+               for (filterIdx = 0; filterIdx < filter_count; filterIdx++) {
                        if (dropMode & (1 << filterIdx)) {
                                if (dropMode & ((1 << filterIdx) - 1)) {
                                        fprintf(stdout, ", ");
                                }
-                               fprintf(stdout, "%s", filter_names[filterIdx]);
+                               fprintf(stdout, "%s", 
local_filter_names[filterIdx]);
                        }
                }
        }
        fprintf(stdout, "\n");
 
-       if (res && debug) {
-               return 1;
-       } else {
-               return 0;
+       return res;
+}
+
+static int run_test_by_id(int id)
+{
+       int pscale = full ? 120 : 6;
+       int dropMode, serverFinishedPermute, serverHelloPermute, 
clientFinishedPermute;
+
+       clientFinishedPermute = id % pscale;
+       id /= pscale;
+
+       serverHelloPermute = id % pscale;
+       id /= pscale;
+
+       serverFinishedPermute = id % 2;
+       id /= 2;
+
+       dropMode = id;
+
+       return run_one_test(dropMode, serverFinishedPermute, 
serverHelloPermute, clientFinishedPermute);
+}
+
+int* job_pids;
+int job_limit;
+int children = 0;
+
+static void register_child(int pid)
+{
+       int idx;
+
+       children++;
+       for (idx = 0; idx < job_limit; idx++) {
+               if (job_pids[idx] == 0) {
+                       job_pids[idx] = pid;
+                       return;
+               }
        }
 }
 
-static
-void run_tests(int childcount)
+static int wait_children(int child_limit)
+{
+       int fail = 0;
+       int result = 1;
+
+       while (children > child_limit) {
+               int status;
+               int idx;
+               int pid = waitpid(0, &status, 0);
+               if (pid < 0 && errno == ECHILD) {
+                       break;
+               }
+               for (idx = 0; idx < job_limit; idx++) {
+                       if (job_pids[idx] == pid) {
+                               children--;
+                               if (WEXITSTATUS(status)) {
+                                       result = 1;
+                                       if (!run_to_end && !fail) {
+                                               fprintf(stderr, "One test 
failed, waiting for remaining tests\n");
+                                               fail = 1;
+                                               child_limit = 0;
+                                       }
+                               }
+                               job_pids[idx] = 0;
+                               break;
+                       }
+               }
+       }
+
+       if (fail) {
+               exit(1);
+       }
+
+       return result;
+}
+
+static int run_tests_from_id_list(int childcount)
+{
+       int test_id;
+       int ret;
+       int result = 0;
+
+       while ((ret = fscanf(stdin, "%i\n", &test_id)) > 0) {
+               int pid;
+               if (test_id < 0 || test_id > 2 * (full ? 120 * 120 * (1 << 12) 
: 6 * 6 * 256)) {
+                       fprintf(stderr, "Invalid test id %i\n", test_id);
+                       break;
+               }
+               if (!(pid = fork())) {
+                       exit(run_test_by_id(test_id));
+               } else if (pid < 0) {
+                       rperror("fork");
+                       result = 4;
+                       break;
+               } else {
+                       register_child(pid);
+                       result |= wait_children(childcount);
+               }
+       }
+
+       if (ret < 0 && ret != EOF) {
+               fprintf(stderr, "Error reading test id list\n");
+       }
+
+       result |= wait_children(0);
+
+       return result;
+}
+
+static int run_all_tests(int childcount)
 {
-       int children = 0;
        int dropMode, serverFinishedPermute, serverHelloPermute, 
clientFinishedPermute;
+       int result = 0;
 
-       for (dropMode = 0; dropMode != 1 << 8; dropMode++)
+       for (dropMode = 0; dropMode != 1 << (full ? 12 : 8); dropMode++)
        for (serverFinishedPermute = 0; serverFinishedPermute < 2; 
serverFinishedPermute++)
-       for (serverHelloPermute = 0; serverHelloPermute < 6; 
serverHelloPermute++)
-       for (clientFinishedPermute = 0; clientFinishedPermute < 6; 
clientFinishedPermute++) {
-               if (!fork()) {
+       for (serverHelloPermute = 0; serverHelloPermute < (full ? 120 : 6); 
serverHelloPermute++)
+       for (clientFinishedPermute = 0; clientFinishedPermute < (full ? 120 : 
6); clientFinishedPermute++) {
+               int pid;
+               if (!(pid = fork())) {
                        exit(run_one_test(dropMode, serverFinishedPermute, 
serverHelloPermute, clientFinishedPermute));
+               } else if (pid < 0) {
+                       rperror("fork");
+                       result = 4;
+                       break;
                } else {
-                       children++;
-                       while (children >= childcount) {
-                               wait(0);
-                               children--;
-                       }
+                       register_child(pid);
+                       result |= wait_children(childcount);
                }
        }
 
-       while (children > 0) {
-               wait(0);
-               children--;
-       }
+       result |= wait_children(0);
+
+       return result;
 }
 
+// }}}
 
+static int parse_permutation(const char* arg, const char* permutations[], int* 
val)
+{
+       *val = 0;
+       while (permutations[*val]) {
+               if (strcmp(permutations[*val], arg) == 0) {
+                       return 1;
+               } else {
+                       *val += 1;
+               }
+       }
+       return 0;
+}
 
 int main(int argc, const char* argv[])
 {
-int arg;
-
-       setlinebuf(stdout);
-       gnutls_global_init();
-       gnutls_global_set_log_function(logfn);
-       gnutls_global_set_audit_log_function(auditfn);
+       int dropMode = 0;
+       int serverFinishedPermute = 0;
+       int serverHelloPermute = 0;
+       int clientFinishedPermute = 0;
+       int batch = 0;
+       int arg;
 
        nonblock = 0;
        debug = 0;
-
-       if (argc == 1) {
-               run_tests(100);
-       } else {
-               int dropMode = 0;
-               int serverFinishedPermute = 0;
-               int serverHelloPermute = 0;
-               int clientFinishedPermute = 0;
-
-               for (arg = 1; arg < argc; arg++) {
-                       if (strcmp("-shello", argv[arg]) == 0) {
+       timeout_seconds = 120;
+       retransmit_milliseconds = 100;
+       full = 0;
+       run_to_end = 1;
+       job_limit = 1;
+
+#define NEXT_ARG(name) \
+       do { \
+               if (++arg >= argc) { \
+                       fprintf(stderr, "No argument for -" #name "\n"); \
+                       exit(8); \
+               } \
+       } while (0);
+#define FAIL_ARG(name) \
+       do { \
+               fprintf(stderr, "Invalid argument for -" #name "\n"); \
+               exit(8); \
+       } while (0);
+
+       for (arg = 1; arg < argc; arg++) {
+               if (strcmp("-die", argv[arg]) == 0) {
+                       run_to_end = 0;
+               } else if (strcmp("-batch", argv[arg]) == 0) {
+                       batch = 1;
+               } else if (strcmp("-d", argv[arg]) == 0) {
+                       char* end;
+                       int level = strtol(argv[arg+1], &end, 10);
+                       if (*end == '\0') {
+                               debug = level;
                                arg++;
-                               if (arg >= argc) {
-                                       fprintf(stderr, "No arg to -shello\n");
-                                       exit(1);
-                               }
-                               while (serverHelloPermute < 6) {
-                                       if 
(strcmp(permutations3names[serverHelloPermute], argv[arg]) == 0) {
-                                               break;
-                                       }
-                                       serverHelloPermute++;
-                               }
-                               if (serverHelloPermute == 6) {
-                                       fprintf(stderr, "Unknown permutation 
%s\n", argv[arg]);
-                                       exit(1);
-                               }
-                       } else if (strcmp("-d", argv[arg]) == 0) {
+                       } else {
                                debug++;
-                       } else if (strcmp("-nb", argv[arg]) == 0) {
-                               nonblock = 1;
-                       } else if (strcmp("-sfinished", argv[arg]) == 0) {
-                               arg++;
-                               if (arg >= argc) {
-                                       fprintf(stderr, "No arg to 
-sfinished\n");
-                                       exit(1);
-                               }
-                               while (serverFinishedPermute < 2) {
-                                       if 
(strcmp(permutations2names[serverFinishedPermute], argv[arg]) == 0) {
-                                               break;
-                                       }
-                                       serverFinishedPermute++;
-                               }
-                               if (serverFinishedPermute == 2) {
-                                       fprintf(stderr, "Unknown permutation 
%s\n", argv[arg]);
-                                       exit(1);
-                               }
-                       } else if (strcmp("-cfinished", argv[arg]) == 0) {
-                               arg++;
-                               if (arg >= argc) {
-                                       fprintf(stderr, "No arg to 
-cfinished\n");
-                                       exit(1);
-                               }
-                               while (clientFinishedPermute < 6) {
-                                       if 
(strcmp(permutations3names[clientFinishedPermute], argv[arg]) == 0) {
-                                               break;
-                                       }
-                                       clientFinishedPermute++;
-                               }
-                               if (clientFinishedPermute == 6) {
-                                       fprintf(stderr, "Unknown permutation 
%s\n", argv[arg]);
-                                       exit(1);
-                               }
+                       }
+               } else if (strcmp("-nb", argv[arg]) == 0) {
+                       nonblock = 1;
+               } else if (strcmp("-timeout", argv[arg]) == 0) {
+                       char* end;
+                       int val;
+
+                       NEXT_ARG(timeout);
+                       val = strtol(argv[arg], &end, 10);
+                       if (*end == '\0') {
+                               timeout_seconds = val;
                        } else {
-                               int drop;
-                               for (drop = 0; drop < 8; drop++) {
-                                       if (strcmp(filter_names[drop], 
argv[arg]) == 0) {
-                                               dropMode |= (1 << drop);
-                                               break;
-                                       }
-                               }
-                               if (drop == 8) {
-                                       fprintf(stderr, "Unknown packet %s\n", 
argv[arg]);
-                                       exit(8);
+                               FAIL_ARG(timeout);
+                       }
+               } else if (strcmp("-retransmit", argv[arg]) == 0) {
+                       char* end;
+                       int val;
+
+                       NEXT_ARG(retransmit);
+                       val = strtol(argv[arg], &end, 10);
+                       if (*end == '\0') {
+                               retransmit_milliseconds = val;
+                       } else {
+                               FAIL_ARG(retransmit);
+                       }
+               } else if (strcmp("-j", argv[arg]) == 0) {
+                       char* end;
+                       int val;
+
+                       NEXT_ARG(timeout);
+                       val = strtol(argv[arg], &end, 10);
+                       if (*end == '\0') {
+                               job_limit = val;
+                       } else {
+                               FAIL_ARG(j);
+                       }
+               } else if (strcmp("-full", argv[arg]) == 0) {
+                       full = 1;
+               } else if (strcmp("-shello", argv[arg]) == 0) {
+                       NEXT_ARG(shello);
+                       if (!parse_permutation(argv[arg], full ? 
permutation_names5 : permutation_names3, &serverHelloPermute)) {
+                               FAIL_ARG(shell);
+                       }
+               } else if (strcmp("-sfinished", argv[arg]) == 0) {
+                       NEXT_ARG(sfinished);
+                       if (!parse_permutation(argv[arg], permutation_names2, 
&serverFinishedPermute)) {
+                               FAIL_ARG(sfinished);
+                       }
+               } else if (strcmp("-cfinished", argv[arg]) == 0) {
+                       NEXT_ARG(cfinished);
+                       if (!parse_permutation(argv[arg], full ? 
permutation_names5 : permutation_names3, &clientFinishedPermute)) {
+                               FAIL_ARG(cfinished);
+                       }
+               } else {
+                       int drop;
+                       int filter_count = full ? 12 : 8;
+                       const char** local_filter_names = full ? 
filter_names_full : filter_names;
+                       for (drop = 0; drop < filter_count; drop++) {
+                               if (strcmp(local_filter_names[drop], argv[arg]) 
== 0) {
+                                       dropMode |= (1 << drop);
+                                       break;
                                }
                        }
+                       if (drop == filter_count) {
+                               fprintf(stderr, "Unknown packet %s\n", 
argv[arg]);
+                               exit(8);
+                       }
                }
-               
-               if (debug)
-                       gnutls_global_set_log_level(99);
-               run_one_test(dropMode, serverFinishedPermute, 
serverHelloPermute, clientFinishedPermute);
        }
 
-       gnutls_global_deinit();
+       setlinebuf(stdout);
+       gnutls_global_init();
+       cred_init();
+       gnutls_global_set_log_function(logfn);
+       gnutls_global_set_audit_log_function(auditfn);
+       gnutls_global_set_log_level(debug);
+
+       if (dropMode || serverFinishedPermute || serverHelloPermute || 
clientFinishedPermute) {
+               return run_one_test(dropMode, serverFinishedPermute, 
serverHelloPermute, clientFinishedPermute);
+       } else {
+               job_pids = calloc(sizeof(int), job_limit);
+               if (batch) {
+                       return run_tests_from_id_list(job_limit);
+               } else {
+                       return run_all_tests(job_limit);
+               }
+       }
 }
 
+// vim: foldmethod=marker


hooks/post-receive
-- 
GNU gnutls



reply via email to

[Prev in Thread] Current Thread [Next in Thread]