// Functionality: // Connect to a UDT entity listening at address "peer", which has sent "hs" request. // Parameters: // 0) [in] peer: The address of the listening UDT entity. // 1) [in/out] hs: The handshake information sent by the peer side (in), negotiated value (out). // Returned value: // None. public void connect(IPAddress peer, CHandShake hs) { // Type 0 (handshake) control packet CPacket initpkt; CHandShake ci; memcpy(&ci, hs, sizeof(CHandShake)); initpkt.pack(0, null, &ci, sizeof(CHandShake)); // Uses the smaller MSS between the peers if (ci.m_iMSS > m_iMSS) ci.m_iMSS = m_iMSS; else m_iMSS = ci.m_iMSS; // exchange info for maximum flow window size m_iFlowWindowSize = ci.m_iFlightFlagSize; ci.m_iFlightFlagSize = (m_iRcvBufSize < m_iFlightFlagSize)? m_iRcvBufSize : m_iFlightFlagSize; m_iPeerISN = ci.m_iISN; m_iRcvLastAck = ci.m_iISN; m_iRcvLastAckAck = ci.m_iISN; m_iRcvCurrSeqNo = ci.m_iISN - 1; m_PeerID = ci.m_iID; ci.m_iID = m_SocketID; // use peer's ISN and send it back for security check m_iISN = ci.m_iISN; m_iLastDecSeq = m_iISN - 1; m_iSndLastAck = m_iISN; m_iSndLastDataAck = m_iISN; m_iSndCurrSeqNo = m_iISN - 1; m_iSndLastAck2 = m_iISN; m_ullSndLastAck2Time = CClock.getTime(); // this is a reponse handshake ci.m_iReqType = -1; // get local IP address and send the peer its IP address (because UDP cannot get local IP address) memcpy(m_piSelfIP, ci.m_piPeerIP, 16); CIPAddress.ntop(peer, ci.m_piPeerIP, m_iIPversion); // Save the negotiated configurations. memcpy(hs, &ci, sizeof(CHandShake)); m_iPktSize = m_iMSS - 28; m_iPayloadSize = m_iPktSize - CPacket.m_iPktHdrSize; // Prepare all structures try { m_pSndBuffer = new CSndBuffer(32, m_iPayloadSize); m_pRcvBuffer = new CRcvBuffer(m_iRcvBufSize, &(m_pRcvQueue.m_UnitQueue)); 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 = (long)(m_pCC.m_dPktSndPeriod * m_ullCPUFrequency); m_dCongestionWindow = m_pCC.m_dCWndSize; CInfoBlock ib; if (m_pCache.lookup(peer, 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 = peer; //m_pPeerAddr = (AF_INET == m_iIPversion) ? (sockaddr*)new sockaddr_in : (sockaddr*)new sockaddr_in6; //memcpy(m_pPeerAddr, peer, (AF_INET == m_iIPversion) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6)); // And of course, it is connected. m_bConnected = true; // register this socket for receiving data packets m_pRcvQueue.setNewEntry(this); }
internal CRNode m_pRNode; // node information for UDT list used in rcv queue #endregion #region constructor and desctructor CUDT(CUDT ancestor) { m_pSndBuffer = null; m_pRcvBuffer = null; m_pSndLossList = null; m_pRcvLossList = null; m_pACKWindow = null; m_pSndTimeWindow = null; m_pRcvTimeWindow = null; m_pSndQueue = null; m_pRcvQueue = null; m_pPeerAddr = null; m_pSNode = null; m_pRNode = null; // Initilize mutex and condition variables initSynch(); // Default UDT configurations m_iMSS = ancestor.m_iMSS; m_bSynSending = ancestor.m_bSynSending; m_bSynRecving = ancestor.m_bSynRecving; m_iFlightFlagSize = ancestor.m_iFlightFlagSize; m_iSndBufSize = ancestor.m_iSndBufSize; m_iRcvBufSize = ancestor.m_iRcvBufSize; m_Linger = ancestor.m_Linger; m_iUDPSndBufSize = ancestor.m_iUDPSndBufSize; m_iUDPRcvBufSize = ancestor.m_iUDPRcvBufSize; m_iSockType = ancestor.m_iSockType; m_iIPversion = ancestor.m_iIPversion; m_bRendezvous = ancestor.m_bRendezvous; m_iSndTimeOut = ancestor.m_iSndTimeOut; m_iRcvTimeOut = ancestor.m_iRcvTimeOut; m_bReuseAddr = true; // this must be true, because all accepted sockets shared the same port with the listener m_llMaxBW = ancestor.m_llMaxBW; m_pCCFactory = ancestor.m_pCCFactory.clone(); m_pCC = null; m_pCache = ancestor.m_pCache; // Initial status m_bOpened = false; m_bListening = false; m_bConnected = false; m_bClosing = false; m_bShutdown = false; m_bBroken = false; }
// 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); }