// Copyright (C) 2001-2015 Federico Montesino Pouzols <fedemp@altern.org>.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// 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 Lesser General Public License
// along with GNU ccRTP.  If not, see <http://www.gnu.org/licenses/>.
//
// As a special exception, you may use this file as part of a free software
// library without restriction.  Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License.  This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
//
// This exception applies only to the code released under the name GNU
// ccRTP.  If you copy code from other releases into a copy of GNU
// ccRTP, as the General Public License permits, the exception does
// not apply to the code that you add in this way.  To avoid misleading
// anyone as to the status of such modified files, you must delete
// this exception notice from them.
//
// If you write modifications of your own for GNU ccRTP, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice.
//

#ifndef CCXX_RTP_RTCPPKT_H_
#define CCXX_RTP_RTCPPKT_H_

#include <ccrtp/base.h>

NAMESPACE_COMMONCPP

/**
 * @file rtcppkt.h
 *
 * @short RTCP packets handling.
 **/

/**
 * @defgroup rtcppacket RTCP compound packets manipulation.
 * @{
 **/

/**
 * @enum SDESItemType
 * @short SDES items that may be carried in a Source DEScription RTCP packet.
 *
 * CNAME is mandatory in each RTCP compound packet (except when
 * splitted for partial encryption), the others are optional and have
 * different sending frequencies, though with recommended default
 * values.
 **/
typedef enum
{
    SDESItemTypeEND = 0,         ///< END of SDES item list.
    SDESItemTypeCNAME,           ///< Canonical end-point identifier.
    SDESItemTypeNAME,            ///< Personal NAME of the user.
    SDESItemTypeEMAIL,           ///< EMAIL address of the user.
    SDESItemTypePHONE,           ///< Phone number of the user.
    SDESItemTypeLOC,             ///< Location where the user is.
    SDESItemTypeTOOL,            ///< Application or tool.
    SDESItemTypeNOTE,            ///< Comment usually reporting state.
    SDESItemTypePRIV,            ///< Private extension.
    SDESItemTypeH323CADDR,       ///< H323 callable address.
    SDESItemTypeLast = SDESItemTypeH323CADDR ///< Last defined code.
}       SDESItemType;

/**
 * @class RTCPCompoundHandler
 * @short low level structs and RTCP packet parsing and building
 * methods.
 *
 * Intended to be used, through inheritance, in RTCP management
 * classes, such as QueueRTCPManager.
 *
 * @author Federico Montesino Pouzols <fedemp@altern.org>
 **/
class __EXPORT RTCPCompoundHandler
{
public:
    inline void setPathMTU(uint16 mtu)
    { pathMTU = mtu; }

    inline uint16 getPathMTU()
    { return pathMTU; }

#ifdef  CCXX_PACKED
#pragma pack(1)
#endif
    /**
     * @struct ReceiverInfo
     *
     * Struct for the data contained in a receiver info
     * block. Receiver info blocks can be found in SR (sender
     * report) or RR (receiver report) RTCP packets.
     **/
    struct ReceiverInfo
    {
        uint8 fractionLost;      ///< packet fraction lost.
        uint8 lostMSB;           ///< cumulative lost MSB of 3 octets.
        uint16 lostLSW;          ///< cumulative lost two LSB.
        uint32 highestSeqNum;    ///< highest sequence number.
        uint32 jitter;           ///< arrival jitter.
        uint32 lsr;              ///< last sender report timestamp.
        uint32 dlsr;             ///< delay since last sender report.
    };

    /**
     * @struct RRBlock
     *
     * Struct for a receiver info block in a SR (sender report) or an RR
     * (receiver report) RTCP packet.
     **/
    struct RRBlock
    {
        uint32 ssrc;                   ///< source identifier.
        ReceiverInfo rinfo;            ///< info about the source.
    };

    /**
     * @struct RecvReport
     *
     * @short raw structure of the source and every receiver report in an
     * SR or RR RTCP packet.
     **/
    struct RecvReport
    {
        uint32 ssrc;                 ///< source identifier.
        RRBlock blocks[1];           ///< receiver report blocks.
    };

    /**
     * @struct SenderInfo
     *
     * Struct for the sender info block in a SR (sender report)
     * RTCP packet.
     **/
    struct SenderInfo
    {
        uint32 NTPMSW;              ///< NTP timestamp higher octets.
        uint32 NTPLSW;              ///< NTP timestamp lower octets.
        uint32 RTPTimestamp;        ///< RTP timestamp.
        uint32 packetCount;         ///< cumulative packet counter.
        uint32 octetCount;          ///< cumulative octet counter.
    };

    /**
     * @struct SendReport
     *
     * Struct for SR (sender report) RTCP packets.
     **/
    struct SendReport
    {
        uint32 ssrc;       ///< source identifier.
        SenderInfo sinfo;  ///< actual sender info.
        RRBlock blocks[1]; ///< possibly several receiver info blocks.
    };

    /**
     * @struct SDESItem
     *
     * Struct for an item description of a SDES packet.
     **/
    struct SDESItem
    {
        uint8 type;       ///< item identifier.
        uint8 len;        ///< item len in octets.
        char data[1];     ///< item content.
    };

