/*
 * Copyright (c) 2017 Fastly, Kazuho Oku
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */
#ifndef quicly_constants_h
#define quicly_constants_h

#ifdef __cplusplus
extern "C" {
#endif

#include <stddef.h>
#include <stdint.h>
#include "picotls.h"

#define QUICLY_DELAYED_ACK_TIMEOUT 25   /* milliseconds */
#define QUICLY_DEFAULT_MAX_ACK_DELAY 25 /* milliseconds */
#define QUICLY_LOCAL_MAX_ACK_DELAY 25   /* milliseconds */
#define QUICLY_DEFAULT_ACK_DELAY_EXPONENT 3
#define QUICLY_LOCAL_ACK_DELAY_EXPONENT 10
#define QUICLY_MIN_INITIAL_DCID_LEN 8
#define QUICLY_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT 2 /* If this transport parameter is absent, a default of 2 is assumed. (18.2) */
/**
 * how many CIDs is quicly willing to manage at the same time?
 * this value is used in two ways:
 * - active_connection_id_limit transport parameter advertised to the remote peer
 * - maximum number of connection IDs we issue to the remote peer at a moment
 */
#define QUICLY_LOCAL_ACTIVE_CONNECTION_ID_LIMIT 4
#define QUICLY_MIN_ACTIVE_CONNECTION_ID_LIMIT 2
#define QUICLY_DEFAULT_MAX_UDP_PAYLOAD_SIZE 65527
#define QUICLY_MIN_CLIENT_INITIAL_SIZE 1200
#define QUICLY_DEFAULT_MIN_PTO 1      /* milliseconds */
#define QUICLY_DEFAULT_INITIAL_RTT 66 /* initial retransmission timeout is *3, i.e. 200ms */
#define QUICLY_LOSS_DEFAULT_PACKET_THRESHOLD 3

#define QUICLY_DEFAULT_PACKET_TOLERANCE 2
#define QUICLY_MAX_PACKET_TOLERANCE 10
#define QUICLY_FIRST_ACK_FREQUENCY_LOSS_EPISODE 4

#define QUICLY_AEAD_TAG_SIZE 16

#define QUICLY_MAX_CID_LEN_V1 20
#define QUICLY_STATELESS_RESET_TOKEN_LEN 16

#define QUICLY_EPOCH_INITIAL 0
#define QUICLY_EPOCH_0RTT 1
#define QUICLY_EPOCH_HANDSHAKE 2
#define QUICLY_EPOCH_1RTT 3
#define QUICLY_NUM_EPOCHS 4

/**
 * Error code used by quicly. The code coalesces the following to an int64_t.
 * * 0..0x2ff: picotls error codes (of type int)
 * * 0x30000..0x400000000002ffff: QUIC application error codes
 * * 0x4000000000030000..0x800000000002ffff...: QUIC protocol error codes
 * Internal error codes should be allocated from the unused space below 0x30000 (i.e., unused space of picotls error codes);
 * quicly itself uses 0xffxx. `quicly_error_t` is defined as a signed type so that the picotls error code space can be mapped
 * without sign conversion.
 */
typedef int64_t quicly_error_t;

#define QUICLY_ERROR_IS_QUIC(e) ((uint64_t)(quicly_error_t)(e) - 0x30000u < 0x8000000000000000u)
#define QUICLY_ERROR_IS_QUIC_TRANSPORT(e) ((uint64_t)(quicly_error_t)(e) - 0x4000000000030000u < 0x4000000000000000u)
#define QUICLY_ERROR_IS_QUIC_APPLICATION(e) ((uint64_t)(quicly_error_t)(e) - 0x30000u < 0x4000000000000000u)
#define QUICLY_ERROR_GET_ERROR_CODE(e) (((uint64_t)(quicly_error_t)(e) - 0x30000u) & 0x3fffffffffffffffu)
#define QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(e) ((quicly_error_t)((uint64_t)(e) + 0x4000000000030000u))
#define QUICLY_ERROR_FROM_APPLICATION_ERROR_CODE(e) ((quicly_error_t)(uint64_t)(e) + 0x30000)
/**
 * PTLS_ERROR_NO_MEMORY and QUICLY_ERROR_STATE_EXHAUSTION are special error codes that are internal but can be passed to
 * quicly_close. These are converted to QUICLY_TRANSPORT_ERROR_INTERNAL when sent over the wire.
 */
#define QUICLY_ERROR_IS_CONCEALED(err) ((err) == PTLS_ERROR_NO_MEMORY || (err) == QUICLY_ERROR_STATE_EXHAUSTION)

/* transport error codes */
#define QUICLY_TRANSPORT_ERROR_NONE QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0x0)
#define QUICLY_TRANSPORT_ERROR_INTERNAL QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0x1)
#define QUICLY_TRANSPORT_ERROR_CONNECTION_REFUSED QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0x2)
#define QUICLY_TRANSPORT_ERROR_FLOW_CONTROL QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0x3)
#define QUICLY_TRANSPORT_ERROR_STREAM_LIMIT QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0x4)
#define QUICLY_TRANSPORT_ERROR_STREAM_STATE QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0x5)
#define QUICLY_TRANSPORT_ERROR_FINAL_SIZE QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0x6)
#define QUICLY_TRANSPORT_ERROR_FRAME_ENCODING QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0x7)
#define QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0x8)
#define QUICLY_TRANSPORT_ERROR_CONNECTION_ID_LIMIT QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0x9)
#define QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0xa)
#define QUICLY_TRANSPORT_ERROR_INVALID_TOKEN QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0xb)
#define QUICLY_TRANSPORT_ERROR_APPLICATION QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0xc)
#define QUICLY_TRANSPORT_ERROR_CRYPTO_BUFFER_EXCEEDED QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0xd)
#define QUICLY_TRANSPORT_ERROR_KEY_UPDATE QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0xe)
#define QUICLY_TRANSPORT_ERROR_AEAD_LIMIT_REACHED QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0xf)
#define QUICLY_TRANSPORT_ERROR_CRYPTO(tls_alert) QUICLY_ERROR_FROM_TRANSPORT_ERROR_CODE(0x100 + (tls_alert))

/* local error codes, used for signaling status between quicly and the application */
#define QUICLY_ERROR_PACKET_IGNORED 0xff01
#define QUICLY_ERROR_SENDBUF_FULL 0xff02    /* internal use only; the error code is never exposed to the application */
#define QUICLY_ERROR_FREE_CONNECTION 0xff03 /* returned by quicly_send when the connection is freeable */
#define QUICLY_ERROR_RECEIVED_STATELESS_RESET 0xff04
#define QUICLY_ERROR_NO_COMPATIBLE_VERSION 0xff05
#define QUICLY_ERROR_IS_CLOSING 0xff06 /* indicates that the connection has already entered closing state */
#define QUICLY_ERROR_STATE_EXHAUSTION 0xff07
#define QUICLY_ERROR_INVALID_INITIAL_VERSION 0xff08
#define QUICLY_ERROR_DECRYPTION_FAILED 0xff09

typedef int64_t quicly_stream_id_t;

typedef struct st_quicly_conn_t quicly_conn_t;

static uint32_t quicly_u32_add_saturating(uint32_t x, uint32_t y);

/**
 * Used for emitting arbitrary debug message through probes. The debug message might get emitted unescaped as a JSON string,
 * therefore cannot contain characters that are required to be escaped as a JSON string (e.g., `\n`, `"`).
 */
void quicly__debug_printf(quicly_conn_t *conn, const char *function, int line, const char *fmt, ...)
    __attribute__((format(printf, 4, 5)));

#define quicly_debug_printf(conn, ...) quicly__debug_printf((conn), __FUNCTION__, __LINE__, __VA_ARGS__)

/* inline definitions */

inline uint32_t quicly_u32_add_saturating(uint32_t x, uint32_t y)
{
#ifdef __GNUC__ /* GCC or clang */
    uint32_t r;
    return __builtin_add_overflow(x, y, &r) ? UINT32_MAX : r;
#else
    return x > UINT32_MAX - y ? UINT32_MAX : x + y;
#endif
}

#ifdef __cplusplus
}
#endif

#endif
