/*
 *  OpenVPN -- An application to securely tunnel IP networks
 *             over a single UDP port, with support for SSL/TLS-based
 *             session authentication and key exchange,
 *             packet encryption, packet authentication, and
 *             packet compression.
 *
 *  Copyright (C) 2002-2026 OpenVPN Inc <sales@openvpn.net>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, see <https://www.gnu.org/licenses/>.
 */


/**
 * @file
 * Reliability Layer module header file.
 */


#ifndef RELIABLE_H
#define RELIABLE_H

#include "basic.h"
#include "buffer.h"
#include "packet_id.h"
#include "session_id.h"
#include "mtu.h"

/** @addtogroup reliable
 *  @{ */


#define RELIABLE_ACK_SIZE                       \
    8 /**< The maximum number of packet IDs     \
       *   waiting to be acknowledged which can \
       *   be stored in one \c reliable_ack     \
       *   structure. */

#define RELIABLE_CAPACITY                      \
    12 /**< The maximum number of packets that \
        *   the reliability layer for one VPN  \
        *   tunnel in one direction can store. */

#define N_ACK_RETRANSMIT                      \
    3 /**< We retry sending a packet early if \
       *   this many later packets have been  \
       *   ACKed. */

/**
 * The acknowledgment structure in which packet IDs are stored for later
 * acknowledgment.
 */
struct reliable_ack
{
    int len;
    packet_id_type packet_id[RELIABLE_ACK_SIZE];
};

/* The size of the ACK header */
#define ACK_SIZE(n) (sizeof(uint8_t) + ((n) ? SID_SIZE : 0) + sizeof(packet_id_type) * (n))

/**
 * The structure in which the reliability layer stores a single incoming
 * or outgoing packet.
 */
struct reliable_entry
{
    bool active;
    interval_t timeout;
    time_t next_try;
    packet_id_type packet_id;
    size_t n_acks; /* Number of acks received for packets with higher PID.
                    * Used for fast retransmission when there were at least
                    * N_ACK_RETRANSMIT. */
    int opcode;
    struct buffer buf;
};

/**
 * The reliability layer storage structure for one VPN tunnel's control
 * channel in one direction.
 */
struct reliable
{
    int size;
    interval_t initial_timeout;
    packet_id_type packet_id;
    int offset; /**< Offset of the bufs in the reliable_entry array */
    bool hold;  /* don't xmit until reliable_schedule_now is called */
    struct reliable_entry array[RELIABLE_CAPACITY];
};


/**************************************************************************/
/** @name Functions for processing incoming acknowledgments
 *  @{ */

/**
 * Read an acknowledgment record from a received packet.
 *
 * This function reads the packet ID acknowledgment record from the packet
 * contained in \a buf.  If the record contains acknowledgments, these are
 * stored in \a ack.  This function also compares the packet's session ID
 * with the expected session ID \a sid, which should be equal.
 *
 * @param ack The acknowledgment structure in which received
 *     acknowledgments are to be stored.
 * @param buf The buffer containing the packet.
 * @param sid The expected session ID to compare to the session ID in
 *     the packet.
 *
 * @return
 * @li True, if processing was successful.
 * @li False, if an error occurs during processing.
 */
bool reliable_ack_read(struct reliable_ack *ack, struct buffer *buf, const struct session_id *sid);


/**
 * Parse an acknowledgment record from a received packet.
 *
 * This function parses the packet ID acknowledgment record from the packet
 * contained in \a buf.  If the record contains acknowledgments, these are
 * stored in \a ack.  This function also extracts packet's session ID
 * and returns it in \a session_id_remote
 *
 * @param ack The acknowledgment structure in which received
 *     acknowledgments are to be stored.
 * @param buf The buffer containing the packet.
 * @param session_id_remote The parsed remote session id. This field is
 *                          is only filled if ack->len >= 1
 * @return
 * @li True, if processing was successful.
 * @li False, if an error occurs during processing.
 */
