Files
HawkeyeVision/framework/Inspectron.HawkEye/UDT/UdtUnited.cs
2025-08-19 12:45:50 +02:00

961 lines
33 KiB
C#

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