ns-allinone-2.35/sctp/sctp-cmt.cc
SctpDest_S*  SctpCMTAgent::SelectFromPFDests()
{
  
  int iLeastErrorCount = (int) uiPathMaxRetrans; 
  double dMostRecentPFSince = 0; 
  Node_S *spCurrDestNode = NULL;
  SctpDest_S* spCurrDestNodeData = NULL;
  SctpDest_S* spSelectedDest = NULL;
  
  for(spCurrDestNode = sDestList.spHead;
      spCurrDestNode != NULL;
      spCurrDestNode = spCurrDestNode->spNext)
    { 
      spCurrDestNodeData = (SctpDest_S *) spCurrDestNode->vpData;
      
      if (spCurrDestNodeData->eStatus == SCTP_DEST_STATUS_POSSIBLY_FAILED)
	{
	  if (spCurrDestNodeData->iErrorCount < iLeastErrorCount) 
	    {
	      spSelectedDest = spCurrDestNodeData;
	      iLeastErrorCount = spCurrDestNodeData->iErrorCount;
	      dMostRecentPFSince = spCurrDestNodeData->dPFSince;
	    }
	  else if (spCurrDestNodeData->iErrorCount == iLeastErrorCount)
	    {
	      if (spCurrDestNodeData->dPFSince > dMostRecentPFSince)
		{
		  spSelectedDest = spCurrDestNodeData;
		  iLeastErrorCount = spCurrDestNodeData->iErrorCount;
		  dMostRecentPFSince = spCurrDestNodeData->dPFSince;
		}
	      else if (spCurrDestNodeData->dPFSince == dMostRecentPFSince)
		{
		  if (Random::random()&01)
		    spSelectedDest = spCurrDestNodeData;
		}
	    } 
	  
	} 
      else 
	{
	  /* Found a non-PF dest, return NULL 
	   */
	  return NULL;
	  
	}
      
    } 

  /* A PF destination was selected to be marked Active
   */
  if (spSelectedDest->eRtxTimerIsRunning == TRUE)
    StopT3RtxTimer(spSelectedDest);
  
  spSelectedDest->opHeartbeatTimeoutTimer->force_cancel();
  spSelectedDest->eHBTimerIsRunning = FALSE;
  
  spSelectedDest->iCwnd = 1*uiMaxDataSize;
  
  spSelectedDest->eStatus = SCTP_DEST_STATUS_ACTIVE;
  spSelectedDest->dPFSince = 0;
  
  //  DBG_PL(SelectFromPFDests, "Dest: %p changed from PF to Active"),
  // spSelectedDest  DBG_PR;
  
  return spSelectedDest;

}
/* New CMT-PF method:
 *
 * If all destinations are marked PF, send data to one of
 * the destinations so that CMT-PF does not perform worse than
 * CMT.  
 *
 * Algorithm to select the PF destination:
 *   Select the dest with the least error count.
 *   If tie in errorcount values, then all destinations
 *   have "Possibly failed" to the same degree. So, select dest
 *   that was most recently active (marked PF most recently). 
 *
 * Implementation: 
 * If atleast 1 non-PF dest exists, return NULL
 * else, 
 *	- select a dest based on the above algo.
 * 	- set cwnd on the selected PF dest to 1 MTU
 * 	- stop the HB timer if it is running. - hb goes to blackhole !
 *	  hb loss cannot be detected. But, if hb-ack comes back,
 *	  errorcount for the destination is cleared. Situation is
 *	  similar to an ACTIVE dest recving hb. 
 * 	- set eRtxTimerIsRunning to false -- when data is sent, 
 * 	  T3RTX timer be started by RtxMarkedChunks or GenOneDataChunk.
 *	- change dest status to ACTIVE. This dest status is just for
 *	  easier implementation and does not change anything in the
 *	  CMT-PF details. This implementation uses the following rule:
 *		If a dest is PF, only HBs are sent
 *		If a dest is ACTIVE, data is sent
 *	- Schedule HeartbeatGenTimer 
 *
 * Note: This implementation can be considered _aggressive_,
 * since, on the selected PF dest, a HB could've been sent and
 * before HB-ACK arrives, 1MTU of data will be sent.  
 * MAYBE, this aggressiveness can be
 * avoided with a better implementation - do not send HB on
 * a destination with the least error count? 
 */
