hawkeye camera support(not tested)
This commit is contained in:
960
framework/Inspectron.HawkEye/UDT/UdtUnited.cs
Normal file
960
framework/Inspectron.HawkEye/UDT/UdtUnited.cs
Normal file
@@ -0,0 +1,960 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
using UDTSOCKET = System.Int32;
|
||||
|
||||
namespace UdtSharp
|
||||
{
|
||||
class Multiplexer
|
||||
{
|
||||
internal SndQueue m_pSndQueue; // The sending queue
|
||||
internal RcvQueue m_pRcvQueue; // The receiving queue
|
||||
internal Channel m_pChannel; // The UDP channel for sending and receiving
|
||||
internal Timer m_pTimer; // The timer
|
||||
|
||||
internal int m_iPort; // The UDP port number of this multiplexer
|
||||
internal AddressFamily m_iIPversion; // IP version
|
||||
internal int m_iMSS; // Maximum Segment Size
|
||||
internal int m_iRefCount; // number of UDT instances that are associated with this multiplexer
|
||||
internal bool m_bReusable; // if this one can be shared with others
|
||||
|
||||
internal int m_iID; // multiplexer ID
|
||||
}
|
||||
|
||||
internal class UdtSocketInternal
|
||||
{
|
||||
public UDTSTATUS m_Status; // current socket state
|
||||
|
||||
public ulong m_TimeStamp; // time when the socket is closed
|
||||
|
||||
public AddressFamily m_iIPversion; // IP version
|
||||
public IPEndPoint m_pSelfAddr; // pointer to the local address of the socket
|
||||
public IPEndPoint m_pPeerAddr; // pointer to the peer address of the socket
|
||||
|
||||
public UDTSOCKET m_SocketID; // socket ID
|
||||
public UDTSOCKET m_ListenSocket; // ID of the listener socket; 0 means this is an independent socket
|
||||
|
||||
public UDTSOCKET m_PeerID; // peer socket ID
|
||||
public int m_iISN; // initial sequence number, used to tell different connection from same IP:port
|
||||
|
||||
public UDT m_pUDT; // pointer to the UDT entity
|
||||
|
||||
public HashSet<UDTSOCKET> m_pQueuedSockets; // set of connections waiting for accept()
|
||||
public HashSet<UDTSOCKET> m_pAcceptSockets; // set of accept()ed connections
|
||||
|
||||
public EventWaitHandle m_AcceptCond = new EventWaitHandle(false, EventResetMode.AutoReset);// used to block "accept" call
|
||||
public object m_AcceptLock = new object(); // mutex associated to m_AcceptCond
|
||||
|
||||
public uint m_uiBackLog; // maximum number of connections in queue
|
||||
|
||||
public int m_iMuxID; // multiplexer ID
|
||||
|
||||
public object m_ControlLock = new object(); // lock this socket exclusively for control APIs: bind/listen/connect
|
||||
|
||||
public UdtSocketInternal()
|
||||
{
|
||||
m_Status = UDTSTATUS.INIT;
|
||||
m_iMuxID = -1;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
m_AcceptCond.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public class UdtUnited
|
||||
{
|
||||
Dictionary<UDTSOCKET, UdtSocketInternal> m_Sockets = new Dictionary<UDTSOCKET, UdtSocketInternal>(); // stores all the socket structures
|
||||
|
||||
object m_ControlLock = new object(); // used to synchronize UDT API
|
||||
|
||||
object m_IDLock = new object(); // used to synchronize ID generation
|
||||
UDTSOCKET m_SocketID; // seed to generate a new unique socket ID
|
||||
|
||||
Dictionary<long, HashSet<UDTSOCKET>> m_PeerRec = new Dictionary<long, HashSet<UDTSOCKET>>();// record sockets from peers to avoid repeated connection request, int64_t = (socker_id << 30) + isn
|
||||
|
||||
//pthread_key_t m_TLSError; // thread local error record (last error)
|
||||
Dictionary<uint, UdtException> m_mTLSRecord;
|
||||
object m_TLSLock = new object();
|
||||
|
||||
Dictionary<int, Multiplexer> m_mMultiplexer = new Dictionary<UDTSOCKET, Multiplexer>(); // UDP multiplexer
|
||||
object m_MultiplexerLock = new object();
|
||||
|
||||
HashSet<InfoBlock> m_pCache = new HashSet<InfoBlock>(); // UDT network information cache
|
||||
|
||||
volatile bool m_bClosing;
|
||||
object m_GCStopLock = new object();
|
||||
EventWaitHandle m_GCStopCond = new EventWaitHandle(false, EventResetMode.AutoReset);
|
||||
|
||||
object m_InitLock = new object();
|
||||
int m_iInstanceCount; // number of startup() called by application
|
||||
|
||||
Dictionary<UDTSOCKET, UdtSocketInternal> m_ClosedSockets = new Dictionary<UDTSOCKET, UdtSocketInternal>(); // temporarily store closed sockets
|
||||
|
||||
static Random m_random = new Random();
|
||||
|
||||
public UdtUnited()
|
||||
{
|
||||
// Socket ID MUST start from a random value
|
||||
m_SocketID = 1 + (int)((1 << 30) * m_random.NextDouble());
|
||||
|
||||
//m_TLSError = TlsAlloc();
|
||||
}
|
||||
|
||||
~UdtUnited()
|
||||
{
|
||||
//TlsFree(m_TLSError);
|
||||
}
|
||||
|
||||
public int startup()
|
||||
{
|
||||
lock (m_InitLock)
|
||||
{
|
||||
++m_iInstanceCount;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int cleanup()
|
||||
{
|
||||
lock (m_InitLock)
|
||||
{
|
||||
if (--m_iInstanceCount > 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_bClosing = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public UDTSOCKET newSocket(AddressFamily af, SocketType type)
|
||||
{
|
||||
if ((type != SocketType.Stream) && (type != SocketType.Dgram))
|
||||
throw new UdtException(5, 3, 0);
|
||||
|
||||
UdtSocketInternal ns = new UdtSocketInternal();
|
||||
ns.m_pUDT = new UDT();
|
||||
ns.m_pSelfAddr = new IPEndPoint(IPAddress.Any, 0);
|
||||
|
||||
lock (m_IDLock)
|
||||
{
|
||||
ns.m_SocketID = --m_SocketID;
|
||||
}
|
||||
|
||||
ns.m_Status = UDTSTATUS.INIT;
|
||||
ns.m_ListenSocket = 0;
|
||||
ns.m_pUDT.m_SocketID = ns.m_SocketID;
|
||||
ns.m_pUDT.m_iSockType = type;
|
||||
ns.m_pUDT.m_iIPversion = af;
|
||||
ns.m_pUDT.m_pCache = m_pCache;
|
||||
|
||||
// protect the m_Sockets structure.
|
||||
lock (m_ControlLock)
|
||||
{
|
||||
m_Sockets[ns.m_SocketID] = ns;
|
||||
}
|
||||
|
||||
return ns.m_SocketID;
|
||||
}
|
||||
|
||||
public int newConnection(UDTSOCKET listen, IPEndPoint peer, Handshake hs)
|
||||
{
|
||||
UdtSocketInternal ns = null;
|
||||
UdtSocketInternal ls = locate(listen);
|
||||
|
||||
if (null == ls)
|
||||
return -1;
|
||||
|
||||
// if this connection has already been processed
|
||||
if (null != (ns = locate(peer, hs.m_iID, hs.m_iISN)))
|
||||
{
|
||||
if (ns.m_pUDT.m_bBroken)
|
||||
{
|
||||
// last connection from the "peer" address has been broken
|
||||
ns.m_Status = UDTSTATUS.CLOSED;
|
||||
ns.m_TimeStamp = Timer.getTime();
|
||||
|
||||
lock (ls.m_AcceptLock)
|
||||
{
|
||||
ls.m_pQueuedSockets.Remove(ns.m_SocketID);
|
||||
ls.m_pAcceptSockets.Remove(ns.m_SocketID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// connection already exist, this is a repeated connection request
|
||||
// respond with existing HS information
|
||||
|
||||
hs.m_iISN = ns.m_pUDT.m_iISN;
|
||||
hs.m_iMSS = ns.m_pUDT.m_iMSS;
|
||||
hs.m_iFlightFlagSize = ns.m_pUDT.m_iFlightFlagSize;
|
||||
hs.m_iReqType = -1;
|
||||
hs.m_iID = ns.m_SocketID;
|
||||
|
||||
return 0;
|
||||
|
||||
//except for this situation a new connection should be started
|
||||
}
|
||||
}
|
||||
|
||||
// exceeding backlog, refuse the connection request
|
||||
if (ls.m_pQueuedSockets.Count >= ls.m_uiBackLog)
|
||||
return -1;
|
||||
|
||||
ns = new UdtSocketInternal();
|
||||
ns.m_pUDT = new UDT(ls.m_pUDT);
|
||||
ns.m_pSelfAddr = new IPEndPoint(IPAddress.Any, 0);
|
||||
ns.m_pPeerAddr = peer;
|
||||
|
||||
lock (m_IDLock)
|
||||
{
|
||||
ns.m_SocketID = --m_SocketID;
|
||||
}
|
||||
|
||||
ns.m_ListenSocket = listen;
|
||||
ns.m_iIPversion = ls.m_iIPversion;
|
||||
ns.m_pUDT.m_SocketID = ns.m_SocketID;
|
||||
ns.m_PeerID = hs.m_iID;
|
||||
ns.m_iISN = hs.m_iISN;
|
||||
|
||||
int error = 0;
|
||||
|
||||
try
|
||||
{
|
||||
// bind to the same addr of listening socket
|
||||
ns.m_pUDT.open();
|
||||
updateMux(ns, ls);
|
||||
ns.m_pUDT.connect(peer, hs);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
error = 1;
|
||||
goto ERR_ROLLBACK;
|
||||
}
|
||||
|
||||
ns.m_Status = UDTSTATUS.CONNECTED;
|
||||
|
||||
// copy address information of local node
|
||||
ns.m_pUDT.m_pSndQueue.m_pChannel.getSockAddr(ref ns.m_pSelfAddr);
|
||||
ConvertIPAddress.ToUintArray(ns.m_pSelfAddr.Address, ref ns.m_pUDT.m_piSelfIP);
|
||||
|
||||
// protect the m_Sockets structure.
|
||||
lock (m_ControlLock)
|
||||
{
|
||||
m_Sockets[ns.m_SocketID] = ns;
|
||||
HashSet<int> sockets;
|
||||
if (!m_PeerRec.TryGetValue((ns.m_PeerID << 30) + ns.m_iISN, out sockets))
|
||||
{
|
||||
sockets = new HashSet<int>();
|
||||
m_PeerRec.Add((ns.m_PeerID << 30) + ns.m_iISN, sockets);
|
||||
}
|
||||
|
||||
sockets.Add(ns.m_SocketID);
|
||||
}
|
||||
|
||||
lock (ls.m_AcceptLock)
|
||||
{
|
||||
ls.m_pQueuedSockets.Add(ns.m_SocketID);
|
||||
}
|
||||
|
||||
// acknowledge users waiting for new connections on the listening socket
|
||||
//m_EPoll.update_events(listen, ls.m_pUDT.m_sPollID, UDT_EPOLL_IN, true);
|
||||
|
||||
Timer.triggerEvent();
|
||||
|
||||
ERR_ROLLBACK:
|
||||
if (error > 0)
|
||||
{
|
||||
ns.m_pUDT.close();
|
||||
ns.m_Status = UDTSTATUS.CLOSED;
|
||||
ns.m_TimeStamp = Timer.getTime();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// wake up a waiting accept() call
|
||||
ls.m_AcceptCond.Set();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public UDT lookup(UDTSOCKET u)
|
||||
{
|
||||
// protects the m_Sockets structure
|
||||
lock (m_ControlLock)
|
||||
{
|
||||
UdtSocketInternal socket;
|
||||
if (!m_Sockets.TryGetValue(u, out socket) || socket.m_Status == UDTSTATUS.CLOSED)
|
||||
throw new UdtException(5, 4, 0);
|
||||
|
||||
return socket.m_pUDT;
|
||||
}
|
||||
}
|
||||
|
||||
public UDTSTATUS getStatus(UDTSOCKET u)
|
||||
{
|
||||
// protects the m_Sockets structure
|
||||
lock (m_ControlLock)
|
||||
{
|
||||
UdtSocketInternal socket;
|
||||
if (m_Sockets.TryGetValue(u, out socket))
|
||||
{
|
||||
if (socket.m_pUDT.m_bBroken)
|
||||
return UDTSTATUS.BROKEN;
|
||||
|
||||
return socket.m_Status;
|
||||
}
|
||||
|
||||
if (m_ClosedSockets.ContainsKey(u))
|
||||
return UDTSTATUS.CLOSED;
|
||||
|
||||
return UDTSTATUS.NONEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
public int bind(UDTSOCKET u, IPEndPoint name)
|
||||
{
|
||||
UdtSocketInternal s = locate(u);
|
||||
if (null == s)
|
||||
throw new UdtException(5, 4, 0);
|
||||
|
||||
lock (s.m_ControlLock)
|
||||
{
|
||||
// cannot bind a socket more than once
|
||||
if (UDTSTATUS.INIT != s.m_Status)
|
||||
throw new UdtException(5, 0, 0);
|
||||
|
||||
s.m_pUDT.open();
|
||||
updateMux(s, name);
|
||||
s.m_Status = UDTSTATUS.OPENED;
|
||||
|
||||
// copy address information of local node
|
||||
s.m_pUDT.m_pSndQueue.m_pChannel.getSockAddr(ref s.m_pSelfAddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int bind(UDTSOCKET u, Socket udpsock)
|
||||
{
|
||||
UdtSocketInternal s = locate(u);
|
||||
if (null == s)
|
||||
throw new UdtException(5, 4, 0);
|
||||
|
||||
lock (s.m_ControlLock)
|
||||
{
|
||||
|
||||
// cannot bind a socket more than once
|
||||
if (UDTSTATUS.INIT != s.m_Status)
|
||||
throw new UdtException(5, 0, 0);
|
||||
|
||||
IPEndPoint name = null;
|
||||
s.m_pUDT.m_pSndQueue.m_pChannel.getSockAddr(ref name); //TODO CHECK THIS
|
||||
|
||||
s.m_pUDT.open();
|
||||
updateMux(s, name, udpsock);
|
||||
s.m_Status = UDTSTATUS.OPENED;
|
||||
|
||||
// copy address information of local node
|
||||
s.m_pUDT.m_pSndQueue.m_pChannel.getSockAddr(ref s.m_pSelfAddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int listen(UDTSOCKET u, int backlog)
|
||||
{
|
||||
UdtSocketInternal s = locate(u);
|
||||
if (null == s)
|
||||
throw new UdtException(5, 4, 0);
|
||||
|
||||
lock (s.m_ControlLock)
|
||||
{
|
||||
|
||||
// do nothing if the socket is already listening
|
||||
if (UDTSTATUS.LISTENING == s.m_Status)
|
||||
return 0;
|
||||
|
||||
// a socket can listen only if is in UDTSTATUS.OPENED status
|
||||
if (UDTSTATUS.OPENED != s.m_Status)
|
||||
throw new UdtException(5, 5, 0);
|
||||
|
||||
// listen is not supported in rendezvous connection setup
|
||||
if (s.m_pUDT.m_bRendezvous)
|
||||
throw new UdtException(5, 7, 0);
|
||||
|
||||
if (backlog <= 0)
|
||||
throw new UdtException(5, 3, 0);
|
||||
|
||||
s.m_uiBackLog = (uint)backlog;
|
||||
|
||||
s.m_pQueuedSockets = new HashSet<UDTSOCKET>();
|
||||
s.m_pAcceptSockets = new HashSet<UDTSOCKET>();
|
||||
|
||||
s.m_pUDT.listen();
|
||||
|
||||
s.m_Status = UDTSTATUS.LISTENING;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public UDTSOCKET accept(UDTSOCKET listen, ref IPEndPoint addr)
|
||||
{
|
||||
if (null != addr)
|
||||
throw new UdtException(5, 3, 0);
|
||||
|
||||
UdtSocketInternal ls = locate(listen);
|
||||
|
||||
if (ls == null)
|
||||
throw new UdtException(5, 4, 0);
|
||||
|
||||
// the "listen" socket must be in UDTSTATUS.LISTENING status
|
||||
if (UDTSTATUS.LISTENING != ls.m_Status)
|
||||
throw new UdtException(5, 6, 0);
|
||||
|
||||
// no "accept" in rendezvous connection setup
|
||||
if (ls.m_pUDT.m_bRendezvous)
|
||||
throw new UdtException(5, 7, 0);
|
||||
|
||||
UDTSOCKET u = UDT.INVALID_SOCK;
|
||||
bool accepted = false;
|
||||
|
||||
// !!only one conection can be set up each time!!
|
||||
while (!accepted)
|
||||
{
|
||||
lock (ls.m_AcceptLock)
|
||||
{
|
||||
if (ls.m_pQueuedSockets.Count > 0)
|
||||
{
|
||||
HashSet<UDTSOCKET>.Enumerator e = ls.m_pQueuedSockets.GetEnumerator();
|
||||
e.MoveNext();
|
||||
u = e.Current;
|
||||
ls.m_pAcceptSockets.Add(u);
|
||||
ls.m_pQueuedSockets.Remove(u);
|
||||
|
||||
accepted = true;
|
||||
}
|
||||
else if (!ls.m_pUDT.m_bSynRecving)
|
||||
accepted = true;
|
||||
}
|
||||
|
||||
if (!accepted & (UDTSTATUS.LISTENING == ls.m_Status))
|
||||
ls.m_AcceptCond.WaitOne(Timeout.Infinite);
|
||||
|
||||
if ((UDTSTATUS.LISTENING != ls.m_Status) || ls.m_pUDT.m_bBroken)
|
||||
{
|
||||
// Send signal to other threads that are waiting to accept.
|
||||
ls.m_AcceptCond.Set();
|
||||
accepted = true;
|
||||
}
|
||||
|
||||
//if (ls.m_pQueuedSockets.Count == 0)
|
||||
// m_EPoll.update_events(listen, ls.m_pUDT.m_sPollID, UDT_EPOLL_IN, false);
|
||||
}
|
||||
|
||||
if (u == UDT.INVALID_SOCK)
|
||||
{
|
||||
// non-blocking receiving, no connection available
|
||||
if (!ls.m_pUDT.m_bSynRecving)
|
||||
throw new UdtException(6, 2, 0);
|
||||
|
||||
// listening socket is closed
|
||||
throw new UdtException(5, 6, 0);
|
||||
}
|
||||
|
||||
addr = locate(u).m_pPeerAddr;
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
public int connect(UDTSOCKET u, IPEndPoint name)
|
||||
{
|
||||
UdtSocketInternal s = locate(u);
|
||||
if (null == s)
|
||||
throw new UdtException(5, 4, 0);
|
||||
|
||||
lock (s.m_ControlLock)
|
||||
{
|
||||
// a socket can "connect" only if it is in INIT or UDTSTATUS.OPENED status
|
||||
if (UDTSTATUS.INIT == s.m_Status)
|
||||
{
|
||||
if (!s.m_pUDT.m_bRendezvous)
|
||||
{
|
||||
s.m_pUDT.open();
|
||||
updateMux(s);
|
||||
s.m_Status = UDTSTATUS.OPENED;
|
||||
}
|
||||
else
|
||||
throw new UdtException(5, 8, 0);
|
||||
}
|
||||
else if (UDTSTATUS.OPENED != s.m_Status)
|
||||
throw new UdtException(5, 2, 0);
|
||||
|
||||
// connect_complete() may be called before connect() returns.
|
||||
// So we need to update the status before connect() is called,
|
||||
// otherwise the status may be overwritten with wrong value (CONNECTED vs. CONNECTING).
|
||||
s.m_Status = UDTSTATUS.CONNECTING;
|
||||
try
|
||||
{
|
||||
s.m_pUDT.connect(name);
|
||||
}
|
||||
catch (UdtException e)
|
||||
{
|
||||
s.m_Status = UDTSTATUS.OPENED;
|
||||
throw e;
|
||||
}
|
||||
|
||||
// record peer address
|
||||
s.m_pPeerAddr = name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void connect_complete(UDTSOCKET u)
|
||||
{
|
||||
UdtSocketInternal s = locate(u);
|
||||
if (null == s)
|
||||
throw new UdtException(5, 4, 0);
|
||||
|
||||
// copy address information of local node
|
||||
// the local port must be correctly assigned BEFORE CUDT.connect(),
|
||||
// otherwise if connect() fails, the multiplexer cannot be located by garbage collection and will cause leak
|
||||
s.m_pUDT.m_pSndQueue.m_pChannel.getSockAddr(ref s.m_pSelfAddr);
|
||||
ConvertIPAddress.ToUintArray(s.m_pSelfAddr.Address, ref s.m_pUDT.m_piSelfIP);
|
||||
|
||||
s.m_Status = UDTSTATUS.CONNECTED;
|
||||
}
|
||||
|
||||
public int close(UDTSOCKET u)
|
||||
{
|
||||
UdtSocketInternal s = locate(u);
|
||||
if (null == s)
|
||||
throw new UdtException(5, 4, 0);
|
||||
|
||||
lock (s.m_ControlLock)
|
||||
{
|
||||
|
||||
if (s.m_Status == UDTSTATUS.LISTENING)
|
||||
{
|
||||
if (s.m_pUDT.m_bBroken)
|
||||
return 0;
|
||||
|
||||
s.m_TimeStamp = Timer.getTime();
|
||||
s.m_pUDT.m_bBroken = true;
|
||||
|
||||
// broadcast all "accept" waiting
|
||||
s.m_AcceptCond.Set();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
s.m_pUDT.close();
|
||||
|
||||
// synchronize with garbage collection.
|
||||
lock (m_ControlLock)
|
||||
{
|
||||
|
||||
// since "s" is located before m_ControlLock, locate it again in case it became invalid
|
||||
if (!m_Sockets.TryGetValue(u, out s) || s.m_Status == UDTSTATUS.CLOSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
s.m_Status = UDTSTATUS.CLOSED;
|
||||
|
||||
// a socket will not be immediated removed when it is closed
|
||||
// in order to prevent other methods from accessing invalid address
|
||||
// a timer is started and the socket will be removed after approximately 1 second
|
||||
s.m_TimeStamp = Timer.getTime();
|
||||
|
||||
m_Sockets.Remove(s.m_SocketID);
|
||||
m_ClosedSockets.Add(s.m_SocketID, s);
|
||||
|
||||
Timer.triggerEvent();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// int CUDTUnited.getpeername(const UDTSOCKET u, sockaddr*name, int* namelen)
|
||||
//{
|
||||
// if (CONNECTED != getStatus(u))
|
||||
// throw new UdtException(2, 2, 0);
|
||||
|
||||
// UdtSocket* s = locate(u);
|
||||
|
||||
// if (null == s)
|
||||
// throw new UdtException(5, 4, 0);
|
||||
|
||||
// if (!s.m_pUDT.m_bConnected || s.m_pUDT.m_bBroken)
|
||||
// throw new UdtException(2, 2, 0);
|
||||
|
||||
// if (AF_INET == s.m_iIPversion)
|
||||
// *namelen = sizeof(sockaddr_in);
|
||||
// else
|
||||
// *namelen = sizeof(sockaddr_in6);
|
||||
|
||||
// // copy address information of peer node
|
||||
// memcpy(name, s.m_pPeerAddr, *namelen);
|
||||
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// int CUDTUnited.getsockname(const UDTSOCKET u, sockaddr*name, int* namelen)
|
||||
//{
|
||||
// UdtSocket* s = locate(u);
|
||||
|
||||
// if (null == s)
|
||||
// throw new UdtException(5, 4, 0);
|
||||
|
||||
// if (s.m_pUDT.m_bBroken)
|
||||
// throw new UdtException(5, 4, 0);
|
||||
|
||||
// if (INIT == s.m_Status)
|
||||
// throw new UdtException(2, 2, 0);
|
||||
|
||||
// if (AF_INET == s.m_iIPversion)
|
||||
// *namelen = sizeof(sockaddr_in);
|
||||
// else
|
||||
// *namelen = sizeof(sockaddr_in6);
|
||||
|
||||
// // copy address information of local node
|
||||
// memcpy(name, s.m_pSelfAddr, *namelen);
|
||||
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
internal UdtSocketInternal locate(UDTSOCKET u)
|
||||
{
|
||||
lock (m_ControlLock)
|
||||
{
|
||||
UdtSocketInternal s;
|
||||
if (!m_Sockets.TryGetValue(u, out s) || s.m_Status == UDTSTATUS.CLOSED)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
UdtSocketInternal locate(IPEndPoint peer, UDTSOCKET id, int isn)
|
||||
{
|
||||
lock (m_ControlLock)
|
||||
{
|
||||
HashSet<int> sockets;
|
||||
if (!m_PeerRec.TryGetValue((id << 30) + isn, out sockets))
|
||||
return null;
|
||||
|
||||
foreach (int iSocket in sockets)
|
||||
{
|
||||
UdtSocketInternal socket;
|
||||
if (!m_Sockets.TryGetValue(iSocket, out socket))
|
||||
continue;
|
||||
|
||||
if (socket.m_pPeerAddr.Equals(peer))
|
||||
return socket;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void checkBrokenSockets()
|
||||
{
|
||||
lock (m_ControlLock)
|
||||
{
|
||||
checkBrokenSockets_unsafe();
|
||||
}
|
||||
}
|
||||
|
||||
void checkBrokenSockets_unsafe()
|
||||
{
|
||||
// set of sockets To Be Closed and To Be Removed
|
||||
List<UDTSOCKET> tbc = new List<UDTSOCKET>();
|
||||
List<UDTSOCKET> tbr = new List<UDTSOCKET>();
|
||||
|
||||
foreach (KeyValuePair<UDTSOCKET, UdtSocketInternal> item in m_Sockets)
|
||||
{
|
||||
// check broken connection
|
||||
if (item.Value.m_pUDT.m_bBroken)
|
||||
{
|
||||
if (item.Value.m_Status == UDTSTATUS.LISTENING)
|
||||
{
|
||||
// for a listening socket, it should wait an extra 3 seconds in case a client is connecting
|
||||
if (Timer.getTime() - item.Value.m_TimeStamp < 3000000)
|
||||
continue;
|
||||
}
|
||||
else if ((item.Value.m_pUDT.m_pRcvBuffer != null) && (item.Value.m_pUDT.m_pRcvBuffer.getRcvDataSize() > 0) && (item.Value.m_pUDT.m_iBrokenCounter-- > 0))
|
||||
{
|
||||
// if there is still data in the receiver buffer, wait longer
|
||||
continue;
|
||||
}
|
||||
|
||||
//close broken connections and start removal timer
|
||||
item.Value.m_Status = UDTSTATUS.CLOSED;
|
||||
item.Value.m_TimeStamp = Timer.getTime();
|
||||
tbc.Add(item.Key);
|
||||
m_ClosedSockets[item.Key] = item.Value;
|
||||
|
||||
// remove from listener's queue
|
||||
UdtSocketInternal listenSocket;
|
||||
if (!m_Sockets.TryGetValue(item.Value.m_ListenSocket, out listenSocket))
|
||||
{
|
||||
if (!m_ClosedSockets.TryGetValue(item.Value.m_ListenSocket, out listenSocket))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Monitor.Enter(listenSocket.m_AcceptLock);
|
||||
listenSocket.m_pQueuedSockets.Remove(item.Value.m_SocketID);
|
||||
listenSocket.m_pAcceptSockets.Remove(item.Value.m_SocketID);
|
||||
Monitor.Exit(listenSocket.m_AcceptLock);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<UDTSOCKET, UdtSocketInternal> j in m_ClosedSockets)
|
||||
{
|
||||
if (j.Value.m_pUDT.m_ullLingerExpiration > 0)
|
||||
{
|
||||
// asynchronous close:
|
||||
if ((null == j.Value.m_pUDT.m_pSndBuffer) || (0 == j.Value.m_pUDT.m_pSndBuffer.getCurrBufSize()) || (j.Value.m_pUDT.m_ullLingerExpiration <= Timer.getTime()))
|
||||
{
|
||||
j.Value.m_pUDT.m_ullLingerExpiration = 0;
|
||||
j.Value.m_pUDT.m_bClosing = true;
|
||||
j.Value.m_TimeStamp = Timer.getTime();
|
||||
}
|
||||
}
|
||||
|
||||
// timeout 1 second to destroy a socket AND it has been removed from RcvUList
|
||||
if ((Timer.getTime() - j.Value.m_TimeStamp > 1000000) && ((null == j.Value.m_pUDT.m_pRNode) || !j.Value.m_pUDT.m_pRNode.m_bOnList))
|
||||
{
|
||||
tbr.Add(j.Key);
|
||||
}
|
||||
}
|
||||
|
||||
// move closed sockets to the ClosedSockets structure
|
||||
foreach (UDTSOCKET k in tbc)
|
||||
m_Sockets.Remove(k);
|
||||
|
||||
// remove those timeout sockets
|
||||
foreach (UDTSOCKET l in tbr)
|
||||
removeSocket(l);
|
||||
}
|
||||
|
||||
void removeSocket(UDTSOCKET u)
|
||||
{
|
||||
UdtSocketInternal closedSocket;
|
||||
if (!m_ClosedSockets.TryGetValue(u, out closedSocket))
|
||||
return;
|
||||
|
||||
// decrease multiplexer reference count, and remove it if necessary
|
||||
int mid = closedSocket.m_iMuxID;
|
||||
|
||||
if (null != closedSocket.m_pQueuedSockets)
|
||||
{
|
||||
Monitor.Enter(closedSocket.m_AcceptLock);
|
||||
|
||||
// if it is a listener, close all un-accepted sockets in its queue and remove them later
|
||||
foreach (UDTSOCKET q in closedSocket.m_pQueuedSockets)
|
||||
{
|
||||
m_Sockets[q].m_pUDT.m_bBroken = true;
|
||||
m_Sockets[q].m_pUDT.close();
|
||||
m_Sockets[q].m_TimeStamp = Timer.getTime();
|
||||
m_Sockets[q].m_Status = UDTSTATUS.CLOSED;
|
||||
m_ClosedSockets[q] = m_Sockets[q];
|
||||
m_Sockets.Remove(q);
|
||||
}
|
||||
|
||||
Monitor.Exit(closedSocket.m_AcceptLock);
|
||||
}
|
||||
|
||||
// remove from peer rec
|
||||
HashSet<int> sockets;
|
||||
if (m_PeerRec.TryGetValue((closedSocket.m_PeerID << 30) + closedSocket.m_iISN, out sockets))
|
||||
{
|
||||
sockets.Remove(u);
|
||||
if (sockets.Count == 0)
|
||||
m_PeerRec.Remove(closedSocket.m_PeerID);
|
||||
}
|
||||
|
||||
// delete this one
|
||||
closedSocket.m_pUDT.close();
|
||||
closedSocket.Close();
|
||||
m_ClosedSockets.Remove(u);
|
||||
|
||||
Multiplexer m;
|
||||
if (!m_mMultiplexer.TryGetValue(mid, out m))
|
||||
{
|
||||
//something is wrong!!!
|
||||
return;
|
||||
}
|
||||
|
||||
m.m_iRefCount--;
|
||||
if (0 == m.m_iRefCount)
|
||||
{
|
||||
m.m_pChannel.close();
|
||||
m.m_pSndQueue.Close();
|
||||
m.m_pRcvQueue.Close();
|
||||
m.m_pTimer.Stop();
|
||||
|
||||
m_mMultiplexer.Remove(mid);
|
||||
}
|
||||
}
|
||||
|
||||
// void setError(UdtException e)
|
||||
//{
|
||||
// CGuard tg(m_TLSLock);
|
||||
// delete(UdtException *)TlsGetValue(m_TLSError);
|
||||
// TlsSetValue(m_TLSError, e);
|
||||
// m_mTLSRecord[GetCurrentThreadId()] = e;
|
||||
// }
|
||||
|
||||
// UdtException getError()
|
||||
//{
|
||||
// CGuard tg(m_TLSLock);
|
||||
// if (null == TlsGetValue(m_TLSError))
|
||||
// {
|
||||
// UdtException* e = new UdtException;
|
||||
// TlsSetValue(m_TLSError, e);
|
||||
// m_mTLSRecord[GetCurrentThreadId()] = e;
|
||||
// }
|
||||
// return (UdtException*)TlsGetValue(m_TLSError);
|
||||
// }
|
||||
|
||||
// void checkTLSValue()
|
||||
//{
|
||||
// CGuard tg(m_TLSLock);
|
||||
|
||||
// vector<DWORD> tbr;
|
||||
// for (map<DWORD, UdtException*>.iterator i = m_mTLSRecord.begin(); i != m_mTLSRecord.end(); ++i)
|
||||
// {
|
||||
// HANDLE h = OpenThread(THREAD_QUERY_INFORMATION, FALSE, i.first);
|
||||
// if (null == h)
|
||||
// {
|
||||
// tbr.push_back(i.first);
|
||||
// break;
|
||||
// }
|
||||
// if (WAIT_OBJECT_0 == WaitForSingleObject(h, 0))
|
||||
// {
|
||||
// delete i.second;
|
||||
// tbr.push_back(i.first);
|
||||
// }
|
||||
// CloseHandle(h);
|
||||
// }
|
||||
// for (vector<DWORD>.iterator j = tbr.begin(); j != tbr.end(); ++j)
|
||||
// m_mTLSRecord.erase(*j);
|
||||
// }
|
||||
|
||||
void updateMux(UdtSocketInternal s, IPEndPoint addr = null, Socket udpsock = null)
|
||||
{
|
||||
lock (m_ControlLock)
|
||||
{
|
||||
Multiplexer m;
|
||||
if ((s.m_pUDT.m_bReuseAddr) && (null != addr))
|
||||
{
|
||||
int port = addr.Port;
|
||||
|
||||
// find a reusable address
|
||||
foreach (KeyValuePair<int, Multiplexer> item in m_mMultiplexer)
|
||||
{
|
||||
// reuse the existing multiplexer
|
||||
m = item.Value;
|
||||
if ((m.m_iIPversion == s.m_pUDT.m_iIPversion) && (m.m_iMSS == s.m_pUDT.m_iMSS) && m.m_bReusable)
|
||||
{
|
||||
if (m.m_iPort == port)
|
||||
{
|
||||
// reuse the existing multiplexer
|
||||
++m.m_iRefCount;
|
||||
s.m_pUDT.m_pSndQueue = m.m_pSndQueue;
|
||||
s.m_pUDT.m_pRcvQueue = m.m_pRcvQueue;
|
||||
s.m_iMuxID = m.m_iID;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// a new multiplexer is needed
|
||||
m = new Multiplexer();
|
||||
m.m_iMSS = s.m_pUDT.m_iMSS;
|
||||
m.m_iIPversion = s.m_pUDT.m_iIPversion;
|
||||
m.m_iRefCount = 1;
|
||||
m.m_bReusable = s.m_pUDT.m_bReuseAddr;
|
||||
m.m_iID = s.m_SocketID;
|
||||
|
||||
m.m_pChannel = new Channel(s.m_pUDT.m_iIPversion);
|
||||
m.m_pChannel.setSndBufSize(s.m_pUDT.m_iUDPSndBufSize);
|
||||
m.m_pChannel.setRcvBufSize(s.m_pUDT.m_iUDPRcvBufSize);
|
||||
|
||||
try
|
||||
{
|
||||
if (null != udpsock)
|
||||
m.m_pChannel.open(udpsock);
|
||||
else
|
||||
m.m_pChannel.open(addr);
|
||||
}
|
||||
catch (UdtException e)
|
||||
{
|
||||
m.m_pChannel.close();
|
||||
throw e;
|
||||
}
|
||||
|
||||
IPEndPoint sa = new IPEndPoint(IPAddress.Any, 0);
|
||||
m.m_pChannel.getSockAddr(ref sa);
|
||||
m.m_iPort = sa.Port;
|
||||
|
||||
m.m_pTimer = new Timer();
|
||||
|
||||
m.m_pSndQueue = new SndQueue();
|
||||
m.m_pSndQueue.init(m.m_pChannel, m.m_pTimer);
|
||||
m.m_pRcvQueue = new RcvQueue();
|
||||
m.m_pRcvQueue.init(32, s.m_pUDT.m_iPayloadSize, m.m_iIPversion, 1024, m.m_pChannel, m.m_pTimer);
|
||||
|
||||
m_mMultiplexer[m.m_iID] = m;
|
||||
|
||||
s.m_pUDT.m_pSndQueue = m.m_pSndQueue;
|
||||
s.m_pUDT.m_pRcvQueue = m.m_pRcvQueue;
|
||||
s.m_iMuxID = m.m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
void updateMux(UdtSocketInternal s, UdtSocketInternal ls)
|
||||
{
|
||||
lock (m_ControlLock)
|
||||
{
|
||||
|
||||
int port = ls.m_pSelfAddr.Port;
|
||||
|
||||
// find the listener's address
|
||||
foreach (KeyValuePair<int, Multiplexer> item in m_mMultiplexer)
|
||||
{
|
||||
if (item.Value.m_iPort == port)
|
||||
{
|
||||
// reuse the existing multiplexer
|
||||
Multiplexer multiplexer = item.Value;
|
||||
++multiplexer.m_iRefCount;
|
||||
s.m_pUDT.m_pSndQueue = multiplexer.m_pSndQueue;
|
||||
s.m_pUDT.m_pRcvQueue = multiplexer.m_pRcvQueue;
|
||||
s.m_iMuxID = multiplexer.m_iID;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace UdtSharp
|
||||
Reference in New Issue
Block a user