in tls/s2n_early_data_io.c [149:207]
S2N_RESULT s2n_send_early_data_impl(struct s2n_connection *conn, const uint8_t *data, ssize_t data_len_signed,
ssize_t *data_sent, s2n_blocked_status *blocked)
{
RESULT_ENSURE_GTE(data_len_signed, 0);
size_t data_len = data_len_signed;
RESULT_ENSURE_REF(conn);
RESULT_ENSURE_REF(blocked);
*blocked = S2N_NOT_BLOCKED;
RESULT_ENSURE_REF(data_sent);
*data_sent = 0;
RESULT_ENSURE(conn->mode == S2N_CLIENT, S2N_ERR_SERVER_MODE);
RESULT_ENSURE(s2n_connection_supports_tls13(conn), S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED);
if (!s2n_early_data_can_continue(conn)) {
return S2N_RESULT_OK;
}
/* Attempt to make progress in the handshake even if s2n_send eventually fails.
* We only care about the result of this call if it would prevent us from calling s2n_send. */
int negotiate_result = s2n_negotiate(conn, blocked);
if (negotiate_result < S2N_SUCCESS) {
if (s2n_error_get_type(s2n_errno) != S2N_ERR_T_BLOCKED) {
RESULT_GUARD_POSIX(negotiate_result);
} else if (*blocked != S2N_BLOCKED_ON_EARLY_DATA && *blocked != S2N_BLOCKED_ON_READ) {
RESULT_GUARD_POSIX(negotiate_result);
}
}
/* Save the error status for later */
int negotiate_error = s2n_errno;
s2n_blocked_status negotiate_blocked = *blocked;
/* Attempt to send the early data.
* We only care about the result of this call if it fails. */
uint32_t early_data_to_send = 0;
RESULT_GUARD_POSIX(s2n_connection_get_remaining_early_data_size(conn, &early_data_to_send));
early_data_to_send = MIN(data_len, early_data_to_send);
if (early_data_to_send) {
ssize_t send_result = s2n_send(conn, data, early_data_to_send, blocked);
RESULT_GUARD_POSIX(send_result);
*data_sent = send_result;
}
*blocked = S2N_NOT_BLOCKED;
/* Since the send was successful, report the result of the original negotiate call.
* If we got this far, the result must have been success or a blocking error. */
if (negotiate_result < S2N_SUCCESS) {
RESULT_ENSURE_EQ(s2n_error_get_type(negotiate_error), S2N_ERR_T_BLOCKED);
if (negotiate_blocked == S2N_BLOCKED_ON_EARLY_DATA) {
return S2N_RESULT_OK;
} else if (s2n_early_data_can_continue(conn)) {
*blocked = negotiate_blocked;
RESULT_BAIL(negotiate_error);
} else {
return S2N_RESULT_OK;
}
}
return S2N_RESULT_OK;
}