New CMT-PF method:
If all destinations are marked PF, send data to one of
the destinations so that CMT-PF does not perform worse than
CMT.

Algorithm to select the PF destination:
Select the dest with the least error count.
If tie in errorcount values, then all destinations
have "Possibly failed" to the same degree. So, select dest
that was most recently active (marked PF most recently).

If atleast 1 non-PF dest exists, return NULL
else,
- select a dest based on the above algo.
- set cwnd on the selected PF dest to 1 MTU
- stop the HB timer if it is running. - hb goes to blackhole .
hb loss cannot be detected. But, if hb-ack comes back,
errorcount for the destination is cleared. Situation is
similar to an ACTIVE dest recving hb.
- set eRtxTimerIsRunning to false -- when data is sent,
T3RTX timer be started by RtxMarkedChunks or GenOneDataChunk.
- change dest status to ACTIVE. This dest status is just for
easier implementation and does not change anything in the
CMT-PF details. This implementation uses the following rule:
If a dest is PF, only HBs are sent
If a dest is ACTIVE, data is sent
- Schedule HeartbeatGenTimer

This implementation can be considered _aggressive_,
since, on the selected PF dest, a HB could've been sent and
before HB-ACK arrives, 1MTU of data will be sent.
New CMT - PF method : If all destinations are marked PF send data to one of the destinations so that CMT - PF does not perform worse than CMT . Algorithm to select the PF destination : Select the dest with the least error count . If tie in errorcount values then all destinations have " Possibly failed " to the same degree . So select dest that was most recently active ( marked PF most recently ) . If atleast 1 non - PF dest exists return NULL else - select a dest based on the above algo . - set cwnd on the selected PF dest to 1 MTU - stop the HB timer if it is running . - hb goes to blackhole . hb loss cannot be detected . But if hb - ack comes back errorcount for the destination is cleared . Situation is similar to an ACTIVE dest recving hb . - set eRtxTimerIsRunning to false -- when data is sent T3RTX timer be started by RtxMarkedChunks or GenOneDataChunk . - change dest status to ACTIVE . This dest status is just for easier implementation and does not change anything in the CMT - PF details . This implementation uses the following rule : If a dest is PF only HBs are sent If a dest is ACTIVE data is sent - Schedule HeartbeatGenTimer This implementation can be considered _aggressive_ since on the selected PF dest a HB could ' ve been sent and before HB - ACK arrives 1MTU of data will be sent .
SctpDest_S*  SctpCMTAgent::SelectFromPFDests()
{
  int iLeastErrorCount = (int) uiPathMaxRetrans; 
  double dMostRecentPFSince = 0; 
  Node_S *spCurrDestNode = NULL;
  SctpDest_S* spCurrDestNodeData = NULL;
  SctpDest_S* spSelectedDest = NULL;
  for(spCurrDestNode = sDestList.spHead;
      spCurrDestNode != NULL;
      spCurrDestNode = spCurrDestNode->spNext)
    { 
      spCurrDestNodeData = (SctpDest_S *) spCurrDestNode->vpData;
      if (spCurrDestNodeData->eStatus == SCTP_DEST_STATUS_POSSIBLY_FAILED)
	{
	  if (spCurrDestNodeData->iErrorCount < iLeastErrorCount) 
	    {
	      spSelectedDest = spCurrDestNodeData;
	      iLeastErrorCount = spCurrDestNodeData->iErrorCount;
	      dMostRecentPFSince = spCurrDestNodeData->dPFSince;
	    }
	  else if (spCurrDestNodeData->iErrorCount == iLeastErrorCount)
	    {
	      if (spCurrDestNodeData->dPFSince > dMostRecentPFSince)
		{
		  spSelectedDest = spCurrDestNodeData;
		  iLeastErrorCount = spCurrDestNodeData->iErrorCount;
		  dMostRecentPFSince = spCurrDestNodeData->dPFSince;
		}
	      else if (spCurrDestNodeData->dPFSince == dMostRecentPFSince)
		{
		  if (Random::random()&01)
		    spSelectedDest = spCurrDestNodeData;
		}
	    } 
	} 
      else 
	{
	  return NULL;
	}
    } 
  if (spSelectedDest->eRtxTimerIsRunning == TRUE)
    StopT3RtxTimer(spSelectedDest);
  spSelectedDest->opHeartbeatTimeoutTimer->force_cancel();
  spSelectedDest->eHBTimerIsRunning = FALSE;
  spSelectedDest->iCwnd = 1*uiMaxDataSize;
  spSelectedDest->eStatus = SCTP_DEST_STATUS_ACTIVE;
  spSelectedDest->dPFSince = 0;
  return spSelectedDest;
}
SctpDest_S * SctpCMTAgent :: SelectFromPFDests ( ) { int iLeastErrorCount = ( int ) uiPathMaxRetrans ; double dMostRecentPFSince = 0 ; Node_S * spCurrDestNode = NULL ; SctpDest_S * spCurrDestNodeData = NULL ; SctpDest_S * spSelectedDest = NULL ; for ( spCurrDestNode = sDestList . spHead ; spCurrDestNode != NULL ; spCurrDestNode = spCurrDestNode -> spNext ) { spCurrDestNodeData = ( SctpDest_S * ) spCurrDestNode -> vpData ; if ( spCurrDestNodeData -> eStatus == SCTP_DEST_STATUS_POSSIBLY_FAILED ) { if ( spCurrDestNodeData -> iErrorCount < iLeastErrorCount ) { spSelectedDest = spCurrDestNodeData ; iLeastErrorCount = spCurrDestNodeData -> iErrorCount ; dMostRecentPFSince = spCurrDestNodeData -> dPFSince ; } else if ( spCurrDestNodeData -> iErrorCount == iLeastErrorCount ) { if ( spCurrDestNodeData -> dPFSince > dMostRecentPFSince ) { spSelectedDest = spCurrDestNodeData ; iLeastErrorCount = spCurrDestNodeData -> iErrorCount ; dMostRecentPFSince = spCurrDestNodeData -> dPFSince ; } else if ( spCurrDestNodeData -> dPFSince == dMostRecentPFSince ) { if ( Random :: random ( ) & 01 ) spSelectedDest = spCurrDestNodeData ; } } } else { return NULL ; } } if ( spSelectedDest -> eRtxTimerIsRunning == TRUE ) StopT3RtxTimer ( spSelectedDest ) ; spSelectedDest -> opHeartbeatTimeoutTimer -> force_cancel ( ) ; spSelectedDest -> eHBTimerIsRunning = FALSE ; spSelectedDest -> iCwnd = 1 * uiMaxDataSize ; spSelectedDest -> eStatus = SCTP_DEST_STATUS_ACTIVE ; spSelectedDest -> dPFSince = 0 ; return spSelectedDest ; }
New CMT-PF method:
 If all destinations are marked PF, send data to one of
 the destinations so that CMT-PF does not perform worse than
 CMT.
New CMT - PF method : If all destinations are marked PF send data to one of the destinations so that CMT - PF does not perform worse than CMT .
/* Found a non-PF dest, return NULL 
	   */ /* A PF destination was selected to be marked Active
   */ //  DBG_PL(SelectFromPFDests, "Dest: %p changed from PF to Active"), // spSelectedDest  DBG_PR;