summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--lib/gnutls_buffers.c31
-rw-r--r--lib/gnutls_dtls.c107
-rw-r--r--lib/gnutls_int.h20
-rw-r--r--lib/gnutls_state.c8
-rw-r--r--lib/includes/gnutls/gnutls.h.in2
-rw-r--r--lib/system.h17
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/eagain-common.h144
-rw-r--r--tests/mini-eagain-dtls.c219
-rw-r--r--tests/mini-eagain.c169
-rw-r--r--tests/utils.c2
12 files changed, 564 insertions, 162 deletions
diff --git a/.gitignore b/.gitignore
index d286453d44..4b94e31cb9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -412,6 +412,8 @@ src/psktool
src/srptool
stamp-h1
tags
+tests/rng-fork
+tests/mini-eagain-dtls
tests/*/out
tests/Makefile
tests/Makefile.in
@@ -446,6 +448,7 @@ tests/mpi
tests/netconf-psk
tests/nul-in-x509-names
tests/openpgp-auth
+tests/openpgp-auth2
tests/openpgp-certs/Makefile
tests/openpgp-certs/Makefile.in
tests/openpgp-keyring
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c
index 778af8d0bc..39657a0ed6 100644
--- a/lib/gnutls_buffers.c
+++ b/lib/gnutls_buffers.c
@@ -54,6 +54,7 @@
#include <system.h>
#include <gnutls_constate.h> /* gnutls_epoch_get */
#include <errno.h>
+#include <system.h>
#ifndef EAGAIN
#define EAGAIN EWOULDBLOCK
@@ -61,7 +62,7 @@
/* this is the maximum number of messages allowed to queue.
*/
-#define MAX_QUEUE 16
+#define MAX_QUEUE 32
/* Buffers received packets of type APPLICATION DATA and
* HANDSHAKE DATA.
@@ -553,7 +554,7 @@ _gnutls_io_write_flush (gnutls_session_t session)
tosend += msg.size;
/* we buffer up to MAX_QUEUE messages */
- if (i >= sizeof (iovec) / sizeof (iovec[0]))
+ if (i >= MAX_QUEUE)
{
gnutls_assert ();
return GNUTLS_E_INTERNAL_ERROR;
@@ -676,7 +677,6 @@ _gnutls_handshake_io_write_flush (gnutls_session_t session)
}
return _gnutls_io_write_flush (session);
-
}
@@ -914,7 +914,7 @@ handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer;
{
if (session->internals.handshake_recv_buffer_size == 0 ||
(session->internals.dtls.hsk_read_seq != recv_buf[LAST_ELEMENT].sequence))
- return gnutls_assert_val(GNUTLS_E_AGAIN);
+ goto timeout;
if (htype != recv_buf[LAST_ELEMENT].htype)
{
@@ -932,7 +932,7 @@ handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer;
return 0;
}
else
- return gnutls_assert_val(GNUTLS_E_AGAIN);
+ goto timeout;
}
else /* TLS */
{
@@ -949,7 +949,18 @@ handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer;
return 0;
}
else
- return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+ }
+
+timeout:
+ if (time(0)-session->internals.dtls.handshake_start_time > session->internals.dtls.total_timeout/1000)
+ return gnutls_assert_val(GNUTLS_E_TIMEDOUT);
+ else
+ {
+ if (session->internals.dtls.blocking != 0)
+ millisleep(50);
+
+ return gnutls_assert_val(GNUTLS_E_AGAIN);
}
}
@@ -1108,7 +1119,7 @@ next:
while(session->internals.handshake_recv_buffer_size > 0 &&
recv_buf[LAST_ELEMENT].sequence < session->internals.dtls.hsk_read_seq)
{
- _gnutls_audit_log("Discarded replayed handshake packet with sequence %d\n", tmp.sequence);
+ _gnutls_audit_log("Discarded replayed handshake packet with sequence %d\n", recv_buf[LAST_ELEMENT].sequence);
_gnutls_handshake_buffer_clear(&recv_buf[LAST_ELEMENT]);
session->internals.handshake_recv_buffer_size--;
}
@@ -1128,8 +1139,10 @@ _gnutls_handshake_io_recv_int (gnutls_session_t session,
int ret;
ret = get_last_packet(session, htype, hsk);
- if (ret >= 0)
- return ret;
+ if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+ {
+ return gnutls_assert_val(ret);
+ }
/* try using the already existing records before
* trying to receive.
diff --git a/lib/gnutls_dtls.c b/lib/gnutls_dtls.c
index 076be8c643..89dc0661bb 100644
--- a/lib/gnutls_dtls.c
+++ b/lib/gnutls_dtls.c
@@ -1,7 +1,8 @@
/*
- * Copyright (C) 2009 Free Software Foundation (copyright assignement pending)
+ * Copyright (C) 2009,2011 Free Software Foundation
*
- * Author: Jonathan Bastien-Filiatrault
+ * Authors: Jonathan Bastien-Filiatrault
+ * Nikos Mavrogiannopoulos
*
* This file is part of GNUTLS.
*
@@ -155,6 +156,10 @@ time_t now = time(0);
}
+#define UPDATE_TIMER \
+ session->internals.dtls.actual_retrans_timeout *= 2; \
+ session->internals.dtls.actual_retrans_timeout %= MAX_DTLS_TIMEOUT
+
/* This function transmits the flight that has been previously
* buffered.
*
@@ -170,13 +175,52 @@ int ret;
mbuffer_head_st *const send_buffer =
&session->internals.handshake_send_buffer;
mbuffer_st *cur;
- unsigned int total_timeout = 0;
- unsigned int timeout = session->internals.dtls.retrans_timeout;
gnutls_handshake_description_t last_type = 0;
+ time_t now = time(0);
+
+ /* If we have already sent a flight and we are operating in a
+ * non blocking way, check if it is time to retransmit or just
+ * return.
+ */
+ if (session->internals.dtls.flight_init != 0 && session->internals.dtls.blocking == 0)
+ {
+ /* just in case previous run was interrupted */
+ ret = _gnutls_io_write_flush (session);
+
+ if (session->internals.dtls.last_flight == 0)
+ {
+ /* check for ACK */
+ ret = _gnutls_io_check_recv(session, 0);
+ if (ret == GNUTLS_E_TIMEDOUT)
+ {
+ /* if no retransmission is required yet just return
+ */
+ if (now-session->internals.dtls.handshake_start_time < session->internals.dtls.actual_retrans_timeout)
+ {
+ session->internals.dtls.handshake_last_call = now;
+ goto nb_timeout;
+ }
+ }
+ else /* received ack */
+ {
+ ret = 0;
+ goto cleanup;
+ }
+ }
+ else
+ return ret;
+ }
+
do
{
- _gnutls_dtls_log ("DTLS[%p]: Start of flight transmission.\n", session);
+ if (now-session->internals.dtls.handshake_start_time >= session->internals.dtls.total_timeout/1000)
+ {
+ ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
+ goto cleanup;
+ }
+
+ _gnutls_dtls_log ("DTLS[%p]: %sstart of flight transmission.\n", session, (session->internals.dtls.flight_init == 0)?"":"re-");
for (cur = send_buffer->head;
cur != NULL; cur = cur->next)
@@ -185,12 +229,32 @@ int ret;
last_type = cur->htype;
}
+ if (session->internals.dtls.flight_init == 0)
+ {
+ session->internals.dtls.flight_init = 1;
+ session->internals.dtls.handshake_last_call = now;
+ session->internals.dtls.actual_retrans_timeout = session->internals.dtls.retrans_timeout;
+
+ if (last_type == GNUTLS_HANDSHAKE_FINISHED && _dtls_is_async(session))
+ {
+ /* we cannot do anything here. We just return 0 and
+ * if a retransmission occurs because peer didn't receive it
+ * we rely on the record layer calling this function again.
+ */
+ session->internals.dtls.last_flight = 1;
+ }
+ else
+ session->internals.dtls.last_flight = 0;
+
+
+ }
+
ret = _gnutls_io_write_flush (session);
if (ret < 0)
return gnutls_assert_val(ret);
/* last message in handshake -> no ack */
- if (last_type == GNUTLS_HANDSHAKE_FINISHED && _dtls_is_async(session))
+ if (session->internals.dtls.last_flight != 0)
{
/* we cannot do anything here. We just return 0 and
* if a retransmission occurs because peer didn't receive it
@@ -200,17 +264,21 @@ int ret;
}
else /* all other messages -> implicit ack (receive of next flight) */
{
- ret = _gnutls_io_check_recv(session, timeout);
+ if (session->internals.dtls.blocking != 0)
+ ret = _gnutls_io_check_recv(session, session->internals.dtls.actual_retrans_timeout);
+ else
+ {
+ ret = _gnutls_io_check_recv(session, 0);
+ if (ret == GNUTLS_E_TIMEDOUT)
+ {
+ UPDATE_TIMER;
+ goto nb_timeout;
+ }
+ }
}
- total_timeout += timeout;
- timeout *= 2;
- timeout %= MAX_DTLS_TIMEOUT;
-
- if (total_timeout >= session->internals.dtls.total_timeout) {
- ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
- goto cleanup;
- }
+ UPDATE_TIMER;
+ now = time(0);
} while(ret == GNUTLS_E_TIMEDOUT);
if (ret < 0)
@@ -219,15 +287,20 @@ int ret;
goto cleanup;
}
- _gnutls_dtls_log ("DTLS[%p]: End of flight transmission.\n", session);
ret = 0;
cleanup:
+ _gnutls_dtls_log ("DTLS[%p]: End of flight transmission.\n", session);
+
+ session->internals.dtls.flight_init = 0;
drop_usage_count(session, send_buffer);
_mbuffer_head_clear(send_buffer);
/* SENDING -> WAITING state transition */
return ret;
+
+nb_timeout:
+ return GNUTLS_E_AGAIN;
}
#define window_table session->internals.dtls.record_sw
@@ -352,7 +425,7 @@ int i, offset = 0;
void gnutls_dtls_set_timeouts (gnutls_session_t session, unsigned int retrans_timeout,
unsigned int total_timeout)
{
- session->internals.dtls.retrans_timeout = retrans_timeout;
+ session->internals.dtls.retrans_timeout = retrans_timeout;
session->internals.dtls.total_timeout = total_timeout;
}
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index c44b9cab33..b11df42fcf 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -581,17 +581,30 @@ typedef struct
/* For DTLS handshake fragmentation and reassembly. */
uint16_t hsk_write_seq;
- int hsk_read_seq;
+ unsigned int hsk_read_seq;
uint16_t mtu;
+ /* a flight transmission is in process */
+ unsigned int flight_init:1;
+ /* whether this is the last flight in the protocol */
+ unsigned int last_flight:1;
unsigned int retrans_timeout;
unsigned int total_timeout;
unsigned int hsk_hello_verify_requests;
uint64_t record_sw[DTLS_RECORD_WINDOW_SIZE];
- int record_sw_size;
-
+ unsigned int record_sw_size;
+
+ /* non blocking stuff variables */
+ unsigned int blocking:1;
+ /* starting time of current handshake */
+ time_t handshake_start_time;
+ /* time in seconds of the last handshake call */
+ time_t handshake_last_call;
+ /* The actual retrans_timeout for the next message (e.g. doubled or so) */
+ unsigned int actual_retrans_timeout;
+
/* timers to handle async handshake after gnutls_handshake()
* has terminated. Required to handle retransmissions.
*/
@@ -850,7 +863,6 @@ struct gnutls_session_int
};
-
/* functions
*/
void _gnutls_set_current_version (gnutls_session_t session,
diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c
index b268971cb0..f14927db18 100644
--- a/lib/gnutls_state.c
+++ b/lib/gnutls_state.c
@@ -258,6 +258,7 @@ _gnutls_handshake_internal_state_init (gnutls_session_t session)
session->internals.dtls.hsk_read_seq = 0;
session->internals.dtls.hsk_write_seq = 0;
+ session->internals.dtls.handshake_start_time = time(0);
}
void
@@ -380,6 +381,13 @@ gnutls_init (gnutls_session_t * session, unsigned int flags)
(*session)->internals.dtls.record_sw_size = 0;
}
+ else
+ (*session)->internals.transport = GNUTLS_STREAM;
+
+ if (flags & GNUTLS_NONBLOCK)
+ (*session)->internals.dtls.blocking = 0;
+ else
+ (*session)->internals.dtls.blocking = 1;
return 0;
}
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 674ca60532..821002135b 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -284,12 +284,14 @@ extern "C"
* @GNUTLS_SERVER: Connection end is a server.
* @GNUTLS_CLIENT: Connection end is a client.
* @GNUTLS_DATAGRAM: Connection is datagram oriented (DTLS).
+ * @GNUTLS_NONBLOCK: Connection should not block (DTLS).
*
* Enumeration of different TLS connection end types.
*/
#define GNUTLS_SERVER 1
#define GNUTLS_CLIENT (1<<1)
#define GNUTLS_DATAGRAM (1<<2)
+#define GNUTLS_NONBLOCK (1<<3)
/**
* gnutls_alert_level_t:
diff --git a/lib/system.h b/lib/system.h
index b1f556557a..849090ee3a 100644
--- a/lib/system.h
+++ b/lib/system.h
@@ -4,7 +4,9 @@
#include <gnutls_int.h>
#ifndef _WIN32
-#include <sys/uio.h> /* for writev */
+# include <sys/uio.h> /* for writev */
+#else
+# include <windows.h> /* for Sleep */
#endif
int system_errno (gnutls_transport_ptr_t);
@@ -35,4 +37,17 @@ ssize_t system_read_peek (gnutls_transport_ptr_t ptr, void *data,
int _gnutls_atfork (void (*prepare) (void), void (*parent) (void),
void (*child) (void));
+static inline void millisleep(unsigned int ms)
+{
+#ifdef _WIN32
+ Sleep(ms);
+#else
+struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = ms*1000*1000;
+
+ nanosleep(&ts, NULL);
+#endif
+}
+
#endif /* SYSTEM_H */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 2d5e2d4d23..cef6bd66ec 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -27,7 +27,7 @@ if ENABLE_OPENPGP
SUBDIRS += openpgp-certs
endif
-EXTRA_DIST = libgcrypt.supp
+EXTRA_DIST = libgcrypt.supp eagain-common.h
AM_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS)
AM_CPPFLAGS = \
@@ -60,7 +60,7 @@ ctests = simple gc set_pkcs12_cred certder certuniqueid mpi \
crq_key_id x509sign-verify cve-2009-1415 cve-2009-1416 \
crq_apis init_roundtrip pkcs12_s2k_pem dn2 mini-eagain \
nul-in-x509-names x509_altname pkcs12_encode mini-x509 \
- mini-x509-rehandshake rng-fork #gendh
+ mini-x509-rehandshake rng-fork mini-eagain-dtls #gendh
if ENABLE_OPENSSL
ctests += openssl
diff --git a/tests/eagain-common.h b/tests/eagain-common.h
new file mode 100644
index 0000000000..5fb436e453
--- /dev/null
+++ b/tests/eagain-common.h
@@ -0,0 +1,144 @@
+#define min(x,y) ((x)<(y)?(x):(y))
+//#define EAGAIN_DEBUG
+#define RANDOMIZE
+
+static char to_server[64*1024];
+static size_t to_server_len = 0;
+
+static char to_client[64*1024];
+static size_t to_client_len = 0;
+
+#ifdef RANDOMIZE
+#define RETURN_RND_EAGAIN() \
+ static unsigned char rnd = 0; \
+ if (rnd++ % 2 == 0) \
+ { \
+ gnutls_transport_set_global_errno (EAGAIN); \
+ return -1; \
+ }
+#else
+#define RETURN_RND_EAGAIN()
+#endif
+
+static ssize_t
+client_push (gnutls_transport_ptr_t tr, const void *data, size_t len)
+{
+ size_t newlen;
+ RETURN_RND_EAGAIN();
+
+ len = min(len, sizeof(to_server)-to_server_len);
+
+ newlen = to_server_len + len;
+ memcpy (to_server + to_server_len, data, len);
+ to_server_len = newlen;
+#ifdef EAGAIN_DEBUG
+ fprintf(stderr, "eagain: pushed %d bytes to server (avail: %d)\n", (int)len, (int)to_server_len);
+#endif
+ return len;
+}
+
+static ssize_t
+client_pull (gnutls_transport_ptr_t tr, void *data, size_t len)
+{
+ RETURN_RND_EAGAIN();
+
+ if (to_client_len == 0)
+ {
+#ifdef EAGAIN_DEBUG
+ fprintf(stderr, "eagain: Not enough data by server (asked for: %d, have: %d)\n", (int)len, (int)to_client_len);
+#endif
+ gnutls_transport_set_global_errno (EAGAIN);
+ return -1;
+ }
+
+ len = min(len, to_client_len);
+
+ memcpy (data, to_client, len);
+
+ memmove (to_client, to_client + len, to_client_len - len);
+ to_client_len -= len;
+#ifdef EAGAIN_DEBUG
+ fprintf(stderr, "eagain: pulled %d bytes by client (avail: %d)\n", (int)len, (int)to_client_len);
+#endif
+ return len;
+}
+
+static ssize_t
+server_pull (gnutls_transport_ptr_t tr, void *data, size_t len)
+{
+ //success ("server_pull len %d has %d\n", len, to_server_len);
+ RETURN_RND_EAGAIN();
+
+ if (to_server_len == 0)
+ {
+#ifdef EAGAIN_DEBUG
+ fprintf(stderr, "eagain: Not enough data by client (asked for: %d, have: %d)\n", (int)len, (int)to_server_len);
+#endif
+ gnutls_transport_set_global_errno (EAGAIN);
+ return -1;
+ }
+
+ len = min(len, to_server_len);
+#ifdef EAGAIN_DEBUG
+ fprintf(stderr, "eagain: pulled %d bytes by server (avail: %d)\n", (int)len, (int)to_server_len);
+#endif
+ memcpy (data, to_server, len);
+
+ memmove (to_server, to_server + len, to_server_len - len);
+ to_server_len -= len;
+
+ return len;
+}
+
+static ssize_t
+server_push (gnutls_transport_ptr_t tr, const void *data, size_t len)
+{
+ size_t newlen;
+ RETURN_RND_EAGAIN();
+
+// hexprint (data, len);
+
+ len = min(len, sizeof(to_client)-to_client_len);
+
+ newlen = to_client_len + len;
+ memcpy (to_client + to_client_len, data, len);
+ to_client_len = newlen;
+#ifdef EAGAIN_DEBUG
+ fprintf(stderr, "eagain: pushed %d bytes to client (avail: %d)\n", (int)len, (int)to_client_len);
+#endif
+
+ return len;
+}
+
+/* inline is used to avoid a gcc warning if used in mini-eagain */
+inline static int server_pull_timeout_func(gnutls_transport_ptr_t ptr, unsigned int ms)
+{
+int ret;
+
+ if (to_server_len > 0)
+ ret = 1; /* available data */
+ else
+ ret = 0; /* timeout */
+
+#ifdef EAGAIN_DEBUG
+ fprintf(stderr, "eagain: server_pull_timeout: %d\n", ret);
+#endif
+
+ return ret;
+}
+
+inline static int client_pull_timeout_func(gnutls_transport_ptr_t ptr, unsigned int ms)
+{
+int ret;
+
+ if (to_client_len > 0)
+ ret = 1;
+ else
+ ret = 0;
+
+#ifdef EAGAIN_DEBUG
+ fprintf(stderr, "eagain: client_pull_timeout: %d\n", ret);
+#endif
+
+ return ret;
+}
diff --git a/tests/mini-eagain-dtls.c b/tests/mini-eagain-dtls.c
new file mode 100644
index 0000000000..0b3ed4791d
--- /dev/null
+++ b/tests/mini-eagain-dtls.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2008, 2010 Free Software Foundation, Inc.
+ *
+ * Author: Simon Josefsson, Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * GnuTLS is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuTLS is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GnuTLS; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include "utils.h"
+#include "eagain-common.h"
+
+static void
+tls_log_func (int level, const char *str)
+{
+ fprintf (stderr, "|<%d>| %s", level, str);
+}
+
+static int handshake = 0;
+
+#define MAX_BUF 1024
+#define MSG "Hello TLS, and hi and how are you and more data here... and more... and even more and even more more data..."
+
+void
+doit (void)
+{
+ /* Server stuff. */
+ gnutls_anon_server_credentials_t s_anoncred;
+ const gnutls_datum_t p3 = { (char *) pkcs3, strlen (pkcs3) };
+ static gnutls_dh_params_t dh_params;
+ gnutls_session_t server;
+ int sret, cret;
+ /* Client stuff. */
+ gnutls_anon_client_credentials_t c_anoncred;
+ gnutls_session_t client;
+ /* Need to enable anonymous KX specifically. */
+ char buffer[MAX_BUF + 1];
+ ssize_t ns;
+ int ret, transferred = 0, msglen;
+
+ /* General init. */
+ gnutls_global_init ();
+ gnutls_global_set_log_function (tls_log_func);
+ if (debug)
+ gnutls_global_set_log_level (99);
+
+ /* Init server */
+ gnutls_anon_allocate_server_credentials (&s_anoncred);
+ gnutls_dh_params_init (&dh_params);
+ gnutls_dh_params_import_pkcs3 (dh_params, &p3, GNUTLS_X509_FMT_PEM);
+ gnutls_anon_set_server_dh_params (s_anoncred, dh_params);
+ gnutls_init (&server, GNUTLS_SERVER|GNUTLS_DATAGRAM|GNUTLS_NONBLOCK);
+ ret = gnutls_priority_set_direct (server, "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-DH", NULL);
+ if (ret < 0)
+ exit(1);
+ gnutls_credentials_set (server, GNUTLS_CRD_ANON, s_anoncred);
+ gnutls_dh_set_prime_bits (server, 1024);
+ gnutls_transport_set_push_function (server, server_push);
+ gnutls_transport_set_pull_function (server, server_pull);
+ gnutls_transport_set_pull_timeout_function (server, server_pull_timeout_func);
+
+ /* Init client */
+ gnutls_anon_allocate_client_credentials (&c_anoncred);
+ gnutls_init (&client, GNUTLS_CLIENT|GNUTLS_DATAGRAM|GNUTLS_NONBLOCK);
+ cret = gnutls_priority_set_direct (client, "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-DH", NULL);
+ if (cret < 0)
+ exit(1);
+ gnutls_credentials_set (client, GNUTLS_CRD_ANON, c_anoncred);
+ gnutls_transport_set_push_function (client, client_push);
+ gnutls_transport_set_pull_function (client, client_pull);
+ gnutls_transport_set_pull_timeout_function (client, client_pull_timeout_func);
+
+ handshake = 1;
+ sret = cret = GNUTLS_E_AGAIN;
+ do
+ {
+ if (cret == GNUTLS_E_AGAIN)
+ {
+ //success ("loop invoking client:\n");
+ cret = gnutls_handshake (client);
+ //success ("client %d: %s\n", cret, gnutls_strerror (cret));
+ }
+
+ if (sret == GNUTLS_E_AGAIN)
+ {
+ //success ("loop invoking server:\n");
+ sret = gnutls_handshake (server);
+ //success ("server %d: %s\n", sret, gnutls_strerror (sret));
+ }
+ }
+ while ((cret == GNUTLS_E_AGAIN && gnutls_error_is_fatal(sret)==0) || (sret == GNUTLS_E_AGAIN && gnutls_error_is_fatal(cret)==0));
+
+ if (cret < 0 || sret < 0)
+ {
+ fprintf(stderr, "client: %s\n", gnutls_strerror(cret));
+ fprintf(stderr, "server: %s\n", gnutls_strerror(sret));
+ fail("Handshake failed\n");
+ exit(1);
+ }
+
+ handshake = 0;
+ if (debug)
+ success ("Handshake established\n");
+
+ do
+ {
+ ret = gnutls_record_send (client, MSG, strlen (MSG));
+ }
+ while(ret == GNUTLS_E_AGAIN);
+ //success ("client: sent %d\n", ns);
+
+ do
+ {
+ //success("transferred: %d\n", transferred);
+
+ do
+ {
+ ret = gnutls_record_recv (server, buffer, MAX_BUF);
+ }
+ while(ret == GNUTLS_E_AGAIN);
+
+ if (ret == 0)
+ fail ("server: didn't receive any data\n");
+ else if (ret < 0)
+ {
+ // if (debug)
+ // fputs ("#", stdout);
+ fail ("server: error: %s\n", gnutls_strerror (ret));
+ }
+ else
+ {
+ transferred += ret;
+ // if (debug)
+ // fputs ("*", stdout);
+ }
+
+ msglen = strlen (MSG);
+ do
+ {
+ ns = gnutls_record_send (server, MSG, msglen);
+ }
+ while (ns == GNUTLS_E_AGAIN);
+
+ do
+ {
+ ret = gnutls_record_recv (client, buffer, MAX_BUF);
+ }
+ while(ret == GNUTLS_E_AGAIN);
+
+
+ if (ret == 0)
+ {
+ fail ("client: Peer has closed the TLS connection\n");
+ }
+ else if (ret < 0)
+ {
+ if (debug)
+ fputs ("!", stdout);
+ fail ("client: Error: %s\n", gnutls_strerror (ret));
+ }
+ else
+ {
+ if (msglen != ret || memcmp (buffer, MSG, msglen) != 0)
+ {
+ fail ("client: Transmitted data do not match\n");
+ }
+
+ /* echo back */
+ do
+ {
+ ns = gnutls_record_send (client, buffer, msglen);
+ }
+ while (ns == GNUTLS_E_AGAIN);
+
+ transferred += ret;
+ if (debug)
+ fputs (".", stdout);
+ }
+ }
+ while (transferred < 70000);
+ if (debug)
+ fputs ("\n", stdout);
+
+ gnutls_bye (client, GNUTLS_SHUT_WR);
+ gnutls_bye (server, GNUTLS_SHUT_WR);
+
+ gnutls_deinit (client);
+ gnutls_deinit (server);
+
+ gnutls_anon_free_client_credentials (c_anoncred);
+ gnutls_anon_free_server_credentials (s_anoncred);
+
+ gnutls_dh_params_deinit (dh_params);
+
+ gnutls_global_deinit ();
+}
diff --git a/tests/mini-eagain.c b/tests/mini-eagain.c
index 9bb7e2c321..3b2ea2951c 100644
--- a/tests/mini-eagain.c
+++ b/tests/mini-eagain.c
@@ -32,6 +32,7 @@
#include <gnutls/crypto.h>
#include "utils.h"
+#include "eagain-common.h"
static void
tls_log_func (int level, const char *str)
@@ -41,109 +42,6 @@ tls_log_func (int level, const char *str)
static int handshake = 0;
-char *to_server;
-size_t to_server_len;
-
-char *to_client;
-size_t to_client_len;
-
-
-static ssize_t
-client_pull (gnutls_transport_ptr_t tr, void *data, size_t len)
-{
-// success ("client_pull len %d has %d\n", len, to_client_len);
- static unsigned char rnd = 0;
-
- if (rnd++ % 2 == 0 || to_client_len < len)
- {
- gnutls_transport_set_global_errno (EAGAIN);
- return -1;
- }
-
- memcpy (data, to_client, len);
-
- memmove (to_client, to_client + len, to_client_len - len);
- to_client_len -= len;
-
- return len;
-}
-
-static ssize_t
-client_push (gnutls_transport_ptr_t tr, const void *data, size_t len)
-{
- char *tmp;
- size_t newlen = to_server_len + len;
- static unsigned char rnd = 0;
-
- if (rnd++ % 2 == 0)
- {
- gnutls_transport_set_global_errno (EAGAIN);
- return -1;
- }
-
- tmp = realloc (to_server, newlen);
- if (!tmp)
- {
- fail ("Memory allocation failure...\n");
- exit (1);
- }
- to_server = tmp;
-
- memcpy (to_server + to_server_len, data, len);
- to_server_len = newlen;
-
- return len;
-}
-
-static ssize_t
-server_pull (gnutls_transport_ptr_t tr, void *data, size_t len)
-{
- //success ("server_pull len %d has %d\n", len, to_server_len);
- static unsigned char rnd = 0;
-
- if (rnd++ % 2 == 0 || to_server_len < len)
- {
- gnutls_transport_set_global_errno (EAGAIN);
- return -1;
- }
-
- memcpy (data, to_server, len);
-
- memmove (to_server, to_server + len, to_server_len - len);
- to_server_len -= len;
-
- return len;
-}
-
-static ssize_t
-server_push (gnutls_transport_ptr_t tr, const void *data, size_t len)
-{
- char *tmp;
- size_t newlen = to_client_len + len;
- static unsigned char rnd = 0;
-
- if (rnd++ % 2 == 0)
- {
- gnutls_transport_set_global_errno (EAGAIN);
- return -1;
- }
-
-// hexprint (data, len);
-
- tmp = realloc (to_client, newlen);
- if (!tmp)
- {
- fail ("Memory allocation failure...\n");
- exit (1);
- }
- to_client = tmp;
-
- memcpy (to_client + to_client_len, data, len);
- to_client_len = newlen;
-
- return len;
-}
-
#define MAX_BUF 1024
#define MSG "Hello TLS, and hi and how are you and more data here... and more... and even more and even more more data..."
@@ -155,11 +53,10 @@ doit (void)
const gnutls_datum_t p3 = { (char *) pkcs3, strlen (pkcs3) };
static gnutls_dh_params_t dh_params;
gnutls_session_t server;
- int sret = GNUTLS_E_AGAIN;
+ int sret, cret;
/* Client stuff. */
gnutls_anon_client_credentials_t c_anoncred;
gnutls_session_t client;
- int cret = GNUTLS_E_AGAIN;
/* Need to enable anonymous KX specifically. */
char buffer[MAX_BUF + 1];
ssize_t ns;
@@ -169,7 +66,7 @@ doit (void)
gnutls_global_init ();
gnutls_global_set_log_function (tls_log_func);
if (debug)
- gnutls_global_set_log_level (99);
+ gnutls_global_set_log_level (2);
/* Init server */
gnutls_anon_allocate_server_credentials (&s_anoncred);
@@ -177,7 +74,9 @@ doit (void)
gnutls_dh_params_import_pkcs3 (dh_params, &p3, GNUTLS_X509_FMT_PEM);
gnutls_anon_set_server_dh_params (s_anoncred, dh_params);
gnutls_init (&server, GNUTLS_SERVER);
- gnutls_priority_set_direct (server, "NONE:+VERS-TLS-ALL:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-DH", NULL);
+ ret = gnutls_priority_set_direct (server, "NONE:+VERS-TLS-ALL:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-DH", NULL);
+ if (ret < 0)
+ exit(1);
gnutls_credentials_set (server, GNUTLS_CRD_ANON, s_anoncred);
gnutls_dh_set_prime_bits (server, 1024);
gnutls_transport_set_push_function (server, server_push);
@@ -186,12 +85,15 @@ doit (void)
/* Init client */
gnutls_anon_allocate_client_credentials (&c_anoncred);
gnutls_init (&client, GNUTLS_CLIENT);
- gnutls_priority_set_direct (client, "NONE:+VERS-TLS-ALL:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-DH", NULL);
+ ret = gnutls_priority_set_direct (client, "NONE:+VERS-TLS-ALL:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-DH", NULL);
+ if (ret < 0)
+ exit(1);
gnutls_credentials_set (client, GNUTLS_CRD_ANON, c_anoncred);
gnutls_transport_set_push_function (client, client_push);
gnutls_transport_set_pull_function (client, client_pull);
handshake = 1;
+ sret = cret = GNUTLS_E_AGAIN;
do
{
if (cret == GNUTLS_E_AGAIN)
@@ -210,35 +112,48 @@ doit (void)
}
while (cret == GNUTLS_E_AGAIN || sret == GNUTLS_E_AGAIN);
+ if (cret < 0 || sret < 0)
+ {
+ fprintf(stderr, "client: %s\n", gnutls_strerror(cret));
+ fprintf(stderr, "server: %s\n", gnutls_strerror(sret));
+ fail("Handshake failed\n");
+ exit(1);
+ }
+
handshake = 0;
if (debug)
success ("Handshake established\n");
- ns = gnutls_record_send (client, MSG, strlen (MSG));
+ do
+ {
+ ret = gnutls_record_send (client, MSG, strlen (MSG));
+ }
+ while(ret == GNUTLS_E_AGAIN);
//success ("client: sent %d\n", ns);
do
{
//success("transferred: %d\n", transferred);
- ret = gnutls_record_recv (server, buffer, MAX_BUF);
+ do
+ {
+ ret = gnutls_record_recv (server, buffer, MAX_BUF);
+ }
+ while(ret == GNUTLS_E_AGAIN);
+
if (ret == 0)
fail ("server: didn't receive any data\n");
else if (ret < 0)
{
-// if (debug)
-// fputs ("#", stdout);
- if (ret != GNUTLS_E_AGAIN)
- {
- fail ("server: error: %s\n", gnutls_strerror (ret));
- break;
- }
+ // if (debug)
+ // fputs ("#", stdout);
+ fail ("server: error: %s\n", gnutls_strerror (ret));
}
else
{
transferred += ret;
-// if (debug)
-// fputs ("*", stdout);
+ // if (debug)
+ // fputs ("*", stdout);
}
msglen = strlen (MSG);
@@ -248,7 +163,12 @@ doit (void)
}
while (ns == GNUTLS_E_AGAIN);
- ret = gnutls_record_recv (client, buffer, MAX_BUF);
+ do
+ {
+ ret = gnutls_record_recv (client, buffer, MAX_BUF);
+ }
+ while(ret == GNUTLS_E_AGAIN);
+
if (ret == 0)
{
fail ("client: Peer has closed the TLS connection\n");
@@ -257,11 +177,7 @@ doit (void)
{
if (debug)
fputs ("!", stdout);
- if (ret != GNUTLS_E_AGAIN)
- {
- fail ("client: Error: %s\n", gnutls_strerror (ret));
- break;
- }
+ fail ("client: Error: %s\n", gnutls_strerror (ret));
}
else
{
@@ -292,9 +208,6 @@ doit (void)
gnutls_deinit (client);
gnutls_deinit (server);
- free (to_server);
- free (to_client);
-
gnutls_anon_free_client_credentials (c_anoncred);
gnutls_anon_free_server_credentials (s_anoncred);
diff --git a/tests/utils.c b/tests/utils.c
index 105869c903..c8ed85357f 100644
--- a/tests/utils.c
+++ b/tests/utils.c
@@ -60,7 +60,7 @@ success (const char *format, ...)
va_list arg_ptr;
va_start (arg_ptr, format);
- vfprintf (stdout, format, arg_ptr);
+ vfprintf (stderr, format, arg_ptr);
va_end (arg_ptr);
}