Subject: [AAA-WG]: Resolution of Issue #394

From: Bernard Aboba <[email-masked]>
Date: Fri, 20 Dec 2002 09:57:53 -0800 (PST)

Issue 394 relates to the Transport state machine. The Transport document
has gone through IETF last call and IESG review, and has been appoved as a
Proposed Standard. Therefore changes are somewhat painful to make at this
time.

However, Issue 394 seems substantive to be worth resolving. The proposed
fix is as to revise the code and state machine as follows:

SetWatchdog()
{
/*
 SetWatchdog() is called whenever it is necessary
 to reset the watchdog timer Tw. The value of the
 watchdog timer is calculated based on the default
 initial value TWINIT and a jitter ranging from
 -2 to 2 seconds. The default for TWINIT is 30 seconds,
 and MUST NOT be set lower than 6 seconds.
*/
    Tw=TWINIT -2.0 + 4.0 * random() ;
    SetTimer(Tw) ;
    return ;
}

/*
 OnReceive() is called whenever a message
 is received from the peer. This message MAY
 be a request or an answer, and can include
 DWR and DWA messages. Pending is assumed to
 be a global variable.
*/
OnReceive(pcb, msgType)
{
   if (msgType == DWA) {
        Pending = FALSE;
        }
   switch (pcb->Status){
   case OKAY:
        SetWatchdog();
        break;
   case SUSPECT:
        pcb->Status = OKAY;
        Failback(pcb);
        SetWatchdog();
        break;
   case REOPEN:
        if (msgType == DWA) {
           NumDWA++;
           if (NumDWA == 3) {
              pcb->status = OKAY;
              Failback();
           }
        } else {
           Throwaway(received packet);
        }
        break;
   case INITIAL:
   case DOWN:
        Throwaway(received packet);
        break;
   default:
        Error("Shouldn't be here!");
        break;
   }
}

/*
OnTimerElapsed() is called whenever Tw reaches zero (0).
*/
OnTimerElapsed(pcb)
{
    switch (pcb->status){
       case OKAY:
          if (!Pending) {
             SendWatchdog(pbc);
             SetWatchdog();
             Pending = TRUE;
             break;
          }
          pcb->status = SUSPECT;
          FailOver(pcb);
          SetWatchdog();
          break ;
       case SUSPECT:
          pcb->status = DOWN;
          CloseConnection(pcb);
          SetWatchdog();
          break;
       case INITIAL:
       case DOWN:
          AttemptOpen(pcb);
          SetWatchdog();
          break;
       case REOPEN:
          if (!Pending) {
             SendWatchdog(pbc);
             SetWatchdog();
             Pending = TRUE;
             break;
          }
          if (NumDWA < 0) {
             pcb->status = DOWN;
             CloseConnection(pcb);
          } else {
             NumDWA = -1;
          }
          SetWatchdog();
          break;
       default:
          error("Shouldn't be here!);
          break;
       }
}

/*
OnConnectionUp() is called whenever a connection comes up
*/
OnConnectionUp(pcb)
{
    switch (pcb->status){
       case INITIAL:
          pcb->status = OKAY;
          SetWatchdog();
          break;
       case DOWN:
          pcb->status = REOPEN;
          NumDWA = 0;
          SendWatchdog(pcb);
          SetWatchdog();
          Pending = TRUE;
          break;
       default:
          error("Shouldn't be here!);
          break;
       }
}

/*
OnConnectionDown() is called whenever a connection goes down
*/
OnConnectionDown(pcb)
{
    pcb->status = DOWN;
    CloseConnection();
    switch (pcb->status){
       case OKAY:
          Failover(pcb);
          SetWatchdog();
          break;
       case INITIAL:
       case SUSPECT:
       case REOPEN:
          SetWatchdog();
          break;
       case DOWN:
          break;
       default:
          error("Shouldn't be here!);
          break;
       }
}

/* Here is the state machine

STATE         Event                Actions              New State
=====         ------               -------              ----------
OKAY          Receive DWA          Pending = FALSE
                                   SetWatchdog()        OKAY
OKAY          Receive non-DWA      SetWatchdog()        OKAY
SUSPECT       Receive DWA          Pending = FALSE
                                   SetWatchdog()
                                   Failback()           OKAY
REOPEN        Receive DWA &        Pending = FALSE
              NumDWA == 2          NumDWA++
                                   Failback()           OKAY
REOPEN        Receive DWA &        Pending = FALSE
              NumDWA < 2           NumDWA++             REOPEN
REOPEN        Receive Non DWA      Throwaway()          REOPEN
INITIAL       Receive DWA          Pending = FALSE
                                   Throwaway()          INITIAL
INITIAL       Receive non-DWA      Throwaway()          INITIAL
DOWN          Receive DWA          Pending = FALSE
                                   Throwaway()          DOWN
DOWN          Receive non-DWA      Throwaway()          DOWN
OKAY          Timer expires &      SendWatchdog()
              !Pending             SetWatchdog()
                                   Pending = TRUE       OKAY
OKAY          Timer expires &      FailOver()
              Pending              SetWatchdog()        SUSPECT
SUSPECT       Timer expires        CloseConnection()
                                   SetWatchdog()        DOWN
INITIAL       Timer expires        AttemptOpen()
                                   SetWatchdog()        INITIAL
DOWN          Timer expires        AttemptOpen()
                                   SetWatchdog()        DOWN
REOPEN        Timer expires &      SendWatchdog()
              !Pending             SetWatchdog()
                                   Pending = TRUE       REOPEN
REOPEN        Timer expires &      CloseConnection()
              Pending &            SetWatchdog
              NumDWA < 0                                DOWN
REOPEN        Timer expires &      NumDWA = -1
              Pending &            SetWatchdog()
              NumDWA >= 0                               REOPEN
INITIAL       Connection up        SetWatchDog()        OKAY
DOWN          Connection up        NumDWA = 0
                                   SendWatchdog()
                                   SetWatchdog()
                                   Pending = TRUE       REOPEN
OKAY          Connection down      CloseConnection()
                                   Failover()
                                   SetWatchdog()        DOWN
SUSPECT       Connection down      CloseConnection()
                                   SetWatchdog()        DOWN
REOPEN        Connection down      CloseConnection()
                                   SetWatchdog()        DOWN
DOWN          Connection down      CloseConnection()    DOWN
INITIAL       Connection down      CloseConnection()
                                   SetWatchdog()        DOWN
*/