    /**
     * @struct SDESChunk
     *
     * Struct for a chunk of items in a SDES RTCP packet.
     **/
    struct SDESChunk
    {
        uint32 getSSRC() const
        { return (ntohl(ssrc)); }

        uint32 ssrc;      ///< SSRC identifer from sender.
        SDESItem item;    ///< SDES item from sender.
    };

    /**
     * @struct BYEPacket
     *
     * @short Struct for BYE (leaving session) RTCP packets.
     **/
    struct BYEPacket
    {
        uint32 ssrc;          ///< ssrc identifier of source leaving.
        uint8 length;         ///< [optional] length of reason.
    };

    /**
     * @struct APPPacket
     *
     * @short Struct for APP (application specific) RTCP packets.
     **/
    struct APPPacket
    {
        uint32 ssrc;           ///< ssrc identifier of source.
        char name [4];         ///< Name of the APP packet,
                       ///interpreted as a sequence of
                       ///four characters.
        unsigned char data[1]; ///< application dependent data.
    };

    /**
     * @struct FIRPacket
     *
     * @short Struct for Full Intra-frame Request (FIR) RTCP
     * packet. Specific for H.261 sessions (see RFC 2032).
     **/
    struct FIRPacket
    {
        uint32 ssrc;           ///< ssrc identifier of source.
    };

    /**
     * @struct NACKPacket
     *
     * @short Struct for Negative ACKnowledgements (NACK) RTCP
     * packet. Specific for H.261 sessions (see RFC 2032).
     **/
    struct NACKPacket
    {
        uint32 ssrc;           ///< ssrc identifier of source.
        uint16 fsn;            ///< First Sequence Number lost.
        uint16 blp;            ///< Bitmask of following Lost Packets.
    };

    /**
     * @struct RTCPFixedHeader
     * Fixed RTCP packet header. First 32-bit word in any RTCP
     * packet.
     */
    struct RTCPFixedHeader
    {
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN
        ///< For big endian boxes
        unsigned char version:2;      ///< Version, currently 2.
        unsigned char padding:1;      ///< Padding bit.
        unsigned char block_count:5;  ///< Number of RR, SR, or SDES chunks.
#else
        ///< For little endian boxes
        unsigned char block_count:5;  ///< Number of RR, SR, or SDES chunks.
        unsigned char padding:1;      ///< Padding bit.
        unsigned char version:2;      ///< Version, currently 2.
#endif
        uint8 type;    ///< type of RTCP packet.
        uint16 length; ///< number of 32-bit words in the packet (*minus one*).
    };

    /**
     * @struct RTCPPacket
     *
     * @short Struct representing general RTCP packet headers as they are
     * sent through the network.
     *
     * This struct consists of a fixed header, always at the
     * beginning of any RTCP packet, and a union for all the RTCP
     * packet types supported.
     **/
    struct RTCPPacket
    {
        /**
         * @enum Type rtp.h cc++/rtp.h
         *
         * RTCP packet types. They are registered with IANA.
         */
        typedef enum {
            tSR = 200,      ///< Sender Report.
            tRR,            ///< Receiver Report.
            tSDES,          ///< Source DEScription.
            tBYE,           ///< End of participation.
            tAPP,           ///< APPlication specific.
            tFIR   = 192,   ///< Full Intra-frame request.
            tNACK  = 193,   ///< Negative ACK.
            tXR             ///< Extended Report.
        }       Type;

        /**
         * Get the packet length specified in its header, in
         * octets and in host order.
         **/
        uint32 getLength() const
        { return ((ntohs(fh.length) + 1) << 2); }

        /**
         * Get the SSRC identifier specified in the packet
         * header, in host order.
         **/
        uint32 getSSRC()  const
        { return (ntohl(info.RR.ssrc)); } // SSRC is always the first
                          // word after fh.

        RTCPFixedHeader fh;           ///< Fixed RTCP header.

        // An RTCP packet may be of any of the types defined
        // above, including APP specific ones.
        union
        {
            SendReport SR;
            RecvReport RR;
            SDESChunk SDES;
            BYEPacket BYE;
            APPPacket APP;
            NACKPacket NACK;
            FIRPacket FIR;
        }       info;        ///< Union for SR, RR, SDES, BYE and APP
    };
#ifdef  CCXX_PACKED
#pragma pack()
#endif

protected:
    enum { defaultPathMTU = 1500 };

    RTCPCompoundHandler(uint16 mtu = defaultPathMTU);

    ~RTCPCompoundHandler();

    /**
     * Perform RTCP compound packet header validity check as
     * specified in draft-ietv-avt-rtp-new. This method follows
     * appendix A.2. Correct version, payload type, padding bit
     * and length of every RTCP packet in the compound are
     * verified.
     *
     * @param len length of the RTCP compound packet in
     *        the reception buffer
     * @return whether the header is valid.
     */
    bool
    checkCompoundRTCPHeader(size_t len);

