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; }
void processCtrl(CPacket ctrlpkt) { // Just heard from the peer, reset the expiration count. m_iEXPCount = 1; if ((CSeqNo.incseq(m_iSndCurrSeqNo) == m_iSndLastAck) || (2 == ctrlpkt.getType()) || (3 == ctrlpkt.getType())) { m_ullEXPInt = m_ullMinEXPInt; CClock.rdtsc(out m_ullNextEXPTime); m_ullNextEXPTime += m_ullEXPInt; } switch (ctrlpkt.getType()) { case 2: //010 - Acknowledgement { Int32 ack; // process a lite ACK if (4 == ctrlpkt.getLength()) { ack = *(Int32 *)ctrlpkt.m_pcData; if (CSeqNo.seqcmp(ack, (Int32)(m_iSndLastAck)) >= 0) { m_iFlowWindowSize -= CSeqNo.seqoff((Int32)(m_iSndLastAck), ack); m_iSndLastAck = ack; } break; } // read ACK seq. no. ack = ctrlpkt.getAckSeqNo(); // send ACK acknowledgement // ACK2 can be much less than ACK Int64 currtime = CClock.getTime(); if ((currtime - m_ullSndLastAck2Time > (Int64)m_iSYNInterval) || (ack == m_iSndLastAck2)) { sendCtrl(6, &ack); m_iSndLastAck2 = ack; m_ullSndLastAck2Time = currtime; } // Got data ACK ack = *(Int32 *)ctrlpkt.m_pcData; // check the validation of the ack if (CSeqNo.seqcmp(ack, CSeqNo.incseq(m_iSndCurrSeqNo)) > 0) { //this should not happen: attack or bug m_bBroken = true; m_iBrokenCounter = 0; break; } if (CSeqNo.seqcmp(ack, (Int32)(m_iSndLastAck)) >= 0) { // Update Flow Window Size, must update before and together with m_iSndLastAck m_iFlowWindowSize = *((Int32 *)ctrlpkt.m_pcData + 3); m_iSndLastAck = ack; } // protect packet retransmission CGuard.enterCS(m_AckLock); int offset = CSeqNo.seqoff((Int32)m_iSndLastDataAck, ack); if (offset <= 0) { // discard it if it is a repeated ACK CGuard.leaveCS(m_AckLock); break; } // acknowledge the sending buffer m_pSndBuffer.ackData(offset); // record total time used for sending m_llSndDuration += currtime - m_llSndDurationCounter; m_llSndDurationTotal += currtime - m_llSndDurationCounter; m_llSndDurationCounter = currtime; // update sending variables m_iSndLastDataAck = ack; m_pSndLossList.remove(CSeqNo.decseq((Int32)m_iSndLastDataAck)); CGuard.leaveCS(m_AckLock); if (m_bSynSending) SetEvent(m_SendBlockCond); // insert this socket to snd list if it is not on the list yet m_pSndQueue.m_pSndUList.update(this, false); // Update RTT //m_iRTT = *((Int32 *)ctrlpkt.m_pcData + 1); //m_iRTTVar = *((Int32 *)ctrlpkt.m_pcData + 2); int rtt = *((Int32 *)ctrlpkt.m_pcData + 1); m_iRTTVar = (m_iRTTVar * 3 + abs(rtt - m_iRTT)) >> 2; m_iRTT = (m_iRTT * 7 + rtt) >> 3; m_pCC.setRTT(m_iRTT); m_ullMinEXPInt = (m_iRTT + 4 * m_iRTTVar) * m_ullCPUFrequency + m_ullSYNInt; if (m_ullMinEXPInt < 100000 * m_ullCPUFrequency) m_ullMinEXPInt = 100000 * m_ullCPUFrequency; if (ctrlpkt.getLength() > 16) { // Update Estimated Bandwidth and packet delivery rate if (*((Int32 *)ctrlpkt.m_pcData + 4) > 0) m_iDeliveryRate = (m_iDeliveryRate * 7 + *((Int32 *)ctrlpkt.m_pcData + 4)) >> 3; if (*((Int32 *)ctrlpkt.m_pcData + 5) > 0) m_iBandwidth = (m_iBandwidth * 7 + *((Int32 *)ctrlpkt.m_pcData + 5)) >> 3; m_pCC.setRcvRate(m_iDeliveryRate); m_pCC.setBandwidth(m_iBandwidth); } m_pCC.onACK(ack); // update CC parameters m_ullInterval = (Int64)(m_pCC.m_dPktSndPeriod * m_ullCPUFrequency); m_dCongestionWindow = m_pCC.m_dCWndSize; ++ m_iRecvACK; ++ m_iRecvACKTotal; break; } case 6: //110 - Acknowledgement of Acknowledgement { Int32 ack; int rtt = -1; // update RTT rtt = m_pACKWindow.acknowledge(ctrlpkt.getAckSeqNo(), ack); if (rtt <= 0) break; //if increasing delay detected... // sendCtrl(4); // RTT EWMA m_iRTTVar = (m_iRTTVar * 3 + abs(rtt - m_iRTT)) >> 2; m_iRTT = (m_iRTT * 7 + rtt) >> 3; m_pCC.setRTT(m_iRTT); m_ullMinEXPInt = (m_iRTT + 4 * m_iRTTVar) * m_ullCPUFrequency + m_ullSYNInt; if (m_ullMinEXPInt < 100000 * m_ullCPUFrequency) m_ullMinEXPInt = 100000 * m_ullCPUFrequency; // update last ACK that has been received by the sender if (CSeqNo.seqcmp(ack, m_iRcvLastAckAck) > 0) m_iRcvLastAckAck = ack; break; } case 3: //011 - Loss Report { Int32* losslist = (Int32 *)(ctrlpkt.m_pcData); m_pCC.onLoss(losslist, ctrlpkt.getLength() / 4); // update CC parameters m_ullInterval = (Int64)(m_pCC.m_dPktSndPeriod * m_ullCPUFrequency); m_dCongestionWindow = m_pCC.m_dCWndSize; bool secure = true; // decode loss list message and insert loss into the sender loss list for (int i = 0, n = (int)(ctrlpkt.getLength() / 4); i < n; ++ i) { if (0 != (losslist[i] & 0x80000000)) { if ((CSeqNo.seqcmp(losslist[i] & 0x7FFFFFFF, losslist[i + 1]) > 0) || (CSeqNo.seqcmp(losslist[i + 1], (Int32)(m_iSndCurrSeqNo)) > 0)) { // seq_a must not be greater than seq_b; seq_b must not be greater than the most recent sent seq secure = false; break; } int num = 0; if (CSeqNo.seqcmp(losslist[i] & 0x7FFFFFFF, (Int32)(m_iSndLastAck)) >= 0) num = m_pSndLossList.insert(losslist[i] & 0x7FFFFFFF, losslist[i + 1]); else if (CSeqNo.seqcmp(losslist[i + 1], (Int32)(m_iSndLastAck)) >= 0) num = m_pSndLossList.insert((Int32)(m_iSndLastAck), losslist[i + 1]); m_iTraceSndLoss += num; m_iSndLossTotal += num; ++ i; } else if (CSeqNo.seqcmp(losslist[i], (Int32)(m_iSndLastAck)) >= 0) { if (CSeqNo.seqcmp(losslist[i], (Int32)(m_iSndCurrSeqNo)) > 0) { //seq_a must not be greater than the most recent sent seq secure = false; break; } int num = m_pSndLossList.insert(losslist[i], losslist[i]); m_iTraceSndLoss += num; m_iSndLossTotal += num; } } if (!secure) { //this should not happen: attack or bug m_bBroken = true; m_iBrokenCounter = 0; break; } // the lost packet (retransmission) should be sent out immediately m_pSndQueue.m_pSndUList.update(this); ++ m_iRecvNAK; ++ m_iRecvNAKTotal; break; } case 4: //100 - Delay Warning // One way packet delay is increasing, so decrease the sending rate m_ullInterval = (Int64)ceil(m_ullInterval * 1.125); m_iLastDecSeq = m_iSndCurrSeqNo; break; case 1: //001 - Keep-alive // The only purpose of keep-alive packet is to tell that the peer is still alive // nothing needs to be done. break; case 0: //000 - Handshake if ((((CHandShake*)(ctrlpkt.m_pcData)).m_iReqType > 0) || (m_bRendezvous && (((CHandShake*)(ctrlpkt.m_pcData)).m_iReqType != -2))) { // The peer side has not received the handshake message, so it keeps querying // resend the handshake packet CHandShake initdata; initdata.m_iISN = m_iISN; initdata.m_iMSS = m_iMSS; initdata.m_iFlightFlagSize = m_iFlightFlagSize; initdata.m_iReqType = (!m_bRendezvous) ? -1 : -2; initdata.m_iID = m_SocketID; sendCtrl(0, null, (char *)&initdata, sizeof(CHandShake)); } break; case 5: //101 - Shutdown m_bShutdown = true; m_bClosing = true; m_bBroken = true; m_iBrokenCounter = 60; // Signal the sender and recver if they are waiting for data. releaseSynch(); CClock.triggerEvent(); break; case 7: //111 - Msg drop request m_pRcvBuffer.dropMsg(ctrlpkt.getMsgSeq()); m_pRcvLossList.remove(*(Int32*)ctrlpkt.m_pcData, *(Int32*)(ctrlpkt.m_pcData + 4)); break; case 32767: //0x7FFF - reserved and user defined messages m_pCC.processCustomMsg(&ctrlpkt); // update CC parameters m_ullInterval = (Int64)(m_pCC.m_dPktSndPeriod * m_ullCPUFrequency); m_dCongestionWindow = m_pCC.m_dCWndSize; break; default: break; } }