#include "platform_sys.h"
#include <cstring>
#include "packet.h"
#include "handshake.h"
#include "logging.h"
#include "handshake.h"
namespace srt_logging
{
extern Logger inlog;
}
using namespace srt_logging;
CPacket::CPacket():
m_extra_pad(),
m_data_owned(false),
m_iSeqNo((int32_t&)(m_nHeader[SRT_PH_SEQNO])),
m_iMsgNo((int32_t&)(m_nHeader[SRT_PH_MSGNO])),
m_iTimeStamp((int32_t&)(m_nHeader[SRT_PH_TIMESTAMP])),
m_iID((int32_t&)(m_nHeader[SRT_PH_ID])),
m_pcData((char*&)(m_PacketVector[PV_DATA].dataRef()))
{
m_nHeader.clear();
m_PacketVector[PV_HEADER].set(m_nHeader.raw(), HDR_SIZE);
m_PacketVector[PV_DATA].set(NULL, 0);
}
char* CPacket::getData()
{
return (char*)m_PacketVector[PV_DATA].dataRef();
}
void CPacket::allocate(size_t alloc_buffer_size)
{
if (m_data_owned)
{
if (getLength() == alloc_buffer_size)
return;
delete [] m_pcData;
}
m_PacketVector[PV_DATA].set(new char[alloc_buffer_size], alloc_buffer_size);
m_data_owned = true;
}
void CPacket::deallocate()
{
if (m_data_owned)
delete [] (char*)m_PacketVector[PV_DATA].data();
m_PacketVector[PV_DATA].set(NULL, 0);
}
char* CPacket::release()
{
char* buffer = NULL;
if (m_data_owned)
{
buffer = getData();
m_data_owned = false;
}
deallocate(); return buffer;
}
CPacket::~CPacket()
{
if (m_data_owned)
delete[](char*)m_PacketVector[PV_DATA].data();
}
size_t CPacket::getLength() const
{
return m_PacketVector[PV_DATA].size();
}
void CPacket::setLength(size_t len)
{
m_PacketVector[PV_DATA].setLength(len);
}
void CPacket::pack(UDTMessageType pkttype, const int32_t* lparam, void* rparam, int size)
{
setControl(pkttype);
HLOGC(inlog.Debug, log << "pack: type=" << MessageTypeStr(pkttype)
<< " ARG=" << (lparam ? Sprint(*lparam) : std::string("NULL"))
<< " [ " << (rparam ? Sprint(*(int32_t*)rparam) : std::string()) << " ]");
switch (pkttype)
{
case UMSG_ACK: if (NULL != lparam)
m_nHeader[SRT_PH_MSGNO] = *lparam;
m_PacketVector[PV_DATA].set(rparam, size);
break;
case UMSG_ACKACK: m_nHeader[SRT_PH_MSGNO] = *lparam;
m_PacketVector[PV_DATA].set((void *)&m_extra_pad, 4);
break;
case UMSG_LOSSREPORT: m_PacketVector[PV_DATA].set(rparam, size);
break;
case UMSG_CGWARNING: m_PacketVector[PV_DATA].set((void *)&m_extra_pad, 4);
break;
case UMSG_KEEPALIVE: if (lparam)
{
m_nHeader[SRT_PH_MSGNO] = *lparam;
}
m_PacketVector[PV_DATA].set((void *)&m_extra_pad, 4);
break;
case UMSG_HANDSHAKE: m_PacketVector[PV_DATA].set(rparam, size);
break;
case UMSG_SHUTDOWN: m_PacketVector[PV_DATA].set((void *)&m_extra_pad, 4);
break;
case UMSG_DROPREQ: m_nHeader[SRT_PH_MSGNO] = *lparam;
m_PacketVector[PV_DATA].set(rparam, size);
break;
case UMSG_PEERERROR: m_nHeader[SRT_PH_MSGNO] = *lparam;
m_PacketVector[PV_DATA].set((void *)&m_extra_pad, 4);
break;
case UMSG_EXT: m_nHeader[SRT_PH_SEQNO] |= *lparam;
if (NULL != rparam)
{
m_PacketVector[PV_DATA].set(rparam, size);
}
else
{
m_PacketVector[PV_DATA].set((void *)&m_extra_pad, 4);
}
break;
default:
break;
}
}
void CPacket::toNL()
{
if (isControl())
{
for (ptrdiff_t i = 0, n = getLength() / 4; i < n; ++i)
*((uint32_t*)m_pcData + i) = htonl(*((uint32_t*)m_pcData + i));
}
uint32_t* p = m_nHeader;
for (int j = 0; j < 4; ++j)
{
*p = htonl(*p);
++p;
}
}
void CPacket::toHL()
{
uint32_t* p = m_nHeader;
for (int k = 0; k < 4; ++k)
{
*p = ntohl(*p);
++p;
}
if (isControl())
{
for (ptrdiff_t l = 0, n = getLength() / 4; l < n; ++l)
*((uint32_t*) m_pcData + l) = ntohl(*((uint32_t*) m_pcData + l));
}
}
IOVector* CPacket::getPacketVector()
{
return m_PacketVector;
}
UDTMessageType CPacket::getType() const
{
return UDTMessageType(SEQNO_MSGTYPE::unwrap(m_nHeader[SRT_PH_SEQNO]));
}
int CPacket::getExtendedType() const
{
return SEQNO_EXTTYPE::unwrap(m_nHeader[SRT_PH_SEQNO]);
}
int32_t CPacket::getAckSeqNo() const
{
return m_nHeader[SRT_PH_MSGNO];
}
uint16_t CPacket::getControlFlags() const
{
return SEQNO_EXTTYPE::unwrap(m_nHeader[SRT_PH_SEQNO]);
}
PacketBoundary CPacket::getMsgBoundary() const
{
return PacketBoundary(MSGNO_PACKET_BOUNDARY::unwrap(m_nHeader[SRT_PH_MSGNO]));
}
bool CPacket::getMsgOrderFlag() const
{
return 0!= MSGNO_PACKET_INORDER::unwrap(m_nHeader[SRT_PH_MSGNO]);
}
int32_t CPacket::getMsgSeq(bool has_rexmit) const
{
if ( has_rexmit )
{
return MSGNO_SEQ::unwrap(m_nHeader[SRT_PH_MSGNO]);
}
else
{
return MSGNO_SEQ_OLD::unwrap(m_nHeader[SRT_PH_MSGNO]);
}
}
bool CPacket::getRexmitFlag() const
{
return 0 != MSGNO_REXMIT::unwrap(m_nHeader[SRT_PH_MSGNO]);
}
EncryptionKeySpec CPacket::getMsgCryptoFlags() const
{
return EncryptionKeySpec(MSGNO_ENCKEYSPEC::unwrap(m_nHeader[SRT_PH_MSGNO]));
}
void CPacket::setMsgCryptoFlags(EncryptionKeySpec spec)
{
int32_t clr_msgno = m_nHeader[SRT_PH_MSGNO] & ~MSGNO_ENCKEYSPEC::mask;
m_nHeader[SRT_PH_MSGNO] = clr_msgno | EncryptionKeyBits(spec);
}
uint32_t CPacket::getMsgTimeStamp() const
{
return (uint32_t)m_nHeader[SRT_PH_TIMESTAMP] & TIMESTAMP_MASK;
}
CPacket* CPacket::clone() const
{
CPacket* pkt = new CPacket;
memcpy((pkt->m_nHeader), m_nHeader, HDR_SIZE);
pkt->m_pcData = new char[m_PacketVector[PV_DATA].size()];
memcpy((pkt->m_pcData), m_pcData, m_PacketVector[PV_DATA].size());
pkt->m_PacketVector[PV_DATA].setLength(m_PacketVector[PV_DATA].size());
return pkt;
}
std::string PacketMessageFlagStr(uint32_t msgno_field)
{
using namespace std;
stringstream out;
static const char* const boundary [] = { "PB_SUBSEQUENT", "PB_LAST", "PB_FIRST", "PB_SOLO" };
static const char* const order [] = { "ORD_RELAXED", "ORD_REQUIRED" };
static const char* const crypto [] = { "EK_NOENC", "EK_EVEN", "EK_ODD", "EK*ERROR" };
static const char* const rexmit [] = { "SN_ORIGINAL", "SN_REXMIT" };
out << boundary[MSGNO_PACKET_BOUNDARY::unwrap(msgno_field)] << " ";
out << order[MSGNO_PACKET_INORDER::unwrap(msgno_field)] << " ";
out << crypto[MSGNO_ENCKEYSPEC::unwrap(msgno_field)] << " ";
out << rexmit[MSGNO_REXMIT::unwrap(msgno_field)];
return out.str();
}
inline void SprintSpecialWord(std::ostream& os, int32_t val)
{
if (val & LOSSDATA_SEQNO_RANGE_FIRST)
os << "<" << (val & (~LOSSDATA_SEQNO_RANGE_FIRST)) << ">";
else
os << val;
}
#if ENABLE_LOGGING
std::string CPacket::Info()
{
std::ostringstream os;
os << "TARGET=@" << m_iID << " ";
if (isControl())
{
os << "CONTROL: size=" << getLength() << " type=" << MessageTypeStr(getType(), getExtendedType());
if (getType() == UMSG_HANDSHAKE)
{
os << " HS: ";
CHandShake hs;
hs.load_from(m_pcData, getLength());
os << hs.show();
}
else
{
os << " ARG: 0x";
os << std::hex << getAckSeqNo() << " ";
os << std::dec << getAckSeqNo();
size_t wordlen = getLength()/4; int32_t* array = (int32_t*)m_pcData;
os << " [ ";
for (size_t i = 0; i < wordlen; ++i)
{
SprintSpecialWord(os, array[i]);
os << " ";
}
os << "]";
}
}
else
{
os << "DATA: size=" << getLength()
<< " " << BufferStamp(m_pcData, getLength())
<< " #" << getMsgSeq(true) << " %" << getSeqNo()
<< " " << MessageFlagStr();
}
return os.str();
}
#endif