765 lines
26 KiB
C#
765 lines
26 KiB
C#
//////////////////////////////////////////////////////////////////////////////
|
|
// 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.
|
|
|
|
using System;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
using System.Text;
|
|
|
|
namespace UdtSharp
|
|
{
|
|
public struct iovec
|
|
{
|
|
public uint[] iov_base;
|
|
public int iov_len;
|
|
}
|
|
|
|
|
|
|
|
public unsafe class Packet
|
|
{
|
|
public enum ControlType
|
|
{
|
|
Handshake = 0,
|
|
KeepAlive = 1,
|
|
Ack = 2,
|
|
Nak = 3,
|
|
CongestionWarning = 4,
|
|
Shutdown = 5,
|
|
Ack2 = 6,
|
|
DropMessage = 7,
|
|
Error = 8,
|
|
UserType = 32767,
|
|
}
|
|
|
|
const int m_iSeqNoIndex = 0; // alias: sequence number
|
|
const int m_iMsgNoIndex = 1; // alias: message number
|
|
const int m_iTimeStampIndex = 2; // alias: timestamp
|
|
const int m_iIdIndex = 3; // alias: socket ID
|
|
|
|
public const int m_iPktHdrSize = 16; // packet header size
|
|
|
|
iovec[] m_PacketVector = new iovec[2]; // The 2-demension vector of UDT packet [header, data]
|
|
|
|
public override string ToString()
|
|
{
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
|
|
if (getFlag() == 0)
|
|
{
|
|
byte[] data = GetDataBytes();
|
|
stringBuilder.AppendFormat("Data length {0} bytes", data != null ? data.Length : 0);
|
|
stringBuilder.AppendLine();
|
|
stringBuilder.AppendLine(" SeqNo " + GetSequenceNumber());
|
|
stringBuilder.AppendLine(" MsgNo " + GetMessageNumber());
|
|
stringBuilder.AppendLine(" Timestamp " + GetTimestamp());
|
|
stringBuilder.AppendLine(" SocketID " + GetId());
|
|
stringBuilder.Append(" Data: {");
|
|
if (data != null)
|
|
{
|
|
for (int i = 0; i < Math.Min(data.Length, 10); ++i)
|
|
{
|
|
stringBuilder.Append(data[i] + ",");
|
|
}
|
|
stringBuilder.Length = stringBuilder.Length - 1;
|
|
}
|
|
stringBuilder.AppendLine("}");
|
|
}
|
|
else if (getFlag() == 1)
|
|
{
|
|
int type = getType();
|
|
stringBuilder.AppendFormat("CTRL {0} ({1})", (Packet.ControlType)type, type);
|
|
stringBuilder.AppendLine();
|
|
switch (type)
|
|
{
|
|
case 2: //0010 - Acknowledgement (ACK)
|
|
stringBuilder.AppendFormat(" Ack sequence {0}", getAckSeqNo());
|
|
stringBuilder.AppendLine();
|
|
break;
|
|
|
|
case 6: //0110 - Acknowledgement of Acknowledgement (ACK-2)
|
|
stringBuilder.AppendFormat(" Ack2 sequence {0}", getAckSeqNo());
|
|
stringBuilder.AppendLine();
|
|
break;
|
|
|
|
case 3: //0011 - Loss Report (NAK)
|
|
break;
|
|
|
|
case 4: //0100 - Congestion Warning
|
|
break;
|
|
|
|
case 1: //0001 - Keep-alive
|
|
break;
|
|
|
|
case 0: //0000 - Handshake
|
|
// control info filed is handshake info
|
|
Handshake handshake = new Handshake();
|
|
handshake.deserialize(GetDataBytes(), Handshake.m_iContentSize);
|
|
stringBuilder.AppendFormat(handshake.ToString());
|
|
stringBuilder.AppendLine();
|
|
break;
|
|
|
|
case 5: //0101 - Shutdown
|
|
break;
|
|
|
|
case 7: //0111 - Message Drop Request
|
|
|
|
break;
|
|
|
|
case 8: //1000 - Error Signal from the Peer Side
|
|
// Error type
|
|
stringBuilder.AppendLine("Error: " + m_PacketVector[0].iov_base[m_iMsgNoIndex].ToString());
|
|
|
|
break;
|
|
|
|
case 32767: //0x7FFF - Reserved for user defined control packets
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return stringBuilder.ToString();
|
|
}
|
|
|
|
public Packet()
|
|
{
|
|
m_PacketVector[0].iov_base = new uint[4];
|
|
m_PacketVector[0].iov_len = m_iPktHdrSize;
|
|
m_PacketVector[1].iov_base = null;
|
|
m_PacketVector[1].iov_len = 0;
|
|
}
|
|
|
|
~Packet()
|
|
{
|
|
}
|
|
|
|
public void Clone(Packet source)
|
|
{
|
|
Buffer.BlockCopy(source.m_PacketVector[0].iov_base, 0, m_PacketVector[0].iov_base, 0, m_iPktHdrSize);
|
|
|
|
if (source.m_PacketVector[1].iov_base == null)
|
|
{
|
|
m_PacketVector[1].iov_base = null;
|
|
m_PacketVector[1].iov_len = source.m_PacketVector[1].iov_len;
|
|
return;
|
|
}
|
|
|
|
m_PacketVector[1].iov_base = new uint[source.m_PacketVector[1].iov_base.Length];
|
|
Buffer.BlockCopy(source.m_PacketVector[1].iov_base, 0, m_PacketVector[1].iov_base, 0, source.m_PacketVector[1].iov_len);
|
|
m_PacketVector[1].iov_len = source.m_PacketVector[1].iov_len;
|
|
}
|
|
|
|
public int GetSequenceNumber()
|
|
{
|
|
return (int)m_PacketVector[0].iov_base[m_iSeqNoIndex];
|
|
}
|
|
|
|
public void SetSequenceNumber(int sequenceNumber)
|
|
{
|
|
m_PacketVector[0].iov_base[m_iSeqNoIndex] = (uint)sequenceNumber;
|
|
}
|
|
|
|
public uint GetMessageNumber()
|
|
{
|
|
return m_PacketVector[0].iov_base[m_iMsgNoIndex];
|
|
}
|
|
|
|
public void SetMessageNumber(uint messageNumber)
|
|
{
|
|
m_PacketVector[0].iov_base[m_iMsgNoIndex] = messageNumber;
|
|
}
|
|
|
|
public int GetTimestamp()
|
|
{
|
|
return (int)m_PacketVector[0].iov_base[m_iTimeStampIndex];
|
|
}
|
|
|
|
public void SetTimestamp(int timestamp)
|
|
{
|
|
m_PacketVector[0].iov_base[m_iTimeStampIndex] = (uint)timestamp;
|
|
}
|
|
|
|
public int GetId()
|
|
{
|
|
return (int)m_PacketVector[0].iov_base[m_iIdIndex];
|
|
}
|
|
|
|
public void SetId(int id)
|
|
{
|
|
m_PacketVector[0].iov_base[m_iIdIndex] = (uint)id;
|
|
}
|
|
|
|
public byte[] GetBytes()
|
|
{
|
|
int dataLength = m_PacketVector[1].iov_len;
|
|
|
|
byte[] bytes = new byte[m_iPktHdrSize + dataLength];
|
|
Buffer.BlockCopy(m_PacketVector[0].iov_base, 0, bytes, 0, m_iPktHdrSize);
|
|
|
|
if (dataLength == 0 || m_PacketVector[1].iov_base == null)
|
|
return bytes;
|
|
|
|
Buffer.BlockCopy(m_PacketVector[1].iov_base, 0, bytes, m_iPktHdrSize, dataLength);
|
|
return bytes;
|
|
}
|
|
|
|
public byte[] GetHeaderBytes()
|
|
{
|
|
byte[] bytes = new byte[m_iPktHdrSize];
|
|
Buffer.BlockCopy(m_PacketVector[0].iov_base, 0, bytes, 0, m_iPktHdrSize);
|
|
return bytes;
|
|
}
|
|
|
|
public int GetDataBytes(int packetOffset, byte[] data, int dataOffset, int length)
|
|
{
|
|
if (m_PacketVector[1].iov_base == null)
|
|
return 0;
|
|
|
|
int bufferAvailable = data.Length - dataOffset;
|
|
if (bufferAvailable < length)
|
|
length = bufferAvailable;
|
|
|
|
Buffer.BlockCopy(m_PacketVector[1].iov_base, packetOffset, data, dataOffset, length);
|
|
return length;
|
|
}
|
|
|
|
public int GetIntFromData(int offset)
|
|
{
|
|
return (int)m_PacketVector[1].iov_base[offset];
|
|
}
|
|
|
|
public byte[] GetDataBytes()
|
|
{
|
|
if (m_PacketVector[1].iov_base == null)
|
|
return null;
|
|
|
|
int dataLength = m_PacketVector[1].iov_len;
|
|
if (dataLength <= 0)
|
|
return null;
|
|
|
|
byte[] bytes = new byte[dataLength];
|
|
Buffer.BlockCopy(m_PacketVector[1].iov_base, 0, bytes, 0, bytes.Length);
|
|
return bytes;
|
|
}
|
|
|
|
public bool SetHeaderAndDataFromBytes(byte[] bytes, int length)
|
|
{
|
|
if (length < m_iPktHdrSize)
|
|
return false;
|
|
|
|
Buffer.BlockCopy(bytes, 0, m_PacketVector[0].iov_base, 0, m_iPktHdrSize);
|
|
|
|
int dataLength = length - m_iPktHdrSize;
|
|
if (dataLength == 0)
|
|
{
|
|
m_PacketVector[1].iov_base = null;
|
|
m_PacketVector[1].iov_len = 0;
|
|
return true;
|
|
}
|
|
|
|
SetDataFromBytes(bytes, m_iPktHdrSize, dataLength);
|
|
|
|
return true;
|
|
}
|
|
|
|
public void SetDataFromBytes(byte[] bytes)
|
|
{
|
|
SetDataFromBytes(bytes, 0, bytes.Length);
|
|
}
|
|
|
|
public void SetDataFromBytes(byte[] bytes, int offset, int byteCount)
|
|
{
|
|
int intCount = byteCount / 4;
|
|
if (byteCount % 4 != 0)
|
|
++intCount;
|
|
|
|
m_PacketVector[1].iov_base = new uint[intCount];
|
|
m_PacketVector[1].iov_len = byteCount;
|
|
|
|
Buffer.BlockCopy(bytes, offset, m_PacketVector[1].iov_base, 0, byteCount);
|
|
}
|
|
|
|
public void ConvertControlInfoToNetworkOrder()
|
|
{
|
|
if (getFlag() == 0)
|
|
return;
|
|
|
|
if (m_PacketVector[1].iov_base == null || m_PacketVector[1].iov_len == 0)
|
|
return;
|
|
|
|
for (int i = 0; i < m_PacketVector[1].iov_base.Length; ++i)
|
|
{
|
|
m_PacketVector[1].iov_base[i] =
|
|
(uint)IPAddress.HostToNetworkOrder((int)m_PacketVector[1].iov_base[i]);
|
|
}
|
|
}
|
|
|
|
public void ConvertControlInfoToHostOrder()
|
|
{
|
|
if (getFlag() == 0)
|
|
return;
|
|
|
|
if (m_PacketVector[1].iov_base == null || m_PacketVector[1].iov_len == 0)
|
|
return;
|
|
|
|
for (int i = 0; i < m_PacketVector[1].iov_base.Length; ++i)
|
|
{
|
|
m_PacketVector[1].iov_base[i] =
|
|
(uint)IPAddress.NetworkToHostOrder((int)m_PacketVector[1].iov_base[i]);
|
|
}
|
|
}
|
|
|
|
public void ConvertHeaderToNetworkOrder()
|
|
{
|
|
for (int i = 0; i < m_PacketVector[0].iov_base.Length; ++i)
|
|
{
|
|
m_PacketVector[0].iov_base[i] =
|
|
(uint)IPAddress.HostToNetworkOrder((int)m_PacketVector[0].iov_base[i]);
|
|
}
|
|
}
|
|
|
|
public void ConvertHeaderToHostOrder()
|
|
{
|
|
for (int i = 0; i < m_PacketVector[0].iov_base.Length; ++i)
|
|
{
|
|
m_PacketVector[0].iov_base[i] =
|
|
(uint)IPAddress.NetworkToHostOrder((int)m_PacketVector[0].iov_base[i]);
|
|
}
|
|
}
|
|
|
|
public int getLength()
|
|
{
|
|
return m_PacketVector[1].iov_len;
|
|
}
|
|
|
|
public void setLength(int len)
|
|
{
|
|
m_PacketVector[1].iov_len = len;
|
|
}
|
|
|
|
static iovec MakeIovec(void* rparam, int size)
|
|
{
|
|
iovec result = new iovec();
|
|
result.iov_len = size;
|
|
|
|
if (rparam == null)
|
|
return result;
|
|
|
|
result.iov_base = new uint[size >> 2];
|
|
|
|
uint* pIn = (uint*)rparam;
|
|
for (int i = 0; i < size >> 2; ++i)
|
|
{
|
|
result.iov_base[i] = *pIn++;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public void pack(Handshake hs)
|
|
{
|
|
// TODO avoid this inefficient buffer creation
|
|
// we copy this buffer into another buffer later
|
|
byte[] bytes = new byte[Handshake.m_iContentSize];
|
|
hs.serialize(bytes);
|
|
pack(0, bytes);
|
|
}
|
|
|
|
public void pack(int pkttype, void* lparam)
|
|
{
|
|
if (pkttype != 6 && pkttype != 8)
|
|
throw new Exception("pkttype must be 6 or 8");
|
|
|
|
pack(pkttype, lparam, (void*)null, 0);
|
|
}
|
|
|
|
public void pack(int pkttype, byte[] rparam)
|
|
{
|
|
if (pkttype != 0)
|
|
throw new Exception("pkttype must be 0");
|
|
|
|
fixed (byte* prparam = rparam)
|
|
{
|
|
pack(pkttype, (void*)null, (void*)prparam, rparam.Length);
|
|
}
|
|
}
|
|
|
|
public void pack(int pkttype, int lparam, int[] rparam)
|
|
{
|
|
if (pkttype != 2)
|
|
throw new Exception("pkttype must be 2");
|
|
|
|
fixed (int* prparam = rparam)
|
|
{
|
|
pack(pkttype, &lparam, (void*)prparam, rparam.Length * 4);
|
|
}
|
|
}
|
|
|
|
public void pack(int pkttype, int lparam, int[] rparam, int length)
|
|
{
|
|
if (pkttype != 2)
|
|
throw new Exception("pkttype must be 2");
|
|
|
|
fixed (int* prparam = rparam)
|
|
{
|
|
pack(pkttype, &lparam, (void*)prparam, length * 4);
|
|
}
|
|
}
|
|
|
|
public void pack(int pkttype, int[] rparam, int length)
|
|
{
|
|
if (pkttype != 3)
|
|
throw new Exception("pkttype must be 3");
|
|
|
|
fixed (int* prparam = rparam)
|
|
{
|
|
pack(pkttype, (void*)null, (void*)prparam, length * 4);
|
|
}
|
|
}
|
|
|
|
public void pack(int pkttype)
|
|
{
|
|
if (pkttype != 1 && pkttype != 4 && pkttype != 5)
|
|
throw new Exception("pkttype must be 1, 4 or 5");
|
|
|
|
pack(pkttype, (void*)null, (void*)null, 0);
|
|
}
|
|
|
|
public void pack(int pkttype, void* lparam, void* rparam, int size)
|
|
{
|
|
// Set (bit-0 = 1) and (bit-1~15 = type)
|
|
m_PacketVector[0].iov_base[m_iSeqNoIndex] = (uint)0x80000000 | (uint)(pkttype << 16);
|
|
|
|
// Set additional information and control information field
|
|
switch (pkttype)
|
|
{
|
|
case 2: //0010 - Acknowledgement (ACK)
|
|
// ACK packet seq. no.
|
|
if (null != lparam)
|
|
m_PacketVector[0].iov_base[m_iMsgNoIndex] = *(uint*)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] = MakeIovec(rparam, size);
|
|
|
|
break;
|
|
|
|
case 6: //0110 - Acknowledgement of Acknowledgement (ACK-2)
|
|
// ACK packet seq. no.
|
|
m_PacketVector[0].iov_base[m_iMsgNoIndex] = *(uint*)lparam;
|
|
|
|
// control info field should be none
|
|
// but "writev" does not allow this
|
|
m_PacketVector[1] = MakeIovec(null, 4);
|
|
|
|
break;
|
|
|
|
case 3: //0011 - Loss Report (NAK)
|
|
// loss list
|
|
m_PacketVector[1] = MakeIovec(rparam, size);
|
|
|
|
break;
|
|
|
|
case 4: //0100 - Congestion Warning
|
|
// control info field should be none
|
|
// but "writev" does not allow this
|
|
m_PacketVector[1] = MakeIovec(null, 4);
|
|
|
|
break;
|
|
|
|
case 1: //0001 - Keep-alive
|
|
// control info field should be none
|
|
// but "writev" does not allow this
|
|
m_PacketVector[1] = MakeIovec(null, 4);
|
|
|
|
break;
|
|
|
|
case 0: //0000 - Handshake
|
|
// control info filed is handshake info
|
|
m_PacketVector[1] = MakeIovec(rparam, size);
|
|
|
|
break;
|
|
|
|
case 5: //0101 - Shutdown
|
|
// control info field should be none
|
|
// but "writev" does not allow this
|
|
m_PacketVector[1] = MakeIovec(null, 4);
|
|
|
|
break;
|
|
|
|
case 7: //0111 - Message Drop Request
|
|
// msg id
|
|
m_PacketVector[0].iov_base[m_iMsgNoIndex] = *(uint*)lparam;
|
|
|
|
//first seq no, last seq no
|
|
m_PacketVector[1] = MakeIovec(rparam, size);
|
|
|
|
break;
|
|
|
|
case 8: //1000 - Error Signal from the Peer Side
|
|
// Error type
|
|
m_PacketVector[0].iov_base[m_iMsgNoIndex] = *(uint*)lparam;
|
|
|
|
// control info field should be none
|
|
// but "writev" does not allow this
|
|
m_PacketVector[1] = MakeIovec(null, 4);
|
|
|
|
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_PacketVector[0].iov_base[m_iSeqNoIndex] |= *(uint*)lparam;
|
|
|
|
if (null != rparam)
|
|
{
|
|
m_PacketVector[1] = MakeIovec(rparam, size);
|
|
}
|
|
else
|
|
{
|
|
m_PacketVector[1] = MakeIovec(null, 4);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
public iovec[] getPacketVector()
|
|
{
|
|
return m_PacketVector;
|
|
}
|
|
|
|
public int getFlag()
|
|
{
|
|
// read bit 0
|
|
return (int)(m_PacketVector[0].iov_base[m_iSeqNoIndex] >> 31);
|
|
}
|
|
|
|
public int getType()
|
|
{
|
|
// read bit 1~15
|
|
return (int)((m_PacketVector[0].iov_base[m_iSeqNoIndex] >> 16) & 0x00007FFF);
|
|
}
|
|
|
|
int getExtendedType()
|
|
{
|
|
// read bit 16~31
|
|
return (int)(m_PacketVector[0].iov_base[m_iSeqNoIndex] & 0x0000FFFF);
|
|
}
|
|
|
|
public int getAckSeqNo()
|
|
{
|
|
// read additional information field
|
|
return (int)m_PacketVector[0].iov_base[m_iMsgNoIndex];
|
|
}
|
|
|
|
public int getMsgBoundary()
|
|
{
|
|
// read [1] bit 0~1
|
|
return (int)(m_PacketVector[0].iov_base[m_iMsgNoIndex] >> 30);
|
|
}
|
|
|
|
public bool getMsgOrderFlag()
|
|
{
|
|
// read [1] bit 2
|
|
return (1 == ((m_PacketVector[0].iov_base[m_iMsgNoIndex] >> 29) & 1));
|
|
}
|
|
|
|
public int getMsgSeq()
|
|
{
|
|
// read [1] bit 3~31
|
|
return (int)(m_PacketVector[0].iov_base[m_iMsgNoIndex] & 0x1FFFFFFF);
|
|
}
|
|
}
|
|
|
|
public class Handshake
|
|
{
|
|
public const int m_iContentSize = 48; // Size of hand shake data
|
|
|
|
public int m_iVersion; // UDT version
|
|
public SocketType m_iType; // UDT socket type
|
|
public int m_iISN; // random initial sequence number
|
|
public int m_iMSS; // maximum segment size
|
|
public int m_iFlightFlagSize; // flow control window size
|
|
public int m_iReqType; // connection request type: 1: regular connection request, 0: rendezvous connection request, -1/-2: response
|
|
public int m_iID; // socket ID
|
|
public int m_iCookie; // cookie
|
|
public uint[] m_piPeerIP = new uint[4]; // The IP address that the peer's UDP port is bound to
|
|
|
|
public Handshake()
|
|
{
|
|
for (int i = 0; i < 4; ++i)
|
|
m_piPeerIP[i] = 0;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
string type = "connection request";
|
|
if (m_iReqType == 0)
|
|
type = "rendezvouz";
|
|
if (m_iReqType < 0)
|
|
type = "reponse";
|
|
if (m_iReqType == 1002)
|
|
type = "rejected request";
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.AppendLine(" Version " + m_iVersion);
|
|
sb.AppendLine(" Type " + type);
|
|
sb.AppendLine(" Cookie " + m_iCookie);
|
|
//sb.AppendLine(" Socket type " + m_iType.ToString());
|
|
//sb.AppendLine(" Socket id " + m_iID);
|
|
sb.AppendLine(" Initial seq# " + m_iISN);
|
|
//sb.AppendLine(" MSS " + m_iMSS);
|
|
//sb.AppendLine(" Flight size " + m_iFlightFlagSize);
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
public unsafe void serialize(byte[] buf)
|
|
{
|
|
fixed (byte* pb = buf)
|
|
{
|
|
int* p = (int*)(pb);
|
|
*p++ = m_iVersion;
|
|
*p++ = (int)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++ = (int)m_piPeerIP[i];
|
|
}
|
|
}
|
|
|
|
public unsafe bool deserialize(byte[] buf, int size)
|
|
{
|
|
if (size < m_iContentSize)
|
|
return false;
|
|
|
|
fixed (byte* pb = buf)
|
|
{
|
|
int* p = (int*)(pb);
|
|
m_iVersion = *p++;
|
|
m_iType = (SocketType)(*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] = (uint)*p++;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|