bool reliable_ack_parse(struct buffer *buf, struct reliable_ack *ack,
                        struct session_id *session_id_remote);

/**
 * Remove acknowledged packets from a reliable structure.
 *
 * @param rel The reliable structure storing sent packets.
 * @param ack The acknowledgment structure containing received
 *     acknowledgments.
 */
void reliable_send_purge(struct reliable *rel, const struct reliable_ack *ack);

/** @} name Functions for processing incoming acknowledgments */


/**************************************************************************/
/** @name Functions for processing outgoing acknowledgments
 *  @{ */

/**
 * Check whether an acknowledgment structure contains any
 *     packet IDs to be acknowledged.
 *
 * @param ack The acknowledgment structure to check.
 *
 * @return
 * @li True, if the acknowledgment structure is empty.
 * @li False, if there are packet IDs to be acknowledged.
 */
static inline bool
reliable_ack_empty(struct reliable_ack *ack)
{
    return !ack->len;
}

/**
 * Returns the number of packets that need to be acked.
 *
 * @param ack The acknowledgment structure to check.
 *
 * @returns the number of outstanding acks
 */
static inline int
reliable_ack_outstanding(struct reliable_ack *ack)
{
    return ack->len;
}


/**
 * Write a packet ID acknowledgment record to a buffer.
 *
 * @param ack The acknowledgment structure containing packet IDs to be
 *     acknowledged.
 * @param ack_mru List of packets we have acknowledged before. Packets from
 *                \c ack will be moved here and if there is space in our
 *                ack structure we will fill it with packets from this
 * @param buf The buffer into which the acknowledgment record will be
 *     written.
 * @param sid The session ID of the VPN tunnel associated with the
 *     packet IDs to be acknowledged.
 * @param max The maximum number of acknowledgments to be written in
 *     the record.
 * @param prepend If true, prepend the acknowledgment record in the
 *     buffer; if false, write into the buffer's current position.
 *
 * @return
 * @li True, if processing was successful.
 * @li False, if an error occurs during processing.
 */
bool reliable_ack_write(struct reliable_ack *ack, struct reliable_ack *ack_mru, struct buffer *buf,
                        const struct session_id *sid, int max, bool prepend);

/** @} name Functions for processing outgoing acknowledgments */


/**************************************************************************/
/** @name Functions for initialization and cleanup
 *  @{ */

/**
 * Initialize a reliable structure.
 *
 * @param rel The reliable structure to initialize.
 * @param buf_size The size of the buffers in which packets will be
 *     stored.
 * @param offset The size of reserved space at the beginning of the
 *     buffers to allow efficient header prepending.
 * @param array_size The number of packets that this reliable
 *     structure can store simultaneously.
 * @param hold description
 */
void reliable_init(struct reliable *rel, int buf_size, int offset, int array_size, bool hold);

/**
 * Free allocated memory associated with a reliable structure and the pointer
 * itself.
 * Does nothing if rel is NULL.
 *
 * @param rel The reliable structured to clean up.
 */
void reliable_free(struct reliable *rel);

/** @} name Functions for initialization and cleanup */


/**************************************************************************/
/** @name Functions for inserting incoming packets
 *  @{ */

/**
 * Check whether a reliable structure has any free buffers
 *     available for use.
 *
 * @param rel The reliable structure to check.
 *
 * @return
 * @li True, if at least one buffer is available for use.
 * @li False, if all the buffers are active.
 */
bool reliable_can_get(const struct reliable *rel);

/**
 * Check that a received packet's ID is not a replay.
 *
 * @param rel The reliable structure for handling this VPN tunnel's
 *     received packets.
 * @param id The packet ID of the received packet.
 *
 * @return
 * @li True, if the packet ID is not a replay.
 * @li False, if the packet ID is a replay.
 */
bool reliable_not_replay(const struct reliable *rel, packet_id_type id);

