/*****************************************************************************
Copyright (c) 2001 - 2007, 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 04/27/2007
*****************************************************************************/
//////////////////////////////////////////////////////////////////////////////
// 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| 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
//
// 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:
// 0: Protocol Connection Handshake
// Add. Info: Undefined
// Control Info: Handshake information (see CHandShake)
// 1: Keep-alive
// Add. Info: Undefined
// Control Info: None
// 2: Acknowledgement (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
// advertised flow window size (number of packets)
// estimated bandwidth (number of packets per second)
// 3: Negative Acknowledgement (NAK)
// Add. Info: Undefined
// Control Info: Loss list (see loss list coding below)
// 4: Congestion Warning
// Add. Info: Undefined
// Control Info: None
// 5: Shutdown
// Add. Info: Undefined
// Control Info: None
// 6: Acknowledgement of Acknowledement (ACK-square)
// Add. Info: The ACK sequence number
// Control Info: None
// 7: Message Drop Request
// Add. Info: Message ID
// Control Info: first sequence number of the message
// last seqeunce number of the message
// 65535: Explained by bits 16 - 31
//
// 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 consectutive 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 consectutive loss less than 2 packets, use
// the original sequence numbers in the field.
#include "packet.h"
const int CPacket::m_iPktHdrSize = 16;
// Set up the aliases in the constructure
CPacket::CPacket():
m_iSeqNo((int32_t&)(m_nHeader[0])),
m_iMsgNo((int32_t&)(m_nHeader[1])),
m_iTimeStamp((int32_t&)(m_nHeader[2])),
m_iID((int32_t&)(m_nHeader[3])),
m_pcData((char*&)(m_PacketVector[1].iov_base))
{
m_PacketVector[0].iov_base = (char *)m_nHeader;
m_PacketVector[0].iov_len = CPacket::m_iPktHdrSize;
}
CPacket::~CPacket()
{
}
int CPacket::getLength() const
{
return m_PacketVector[1].iov_len;
}
void CPacket::setLength(const int& len)
{
m_PacketVector[1].iov_len = len;
}
void CPacket::pack(const int& pkttype, void* lparam, void* rparam, const int& size)
{
// Set (bit-0 = 1) and (bit-1~15 = type)
m_nHeader[0] = 0x80000000 | (pkttype << 16);
// Set additional information and control information field
switch (pkttype)
{
case 2: //0010 - Acknowledgement (ACK)
// ACK packet seq. no.
if (NULL != lparam)
m_nHeader[1] = *(int32_t *)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[1].iov_base = (char *)rparam;
m_PacketVector[1].iov_len = size;
break;
case 6: //0110 - Acknowledgement of Acknowledgement (ACK-2)
// ACK packet seq. no.
m_nHeader[1] = *(int32_t *)lparam;
// control info field should be none
// but "writev" does not allow this
m_PacketVector[1].iov_base = (char *)&__pad; //NULL;
m_PacketVector[1].iov_len = 4; //0;
break;
case 3: //0011 - Loss Report (NAK)
// loss list
m_PacketVector[1].iov_base = (char *)rparam;
m_PacketVector[1].iov_len = size;
break;
case 4: //0100 - Congestion Warning
// control info field should be none
// but "writev" does not allow this
m_PacketVector[1].iov_base = (char *)&__pad; //NULL;
m_PacketVector[1].iov_len = 4; //0;
break;
case 1: //0001 - Keep-alive
// control info field should be none
// but "writev" does not allow this
m_PacketVector[1].iov_base = (char *)&__pad; //NULL;
m_PacketVector[1].iov_len = 4; //0;
break;
case 0: //0000 - Handshake
// control info filed is handshake info
m_PacketVector[1].iov_base = (char *)rparam;
m_PacketVector[1].iov_len = size; //sizeof(CHandShake);
break;
case 5: //0101 - Shutdown
// control info field should be none
// but "writev" does not allow this
m_PacketVector[1].iov_base = (char *)&__pad; //NULL;
m_PacketVector[1].iov_len = 4; //0;
break;
case 7: //0111 - Message Drop Request
// msg id
m_nHeader[1] = *(int32_t *)lparam;
//first seq no, last seq no
m_PacketVector[1].iov_base = (char *)rparam;
m_PacketVector[1].iov_len = size;
break;
case 65535: //0x7FFF - Reserved for user defined control packets
// for extended control packet
// "lparam" contains the extneded type information for bit 4 - 15
// "rparam" is the control information
m_nHeader[0] |= (*(int32_t *)lparam) << 16;
if (NULL != rparam)
{
m_PacketVector[1].iov_base = (char *)rparam;
m_PacketVector[1].iov_len = size;
}
else
{
m_PacketVector[1].iov_base = (char *)&__pad;
m_PacketVector[1].iov_len = 4;
}
break;
default:
break;
}
}
iovec* CPacket::getPacketVector()
{
return m_PacketVector;
}
int CPacket::getFlag() const
{
// read bit 0
return m_nHeader[0] >> 31;
}
int CPacket::getType() const
{
// read bit 1~15
return (m_nHeader[0] >> 16) & 0x00007FFF;
}
int CPacket::getExtendedType() const
{
// read bit 16~31
return m_nHeader[0] & 0x0000FFFF;
}
int32_t CPacket::getAckSeqNo() const
{
// read additional information field
return m_nHeader[1];
}
int CPacket::getMsgBoundary() const
{
// read [1] bit 0~1
return m_nHeader[1] >> 30;
}
bool CPacket::getMsgOrderFlag() const
{
// read [1] bit 2
return (1 == ((m_nHeader[1] >> 29) & 1));
}
int32_t CPacket::getMsgSeq() const
{
// read [1] bit 3~31
return m_nHeader[1] & 0x1FFFFFFF;
}
CPacket* CPacket::clone() const
{
CPacket* pkt = new CPacket;
memcpy(pkt->m_nHeader, m_nHeader, m_iPktHdrSize);
pkt->m_pcData = new char[m_PacketVector[1].iov_len];
memcpy(pkt->m_pcData, m_pcData, m_PacketVector[1].iov_len);
pkt->m_PacketVector[1].iov_len = m_PacketVector[1].iov_len;
return pkt;
}