    // buffer to hold RTCP compound packets being sent. Allocated
    // in construction time
    unsigned char* rtcpSendBuffer;
    // buffer to hold RTCP compound packets being
    // received. Allocated at construction time
    unsigned char* rtcpRecvBuffer;

    friend class RTCPSenderInfo;
    friend class RTCPReceiverInfo;
private:
    // path MTU. RTCP packets should not be greater than this
    uint16 pathMTU;
    // masks for RTCP header validation;
    static const uint16 RTCP_VALID_MASK;
    static const uint16 RTCP_VALID_VALUE;
};

/**
 * @class RTCPReceiverInfo
 * @short Report block information of SR/RR RTCP reports.
 *
 * @author Federico Montesino Pouzols <fedemp@altern.org>
 **/
class __EXPORT RTCPReceiverInfo
{
public:
    RTCPReceiverInfo(void* ri)
    { memcpy(&receiverInfo,&ri,
         sizeof(RTCPCompoundHandler::ReceiverInfo));}

        RTCPReceiverInfo(RTCPCompoundHandler::ReceiverInfo& si)
        : receiverInfo( si )
        {
        }

    ~RTCPReceiverInfo()
    { }

    /**
     * Get fraction of lost packets, as a number between 0 and
     * 255.
     **/
    inline uint8
    getFractionLost() const
    { return receiverInfo.fractionLost; }

    inline uint32
    getCumulativePacketLost() const
    { return ( ((uint32)ntohs(receiverInfo.lostLSW)) +
           (((uint32)receiverInfo.lostMSB) << 16) ); }

    inline uint32
    getExtendedSeqNum() const
    { return ntohl(receiverInfo.highestSeqNum); }

    /**
    * Get the statistical variance of the RTP data packets
    * interarrival time.
    *
    * @return Interarrival jitter, in timestamp units.
    **/
    uint32
    getJitter() const
    { return ntohl(receiverInfo.jitter); }

    /**
     * Get the integer part of the NTP timestamp of the last SR
     * RTCP packet received from the source this receiver report
     * refers to.
     **/
    uint16
    getLastSRNTPTimestampInt() const
    { return (uint16)((ntohl(receiverInfo.lsr) & 0xFFFF0000) >> 16); }

    /**
     * Get the fractional part of the NTP timestamp of the last SR
     * RTCP packet received from the source this receiver report
     * refers to.
     **/
    uint16
    getLastSRNTPTimestampFrac() const
    { return (uint16)(ntohl(receiverInfo.lsr) & 0xFFFF); }

    /**
     * Get the delay between the last SR packet received and the
     * transmission of this report.
     *
     * @return Delay, in units of 1/65536 seconds
     **/
    uint32
    getDelayLastSR() const
    { return ntohl(receiverInfo.dlsr); }

private:
    RTCPCompoundHandler::ReceiverInfo receiverInfo;
};

/**
 * @class RTCPSenderInfo
 * @short Sender block information of SR RTCP reports.
 *
 * @author Federico Montesino Pouzols <fedemp@altern.org>
 **/
class __EXPORT RTCPSenderInfo
{
public:
    RTCPSenderInfo(void* si)
    { memcpy(&senderInfo,&si,
         sizeof(RTCPCompoundHandler::SenderInfo));}

        RTCPSenderInfo(RTCPCompoundHandler::SenderInfo& si)
        : senderInfo( si )
        {
        }

    ~RTCPSenderInfo()
    { }

    /**
     * Get integer part of the NTP timestamp of this packet.
     * @see NTP2Timeval
     **/
    uint32
    getNTPTimestampInt() const
    { return ntohl(senderInfo.NTPMSW); }

    /**
     * Get fractional part of the NTP timestamp of this packet.
     * @see NTP2Timeval
     **/
    uint32
    getNTPTimestampFrac() const
    { return ntohl(senderInfo.NTPLSW); }

    inline uint32
    getRTPTimestamp() const
    { return ntohl(senderInfo.RTPTimestamp); }

    /**
     * Get count of sent data packets.
     **/
    inline uint32
    getPacketCount() const
    { return ntohl(senderInfo.packetCount); }

    inline uint32
    getOctetCount() const
    { return ntohl(senderInfo.octetCount); }

private:
    RTCPCompoundHandler::SenderInfo senderInfo;
};

/**
 * Convert a NTP timestamp, expressed as two 32-bit long words, into a
 * timeval value.
 *
 * @param msw Integer part of NTP timestamp.
 * @param lsw Fractional part of NTP timestamp.
 * @return timeval value corresponding to the given NTP timestamp.
 **/
timeval
NTP2Timeval(uint32 msw, uint32 lsw);

/**
 * Convert a time interval, expressed as a timeval, into a 32-bit time
 * interval expressed in units of 1/65536 seconds.
 *
 * @param t Timeval interval.
 * @return 32-bit value corresponding to the given timeval interval.
 **/
uint32
timevalIntervalTo65536(timeval& t);

/** @}*/ // rtcppacket

END_NAMESPACE

#endif  // ndef CCXX_RTP_RTCPPKT_H_

/** EMACS **
 * Local variables:
 * mode: c++
 * c-basic-offset: 8
 * End:
 */

