// Functionality: // Read the first (smallest) loss seq. no. in the list and remove it. // Parameters: // None. // Returned value: // The seq. no. or -1 if the list is empty. public Int32 getLostSeq() { if (0 == m_iLength) return -1; CGuard listguard = new CGuard(m_ListLock); if (0 == m_iLength) return -1; if (m_iLastInsertPos == m_iHead) m_iLastInsertPos = -1; // return the first loss seq. no. Int32 seqno = m_piData1[m_iHead]; // head moves to the next node if (-1 == m_piData2[m_iHead]) { //[3, -1] becomes [], and head moves to next node in the list m_piData1[m_iHead] = -1; m_iHead = m_piNext[m_iHead]; } else { // shift to next node, e.g., [3, 7] becomes [], [4, 7] int loc = (m_iHead + 1) % m_iSize; m_piData1[loc] = CSeqNo.incseq(seqno); if (CSeqNo.seqcmp(m_piData2[m_iHead], m_piData1[loc]) > 0) m_piData2[loc] = m_piData2[m_iHead]; m_piData1[m_iHead] = -1; m_piData2[m_iHead] = -1; m_piNext[loc] = m_piNext[m_iHead]; m_iHead = loc; } m_iLength--; return seqno; }
// Functionality: // initialize the UDT library. // Parameters: // None. // Returned value: // 0 if success, otherwise -1 is returned. static CUDTUnited() { m_InitLock = new Mutex(); CGuard gcinit = new CGuard(m_InitLock); //init CTimer.EventLock if (m_bGCStatus) return true; m_bClosing = false; m_GCStopLock = new Mutex(); m_GCStopCond = new AutoResetEvent(false); DWORD ThreadID; m_GCThread = CreateThread(null, 0, garbageCollect, this, null, &ThreadID); m_bGCStatus = true; return 0; }
// Functionality: // Connect to a UDT entity listening at address "peer". // Parameters: // 0) [in] peer: The address of the listening UDT entity. // Returned value: // None. public void connect(IPEndPoint serv_addr) { CGuard cg = new CGuard(m_ConnectionLock); if (!m_bOpened) throw new CUDTException(5, 0, 0); if (m_bListening) throw new CUDTException(5, 2, 0); if (m_bConnected) throw new CUDTException(5, 2, 0); // register this socket in the rendezvous queue m_pRcvQueue.m_pRendezvousQueue.insert(m_SocketID, m_iIPversion, serv_addr); CPacket request; byte[] reqdata = new byte [m_iPayloadSize]; CHandShake req = (CHandShake)reqdata; CPacket response; byte[] resdata = new byte [m_iPayloadSize]; CHandShake res = (CHandShake)resdata; // This is my current configurations. req.m_iVersion = m_iVersion; req.m_iType = m_iSockType; req.m_iMSS = m_iMSS; req.m_iFlightFlagSize = (m_iRcvBufSize < m_iFlightFlagSize)? m_iRcvBufSize : m_iFlightFlagSize; req.m_iReqType = (!m_bRendezvous) ? 1 : 0; req.m_iID = m_SocketID; CIPAddress.ntop(serv_addr, req.m_piPeerIP, m_iIPversion); // Random Initial Sequence Number srand((int)CClock.getTime()); m_iISN = req.m_iISN = (Int32)(CSeqNo.m_iMaxSeqNo * ((double)(rand()) / RAND_MAX)); m_iLastDecSeq = req.m_iISN - 1; m_iSndLastAck = req.m_iISN; m_iSndLastDataAck = req.m_iISN; m_iSndCurrSeqNo = req.m_iISN - 1; m_iSndLastAck2 = req.m_iISN; m_ullSndLastAck2Time = CClock.getTime(); // Inform the server my configurations. request.pack(0, null, reqdata, sizeof(CHandShake)); // ID = 0, connection request request.m_iID = 0; // Wait for the negotiated configurations from the peer side. response.pack(0, null, resdata, sizeof(CHandShake)); Int64 timeo = 3000000; if (m_bRendezvous) timeo *= 10; Int64 entertime = CClock.getTime(); CUDTException e = new CUDTException(0, 0); byte[] tmp = null; while (!m_bClosing) { m_pSndQueue.sendto(serv_addr, request); response.setLength(m_iPayloadSize); if (m_pRcvQueue.recvfrom(m_SocketID, response) > 0) { if (m_bRendezvous && ((0 == response.getFlag()) || (1 == response.getType())) && (null != tmp)) { // a data packet or a keep-alive packet comes, which means the peer side is already connected // in this situation, a previously recorded response (tmp) will be used memcpy(resdata, tmp, sizeof(CHandShake)); memcpy(m_piSelfIP, res.m_piPeerIP, 16); break; } if ((1 != response.getFlag()) || (0 != response.getType())) response.setLength(-1); if (m_bRendezvous) { // regular connect should NOT communicate with rendezvous connect // rendezvous connect require 3-way handshake if (1 == res.m_iReqType) response.setLength(-1); else if ((0 == res.m_iReqType) || (0 == req.m_iReqType)) { tmp = new char [m_iPayloadSize]; memcpy(tmp, resdata, sizeof(CHandShake)); req.m_iReqType = -1; request.m_iID = res.m_iID; response.setLength(-1); } } else { // set cookie if (1 == res.m_iReqType) { req.m_iReqType = -1; req.m_iCookie = res.m_iCookie; response.setLength(-1); } } } if (response.getLength() > 0) { memcpy(m_piSelfIP, res.m_piPeerIP, 16); break; } if (CClock.getTime() > entertime + timeo) { // timeout e = CUDTException(1, 1, 0); break; } } //delete [] tmp; //delete [] reqdata; if (e.getErrorCode() == 0) { if (m_bClosing) // if the socket is closed before connection... e = new CUDTException(1); else if (1002 == res.m_iReqType) // connection request rejected e = new CUDTException(1, 2, 0); else if ((!m_bRendezvous) && (m_iISN != res.m_iISN)) // secuity check e = new CUDTException(1, 4, 0); } if (e.getErrorCode() != 0) { // connection failure, clean up and throw exception // delete [] resdata; if (m_bRendezvous) m_pRcvQueue.m_pRendezvousQueue.remove(m_SocketID); throw e; } // Got it. Re-configure according to the negotiated values. m_iMSS = res.m_iMSS; m_iFlowWindowSize = res.m_iFlightFlagSize; m_iPktSize = m_iMSS - 28; m_iPayloadSize = m_iPktSize - CPacket.m_iPktHdrSize; m_iPeerISN = res.m_iISN; m_iRcvLastAck = res.m_iISN; m_iRcvLastAckAck = res.m_iISN; m_iRcvCurrSeqNo = res.m_iISN - 1; m_PeerID = res.m_iID; delete [] resdata; // Prepare all data structures try { m_pSndBuffer = new CSndBuffer(32, m_iPayloadSize); m_pRcvBuffer = new CRcvBuffer(m_iRcvBufSize, &(m_pRcvQueue.m_UnitQueue)); // after introducing lite ACK, the sndlosslist may not be cleared in time, so it requires twice space. m_pSndLossList = new CSndLossList(m_iFlowWindowSize * 2); m_pRcvLossList = new CRcvLossList(m_iFlightFlagSize); m_pACKWindow = new CACKWindow(4096); m_pRcvTimeWindow = new CPktTimeWindow(16, 64); m_pSndTimeWindow = new CPktTimeWindow(); } catch (Exception e) { throw new CUDTException(3, 2, 0); } m_pCC = m_pCCFactory.create(); m_pCC.m_UDT = m_SocketID; m_ullInterval = (Int64)(m_pCC.m_dPktSndPeriod * m_ullCPUFrequency); m_dCongestionWindow = m_pCC.m_dCWndSize; CInfoBlock ib; if (m_pCache.lookup(serv_addr, m_iIPversion, &ib) >= 0) { m_iRTT = ib.m_iRTT; m_iBandwidth = ib.m_iBandwidth; } m_pCC.setMSS(m_iMSS); m_pCC.setMaxCWndSize((int)m_iFlowWindowSize); m_pCC.setSndCurrSeqNo((int)m_iSndCurrSeqNo); m_pCC.setRcvRate(m_iDeliveryRate); m_pCC.setRTT(m_iRTT); m_pCC.setBandwidth(m_iBandwidth); if (m_llMaxBW > 0) m_pCC.setUserParam((char*)&(m_llMaxBW), 8); m_pCC.init(); m_pPeerAddr = serv_addr; // m_pPeerAddr = (AddressFamily.InterNetwork == m_iIPversion) ? new IPEndPoint(IPAddress.Any,0) : new IPEndPoint(IPAddress.IPv6Any,0); //memcpy(m_pPeerAddr, serv_addr, (AF_INET == m_iIPversion) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6)); // And, I am connected too. m_bConnected = true; // register this socket for receiving data packets m_pRcvQueue.setNewEntry(this); // remove from rendezvous queue m_pRcvQueue.m_pRendezvousQueue.remove(m_SocketID); }
void updateMux(CUDT u, IPEndPoint addr, Socket udpsock) { CGuard cg = new CGuard(m_ControlLock); if ((u.m_bReuseAddr) && (null != addr)) { //int port = (AF_INET == u.m_iIPversion) ? ntohs(((sockaddr_in*)addr).sin_port) : ntohs(((sockaddr_in6*)addr).sin6_port); int port = addr.Port; // find a reusable address //for (vector<CMultiplexer>::iterator i = m_vMultiplexer.begin(); i != m_vMultiplexer.end(); ++ i) foreach (CMultiplexer i in m_vMultiplexer) { if ((i.m_iIPversion == u.m_iIPversion) && (i.m_iMSS == u.m_iMSS) && i.m_bReusable) { if (i.m_iPort == port) { // reuse the existing multiplexer ++i.m_iRefCount; u.m_pSndQueue = i.m_pSndQueue; u.m_pRcvQueue = i.m_pRcvQueue; return; } } } } // a new multiplexer is needed CMultiplexer m; m.m_iMSS = u.m_iMSS; m.m_iIPversion = u.m_iIPversion; m.m_iRefCount = 1; m.m_bReusable = u.m_bReuseAddr; m.m_pChannel = new CChannel(u.m_iIPversion); m.m_pChannel.setSndBufSize(u.m_iUDPSndBufSize); m.m_pChannel.setRcvBufSize(u.m_iUDPRcvBufSize); try { if (null != udpsock) m.m_pChannel.open(udpsock); else m.m_pChannel.open(addr); } catch (CUDTException e) { m.m_pChannel.close(); //delete m.m_pChannel; throw e; } IPEndPoint sa = (AddressFamily.InterNetwork == u.m_iIPversion) ? new IPEndPoint(IPAddress.Any, 0) : new IPEndPoint(IPAddress.IPv6Any, 0); m.m_pChannel.getSockAddr(out sa); m.m_iPort = sa.Port; // (AF_INET == u.m_iIPversion) ? ntohs(((sockaddr_in*)sa).sin_port) : ntohs(((sockaddr_in6*)sa).sin6_port); //if (AddressFamily.InterNetwork == u.m_iIPversion) // delete (sockaddr_in*)sa; // else // delete (sockaddr_in6*)sa; m.m_pTimer = new CClock(); m.m_pSndQueue = new CSndQueue(m.m_pChannel, m.m_pTimer); m.m_pRcvQueue = new CRcvQueue(); m.m_pRcvQueue.init(32, u.m_iPayloadSize, m.m_iIPversion, 1024, m.m_pChannel, m.m_pTimer); m_vMultiplexer.insert(m_vMultiplexer.end(), m); u.m_pSndQueue = m.m_pSndQueue; u.m_pRcvQueue = m.m_pRcvQueue; }
DWORD garbageCollect(Object p) { CUDTUnited self = (CUDTUnited)p; CGuard gcguard = new CGuard(self.m_GCStopLock); while (!self.m_bClosing) { self.checkBrokenSockets(); self.checkTLSValue(); //WaitForSingleObject(self.m_GCStopCond, 1000); self.m_GCStopCond.WaitOne(1000); } // remove all sockets and multiplexers foreach (KeyValuePair<UDTSOCKET, UdtSocket> kvp in m_Sockets) { kvp.Value.m_pUDT.close(); kvp.Value.m_Status = UDTSTATUS.CLOSED; kvp.Value.m_TimeStamp = CClock.getTime(); self.m_ClosedSockets[kvp.Key] = kvp.Value; } self.m_Sockets.Clear(); while (self.m_ClosedSockets.Count > 0) { Thread.Sleep(1); self.checkBrokenSockets(); } return 0; }
public void setNewEntry(CUDT u) { CGuard listguard = new CGuard(m_IDLock); m_vNewEntry.insert(m_vNewEntry.end(), u); }
// Functionality: // look up the most recent UDT exception. // Parameters: // None. // Returned value: // pointer to a UDT exception instance. public CUDTException getError() { CGuard tg = new CGuard(m_TLSLock); if (null == TlsGetValue(m_TLSError)) { CUDTException* e = new CUDTException(); TlsSetValue(m_TLSError, e); m_mTLSRecord[GetCurrentThreadId()] = e; } return (CUDTException*)TlsGetValue(m_TLSError); }
// Functionality: // Request UDT to receive data into a file described as "fd", starting from "offset", with expected size of "size". // Parameters: // 0) [out] ofs: The output file stream. // 1) [in] offset: From where to write data; // 2) [in] size: How many data to be received. // 3) [in] block: size of block per write to disk // Returned value: // Actual size of data received. public Int64 recvfile(Stream ofs, Int64 offset, Int64 size, int block) { if (UDT_DGRAM == m_iSockType) throw new CUDTException(5, 10, 0); if (!m_bConnected) throw new CUDTException(2, 2, 0); else if ((m_bBroken || m_bClosing) && (0 == m_pRcvBuffer.getRcvDataSize())) throw new CUDTException(2, 1, 0); if (size <= 0) return 0; CGuard recvguard = new CGuard(m_RecvLock); long torecv = size; int unitsize = block; int recvsize; // positioning... try { ofs.seekp((streamoff)offset); } catch (Exception e) { throw new CUDTException(4, 3); } // receiving... "recvfile" is always blocking while (torecv > 0) { if (ofs.bad() || ofs.fail()) break; while (!m_bBroken && m_bConnected && !m_bClosing && (0 == m_pRcvBuffer.getRcvDataSize())) m_RecvDataCond.WaitOne(-1); if (!m_bConnected) throw new CUDTException(2, 2, 0); else if ((m_bBroken || m_bClosing) && (0 == m_pRcvBuffer.getRcvDataSize())) throw new CUDTException(2, 1, 0); unitsize = (int)((torecv >= block) ? block : torecv); recvsize = m_pRcvBuffer.readBufferToFile(ofs, unitsize); torecv -= recvsize; } return size - torecv; }
// Functionality: // Configure UDT options. // Parameters: // 0) [in] optName: The enum name of a UDT option. // 1) [in] optval: The value to be set. // 2) [in] optlen: size of "optval". // Returned value: // None. void setOpt(UDTOpt optName, Object optval, int optlen) { CGuard cg = new CGuard(m_ConnectionLock); CGuard sendguard = new CGuard(m_SendLock); CGuard recvguard = new CGuard(m_RecvLock); switch (optName) { case UDTOpt.UDT_MSS: if (m_bOpened) throw new CUDTException(5, 1, 0); if ((int)optval < (int)(28 + sizeof(CHandShake))) throw new CUDTException(5, 3, 0); m_iMSS = (int)optval; // Packet size cannot be greater than UDP buffer size if (m_iMSS > m_iUDPSndBufSize) m_iMSS = m_iUDPSndBufSize; if (m_iMSS > m_iUDPRcvBufSize) m_iMSS = m_iUDPRcvBufSize; break; case UDTOpt.UDT_SNDSYN: m_bSynSending = (bool)optval; break; case UDTOpt.UDT_RCVSYN: m_bSynRecving = (bool)optval; break; case UDTOpt.UDT_CC: if (m_bConnected) throw new CUDTException(5, 1, 0); //if (null != m_pCCFactory) // delete m_pCCFactory; m_pCCFactory = ((CCCVirtualFactory )optval).clone(); break; case UDTOpt.UDT_FC: if (m_bConnected) throw new CUDTException(5, 2, 0); if (*(int*)optval < 1) throw new CUDTException(5, 3); // Mimimum recv flight flag size is 32 packets if (*(int*)optval > 32) m_iFlightFlagSize = *(int*)optval; else m_iFlightFlagSize = 32; break; case UDTOpt.UDT_SNDBUF: if (m_bOpened) throw new CUDTException(5, 1, 0); if (*(int*)optval <= 0) throw new CUDTException(5, 3, 0); m_iSndBufSize = *(int*)optval / (m_iMSS - 28); break; case UDTOpt.UDT_RCVBUF: if (m_bOpened) throw new CUDTException(5, 1, 0); if (*(int*)optval <= 0) throw new CUDTException(5, 3, 0); // Mimimum recv buffer size is 32 packets if (*(int*)optval > (m_iMSS - 28) * 32) m_iRcvBufSize = *(int*)optval / (m_iMSS - 28); else m_iRcvBufSize = 32; // recv buffer MUST not be greater than FC size if (m_iRcvBufSize > m_iFlightFlagSize) m_iRcvBufSize = m_iFlightFlagSize; break; case UDTOpt.UDT_LINGER: m_Linger = *(linger*)optval; break; case UDTOpt.UDP_SNDBUF: if (m_bOpened) throw new CUDTException(5, 1, 0); m_iUDPSndBufSize = *(int*)optval; if (m_iUDPSndBufSize < m_iMSS) m_iUDPSndBufSize = m_iMSS; break; case UDTOpt.UDP_RCVBUF: if (m_bOpened) throw new CUDTException(5, 1, 0); m_iUDPRcvBufSize = *(int*)optval; if (m_iUDPRcvBufSize < m_iMSS) m_iUDPRcvBufSize = m_iMSS; break; case UDTOpt.UDT_RENDEZVOUS: if (m_bConnected) throw new CUDTException(5, 1, 0); m_bRendezvous = *(bool *)optval; break; case UDTOpt.UDT_SNDTIMEO: m_iSndTimeOut = *(int*)optval; break; case UDTOpt.UDT_RCVTIMEO: m_iRcvTimeOut = *(int*)optval; break; case UDTOpt.UDT_REUSEADDR: if (m_bOpened) throw new CUDTException(5, 1, 0); m_bReuseAddr = *(bool*)optval; break; case UDTOpt.UDT_MAXBW: if (m_bConnected) throw new CUDTException(5, 1, 0); m_llMaxBW = *(Int64*)optval; break; default: throw new CUDTException(5, 0, 0); } }
// Functionality: // Receive a message to buffer "data". // Parameters: // 0) [out] data: data received. // 1) [in] len: size of the buffer. // Returned value: // Actual size of data received. public int recvmsg(byte[] data, int len) { if (UDT_STREAM == m_iSockType) throw new CUDTException(5, 9, 0); // throw an exception if not connected if (!m_bConnected) throw new CUDTException(2, 2, 0); if (len <= 0) return 0; CGuard recvguard = new CGuard(m_RecvLock); if (m_bBroken || m_bClosing) { int res = m_pRcvBuffer.readMsg(data, len); if (0 == res) throw new CUDTException(2, 1, 0); else return res; } if (!m_bSynRecving) { int res = m_pRcvBuffer.readMsg(data, len); if (0 == res) throw new CUDTException(6, 2, 0); else return res; } int res = 0; bool timeout = false; do { if (m_iRcvTimeOut < 0) { while (!m_bBroken && m_bConnected && !m_bClosing && (0 == (res = m_pRcvBuffer.readMsg(data, len)))) WaitForSingleObject(m_RecvDataCond, INFINITE); } else { if (WaitForSingleObject(m_RecvDataCond, DWORD(m_iRcvTimeOut)) == WAIT_TIMEOUT) timeout = true; res = m_pRcvBuffer.readMsg(data, len); } if (m_bBroken || m_bClosing) throw new CUDTException(2, 1, 0); else if (!m_bConnected) throw new CUDTException(2, 2, 0); } while ((0 == res) && !timeout); return res; }
// Functionality: // Request UDT to send out a file described as "fd", starting from "offset", with size of "size". // Parameters: // 0) [in] ifs: The input file stream. // 1) [in] offset: From where to read and send data; // 2) [in] size: How many data to be sent. // 3) [in] block: size of block per read from disk // Returned value: // Actual size of data sent. public Int64 sendfile(Stream ifs, Int64 offset, Int64 size, int block) { if (UDT_DGRAM == m_iSockType) throw new CUDTException(5, 10, 0); if (m_bBroken || m_bClosing) throw new CUDTException(2, 1, 0); else if (!m_bConnected) throw new CUDTException(2, 2, 0); if (size <= 0) return 0; CGuard sendguard = new CGuard(m_SendLock); long tosend = size; int unitsize; // positioning... try { ifs.seekg((streamoff)offset); } catch (Exception e) { throw new CUDTException(4, 1); } // sending block by block while (tosend > 0) { if (ifs.bad() || ifs.fail() || ifs.eof()) break; unitsize = (int)((tosend >= block) ? block : tosend); while (!m_bBroken && m_bConnected && !m_bClosing && (m_iSndBufSize <= m_pSndBuffer.getCurrBufSize())) WaitForSingleObject(m_SendBlockCond, INFINITE); if (m_bBroken || m_bClosing) throw new CUDTException(2, 1, 0); else if (!m_bConnected) throw new CUDTException(2, 2, 0); // record total time used for sending if (0 == m_pSndBuffer.getCurrBufSize()) m_llSndDurationCounter = CClock.getTime(); tosend -= m_pSndBuffer.addBufferFromFile(ifs, unitsize); // insert this socket to snd list if it is not on the list yet m_pSndQueue.m_pSndUList.update(this, false); } return size - tosend; }
// Functionality: // send a message of a memory block "data" with size of "len". // Parameters: // 0) [out] data: data received. // 1) [in] len: The desired size of data to be received. // 2) [in] ttl: the time-to-live of the message. // 3) [in] inorder: if the message should be delivered in order. // Returned value: // Actual size of data sent. public int sendmsg(byte[] data, int len, int msttl, bool inorder) { if (UDT_STREAM == m_iSockType) throw new CUDTException(5, 9, 0); // throw an exception if not connected if (m_bBroken || m_bClosing) throw new CUDTException(2, 1, 0); else if (!m_bConnected) throw new CUDTException(2, 2, 0); if (len <= 0) return 0; if (len > m_iSndBufSize * m_iPayloadSize) throw new CUDTException(5, 12, 0); CGuard sendguard = new CGuard(m_SendLock); if ((m_iSndBufSize - m_pSndBuffer.getCurrBufSize()) * m_iPayloadSize < len) { if (!m_bSynSending) throw new CUDTException(6, 1, 0); else { // wait here during a blocking sending if (m_iSndTimeOut < 0) { while (!m_bBroken && m_bConnected && !m_bClosing && ((m_iSndBufSize - m_pSndBuffer.getCurrBufSize()) * m_iPayloadSize < len)) WaitForSingleObject(m_SendBlockCond, INFINITE); } else WaitForSingleObject(m_SendBlockCond, DWORD(m_iSndTimeOut)); // check the connection status if (m_bBroken || m_bClosing) throw new CUDTException(2, 1, 0); else if (!m_bConnected) throw new CUDTException(2, 2, 0); } } if ((m_iSndBufSize - m_pSndBuffer.getCurrBufSize()) * m_iPayloadSize < len) return 0; // record total time used for sending if (0 == m_pSndBuffer.getCurrBufSize()) m_llSndDurationCounter = CClock.getTime(); // insert the user buffer into the sening list m_pSndBuffer.addBuffer(data, len, msttl, inorder); // insert this socket to the snd list if it is not on the list yet m_pSndQueue.m_pSndUList.update(this, false); return len; }
// Functionality: // Request UDT to receive data to a memory block "data" with size of "len". // Parameters: // 0) [out] data: data received. // 1) [in] len: The desired size of data to be received. // Returned value: // Actual size of data received. public int recv(byte[] data, int len) { if (UDT_DGRAM == m_iSockType) throw new CUDTException(5, 10, 0); // throw an exception if not connected if (!m_bConnected) throw new CUDTException(2, 2, 0); else if ((m_bBroken || m_bClosing) && (0 == m_pRcvBuffer.getRcvDataSize())) throw new CUDTException(2, 1, 0); if (len <= 0) return 0; CGuard recvguard = new CGuard(m_RecvLock); if (0 == m_pRcvBuffer.getRcvDataSize()) { if (!m_bSynRecving) throw new CUDTException(6, 2, 0); else { if (m_iRcvTimeOut < 0) { while (!m_bBroken && m_bConnected && !m_bClosing && (0 == m_pRcvBuffer.getRcvDataSize())) WaitForSingleObject(m_RecvDataCond, INFINITE); } else { Int64 enter_time = CClock.getTime(); while (!m_bBroken && m_bConnected && !m_bClosing && (0 == m_pRcvBuffer.getRcvDataSize())) { int diff = (int)(CClock.getTime() - enter_time) / 1000; if (diff >= m_iRcvTimeOut) break; WaitForSingleObject(m_RecvDataCond, DWORD(m_iRcvTimeOut - diff )); } } } } // throw an exception if not connected if (!m_bConnected) throw new CUDTException(2, 2, 0); else if ((m_bBroken || m_bClosing) && (0 == m_pRcvBuffer.getRcvDataSize())) throw new CUDTException(2, 1, 0); return m_pRcvBuffer.readBuffer(data, len); }
// Functionality: // Close the opened UDT entity. // Parameters: // None. // Returned value: // None. public void close() { if (!m_bOpened) return; if (!m_bConnected) m_bClosing = true; if (0 != m_Linger.l_onoff) { Int64 entertime = CClock.getTime(); while (!m_bBroken && m_bConnected && (m_pSndBuffer.getCurrBufSize() > 0) && (CClock.getTime() - entertime < m_Linger.l_linger * 1000000)) { Thread.Sleep(1); } } // remove this socket from the snd queue if (m_bConnected) m_pSndQueue.m_pSndUList.remove(this); CGuard cg = new CGuard(m_ConnectionLock); // Inform the threads handler to stop. m_bClosing = true; // Signal the sender and recver if they are waiting for data. releaseSynch(); if (m_bListening) { m_bListening = false; m_pRcvQueue.removeListener(this); } if (m_bConnected) { if (!m_bShutdown) sendCtrl(5); m_pCC.close(); CInfoBlock ib; ib.m_iRTT = m_iRTT; ib.m_iBandwidth = m_iBandwidth; m_pCache.update(m_pPeerAddr, m_iIPversion, &ib); m_bConnected = false; } // waiting all send and recv calls to stop CGuard sendguard = new CGuard(m_SendLock); CGuard recvguard = new CGuard(m_RecvLock); // CLOSED. m_bOpened = false; }
//~CSndLossList() //{ // m_ListLock.Close(); //} // Functionality: // Insert a seq. no. into the sender loss list. // Parameters: // 0) [in] seqno1: sequence number starts. // 1) [in] seqno2: sequence number ends. // Returned value: // number of packets that are not in the list previously. public override int insert(Int32 seqno1, Int32 seqno2) { CGuard listguard = new CGuard(m_ListLock); if (0 == m_iLength) { // insert data into an empty list m_iHead = 0; m_piData1[m_iHead] = seqno1; if (seqno2 != seqno1) m_piData2[m_iHead] = seqno2; m_piNext[m_iHead] = -1; m_iLastInsertPos = m_iHead; m_iLength += CSeqNo.seqlen(seqno1, seqno2); return m_iLength; } // otherwise find the position where the data can be inserted int origlen = m_iLength; int offset = CSeqNo.seqoff(m_piData1[m_iHead], seqno1); int loc = (m_iHead + offset + m_iSize) % m_iSize; if (offset < 0) { // Insert data prior to the head pointer m_piData1[loc] = seqno1; if (seqno2 != seqno1) m_piData2[loc] = seqno2; // new node becomes head m_piNext[loc] = m_iHead; m_iHead = loc; m_iLastInsertPos = loc; m_iLength += CSeqNo.seqlen(seqno1, seqno2); } else if (offset > 0) { if (seqno1 == m_piData1[loc]) { m_iLastInsertPos = loc; // first seqno is equivlent, compare the second if (-1 == m_piData2[loc]) { if (seqno2 != seqno1) { m_iLength += CSeqNo.seqlen(seqno1, seqno2) - 1; m_piData2[loc] = seqno2; } } else if (CSeqNo.seqcmp(seqno2, m_piData2[loc]) > 0) { // new seq pair is longer than old pair, e.g., insert [3, 7] to [3, 5], becomes [3, 7] m_iLength += CSeqNo.seqlen(m_piData2[loc], seqno2) - 1; m_piData2[loc] = seqno2; } else // Do nothing if it is already there return 0; } else { // searching the prior node int i; if ((-1 != m_iLastInsertPos) && (CSeqNo.seqcmp(m_piData1[m_iLastInsertPos], seqno1) < 0)) i = m_iLastInsertPos; else i = m_iHead; while ((-1 != m_piNext[i]) && (CSeqNo.seqcmp(m_piData1[m_piNext[i]], seqno1) < 0)) i = m_piNext[i]; if ((-1 == m_piData2[i]) || (CSeqNo.seqcmp(m_piData2[i], seqno1) < 0)) { m_iLastInsertPos = loc; // no overlap, create new node m_piData1[loc] = seqno1; if (seqno2 != seqno1) m_piData2[loc] = seqno2; m_piNext[loc] = m_piNext[i]; m_piNext[i] = loc; m_iLength += CSeqNo.seqlen(seqno1, seqno2); } else { m_iLastInsertPos = i; // overlap, coalesce with prior node, insert(3, 7) to [2, 5], ... becomes [2, 7] if (CSeqNo.seqcmp(m_piData2[i], seqno2) < 0) { m_iLength += CSeqNo.seqlen(m_piData2[i], seqno2) - 1; m_piData2[i] = seqno2; loc = i; } else return 0; } } } else { m_iLastInsertPos = m_iHead; // insert to head node if (seqno2 != seqno1) { if (-1 == m_piData2[loc]) { m_iLength += CSeqNo.seqlen(seqno1, seqno2) - 1; m_piData2[loc] = seqno2; } else if (CSeqNo.seqcmp(seqno2, m_piData2[loc]) > 0) { m_iLength += CSeqNo.seqlen(m_piData2[loc], seqno2) - 1; m_piData2[loc] = seqno2; } else return 0; } else return 0; } // coalesce with next node. E.g., [3, 7], ..., [6, 9] becomes [3, 9] while ((-1 != m_piNext[loc]) && (-1 != m_piData2[loc])) { int i = m_piNext[loc]; if (CSeqNo.seqcmp(m_piData1[i], CSeqNo.incseq(m_piData2[loc])) <= 0) { // coalesce if there is overlap if (-1 != m_piData2[i]) { if (CSeqNo.seqcmp(m_piData2[i], m_piData2[loc]) > 0) { if (CSeqNo.seqcmp(m_piData2[loc], m_piData1[i]) >= 0) m_iLength -= CSeqNo.seqlen(m_piData1[i], m_piData2[loc]); m_piData2[loc] = m_piData2[i]; } else m_iLength -= CSeqNo.seqlen(m_piData1[i], m_piData2[i]); } else { if (m_piData1[i] == CSeqNo.incseq(m_piData2[loc])) m_piData2[loc] = m_piData1[i]; else m_iLength--; } m_piData1[i] = -1; m_piData2[i] = -1; m_piNext[loc] = m_piNext[i]; } else break; } return m_iLength - origlen; }
// Functionality: // Read UDT options. // Parameters: // 0) [in] optName: The enum name of a UDT option. // 1) [in] optval: The value to be returned. // 2) [out] optlen: size of "optval". // Returned value: // None. void getOpt(UDTOpt optName, Object optval, int optlen) { CGuard cg = new CGuard(m_ConnectionLock); switch (optName) { case UDT_MSS: *(int*)optval = m_iMSS; optlen = sizeof(int); break; case UDT_SNDSYN: *(bool*)optval = m_bSynSending; optlen = sizeof(bool); break; case UDT_RCVSYN: *(bool*)optval = m_bSynRecving; optlen = sizeof(bool); break; case UDT_CC: if (!m_bOpened) throw new CUDTException(5, 5, 0); *(CCC**)optval = m_pCC; optlen = sizeof(CCC*); break; case UDT_FC: *(int*)optval = m_iFlightFlagSize; optlen = sizeof(int); break; case UDT_SNDBUF: *(int*)optval = m_iSndBufSize * (m_iMSS - 28); optlen = sizeof(int); break; case UDT_RCVBUF: *(int*)optval = m_iRcvBufSize * (m_iMSS - 28); optlen = sizeof(int); break; case UDT_LINGER: if (optlen < (int)(sizeof(linger))) throw new CUDTException(5, 3, 0); *(linger*)optval = m_Linger; optlen = sizeof(linger); break; case UDP_SNDBUF: *(int*)optval = m_iUDPSndBufSize; optlen = sizeof(int); break; case UDP_RCVBUF: *(int*)optval = m_iUDPRcvBufSize; optlen = sizeof(int); break; case UDT_RENDEZVOUS: *(bool *)optval = m_bRendezvous; optlen = sizeof(bool); break; case UDT_SNDTIMEO: *(int*)optval = m_iSndTimeOut; optlen = sizeof(int); break; case UDT_RCVTIMEO: *(int*)optval = m_iRcvTimeOut; optlen = sizeof(int); break; case UDT_REUSEADDR: *(bool *)optval = m_bReuseAddr; optlen = sizeof(bool); break; case UDT_MAXBW: *(Int64*)optval = m_llMaxBW; break; default: throw new CUDTException(5, 0, 0); } }
// Functionality: // Read a packet for a specific UDT socket id. // Parameters: // 1) [in] id: Socket ID // 2) [out] packet: received packet // Returned value: // Data size of the packet public int recvfrom(int id, ref CPacket packet) { packet = null; CGuard bufferlock = new CGuard(m_PassLock); // Try to find a packet for the specified // socket ID CPacket workPacket; if (!m_mBuffer.TryGetValue(id, out workPacket)) { // If we didn't find the packet waiting already // Then wait around until a packet arrives m_PassLock.ReleaseMutex(); m_PassCond.WaitOne(1000); m_PassLock.WaitOne(-1); // Try to find it again if (!m_Buffer.TryGetValue(id, out workPacket)) { packet.setLength(-1); return -1; } } if (packet.getLength() < i.second.getLength()) { packet.setLength(-1); return -1; } workPacket.m_nHeader.CopyTo(packet.m_nHeader, 0); workPacket.m_pcData.CopyTo(packet.m_pcData, 0); packet.setLength(workPacket.getLength()); m_mBuffer.Remove(i); return packet.getLength(); }
private int CUDTpackData(CPacket packet, Int64 ts) { int payload = 0; bool probe = false; Int64 entertime; CClock.rdtsc(out entertime); if ((0 != m_ullTargetTime) && (entertime > m_ullTargetTime)) m_ullTimeDiff += entertime - m_ullTargetTime; // Loss retransmission always has higher priority. if ((packet.m_iSeqNo = m_pSndLossList.getLostSeq()) >= 0) { // protect m_iSndLastDataAck from updating by ACK processing CGuard ackguard = new CGuard(m_AckLock); int offset = CSeqNo.seqoff((Int32)m_iSndLastDataAck, packet.m_iSeqNo); if (offset < 0) return 0; int msglen; payload = m_pSndBuffer.readData(&(packet.m_pcData), offset, packet.m_iMsgNo, msglen); if (-1 == payload) { Int32[] seqpair = new int[2]; seqpair[0] = packet.m_iSeqNo; seqpair[1] = CSeqNo.incseq(seqpair[0], msglen); sendCtrl(7, &packet.m_iMsgNo, seqpair, 8); // only one msg drop request is necessary m_pSndLossList.remove(seqpair[1]); return 0; } else if (0 == payload) return 0; ++ m_iTraceRetrans; ++ m_iRetransTotal; } else { // If no loss, pack a new packet. // check congestion/flow window limit int cwnd = (m_iFlowWindowSize < (int)m_dCongestionWindow) ? m_iFlowWindowSize : (int)m_dCongestionWindow; if (cwnd >= CSeqNo.seqlen((m_iSndLastAck), CSeqNo.incseq(m_iSndCurrSeqNo))) { if (0 != (payload = m_pSndBuffer.readData(&(packet.m_pcData), packet.m_iMsgNo))) { m_iSndCurrSeqNo = CSeqNo.incseq(m_iSndCurrSeqNo); m_pCC.setSndCurrSeqNo((Int32)m_iSndCurrSeqNo); packet.m_iSeqNo = m_iSndCurrSeqNo; // every 16 (0xF) packets, a packet pair is sent if (0 == (packet.m_iSeqNo & 0xF)) probe = true; } else { m_ullTargetTime = 0; m_ullTimeDiff = 0; ts = 0; return 0; } } else { m_ullTargetTime = 0; m_ullTimeDiff = 0; ts = 0; return 0; } } packet.m_iTimeStamp = (int)(CClock.getTime() - m_StartTime); m_pSndTimeWindow.onPktSent(packet.m_iTimeStamp); packet.m_iID = m_PeerID; m_pCC.onPktSent(&packet); ++ m_llTraceSent; ++ m_llSentTotal; if (probe) { // sends out probing packet pair ts = entertime; probe = false; } else { if (m_ullTimeDiff >= m_ullInterval) { ts = entertime; m_ullTimeDiff -= m_ullInterval; } else { ts = entertime + m_ullInterval - m_ullTimeDiff; m_ullTimeDiff = 0; } } m_ullTargetTime = ts; packet.m_iID = m_PeerID; packet.setLength(payload); return payload; }
// Functionality: // record the UDT exception. // Parameters: // 0) [in] e: pointer to a UDT exception instance. // Returned value: // None. internal void setError(CUDTException e) { CGuard tg = new CGuard(m_TLSLock); //delete (CUDTException*)TlsGetValue(m_TLSError); //TlsSetValue(m_TLSError, e); m_mTLSRecord[GetCurrentThreadId()] = e; }
public static int listen(IPAddress addr, out CPacket packet) { CGuard cg = new CGuard(m_ConnectionLock); if (m_bClosing) return 1002; CHandShake hs = (CHandShake )packet.m_pcData; // SYN cookie byte[] clienthost = new byte[NI_MAXHOST]; byte[] clientport = new byte[NI_MAXSERV]; getnameinfo(addr, (AF_INET == m_iVersion) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6), clienthost, sizeof(clienthost), clientport, sizeof(clientport), NI_NUMERICHOST|NI_NUMERICSERV); Int64 timestamp = (CClock.getTime() - m_StartTime) / 60000000; // secret changes every one minute //byte[] cookiestr = new byte[1024]; //sprintf(cookiestr, "%s:%s:%lld", clienthost, clientport, (long long int)timestamp); string cookiestr = string.Format("{0}:{1}:{2}", clienthost, clientport, timestamp); byte[] cookie = new byte[16]; CMD5.compute(cookiestr, cookie); if (1 == hs.m_iReqType) { hs.m_iCookie = *(int*)cookie; packet.m_iID = hs.m_iID; m_pSndQueue.sendto(addr, packet); return 0; } else { if (hs.m_iCookie != *(int*)cookie) { timestamp --; cookiestr = string.Format("{0}:{1}:{2}", clienthost, clientport, timestamp); CMD5.compute(cookiestr, out cookie); if (hs.m_iCookie != *(int*)cookie) return -1; } } Int32 id = hs.m_iID; // When a peer side connects in... if ((1 == packet.getFlag()) && (0 == packet.getType())) { if ((hs.m_iVersion != m_iVersion) || (hs.m_iType != m_iSockType) || (-1 == s_UDTUnited.newConnection(m_SocketID, addr, hs))) { // couldn't create a new connection, reject the request hs.m_iReqType = 1002; } packet.m_iID = id; m_pSndQueue.sendto(addr, packet); } return hs.m_iReqType; }
public UdtSocket locate(UDTSOCKET u, IPEndPoint peer, UDTSOCKET id, Int32 isn) { CGuard cg = new CGuard(m_ControlLock); UdtSocket i = null; m_Sockets.TryGetValue(u, out i); CGuard ag = new CGuard(i.m_AcceptLock); // look up the "peer" address in queued sockets set foreach (UDTSOCKET j1 in i.m_pQueuedSockets) { UdtSocket k1 = null; m_Sockets.TryGetValue(j1, out k1); // this socket might have been closed and moved m_ClosedSockets if (k1 == null) continue; if (CIPAddress.ipcmp(peer, k1.m_pPeerAddr, i.m_iIPversion)) { if ((id == k1.m_PeerID) && (isn == k1.m_iISN)) return k1; } } // look up the "peer" address in accept sockets set foreach (UDTSOCKET j1 in i.m_pAcceptSockets) { UdtSocket k2 = null; m_Sockets.TryGetValue(j2, out k2); // this socket might have been closed and moved m_ClosedSockets if (k2 == null) continue; if (CIPAddress.ipcmp(peer, k2.m_pPeerAddr, i.m_iIPversion)) { if ((id == k2.m_PeerID) && (isn == k2.m_iISN)) return k2; } } return null; }
// Functionality: // initialize a UDT entity and bind to a local address. // Parameters: // None. // Returned value: // None. public void open() { CGuard cg = new CGuard(m_ConnectionLock); // Initial sequence number, loss, acknowledgement, etc. m_iPktSize = m_iMSS - 28; m_iPayloadSize = m_iPktSize - CPacket.m_iPktHdrSize; m_iEXPCount = 1; m_iBandwidth = 1; m_iDeliveryRate = 16; m_iAckSeqNo = 0; m_ullLastAckTime = 0; // trace information m_StartTime = CClock.getTime(); m_llSentTotal = m_llRecvTotal = m_iSndLossTotal = m_iRcvLossTotal = m_iRetransTotal = m_iSentACKTotal = m_iRecvACKTotal = m_iSentNAKTotal = m_iRecvNAKTotal = 0; m_LastSampleTime = CClock.getTime(); m_llTraceSent = m_llTraceRecv = m_iTraceSndLoss = m_iTraceRcvLoss = m_iTraceRetrans = m_iSentACK = m_iRecvACK = m_iSentNAK = m_iRecvNAK = 0; m_llSndDuration = m_llSndDurationTotal = 0; // structures for queue if (null == m_pSNode) m_pSNode = new CSNode(); m_pSNode.m_pUDT = this; m_pSNode.m_llTimeStamp = 1; m_pSNode.m_iHeapLoc = -1; if (null == m_pRNode) m_pRNode = new CRNode(); m_pRNode.m_pUDT = this; m_pRNode.m_llTimeStamp = 1; m_pRNode.m_pPrev = m_pRNode.m_pNext = null; m_pRNode.m_bOnList = false; m_iRTT = 10 * m_iSYNInterval; m_iRTTVar = m_iRTT >> 1; m_ullCPUFrequency = CClock.getCPUFrequency(); // set up the timers m_ullSYNInt = m_iSYNInterval * m_ullCPUFrequency; m_ullACKInt = m_ullSYNInt; m_ullNAKInt = (m_iRTT + 4 * m_iRTTVar) * m_ullCPUFrequency; m_ullEXPInt = (m_iRTT + 4 * m_iRTTVar) * m_ullCPUFrequency + m_ullSYNInt; m_ullMinEXPInt = 100000 * m_ullCPUFrequency; CClock.rdtsc(m_ullNextACKTime); m_ullNextACKTime += m_ullSYNInt; CClock.rdtsc(m_ullNextNAKTime); m_ullNextNAKTime += m_ullNAKInt; CClock.rdtsc(m_ullNextEXPTime); m_ullNextEXPTime += m_ullEXPInt; m_iPktCount = 0; m_iLightACKCount = 1; m_ullTargetTime = 0; m_ullTimeDiff = 0; // Now UDT is opened. m_bOpened = true; }
public void updateMux(CUDT u, UdtSocket ls) { CGuard cg = new CGuard(m_ControlLock); //int port = (AF_INET == ls.m_iIPversion) ? ntohs(((sockaddr_in*)ls.m_pSelfAddr).sin_port) : ntohs(((sockaddr_in6*)ls.m_pSelfAddr).sin6_port); int port = ls.m_pSelfAddr.Port; // find the listener's address foreach (CMultiplexer i in m_vMultiplexer) { if (i.m_iPort == port) { // reuse the existing multiplexer ++i.m_iRefCount; u.m_pSndQueue = i.m_pSndQueue; u.m_pRcvQueue = i.m_pRcvQueue; return; } } }
// Functionality: // Remove ALL the seq. no. that are not greater than the parameter. // Parameters: // 0) [in] seqno: sequence number. // Returned value: // None. public override bool remove(int seqno) { CGuard listguard = new CGuard(m_ListLock); if (0 == m_iLength) return false; // Remove all from the head pointer to a node with a larger seq. no. or the list is empty int offset = CSeqNo.seqoff(m_piData1[m_iHead], seqno); int loc = (m_iHead + offset + m_iSize) % m_iSize; if (0 == offset) { // It is the head. Remove the head and point to the next node loc = (loc + 1) % m_iSize; if (-1 == m_piData2[m_iHead]) loc = m_piNext[m_iHead]; else { m_piData1[loc] = CSeqNo.incseq(seqno); if (CSeqNo.seqcmp(m_piData2[m_iHead], CSeqNo.incseq(seqno)) > 0) m_piData2[loc] = m_piData2[m_iHead]; m_piData2[m_iHead] = -1; m_piNext[loc] = m_piNext[m_iHead]; } m_piData1[m_iHead] = -1; if (m_iLastInsertPos == m_iHead) m_iLastInsertPos = -1; m_iHead = loc; m_iLength--; } else if (offset > 0) { int h = m_iHead; if (seqno == m_piData1[loc]) { // target node is not empty, remove part/all of the seqno in the node. int temp = loc; loc = (loc + 1) % m_iSize; if (-1 == m_piData2[temp]) m_iHead = m_piNext[temp]; else { // remove part, e.g., [3, 7] becomes [], [4, 7] after remove(3) m_piData1[loc] = CSeqNo.incseq(seqno); if (CSeqNo.seqcmp(m_piData2[temp], m_piData1[loc]) > 0) m_piData2[loc] = m_piData2[temp]; m_iHead = loc; m_piNext[loc] = m_piNext[temp]; m_piNext[temp] = loc; m_piData2[temp] = -1; } } else { // target node is empty, check prior node int i = m_iHead; while ((-1 != m_piNext[i]) && (CSeqNo.seqcmp(m_piData1[m_piNext[i]], seqno) < 0)) i = m_piNext[i]; loc = (loc + 1) % m_iSize; if (-1 == m_piData2[i]) m_iHead = m_piNext[i]; else if (CSeqNo.seqcmp(m_piData2[i], seqno) > 0) { // remove part/all seqno in the prior node m_piData1[loc] = CSeqNo.incseq(seqno); if (CSeqNo.seqcmp(m_piData2[i], m_piData1[loc]) > 0) m_piData2[loc] = m_piData2[i]; m_piData2[i] = seqno; m_piNext[loc] = m_piNext[i]; m_piNext[i] = loc; m_iHead = loc; } else m_iHead = m_piNext[i]; } // Remove all nodes prior to the new head while (h != m_iHead) { if (m_piData2[h] != -1) { m_iLength -= CSeqNo.seqlen(m_piData1[h], m_piData2[h]); m_piData2[h] = -1; } else m_iLength--; m_piData1[h] = -1; if (m_iLastInsertPos == h) m_iLastInsertPos = -1; h = m_piNext[h]; } } return true; }
public void checkBrokenSockets() { CGuard cg = new CGuard(m_ControlLock); // set of sockets To Be Closed and To Be Removed HashSet<UDTSOCKET> tbc = new HashSet<int>(); HashSet<UDTSOCKET> tbr = new HashSet<int>(); //for (map<UDTSOCKET, UdtSocket*>::iterator i = m_Sockets.begin(); i != m_Sockets.end(); ++ i) foreach (KeyValuePair<UDTSOCKET, UdtSocket> i in m_Sockets) { // check broken connection if (i.Value.m_pUDT.m_bBroken) { // if there is still data in the receiver buffer, wait longer if ((i.Value.m_pUDT.m_pRcvBuffer.getRcvDataSize() > 0) && (i.Value.m_pUDT.m_iBrokenCounter-- > 0)) continue; //close broken connections and start removal timer i.Value.m_Status = UDTSTATUS.CLOSED; i.Value.m_TimeStamp = CClock.getTime(); tbc.Add(i.Key); m_ClosedSockets[i.Key] = i.Value; // remove from listener's queue //map<UDTSOCKET, UdtSocket*>::iterator ls = m_Sockets.find(i.second.m_ListenSocket); UdtSocket ls = null; bool foundIt = m_Sockets.TryGetValue(i.Value.m_ListenSocket, out ls); if (ls != null) { lock (ls.Value.m_AcceptLock) { ls.Value.m_pQueuedSockets.erase(i.Value.m_SocketID); ls.Value.m_pAcceptSockets.erase(i.Value.m_SocketID); } } } } foreach (KeyValuePair<UDTSOCKET, UdtSocket> j in m_ClosedSockets) { // timeout 1 second to destroy a socket AND it has been removed from RcvUList if ((CClock.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); // sockets cannot be removed here because it will invalidate the map iterator } // move closed sockets to the ClosedSockets structure foreach (UDTSOCKET sock in tbc) { m_Sockets.Remove(sock); } // remove those timeout sockets foreach (UDTSOCKET sock in tbr) { removeSocket(sock); } }
// Functionality: // Read the loss length. // Parameters: // None. // Returned value: // The length of the list. public override int getLossLength() { CGuard listguard = new CGuard(m_ListLock); return m_iLength; }
// Functionality: // release the UDT library. // Parameters: // None. // Returned value: // 0 if success, otherwise -1 is returned. int cleanup() { CGuard gcinit = new CGuard(m_InitLock); //destroy CTimer.EventLock if (!m_bGCStatus) return 0; m_bClosing = true; m_GCStopCond.Set(); m_GCThread.Join(); m_GCThread.Join(); m_GCStopLock.Close(); m_GCStopCond.Close(); m_bGCStatus = false; return 0; }
// Functionality: // Start listening to any connection request. // Parameters: // None. // Returned value: // None. public void listen() { CGuard cg = new CGuard(m_ConnectionLock); if (!m_bOpened) throw new CUDTException(5, 0, 0); if (m_bConnected) throw new CUDTException(5, 2, 0); // listen can be called more than once if (m_bListening) return; // if there is already another socket listening on the same port if (m_pRcvQueue.setListener(this) < 0) throw new CUDTException(5, 11, 0); m_bListening = true; }