Latest changes
- Hide handshake implementation behind a set of function pointers - Use monotonically increasing clock - Make sure that retx delay is not larger than the max of 60 seconds
This commit is contained in:
parent
0fb9ea94ae
commit
83287402d5
|
@ -1,3 +1,9 @@
|
|||
2017-10-09
|
||||
|
||||
- Hide handshake implementation behind a set of function pointers
|
||||
- Use monotonically increasing clock
|
||||
- Make sure that retx delay is not larger than the max of 60 seconds
|
||||
|
||||
2017-09-29
|
||||
|
||||
- A few fixes to code and README
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "lsquic_int_types.h"
|
||||
#include "lsquic.h"
|
||||
|
||||
#include "lsquic_str.h"
|
||||
#include "lsquic_handshake.h"
|
||||
#include "lsquic_chsk_stream.h"
|
||||
#include "lsquic_ver_neg.h"
|
||||
|
@ -78,9 +79,9 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
|||
}
|
||||
c_hsk->buf_off += nread;
|
||||
|
||||
s = handle_chlo_reply(c_hsk->lconn->cn_enc_session,
|
||||
s = c_hsk->lconn->cn_esf->esf_handle_chlo_reply(c_hsk->lconn->cn_enc_session,
|
||||
c_hsk->buf_in, c_hsk->buf_off);
|
||||
LSQ_DEBUG("handle_chlo_reply returned %d", s);
|
||||
LSQ_DEBUG("lsquic_enc_session_handle_chlo_reply returned %d", s);
|
||||
switch (s)
|
||||
{
|
||||
case DATA_NOT_ENOUGH:
|
||||
|
@ -101,7 +102,7 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
|||
lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
|
||||
c_hsk->buf_in = NULL;
|
||||
lsquic_stream_wantread(stream, 0);
|
||||
if (is_hs_done(c_hsk->lconn->cn_enc_session))
|
||||
if (c_hsk->lconn->cn_esf->esf_is_hsk_done(c_hsk->lconn->cn_enc_session))
|
||||
{
|
||||
LSQ_DEBUG("handshake is complete, inform connection");
|
||||
c_hsk->lconn->cn_if->ci_handshake_done(c_hsk->lconn);
|
||||
|
@ -114,9 +115,9 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
LSQ_WARN("handle_chlo_reply returned unknown value %d", s);
|
||||
LSQ_WARN("lsquic_enc_session_handle_chlo_reply returned unknown value %d", s);
|
||||
case DATA_FORMAT_ERROR:
|
||||
LSQ_INFO("handle_chlo_reply returned an error");
|
||||
LSQ_INFO("lsquic_enc_session_handle_chlo_reply returned an error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -144,8 +145,8 @@ hsk_client_on_write (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
|||
}
|
||||
len = 4 * 1024;
|
||||
|
||||
if (0 != gen_chlo(c_hsk->lconn->cn_enc_session, c_hsk->ver_neg->vn_ver,
|
||||
buf, &len))
|
||||
if (0 != c_hsk->lconn->cn_esf->esf_gen_chlo(c_hsk->lconn->cn_enc_session,
|
||||
c_hsk->ver_neg->vn_ver, buf, &len))
|
||||
{
|
||||
LSQ_WARN("cannot create CHLO message");
|
||||
lsquic_mm_put_4k(c_hsk->mm, buf);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "lsquic_conn.h"
|
||||
#include "lsquic_packet_common.h"
|
||||
#include "lsquic_packet_in.h"
|
||||
#include "lsquic_str.h"
|
||||
#include "lsquic_handshake.h"
|
||||
#include "lsquic_mm.h"
|
||||
#include "lsquic_engine_public.h"
|
||||
|
@ -119,7 +120,8 @@ lsquic_conn_decrypt_packet (lsquic_conn_t *lconn,
|
|||
|
||||
header_len = packet_in->pi_header_sz;
|
||||
data_len = packet_in->pi_data_sz - packet_in->pi_header_sz;
|
||||
if (0 == lsquic_dec(lconn->cn_enc_session, lconn->cn_version, 0,
|
||||
if (0 == lconn->cn_esf->esf_decrypt(lconn->cn_enc_session,
|
||||
lconn->cn_version, 0,
|
||||
packet_in->pi_packno, packet_in->pi_data,
|
||||
&header_len, data_len,
|
||||
lsquic_packet_in_nonce(packet_in),
|
||||
|
|
|
@ -88,6 +88,8 @@ struct lsquic_conn
|
|||
{
|
||||
void *cn_peer_ctx;
|
||||
struct lsquic_enc_session *cn_enc_session;
|
||||
const struct enc_session_funcs
|
||||
*cn_esf;
|
||||
lsquic_cid_t cn_cid;
|
||||
STAILQ_ENTRY(lsquic_conn) cn_next_closed_conn;
|
||||
TAILQ_ENTRY(lsquic_conn) cn_next_all,
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "lsquic_full_conn.h"
|
||||
#include "lsquic_util.h"
|
||||
#include "lsquic_qtags.h"
|
||||
#include "lsquic_str.h"
|
||||
#include "lsquic_handshake.h"
|
||||
#include "lsquic_mm.h"
|
||||
#include "lsquic_conn_hash.h"
|
||||
|
@ -1072,7 +1073,7 @@ really_encrypt_packet (const lsquic_conn_t *conn,
|
|||
return -1;
|
||||
|
||||
is_hello_packet = !!(packet_out->po_flags & PO_HELLO);
|
||||
enc = lsquic_enc(conn->cn_enc_session, conn->cn_version, 0,
|
||||
enc = conn->cn_esf->esf_encrypt(conn->cn_enc_session, conn->cn_version, 0,
|
||||
packet_out->po_packno, header_buf, header_sz,
|
||||
packet_out->po_data, packet_out->po_data_sz,
|
||||
buf, bufsz, &packet_sz, is_hello_packet);
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "lsquic_set.h"
|
||||
#include "lsquic_malo.h"
|
||||
#include "lsquic_chsk_stream.h"
|
||||
#include "lsquic_str.h"
|
||||
#include "lsquic_qtags.h"
|
||||
#include "lsquic_handshake.h"
|
||||
#include "lsquic_headers_stream.h"
|
||||
#include "lsquic_frame_common.h"
|
||||
|
@ -325,7 +327,8 @@ send_smhl (const struct full_conn *conn)
|
|||
uint32_t smhl;
|
||||
return conn->fc_conn.cn_enc_session
|
||||
&& (conn->fc_conn.cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||
&& 0 == get_peer_setting(conn->fc_conn.cn_enc_session, QTAG_SMHL, &smhl)
|
||||
&& 0 == conn->fc_conn.cn_esf->esf_get_peer_setting(
|
||||
conn->fc_conn.cn_enc_session, QTAG_SMHL, &smhl)
|
||||
&& 1 == smhl;
|
||||
}
|
||||
|
||||
|
@ -387,8 +390,8 @@ apply_peer_settings (struct full_conn *conn)
|
|||
#endif
|
||||
|
||||
for (n = 0; n < sizeof(tags) / sizeof(tags[0]); ++n)
|
||||
if (0 != get_peer_setting(conn->fc_conn.cn_enc_session,
|
||||
tags[n].tag, tags[n].val))
|
||||
if (0 != conn->fc_conn.cn_esf->esf_get_peer_setting(
|
||||
conn->fc_conn.cn_enc_session, tags[n].tag, tags[n].val))
|
||||
{
|
||||
LSQ_INFO("peer did not supply value for %s", tags[n].tag_str);
|
||||
return -1;
|
||||
|
@ -521,15 +524,20 @@ full_conn_client_new (struct lsquic_engine_public *enpub,
|
|||
const char *hostname, unsigned short max_packet_size)
|
||||
{
|
||||
struct full_conn *conn;
|
||||
enum lsquic_version version;
|
||||
lsquic_cid_t cid;
|
||||
const struct enc_session_funcs *esf;
|
||||
|
||||
cid = generate_cid();
|
||||
version = highest_bit_set(enpub->enp_settings.es_versions);
|
||||
esf = select_esf_by_ver(version);
|
||||
cid = esf->esf_generate_cid();
|
||||
conn = new_conn_common(cid, enpub, stream_if, stream_if_ctx, flags,
|
||||
max_packet_size);
|
||||
if (!conn)
|
||||
return NULL;
|
||||
conn->fc_conn.cn_enc_session = new_enc_session_c(hostname, cid,
|
||||
conn->fc_enpub);
|
||||
conn->fc_conn.cn_esf = esf;
|
||||
conn->fc_conn.cn_enc_session =
|
||||
conn->fc_conn.cn_esf->esf_create_client(hostname, cid, conn->fc_enpub);
|
||||
if (!conn->fc_conn.cn_enc_session)
|
||||
{
|
||||
LSQ_WARN("could not create enc session: %s", strerror(errno));
|
||||
|
@ -547,7 +555,6 @@ full_conn_client_new (struct lsquic_engine_public *enpub,
|
|||
conn->fc_stream_ifs[STREAM_IF_HSK]
|
||||
.stream_if = &lsquic_client_hsk_stream_if;
|
||||
conn->fc_stream_ifs[STREAM_IF_HSK].stream_if_ctx = &conn->fc_hsk_ctx.client;
|
||||
/* TODO the client does not know how to perform version negotiation */
|
||||
init_ver_neg(conn, conn->fc_settings->es_versions);
|
||||
conn->fc_conn.cn_pf = select_pf_by_ver(conn->fc_ver_neg.vn_ver);
|
||||
if (conn->fc_settings->es_handshake_to)
|
||||
|
@ -628,7 +635,7 @@ full_conn_ci_destroy (lsquic_conn_t *lconn)
|
|||
lsquic_send_ctl_cleanup(&conn->fc_send_ctl);
|
||||
lsquic_rechist_cleanup(&conn->fc_rechist);
|
||||
if (conn->fc_conn.cn_enc_session)
|
||||
free_enc_session(conn->fc_conn.cn_enc_session);
|
||||
conn->fc_conn.cn_esf->esf_destroy(conn->fc_conn.cn_enc_session);
|
||||
lsquic_malo_destroy(conn->fc_pub.packet_out_malo);
|
||||
#if FULL_CONN_STATS
|
||||
LSQ_NOTICE("received %u packets, of which %u were not decryptable, %u were "
|
||||
|
|
|
@ -3,20 +3,24 @@
|
|||
* Global state
|
||||
*/
|
||||
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic.h"
|
||||
#include "lsquic_str.h"
|
||||
#include "lsquic_handshake.h"
|
||||
#include "lsquic_util.h"
|
||||
|
||||
|
||||
int
|
||||
lsquic_global_init (int flags)
|
||||
{
|
||||
return handshake_init(flags);
|
||||
lsquic_init_timers();
|
||||
return lsquic_enc_session_gquic_1.esf_global_init(flags);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_global_cleanup (void)
|
||||
{
|
||||
handshake_cleanup();
|
||||
lsquic_enc_session_gquic_1.esf_global_cleanup();
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "lsquic.h"
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_crypto.h"
|
||||
#include "lsquic_str.h"
|
||||
#include "lsquic_handshake.h"
|
||||
#include "lsquic_parse.h"
|
||||
#include "lsquic_crt_compress.h"
|
||||
|
@ -25,9 +26,9 @@
|
|||
#include "lsquic_version.h"
|
||||
#include "lsquic_mm.h"
|
||||
#include "lsquic_engine_public.h"
|
||||
#include "lsquic_str.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_buf.h"
|
||||
#include "lsquic_qtags.h"
|
||||
|
||||
#include "fiu-local.h"
|
||||
|
||||
|
@ -38,6 +39,114 @@
|
|||
#define LSQUIC_LOGGER_MODULE LSQLM_HANDSHAKE
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
enum handshake_state
|
||||
{
|
||||
HSK_CHLO_REJ = 0,
|
||||
HSK_SHLO,
|
||||
HSK_COMPLETED,
|
||||
N_HSK_STATES
|
||||
};
|
||||
|
||||
#if LSQUIC_KEEP_ENC_SESS_HISTORY
|
||||
typedef unsigned char eshist_idx_t;
|
||||
|
||||
enum enc_sess_history_event
|
||||
{
|
||||
ESHE_EMPTY = '\0',
|
||||
ESHE_SET_SNI = 'I',
|
||||
ESHE_SET_SNO = 'O',
|
||||
ESHE_SET_STK = 'K',
|
||||
ESHE_SET_SCID = 'D',
|
||||
ESHE_SET_PROF = 'P',
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct hs_ctx_st
|
||||
{
|
||||
enum {
|
||||
HSET_TCID = (1 << 0), /* tcid is set */
|
||||
HSET_SMHL = (1 << 1), /* smhl is set */
|
||||
HSET_SCID = (1 << 2),
|
||||
} set;
|
||||
enum {
|
||||
HOPT_NSTP = (1 << 0), /* NSTP option present in COPT */
|
||||
HOPT_SREJ = (1 << 1), /* SREJ option present in COPT */
|
||||
} opts;
|
||||
uint32_t pdmd;
|
||||
uint32_t aead;
|
||||
uint32_t kexs;
|
||||
|
||||
uint32_t mids;
|
||||
uint32_t scls;
|
||||
uint32_t cfcw;
|
||||
uint32_t sfcw;
|
||||
uint32_t srbf;
|
||||
uint32_t icsl;
|
||||
|
||||
uint32_t irtt;
|
||||
uint64_t rcid;
|
||||
uint32_t tcid;
|
||||
uint32_t smhl;
|
||||
uint64_t ctim; /* any usage? */
|
||||
uint64_t sttl;
|
||||
unsigned char scid[SCID_LENGTH];
|
||||
//unsigned char chlo_hash[32]; //SHA256 HASH of CHLO
|
||||
unsigned char nonc[DNONC_LENGTH]; /* 4 tm, 8 orbit ---> REJ, 20 rand */
|
||||
unsigned char pubs[32];
|
||||
|
||||
uint32_t rrej;
|
||||
struct lsquic_str ccs;
|
||||
struct lsquic_str sni; /* 0 rtt */
|
||||
struct lsquic_str ccrt;
|
||||
struct lsquic_str stk;
|
||||
struct lsquic_str sno;
|
||||
struct lsquic_str prof;
|
||||
|
||||
struct lsquic_str csct;
|
||||
struct lsquic_str crt; /* compressed certs buffer */
|
||||
} hs_ctx_t;
|
||||
|
||||
|
||||
struct lsquic_enc_session
|
||||
{
|
||||
enum handshake_state hsk_state;
|
||||
|
||||
uint8_t have_key; /* 0, no 1, I, 2, D, 3, F */
|
||||
uint8_t peer_have_final_key;
|
||||
uint8_t server_start_use_final_key;
|
||||
|
||||
lsquic_cid_t cid;
|
||||
unsigned char priv_key[32];
|
||||
EVP_AEAD_CTX *enc_ctx_i;
|
||||
EVP_AEAD_CTX *dec_ctx_i;
|
||||
|
||||
/* Have to save the initial key for diversification need */
|
||||
unsigned char enc_key_i[aes128_key_len];
|
||||
unsigned char dec_key_i[aes128_key_len];
|
||||
unsigned char enc_key_nonce_i[aes128_iv_len];
|
||||
unsigned char dec_key_nonce_i[aes128_iv_len];
|
||||
|
||||
EVP_AEAD_CTX *enc_ctx_f;
|
||||
EVP_AEAD_CTX *dec_ctx_f;
|
||||
unsigned char enc_key_nonce_f[aes128_iv_len];
|
||||
unsigned char dec_key_nonce_f[aes128_iv_len];
|
||||
|
||||
hs_ctx_t hs_ctx;
|
||||
lsquic_session_cache_info_t *info;
|
||||
SSL_CTX * ssl_ctx;
|
||||
const struct lsquic_engine_public *enpub;
|
||||
struct lsquic_str * cert_ptr; /* pointer to the leaf cert of the server, not real copy */
|
||||
struct lsquic_str chlo; /* real copy of CHLO message */
|
||||
struct lsquic_str sstk;
|
||||
struct lsquic_str ssno;
|
||||
|
||||
#if LSQUIC_KEEP_ENC_SESS_HISTORY
|
||||
eshist_idx_t es_hist_idx;
|
||||
unsigned char es_hist_buf[1 << ESHIST_BITS];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/***
|
||||
* client side, it will store the domain/certs as cache cert
|
||||
|
@ -49,6 +158,15 @@ static struct lsquic_hash *s_cached_client_certs;
|
|||
*/
|
||||
static struct lsquic_hash *s_cached_client_session_infos;
|
||||
|
||||
/* save to hash table */
|
||||
static lsquic_session_cache_info_t *retrieve_session_info_entry(const char *key);
|
||||
static void remove_expire_session_info_entry();
|
||||
static void remove_session_info_entry(struct lsquic_str *key);
|
||||
|
||||
static void free_info (lsquic_session_cache_info_t *);
|
||||
|
||||
static void c_free_cert_hash_item (cert_hash_item_t *item);
|
||||
static void c_free_cert_hash_item(cert_hash_item_t *item);
|
||||
|
||||
|
||||
static int get_tag_val_u32 (unsigned char *v, int len, uint32_t *val);
|
||||
|
@ -74,8 +192,8 @@ eshist_append (lsquic_enc_session_t *enc_session,
|
|||
# define ESHIST_APPEND(sess, event) do { } while (0)
|
||||
#endif
|
||||
|
||||
int
|
||||
handshake_init(int flags)
|
||||
static int
|
||||
lsquic_handshake_init(int flags)
|
||||
{
|
||||
crypto_init();
|
||||
return init_hs_hash_tables(flags);
|
||||
|
@ -114,8 +232,8 @@ cleanup_hs_hash_tables (void)
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
handshake_cleanup (void)
|
||||
static void
|
||||
lsquic_handshake_cleanup (void)
|
||||
{
|
||||
cleanup_hs_hash_tables();
|
||||
lsquic_crt_cleanup();
|
||||
|
@ -141,7 +259,8 @@ static int init_hs_hash_tables(int flags)
|
|||
|
||||
|
||||
/* client */
|
||||
cert_hash_item_t* c_find_certs(lsquic_str_t *domain)
|
||||
cert_hash_item_t *
|
||||
c_find_certs (const lsquic_str_t *domain)
|
||||
{
|
||||
struct lsquic_hash_elem *el;
|
||||
|
||||
|
@ -159,7 +278,8 @@ cert_hash_item_t* c_find_certs(lsquic_str_t *domain)
|
|||
|
||||
/* client */
|
||||
/* certs is an array of lsquic_str_t * */
|
||||
cert_hash_item_t *make_cert_hash_item(lsquic_str_t *domain, lsquic_str_t **certs, int count)
|
||||
static cert_hash_item_t *
|
||||
make_cert_hash_item (lsquic_str_t *domain, lsquic_str_t **certs, int count)
|
||||
{
|
||||
int i;
|
||||
uint64_t hash;
|
||||
|
@ -180,7 +300,8 @@ cert_hash_item_t *make_cert_hash_item(lsquic_str_t *domain, lsquic_str_t **certs
|
|||
|
||||
|
||||
/* client */
|
||||
void c_free_cert_hash_item(cert_hash_item_t *item)
|
||||
void
|
||||
c_free_cert_hash_item (cert_hash_item_t *item)
|
||||
{
|
||||
int i;
|
||||
if (item)
|
||||
|
@ -196,7 +317,8 @@ void c_free_cert_hash_item(cert_hash_item_t *item)
|
|||
|
||||
|
||||
/* client */
|
||||
int c_insert_certs(cert_hash_item_t *item)
|
||||
static int
|
||||
c_insert_certs (cert_hash_item_t *item)
|
||||
{
|
||||
if (lsquic_hash_insert(s_cached_client_certs,
|
||||
lsquic_str_cstr(item->domain),
|
||||
|
@ -223,7 +345,8 @@ static int save_session_info_entry(lsquic_str_t *key, lsquic_session_cache_info_
|
|||
|
||||
|
||||
/* If entry updated and need to remove cached entry */
|
||||
void remove_session_info_entry(lsquic_str_t *key)
|
||||
static void
|
||||
remove_session_info_entry (lsquic_str_t *key)
|
||||
{
|
||||
lsquic_session_cache_info_t *entry;
|
||||
struct lsquic_hash_elem *el;
|
||||
|
@ -239,7 +362,7 @@ void remove_session_info_entry(lsquic_str_t *key)
|
|||
|
||||
|
||||
/* client */
|
||||
lsquic_session_cache_info_t *
|
||||
static lsquic_session_cache_info_t *
|
||||
retrieve_session_info_entry (const char *key)
|
||||
{
|
||||
lsquic_session_cache_info_t *entry;
|
||||
|
@ -262,7 +385,11 @@ retrieve_session_info_entry (const char *key)
|
|||
|
||||
|
||||
/* call it in timer() */
|
||||
void remove_expire_session_info_entry()
|
||||
#if __GNUC__
|
||||
__attribute__((unused))
|
||||
#endif
|
||||
static void
|
||||
remove_expire_session_info_entry (void)
|
||||
{
|
||||
time_t tm = time(NULL);
|
||||
struct lsquic_hash_elem *el;
|
||||
|
@ -280,8 +407,9 @@ void remove_expire_session_info_entry()
|
|||
}
|
||||
|
||||
|
||||
lsquic_enc_session_t *new_enc_session_c(const char *domain, lsquic_cid_t cid,
|
||||
const struct lsquic_engine_public *enpub)
|
||||
static lsquic_enc_session_t *
|
||||
lsquic_enc_session_create_client (const char *domain, lsquic_cid_t cid,
|
||||
const struct lsquic_engine_public *enpub)
|
||||
{
|
||||
lsquic_session_cache_info_t *info;
|
||||
lsquic_enc_session_t *enc_session;
|
||||
|
@ -318,7 +446,8 @@ lsquic_enc_session_t *new_enc_session_c(const char *domain, lsquic_cid_t cid,
|
|||
}
|
||||
|
||||
|
||||
void free_enc_session(lsquic_enc_session_t *enc_session)
|
||||
static void
|
||||
lsquic_enc_session_destroy (lsquic_enc_session_t *enc_session)
|
||||
{
|
||||
if (!enc_session)
|
||||
return ;
|
||||
|
@ -360,7 +489,8 @@ void free_enc_session(lsquic_enc_session_t *enc_session)
|
|||
}
|
||||
|
||||
|
||||
void free_info(lsquic_session_cache_info_t *info)
|
||||
static void
|
||||
free_info (lsquic_session_cache_info_t *info)
|
||||
{
|
||||
lsquic_str_d(&info->sstk);
|
||||
lsquic_str_d(&info->scfg);
|
||||
|
@ -376,7 +506,8 @@ static int get_hs_state(lsquic_enc_session_t *enc_session)
|
|||
|
||||
|
||||
/* make sure have more room for encrypt */
|
||||
int is_hs_done(lsquic_enc_session_t *enc_session)
|
||||
static int
|
||||
lsquic_enc_session_is_hsk_done (lsquic_enc_session_t *enc_session)
|
||||
{
|
||||
return (get_hs_state(enc_session) == HSK_COMPLETED);
|
||||
}
|
||||
|
@ -672,7 +803,8 @@ generate_cid_buf (void *buf, size_t bufsz)
|
|||
}
|
||||
|
||||
|
||||
lsquic_cid_t generate_cid(void)
|
||||
static lsquic_cid_t
|
||||
lsquic_generate_cid (void)
|
||||
{
|
||||
lsquic_cid_t cid;
|
||||
generate_cid_buf(&cid, sizeof(cid));
|
||||
|
@ -783,9 +915,9 @@ struct message_writer
|
|||
#define MSG_LEN_VAL(len) (+(len))
|
||||
|
||||
|
||||
int
|
||||
gen_chlo (lsquic_enc_session_t *enc_session, enum lsquic_version version,
|
||||
uint8_t *buf, size_t *len)
|
||||
static int
|
||||
lsquic_enc_session_gen_chlo (lsquic_enc_session_t *enc_session,
|
||||
enum lsquic_version version, uint8_t *buf, size_t *len)
|
||||
{
|
||||
int ret, include_pad;
|
||||
const lsquic_str_t *const ccs = get_common_certs_hash();
|
||||
|
@ -944,7 +1076,7 @@ gen_chlo (lsquic_enc_session_t *enc_session, enum lsquic_version version,
|
|||
else
|
||||
ret = 0;
|
||||
|
||||
LSQ_DEBUG("gen_chlo called, return %d, buf_len %zd.", ret, *len);
|
||||
LSQ_DEBUG("lsquic_enc_session_gen_chlo called, return %d, buf_len %zd.", ret, *len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1000,7 +1132,8 @@ void setup_aead_ctx(EVP_AEAD_CTX **ctx, unsigned char key[], int key_len,
|
|||
}
|
||||
|
||||
|
||||
int determine_diversification_key(lsquic_enc_session_t *enc_session,
|
||||
static int
|
||||
determine_diversification_key (lsquic_enc_session_t *enc_session,
|
||||
uint8_t *diversification_nonce
|
||||
)
|
||||
{
|
||||
|
@ -1177,8 +1310,9 @@ he2str (enum handshake_error he)
|
|||
* DATA_NOT_ENOUGH(-2) for not enough data,
|
||||
* DATA_FORMAT_ERROR(-1) all other errors
|
||||
*/
|
||||
int handle_chlo_reply(lsquic_enc_session_t *enc_session, const uint8_t *data,
|
||||
int len)
|
||||
static int
|
||||
lsquic_enc_session_handle_chlo_reply (lsquic_enc_session_t *enc_session,
|
||||
const uint8_t *data, int len)
|
||||
{
|
||||
uint32_t head_tag;
|
||||
int ret;
|
||||
|
@ -1278,7 +1412,7 @@ int handle_chlo_reply(lsquic_enc_session_t *enc_session, const uint8_t *data,
|
|||
}
|
||||
|
||||
end:
|
||||
LSQ_DEBUG("handle_chlo_reply called, buf in %d, return %d.", len, ret);
|
||||
LSQ_DEBUG("lsquic_enc_session_handle_chlo_reply called, buf in %d, return %d.", len, ret);
|
||||
EV_LOG_CONN_EVENT(enc_session->cid, "%s returning %s", __func__,
|
||||
he2str(ret));
|
||||
return ret;
|
||||
|
@ -1413,28 +1547,20 @@ decrypt_packet (lsquic_enc_session_t *enc_session, uint8_t path_id,
|
|||
}
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* In debug builds, we need to be able to override this function for testing */
|
||||
__attribute__((weak))
|
||||
int
|
||||
static int
|
||||
lsquic_enc_session_have_key_gt_one (const lsquic_enc_session_t *enc_session)
|
||||
{
|
||||
return enc_session && enc_session->have_key > 1;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* Use weak linkage so that tests can override this function */
|
||||
__attribute__((weak))
|
||||
#endif
|
||||
/* The size of `buf' is *header_len plus data_len. The two parts of the
|
||||
* buffer correspond to the header and the payload of incoming QUIC packet.
|
||||
*/
|
||||
/* 0 for OK, otherwise nonezero */
|
||||
int lsquic_dec(lsquic_enc_session_t *enc_session, enum lsquic_version version,
|
||||
static int
|
||||
lsquic_enc_session_decrypt (lsquic_enc_session_t *enc_session,
|
||||
enum lsquic_version version,
|
||||
uint8_t path_id, uint64_t pack_num,
|
||||
unsigned char *buf, size_t *header_len, size_t data_len,
|
||||
unsigned char *diversification_nonce,
|
||||
|
@ -1456,7 +1582,9 @@ int lsquic_dec(lsquic_enc_session_t *enc_session, enum lsquic_version version,
|
|||
}
|
||||
|
||||
|
||||
int lsquic_enc(lsquic_enc_session_t *enc_session, enum lsquic_version version,
|
||||
static int
|
||||
lsquic_enc_session_encrypt (lsquic_enc_session_t *enc_session,
|
||||
enum lsquic_version version,
|
||||
uint8_t path_id, uint64_t pack_num,
|
||||
const unsigned char *header, size_t header_len,
|
||||
const unsigned char *data, size_t data_len,
|
||||
|
@ -1507,7 +1635,7 @@ int lsquic_enc(lsquic_enc_session_t *enc_session, enum lsquic_version version,
|
|||
((IS_SERVER(enc_session)) &&
|
||||
enc_session->server_start_use_final_key == 0))
|
||||
{
|
||||
LSQ_DEBUG("lsquic_enc using 'I' key...");
|
||||
LSQ_DEBUG("lsquic_enc_session_encrypt using 'I' key...");
|
||||
key = enc_session->enc_ctx_i;
|
||||
memcpy(nonce, enc_session->enc_key_nonce_i, 4);
|
||||
if (is_shlo && enc_session->have_key == 3)
|
||||
|
@ -1517,7 +1645,7 @@ int lsquic_enc(lsquic_enc_session_t *enc_session, enum lsquic_version version,
|
|||
}
|
||||
else
|
||||
{
|
||||
LSQ_DEBUG("lsquic_enc using 'F' key...");
|
||||
LSQ_DEBUG("lsquic_enc_session_encrypt using 'F' key...");
|
||||
key = enc_session->enc_ctx_f;
|
||||
memcpy(nonce, enc_session->enc_key_nonce_f, 4);
|
||||
}
|
||||
|
@ -1536,8 +1664,9 @@ int lsquic_enc(lsquic_enc_session_t *enc_session, enum lsquic_version version,
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
get_peer_option (const lsquic_enc_session_t *enc_session, uint32_t tag)
|
||||
static int
|
||||
lsquic_enc_session_get_peer_option (const lsquic_enc_session_t *enc_session,
|
||||
uint32_t tag)
|
||||
{
|
||||
switch (tag)
|
||||
{
|
||||
|
@ -1555,9 +1684,9 @@ get_peer_option (const lsquic_enc_session_t *enc_session, uint32_t tag)
|
|||
/* Query a several parameters sent by the peer that are required by
|
||||
* connection.
|
||||
*/
|
||||
int
|
||||
get_peer_setting (const lsquic_enc_session_t *enc_session, uint32_t tag,
|
||||
uint32_t *val)
|
||||
static int
|
||||
lsquic_enc_session_get_peer_setting (const lsquic_enc_session_t *enc_session,
|
||||
uint32_t tag, uint32_t *val)
|
||||
{
|
||||
switch (tag)
|
||||
{
|
||||
|
@ -1616,7 +1745,7 @@ get_peer_setting (const lsquic_enc_session_t *enc_session, uint32_t tag,
|
|||
|
||||
|
||||
#if LSQUIC_KEEP_ENC_SESS_HISTORY
|
||||
void
|
||||
static void
|
||||
lsquic_get_enc_hist (const lsquic_enc_session_t *enc_session,
|
||||
char buf[(1 << ESHIST_BITS) + 1])
|
||||
{
|
||||
|
@ -1635,3 +1764,25 @@ lsquic_get_enc_hist (const lsquic_enc_session_t *enc_session,
|
|||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
const
|
||||
#endif
|
||||
struct enc_session_funcs lsquic_enc_session_gquic_1 =
|
||||
{
|
||||
.esf_global_init = lsquic_handshake_init,
|
||||
.esf_global_cleanup = lsquic_handshake_cleanup,
|
||||
#if LSQUIC_KEEP_ENC_SESS_HISTORY
|
||||
.esf_get_hist = lsquic_get_enc_hist,
|
||||
#endif
|
||||
.esf_destroy = lsquic_enc_session_destroy,
|
||||
.esf_is_hsk_done = lsquic_enc_session_is_hsk_done,
|
||||
.esf_encrypt = lsquic_enc_session_encrypt,
|
||||
.esf_decrypt = lsquic_enc_session_decrypt,
|
||||
.esf_get_peer_setting = lsquic_enc_session_get_peer_setting,
|
||||
.esf_get_peer_option = lsquic_enc_session_get_peer_option,
|
||||
.esf_create_client = lsquic_enc_session_create_client,
|
||||
.esf_generate_cid = lsquic_generate_cid,
|
||||
.esf_gen_chlo = lsquic_enc_session_gen_chlo,
|
||||
.esf_handle_chlo_reply = lsquic_enc_session_handle_chlo_reply,
|
||||
};
|
||||
|
|
|
@ -1,18 +1,11 @@
|
|||
/* Copyright (c) 2017 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#ifndef LSQUIC_HANDSHAKE_H
|
||||
#define LSQUIC_HANDSHAKE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <openssl/base.h>
|
||||
#include <openssl/aead.h>
|
||||
|
||||
#include <time.h>
|
||||
#include "lsquic_str.h"
|
||||
#ifndef LSQUIC_HANDSHAKE_SERVER_H
|
||||
#define LSQUIC_HANDSHAKE_SERVER_H
|
||||
|
||||
struct lsquic_engine_public;
|
||||
struct sockaddr;
|
||||
struct lsquic_enc_session;
|
||||
|
||||
#include "lsquic_qtags.h"
|
||||
typedef struct lsquic_enc_session lsquic_enc_session_t;
|
||||
|
||||
#define STK_LENGTH 60
|
||||
#define SNO_LENGTH 56
|
||||
|
@ -21,16 +14,6 @@ struct sockaddr;
|
|||
#define aes128_key_len 16
|
||||
#define aes128_iv_len 4
|
||||
|
||||
/* client side, certs and hashs
|
||||
*/
|
||||
typedef struct cert_hash_item_st
|
||||
{
|
||||
struct lsquic_str* domain; /*with port, such as "xyz.com:8088" as the key */
|
||||
struct lsquic_str* crts;
|
||||
struct lsquic_str* hashs;
|
||||
int count;
|
||||
} cert_hash_item_t;
|
||||
|
||||
enum handshake_error /* TODO: rename this enum */
|
||||
{
|
||||
DATA_NOT_ENOUGH = -2,
|
||||
|
@ -42,66 +25,6 @@ enum handshake_error /* TODO: rename this enum */
|
|||
HS_2RTT = 2,
|
||||
};
|
||||
|
||||
enum handshake_state
|
||||
{
|
||||
HSK_CHLO_REJ = 0,
|
||||
HSK_SHLO,
|
||||
HSK_COMPLETED,
|
||||
N_HSK_STATES
|
||||
};
|
||||
|
||||
typedef struct tag_value_st
|
||||
{
|
||||
uint32_t tag;
|
||||
const char * value;
|
||||
int len;
|
||||
} tag_value_t;
|
||||
|
||||
typedef struct hs_ctx_st
|
||||
{
|
||||
enum {
|
||||
HSET_TCID = (1 << 0), /* tcid is set */
|
||||
HSET_SMHL = (1 << 1), /* smhl is set */
|
||||
HSET_SCID = (1 << 2),
|
||||
} set;
|
||||
enum {
|
||||
HOPT_NSTP = (1 << 0), /* NSTP option present in COPT */
|
||||
HOPT_SREJ = (1 << 1), /* SREJ option present in COPT */
|
||||
} opts;
|
||||
uint32_t pdmd;
|
||||
uint32_t aead;
|
||||
uint32_t kexs;
|
||||
|
||||
uint32_t mids;
|
||||
uint32_t scls;
|
||||
uint32_t cfcw;
|
||||
uint32_t sfcw;
|
||||
uint32_t srbf;
|
||||
uint32_t icsl;
|
||||
|
||||
uint32_t irtt;
|
||||
uint64_t rcid;
|
||||
uint32_t tcid;
|
||||
uint32_t smhl;
|
||||
uint64_t ctim; /* any usage? */
|
||||
uint64_t sttl;
|
||||
unsigned char scid[SCID_LENGTH];
|
||||
//unsigned char chlo_hash[32]; //SHA256 HASH of CHLO
|
||||
unsigned char nonc[DNONC_LENGTH]; /* 4 tm, 8 orbit ---> REJ, 20 rand */
|
||||
unsigned char pubs[32];
|
||||
|
||||
uint32_t rrej;
|
||||
struct lsquic_str ccs;
|
||||
struct lsquic_str sni; /* 0 rtt */
|
||||
struct lsquic_str ccrt;
|
||||
struct lsquic_str stk;
|
||||
struct lsquic_str sno;
|
||||
struct lsquic_str prof;
|
||||
|
||||
struct lsquic_str csct;
|
||||
struct lsquic_str crt; /* compressed certs buffer */
|
||||
} hs_ctx_t;
|
||||
|
||||
/* client side need to store 0rtt info per STK */
|
||||
typedef struct lsquic_session_cache_info_st
|
||||
{
|
||||
|
@ -129,126 +52,89 @@ typedef struct lsquic_session_cache_info_st
|
|||
#endif
|
||||
|
||||
#if LSQUIC_KEEP_ENC_SESS_HISTORY
|
||||
|
||||
#define ESHIST_BITS 7
|
||||
#define ESHIST_MASK ((1 << ESHIST_BITS) - 1)
|
||||
#define ESHIST_STR_SIZE ((1 << ESHIST_BITS) + 1)
|
||||
typedef unsigned char eshist_idx_t;
|
||||
|
||||
enum enc_sess_history_event
|
||||
{
|
||||
ESHE_EMPTY = '\0',
|
||||
ESHE_SET_SNI = 'I',
|
||||
ESHE_SET_SNO = 'O',
|
||||
ESHE_SET_STK = 'K',
|
||||
ESHE_SET_SCID = 'D',
|
||||
ESHE_SET_PROF = 'P',
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct lsquic_enc_session
|
||||
struct enc_session_funcs
|
||||
{
|
||||
enum handshake_state hsk_state;
|
||||
|
||||
uint8_t have_key; /* 0, no 1, I, 2, D, 3, F */
|
||||
uint8_t peer_have_final_key;
|
||||
uint8_t server_start_use_final_key;
|
||||
/* Global initialization: call once per implementation */
|
||||
int (*esf_global_init)(int flags);
|
||||
|
||||
lsquic_cid_t cid;
|
||||
unsigned char priv_key[32];
|
||||
EVP_AEAD_CTX *enc_ctx_i;
|
||||
EVP_AEAD_CTX *dec_ctx_i;
|
||||
|
||||
/* Have to save the initial key for diversification need */
|
||||
unsigned char enc_key_i[aes128_key_len];
|
||||
unsigned char dec_key_i[aes128_key_len];
|
||||
unsigned char enc_key_nonce_i[aes128_iv_len];
|
||||
unsigned char dec_key_nonce_i[aes128_iv_len];
|
||||
|
||||
EVP_AEAD_CTX *enc_ctx_f;
|
||||
EVP_AEAD_CTX *dec_ctx_f;
|
||||
unsigned char enc_key_nonce_f[aes128_iv_len];
|
||||
unsigned char dec_key_nonce_f[aes128_iv_len];
|
||||
|
||||
hs_ctx_t hs_ctx;
|
||||
lsquic_session_cache_info_t *info;
|
||||
SSL_CTX * ssl_ctx;
|
||||
const struct lsquic_engine_public *enpub;
|
||||
struct lsquic_str * cert_ptr; /* pointer to the leaf cert of the server, not real copy */
|
||||
struct lsquic_str chlo; /* real copy of CHLO message */
|
||||
struct lsquic_str sstk;
|
||||
struct lsquic_str ssno;
|
||||
/* Global cleanup: call once per implementation */
|
||||
void (*esf_global_cleanup) (void);
|
||||
|
||||
#if LSQUIC_KEEP_ENC_SESS_HISTORY
|
||||
eshist_idx_t es_hist_idx;
|
||||
unsigned char es_hist_buf[1 << ESHIST_BITS];
|
||||
#endif
|
||||
} lsquic_enc_session_t;
|
||||
|
||||
#if LSQUIC_KEEP_ENC_SESS_HISTORY
|
||||
void
|
||||
lsquic_get_enc_hist (const lsquic_enc_session_t *, char buf[ESHIST_STR_SIZE]);
|
||||
/* Grab encryption session history */
|
||||
void (*esf_get_hist) (const lsquic_enc_session_t *,
|
||||
char buf[ESHIST_STR_SIZE]);
|
||||
#endif
|
||||
|
||||
int handshake_init(int flags);
|
||||
void handshake_cleanup();
|
||||
/* Destroy enc session */
|
||||
void (*esf_destroy)(lsquic_enc_session_t *enc_session);
|
||||
|
||||
lsquic_enc_session_t *
|
||||
new_enc_session_c(const char *domain, lsquic_cid_t cid,
|
||||
const struct lsquic_engine_public *);
|
||||
/* Return true if handshake has been completed */
|
||||
int (*esf_is_hsk_done)(lsquic_enc_session_t *enc_session);
|
||||
|
||||
void free_enc_session(lsquic_enc_session_t *enc_session);
|
||||
void free_info(lsquic_session_cache_info_t *info);
|
||||
|
||||
lsquic_cid_t generate_cid(void);
|
||||
|
||||
/* save to hash table */
|
||||
lsquic_session_cache_info_t *retrieve_session_info_entry(const char *key);
|
||||
void remove_expire_session_info_entry();
|
||||
void remove_session_info_entry(struct lsquic_str *key);
|
||||
|
||||
cert_hash_item_t *make_cert_hash_item(struct lsquic_str *domain, struct lsquic_str **certs, int count);
|
||||
void c_free_cert_hash_item(cert_hash_item_t *item);
|
||||
cert_hash_item_t* c_find_certs(struct lsquic_str *domain);
|
||||
int c_insert_certs(cert_hash_item_t *item);
|
||||
|
||||
/* -1 error, 0, OK, response in `buf' */
|
||||
int gen_chlo(lsquic_enc_session_t *enc_session, enum lsquic_version,
|
||||
uint8_t *buf, size_t *len);
|
||||
int handle_chlo_reply(lsquic_enc_session_t *enc_session, const uint8_t *data,
|
||||
int len);
|
||||
|
||||
int is_hs_done(lsquic_enc_session_t *enc_session);
|
||||
|
||||
/**
|
||||
* The belows are global functions
|
||||
*/
|
||||
|
||||
int lsquic_enc(lsquic_enc_session_t *enc_session, enum lsquic_version,
|
||||
/* Encrypt buffer */
|
||||
int (*esf_encrypt)(lsquic_enc_session_t *enc_session, enum lsquic_version,
|
||||
uint8_t path_id, uint64_t pack_num,
|
||||
const unsigned char *header, size_t header_len,
|
||||
const unsigned char *data, size_t data_len,
|
||||
unsigned char *buf_out, size_t max_out_len, size_t *out_len,
|
||||
int is_hello);
|
||||
|
||||
int lsquic_dec(lsquic_enc_session_t *enc_session, enum lsquic_version,
|
||||
uint8_t path_id, uint64_t pack_num,
|
||||
unsigned char *buf, size_t *header_len, size_t data_len,
|
||||
unsigned char *diversification_nonce,
|
||||
unsigned char *buf_out, size_t max_out_len, size_t *out_len);
|
||||
/* Decrypt buffer */
|
||||
int (*esf_decrypt)(lsquic_enc_session_t *enc_session, enum lsquic_version,
|
||||
uint8_t path_id, uint64_t pack_num,
|
||||
unsigned char *buf, size_t *header_len, size_t data_len,
|
||||
unsigned char *diversification_nonce,
|
||||
unsigned char *buf_out, size_t max_out_len, size_t *out_len);
|
||||
|
||||
int
|
||||
get_peer_setting (const lsquic_enc_session_t *, uint32_t tag, uint32_t *val);
|
||||
/* Get value of setting specified by `tag' */
|
||||
int (*esf_get_peer_setting) (const lsquic_enc_session_t *, uint32_t tag,
|
||||
uint32_t *val);
|
||||
|
||||
int
|
||||
get_peer_option (const lsquic_enc_session_t *enc_session, uint32_t tag);
|
||||
/* Get value of peer option (that from COPT array) */
|
||||
int (*esf_get_peer_option) (const lsquic_enc_session_t *enc_session,
|
||||
uint32_t tag);
|
||||
|
||||
/* Create client session */
|
||||
lsquic_enc_session_t *
|
||||
(*esf_create_client) (const char *domain, lsquic_cid_t cid,
|
||||
const struct lsquic_engine_public *);
|
||||
|
||||
/* Generate connection ID */
|
||||
lsquic_cid_t (*esf_generate_cid) (void);
|
||||
|
||||
/* -1 error, 0, OK, response in `buf' */
|
||||
int
|
||||
(*esf_gen_chlo) (lsquic_enc_session_t *, enum lsquic_version,
|
||||
uint8_t *buf, size_t *len);
|
||||
|
||||
int
|
||||
(*esf_handle_chlo_reply) (lsquic_enc_session_t *,
|
||||
const uint8_t *data, int len);
|
||||
};
|
||||
|
||||
extern
|
||||
#ifdef NDEBUG
|
||||
#define lsquic_enc_session_have_key_gt_one(e) ((e) && (e)->have_key > 1)
|
||||
#else
|
||||
int
|
||||
lsquic_enc_session_have_key_gt_one (const lsquic_enc_session_t *enc_session);
|
||||
const
|
||||
#endif
|
||||
struct enc_session_funcs lsquic_enc_session_gquic_1;
|
||||
|
||||
#define select_esf_by_ver(ver) \
|
||||
(ver ? &lsquic_enc_session_gquic_1 : &lsquic_enc_session_gquic_1)
|
||||
|
||||
/* client side, certs and hashs
|
||||
*/
|
||||
typedef struct cert_hash_item_st
|
||||
{
|
||||
struct lsquic_str* domain; /*with port, such as "xyz.com:8088" as the key */
|
||||
struct lsquic_str* crts;
|
||||
struct lsquic_str* hashs;
|
||||
int count;
|
||||
} cert_hash_item_t;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint64_t lsquic_time_t; /* Microseconds since the epoch */
|
||||
typedef uint64_t lsquic_time_t; /* Microseconds since some time */
|
||||
typedef uint64_t lsquic_packno_t;
|
||||
typedef uint32_t lsquic_ver_tag_t; /* Opaque 4-byte value */
|
||||
|
||||
|
|
|
@ -235,8 +235,6 @@ calculate_packet_rto (lsquic_send_ctl_t *ctl)
|
|||
exp = MAX_RTO_BACKOFFS;
|
||||
|
||||
delay = delay * (1 << exp);
|
||||
if (delay > MAX_RTO_DELAY)
|
||||
delay = MAX_RTO_DELAY;
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
@ -306,6 +304,9 @@ set_retx_alarm (lsquic_send_ctl_t *ctl)
|
|||
break;
|
||||
}
|
||||
|
||||
if (delay > MAX_RTO_DELAY)
|
||||
delay = MAX_RTO_DELAY;
|
||||
|
||||
LSQ_DEBUG("set retx alarm to %"PRIu64", which is %"PRIu64
|
||||
" usec from now, mode %s", now + delay, delay, retx2str[rm]);
|
||||
lsquic_alarmset_set(ctl->sc_alset, AL_RETX, now + delay);
|
||||
|
|
|
@ -8,17 +8,49 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if !(defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(__APPLE__)
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_util.h"
|
||||
|
||||
|
||||
#if defined(__APPLE__)
|
||||
static mach_timebase_info_data_t timebase;
|
||||
#endif
|
||||
|
||||
void
|
||||
lsquic_init_timers (void)
|
||||
{
|
||||
#if defined(__APPLE__)
|
||||
mach_timebase_info(&timebase);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
lsquic_time_t
|
||||
lsquic_time_now (void)
|
||||
{
|
||||
#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
|
||||
struct timespec ts;
|
||||
(void) clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (lsquic_time_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
|
||||
#elif defined(__APPLE__)
|
||||
lsquic_time_t t = mach_absolute_time();
|
||||
t *= timebase.numer;
|
||||
t /= timebase.denom;
|
||||
t /= 1000;
|
||||
return t;
|
||||
#else
|
||||
# warn Monotonically increasing clock is not available on this platform
|
||||
struct timeval tv;
|
||||
(void) gettimeofday(&tv, NULL);
|
||||
return (lsquic_time_t) tv.tv_sec * 1000000 + tv.tv_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,9 @@ extern "C" {
|
|||
lsquic_time_t
|
||||
lsquic_time_now (void);
|
||||
|
||||
void
|
||||
lsquic_init_timers (void);
|
||||
|
||||
/* Returns 1 if `buf' contains only zero bytes, 0 otherwise.
|
||||
*/
|
||||
int
|
||||
|
|
Loading…
Reference in New Issue