mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			342 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			342 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 * SRT - Secure, Reliable, Transport
 | 
						|
 * Copyright (c) 2018 Haivision Systems Inc.
 | 
						|
 * 
 | 
						|
 * This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
						|
 * 
 | 
						|
 */
 | 
						|
 | 
						|
/*****************************************************************************
 | 
						|
Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois.
 | 
						|
All rights reserved.
 | 
						|
 | 
						|
Redistribution and use in source and binary forms, with or without
 | 
						|
modification, are permitted provided that the following conditions are
 | 
						|
met:
 | 
						|
 | 
						|
* Redistributions of source code must retain the above
 | 
						|
  copyright notice, this list of conditions and the
 | 
						|
  following disclaimer.
 | 
						|
 | 
						|
* Redistributions in binary form must reproduce the
 | 
						|
  above copyright notice, this list of conditions
 | 
						|
  and the following disclaimer in the documentation
 | 
						|
  and/or other materials provided with the distribution.
 | 
						|
 | 
						|
* Neither the name of the University of Illinois
 | 
						|
  nor the names of its contributors may be used to
 | 
						|
  endorse or promote products derived from this
 | 
						|
  software without specific prior written permission.
 | 
						|
 | 
						|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 | 
						|
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 | 
						|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
						|
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
						|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
						|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
						|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
						|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 | 
						|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
						|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
						|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
*****************************************************************************/
 | 
						|
 | 
						|
#ifndef INC__HANDSHAKE_H
 | 
						|
#define INC__HANDSHAKE_H
 | 
						|
 | 
						|
#include "crypto.h"
 | 
						|
#include "utilities.h"
 | 
						|
 | 
						|
typedef Bits<31, 16> HS_CMDSPEC_CMD;
 | 
						|
typedef Bits<15, 0> HS_CMDSPEC_SIZE;
 | 
						|
 | 
						|
// NOTE: Some of these flags represent CAPABILITIES, that is,
 | 
						|
// as long as these flags are defined, they must be always set
 | 
						|
// (unless they are deprecated).
 | 
						|
enum SrtOptions
 | 
						|
{
 | 
						|
    SRT_OPT_TSBPDSND  = BIT(0), /* Timestamp-based Packet delivery real-time data sender */
 | 
						|
    SRT_OPT_TSBPDRCV  = BIT(1), /* Timestamp-based Packet delivery real-time data receiver */
 | 
						|
    SRT_OPT_HAICRYPT  = BIT(2), /* CAPABILITY: HaiCrypt AES-128/192/256-CTR */
 | 
						|
    SRT_OPT_TLPKTDROP = BIT(3), /* Drop real-time data packets too late to be processed in time */
 | 
						|
    SRT_OPT_NAKREPORT = BIT(4), /* Periodic NAK report */
 | 
						|
    SRT_OPT_REXMITFLG = BIT(5), // CAPABILITY: One bit in payload packet msgno is "retransmitted" flag
 | 
						|
                                // (this flag can be reused for something else, when pre-1.2.0 versions are all abandoned)
 | 
						|
    SRT_OPT_STREAM    = BIT(6), // STREAM MODE (not MESSAGE mode)
 | 
						|
    SRT_OPT_FILTERCAP = BIT(7), // CAPABILITY: Packet filter supported
 | 
						|
};
 | 
						|
 | 
						|
