int s2n_shutdown(struct s2n_connection *conn, s2n_blocked_status * more) { notnull_check(conn); notnull_check(more); /* Treat this call as a no-op if already wiped */ if (conn->send == NULL && conn->recv == NULL) { return 0; } uint64_t elapsed; GUARD(s2n_timer_elapsed(conn->config, &conn->write_timer, &elapsed)); S2N_ERROR_IF(elapsed < conn->delay, S2N_ERR_SHUTDOWN_PAUSED); /* Queue our close notify, once. Use warning level so clients don't give up */ GUARD(s2n_queue_writer_close_alert_warning(conn)); /* Write it */ GUARD(s2n_flush(conn, more)); /* Assume caller isn't interested in pending incoming data */ if (conn->in_status == PLAINTEXT) { GUARD(s2n_stuffer_wipe(&conn->header_in)); GUARD(s2n_stuffer_wipe(&conn->in)); conn->in_status = ENCRYPTED; } /* Fails with S2N_ERR_SHUTDOWN_RECORD_TYPE or S2N_ERR_ALERT on receipt of anything but a close_notify */ GUARD(s2n_recv_close_notify(conn, more)); return 0; }
int64_t s2n_connection_get_delay(struct s2n_connection *conn) { if (!conn->delay) { return 0; } uint64_t elapsed; GUARD(s2n_timer_elapsed(conn->config, &conn->write_timer, &elapsed)); if (elapsed > conn->delay) { return 0; } return conn->delay - elapsed; }
int s2n_shutdown(struct s2n_connection *conn, s2n_blocked_status *more) { uint64_t elapsed; GUARD(s2n_timer_elapsed(conn->config, &conn->write_timer, &elapsed)); if (elapsed < conn->delay) { S2N_ERROR(S2N_ERR_SHUTDOWN_PAUSED); } /* Write any pending I/O */ GUARD(s2n_flush(conn, more)); GUARD(s2n_queue_writer_close_alert(conn)); /* Write the alert message out */ GUARD(s2n_flush(conn, more)); /* Wipe the connection */ GUARD(s2n_connection_wipe(conn)); return 0; }
int main(int argc, char **argv) { struct s2n_timer timer; uint64_t nanoseconds; BEGIN_TEST(); /* First: Perform some tests using the real clock */ EXPECT_SUCCESS(s2n_timer_start(&timer)); EXPECT_SUCCESS(s2n_timer_reset(&timer, &nanoseconds)); EXPECT_TRUE(nanoseconds < 1000000000); EXPECT_SUCCESS(s2n_timer_elapsed(&timer, &nanoseconds)); EXPECT_TRUE(nanoseconds < 1000000000); EXPECT_SUCCESS(sleep(1)); EXPECT_SUCCESS(s2n_timer_reset(&timer, &nanoseconds)); EXPECT_TRUE(nanoseconds > 1000000000); EXPECT_TRUE(nanoseconds < 2000000000); EXPECT_SUCCESS(sleep(1)); EXPECT_SUCCESS(s2n_timer_elapsed(&timer, &nanoseconds)); EXPECT_TRUE(nanoseconds > 1000000000); EXPECT_TRUE(nanoseconds < 2000000000); #if !defined(__APPLE__) || !defined(__MACH__) /* Next: perform some tests around timespec boundaries */ /* Pretend that there were 999,999,999 nanoseconds elapsed in the * previously measured instant. Keep reseting the timer until * the second progresses from that instant, and there are also * less than 999,999,999 nanoseconds elapsed. * * This sets up a situation in which the tv_sec field causes time * to move "forwards", and tv_nsec causes it to move backwards. * e.g. * * previous_time = 10 * * timer.time.tv_sec = 11 * timer.time.tv_nsec = 123456789; * * delta will be: * (11 - 10) * 1000000000 * + (123456789 - 999999999) * * = 123456790 (same as 1 + 123456789) */ time_t previous_time; do { previous_time = timer.time.tv_sec; timer.time.tv_nsec = 999999999; EXPECT_SUCCESS(s2n_timer_reset(&timer, &nanoseconds)); } while(previous_time != (timer.time.tv_sec - 1) || timer.time.tv_nsec == 999999999); EXPECT_TRUE(nanoseconds < 1000000000); EXPECT_TRUE(nanoseconds == 1 + timer.time.tv_nsec); /* Now we perform the oppossite test: make sure that the previous value for * nsec is smaller than the later one */ do { previous_time = timer.time.tv_sec; timer.time.tv_nsec = 0; EXPECT_SUCCESS(s2n_timer_reset(&timer, &nanoseconds)); } while(previous_time != (timer.time.tv_sec - 1) || timer.time.tv_nsec == 0); EXPECT_TRUE(nanoseconds > 1000000000); EXPECT_TRUE(nanoseconds < 2000000000); EXPECT_TRUE(nanoseconds == 1000000000 + timer.time.tv_nsec); #endif END_TEST(); }