private void ProcessPendingReliableTransactions()
{
try
{
m_reliablesThreadRunning = true;
while (!m_closed)
{
if (m_reliableTransmissions.Count == 0)
{
// No request retransmissions in progress close down thread until next one required.
m_reliablesThreadRunning = false;
break;
}
try
{
List<string> completedTransactions = new List<string>();
lock (m_reliableTransmissions)
{
foreach (SIPTransaction transaction in m_reliableTransmissions.Values)
{
if (!transaction.DeliveryPending)
{
completedTransactions.Add(transaction.TransactionId);
}
else if (transaction.TransactionState == SIPTransactionStatesEnum.Terminated ||
transaction.TransactionState == SIPTransactionStatesEnum.Confirmed ||
transaction.TransactionState == SIPTransactionStatesEnum.Cancelled ||
transaction.HasTimedOut)
{
transaction.DeliveryPending = false;
completedTransactions.Add(transaction.TransactionId);
}
else
{
if (DateTime.Now.Subtract(transaction.InitialTransmit).TotalMilliseconds >= m_t6)
{
//logger.Debug("Request timed out " + transaction.TransactionRequest.Method + " " + transaction.TransactionRequest.URI.ToString() + ".");
transaction.DeliveryPending = false;
transaction.DeliveryFailed = true;
transaction.TimedOutAt = DateTime.Now;
transaction.HasTimedOut = true;
transaction.FireTransactionTimedOut();
completedTransactions.Add(transaction.TransactionId);
}
else
{
double nextTransmitMilliseconds = Math.Pow(2, transaction.Retransmits - 1) * m_t1;
nextTransmitMilliseconds = (nextTransmitMilliseconds > m_t2) ? m_t2 : nextTransmitMilliseconds;
//logger.Debug("Time since retransmit " + transaction.Retransmits + " for " + transaction.TransactionRequest.Method + " " + transaction.TransactionRequest.URI.ToString() + " " + DateTime.Now.Subtract(transaction.LastTransmit).TotalMilliseconds + ".");
if (DateTime.Now.Subtract(transaction.LastTransmit).TotalMilliseconds >= nextTransmitMilliseconds)
{
transaction.Retransmits = transaction.Retransmits + 1;
transaction.LastTransmit = DateTime.Now;
if (transaction.TransactionType == SIPTransactionTypesEnum.Invite && transaction.TransactionState == SIPTransactionStatesEnum.Completed)
{
//logger.Debug("Retransmit " + transaction.Retransmits + "(" + transaction.TransactionId + ") for INVITE reponse " + transaction.TransactionRequest.URI.ToString() + ", last=" + DateTime.Now.Subtract(transaction.LastTransmit).TotalMilliseconds + "ms, first=" + DateTime.Now.Subtract(transaction.InitialTransmit).TotalMilliseconds + "ms.");
// This is an INVITE transaction that wants to send a reliable response, once the ACK is received it will change the transaction state to confirmed.
//SIPViaHeader topViaHeader = transaction.TransactionFinalResponse.Header.Vias.TopViaHeader;
//SendResponse(transaction.TransactionFinalResponse);
//transaction.ResponseRetransmit();
transaction.RetransmitFinalResponse();
}
else
{
//logger.Debug("Retransmit " + transaction.Retransmits + " for request " + transaction.TransactionRequest.Method + " " + transaction.TransactionRequest.URI.ToString() + ", last=" + DateTime.Now.Subtract(transaction.LastTransmit).TotalMilliseconds + "ms, first=" + DateTime.Now.Subtract(transaction.InitialTransmit).TotalMilliseconds + "ms.");
if (transaction.OutboundProxy != null)
{
SendRequest(transaction.OutboundProxy, transaction.TransactionRequest);
}
else
{
SendRequest(transaction.RemoteEndPoint, transaction.TransactionRequest);
}
transaction.RequestRetransmit();
}
}
}
}
}
// Remove timed out or complete transactions from reliable transmissions list.
if (completedTransactions.Count > 0)
{
foreach (string transactionId in completedTransactions)
{
if (m_reliableTransmissions.ContainsKey(transactionId))
{
m_reliableTransmissions.Remove(transactionId);
}
}
}
}
}
catch (Exception excp)
{
logger.Error("Exception SIPTransport ProcessPendingRequests checking pendings. " + excp.Message);
}
Thread.Sleep(PENDINGREQUESTS_CHECK_PERIOD);
}
//logger.Warn("SIPTransport process reliable transmissions thread stopped.");
}
catch (Exception excp)
{
logger.Error("Exception SIPTransport ProcessPendingRequests. " + excp.Message);
}
finally
{
m_reliablesThreadRunning = false;
}
}