return (ack_frm->ack_delay << conn->tx.params.ack_delay_exponent) / 1000;
}
+/* Client only.
+ * Do its best to store <tok> token received from a NEW_TOKEN frame into <s>
+ * server SSL cache for sessions to reuse.
+ */
+static inline void qc_try_store_new_token(struct server *s,
+ const unsigned char *tok,
+ size_t len)
+{
+ /* Cached token */
+ unsigned char *stok;
+
+ HA_RWLOCK_RDLOCK(SSL_SERVER_LOCK, &s->ssl_ctx.lock);
+
+ stok = s->ssl_ctx.reused_sess[tid].tok;
+
+ HA_RWLOCK_WRLOCK(SSL_SERVER_LOCK, &s->ssl_ctx.reused_sess[tid].sess_lock);
+ if (len > s->ssl_ctx.reused_sess[tid].toklen) {
+ stok = realloc(stok, len);
+ if (stok) {
+ s->ssl_ctx.reused_sess[tid].tok = stok;
+ }
+ else {
+ free(s->ssl_ctx.reused_sess[tid].tok);
+ s->ssl_ctx.reused_sess[tid].toklen = 0;
+ }
+ }
+
+ if (stok) {
+ memcpy(stok, tok, len);
+ s->ssl_ctx.reused_sess[tid].toklen = len;
+ }
+
+ HA_RWLOCK_WRUNLOCK(SSL_SERVER_LOCK, &s->ssl_ctx.reused_sess[tid].sess_lock);
+ HA_RWLOCK_RDUNLOCK(SSL_SERVER_LOCK, &s->ssl_ctx.lock);
+}
+
/* Parse all the frames of <pkt> QUIC packet for QUIC connection <qc> and <qel>
* as encryption level.
* Returns 1 if succeeded, 0 if failed.
goto err;
}
else {
- /* TODO NEW_TOKEN not implemented on client side.
- * Note that for now token is not copied into <data> field
- * of qf_new_token frame. See quic_parse_new_token_frame()
- * for further explanations.
- */
+ struct qf_new_token *new_tok_frm = &frm->new_token;
+
+ qc_try_store_new_token(__objt_server(qc->target),
+ new_tok_frm->r_data, new_tok_frm->len);
}
break;
case QUIC_FT_STREAM_8 ... QUIC_FT_STREAM_F:
return ((now_ms - time_received) * 1000) >> conn->tx.params.ack_delay_exponent;
}
+
+/* Encode the <tok> token data field made of <toklen> bytes at <pos> buffer
+ * address. <end> points to the byte following the end of <*pos> buffer.
+ * Note that the type of the frame which embed this token is not encoded.
+ * Return 1 if succeeded, 0 if not.
+ */
+static inline int quic_do_enc_token(unsigned char **pos, const unsigned char *end,
+ const unsigned char *tok, size_t toklen)
+{
+ if (!quic_enc_int(pos, end, toklen) || end - *pos <= toklen)
+ return 0;
+
+ if (toklen) {
+ memcpy(*pos, tok, toklen);
+ *pos += toklen;
+ }
+
+ return 1;
+}
+
+/* Encode a token depending on <qc> connection type (listener or not).
+ * For listeners, ony a null byte is encoded (no token).
+ * For clients, if a RETRY token has been received, it is encoded, if not, if a
+ * new token has been received (from NEW_TOKEN frame) and could be retrieved
+ * from cache, it is encoded, if not a null byte is encoded (no token).
+ */
+static inline int quic_enc_token(struct quic_conn *qc,
+ unsigned char **pos, const unsigned char *end)
+{
+ int ret = 0;
+ const unsigned char *tok;
+ size_t toklen;
+
+ if (objt_listener(qc->target)) {
+ ret = quic_do_enc_token(pos, end, NULL, 0);
+ }
+ else if (qc->retry_token) {
+ tok = qc->retry_token;
+ toklen = qc->retry_token_len;
+ ret = quic_do_enc_token(pos, end, tok, toklen);
+ }
+ else {
+ struct server *s = __objt_server(qc->target);
+
+ HA_RWLOCK_RDLOCK(SSL_SERVER_LOCK, &s->ssl_ctx.lock);
+ if (s->ssl_ctx.reused_sess[tid].tok) {
+ tok = s->ssl_ctx.reused_sess[tid].tok;
+ toklen = s->ssl_ctx.reused_sess[tid].toklen;
+ ret = quic_do_enc_token(pos, end, tok, toklen);
+ }
+ else {
+ uint old_tid = HA_ATOMIC_LOAD(&s->ssl_ctx.last_ssl_sess_tid);
+ if (old_tid) {
+ HA_RWLOCK_RDLOCK(SSL_SERVER_LOCK, &s->ssl_ctx.reused_sess[old_tid-1].sess_lock);
+ tok = s->ssl_ctx.reused_sess[old_tid-1].tok;
+ toklen = s->ssl_ctx.reused_sess[old_tid-1].toklen;
+ ret = quic_do_enc_token(pos, end, tok, toklen);
+ HA_RWLOCK_RDUNLOCK(SSL_SERVER_LOCK, &s->ssl_ctx.reused_sess[old_tid-1].sess_lock);
+ }
+ else
+ ret = quic_do_enc_token(pos, end, NULL, 0);
+ }
+ HA_RWLOCK_RDUNLOCK(SSL_SERVER_LOCK, &s->ssl_ctx.lock);
+ }
+
+ return ret;
+}
+
/* This function builds a clear packet from <pkt> information (its type)
* into a buffer with <pos> as position pointer and <qel> as QUIC TLS encryption
* level for <conn> QUIC connection and <qel> as QUIC TLS encryption level,
/* Encode the token length (0) for an Initial packet. */
if (pkt->type == QUIC_PACKET_TYPE_INITIAL) {
- if (!quic_enc_int(&pos, end, qc->retry_token_len) ||
- end - pos <= qc->retry_token_len)
+ if (!quic_enc_token(qc, &pos, end))
goto no_room;
-
- if (qc->retry_token_len) {
- memcpy(pos, qc->retry_token, qc->retry_token_len);
- pos += qc->retry_token_len;
- }
}
head_len = pos - beg;