LogPrint(eLogWarning,"Streaming: packet was not ACKed after ",MAX_NUM_RESEND_ATTEMPTS," attempts, terminate, rSID=",m_RecvStreamID,", sSID=",m_SendStreamID);
LogPrint(eLogWarning,"Streaming: SYNACK packet was not ACKed after ",m_NumResendAttempts," attempts, terminate, rSID=",m_RecvStreamID,", sSID=",m_SendStreamID);
m_Status=eStreamStatusReset;
m_Status=eStreamStatusReset;
Close();
Close();
return;
return;
}
}
if(m_NumResendAttempts>=MAX_NUM_RESEND_ATTEMPTS)
{
LogPrint(eLogWarning,"Streaming: packet was not ACKed after ",MAX_NUM_RESEND_ATTEMPTS," attempts, terminate, rSID=",m_RecvStreamID,", sSID=",m_SendStreamID);
m_Status=eStreamStatusReset;
Close();
return;
}
// collect packets to resend
// collect packets to resend
autots=i2p::util::GetMillisecondsSinceEpoch();
autots=i2p::util::GetMillisecondsSinceEpoch();
std::vector<Packet*>packets;
std::vector<Packet*>packets;
if(m_IsNAcked)
if(m_IsNAcked)
{
for(autoit:m_NACKedPackets)
{
{
for(autoit:m_NACKedPackets)
if(ts>=it->sendTime+m_RTO)
{
{
if(ts>=it->sendTime+m_RTO)
if(ts<it->sendTime+m_RTO*2)
{
it->resent=true;
if(ts<it->sendTime+m_RTO*2)
else
it->resent=true;
it->resent=false;
else
it->sendTime=ts;
it->resent=false;
packets.push_back(it);
it->sendTime=ts;
if((int)packets.size()>=m_NumPacketsToSend)break;
packets.push_back(it);
if((int)packets.size()>=m_NumPacketsToSend)break;
}
}
}
}
}
else
}
else
{
for(autoit:m_SentPackets)
{
{
for(autoit:m_SentPackets)
if(ts>=it->sendTime+m_RTO)
{
{
if(ts>=it->sendTime+m_RTO)
if(ts<it->sendTime+m_RTO*2)
{
it->resent=true;
if(ts<it->sendTime+m_RTO*2)
else
it->resent=true;
it->resent=false;
else
it->sendTime=ts;
it->resent=false;
packets.push_back(it);
it->sendTime=ts;
if((int)packets.size()>=m_NumPacketsToSend)break;
packets.push_back(it);
if((int)packets.size()>=m_NumPacketsToSend)break;
}
}
}
}
}
}
// select tunnels if necessary and send
// select tunnels if necessary and send
if(packets.size()>0&&m_IsSendTime)
if(packets.size()>0&&m_IsSendTime)
{
if(m_IsNAcked)m_NumResendAttempts=1;
elseif(m_IsTimeOutResend)m_NumResendAttempts++;
if(m_NumResendAttempts==1&&m_RTO!=INITIAL_RTO)
{
// loss-based CC
if(!m_IsWinDropped&&LOSS_BASED_CONTROL_ENABLED)
ProcessWindowDrop();
}
elseif(m_IsTimeOutResend)
{
{
if(m_IsNAcked)m_NumResendAttempts=1;
m_IsTimeOutResend=false;
elseif(m_IsTimeOutResend)m_NumResendAttempts++;
m_RTO=INITIAL_RTO;// drop RTO to initial upon tunnels pair change