/**
 * Check that a received packet's ID can safely be stored in
 *     the reliable structure's processing window.
 *
 * This function checks the difference between the received packet's ID
 * and the lowest non-acknowledged packet ID in the given reliable
 * structure.  If that difference is larger than the total number of
 * packets which can be stored, then this packet cannot be stored safely,
 * because the reliable structure could possibly fill up without leaving
 * room for all intervening packets.  In that case, this received packet
 * could break the reliable structure's sequentiality, and must therefore
 * be discarded.
 *
 * @param rel The reliable structure for handling this VPN tunnel's
 *     received packets.
 * @param id The packet ID of the received packet.
 *
 * @return
 * @li True, if the packet can safely be stored.
 * @li False, if the packet does not fit safely in the reliable
 *     structure's processing window.
 */
bool reliable_wont_break_sequentiality(const struct reliable *rel, packet_id_type id);

/**
 * Read the packet ID of a received packet.
 *
 * @param buf The buffer containing the received packet.
 * @param pid A pointer where the packet's packet ID will be written.
 *
 * @return
 * @li True, if processing was successful.
 * @li False, if an error occurs during processing.
 */
bool reliable_ack_read_packet_id(struct buffer *buf, packet_id_type *pid);

/**
 * Get the buffer of a free %reliable entry in which to store a
 *     packet.
 *
 * @param rel The reliable structure in which to search for a free
 *     entry.
 *
 * @return A pointer to a buffer of a free entry in the \a rel
 *     reliable structure.  If there are no free entries available, this
 *     function returns NULL.
 */
struct buffer *reliable_get_buf(struct reliable *rel);

/**
 * Mark the %reliable entry associated with the given buffer as active
 * incoming.
 *
 * @param rel The reliable structure associated with this packet.
 * @param buf The buffer into which the packet has been copied.
 * @param pid The packet's packet ID.
 * @param opcode The packet's opcode.
 */
void reliable_mark_active_incoming(struct reliable *rel, struct buffer *buf, packet_id_type pid,
                                   int opcode);

/**
 * Record a packet ID for later acknowledgment.
 *
 * @param ack The acknowledgment structure which stores this VPN
 *     tunnel's packet IDs for later acknowledgment.
 * @param pid The packet ID of the received packet which should be
 *     acknowledged.
 *
 * @return
 * @li True, if the packet ID was added to \a ack.
 * @li False, if the packet ID was already present in \a ack or \a ack
 *     has no free space to store any more packet IDs.
 */
bool reliable_ack_acknowledge_packet_id(struct reliable_ack *ack, packet_id_type pid);

/** @} name Functions for inserting incoming packets */


/**************************************************************************/
/** @name Functions for extracting incoming packets
 *  @{ */

/**
 * Get the buffer of the next sequential and active entry.
 *
 * @param rel The reliable structure from which to retrieve the
 *     buffer.
 *
 * @return A pointer to the entry with the next sequential key ID.
 *     If no such entry is present, this function  returns NULL.
 */
struct reliable_entry *reliable_get_entry_sequenced(struct reliable *rel);


/**
 * Copies the first n acks from \c ack to \c ack_mru
 *
 * @param ack The reliable structure to copy the acks from
 * @param ack_mru The reliable structure to insert the acks into
 * @param n The number of ACKS to copy
 */
void copy_acks_to_mru(struct reliable_ack *ack, struct reliable_ack *ack_mru, int n);


/**
 * Remove an entry from a reliable structure.
 *
 * @param rel The reliable structure associated with the given buffer.
 * @param buf The buffer of the reliable entry which is to be removed.
 */
void reliable_mark_deleted(struct reliable *rel, struct buffer *buf);

/** @} name Functions for extracting incoming packets */


/**************************************************************************/
/** @name Functions for inserting outgoing packets
 *  @{ */

/**
 * Get the buffer of free reliable entry and check whether the
 *     outgoing acknowledgment sequence is still okay.
 *
 * @param rel The reliable structure in which to search for a free
 *     entry.
 *
 * @return A pointer to a buffer of a free entry in the \a rel
 *     reliable structure.  If there are no free entries available, this
 *     function returns NULL.  If the outgoing acknowledgment sequence is
 *     broken, this function also returns NULL.
 */
