411 lines
13 KiB
C++
411 lines
13 KiB
C++
/*****************************************************************************
|
|
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
|
|
*****************************************************************************/
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// 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
|
|
// available receiver buffer size (in bytes)
|
|
// 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/Delay 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
|
|
// 8: Error Signal from the Peer Side
|
|
// Add. Info: Error code
|
|
// Control Info: None
|
|
// 0x7FFF: 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 <cstring>
|
|
#include "packet.h"
|
|
|
|
|
|
const int CPacket::m_iPktHdrSize = 16;
|
|
const int CHandShake::m_iContentSize = 48;
|
|
|
|
|
|
// 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)),
|
|
__pad()
|
|
{
|
|
for (int i = 0; i < 4; ++ i)
|
|
m_nHeader[i] = 0;
|
|
m_PacketVector[0].iov_base = (char *)m_nHeader;
|
|
m_PacketVector[0].iov_len = CPacket::m_iPktHdrSize;
|
|
m_PacketVector[1].iov_base = NULL;
|
|
m_PacketVector[1].iov_len = 0;
|
|
}
|
|
|
|
CPacket::~CPacket()
|
|
{
|
|
}
|
|
|
|
int CPacket::getLength() const
|
|
{
|
|
return m_PacketVector[1].iov_len;
|
|
}
|
|
|
|
void CPacket::setLength(int len)
|
|
{
|
|
m_PacketVector[1].iov_len = len;
|
|
}
|
|
|
|
void CPacket::pack(int pkttype, void* lparam, void* rparam, 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 8: //1000 - Error Signal from the Peer Side
|
|
// Error type
|
|
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 32767: //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[0] |= *(int32_t *)lparam;
|
|
|
|
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;
|
|
}
|
|
|
|
CHandShake::CHandShake():
|
|
m_iVersion(0),
|
|
m_iType(0),
|
|
m_iISN(0),
|
|
m_iMSS(0),
|
|
m_iFlightFlagSize(0),
|
|
m_iReqType(0),
|
|
m_iID(0),
|
|
m_iCookie(0)
|
|
{
|
|
for (int i = 0; i < 4; ++ i)
|
|
m_piPeerIP[i] = 0;
|
|
}
|
|
|
|
int CHandShake::serialize(char* buf, int& size)
|
|
{
|
|
if (size < m_iContentSize)
|
|
return -1;
|
|
|
|
int32_t* p = (int32_t*)buf;
|
|
*p++ = m_iVersion;
|
|
*p++ = m_iType;
|
|
*p++ = m_iISN;
|
|
*p++ = m_iMSS;
|
|
*p++ = m_iFlightFlagSize;
|
|
*p++ = m_iReqType;
|
|
*p++ = m_iID;
|
|
*p++ = m_iCookie;
|
|
for (int i = 0; i < 4; ++ i)
|
|
*p++ = m_piPeerIP[i];
|
|
|
|
size = m_iContentSize;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CHandShake::deserialize(const char* buf, int size)
|
|
{
|
|
if (size < m_iContentSize)
|
|
return -1;
|
|
|
|
int32_t* p = (int32_t*)buf;
|
|
m_iVersion = *p++;
|
|
m_iType = *p++;
|
|
m_iISN = *p++;
|
|
m_iMSS = *p++;
|
|
m_iFlightFlagSize = *p++;
|
|
m_iReqType = *p++;
|
|
m_iID = *p++;
|
|
m_iCookie = *p++;
|
|
for (int i = 0; i < 4; ++ i)
|
|
m_piPeerIP[i] = *p++;
|
|
|
|
return 0;
|
|
}
|