#include "platform_sys.h"
#include <cstring>
#include <string>
#include <sstream>
#include <iterator>
#include <algorithm>
#include "udt.h"
#include "core.h"
#include "handshake.h"
#include "utilities.h"
using namespace std;
CHandShake::CHandShake():
m_iVersion(0),
m_iType(0), m_iISN(0),
m_iMSS(0),
m_iFlightFlagSize(0),
m_iReqType(URQ_WAVEAHAND),
m_iID(0),
m_iCookie(0),
m_extension(false)
{
for (int i = 0; i < 4; ++ i)
m_piPeerIP[i] = 0;
}
int CHandShake::store_to(char* buf, size_t& w_size)
{
if (w_size < m_iContentSize)
return -1;
int32_t* p = reinterpret_cast<int32_t*>(buf);
*p++ = m_iVersion;
*p++ = m_iType;
*p++ = m_iISN;
*p++ = m_iMSS;
*p++ = m_iFlightFlagSize;
*p++ = int32_t(m_iReqType);
*p++ = m_iID;
*p++ = m_iCookie;
for (int i = 0; i < 4; ++ i)
*p++ = m_piPeerIP[i];
w_size = m_iContentSize;
return 0;
}
int CHandShake::load_from(const char* buf, size_t size)
{
if (size < m_iContentSize)
return -1;
const int32_t* p = reinterpret_cast<const int32_t*>(buf);
m_iVersion = *p++;
m_iType = *p++;
m_iISN = *p++;
m_iMSS = *p++;
m_iFlightFlagSize = *p++;
m_iReqType = UDTRequestType(*p++);
m_iID = *p++;
m_iCookie = *p++;
for (int i = 0; i < 4; ++ i)
m_piPeerIP[i] = *p++;
return 0;
}
#ifdef ENABLE_LOGGING
const char* srt_rejectreason_name [] = {
"UNKNOWN",
"SYSTEM",
"PEER",
"RESOURCE",
"ROGUE",
"BACKLOG",
"IPE",
"CLOSE",
"VERSION",
"RDVCOOKIE",
"BADSECRET",
"UNSECURE",
"MESSAGEAPI",
"CONGESTION",
"FILTER",
};
std::string RequestTypeStr(UDTRequestType rq)
{
if (rq >= URQ_FAILURE_TYPES)
{
std::ostringstream rt;
rt << "ERROR:";
int id = RejectReasonForURQ(rq);
if (id < SRT_REJ_E_SIZE)
rt << srt_rejectreason_name[id];
else if (id < SRT_REJC_USERDEFINED)
{
if (id < SRT_REJC_PREDEFINED)
rt << "UNKNOWN:" << id;
else
rt << "PREDEFINED:" << (id - SRT_REJC_PREDEFINED);
}
else
rt << "USERDEFINED:" << (id - SRT_REJC_USERDEFINED);
return rt.str();
}
switch ( rq )
{
case URQ_INDUCTION: return "induction";
case URQ_WAVEAHAND: return "waveahand";
case URQ_CONCLUSION: return "conclusion";
case URQ_AGREEMENT: return "agreement";
default: return "INVALID";
}
}
string CHandShake::RdvStateStr(CHandShake::RendezvousState s)
{
switch (s)
{
case RDV_WAVING: return "waving";
case RDV_ATTENTION: return "attention";
case RDV_FINE: return "fine";
case RDV_INITIATED: return "initiated";
case RDV_CONNECTED: return "connected";
default: ;
}
return "invalid";
}
#endif
string CHandShake::show()
{
ostringstream so;
so << "version=" << m_iVersion << " type=0x" << hex << m_iType << dec
<< " ISN=" << m_iISN << " MSS=" << m_iMSS << " FLW=" << m_iFlightFlagSize
<< " reqtype=" << RequestTypeStr(m_iReqType) << " srcID=" << m_iID
<< " cookie=" << hex << m_iCookie << dec
<< " srcIP=";
const unsigned char* p = (const unsigned char*)m_piPeerIP;
const unsigned char* pe = p + 4 * (sizeof(uint32_t));
copy(p, pe, ostream_iterator<unsigned>(so, "."));
if ( m_iVersion > CUDT::HS_VERSION_UDT4 )
{
const int flags = SrtHSRequest::SRT_HSTYPE_HSFLAGS::unwrap(m_iType);
so << "FLAGS: ";
if (flags == SrtHSRequest::SRT_MAGIC_CODE)
so << "MAGIC";
else if (m_iType == 0)
so << "NONE"; else
so << ExtensionFlagStr(m_iType);
}
return so.str();
}
string CHandShake::ExtensionFlagStr(int32_t fl)
{
std::ostringstream out;
if ( fl & HS_EXT_HSREQ )
out << " hsx";
if ( fl & HS_EXT_KMREQ )
out << " kmx";
if ( fl & HS_EXT_CONFIG )
out << " config";
const int kl = SrtHSRequest::SRT_HSTYPE_ENCFLAGS::unwrap(fl) << 6;
if (kl != 0)
{
out << " AES-" << kl;
}
else
{
out << " no-pbklen";
}
return out.str();
}
bool SrtHSRequest::serialize(char* buf, size_t size) const
{
if (size < SRT_HS_SIZE)
return false;
int32_t* p = reinterpret_cast<int32_t*>(buf);
*p++ = m_iSrtVersion;
*p++ = m_iSrtFlags;
*p++ = m_iSrtTsbpd;
*p++ = 0; return true;
}
bool SrtHSRequest::deserialize(const char* buf, size_t size)
{
m_iSrtVersion = 0;
if (size < SRT_HS_SIZE)
return false;
const int32_t* p = reinterpret_cast<const int32_t*>(buf);
m_iSrtVersion = (*p++);
m_iSrtFlags = (*p++);
m_iSrtTsbpd = (*p++);
m_iSrtReserved = (*p++);
return true;
}