inline int SrtVersionCapabilities()
 | 
						|
{
 | 
						|
    // NOTE: SRT_OPT_REXMITFLG is not included here because
 | 
						|
    // SRT is prepared to handle also peers that don't have this
 | 
						|
    // capability, so a listener responding to a peer that doesn't
 | 
						|
    // support it should NOT set this flag.
 | 
						|
    //
 | 
						|
    // This state will remain until this backward compatibility is
 | 
						|
    // decided to be broken, in which case this flag will be always
 | 
						|
    // set, and clients that do not support this capability will be
 | 
						|
    // rejected.
 | 
						|
    return SRT_OPT_HAICRYPT | SRT_OPT_FILTERCAP;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
std::string SrtFlagString(int32_t flags);
 | 
						|
 | 
						|
const int SRT_CMD_REJECT = 0, // REJECT is only a symbol for return type
 | 
						|
      SRT_CMD_HSREQ = 1,
 | 
						|
      SRT_CMD_HSRSP = 2,
 | 
						|
      SRT_CMD_KMREQ = 3,
 | 
						|
      SRT_CMD_KMRSP = 4,
 | 
						|
      SRT_CMD_SID = 5,
 | 
						|
      SRT_CMD_CONGESTION = 6,
 | 
						|
      SRT_CMD_FILTER = 7,
 | 
						|
      SRT_CMD_NONE = -1; // for cases when {no pong for ping is required} | {no extension block found}
 | 
						|
 | 
						|
enum SrtDataStruct
 | 
						|
{
 | 
						|
    SRT_HS_VERSION = 0,
 | 
						|
    SRT_HS_FLAGS,
 | 
						|
    SRT_HS_LATENCY,
 | 
						|
 | 
						|
    // Keep it always last
 | 
						|
    SRT_HS__SIZE
 | 
						|
};
 | 
						|
 | 
						|
// For HSv5 the lo and hi part is used for particular side's latency
 | 
						|
typedef Bits<31, 16> SRT_HS_LATENCY_RCV;
 | 
						|
typedef Bits<15, 0> SRT_HS_LATENCY_SND;
 | 
						|
// For HSv4 only the lower part is used.
 | 
						|
typedef Bits<15, 0> SRT_HS_LATENCY_LEG;
 | 
						|
 | 
						|
 | 
						|
// XXX These structures are currently unused. The code can be changed
 | 
						|
// so that these are used instead of manual tailoring of the messages.
 | 
						|
struct SrtHandshakeExtension
 | 
						|
{
 | 
						|
protected:
 | 
						|
 | 
						|
   uint32_t m_SrtCommand; // Used only in extension
 | 
						|
 | 
						|
public:
 | 
						|
   SrtHandshakeExtension(int cmd)
 | 
						|
   {
 | 
						|
       m_SrtCommand = cmd;
 | 
						|
   }
 | 
						|
 | 
						|
   void setCommand(int cmd)
 | 
						|
   {
 | 
						|
       m_SrtCommand = cmd;
 | 
						|
   }
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
struct SrtHSRequest: public SrtHandshakeExtension
 | 
						|
{
 | 
						|
 | 
						|
    typedef Bits<31, 16> SRT_HSTYPE_ENCFLAGS;
 | 
						|
    typedef Bits<15, 0> SRT_HSTYPE_HSFLAGS;
 | 
						|
 | 
						|
    // For translating PBKEYLEN into crypto flags
 | 
						|
    // This value is 16, 24, 32; after cutting off
 | 
						|
    // the leftmost 3 bits, it is 2, 3, 4.
 | 
						|
    typedef Bits<5, 3> SRT_PBKEYLEN_BITS;
 | 
						|
 | 
						|
    // This value fits ins SRT_HSTYPE_HSFLAGS.
 | 
						|
    //  ....                                HAIVISIOn
 | 
						|
    static const int32_t SRT_MAGIC_CODE = 0x4A17;
 | 
						|
 | 
						|
    static int32_t wrapFlags(bool withmagic, int crypto_keylen)
 | 
						|
    {
 | 
						|
        int32_t base = withmagic ? SRT_MAGIC_CODE : 0;
 | 
						|
        return base | SRT_HSTYPE_ENCFLAGS::wrap( SRT_PBKEYLEN_BITS::unwrap(crypto_keylen) );
 | 
						|
    }
 | 
						|
 | 
						|
private:
 | 
						|
    friend class CHandShake;
 | 
						|
 | 
						|
    static const size_t SRT_HS_SIZE = 4*sizeof(uint32_t); // 4 existing fields
 | 
						|
    static const size_t SRT_EXT_HS_SIZE = 2*sizeof(uint32_t) + SRT_HS_SIZE; // SRT magic and SRT HS type, used only in UDT HS ext
 | 
						|
 | 
						|
    typedef Bits<15, 0> SRT_TSBPD_DELAY;
 | 
						|
 | 
						|
    uint32_t m_iSrtVersion;
 | 
						|
    uint32_t m_iSrtFlags;
 | 
						|
    uint32_t m_iSrtTsbpd;
 | 
						|
    uint32_t m_iSrtReserved;
 | 
						|
 | 
						|
public:
 | 
						|
 | 
						|
    SrtHSRequest(): SrtHandshakeExtension(SRT_CMD_HSREQ), m_iSrtVersion(), m_iSrtFlags(), m_iSrtTsbpd(), m_iSrtReserved() {}
 | 
						|
 | 
						|
    void setVersion(uint32_t v) { m_iSrtVersion = v; }
 | 
						|
    uint32_t version() const { return m_iSrtVersion; }
 | 
						|
 | 
						|
    void setFlag(SrtOptions opt) { m_iSrtFlags |= uint32_t(opt); }
 | 
						|
    void clearFlag(SrtOptions opt) { m_iSrtFlags &= ~opt; }
 | 
						|
    uint32_t flags() const { return m_iSrtFlags; }
 | 
						|
 | 
						|
    void setTsbPdDelay(uint16_t delay) { m_iSrtTsbpd |= SRT_TSBPD_DELAY::wrap(delay); }
 | 
						|
    // Unknown what the 1-16 bits have to be used for.
 | 
						|
    uint16_t tsbPdDelay() const
 | 
						|
    {
 | 
						|
        return SRT_TSBPD_DELAY::unwrap(m_iSrtTsbpd);
 | 
						|
    }
 | 
						|
 | 
						|
    size_t size() const { return SRT_EXT_HS_SIZE; }
 | 
						|
 | 
						|
    bool serialize(char* p, size_t size) const;
 | 
						|
    bool deserialize(const char* mem, size_t size);
 | 
						|
};
 | 
						|
 | 
						|
struct SrtKMRequest: public SrtHandshakeExtension
 | 
						|
{
 | 
						|
    uint32_t m_iKmState;
 | 
						|
    char m_aKey[1]; // dynamic size
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
enum UDTRequestType
 | 
						|
{
 | 
						|
    URQ_INDUCTION_TYPES = 0, // XXX used to check in one place. Consdr rm.
 | 
						|
 | 
						|
    URQ_INDUCTION = 1, // First part for client-server connection
 | 
						|
    URQ_WAVEAHAND = 0, // First part for rendezvous connection
 | 
						|
 | 
						|
    URQ_CONCLUSION = -1, // Second part of handshake negotiation
 | 
						|
    URQ_AGREEMENT = -2, // Extra (last) step for rendezvous only
 | 
						|
    URQ_DONE = -3,      // Special value used only in state-switching, to state that nothing should be sent in response
 | 
						|
 | 
						|
    // Note: the client-server connection uses:
 | 
						|
    // --> INDUCTION (empty)
 | 
						|
    // <-- INDUCTION (cookie)
 | 
						|
    // --> CONCLUSION (cookie)
 | 
						|
    // <-- CONCLUSION (ok)
 | 
						|
 | 
						|
    // The rendezvous HSv4 (legacy):
 | 
						|
    // --> WAVEAHAND (effective only if peer is also connecting)
 | 
						|
    // <-- CONCLUSION (empty) (consider yourself connected upon reception)
 | 
						|
    // --> AGREEMENT (sent as a response for conclusion, requires no response)
 | 
						|
 | 
						|
    // The rendezvous HSv5 (using SRT extensions):
 | 
						|
    // --> WAVEAHAND (with cookie)
 | 
						|
    // --- (selecting INITIATOR/RESPONDER by cookie contest - comparing one another's cookie)
 | 
						|
    // <-- CONCLUSION (without extensions, if RESPONDER, with extensions, if INITIATOR)
 | 
						|
    // --> CONCLUSION (with response extensions, if RESPONDER)
 | 
						|
    // <-- AGREEMENT (sent exclusively by INITIATOR upon reception of CONCLUSIOn with response extensions)
 | 
						|
 | 
						|
    // Errors reported by the peer, also used as useless error codes
 | 
						|
    // in handshake processing functions.
 | 
						|
    URQ_FAILURE_TYPES = 1000
 | 
						|
 | 
						|
    // NOTE: codes above 1000 are reserved for failure codes for
 | 
						|
    // rejection reason, as per `SRT_REJECT_REASON` enum. DO NOT
 | 
						|
    // add any new values here.
 | 
						|
};
 | 
						|
 | 
						|
inline UDTRequestType URQFailure(SRT_REJECT_REASON reason)
 | 
						|
{
 | 
						|
    return UDTRequestType(URQ_FAILURE_TYPES + int(reason));
 | 
						|
}
 | 
						|
 | 
						|
inline SRT_REJECT_REASON RejectReasonForURQ(UDTRequestType req)
 | 
						|
{
 | 
						|
    if (req < URQ_FAILURE_TYPES || req - URQ_FAILURE_TYPES >= SRT_REJ__SIZE)
 | 
						|
        return SRT_REJ_UNKNOWN;
 | 
						|
    return SRT_REJECT_REASON(req - URQ_FAILURE_TYPES);
 | 
						|
}
 | 
						|
 | 
						|
// DEPRECATED values. Use URQFailure(SRT_REJECT_REASON).
 | 
						|
const UDTRequestType URQ_ERROR_REJECT SRT_ATR_DEPRECATED = (UDTRequestType)1002; // == 1000 + SRT_REJ_PEER
 | 
						|
const UDTRequestType URQ_ERROR_INVALID SRT_ATR_DEPRECATED = (UDTRequestType)1004; // == 1000 + SRT_REJ_ROGUE
 | 
						|
 | 
						|
// XXX Change all uses of that field to UDTRequestType when possible
 | 
						|
#if ENABLE_LOGGING
 | 
						|
std::string RequestTypeStr(UDTRequestType);
 | 
						|
#else
 | 
						|
inline std::string RequestTypeStr(UDTRequestType) { return ""; }
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
class CHandShake
 | 
						|
{
 | 
						|
public:
 | 
						|
   CHandShake();
 | 
						|
 | 
						|
   int store_to(char* buf, ref_t<size_t> size);
 | 
						|
   int load_from(const char* buf, size_t size);
 | 
						|
 | 
						|
public:
 | 
						|
   // This is the size of SERIALIZED handshake.
 | 
						|
   // Might be defined as simply sizeof(CHandShake), but the
 | 
						|
   // enum values would have to be forced as int32_t, which is only
 | 
						|
   // available in C++11. Theoretically they are all 32-bit, but
 | 
						|
   // such a statement is not reliable and not portable.
 | 
						|
   static const size_t m_iContentSize = 48;	// Size of hand shake data
 | 
						|
 | 
						|
   // Extension flags
 | 
						|
 | 
						|
    static const int32_t HS_EXT_HSREQ = BIT(0);
 | 
						|
    static const int32_t HS_EXT_KMREQ = BIT(1);
 | 
						|
    static const int32_t HS_EXT_CONFIG  = BIT(2);
 | 
						|
 | 
						|
    static std::string ExtensionFlagStr(int32_t fl);
 | 
						|
 | 
						|
    // Applicable only when m_iVersion == HS_VERSION_SRT1
 | 
						|
    int32_t flags() { return m_iType; }
 | 
						|
 | 
						|
public:
 | 
						|
   int32_t m_iVersion;          // UDT version (HS_VERSION_* symbols)
 | 
						|
   int32_t m_iType;             // UDT4: socket type (only UDT_DGRAM is valid); SRT1: extension flags
 | 
						|
   int32_t m_iISN;              // random initial sequence number
 | 
						|
   int32_t m_iMSS;              // maximum segment size
 | 
						|
   int32_t m_iFlightFlagSize;   // flow control window size
 | 
						|
   UDTRequestType m_iReqType;   // handshake stage
 | 
						|
   int32_t m_iID;		// socket ID
 | 
						|
   int32_t m_iCookie;		// cookie
 | 
						|
   uint32_t m_piPeerIP[4];	// The IP address that the peer's UDP port is bound to
 | 
						|
 | 
						|
   bool m_extension;
 | 
						|
 | 
						|
   std::string show();
 | 
						|
 | 
						|
// The rendezvous state machine used in HSv5 only (in HSv4 everything is happening the old way).
 | 
						|
//
 | 
						|
// The WAVING state is the very initial state of the rendezvous connection and restored after the
 | 
						|
// connection is closed.
 | 
						|
// The ATTENTION and FINE are two alternative states that are transited to from WAVING. The possible
 | 
						|
// situations are:
 | 
						|
// - "serial arrangement": one party transits to ATTENTION and the other party transits to FINE
 | 
						|
// - "parallel arrangement" both parties transit to ATTENTION
 | 
						|
//
 | 
						|
// Parallel arrangement is a "virtually impossible" case, in which both parties must send the first
 | 
						|
// URQ_WAVEAHAND message in a perfect time synchronization, when they are started at exactly the same
 | 
						|
// time, on machines with exactly the same performance and all things preceding the message sending
 | 
						|
// have taken perfectly identical amount of time. This isn't anyhow possible otherwise because if
 | 
						|
// the clients have started at different times, the one who started first sends a message and the
 | 
						|
// system of the receiver buffers this message even before the client binds the port for enough long
 | 
						|
// time so that it outlasts also the possible second, repeated waveahand.
 | 
						|
enum RendezvousState
 | 
						|
{
 | 
						|
    RDV_INVALID,    //< This socket wasn't prepared for rendezvous process. Reject any events.
 | 
						|
    RDV_WAVING,     //< Initial state for rendezvous. No contact seen from the peer.
 | 
						|
    RDV_ATTENTION,  //< When received URQ_WAVEAHAND. [WAVING]:URQ_WAVEAHAND  --> [ATTENTION].
 | 
						|
    RDV_FINE,       //< When received URQ_CONCLUSION. [WAVING]:URQ_CONCLUSION --> [FINE].
 | 
						|
    RDV_INITIATED,  //< When received URQ_CONCLUSION+HSREQ extension in ATTENTION state. 
 | 
						|
    RDV_CONNECTED   //< Final connected state. [ATTENTION]:URQ_CONCLUSION --> [CONNECTED] <-- [FINE]:URQ_AGREEMENT.
 | 
						|
};
 | 
						|
 | 
						|
#if ENABLE_LOGGING
 | 
						|
static std::string RdvStateStr(RendezvousState s);
 | 
						|
#else
 | 
						|
static std::string RdvStateStr(RendezvousState) { return ""; }
 | 
						|
#endif
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
#endif
 |