Support multiple records in one datagram
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 7d6b9ab..8165963 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -1821,14 +1821,19 @@
#endif /* POLARSSL_ZLIB_SUPPORT */
/*
- * Fill the input message buffer
+ * Fill the input message buffer by appending data to it.
+ * The amount of data already fetched is in ssl->in_left.
*
* If we return 0, is it guaranteed that (at least) nb_want bytes are
* available (from this read and/or a previous one). Otherwise, an error code
* is returned (possibly EOF or WANT_READ).
*
- * Set ssl->in_left to 0 before calling to start a new record. Apart from
- * this, ssl->in_left is an internal variable and should never be read.
+ * With stream transport (TLS) on success ssl->in_left == nb_want, but
+ * with datagram transport (DTLS) on success ssl->in_left >= nb_want,
+ * since we always read a whole datagram at once.
+ *
+ * For DTLS, It is up to the caller to set ssl->next_record_offset when
+ * they're done reading a record.
*/
int ssl_fetch_input( ssl_context *ssl, size_t nb_want )
{
@@ -1846,13 +1851,43 @@
#if defined(POLARSSL_SSL_PROTO_DTLS)
if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
{
+ /*
+ * The point is, we need to always read a full datagram at once, so we
+ * sometimes read more then requested, and handle the additional data.
+ * It could be the rest of the current record (while fetching the
+ * header) and/or some other records in the same datagram.
+ */
+
+ /*
+ * Move to the next record in the already read datagram if applicable
+ */
+ if( ssl->next_record_offset != 0 )
+ {
+ if( ssl->in_left < ssl->next_record_offset )
+ {
+ SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+ return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
+ }
+
+ ssl->in_left -= ssl->next_record_offset;
+
+ if( ssl->in_left != 0 )
+ {
+ SSL_DEBUG_MSG( 2, ( "next record in same datagram, offset: %d",
+ ssl->next_record_offset ) );
+ memmove( ssl->in_hdr,
+ ssl->in_hdr + ssl->next_record_offset,
+ ssl->in_left );
+ }
+
+ ssl->next_record_offset = 0;
+ }
+
SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d",
ssl->in_left, nb_want ) );
/*
- * With UDP, we must always read a full datagram.
- * Just remember how much we read and avoid reading again if we
- * already have enough data.
+ * Done if we already have enough data.
*/
if( nb_want <= ssl->in_left)
return( 0 );
@@ -1884,6 +1919,9 @@
else
#endif
{
+ SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d",
+ ssl->in_left, nb_want ) );
+
while( ssl->in_left < nb_want )
{
len = nb_want - ssl->in_left;
@@ -2251,6 +2289,12 @@
return( ret );
}
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+ /* Done reading this record, get ready for the next one */
+ if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
+ ssl->next_record_offset = ssl->in_msglen + ssl_hdr_len( ssl );
+#endif
+
SSL_DEBUG_BUF( 4, "input record from network",
ssl->in_hdr, ssl_hdr_len( ssl ) + ssl->in_msglen );
@@ -2358,6 +2402,10 @@
}
}
+ /* With DTLS there might be other records in the same datagram */
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+ if( ssl->transport != SSL_TRANSPORT_DATAGRAM )
+#endif
ssl->in_left = 0;
SSL_DEBUG_MSG( 2, ( "<= read record" ) );
@@ -3597,6 +3645,9 @@
ssl->in_msgtype = 0;
ssl->in_msglen = 0;
ssl->in_left = 0;
+#if defined(POLARSSL_SSL_PROTO_DTLS)
+ ssl->next_record_offset = 0;
+#endif
ssl->in_hslen = 0;
ssl->nb_zero = 0;