Change non-blocking read/write in TCP mock socket

Previously mocked non-blocking read/write was returning 0 when buffer was empty/full. That was causing ERR_SSL_CONN_EOF error in tests which was using these mocked callbacks. Beside that non-blocking read/write was returning ERR_SSL_WANT_READ/_WRITE depending on block pattern set by test design. Such behavior forced to redesign of these functions so that they could be used in other tests
This commit is contained in:
Piotr Nowicki 2020-01-15 16:19:07 +01:00
parent fb437d72ef
commit 890b5ca330
2 changed files with 118 additions and 136 deletions

View file

@ -35,34 +35,16 @@ Test mock socket sanity
ssl_mock_sanity: ssl_mock_sanity:
Test mock blocking TCP connection Test mock blocking TCP connection
ssl_mock_tcp:1:0:0 ssl_mock_tcp:1
Test mock non-blocking TCP connection: would not block Test mock non-blocking TCP connection
ssl_mock_tcp:0:0:0 ssl_mock_tcp:0
Test mock non-blocking TCP connection: client would block
ssl_mock_tcp:0:0xB509:0
Test mock non-blocking TCP connection: server would block
ssl_mock_tcp:0:0x0FB1:0
Test mock non-blocking TCP connection: both peers would block
ssl_mock_tcp:0:0x1111:0xEEEE
Test mock blocking TCP connection (interleaving) Test mock blocking TCP connection (interleaving)
ssl_mock_tcp_interleaving:1:0:0 ssl_mock_tcp_interleaving:1
Test mock non-blocking TCP connection: would not block (interleaving) Test mock non-blocking TCP connection (interleaving)
ssl_mock_tcp_interleaving:0:0:0 ssl_mock_tcp_interleaving:0
Test mock non-blocking TCP connection: client would block (interleaving)
ssl_mock_tcp_interleaving:0:0xB509:0
Test mock non-blocking TCP connection: server would block (interleaving)
ssl_mock_tcp_interleaving:0:0x0FB1:0
Test mock non-blocking TCP connection: both peers would block (interleaving)
ssl_mock_tcp_interleaving:0:0x1111:0xEEEE
SSL DTLS replay: initial state, seqnum 0 SSL DTLS replay: initial state, seqnum 0
ssl_dtls_replay:"":"000000000000":0 ssl_dtls_replay:"":"000000000000":0

View file

