/*
 * Copyright (C) Nginx, Inc.
 */


#ifndef _NGX_EVENT_QUIC_CONNECTION_H_INCLUDED_
#define _NGX_EVENT_QUIC_CONNECTION_H_INCLUDED_


#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>


/* #define NGX_QUIC_DEBUG_PACKETS */  /* dump packet contents */
/* #define NGX_QUIC_DEBUG_FRAMES */   /* dump frames contents */
/* #define NGX_QUIC_DEBUG_ALLOC */    /* log frames and bufs alloc */
/* #define NGX_QUIC_DEBUG_CRYPTO */

#define NGX_QUIC_ENCRYPTION_INITIAL          0
#define NGX_QUIC_ENCRYPTION_EARLY_DATA       1
#define NGX_QUIC_ENCRYPTION_HANDSHAKE        2
#define NGX_QUIC_ENCRYPTION_APPLICATION      3
#define NGX_QUIC_ENCRYPTION_LAST             4

#define NGX_QUIC_SEND_CTX_LAST               (NGX_QUIC_ENCRYPTION_LAST - 1)


typedef struct ngx_quic_connection_s  ngx_quic_connection_t;
typedef struct ngx_quic_server_id_s   ngx_quic_server_id_t;
typedef struct ngx_quic_client_id_s   ngx_quic_client_id_t;
typedef struct ngx_quic_send_ctx_s    ngx_quic_send_ctx_t;
typedef struct ngx_quic_socket_s      ngx_quic_socket_t;
typedef struct ngx_quic_path_s        ngx_quic_path_t;
typedef struct ngx_quic_keys_s        ngx_quic_keys_t;

#if (NGX_QUIC_OPENSSL_COMPAT)
#include <ngx_event_quic_openssl_compat.h>
#endif
#include <ngx_event_quic_transport.h>
#include <ngx_event_quic_protection.h>
#include <ngx_event_quic_frames.h>
#include <ngx_event_quic_migration.h>
#include <ngx_event_quic_connid.h>
#include <ngx_event_quic_streams.h>
#include <ngx_event_quic_ssl.h>
#include <ngx_event_quic_tokens.h>
#include <ngx_event_quic_ack.h>
#include <ngx_event_quic_output.h>
#include <ngx_event_quic_socket.h>


/* RFC 9002, 6.2.2.  Handshakes and New Paths: kInitialRtt */
#define NGX_QUIC_INITIAL_RTT                 333 /* ms */

#define NGX_QUIC_UNSET_PN                    (uint64_t) -1

/*  0-RTT and 1-RTT data exist in the same packet number space,
 *  so we have 3 packet number spaces:
 *
 *  0 - Initial
 *  1 - Handshake
 *  2 - 0-RTT and 1-RTT
 */
#define ngx_quic_get_send_ctx(qc, level)                                      \
    ((level) == NGX_QUIC_ENCRYPTION_INITIAL) ? &((qc)->send_ctx[0])           \
        : (((level) == NGX_QUIC_ENCRYPTION_HANDSHAKE) ? &((qc)->send_ctx[1])  \
                                                      : &((qc)->send_ctx[2]))

#define ngx_quic_get_connection(c)                                            \
    (((c)->udp) ? (((ngx_quic_socket_t *)((c)->udp))->quic) : NULL)

#define ngx_quic_get_socket(c)               ((ngx_quic_socket_t *)((c)->udp))

#define ngx_quic_init_rtt(qc)                                                 \
    (qc)->avg_rtt = NGX_QUIC_INITIAL_RTT;                                     \
    (qc)->rttvar = NGX_QUIC_INITIAL_RTT / 2;                                  \
    (qc)->min_rtt = NGX_TIMER_INFINITE;                                       \
    (qc)->first_rtt = NGX_TIMER_INFINITE;                                     \
    (qc)->latest_rtt = 0;


typedef enum {
    NGX_QUIC_PATH_IDLE = 0,
    NGX_QUIC_PATH_VALIDATING,
    NGX_QUIC_PATH_WAITING,
    NGX_QUIC_PATH_MTUD
} ngx_quic_path_state_e;


