904 lines
26 KiB
C#
904 lines
26 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
using System.Threading;
|
|
|
|
namespace UdtSharp
|
|
{
|
|
public class SNode
|
|
{
|
|
public UDT m_pUDT; // Pointer to the instance of CUDT socket
|
|
public ulong m_llTimeStamp; // Time Stamp
|
|
|
|
public int m_iHeapLoc; // location on the heap, -1 means not on the heap
|
|
};
|
|
|
|
public class RNode
|
|
{
|
|
public UDT m_pUDT; // Pointer to the instance of CUDT socket
|
|
public ulong m_llTimeStamp; // Time Stamp
|
|
|
|
public bool m_bOnList; // if the node is already on the list
|
|
};
|
|
|
|
class UnitQueue
|
|
{
|
|
struct QEntry
|
|
{
|
|
internal Unit[] m_pUnit; // unit queue
|
|
internal byte[][] m_pBuffer; // data buffer
|
|
internal int m_iSize; // size of each queue
|
|
}
|
|
List<QEntry> mEntries = new List<QEntry>();
|
|
|
|
int m_iCurrEntry = 0;
|
|
int m_iLastEntry = 0;
|
|
|
|
int m_iAvailUnit; // recent available unit
|
|
int m_iAvailableQueue;
|
|
|
|
int m_iSize; // total size of the unit queue, in number of packets
|
|
public int m_iCount; // total number of valid packets in the queue
|
|
|
|
int m_iMSS; // unit buffer size
|
|
AddressFamily m_iIPversion; // IP version
|
|
|
|
UnitQueue()
|
|
{
|
|
m_iSize = 0;
|
|
m_iCount = 0;
|
|
m_iMSS = 0;
|
|
m_iIPversion = 0;
|
|
}
|
|
|
|
~UnitQueue()
|
|
{
|
|
}
|
|
|
|
int init(int size, int mss, AddressFamily version)
|
|
{
|
|
QEntry tempq = new QEntry();
|
|
Unit[] tempu = new Unit[size];
|
|
byte[][] tempb = new byte[size][];
|
|
|
|
for (int i = 0; i < size; ++i)
|
|
{
|
|
tempb[i] = new byte[mss];
|
|
tempu[i] = new Unit();
|
|
tempu[i].m_iFlag = 0;
|
|
|
|
tempu[i].m_Packet.SetDataFromBytes(tempb[i]);
|
|
}
|
|
tempq.m_pUnit = tempu;
|
|
tempq.m_pBuffer = tempb;
|
|
tempq.m_iSize = size;
|
|
|
|
m_iSize = size;
|
|
m_iMSS = mss;
|
|
m_iIPversion = version;
|
|
|
|
mEntries.Add(tempq);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int increase()
|
|
{
|
|
// adjust/correct m_iCount
|
|
int real_count = 0;
|
|
for (int q = 0; q < mEntries.Count; ++q)
|
|
{
|
|
Unit[] units = mEntries[q].m_pUnit;
|
|
for (int u = mEntries[q].m_iSize; u < units.Length; ++u)
|
|
if (units[u].m_iFlag != 0)
|
|
++real_count;
|
|
}
|
|
m_iCount = real_count;
|
|
if ((double)m_iCount / m_iSize < 0.9)
|
|
return -1;
|
|
|
|
// all queues have the same size
|
|
int size = mEntries[0].m_iSize;
|
|
|
|
QEntry tempq = new QEntry();
|
|
Unit[] tempu = new Unit[size];
|
|
byte[][] tempb = new byte[size][];
|
|
|
|
for (int i = 0; i < size; ++i)
|
|
{
|
|
tempb[i] = new byte[m_iMSS];
|
|
tempu[i].m_iFlag = 0;
|
|
tempu[i].m_Packet.SetDataFromBytes(tempb[i]);
|
|
}
|
|
tempq.m_pUnit = tempu;
|
|
tempq.m_pBuffer = tempb;
|
|
tempq.m_iSize = size;
|
|
|
|
mEntries.Add(tempq);
|
|
|
|
m_iSize += size;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int shrink()
|
|
{
|
|
// currently queue cannot be shrunk.
|
|
return -1;
|
|
}
|
|
|
|
Unit getNextAvailUnit()
|
|
{
|
|
if (m_iCount * 10 > m_iSize * 9)
|
|
increase();
|
|
|
|
if (m_iCount >= m_iSize)
|
|
return null;
|
|
|
|
QEntry entrance = mEntries[m_iCurrEntry];
|
|
|
|
//do
|
|
//{
|
|
// QEntry currentEntry = mEntries[m_iCurrEntry];
|
|
// Unit sentinel = currentEntry.m_pUnit[currentEntry.m_iSize - 1];
|
|
// for (CUnit* sentinel = m_pCurrQueue.m_pUnit + m_pCurrQueue.m_iSize - 1; m_pAvailUnit != sentinel; ++m_pAvailUnit)
|
|
// if (m_pAvailUnit.m_iFlag == 0)
|
|
// return m_pAvailUnit;
|
|
|
|
|
|
|
|
// if (m_pCurrQueue.m_pUnit.m_iFlag == 0)
|
|
// {
|
|
// m_pAvailUnit = m_pCurrQueue.m_pUnit;
|
|
// return m_pAvailUnit;
|
|
// }
|
|
|
|
// m_pCurrQueue = m_pCurrQueue.m_pNext;
|
|
// m_pAvailUnit = m_pCurrQueue.m_pUnit;
|
|
//} while (m_pCurrQueue != entrance);
|
|
|
|
increase();
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public class SndUList
|
|
{
|
|
object m_ListLock = new object();
|
|
|
|
public object m_pWindowLock;
|
|
public EventWaitHandle m_pWindowCond;
|
|
|
|
SNode[] m_pHeap; // The heap array
|
|
int m_iArrayLength; // physical length of the array
|
|
int m_iLastEntry; // position of last entry on the heap array
|
|
|
|
public Timer m_pTimer;
|
|
|
|
public SndUList()
|
|
{
|
|
m_iArrayLength = 4096;
|
|
m_iLastEntry = -1;
|
|
|
|
m_pHeap = new SNode[m_iArrayLength];
|
|
}
|
|
|
|
public void insert(ulong ts, UDT u)
|
|
{
|
|
lock (m_ListLock)
|
|
{
|
|
// increase the heap array size if necessary
|
|
if (m_iLastEntry == m_iArrayLength - 1)
|
|
{
|
|
Array.Resize(ref m_pHeap, m_iArrayLength * 2);
|
|
m_iArrayLength *= 2;
|
|
}
|
|
|
|
insert_(ts, u);
|
|
}
|
|
}
|
|
|
|
public void update(UDT u, bool reschedule = true)
|
|
{
|
|
lock (m_ListLock)
|
|
{
|
|
SNode n = u.m_pSNode;
|
|
|
|
if (n.m_iHeapLoc >= 0)
|
|
{
|
|
if (!reschedule)
|
|
return;
|
|
|
|
if (n.m_iHeapLoc == 0)
|
|
{
|
|
n.m_llTimeStamp = 1;
|
|
m_pTimer.interrupt();
|
|
return;
|
|
}
|
|
|
|
remove_(u);
|
|
}
|
|
|
|
insert_(1, u);
|
|
}
|
|
}
|
|
|
|
public int pop(ref IPEndPoint addr, ref Packet pkt)
|
|
{
|
|
lock (m_ListLock)
|
|
{
|
|
if (-1 == m_iLastEntry)
|
|
return -1;
|
|
|
|
// no pop until the next schedulled time
|
|
ulong ts = Timer.rdtsc();
|
|
if (ts < m_pHeap[0].m_llTimeStamp)
|
|
return -1;
|
|
|
|
UDT u = m_pHeap[0].m_pUDT;
|
|
remove_(u);
|
|
|
|
if (!u.m_bConnected || u.m_bBroken)
|
|
return -1;
|
|
|
|
// pack a packet from the socket
|
|
if (u.packData(pkt, ref ts) <= 0)
|
|
return -1;
|
|
|
|
addr = u.m_pPeerAddr;
|
|
|
|
// insert a new entry, ts is the next processing time
|
|
if (ts > 0)
|
|
insert_(ts, u);
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
public void remove(UDT u)
|
|
{
|
|
lock (m_ListLock)
|
|
{
|
|
remove_(u);
|
|
}
|
|
}
|
|
|
|
public ulong getNextProcTime()
|
|
{
|
|
lock (m_ListLock)
|
|
{
|
|
if (-1 == m_iLastEntry)
|
|
return 0;
|
|
|
|
return m_pHeap[0].m_llTimeStamp;
|
|
}
|
|
}
|
|
|
|
void insert_(ulong ts, UDT u)
|
|
{
|
|
SNode n = u.m_pSNode;
|
|
|
|
// do not insert repeated node
|
|
if (n.m_iHeapLoc >= 0)
|
|
return;
|
|
|
|
m_iLastEntry++;
|
|
m_pHeap[m_iLastEntry] = n;
|
|
n.m_llTimeStamp = ts;
|
|
|
|
int q = m_iLastEntry;
|
|
int p = q;
|
|
while (p != 0)
|
|
{
|
|
p = (q - 1) >> 1;
|
|
if (m_pHeap[p].m_llTimeStamp > m_pHeap[q].m_llTimeStamp)
|
|
{
|
|
SNode t = m_pHeap[p];
|
|
m_pHeap[p] = m_pHeap[q];
|
|
m_pHeap[q] = t;
|
|
t.m_iHeapLoc = q;
|
|
q = p;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
n.m_iHeapLoc = q;
|
|
|
|
// an earlier event has been inserted, wake up sending worker
|
|
if (n.m_iHeapLoc == 0)
|
|
m_pTimer.interrupt();
|
|
|
|
// first entry, activate the sending queue
|
|
if (0 == m_iLastEntry)
|
|
{
|
|
m_pWindowCond.Set();
|
|
}
|
|
}
|
|
|
|
void remove_(UDT u)
|
|
{
|
|
SNode n = u.m_pSNode;
|
|
|
|
if (n.m_iHeapLoc >= 0)
|
|
{
|
|
// remove the node from heap
|
|
m_pHeap[n.m_iHeapLoc] = m_pHeap[m_iLastEntry];
|
|
m_iLastEntry--;
|
|
m_pHeap[n.m_iHeapLoc].m_iHeapLoc = n.m_iHeapLoc;
|
|
|
|
int q = n.m_iHeapLoc;
|
|
int p = q * 2 + 1;
|
|
while (p <= m_iLastEntry)
|
|
{
|
|
if ((p + 1 <= m_iLastEntry) && (m_pHeap[p].m_llTimeStamp > m_pHeap[p + 1].m_llTimeStamp))
|
|
p++;
|
|
|
|
if (m_pHeap[q].m_llTimeStamp > m_pHeap[p].m_llTimeStamp)
|
|
{
|
|
SNode t = m_pHeap[p];
|
|
m_pHeap[p] = m_pHeap[q];
|
|
m_pHeap[p].m_iHeapLoc = p;
|
|
m_pHeap[q] = t;
|
|
m_pHeap[q].m_iHeapLoc = q;
|
|
|
|
q = p;
|
|
p = q * 2 + 1;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
n.m_iHeapLoc = -1;
|
|
}
|
|
|
|
// the only event has been deleted, wake up immediately
|
|
if (0 == m_iLastEntry)
|
|
m_pTimer.interrupt();
|
|
}
|
|
}
|
|
|
|
public class RendezvousQueue
|
|
{
|
|
struct CRL
|
|
{
|
|
internal int m_iID; // UDT socket ID (self)
|
|
internal UDT m_pUDT; // UDT instance
|
|
internal AddressFamily m_iIPversion; // IP version
|
|
internal IPEndPoint m_pPeerAddr; // UDT sonnection peer address
|
|
internal ulong m_ullTTL; // the time that this request expires
|
|
};
|
|
List<CRL> m_lRendezvousID = new List<CRL>(); // The sockets currently in rendezvous mode
|
|
|
|
object m_RIDVectorLock = new object();
|
|
|
|
public void insert(int id, UDT u, AddressFamily ipv, IPEndPoint addr, ulong ttl)
|
|
{
|
|
CRL r;
|
|
r.m_iID = id;
|
|
r.m_pUDT = u;
|
|
r.m_iIPversion = ipv;
|
|
r.m_pPeerAddr = addr;
|
|
r.m_ullTTL = ttl;
|
|
|
|
lock (m_RIDVectorLock)
|
|
{
|
|
m_lRendezvousID.Add(r);
|
|
}
|
|
}
|
|
|
|
public void remove(int id)
|
|
{
|
|
lock (m_RIDVectorLock)
|
|
{
|
|
for (int i = 0; i < m_lRendezvousID.Count; ++i)
|
|
{
|
|
if (m_lRendezvousID[i].m_iID == id)
|
|
{
|
|
m_lRendezvousID.RemoveAt(i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public UDT retrieve(IPEndPoint addr, ref int id)
|
|
{
|
|
lock (m_RIDVectorLock)
|
|
{
|
|
foreach (CRL crl in m_lRendezvousID)
|
|
{
|
|
if (crl.m_pPeerAddr.Equals(addr) && (id == 0) || (id == crl.m_iID))
|
|
{
|
|
id = crl.m_iID;
|
|
return crl.m_pUDT;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void updateConnStatus()
|
|
{
|
|
if (m_lRendezvousID.Count == 0)
|
|
return;
|
|
|
|
lock (m_RIDVectorLock)
|
|
{
|
|
|
|
foreach (CRL crl in m_lRendezvousID)
|
|
{
|
|
// avoid sending too many requests, at most 1 request per 250ms
|
|
if (Timer.getTime() - (ulong)crl.m_pUDT.m_llLastReqTime > 250000)
|
|
{
|
|
//if (Timer.getTime() >= crl.m_ullTTL)
|
|
//{
|
|
// // connection timer expired, acknowledge app via epoll
|
|
// i->m_pUDT->m_bConnecting = false;
|
|
// CUDT::s_UDTUnited.m_EPoll.update_events(i->m_iID, i->m_pUDT->m_sPollID, UDT_EPOLL_ERR, true);
|
|
// continue;
|
|
//}
|
|
|
|
Packet request = new Packet();
|
|
request.pack(crl.m_pUDT.m_ConnReq);
|
|
// ID = 0, connection request
|
|
request.SetId(!crl.m_pUDT.m_bRendezvous ? 0 : crl.m_pUDT.m_ConnRes.m_iID);
|
|
crl.m_pUDT.m_pSndQueue.sendto(crl.m_pPeerAddr, request);
|
|
crl.m_pUDT.m_llLastReqTime = (long)Timer.getTime();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public class SndQueue
|
|
{
|
|
public SndUList m_pSndUList; // List of UDT instances for data sending
|
|
public Channel m_pChannel; // The UDP channel for data sending
|
|
Timer m_pTimer; // Timing facility
|
|
|
|
object m_WindowLock;
|
|
EventWaitHandle m_WindowCond;
|
|
|
|
volatile bool m_bClosing; // closing the worker
|
|
EventWaitHandle m_ExitCond;
|
|
|
|
Thread m_WorkerThread;
|
|
|
|
public SndQueue()
|
|
{
|
|
m_WindowLock = new object();
|
|
m_WindowCond = new EventWaitHandle(false, EventResetMode.AutoReset);
|
|
m_ExitCond = new EventWaitHandle(false, EventResetMode.AutoReset);
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
m_bClosing = true;
|
|
|
|
m_WindowCond.Set();
|
|
if (null != m_WorkerThread)
|
|
m_ExitCond.WaitOne(Timeout.Infinite);
|
|
|
|
m_WindowCond.Close();
|
|
m_ExitCond.Close();
|
|
}
|
|
|
|
public void init(Channel c, Timer t)
|
|
{
|
|
m_pChannel = c;
|
|
m_pTimer = t;
|
|
m_pSndUList = new SndUList();
|
|
m_pSndUList.m_pWindowLock = m_WindowLock;
|
|
m_pSndUList.m_pWindowCond = m_WindowCond;
|
|
m_pSndUList.m_pTimer = m_pTimer;
|
|
|
|
m_WorkerThread = new Thread(worker);
|
|
m_WorkerThread.IsBackground = true;
|
|
m_WorkerThread.Start(this);
|
|
}
|
|
|
|
static void worker(object param)
|
|
{
|
|
SndQueue self = param as SndQueue;
|
|
if (self == null)
|
|
return;
|
|
|
|
while (!self.m_bClosing)
|
|
{
|
|
ulong ts = self.m_pSndUList.getNextProcTime();
|
|
|
|
if (ts > 0)
|
|
{
|
|
// wait until next processing time of the first socket on the list
|
|
ulong currtime = Timer.rdtsc();
|
|
if (currtime < ts)
|
|
self.m_pTimer.sleepto(ts);
|
|
|
|
// it is time to send the next pkt
|
|
IPEndPoint addr = null;
|
|
Packet pkt = new Packet();
|
|
if (self.m_pSndUList.pop(ref addr, ref pkt) < 0)
|
|
continue;
|
|
|
|
self.m_pChannel.sendto(addr, pkt);
|
|
}
|
|
else
|
|
{
|
|
// wait here if there is no sockets with data to be sent
|
|
self.m_WindowCond.WaitOne(Timeout.Infinite);
|
|
}
|
|
}
|
|
|
|
self.m_ExitCond.Set();
|
|
}
|
|
|
|
public int sendto(IPEndPoint addr, Packet packet)
|
|
{
|
|
// send out the packet immediately (high priority), this is a control packet
|
|
m_pChannel.sendto(addr, packet);
|
|
return packet.getLength();
|
|
}
|
|
}
|
|
|
|
public class RcvUList
|
|
{
|
|
public List<RNode> m_nodeList = new List<RNode>();
|
|
|
|
public void insert(UDT u)
|
|
{
|
|
RNode n = u.m_pRNode;
|
|
n.m_llTimeStamp = Timer.rdtsc();
|
|
|
|
// always insert at the end for RcvUList
|
|
m_nodeList.Add(n);
|
|
}
|
|
|
|
public void remove(UDT u)
|
|
{
|
|
RNode n = u.m_pRNode;
|
|
|
|
if (!n.m_bOnList)
|
|
return;
|
|
|
|
m_nodeList.Remove(n);
|
|
}
|
|
|
|
public void update(UDT u)
|
|
{
|
|
RNode n = u.m_pRNode;
|
|
|
|
if (!n.m_bOnList)
|
|
return;
|
|
|
|
RNode match = m_nodeList.Find(x => x.Equals(n));
|
|
if (match.Equals(default(RNode)))
|
|
return;
|
|
|
|
match.m_llTimeStamp = Timer.rdtsc();
|
|
}
|
|
}
|
|
|
|
public class RcvQueue
|
|
{
|
|
RcvUList m_pRcvUList = new RcvUList(); // List of UDT instances that will read packets from the queue
|
|
Channel m_pChannel; // UDP channel for receving packets
|
|
Timer m_pTimer; // shared timer with the snd queue
|
|
|
|
int m_iPayloadSize; // packet payload size
|
|
|
|
volatile bool m_bClosing; // closing the workder
|
|
EventWaitHandle m_ExitCond;
|
|
|
|
object m_LSLock;
|
|
UDT m_pListener; // pointer to the (unique, if any) listening UDT entity
|
|
RendezvousQueue m_pRendezvousQueue = new RendezvousQueue(); // The list of sockets in rendezvous mode
|
|
|
|
List<UDT> m_vNewEntry = new List<UDT>(); // newly added entries, to be inserted
|
|
object m_IDLock;
|
|
|
|
Dictionary<int, Queue<Packet>> m_mBuffer = new Dictionary<int, Queue<Packet>>(); // temporary buffer for rendezvous connection request
|
|
|
|
object m_PassLock;
|
|
EventWaitHandle m_PassCond;
|
|
|
|
Thread m_WorkerThread;
|
|
|
|
Dictionary<int, UDT> m_hash = new Dictionary<int, UDT>();
|
|
|
|
public RcvQueue()
|
|
{
|
|
m_PassLock = new object();
|
|
m_PassCond = new EventWaitHandle(false, EventResetMode.AutoReset);
|
|
m_LSLock = new object();
|
|
m_IDLock = new object();
|
|
m_ExitCond = new EventWaitHandle(false, EventResetMode.AutoReset);
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
m_bClosing = true;
|
|
|
|
if (null != m_WorkerThread)
|
|
m_ExitCond.WaitOne(Timeout.Infinite);
|
|
|
|
m_PassCond.Close();
|
|
m_ExitCond.Close();
|
|
}
|
|
|
|
public void init(int qsize, int payload, AddressFamily version, int hsize, Channel cc, Timer t)
|
|
{
|
|
m_iPayloadSize = payload;
|
|
|
|
m_pChannel = cc;
|
|
m_pTimer = t;
|
|
|
|
m_WorkerThread = new Thread(worker);
|
|
m_WorkerThread.IsBackground = true;
|
|
m_WorkerThread.Start(this);
|
|
}
|
|
|
|
static void worker(object param)
|
|
{
|
|
RcvQueue self = param as RcvQueue;
|
|
if (self == null)
|
|
return;
|
|
|
|
IPEndPoint addr = new IPEndPoint(IPAddress.Any, 0);
|
|
UDT u = null;
|
|
int id;
|
|
|
|
while (!self.m_bClosing)
|
|
{
|
|
self.m_pTimer.tick();
|
|
|
|
// check waiting list, if new socket, insert it to the list
|
|
while (self.ifNewEntry())
|
|
{
|
|
UDT ne = self.getNewEntry();
|
|
if (null != ne)
|
|
{
|
|
self.m_pRcvUList.insert(ne);
|
|
self.m_hash.Add(ne.m_SocketID, ne);
|
|
}
|
|
}
|
|
|
|
// find next available slot for incoming packet
|
|
Unit unit = new Unit();
|
|
unit.m_Packet.setLength(self.m_iPayloadSize);
|
|
|
|
// reading next incoming packet, recvfrom returns -1 is nothing has been received
|
|
if (self.m_pChannel.recvfrom(ref addr, unit.m_Packet) < 0)
|
|
goto TIMER_CHECK;
|
|
|
|
id = unit.m_Packet.GetId();
|
|
|
|
// ID 0 is for connection request, which should be passed to the listening socket or rendezvous sockets
|
|
if (0 == id)
|
|
{
|
|
if (null != self.m_pListener)
|
|
self.m_pListener.listen(addr, unit.m_Packet);
|
|
else if (null != (u = self.m_pRendezvousQueue.retrieve(addr, ref id)))
|
|
{
|
|
// asynchronous connect: call connect here
|
|
// otherwise wait for the UDT socket to retrieve this packet
|
|
if (!u.m_bSynRecving)
|
|
u.connect(unit.m_Packet);
|
|
else
|
|
{
|
|
Packet newPacket = new Packet();
|
|
newPacket.Clone(unit.m_Packet);
|
|
self.storePkt(id, newPacket);
|
|
}
|
|
}
|
|
}
|
|
else if (id > 0)
|
|
{
|
|
if (self.m_hash.TryGetValue(id, out u))
|
|
{
|
|
if (addr.Equals(u.m_pPeerAddr))
|
|
{
|
|
if (u.m_bConnected && !u.m_bBroken && !u.m_bClosing)
|
|
{
|
|
if (0 == unit.m_Packet.getFlag())
|
|
u.processData(unit);
|
|
else
|
|
u.processCtrl(unit.m_Packet);
|
|
|
|
u.checkTimers();
|
|
self.m_pRcvUList.update(u);
|
|
}
|
|
}
|
|
}
|
|
else if (null != (u = self.m_pRendezvousQueue.retrieve(addr, ref id)))
|
|
{
|
|
if (!u.m_bSynRecving)
|
|
u.connect(unit.m_Packet);
|
|
else
|
|
{
|
|
Packet newPacket = new Packet();
|
|
newPacket.Clone(unit.m_Packet);
|
|
self.storePkt(id, newPacket);
|
|
}
|
|
}
|
|
}
|
|
|
|
TIMER_CHECK:
|
|
// take care of the timing event for all UDT sockets
|
|
|
|
ulong currtime = Timer.rdtsc();
|
|
|
|
ulong ctime = currtime - 100000 * Timer.getCPUFrequency();
|
|
for (int i = 0; i < self.m_pRcvUList.m_nodeList.Count; ++i)
|
|
{
|
|
RNode ul = self.m_pRcvUList.m_nodeList[0];
|
|
if (ul.m_llTimeStamp >= ctime)
|
|
break;
|
|
|
|
u = ul.m_pUDT;
|
|
|
|
if (u.m_bConnected && !u.m_bBroken && !u.m_bClosing)
|
|
{
|
|
u.checkTimers();
|
|
self.m_pRcvUList.update(u);
|
|
}
|
|
else
|
|
{
|
|
// the socket must be removed from Hash table first, then RcvUList
|
|
self.m_hash.Remove(u.m_SocketID);
|
|
self.m_pRcvUList.remove(u);
|
|
u.m_pRNode.m_bOnList = false;
|
|
}
|
|
}
|
|
|
|
// Check connection requests status for all sockets in the RendezvousQueue.
|
|
self.m_pRendezvousQueue.updateConnStatus();
|
|
}
|
|
|
|
|
|
self.m_ExitCond.Set();
|
|
}
|
|
|
|
public int recvfrom(int id, Packet packet)
|
|
{
|
|
bool gotLock = false;
|
|
Monitor.Enter(m_PassLock, ref gotLock);
|
|
|
|
Queue<Packet> packetQueue;
|
|
if (!m_mBuffer.TryGetValue(id, out packetQueue))
|
|
{
|
|
if (gotLock)
|
|
Monitor.Exit(m_PassLock);
|
|
m_PassCond.WaitOne(1000);
|
|
|
|
lock (m_PassLock)
|
|
{
|
|
|
|
if (!m_mBuffer.TryGetValue(id, out packetQueue))
|
|
{
|
|
packet.setLength(-1);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (gotLock && Monitor.IsEntered(m_PassLock))
|
|
Monitor.Exit(m_PassLock);
|
|
|
|
// retrieve the earliest packet
|
|
Packet newpkt = packetQueue.Peek();
|
|
|
|
if (packet.getLength() < newpkt.getLength())
|
|
{
|
|
packet.setLength(-1);
|
|
return -1;
|
|
}
|
|
|
|
// copy packet content
|
|
|
|
packet.Clone(newpkt);
|
|
|
|
packetQueue.Dequeue();
|
|
if (packetQueue.Count == 0)
|
|
{
|
|
lock (m_PassLock)
|
|
{
|
|
m_mBuffer.Remove(id);
|
|
}
|
|
}
|
|
|
|
return packet.getLength();
|
|
}
|
|
|
|
public int setListener(UDT u)
|
|
{
|
|
lock (m_LSLock)
|
|
{
|
|
|
|
if (null != m_pListener)
|
|
return -1;
|
|
|
|
m_pListener = u;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public void removeListener(UDT u)
|
|
{
|
|
lock (m_LSLock)
|
|
{
|
|
if (u == m_pListener)
|
|
m_pListener = null;
|
|
}
|
|
}
|
|
|
|
public void registerConnector(int id, UDT u, AddressFamily ipv, IPEndPoint addr, ulong ttl)
|
|
{
|
|
m_pRendezvousQueue.insert(id, u, ipv, addr, ttl);
|
|
}
|
|
|
|
public void removeConnector(int id)
|
|
{
|
|
m_pRendezvousQueue.remove(id);
|
|
lock (m_PassLock)
|
|
{
|
|
m_mBuffer.Remove(id);
|
|
}
|
|
}
|
|
|
|
public void setNewEntry(UDT u)
|
|
{
|
|
lock (m_IDLock)
|
|
{
|
|
m_vNewEntry.Add(u);
|
|
}
|
|
}
|
|
|
|
bool ifNewEntry()
|
|
{
|
|
return !(m_vNewEntry.Count == 0);
|
|
}
|
|
|
|
UDT getNewEntry()
|
|
{
|
|
lock (m_IDLock)
|
|
{
|
|
if (m_vNewEntry.Count == 0)
|
|
return null;
|
|
|
|
UDT u = m_vNewEntry[0];
|
|
m_vNewEntry.RemoveAt(0);
|
|
return u;
|
|
}
|
|
}
|
|
|
|
void storePkt(int id, Packet pkt)
|
|
{
|
|
lock (m_PassLock)
|
|
{
|
|
Queue<Packet> packetQueue;
|
|
if (!m_mBuffer.TryGetValue(id, out packetQueue))
|
|
{
|
|
packetQueue = new Queue<Packet>();
|
|
packetQueue.Enqueue(pkt);
|
|
m_mBuffer.Add(id, packetQueue);
|
|
|
|
m_PassCond.Set();
|
|
}
|
|
else
|
|
{
|
|
//avoid storing too many packets, in case of malfunction or attack
|
|
if (packetQueue.Count > 16)
|
|
return;
|
|
|
|
packetQueue.Enqueue(pkt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|