// Functionality: // Receive a packet from the channel and record the source address. // Parameters: // 0) [in] addr: pointer to the source address. // 1) [in] packet: reference to a CPacket entity. // Returned value: // Actual size of data received. public int recvfrom(IPAddress addr, CPacket packet) { DWORD size = CPacket.m_iPktHdrSize + packet.getLength(); DWORD flag = 0; int addrsize = (AF_INET == m_iIPversion) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6); int res = WSARecvFrom(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, &flag, addr, &addrsize, null, null); res = (0 == res) ? size : -1; if (res <= 0) { packet.setLength(-1); return -1; } packet.setLength(res - CPacket.m_iPktHdrSize); // convert back into local host order //for (int i = 0; i < 4; ++ i) // packet.m_nHeader[i] = ntohl(packet.m_nHeader[i]); uint* p = packet.m_nHeader; for (int i = 0; i < 4; ++ i) { *p = ntohl(*p); ++ p; } if (packet.getFlag()) for (int j = 0, n = packet.getLength() / 4; j < n; ++ j) *((uint *)packet.m_pcData + j) = ntohl(*((uint *)packet.m_pcData + j)); return packet.getLength(); }
// Functionality: // Send out a packet to a given address. // Parameters: // 1) [in] addr: destination address // 2) [in] packet: packet to be sent out // Returned value: // Size of data sent out. public int sendto(IPEndPoint addr, CPacket packet) { // send out the packet immediately (high priority), this is a control packet m_pChannel.sendto(addr, packet); return packet.getLength(); }
public void storePkt(Int32 id, CPacket pkt) { m_PassLock.WaitOne(-1); // if the packet already exists for the ID // then replace it, otherwise, add it if (m_mBuffer.ContainsKey(id)) { m_mBuffer.Remove(id); } m_mBuffer.Add(id, pkt); m_PassLock.ReleaseMutex(); m_PassCond.Set(); }
// Functionality: // Send a packet to the given address. // Parameters: // 0) [in] addr: pointer to the destination address. // 1) [in] packet: reference to a CPacket entity. // Returned value: // Actual size of data sent. public int sendto(IPEndPoint addr, CPacket packet) { // convert control information into network order if (packet.getFlag() > 0) for (int i = 0, n = packet.getLength() / 4; i < n; ++ i) *((uint *)packet.m_pcData + i) = htonl(*((uint *)packet.m_pcData + i)); // convert packet header into network order //for (int j = 0; j < 4; ++ j) // packet.m_nHeader[j] = htonl(packet.m_nHeader[j]); uint* p = packet.m_nHeader; for (int j = 0; j < 4; ++ j) { *p = htonl(*p); ++ p; } DWORD size = CPacket.m_iPktHdrSize + packet.getLength(); //int addrsize = (AF_INET == m_iIPversion) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6); //int res = WSASendTo(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, 0, addr, addrsize, null, null); //int res = m_iSocket.SendTo(Buffer, addr); int res = m_iSocket.SendTo(Buffer, 0, size, SocketFlags.None, addr); res = (0 == res) ? size : -1; // convert back into local host order //for (int k = 0; k < 4; ++ k) // packet.m_nHeader[k] = ntohl(packet.m_nHeader[k]); p = packet.m_nHeader; for (int k = 0; k < 4; ++ k) { *p = ntohl(*p); ++ p; } if (packet.getFlag() > 0) for (int l = 0, n = packet.getLength() / 4; l < n; ++ l) packet.m_pcData[l] = ntohl(packet.m_pcData[l]); return res; }
// Functionality: // Clone this packet. // Parameters: // None. // Returned value: // Pointer to the new packet. CPacket clone() { CPacket pkt = new CPacket(); m_nHeader.CopyTo(pkt.m_nHeader, m_iPktHdrSize); //pkt.m_pcData = new byte[m_PacketVector[1].iov_len]; //memcpy(pkt.m_pcData, m_pcData, m_PacketVector[1].iov_len); pkt.m_PacketVector[1].iov_len = m_PacketVector[1].iov_len; return pkt; }
// 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; }
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; } }
// Functionality: // Send a user defined control packet. // Parameters: // 0) [in] pkt: user defined packet. // Returned value: // None. protected void sendCustomMsg(CPacket pkt) { CUDT u = CUDT.getUDTHandle(m_UDT); if (null != u) { pkt.m_iID = u.m_PeerID; u.m_pSndQueue.sendto(u.m_pPeerAddr, pkt); } }
// Functionality: // Callback function to Process a user defined packet. // Parameters: // 0) [in] pkt: the user defined packet. // Returned value: // None. public virtual void processCustomMsg(CPacket packet) { }
// Functionality: // Callback function to be called when a data is received. // Parameters: // 0) [in] packet: the packet, including sequence number, and payload size. // Returned value: // None. public virtual void onPktReceived(CPacket packet) { }
// Functionality: // Callback function to be called when a data is sent. // Parameters: // 0) [in] seqno: the data sequence number. // 1) [in] size: the payload size. // Returned value: // None. public virtual void onPktSent(CPacket packet) { }