in tls/s2n_recv.c [117:204]
ssize_t s2n_recv_impl(struct s2n_connection * conn, void *buf, ssize_t size, s2n_blocked_status * blocked)
{
ssize_t bytes_read = 0;
struct s2n_blob out = {.data = (uint8_t *) buf };
if (conn->closed) {
return 0;
}
*blocked = S2N_BLOCKED_ON_READ;
POSIX_ENSURE(!s2n_connection_is_quic_enabled(conn), S2N_ERR_UNSUPPORTED_WITH_QUIC);
POSIX_GUARD_RESULT(s2n_early_data_validate_recv(conn));
while (size && !conn->closed) {
int isSSLv2 = 0;
uint8_t record_type;
int r = s2n_read_full_record(conn, &record_type, &isSSLv2);
if (r < 0) {
if (s2n_errno == S2N_ERR_CLOSED) {
*blocked = S2N_NOT_BLOCKED;
if (!bytes_read) {
return 0;
} else {
return bytes_read;
}
}
/* Don't propagate the error if we already read some bytes */
if (s2n_errno == S2N_ERR_IO_BLOCKED && bytes_read) {
s2n_errno = S2N_ERR_OK;
return bytes_read;
}
/* If we get here, it's an error condition */
if (s2n_errno != S2N_ERR_IO_BLOCKED && s2n_allowed_to_cache_connection(conn) && conn->session_id_len) {
conn->config->cache_delete(conn, conn->config->cache_delete_data, conn->session_id, conn->session_id_len);
}
S2N_ERROR_PRESERVE_ERRNO();
}
S2N_ERROR_IF(isSSLv2, S2N_ERR_BAD_MESSAGE);
if (record_type != TLS_APPLICATION_DATA) {
switch (record_type)
{
case TLS_ALERT:
POSIX_GUARD(s2n_process_alert_fragment(conn));
POSIX_GUARD(s2n_flush(conn, blocked));
break;
case TLS_HANDSHAKE:
WITH_ERROR_BLINDING(conn, POSIX_GUARD(s2n_post_handshake_recv(conn)));
break;
}
POSIX_GUARD(s2n_stuffer_wipe(&conn->header_in));
POSIX_GUARD(s2n_stuffer_wipe(&conn->in));
conn->in_status = ENCRYPTED;
continue;
}
out.size = MIN(size, s2n_stuffer_data_available(&conn->in));
POSIX_GUARD(s2n_stuffer_erase_and_read(&conn->in, &out));
bytes_read += out.size;
out.data += out.size;
size -= out.size;
/* Are we ready for more encrypted data? */
if (s2n_stuffer_data_available(&conn->in) == 0) {
POSIX_GUARD(s2n_stuffer_wipe(&conn->header_in));
POSIX_GUARD(s2n_stuffer_wipe(&conn->in));
conn->in_status = ENCRYPTED;
}
/* If we've read some data, return it */
if (bytes_read) {
break;
}
}
if (s2n_stuffer_data_available(&conn->in) == 0) {
*blocked = S2N_NOT_BLOCKED;
}
POSIX_GUARD_RESULT(s2n_early_data_record_bytes(conn, bytes_read));
return bytes_read;
}