123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657 |
- /*
- * 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.
- *****************************************************************************/
- /*****************************************************************************
- written by
- Yunhong Gu, last updated 02/12/2011
- modified by
- Haivision Systems Inc.
- *****************************************************************************/
- //////////////////////////////////////////////////////////////////////////////
- // 0 1 2 3
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | Packet Header |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | |
- // ~ Data / Control Information Field ~
- // | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- //
- // 0 1 2 3
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // |0| Sequence Number |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // |ff |o|kf |r| Message Number |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | Time Stamp |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | Destination Socket ID |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- //
- // bit 0:
- // 0: Data Packet
- // 1: Control Packet
- // bit ff:
- // 11: solo message packet
- // 10: first packet of a message
- // 01: last packet of a message
- // bit o:
- // 0: in order delivery not required
- // 1: in order delivery required
- // bit kf: HaiCrypt Key Flags
- // 00: not encrypted
- // 01: encrypted with even key
- // 10: encrypted with odd key
- // bit r: retransmission flag (set to 1 if this packet was sent again)
- //
- // 0 1 2 3
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // |1| Type | Reserved |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | Additional Info |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | Time Stamp |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | Destination Socket ID |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- //
- // bit 1-15: Message type -- see @a UDTMessageType
- // 0: Protocol Connection Handshake (UMSG_HANDSHAKE}
- // Add. Info: Undefined
- // Control Info: Handshake information (see @a CHandShake)
- // 1: Keep-alive (UMSG_KEEPALIVE)
- // Add. Info: Undefined
- // Control Info: None
- // 2: Acknowledgement (UMSG_ACK)
- // Add. Info: The ACK sequence number
- // Control Info: The sequence number to which (but not include) all the previous packets have beed received
- // Optional: RTT
- // RTT Variance
- // available receiver buffer size (in bytes)
- // advertised flow window size (number of packets)
- // estimated bandwidth (number of packets per second)
- // 3: Negative Acknowledgement (UMSG_LOSSREPORT)
- // Add. Info: Undefined
- // Control Info: Loss list (see loss list coding below)
- // 4: Congestion/Delay Warning (UMSG_CGWARNING)
- // Add. Info: Undefined
- // Control Info: None
- // 5: Shutdown (UMSG_SHUTDOWN)
- // Add. Info: Undefined
- // Control Info: None
- // 6: Acknowledgement of Acknowledement (UMSG_ACKACK)
- // Add. Info: The ACK sequence number
- // Control Info: None
- // 7: Message Drop Request (UMSG_DROPREQ)
- // Add. Info: Message ID
- // Control Info: first sequence number of the message
- // last seqeunce number of the message
- // 8: Error Signal from the Peer Side (UMSG_PEERERROR)
- // Add. Info: Error code
- // Control Info: None
- // 0x7FFF: Explained by bits 16 - 31 (UMSG_EXT)
- //
- // bit 16 - 31:
- // This space is used for future expansion or user defined control packets.
- //
- // 0 1 2 3
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // |1| Sequence Number a (first) |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // |0| Sequence Number b (last) |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // |0| Sequence Number (single) |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- //
- // Loss List Field Coding:
- // For any consecutive lost seqeunce numbers that the differnece between
- // the last and first is more than 1, only record the first (a) and the
- // the last (b) sequence numbers in the loss list field, and modify the
- // the first bit of a to 1.
- // For any single loss or consecutive loss less than 2 packets, use
- // the original sequence numbers in the field.
- #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;
- namespace srt {
- // Set up the aliases in the constructure
- CPacket::CPacket()
- : m_nHeader() // Silences GCC 12 warning "used uninitialized".
- , 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();
- // The part at PV_HEADER will be always set to a builtin buffer
- // containing SRT header.
- m_PacketVector[PV_HEADER].set(m_nHeader.raw(), HDR_SIZE);
- // The part at PV_DATA is zero-initialized. It should be
- // set (through m_pcData and setLength()) to some externally
- // provided buffer before calling CChannel::sendto().
- 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; // already allocated
- // Would be nice to reallocate; for now just allocate again.
- 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);
- m_data_owned = false;
- }
- char* CPacket::release()
- {
- // When not owned, release returns NULL.
- char* buffer = NULL;
- if (m_data_owned)
- {
- buffer = getData();
- m_data_owned = false;
- }
- deallocate(); // won't delete because m_data_owned == false
- return buffer;
- }
- CPacket::~CPacket()
- {
- // PV_HEADER is always owned, PV_DATA may use a "borrowed" buffer.
- // Delete the internal buffer only if it was declared as owned.
- deallocate();
- }
- 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::setLength(size_t len, size_t cap)
- {
- SRT_ASSERT(len <= cap);
- setLength(len);
- m_zCapacity = cap;
- }
- #if ENABLE_HEAVY_LOGGING
- // Debug only
- static std::string FormatNumbers(UDTMessageType pkttype, const int32_t* lparam, void* rparam, const size_t size)
- {
- // This may be changed over time, so use special interpretation
- // only for certain types, and still display all data, no matter
- // if it is expected to provide anything or not.
- std::ostringstream out;
- out << "ARG=";
- if (lparam)
- out << *lparam;
- else
- out << "none";
- if (size == 0)
- {
- out << " [no data]";
- return out.str();
- }
- else if (!rparam)
- {
- out << " [ {" << size << "} ]";
- return out.str();
- }
- bool interp_as_seq = (pkttype == UMSG_LOSSREPORT || pkttype == UMSG_DROPREQ);
- bool display_dec = (pkttype == UMSG_ACK || pkttype == UMSG_ACKACK || pkttype == UMSG_DROPREQ);
- out << " [ ";
- // Will be effective only for hex/oct.
- out << std::showbase;
- const size_t size32 = size/4;
- for (size_t i = 0; i < size32; ++i)
- {
- int32_t val = ((int32_t*)rparam)[i];
- if (interp_as_seq)
- {
- if (val & LOSSDATA_SEQNO_RANGE_FIRST)
- out << "<" << (val & (~LOSSDATA_SEQNO_RANGE_FIRST)) << ">";
- else
- out << val;
- }
- else
- {
- if (!display_dec)
- {
- out << std::hex;
- out << val << "/";
- out << std::dec;
- }
- out << val;
- }
- out << " ";
- }
- out << "]";
- return out.str();
- }
- #endif
- void CPacket::pack(UDTMessageType pkttype, const int32_t* lparam, void* rparam, size_t size)
- {
- // Set (bit-0 = 1) and (bit-1~15 = type)
- setControl(pkttype);
- HLOGC(inlog.Debug, log << "pack: type=" << MessageTypeStr(pkttype) << " " << FormatNumbers(pkttype, lparam, rparam, size));
- // Set additional information and control information field
- switch (pkttype)
- {
- case UMSG_ACK: // 0010 - Acknowledgement (ACK)
- // ACK packet seq. no.
- if (NULL != lparam)
- m_nHeader[SRT_PH_MSGNO] = *lparam;
- // data ACK seq. no.
- // optional: RTT (microsends), RTT variance (microseconds) advertised flow window size (packets), and estimated
- // link capacity (packets per second)
- m_PacketVector[PV_DATA].set(rparam, size);
- break;
- case UMSG_ACKACK: // 0110 - Acknowledgement of Acknowledgement (ACK-2)
- // ACK packet seq. no.
- m_nHeader[SRT_PH_MSGNO] = *lparam;
- // control info field should be none
- // but "writev" does not allow this
- m_PacketVector[PV_DATA].set((void*)&m_extra_pad, 4);
- break;
- case UMSG_LOSSREPORT: // 0011 - Loss Report (NAK)
- // loss list
- m_PacketVector[PV_DATA].set(rparam, size);
- break;
- case UMSG_CGWARNING: // 0100 - Congestion Warning
- // control info field should be none
- // but "writev" does not allow this
- m_PacketVector[PV_DATA].set((void*)&m_extra_pad, 4);
- break;
- case UMSG_KEEPALIVE: // 0001 - Keep-alive
- if (lparam)
- {
- // XXX EXPERIMENTAL. Pass the 32-bit integer here.
- m_nHeader[SRT_PH_MSGNO] = *lparam;
- }
- // control info field should be none
- // but "writev" does not allow this
- m_PacketVector[PV_DATA].set((void*)&m_extra_pad, 4);
- break;
- case UMSG_HANDSHAKE: // 0000 - Handshake
- // control info filed is handshake info
- m_PacketVector[PV_DATA].set(rparam, size);
- break;
- case UMSG_SHUTDOWN: // 0101 - Shutdown
- // control info field should be none
- // but "writev" does not allow this
- m_PacketVector[PV_DATA].set((void*)&m_extra_pad, 4);
- break;
- case UMSG_DROPREQ: // 0111 - Message Drop Request
- // msg id
- m_nHeader[SRT_PH_MSGNO] = *lparam;
- // first seq no, last seq no
- m_PacketVector[PV_DATA].set(rparam, size);
- break;
- case UMSG_PEERERROR: // 1000 - Error Signal from the Peer Side
- // Error type
- m_nHeader[SRT_PH_MSGNO] = *lparam;
- // control info field should be none
- // but "writev" does not allow this
- m_PacketVector[PV_DATA].set((void*)&m_extra_pad, 4);
- break;
- case UMSG_EXT: // 0x7FFF - Reserved for user defined control packets
- // for extended control packet
- // "lparam" contains the extended type information for bit 16 - 31
- // "rparam" is the control information
- 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()
- {
- // XXX USE HtoNLA!
- if (isControl())
- {
- for (ptrdiff_t i = 0, n = getLength() / 4; i < n; ++i)
- *((uint32_t*)m_pcData + i) = htonl(*((uint32_t*)m_pcData + i));
- }
- // convert packet header into network order
- uint32_t* p = m_nHeader;
- for (int j = 0; j < 4; ++j)
- {
- *p = htonl(*p);
- ++p;
- }
- }
- void CPacket::toHL()
- {
- // convert back into local host order
- 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
- {
- // read additional information field
- // This field is used only in UMSG_ACK and UMSG_ACKACK,
- // so 'getAckSeqNo' symbolically defines the only use of it
- // in case of CONTROL PACKET.
- return m_nHeader[SRT_PH_MSGNO];
- }
- uint16_t CPacket::getControlFlags() const
- {
- // This returns exactly the "extended type" value,
- // which is not used at all in case when the standard
- // type message is interpreted. This can be used to pass
- // additional special flags.
- 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]);
- }
- void CPacket::setRexmitFlag(bool bRexmit)
- {
- const int32_t clr_msgno = m_nHeader[SRT_PH_MSGNO] & ~MSGNO_REXMIT::mask;
- m_nHeader[SRT_PH_MSGNO] = clr_msgno | MSGNO_REXMIT::wrap(bRexmit? 1 : 0);
- }
- EncryptionKeySpec CPacket::getMsgCryptoFlags() const
- {
- return EncryptionKeySpec(MSGNO_ENCKEYSPEC::unwrap(m_nHeader[SRT_PH_MSGNO]));
- }
- // This is required as the encryption/decryption happens in place.
- // This is required to clear off the flags after decryption or set
- // crypto flags after encrypting a packet.
- 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
- {
- // SRT_DEBUG_TSBPD_WRAP used to enable smaller timestamps for faster testing of how wraparounds are handled
- 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->allocate(this->getLength());
- SRT_ASSERT(this->getLength() == pkt->getLength());
- memcpy((pkt->m_pcData), m_pcData, this->getLength());
- pkt->m_DestAddr = m_DestAddr;
- return pkt;
- }
- // Useful for debugging
- 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: ";
- // For handshake we already have a parsing method
- CHandShake hs;
- hs.load_from(m_pcData, getLength());
- os << hs.show();
- }
- else
- {
- // This is a value that some messages use for some purposes.
- // The "ack seq no" is one of the purposes, used by UMSG_ACK and UMSG_ACKACK.
- // This is simply the SRT_PH_MSGNO field used as a message number in data packets.
- os << " ARG: 0x";
- os << std::hex << getAckSeqNo() << " ";
- os << std::dec << getAckSeqNo();
- // It would be nice to see the extended packet data, but this
- // requires strictly a message-dependent interpreter. So let's simply
- // display all numbers in the array with the following restrictions:
- // - all data contained in the buffer are considered 32-bit integer
- // - sign flag will be cleared before displaying, with additional mark
- size_t wordlen = getLength() / 4; // drop any remainder if present
- int32_t* array = (int32_t*)m_pcData;
- os << " [ ";
- for (size_t i = 0; i < wordlen; ++i)
- {
- SprintSpecialWord(os, array[i]);
- os << " ";
- }
- os << "]";
- }
- }
- else
- {
- // It's hard to extract the information about peer's supported rexmit flag.
- // This is only a log, nothing crucial, so we can risk displaying incorrect message number.
- // Declaring that the peer supports rexmit flag cuts off the highest bit from
- // the displayed number.
- os << "DATA: size=" << getLength() << " " << BufferStamp(m_pcData, getLength()) << " #" << getMsgSeq(true)
- << " %" << getSeqNo() << " " << MessageFlagStr();
- }
- return os.str();
- }
- #endif
- } // end namespace srt
|