struct ngx_quic_client_id_s {
    ngx_queue_t                       queue;
    uint64_t                          seqnum;
    size_t                            len;
    u_char                            id[NGX_QUIC_CID_LEN_MAX];
    u_char                            sr_token[NGX_QUIC_SR_TOKEN_LEN];
    ngx_uint_t                        used;  /* unsigned  used:1; */
};


struct ngx_quic_server_id_s {
    uint64_t                          seqnum;
    size_t                            len;
    u_char                            id[NGX_QUIC_CID_LEN_MAX];
};


struct ngx_quic_path_s {
    ngx_queue_t                       queue;
    struct sockaddr                  *sockaddr;
    ngx_sockaddr_t                    sa;
    socklen_t                         socklen;
    ngx_quic_client_id_t             *cid;
    ngx_quic_path_state_e             state;
    ngx_msec_t                        expires;
    ngx_uint_t                        tries;
    ngx_uint_t                        tag;
    size_t                            mtu;
    size_t                            mtud;
    size_t                            max_mtu;
    off_t                             sent;
    off_t                             received;
    u_char                            challenge[2][8];
    uint64_t                          seqnum;
    uint64_t                          mtu_pnum[NGX_QUIC_PATH_RETRIES];
    ngx_str_t                         addr_text;
    u_char                            text[NGX_SOCKADDR_STRLEN];
    unsigned                          validated:1;
    unsigned                          mtu_unvalidated:1;
};


struct ngx_quic_socket_s {
    ngx_udp_connection_t              udp;
    ngx_quic_connection_t            *quic;
    ngx_queue_t                       queue;
    ngx_quic_server_id_t              sid;
    ngx_sockaddr_t                    sockaddr;
    socklen_t                         socklen;
    ngx_uint_t                        used; /* unsigned  used:1; */
};


typedef struct {
    ngx_rbtree_t                      tree;
    ngx_rbtree_node_t                 sentinel;

    ngx_queue_t                       uninitialized;
    ngx_queue_t                       free;

    uint64_t                          sent;
    uint64_t                          recv_offset;
    uint64_t                          recv_window;
    uint64_t                          recv_last;
    uint64_t                          recv_max_data;
    uint64_t                          send_offset;
    uint64_t                          send_max_data;

    uint64_t                          server_max_streams_uni;
    uint64_t                          server_max_streams_bidi;
    uint64_t                          server_streams_uni;
    uint64_t                          server_streams_bidi;

    uint64_t                          client_max_streams_uni;
    uint64_t                          client_max_streams_bidi;
    uint64_t                          client_streams_uni;
    uint64_t                          client_streams_bidi;

    ngx_uint_t                        initialized;
                                                 /* unsigned  initialized:1; */
} ngx_quic_streams_t;


typedef struct {
    size_t                            in_flight;
    size_t                            window;
    size_t                            ssthresh;
    size_t                            w_max;
    size_t                            w_est;
    size_t                            w_prior;
    size_t                            mtu;
    ngx_msec_t                        recovery_start;
    ngx_msec_t                        idle_start;
    ngx_msec_t                        k;
    ngx_uint_t                        idle; /* unsigned  idle:1; */
} ngx_quic_congestion_t;


/*
 * RFC 9000, 12.3.  Packet Numbers
 *
 *  Conceptually, a packet number space is the context in which a packet
 *  can be processed and acknowledged.  Initial packets can only be sent
 *  with Initial packet protection keys and acknowledged in packets that
 *  are also Initial packets.
 */
struct ngx_quic_send_ctx_s {
    ngx_uint_t                        level;

    ngx_quic_buffer_t                 crypto;
    uint64_t                          crypto_sent;

    uint64_t                          pnum;        /* to be sent */
    uint64_t                          largest_ack; /* received from peer */
    uint64_t                          largest_pn;  /* received from peer */

