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 = (IPEndPoint)udpsock.LocalEndPoint; 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 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 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); } } }
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 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); } }
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; } } } }
// 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; } }
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 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); }