@ -159,7 +159,6 @@ int mbedtls_test_buffer_get( mbedtls_test_buffer *buf,
typedef struct mbedtls_mock_socket typedef struct mbedtls_mock_socket
{ {
int status; int status;
uint32_t blocking_pattern;
mbedtls_test_buffer *input; mbedtls_test_buffer *input;
mbedtls_test_buffer *output; mbedtls_test_buffer *output;
struct mbedtls_mock_socket *peer; struct mbedtls_mock_socket *peer;
@ -268,26 +267,6 @@ exit:
return ret; return ret;
} }
/*
* Set the blocking pattern for the socket.
*
* For every bit of \p blocking_pattern set to one the socket will simulate a
* "would block" event. The bits are processed starting with the least
* significant bit and every call to a non-blocking I/O function consumes one.
*
* The behaviour of blocking I/O functions remains unchanged.
*/
int mbedtls_mock_socket_set_block( mbedtls_mock_socket* socket,
uint32_t blocking_pattern )
{
if( socket == NULL )
return -1;
socket->blocking_pattern = blocking_pattern;
return 0;
}
/* /*
* Callbacks for simulating blocking I/O over connection-oriented transport. * Callbacks for simulating blocking I/O over connection-oriented transport.
*/ */
@ -323,14 +302,11 @@ int mbedtls_mock_tcp_send_nb( void *ctx, const unsigned char *buf, size_t len )
if( socket == NULL || socket->status != MBEDTLS_MOCK_SOCKET_CONNECTED ) if( socket == NULL || socket->status != MBEDTLS_MOCK_SOCKET_CONNECTED )
return -1; return -1;
if( socket->blocking_pattern & 1 ) if( socket->output->capacity == socket->output->content_length )
{ {
socket->blocking_pattern >>= 1;
return MBEDTLS_ERR_SSL_WANT_WRITE; return MBEDTLS_ERR_SSL_WANT_WRITE;
} }
socket->blocking_pattern >>= 1;
return mbedtls_test_buffer_put( socket->output, buf, len ); return mbedtls_test_buffer_put( socket->output, buf, len );
} }
@ -341,14 +317,11 @@ int mbedtls_mock_tcp_recv_nb( void *ctx, unsigned char *buf, size_t len )
if( socket == NULL || socket->status != MBEDTLS_MOCK_SOCKET_CONNECTED ) if( socket == NULL || socket->status != MBEDTLS_MOCK_SOCKET_CONNECTED )
return -1; return -1;
if( socket->blocking_pattern & 1 ) if( socket->input->content_length == 0)
{ {
socket->blocking_pattern >>= 1;
return MBEDTLS_ERR_SSL_WANT_READ; return MBEDTLS_ERR_SSL_WANT_READ;
} }
socket->blocking_pattern >>= 1;
return mbedtls_test_buffer_get( socket->input, buf, len ); return mbedtls_test_buffer_get( socket->input, buf, len );
} }
@ -928,9 +901,10 @@ exit:
*/ */
/* BEGIN_CASE */ /* BEGIN_CASE */
void ssl_mock_tcp( int blocking, int client_pattern, int server_pattern ) void ssl_mock_tcp( int blocking )
{ {
enum { MSGLEN = 105 }; enum { MSGLEN = 105 };
enum { BUFLEN = MSGLEN / 5 };
unsigned char message[MSGLEN]; unsigned char message[MSGLEN];
unsigned char received[MSGLEN]; unsigned char received[MSGLEN];
mbedtls_mock_socket client; mbedtls_mock_socket client;
@ -939,8 +913,6 @@ void ssl_mock_tcp( int blocking, int client_pattern, int server_pattern )
int send_ret, recv_ret; int send_ret, recv_ret;
mbedtls_ssl_send_t *send; mbedtls_ssl_send_t *send;
mbedtls_ssl_recv_t *recv; mbedtls_ssl_recv_t *recv;
uint32_t client_block = client_pattern;
uint32_t server_block = server_pattern;
unsigned i; unsigned i;
if( blocking == 0 ) if( blocking == 0 )
@ -965,10 +937,7 @@ void ssl_mock_tcp( int blocking, int client_pattern, int server_pattern )
} }
/* Make sure that sending a message takes a few iterations. */ /* Make sure that sending a message takes a few iterations. */
TEST_ASSERT( 0 == mbedtls_mock_socket_connect( &client, &server, TEST_ASSERT( 0 == mbedtls_mock_socket_connect( &client, &server, BUFLEN ) );
MSGLEN / 5 ) );
TEST_ASSERT( 0 == mbedtls_mock_socket_set_block( &client, client_block ) );
TEST_ASSERT( 0 == mbedtls_mock_socket_set_block( &server, server_block ) );
/* Send the message to the server */ /* Send the message to the server */
send_ret = recv_ret = 1; send_ret = recv_ret = 1;
@ -977,28 +946,56 @@ void ssl_mock_tcp( int blocking, int client_pattern, int server_pattern )
{ {
send_ret = send( &client, message + written, MSGLEN - written ); send_ret = send( &client, message + written, MSGLEN - written );
if( ( blocking == 0 ) && ( client_block & 1 ) ) TEST_ASSERT( send_ret >= 0 );
TEST_ASSERT( send_ret <= BUFLEN );
written += send_ret;
/* If the buffer is full we can test blocking and non-blocking send */
if ( send_ret == BUFLEN )
{ {
TEST_ASSERT( send_ret == MBEDTLS_ERR_SSL_WANT_WRITE ); int blocking_ret = send( &client, message , 1 );
if ( blocking )
{
TEST_ASSERT( blocking_ret == 0 );
} }
else else
{ {
TEST_ASSERT( send_ret >= 0 ); TEST_ASSERT( blocking_ret == MBEDTLS_ERR_SSL_WANT_WRITE );
written += send_ret; }
} }
client_block >>= 1;
recv_ret = recv( &server, received + read, MSGLEN - read ); recv_ret = recv( &server, received + read, MSGLEN - read );
if( ( blocking == 0 ) && ( server_block & 1 ) )
/* The result depends on whether any data was sent */
if ( send_ret > 0 )
{ {
TEST_ASSERT( recv_ret == MBEDTLS_ERR_SSL_WANT_READ ); TEST_ASSERT( recv_ret > 0 );
TEST_ASSERT( recv_ret <= BUFLEN );
read += recv_ret;
}
else if( blocking )
{
TEST_ASSERT( recv_ret == 0 );
} }
else else
{ {
TEST_ASSERT( recv_ret >= 0 ); TEST_ASSERT( recv_ret == MBEDTLS_ERR_SSL_WANT_READ );
read += recv_ret; recv_ret = 0;
}
/* If the buffer is empty we can test blocking and non-blocking read */
if ( recv_ret == BUFLEN )
{
int blocking_ret = recv( &server, received, 1 );
if ( blocking )
{
TEST_ASSERT( blocking_ret == 0 );
}
else
{
TEST_ASSERT( blocking_ret == MBEDTLS_ERR_SSL_WANT_READ );
}
} }
server_block >>= 1;
} }
TEST_ASSERT( memcmp( message, received, MSGLEN ) == 0 ); TEST_ASSERT( memcmp( message, received, MSGLEN ) == 0 );
@ -1016,11 +1013,11 @@ exit:
*/ */
/* BEGIN_CASE */ /* BEGIN_CASE */
void ssl_mock_tcp_interleaving( int blocking, void ssl_mock_tcp_interleaving( int blocking )
int client_pattern, int server_pattern )
{ {
enum { ROUNDS = 2 }; enum { ROUNDS = 2 };
enum { MSGLEN = 105 }; enum { MSGLEN = 105 };
enum { BUFLEN = MSGLEN / 5 };
unsigned char message[ROUNDS][MSGLEN]; unsigned char message[ROUNDS][MSGLEN];
unsigned char received[ROUNDS][MSGLEN]; unsigned char received[ROUNDS][MSGLEN];
mbedtls_mock_socket client; mbedtls_mock_socket client;
@ -1032,8 +1029,6 @@ void ssl_mock_tcp_interleaving( int blocking,
unsigned i, j, progress; unsigned i, j, progress;
mbedtls_ssl_send_t *send; mbedtls_ssl_send_t *send;
mbedtls_ssl_recv_t *recv; mbedtls_ssl_recv_t *recv;
uint32_t client_block = client_pattern;
uint32_t server_block = server_pattern;
if( blocking == 0 ) if( blocking == 0 )
{ {
@ -1060,10 +1055,7 @@ void ssl_mock_tcp_interleaving( int blocking,
} }
/* Make sure that sending a message takes a few iterations. */ /* Make sure that sending a message takes a few iterations. */
TEST_ASSERT( 0 == mbedtls_mock_socket_connect( &client, &server, TEST_ASSERT( 0 == mbedtls_mock_socket_connect( &client, &server, BUFLEN ) );
MSGLEN / 5 ) );
TEST_ASSERT( 0 == mbedtls_mock_socket_set_block( &client, client_block ) );
TEST_ASSERT( 0 == mbedtls_mock_socket_set_block( &server, server_block ) );
/* Send the message from both sides, interleaving. */ /* Send the message from both sides, interleaving. */
progress = 1; progress = 1;
@ -1076,72 +1068,80 @@ void ssl_mock_tcp_interleaving( int blocking,
* of at least one byte on either side. */ * of at least one byte on either side. */
while( progress != 0 ) while( progress != 0 )
{ {
send_ret[0] = send( &client, message[0] + written[0], mbedtls_mock_socket *socket;
MSGLEN - written[0] );
if( ( blocking == 0 ) && ( client_block & 1 ) )
{
TEST_ASSERT( send_ret[0] == MBEDTLS_ERR_SSL_WANT_WRITE );
}
else
{
TEST_ASSERT( send_ret[0] >= 0 );
written[0] += send_ret[0];
}
client_block >>= 1;
send_ret[1] = send( &server, message[1] + written[1], for( i = 0; i < ROUNDS; i++ )
MSGLEN - written[1] );
if( ( blocking == 0 ) && ( server_block & 1 ) )
{ {
TEST_ASSERT( send_ret[1] == MBEDTLS_ERR_SSL_WANT_WRITE ); /* First sending is from the client */
} socket = ( i % 2 == 0 ) ? ( &client ) : ( &server );
else
{
TEST_ASSERT( send_ret[1] >= 0 );
written[1] += send_ret[1];
}
server_block >>= 1;
recv_ret[0] = recv( &server, received[0] + read[0], send_ret[i] = send( socket, message[i] + written[i],
MSGLEN - read[0] ); MSGLEN - written[i] );
if( ( blocking == 0 ) && ( server_block & 1 ) ) TEST_ASSERT( send_ret[i] >= 0 );
{ TEST_ASSERT( send_ret[i] <= BUFLEN );
TEST_ASSERT( recv_ret[0] == MBEDTLS_ERR_SSL_WANT_READ ); written[i] += send_ret[i];
}
else
{
TEST_ASSERT( recv_ret[0] >= 0 );
read[0] += recv_ret[0];
}
server_block >>= 1;
recv_ret[1] = recv( &client, received[1] + read[1], /* If the buffer is full we can test blocking and non-blocking
MSGLEN - read[1] ); * send */
if( ( blocking == 0 ) && ( client_block & 1 ) ) if ( send_ret[i] == BUFLEN )
{ {
TEST_ASSERT( recv_ret[1] == MBEDTLS_ERR_SSL_WANT_READ ); int blocking_ret = send( socket, message[i] , 1 );
if ( blocking )
{
TEST_ASSERT( blocking_ret == 0 );
} }
else else
{ {
TEST_ASSERT( recv_ret[1] >= 0 ); TEST_ASSERT( blocking_ret == MBEDTLS_ERR_SSL_WANT_WRITE );
read[1] += recv_ret[1]; }
}
}
for( i = 0; i < ROUNDS; i++ )
{
/* First receiving is from the server */
socket = ( i % 2 == 0 ) ? ( &server ) : ( &client );
recv_ret[i] = recv( socket, received[i] + read[i],
MSGLEN - read[i] );
/* The result depends on whether any data was sent */
if ( send_ret[i] > 0 )
{
TEST_ASSERT( recv_ret[i] > 0 );
TEST_ASSERT( recv_ret[i] <= BUFLEN );
read[i] += recv_ret[i];
}
else if( blocking )
{
TEST_ASSERT( recv_ret[i] == 0 );
}
else
{
TEST_ASSERT( recv_ret[i] == MBEDTLS_ERR_SSL_WANT_READ );
recv_ret[i] = 0;
}
/* If the buffer is empty we can test blocking and non-blocking
* read */
if ( recv_ret[i] == BUFLEN )
{
int blocking_ret = recv( socket, received[i], 1 );
if ( blocking )
{
TEST_ASSERT( blocking_ret == 0 );
}
else
{
TEST_ASSERT( blocking_ret == MBEDTLS_ERR_SSL_WANT_READ );
}
}
} }
client_block >>= 1;
progress = 0; progress = 0;
for( i = 0; i < ROUNDS; i++ ) for( i = 0; i < ROUNDS; i++ )
{ {
if( ( send_ret[i] > 0 ) || progress += send_ret[i] + recv_ret[i];
( send_ret[i] == MBEDTLS_ERR_SSL_WANT_WRITE ) )
{
progress++;
}
if( ( recv_ret[i] > 0 ) ||
( recv_ret[i] == MBEDTLS_ERR_SSL_WANT_READ ) )
{
progress++;
}
} }
} }