    ngx_queue_t                       frames;      /* generated frames */
    ngx_queue_t                       sending;     /* frames assigned to pkt */
    ngx_queue_t                       sent;        /* frames waiting ACK */

    uint64_t                          pending_ack; /* non sent ack-eliciting */
    uint64_t                          largest_range;
    uint64_t                          first_range;
    ngx_msec_t                        largest_received;
    ngx_msec_t                        ack_delay_start;
    ngx_uint_t                        nranges;
    ngx_quic_ack_range_t              ranges[NGX_QUIC_MAX_RANGES];
    ngx_uint_t                        send_ack;
};


struct ngx_quic_connection_s {
    uint32_t                          version;

    ngx_quic_path_t                  *path;

    ngx_queue_t                       sockets;
    ngx_queue_t                       paths;
    ngx_queue_t                       client_ids;
    ngx_queue_t                       free_sockets;
    ngx_queue_t                       free_paths;
    ngx_queue_t                       free_client_ids;

    ngx_uint_t                        nsockets;
    ngx_uint_t                        nclient_ids;
    uint64_t                          max_retired_seqnum;
    uint64_t                          client_seqnum;
    uint64_t                          server_seqnum;
    uint64_t                          path_seqnum;

    ngx_quic_tp_t                     tp;
    ngx_quic_tp_t                     ctp;

    ngx_quic_send_ctx_t               send_ctx[NGX_QUIC_SEND_CTX_LAST];

    ngx_quic_keys_t                  *keys;

    ngx_quic_conf_t                  *conf;

    ngx_event_t                       push;
    ngx_event_t                       pto;
    ngx_event_t                       close;
    ngx_event_t                       path_validation;
    ngx_event_t                       key_update;

    ngx_msec_t                        last_cc;

    ngx_msec_t                        first_rtt;
    ngx_msec_t                        latest_rtt;
    ngx_msec_t                        avg_rtt;
    ngx_msec_t                        min_rtt;
    ngx_msec_t                        rttvar;

    ngx_uint_t                        pto_count;

    ngx_queue_t                       free_frames;
    ngx_buf_t                        *free_bufs;
    ngx_buf_t                        *free_shadow_bufs;

    ngx_uint_t                        nframes;
    ngx_uint_t                        max_frames;
#ifdef NGX_QUIC_DEBUG_ALLOC
    ngx_uint_t                        nbufs;
    ngx_uint_t                        nshadowbufs;
#endif

#if (NGX_QUIC_OPENSSL_COMPAT)
    ngx_quic_compat_t                *compat;
#endif

    ngx_quic_streams_t                streams;
    ngx_quic_congestion_t             congestion;

    uint64_t                          rst_pnum;    /* first on validated path */

    off_t                             received;

    ngx_uint_t                        error;
    ngx_uint_t                        error_level;
    ngx_uint_t                        error_ftype;
    const char                       *error_reason;

    ngx_uint_t                        shutdown_code;
    const char                       *shutdown_reason;

    unsigned                          error_app:1;
    unsigned                          send_timer_set:1;
    unsigned                          closing:1;
    unsigned                          shutdown:1;
    unsigned                          draining:1;
    unsigned                          key_phase:1;
    unsigned                          validated:1;
    unsigned                          client_tp_done:1;

#if (NGX_QUIC_OPENSSL_API)
    unsigned                          read_level:2;
    unsigned                          write_level:2;
#endif
};


ngx_int_t ngx_quic_apply_transport_params(ngx_connection_t *c,
    ngx_quic_tp_t *ctp);
void ngx_quic_discard_ctx(ngx_connection_t *c, ngx_uint_t level);
void ngx_quic_close_connection(ngx_connection_t *c, ngx_int_t rc);
void ngx_quic_shutdown_quic(ngx_connection_t *c);

#if (NGX_DEBUG)
void ngx_quic_connstate_dbg(ngx_connection_t *c);
#else
#define ngx_quic_connstate_dbg(c)
#endif

#endif /* _NGX_EVENT_QUIC_CONNECTION_H_INCLUDED_ */