struct buffer *reliable_get_buf_output_sequenced(struct reliable *rel);


/**
 * Counts the number of free buffers in output that can be potentially used
 * for sending
 *
 *  @param rel The reliable structure in which to search for a free
 *     entry.
 *
 *  @return the number of buffer that are available for sending without
 *             breaking ack sequence
 * */
int reliable_get_num_output_sequenced_available(struct reliable *rel);

/**
 * Mark the reliable entry associated with the given buffer as
 *     active outgoing.
 *
 * @param rel The reliable structure for handling this VPN tunnel's
 *     outgoing packets.
 * @param buf The buffer previously returned by \c
 *     reliable_get_buf_output_sequenced() into which the packet has been
 *     copied.
 * @param opcode The packet's opcode.
 */
void reliable_mark_active_outgoing(struct reliable *rel, struct buffer *buf, int opcode);

/** @} name Functions for inserting outgoing packets */


/**************************************************************************/
/** @name Functions for extracting outgoing packets
 *  @{ */

/**
 * Check whether a reliable structure has any active entries
 *     ready to be (re)sent.
 *
 * @param rel The reliable structure to check.
 *
 * @return
 * @li True, if there are active entries ready to be (re)sent
 *     president.
 * @li False, if there are no active entries, or the active entries
 *     are not yet ready for resending.
 */
bool reliable_can_send(const struct reliable *rel);

/**
 * Get the next packet to send to the remote peer.
 *
 * This function looks for the active entry ready for (re)sending with the
 * lowest packet ID, and returns the buffer associated with it.  This
 * function also resets the timeout after which that entry will become
 * ready for resending again.
 *
 * @param rel The reliable structure to check.
 * @param opcode A pointer to an integer in which this function will
 *     store the opcode of the next packet to be sent.
 *
 * @return A pointer to the buffer of the next entry to be sent, or
 *     NULL if there are no entries ready for (re)sending present in the
 *     reliable structure.  If a valid pointer is returned, then \a opcode
 *     will point to the opcode of that packet.
 */
struct buffer *reliable_send(struct reliable *rel, int *opcode);

/** @} name Functions for extracting outgoing packets */


/**************************************************************************/
/** @name Miscellaneous functions
 *  @{ */

/**
 * Check whether a reliable structure is empty.
 *
 * @param rel The reliable structure to check.
 *
 * @return
 * @li True, if there are no active entries in the given reliable
 *     structure.
 * @li False, if there is at least one active entry present.
 */
bool reliable_empty(const struct reliable *rel);

/**
 * Determined how many seconds until the earliest resend should
 *     be attempted.
 *
 * @param rel The reliable structured to check.
 *
 * @return The interval in seconds until the earliest resend attempt
 *     of the outgoing packets stored in the \a rel reliable structure. If
 *     the next time for attempting resending of one or more packets has
 *     already passed, this function will return 0.
 */
interval_t reliable_send_timeout(const struct reliable *rel);

/**
 * Reschedule all entries of a reliable structure to be ready
 *     for (re)sending immediately.
 *
 * @param rel The reliable structure of which the entries should be
 *     modified.
 */
void reliable_schedule_now(struct reliable *rel);

void reliable_debug_print(const struct reliable *rel, char *desc);

/* set sending timeout (after this time we send again until ACK) */
static inline void
reliable_set_timeout(struct reliable *rel, interval_t timeout)
{
    rel->initial_timeout = timeout;
}

/* print a reliable ACK record coming off the wire */
const char *reliable_ack_print(struct buffer *buf, bool verbose, struct gc_arena *gc);

void reliable_ack_debug_print(const struct reliable_ack *ack, char *desc);

/** @} name Miscellaneous functions */


/** @} addtogroup reliable */


#endif /* RELIABLE_H */
