Add support for event-driven IO in ssl_client2 and ssl_server2
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index a258868..b317bcc 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -101,6 +101,7 @@
#define DFL_SERVER_PORT "4433"
#define DFL_DEBUG_LEVEL 0
#define DFL_NBIO 0
+#define DFL_EVENT 0
#define DFL_READ_TIMEOUT 0
#define DFL_CA_FILE ""
#define DFL_CA_PATH ""
@@ -331,6 +332,8 @@
" debug_level=%%d default: 0 (disabled)\n" \
" nbio=%%d default: 0 (blocking I/O)\n" \
" options: 1 (non-blocking), 2 (added delays)\n" \
+ " event=%%d default: 0 (loop)\n" \
+ " options: 1 (level-triggered, implies nbio=1),\n" \
" read_timeout=%%d default: 0 ms (no timeout)\n" \
"\n" \
USAGE_DTLS \
@@ -399,6 +402,7 @@
const char *server_port; /* port on which the ssl service runs */
int debug_level; /* level of debugging */
int nbio; /* should I/O be blocking? */
+ int event; /* loop or event-driven IO? level or edge triggered? */
uint32_t read_timeout; /* timeout on mbedtls_ssl_read() in milliseconds */
const char *ca_file; /* the file with the CA certificate(s) */
const char *ca_path; /* the path with the CA certificate(s) reside */
@@ -837,6 +841,78 @@
};
#endif /* MBEDTLS_X509_CRT_PARSE_C */
+/*
+ * Wait for an event from the underlying transport or the timer
+ * (Used in event-driven IO mode).
+ */
+#if !defined(MBEDTLS_TIMING_C)
+void idle( mbedtls_ssl_context *ssl,
+ mbedtls_net_context *fd,
+ int idle_reason )
+{
+#else
+void idle( mbedtls_ssl_context *ssl,
+ mbedtls_net_context *fd,
+ mbedtls_timing_delay_context *timer,
+ int idle_reason )
+{
+#if defined(MBEDTLS_DEBUG_C)
+ struct mbedtls_timing_hr_time tm;
+ unsigned long time_elapsed;
+#endif
+#endif
+
+ int poll_type = 0;
+
+ if( idle_reason == MBEDTLS_ERR_SSL_WANT_WRITE )
+ poll_type = MBEDTLS_NET_POLL_WRITE;
+ else if( idle_reason == MBEDTLS_ERR_SSL_WANT_READ )
+ poll_type = MBEDTLS_NET_POLL_READ;
+#if !defined(MBEDTLS_TIMING_C)
+ else
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "WARNING: No reason for idling given" ) );
+ return;
+ }
+#endif
+
+ /* One should not idle on the underlying transport
+ * if data is still pending to be processed. */
+ if( mbedtls_ssl_check_pending( ssl ) != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "WARNING: Data still pending, "
+ "but idling requested!" ) );
+ }
+ MBEDTLS_SSL_DEBUG_MSG( 3, ( "idle, waiting for event... " ) );
+
+#if defined(MBEDTLS_TIMING_C) && defined(MBEDTLS_DEBUG_C)
+ mbedtls_timing_get_timer( &tm, 1 /* restart */ );
+#endif
+
+ while( 1 )
+ {
+#if defined(MBEDTLS_TIMING_C)
+#if defined(MBEDTLS_DEBUG_C)
+ time_elapsed = mbedtls_timing_get_timer( &tm, 0 );
+#endif
+ if( mbedtls_timing_get_delay( timer ) == 2 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 3, ( "[%lu ms] timer expired - continue",
+ time_elapsed ) );
+ break;
+ }
+#endif
+
+ if( poll_type != 0 &&
+ mbedtls_net_poll( fd, poll_type, 0 ) == poll_type )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 3, ( "[%lu ms] net_context signals data - "
+ "continue", time_elapsed ) );
+ break;
+ }
+ }
+}
+
int main( int argc, char *argv[] )
{
int ret = 0, len, written, frags, exchanges_left;
@@ -969,6 +1045,7 @@
opt.server_addr = DFL_SERVER_ADDR;
opt.server_port = DFL_SERVER_PORT;
opt.debug_level = DFL_DEBUG_LEVEL;
+ opt.event = DFL_EVENT;
opt.nbio = DFL_NBIO;
opt.read_timeout = DFL_READ_TIMEOUT;
opt.ca_file = DFL_CA_FILE;
@@ -1047,6 +1124,12 @@
if( opt.nbio < 0 || opt.nbio > 2 )
goto usage;
}
+ else if( strcmp( p, "event" ) == 0 )
+ {
+ opt.event = atoi( q );
+ if( opt.event < 0 || opt.event > 2 )
+ goto usage;
+ }
else if( strcmp( p, "read_timeout" ) == 0 )
opt.read_timeout = atoi( q );
else if( strcmp( p, "ca_file" ) == 0 )
@@ -1328,6 +1411,16 @@
goto usage;
}
+ /* Event-driven IO is incompatible with the above custom
+ * receive and send functions, as the polling builds on
+ * refers to the underlying net_context. */
+ if( opt.event == 1 && opt.nbio != 1 )
+ {
+ mbedtls_printf( "Warning: event-driven IO mandates nbio=1"
+ " - overwrite\n" );
+ opt.nbio = 1;
+ }
+
#if defined(MBEDTLS_DEBUG_C)
mbedtls_debug_set_threshold( opt.debug_level );
#endif
@@ -2113,9 +2206,22 @@
mbedtls_printf( " . Performing the SSL/TLS handshake..." );
fflush( stdout );
- do ret = mbedtls_ssl_handshake( &ssl );
- while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
- ret == MBEDTLS_ERR_SSL_WANT_WRITE );
+ while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 )
+ {
+ if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+ break;
+
+ /* For event-driven IO, wait for socket to become available */
+ if( opt.event == 1 /* level triggered IO */ )
+ {
+#if defined(MBEDTLS_TIMING_C)
+ idle( &ssl, &client_fd, &timer, ret );
+#else
+ idle( &ssl, &client_fd, ret );
+#endif
+ }
+ }
if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED )
{
@@ -2221,7 +2327,18 @@
if( ret == MBEDTLS_ERR_SSL_WANT_READ ||
ret == MBEDTLS_ERR_SSL_WANT_WRITE )
+ {
+ if( opt.event == 1 /* level triggered IO */ )
+ {
+#if defined(MBEDTLS_TIMING_C)
+ idle( &ssl, &client_fd, &timer, ret );
+#else
+ idle( &ssl, &client_fd, ret );
+#endif
+ }
+
continue;
+ }
if( ret <= 0 )
{
@@ -2309,9 +2426,24 @@
len = sizeof( buf ) - 1;
memset( buf, 0, sizeof( buf ) );
- do ret = mbedtls_ssl_read( &ssl, buf, len );
- while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
- ret == MBEDTLS_ERR_SSL_WANT_WRITE );
+ while( 1 )
+ {
+ ret = mbedtls_ssl_read( &ssl, buf, len );
+
+ if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+ break;
+
+ /* For event-driven IO, wait for socket to become available */
+ if( opt.event == 1 /* level triggered IO */ )
+ {
+#if defined(MBEDTLS_TIMING_C)
+ idle( &ssl, &client_fd, &timer, ret );
+#else
+ idle( &ssl, &client_fd, ret );
+#endif
+ }
+ }
if( ret <= 0 )
{
@@ -2352,6 +2484,16 @@
mbedtls_printf( " failed\n ! mbedtls_ssl_renegotiate returned %d\n\n", ret );
goto reset;
}
+
+ /* For event-driven IO, wait for socket to become available */
+ if( opt.event == 1 /* level triggered IO */ )
+ {
+#if defined(MBEDTLS_TIMING_C)
+ idle( &ssl, &client_fd, &timer, ret );
+#else
+ idle( &ssl, &client_fd, ret );
+#endif
+ }
}
mbedtls_printf( " ok\n" );
@@ -2386,14 +2528,39 @@
mbedtls_printf( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret );
goto reset;
}
+
+ /* For event-driven IO, wait for socket to become available */
+ if( opt.event == 1 /* level triggered IO */ )
+ {
+#if defined(MBEDTLS_TIMING_C)
+ idle( &ssl, &client_fd, &timer, ret );
+#else
+ idle( &ssl, &client_fd, ret );
+#endif
+ }
}
}
}
else /* Not stream, so datagram */
{
- do ret = mbedtls_ssl_write( &ssl, buf, len );
- while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
- ret == MBEDTLS_ERR_SSL_WANT_WRITE );
+ while( 1 )
+ {
+ ret = mbedtls_ssl_write( &ssl, buf, len );
+
+ if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+ break;
+
+ /* For event-driven IO, wait for socket to become available */
+ if( opt.event == 1 /* level triggered IO */ )
+ {
+#if defined(MBEDTLS_TIMING_C)
+ idle( &ssl, &client_fd, &timer, ret );
+#else
+ idle( &ssl, &client_fd, ret );
+#endif
+ }
+ }
if( ret < 0 )
{