[FEATURE, API CHANGE] Support zero-sized CIDs in received packets
This commit is contained in:
parent
e98f5deb04
commit
96f77e2060
|
@ -1,3 +1,7 @@
|
|||
2018-05-30
|
||||
|
||||
- [FEATURE, API CHANGE] Support zero-sized CIDs in received packets
|
||||
|
||||
2018-05-24
|
||||
|
||||
- Close connection properly when packet encryption fails
|
||||
|
|
|
@ -319,8 +319,7 @@ struct lsquic_engine_settings {
|
|||
* If set to true value, the server will not include connection ID in
|
||||
* outgoing packets if client's CHLO specifies TCID=0.
|
||||
*
|
||||
* For client, this means including TCID=0 into CHLO message. TODO:
|
||||
* this does not work yet.
|
||||
* For client, this means including TCID=0 into CHLO message.
|
||||
*/
|
||||
int es_support_tcid0;
|
||||
|
||||
|
@ -492,7 +491,8 @@ lsquic_engine_new (unsigned lsquic_engine_flags,
|
|||
* 1350 for IPv6 and 1370 for IPv4.
|
||||
*/
|
||||
lsquic_conn_t *
|
||||
lsquic_engine_connect (lsquic_engine_t *, const struct sockaddr *peer_sa,
|
||||
lsquic_engine_connect (lsquic_engine_t *, const struct sockaddr *local_sa,
|
||||
const struct sockaddr *peer_sa,
|
||||
void *peer_ctx, lsquic_conn_ctx_t *conn_ctx,
|
||||
const char *hostname, unsigned short max_packet_size);
|
||||
|
||||
|
|
|
@ -51,23 +51,6 @@ lsquic_conn_record_sockaddr (lsquic_conn_t *lconn,
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_conn_record_peer_sa (lsquic_conn_t *lconn, const struct sockaddr *peer)
|
||||
{
|
||||
switch (peer->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
lconn->cn_flags |= LSCONN_HAS_PEER_SA;
|
||||
memcpy(lconn->cn_peer_addr, peer, sizeof(struct sockaddr_in));
|
||||
break;
|
||||
case AF_INET6:
|
||||
lconn->cn_flags |= LSCONN_HAS_PEER_SA;
|
||||
memcpy(lconn->cn_peer_addr, peer, sizeof(struct sockaddr_in6));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_conn_get_sockaddr (const lsquic_conn_t *lconn,
|
||||
const struct sockaddr **local, const struct sockaddr **peer)
|
||||
|
|
|
@ -113,9 +113,6 @@ void
|
|||
lsquic_conn_record_sockaddr (lsquic_conn_t *lconn, const struct sockaddr *local,
|
||||
const struct sockaddr *peer);
|
||||
|
||||
void
|
||||
lsquic_conn_record_peer_sa (lsquic_conn_t *lconn, const struct sockaddr *peer);
|
||||
|
||||
int
|
||||
lsquic_conn_decrypt_packet (lsquic_conn_t *lconn,
|
||||
struct lsquic_engine_public *, struct lsquic_packet_in *);
|
||||
|
|
|
@ -18,9 +18,61 @@
|
|||
#define conn_hash_mask(conn_hash) ((1 << (conn_hash)->ch_nbits) - 1)
|
||||
#define conn_hash_bucket_no(conn_hash, hash) (hash & conn_hash_mask(conn_hash))
|
||||
|
||||
#if FULL_LOCAL_ADDR_SUPPORTED
|
||||
#define HASHBUF_SZ (2 + sizeof(((struct sockaddr_in6 *) 0)->sin6_addr))
|
||||
#else
|
||||
#define HASHBUF_SZ 2
|
||||
#endif
|
||||
|
||||
|
||||
static const unsigned char *
|
||||
conn2hash_server (const struct lsquic_conn *lconn, unsigned char *buf,
|
||||
size_t *sz)
|
||||
{
|
||||
*sz = sizeof(lconn->cn_cid);
|
||||
return (unsigned char *) &lconn->cn_cid;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sockaddr2hash (const struct sockaddr *sa, unsigned char *buf, size_t *sz)
|
||||
{
|
||||
if (sa->sa_family == AF_INET)
|
||||
{
|
||||
const struct sockaddr_in *const sa4 = (void *) sa;
|
||||
memcpy(buf, &sa4->sin_port, 2);
|
||||
#if FULL_LOCAL_ADDR_SUPPORTED
|
||||
memcpy(buf + 2, &sa4->sin_addr, sizeof(sa4->sin_addr));
|
||||
*sz = 2 + sizeof(sa4->sin_addr);
|
||||
#else
|
||||
*sz = 2;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
const struct sockaddr_in6 *const sa6 = (void *) sa;
|
||||
memcpy(buf, &sa6->sin6_port, 2);
|
||||
#if FULL_LOCAL_ADDR_SUPPORTED
|
||||
memcpy(buf + 2, &sa6->sin6_addr, sizeof(sa6->sin6_addr));
|
||||
*sz = 2 + sizeof(sa6->sin6_addr);
|
||||
#else
|
||||
*sz = 2;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const unsigned char *
|
||||
conn2hash_client (const struct lsquic_conn *lconn, unsigned char *buf,
|
||||
size_t *sz)
|
||||
{
|
||||
sockaddr2hash((struct sockaddr *) &lconn->cn_local_addr, buf, sz);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
conn_hash_init (struct conn_hash *conn_hash)
|
||||
conn_hash_init (struct conn_hash *conn_hash, int server)
|
||||
{
|
||||
unsigned n;
|
||||
|
||||
|
@ -32,6 +84,10 @@ conn_hash_init (struct conn_hash *conn_hash)
|
|||
return -1;
|
||||
for (n = 0; n < n_buckets(conn_hash->ch_nbits); ++n)
|
||||
TAILQ_INIT(&conn_hash->ch_buckets[n]);
|
||||
if (server)
|
||||
conn_hash->ch_conn2hash = conn2hash_server;
|
||||
else
|
||||
conn_hash->ch_conn2hash = conn2hash_client;
|
||||
LSQ_INFO("initialized");
|
||||
return 0;
|
||||
}
|
||||
|
@ -45,7 +101,7 @@ conn_hash_cleanup (struct conn_hash *conn_hash)
|
|||
|
||||
|
||||
struct lsquic_conn *
|
||||
conn_hash_find (struct conn_hash *conn_hash, lsquic_cid_t cid)
|
||||
conn_hash_find_by_cid (struct conn_hash *conn_hash, lsquic_cid_t cid)
|
||||
{
|
||||
const unsigned hash = XXH32(&cid, sizeof(cid), (uintptr_t) conn_hash);
|
||||
const unsigned buckno = conn_hash_bucket_no(conn_hash, hash);
|
||||
|
@ -57,6 +113,31 @@ conn_hash_find (struct conn_hash *conn_hash, lsquic_cid_t cid)
|
|||
}
|
||||
|
||||
|
||||
struct lsquic_conn *
|
||||
conn_hash_find_by_addr (struct conn_hash *conn_hash, const struct sockaddr *sa)
|
||||
{
|
||||
unsigned char hash_buf[HASHBUF_SZ][2];
|
||||
struct lsquic_conn *lconn;
|
||||
unsigned hash, buckno;
|
||||
size_t hash_sz[2];
|
||||
|
||||
sockaddr2hash(sa, hash_buf[0], &hash_sz[0]);
|
||||
hash = XXH32(hash_buf, hash_sz[0], (uintptr_t) conn_hash);
|
||||
buckno = conn_hash_bucket_no(conn_hash, hash);
|
||||
TAILQ_FOREACH(lconn, &conn_hash->ch_buckets[buckno], cn_next_hash)
|
||||
if (lconn->cn_hash == hash)
|
||||
{
|
||||
sockaddr2hash((struct sockaddr *) lconn->cn_local_addr, hash_buf[1],
|
||||
&hash_sz[1]);
|
||||
if (hash_sz[0] == hash_sz[1]
|
||||
&& 0 == memcmp(hash_buf[0], hash_buf[1], hash_sz[0]))
|
||||
return lconn;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
double_conn_hash_buckets (struct conn_hash *conn_hash)
|
||||
{
|
||||
|
@ -98,8 +179,13 @@ double_conn_hash_buckets (struct conn_hash *conn_hash)
|
|||
int
|
||||
conn_hash_add (struct conn_hash *conn_hash, struct lsquic_conn *lconn)
|
||||
{
|
||||
const unsigned hash = XXH32(&lconn->cn_cid, sizeof(lconn->cn_cid),
|
||||
(uintptr_t) conn_hash);
|
||||
unsigned char hash_buf[HASHBUF_SZ];
|
||||
const unsigned char *key;
|
||||
size_t key_sz;
|
||||
unsigned hash, buckno;
|
||||
|
||||
key = conn_hash->ch_conn2hash(lconn, hash_buf, &key_sz);
|
||||
hash = XXH32(key, key_sz, (uintptr_t) conn_hash);
|
||||
if (conn_hash->ch_count >=
|
||||
n_buckets(conn_hash->ch_nbits) * CONN_HASH_MAX_PER_BUCKET &&
|
||||
conn_hash->ch_nbits < sizeof(hash) * 8 - 1 &&
|
||||
|
@ -107,7 +193,7 @@ conn_hash_add (struct conn_hash *conn_hash, struct lsquic_conn *lconn)
|
|||
{
|
||||
return -1;
|
||||
}
|
||||
const unsigned buckno = conn_hash_bucket_no(conn_hash, hash);
|
||||
buckno = conn_hash_bucket_no(conn_hash, hash);
|
||||
lconn->cn_hash = hash;
|
||||
TAILQ_INSERT_TAIL(&conn_hash->ch_buckets[buckno], lconn, cn_next_hash);
|
||||
++conn_hash->ch_count;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define CONN_HASH_MAX_PER_BUCKET 2
|
||||
|
||||
struct lsquic_conn;
|
||||
struct sockaddr;
|
||||
|
||||
TAILQ_HEAD(lsquic_conn_head, lsquic_conn);
|
||||
|
||||
|
@ -28,19 +29,24 @@ struct conn_hash
|
|||
} ch_iter;
|
||||
unsigned ch_count;
|
||||
unsigned ch_nbits;
|
||||
const unsigned char * (*ch_conn2hash)(const struct lsquic_conn *,
|
||||
unsigned char *, size_t *);
|
||||
};
|
||||
|
||||
#define conn_hash_count(conn_hash) (+(conn_hash)->ch_count)
|
||||
|
||||
/* Returns -1 if malloc fails */
|
||||
int
|
||||
conn_hash_init (struct conn_hash *);
|
||||
conn_hash_init (struct conn_hash *, int server);
|
||||
|
||||
void
|
||||
conn_hash_cleanup (struct conn_hash *);
|
||||
|
||||
struct lsquic_conn *
|
||||
conn_hash_find (struct conn_hash *conn_hash, lsquic_cid_t);
|
||||
conn_hash_find_by_cid (struct conn_hash *, lsquic_cid_t);
|
||||
|
||||
struct lsquic_conn *
|
||||
conn_hash_find_by_addr (struct conn_hash *, const struct sockaddr *);
|
||||
|
||||
/* Returns -1 if limit has been reached or if malloc fails */
|
||||
int
|
||||
|
|
|
@ -323,7 +323,7 @@ lsquic_engine_new (unsigned flags,
|
|||
engine->pub.enp_pmi_ctx = NULL;
|
||||
}
|
||||
engine->pub.enp_engine = engine;
|
||||
conn_hash_init(&engine->conns_hash);
|
||||
conn_hash_init(&engine->conns_hash, flags & ENG_SERVER);
|
||||
engine->attq = attq_create();
|
||||
eng_hist_init(&engine->history);
|
||||
engine->batch_size = INITIAL_OUT_BATCH_SIZE;
|
||||
|
@ -409,50 +409,28 @@ new_full_conn_client (lsquic_engine_t *engine, const char *hostname,
|
|||
if (!conn)
|
||||
return NULL;
|
||||
++engine->n_conns;
|
||||
if (0 != conn_hash_add(&engine->conns_hash, conn))
|
||||
{
|
||||
LSQ_WARN("cannot add connection %"PRIu64" to hash - destroy",
|
||||
conn->cn_cid);
|
||||
destroy_conn(engine, conn);
|
||||
return NULL;
|
||||
}
|
||||
assert(!(conn->cn_flags &
|
||||
(CONN_REF_FLAGS
|
||||
& ~LSCONN_TICKABLE /* This flag may be set as effect of user
|
||||
callbacks */
|
||||
)));
|
||||
conn->cn_flags |= LSCONN_HASHED;
|
||||
return conn;
|
||||
}
|
||||
|
||||
|
||||
static lsquic_conn_t *
|
||||
find_or_create_conn (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
|
||||
struct packin_parse_state *ppstate, const struct sockaddr *sa_peer,
|
||||
void *peer_ctx)
|
||||
find_conn (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
|
||||
struct packin_parse_state *ppstate, const struct sockaddr *sa_local)
|
||||
{
|
||||
lsquic_conn_t *conn;
|
||||
|
||||
if (lsquic_packet_in_is_prst(packet_in)
|
||||
&& !engine->pub.enp_settings.es_honor_prst)
|
||||
{
|
||||
LSQ_DEBUG("public reset packet: discarding");
|
||||
conn = conn_hash_find_by_addr(&engine->conns_hash, sa_local);
|
||||
if (!conn)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(packet_in->pi_flags & PI_CONN_ID))
|
||||
conn->cn_pf->pf_parse_packet_in_finish(packet_in, ppstate);
|
||||
if ((packet_in->pi_flags & PI_CONN_ID)
|
||||
&& conn->cn_cid != packet_in->pi_conn_id)
|
||||
{
|
||||
LSQ_DEBUG("packet header does not have connection ID: discarding");
|
||||
LSQ_DEBUG("connection IDs do not match");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
conn = conn_hash_find(&engine->conns_hash, packet_in->pi_conn_id);
|
||||
if (conn)
|
||||
{
|
||||
conn->cn_pf->pf_parse_packet_in_finish(packet_in, ppstate);
|
||||
return conn;
|
||||
}
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
|
@ -508,7 +486,16 @@ process_packet_in (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
|
|||
{
|
||||
lsquic_conn_t *conn;
|
||||
|
||||
conn = find_or_create_conn(engine, packet_in, ppstate, sa_peer, peer_ctx);
|
||||
if (lsquic_packet_in_is_prst(packet_in)
|
||||
&& !engine->pub.enp_settings.es_honor_prst)
|
||||
{
|
||||
lsquic_mm_put_packet_in(&engine->pub.enp_mm, packet_in);
|
||||
LSQ_DEBUG("public reset packet: discarding");
|
||||
return 1;
|
||||
}
|
||||
|
||||
conn = find_conn(engine, packet_in, ppstate, sa_local);
|
||||
|
||||
if (!conn)
|
||||
{
|
||||
lsquic_mm_put_packet_in(&engine->pub.enp_mm, packet_in);
|
||||
|
@ -567,7 +554,8 @@ lsquic_engine_destroy (lsquic_engine_t *engine)
|
|||
|
||||
|
||||
lsquic_conn_t *
|
||||
lsquic_engine_connect (lsquic_engine_t *engine, const struct sockaddr *peer_sa,
|
||||
lsquic_engine_connect (lsquic_engine_t *engine, const struct sockaddr *local_sa,
|
||||
const struct sockaddr *peer_sa,
|
||||
void *peer_ctx, lsquic_conn_ctx_t *conn_ctx,
|
||||
const char *hostname, unsigned short max_packet_size)
|
||||
{
|
||||
|
@ -596,9 +584,22 @@ lsquic_engine_connect (lsquic_engine_t *engine, const struct sockaddr *peer_sa,
|
|||
conn = new_full_conn_client(engine, hostname, max_packet_size);
|
||||
if (!conn)
|
||||
goto err;
|
||||
lsquic_conn_record_sockaddr(conn, local_sa, peer_sa);
|
||||
if (0 != conn_hash_add(&engine->conns_hash, conn))
|
||||
{
|
||||
LSQ_WARN("cannot add connection %"PRIu64" to hash - destroy",
|
||||
conn->cn_cid);
|
||||
destroy_conn(engine, conn);
|
||||
goto err;
|
||||
}
|
||||
assert(!(conn->cn_flags &
|
||||
(CONN_REF_FLAGS
|
||||
& ~LSCONN_TICKABLE /* This flag may be set as effect of user
|
||||
callbacks */
|
||||
)));
|
||||
conn->cn_flags |= LSCONN_HASHED;
|
||||
lsquic_mh_insert(&engine->conns_tickable, conn, conn->cn_last_ticked);
|
||||
engine_incref_conn(conn, LSCONN_TICKABLE);
|
||||
lsquic_conn_record_peer_sa(conn, peer_sa);
|
||||
conn->cn_peer_ctx = peer_ctx;
|
||||
lsquic_conn_set_ctx(conn, conn_ctx);
|
||||
full_conn_client_call_on_new(conn);
|
||||
|
|
|
@ -964,6 +964,10 @@ lsquic_enc_session_gen_chlo (lsquic_enc_session_t *enc_session,
|
|||
}
|
||||
else
|
||||
ua_len = 0;
|
||||
if (settings->es_support_tcid0)
|
||||
{
|
||||
MSG_LEN_ADD(msg_len, 4); ++n_tags; /* TCID */
|
||||
}
|
||||
MSG_LEN_ADD(msg_len, lsquic_str_len(&enc_session->hs_ctx.sni));
|
||||
++n_tags; /* SNI */
|
||||
MSG_LEN_ADD(msg_len, lsquic_str_len(ccs)); ++n_tags; /* CCS */
|
||||
|
@ -1034,6 +1038,8 @@ lsquic_enc_session_gen_chlo (lsquic_enc_session_t *enc_session,
|
|||
if (lsquic_str_len(&enc_session->info->scfg) > 0)
|
||||
MW_WRITE_BUFFER(&mw, QTAG_SCID, enc_session->info->sscid,
|
||||
sizeof(enc_session->info->sscid));
|
||||
if (settings->es_support_tcid0)
|
||||
MW_WRITE_UINT32(&mw, QTAG_TCID, 0);
|
||||
MW_WRITE_UINT32(&mw, QTAG_PDMD, settings->es_pdmd);
|
||||
MW_WRITE_UINT32(&mw, QTAG_SMHL, 1);
|
||||
MW_WRITE_UINT32(&mw, QTAG_ICSL, settings->es_idle_conn_to / 1000000);
|
||||
|
|
|
@ -251,6 +251,7 @@ prog_connect (struct prog *prog)
|
|||
|
||||
sport = TAILQ_FIRST(prog->prog_sports);
|
||||
if (NULL == lsquic_engine_connect(prog->prog_engine,
|
||||
(struct sockaddr *) &sport->sp_local_addr,
|
||||
(struct sockaddr *) &sport->sas, sport, NULL,
|
||||
prog->prog_hostname ? prog->prog_hostname : sport->host,
|
||||
prog->prog_max_packet_size))
|
||||
|
|
|
@ -512,7 +512,7 @@ read_one_packet (struct read_iter *iter)
|
|||
#endif
|
||||
|
||||
local_addr = &packs_in->local_addresses[iter->ri_idx];
|
||||
memcpy(local_addr, &sport->sas, sizeof(*local_addr));
|
||||
memcpy(local_addr, &sport->sp_local_addr, sizeof(*local_addr));
|
||||
#if __linux__
|
||||
n_dropped = 0;
|
||||
#endif
|
||||
|
@ -753,6 +753,9 @@ sport_init_client (struct service_port *sport, struct lsquic_engine *engine,
|
|||
return -1;
|
||||
}
|
||||
|
||||
memcpy((void *) &sport->sp_local_addr, sa_local,
|
||||
sa_local->sa_family == AF_INET ?
|
||||
sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
|
||||
switch (sa_local->sa_family) {
|
||||
case AF_INET:
|
||||
LSQ_DEBUG("local address: %s:%d",
|
||||
|
|
|
@ -47,6 +47,7 @@ struct service_port {
|
|||
void *conn_ctx;
|
||||
char host[80];
|
||||
struct sockaddr_storage sas;
|
||||
struct sockaddr_storage sp_local_addr;
|
||||
struct packets_in *packs_in;
|
||||
enum sport_flags sp_flags;
|
||||
int sp_sndbuf; /* If SPORT_SET_SNDBUF is set */
|
||||
|
|
|
@ -48,14 +48,14 @@ main (int argc, char **argv)
|
|||
lsquic_set_log_level("info");
|
||||
|
||||
malo = lsquic_malo_create(sizeof(*lconn));
|
||||
s = conn_hash_init(&conn_hash);
|
||||
s = conn_hash_init(&conn_hash, 1);
|
||||
assert(0 == s);
|
||||
|
||||
for (n = 0; n < nelems; ++n)
|
||||
{
|
||||
lconn = get_new_lsquic_conn(malo);
|
||||
lconn->cn_if = (void *) (uintptr_t) n; /* This will be used for verification later the test */
|
||||
find_lsconn = conn_hash_find(&conn_hash, lconn->cn_cid);
|
||||
find_lsconn = conn_hash_find_by_cid(&conn_hash, lconn->cn_cid);
|
||||
assert(!find_lsconn);
|
||||
s = conn_hash_add(&conn_hash, lconn);
|
||||
assert(0 == s);
|
||||
|
@ -66,10 +66,10 @@ main (int argc, char **argv)
|
|||
for (lconn = lsquic_malo_first(malo); lconn;
|
||||
lconn = lsquic_malo_next(malo))
|
||||
{
|
||||
find_lsconn = conn_hash_find(&conn_hash, lconn->cn_cid);
|
||||
find_lsconn = conn_hash_find_by_cid(&conn_hash, lconn->cn_cid);
|
||||
assert(find_lsconn == lconn);
|
||||
conn_hash_remove(&conn_hash, lconn);
|
||||
find_lsconn = conn_hash_find(&conn_hash, lconn->cn_cid);
|
||||
find_lsconn = conn_hash_find_by_cid(&conn_hash, lconn->cn_cid);
|
||||
assert(!find_lsconn);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue