#  Ring 1.0 --- Software Tools Subsystem Network Utility.
#               R. J. Mongiovi.  04/01/83.
#
#           One  ring  to  rule  them all,
#           One   ring   to   find   them,
#           One  ring  to  bring them all,
#           And in the darkness bind them.
#
#                        J. R. R. Tolkien.

include NET_DEFS
include "ring_def.r.i"

   include RING_COMMON

   external cleanup

   call mkon$f("CLEANUP$", 8, cleanup)

   call initialize

   repeat
   {
      call timdat(Time_info, INFOSIZE)

      call connect
      call accept
      call generate
      call update
      call search
      call examine
      call remove

      call pause
   }

   end


   subroutine accept

#  accept --- determine and accept all connection requests.

   include RING_COMMON

   integer ptoc

   character line(MAXLINE)
   integer name(NAMESIZE), status(2)

   integer vcid, port, size, addr, node, i, j

DB call print(STDOUT, "Checking pending connection requests*n"s)

   repeat
   {
      call xlgcon(XK$NAM, vcid, port, name, 2 * NAMESIZE, i,
                          0, 0, 0, 0, 0, 0, 0, 0, 0, status)

      if (status(1) == XS$CMP)
      {
         size = ptoc(name, " "c, line, i + 1)

         for (i = size + 1; i <= 2 * NAMESIZE; i += 1)
            line(i) = " "c
         line(i) = EOS

         call mapstr(line, UPPER)

         i = 1; call ctop(line, i, name, NAMESIZE)

         addr = 0
         do i = 1, Ring_size
         {
            do j = 1, NAMESIZE
               if (Node_name(j, Index_ring(i)) ~= name(j))
                  next 2

            addr = i
            call print(STDOUT, "Connection received from *,#h*n"s,
               Name_size(Index_ring(i)), Node_name(1, Index_ring(i)))

            break
         }

         if (addr > 0)
         {
            call allocate(node)
            TYPE(node) = BOGUS
            NODE(node) = addr
            VCID(node) = vcid

            select (port)
               when (RING)
                  call verify(node)

               when (CHCK)
                  call respond(node)

               when (USER)
                  call process(node)
         }
         else
         {
            call x$clr(vcid, 0, status)
DB          call print(STDOUT, "Connection from *,#h rejected*n"s,
DB             size, name)
         }
      }
      else
         return
   }

   end


   subroutine allocate(node)

#  allocate --- allocate a virtual circuit block.

   pointer node

   include RING_COMMON

   pointer dsget

   integer i

   Sequence += 1

   node = dsget(NODESIZE + NAMESIZE + PCKTSIZE + MESGSIZE)
DB call print(STDOUT, "Node #*i allocated at *i*n"s, Sequence, node)

   TYPE(node) = CLEAR

   BACK(node) = NULL
   NEXT(node) = NULL

   TIME(node) = ELAPSED

   HOLD(node) = NO
   SENT(node) = NO
   EXEC(node) = NO
   TOLD(node) = NO
   DONE(node) = NO

   NODE(node) = 0
   do i = 1, NAMESIZE
      NAME(i, node) = 0
   PROC(node) = 0
   CODE(node) = Sequence

   VCID(node) = 0
   STAT(node) = XS$CLR
   CLRS(node) = CC$CLR
   XMTS(node) = XS$CLR
   RCVS(node) = XS$CLR
   RCVL(node) = 0
   RCVN(node) = 0

   ANSR(node) = 0
   INDX(node) = 0

   return
   end


   subroutine build

#  build --- determine names of accessable systems.

   include RING_COMMON

   integer ptoc

   character line(MAXLINE)

   integer status, index, i, j, k, l

   call x$stat(XI$ADR, Ring_size, Ring_address, i, Address_size, j, status, k)
DB call print(STDOUT, "Determining *i system names*n"s, Ring_size)

   i = 1
   do j = 1, Ring_size
   {
      Index_ring(j) = j

      Address_index(j) = i
      i += (Address_size(j) + 1) / 2
   }

   do i = 1, Ring_size
   {
      call x$stat(XI$XTP, j, Ring_address(Address_index(i)), Address_size(i),
                             Node_name(1, i), k, status, l)

      Name_size(i) = ptoc(Node_name(1, i), " "c, line, k + 1)

      for (j = Name_size(i) + 1; j <= 2 * NAMESIZE; j += 1)
         line(j) = " "c
      line(j) = EOS

      call mapstr(line, UPPER)

      j = 1; call ctop(line, j, Node_name(1, i), NAMESIZE)
   }

DB call print(STDOUT, "Systems are: "s)
DB do i = 1, Ring_size
DB {
DB    call print(STDOUT, ' "*,#h"'s, Name_size(i), Node_name(1, i))
DB    if (i < Ring_size)
DB       call print(STDOUT, ","s)
DB    else
DB       call print(STDOUT, "*n"s)
DB }

   for (i = Ring_size / 2; i > 0; i /= 2)
      for (j = i + 1; j <= Ring_size; j += 1)
         for (k = j - i; k > 0; k -= i)
         {
            for (l = 1; l < NAMESIZE; l += 1)
               if (Node_name(l, Index_ring(k)) ~= Node_name(l, Index_ring(k + i)))
                  break

            if (Node_name(l, Index_ring(k)) > Node_name(l, Index_ring(k + i)))
            {
               index = Index_ring(k)
               Index_ring(k) = Index_ring(k + i)
               Index_ring(k + i) = index
            }
            else
               break
         }

DB call print(STDOUT, "Sorted order is: "s)
DB do i = 1, Ring_size
DB    call print(STDOUT, " *i"s, Index_ring(i))
DB call print(STDOUT, "*n"s)

   do i = 1, Ring_size
      if (Index_ring(i) == HOME)
      {
         Home_index = i

         break
      }
DB call print(STDOUT, "This system is *i*n"s, Home_index)

   Active_ring = Ring_size
DB call print(STDOUT, "Default ring size is *i*n"s, Active_ring)

   return
   end


   subroutine change(rcv)

#  change --- process and possibly change fields of packet.

   pointer rcv

   include RING_COMMON

   logical valid

   pointer xmt, req

   if (COMMAND(rcv) == INITIALIZE)
   {
      if (PACKET(rcv) == REQUEST)
      {
         COUNT(rcv) += 1
DB       call print(STDOUT, "Count of active systems is *i*n"s, COUNT(rcv))

         if (SOURCE(rcv) == Home_index)
         {
            PACKET(rcv) = RESPONSE
            NUMBER(rcv) = 1
            call print(STDOUT, "Created INITIALIZE response*n"s)
         }
      }

      if (PACKET(rcv) == RESPONSE)
      {
         Active_ring = COUNT(rcv)
DB       call print(STDOUT, "Number of active systems is *i*n"s, Active_ring)

         for (req = NEXT(Request); req ~= Request; req = NEXT(req))
            if (ANSR(req) > Active_ring)
               ANSR(req) = Active_ring

         select (STATE(rcv))
            when (0)
               if (NODE(rcv) > Home_index)
               {
                  SEARCH(Transmit, TYPE, VALID, xmt, DUMMY)

                  if (xmt ~= Transmit && valid(STAT(xmt)) && NODE(xmt) > Home_index)
                     if (Initialized)
                     {
                        STATE(rcv) = 2

                        if (Priviledged)
                        {
                           Synchronize = TRUE
DB                         call print(STDOUT, "This system will synchronize*n"s)
                        }
                     }
                     else
                     {
                        SOURCE(rcv) = Home_index
                        NUMBER(rcv) = 1
                        STATE(rcv) = 1
DB                      call print(STDOUT, "Next initialized system will synchronize*n"s)
                     }
               }

            when (1)
               if (Initialized)
               {
                  STATE(rcv) = 2

                  if (Priviledged)
                  {
                     Synchronize = TRUE
DB                   call print(STDOUT, "This system will synchronize*n"s)
                  }
               }

            when (2)
               ;
      }
   }

   return
   end


   subroutine cleanup(cp)

#  cleanup --- onunit to clean up at end of execution.

   longint cp

   include RING_COMMON

   if (~Terminated)
   {
      call x$clra
DB    call print(STDOUT, "Network cleared*n"s)
   }

   return
   end


   subroutine connect

#  connect --- determine if there is a transmit connection.

   include RING_COMMON

   logical valid

   pointer xmt, rsp

DB call print(STDOUT, "Checking transmission connection*n"s)

   SEARCH(Transmit, TYPE, VALID, xmt, DUMMY)

   if (xmt ~= Transmit)
      if (~valid(STAT(xmt)))
      {
         call print(STDOUT, "Lost transmission to *,#h*n"s,
            Name_size(Index_ring(NODE(xmt))), Node_name(1, Index_ring(NODE(xmt))))

         call delete(xmt)
         call dispose(xmt)
      }
      else
         return

   SEARCH(Transmit, TYPE, BOGUS, xmt, DUMMY)

   if (xmt == Transmit)
   {
      call build

      call allocate(xmt)
      TYPE(xmt) = BOGUS
      NODE(xmt) = Home_index
      call insert(Transmit, xmt)
DB    call print(STDOUT, "Created new transmission circuit*n"s)
   }

   if (~valid(STAT(xmt)))
   {
      TIME(xmt) = ELAPSED

      repeat
      {
         NODE(xmt) = mod(NODE(xmt), Ring_size) + 1

         SEARCH(Response, NODE, NODE(xmt), rsp, 0)

         if (rsp ~= Response && valid(STAT(rsp)))
         {
            call terminate(rsp)
DB          call print(STDOUT, "Invalid response circuit cleared*n"s)
         }

         call x$conn(VCID(xmt), RING, Node_name(1, Index_ring(NODE(xmt))),
                     Name_size(Index_ring(NODE(xmt))), STAT(xmt))
         call print(STDOUT, "Attempting connection to *,#h*n"s,
            Name_size(Index_ring(NODE(xmt))), Node_name(1, Index_ring(NODE(xmt))))
      }
      until (valid(STAT(xmt)))
   }

   return
   end


   subroutine delete(node)

#  delete --- delete node from doubly linked circular list.

   pointer node

   include RING_COMMON

   if (TYPE(node) == DUMMY)
      call error("Can't delete dummy header node"p)

   if (BACK(node) == NULL || NEXT(node) == NULL)
      call error("Node already deleted"p)

   NEXT(BACK(node)) = NEXT(node)
   BACK(NEXT(node)) = BACK(node)

   BACK(node) = NULL
   NEXT(node) = NULL

   return
   end


   subroutine dispose(node)

#  dispose --- return virtual circuit block to free space.

   pointer node

   include RING_COMMON

   if (TYPE(node) == DUMMY)
      call error("Can't dispose dummy header node"p)
   else
      if (TYPE(node) == CLEAR)
      {
         call dsfree(node)
DB       call print(STDOUT, "Disposed node #*i at *i*n"s, CODE(node), node)
      }
      else
         call insert(Complete, node)

   return
   end


   subroutine examine

#  examine --- examine all linked lists for invalid entries.

   include RING_COMMON

   logical valid

   integer time
   pointer xmt, rsp, rcv, val, back, list, ptr

DB call print(STDOUT, "Checking for elapsed virtual circuits*n"s)

   for (xmt = NEXT(Transmit); xmt ~= Transmit; xmt = NEXT(xmt))
      if (TYPE(xmt) == BOGUS && valid(STAT(xmt)))
      {
         time = ELAPSED

         if (time < TIME(xmt))
            time += 28800

         if (time - TIME(xmt) > INTERVAL)
         {
            back = BACK(xmt)

            call terminate(xmt)
DB          call print(STDOUT, "Elapsed transmission circuit cleared*n"s)

            SEARCH(Response, NODE, NODE(xmt), rsp, 0)

            if (rsp ~= Response && valid(STAT(rsp)))
            {
               call terminate(rsp)
DB             call print(STDOUT, "Elapsed response circuit cleared*n"s)

               call delete(rsp)
               call dispose(rsp)
            }

            call delete(xmt)
            call dispose(xmt)

            xmt = back
         }
      }

   for (rcv = NEXT(Receive); rcv ~= Receive; rcv = NEXT(rcv))
      if (valid(STAT(rcv)))
      {
         if (TYPE(rcv) == BOGUS)
         {
            time = ELAPSED

            if (time < TIME(rcv))
               time += 28800

            if (time - TIME(rcv) > INTERVAL)
            {
               back = BACK(rcv)

               call terminate(rcv)
DB             call print(STDOUT, "Elapsed receive circuit cleared*n"s)

               SEARCH(Validate, NODE, NODE(rcv), val, 0)

               if (val ~= Validate && valid(STAT(val)))
               {
                  call terminate(val)
DB                call print(STDOUT, "Elapsed validation circuit cleared*n"s)

                  call delete(val)
                  call dispose(val)
               }

               call delete(rcv)
               call dispose(rcv)

               rcv = back
            }
         }
      }
      else
      {
         back = BACK(rcv)

         call delete(rcv)
         call dispose(rcv)

         rcv = back
      }

   list = Validate
   repeat
   {
      for (ptr = NEXT(list); ptr ~= list; ptr = NEXT(ptr))
         if (valid(STAT(ptr)))
         {
            time = ELAPSED

            if (time < TIME(ptr))
               time += 28800

            if (time - TIME(ptr) > INTERVAL)
            {
               back = BACK(ptr)

               call terminate(ptr)
DB             call print(STDOUT, "Elapsed virtual circuit cleared*n"s)

               call delete(ptr)
               call dispose(ptr)

               ptr = back
            }
         }
         else
         {
            back = BACK(ptr)

            call delete(ptr)
            call dispose(ptr)

            ptr = back
         }

      select (list)
         when (Validate)
            list = Response

         when (Response)
            list = Request

         when (Request)
            return
   }

   end


   subroutine execute(rcv)

#  execute --- determine and perform action for ring.

   pointer rcv

   include RING_COMMON

   logical valid

   integer i
   pointer xmt

   if (valid(RCVS(rcv)))
   {
      if (RCVS(rcv) == XS$CMP)
      {
         TIME(rcv) = ELAPSED

DB       call print(STDOUT, "Received (*i *i *i *i *i *i *i *i *i)*n"s,
DB          PACKET(rcv), SOURCE(rcv), ADDRESS(rcv), NUMBER(rcv),
DB          PROCESS(rcv), JOBNAME(rcv), COMMAND(rcv), STATUS(rcv),
DB          RESULT(rcv))

         if (NUMBER(rcv) < Active_ring)
         {
            NUMBER(rcv) += 1

            if (HOLD(rcv) == NO)
               call change(rcv)

            if (SENT(rcv) == NO && ADDRESS(rcv) ~= Home_index)
            {
               SEARCH(Transmit, TYPE, VALID, xmt, DUMMY)

               if (xmt ~= Transmit && valid(STAT(xmt)) && XMTS(xmt) ~= XS$IP)
               {
                  TIME(xmt) = ELAPSED

                  for (i = 0; i < PCKTSIZE + MESGSIZE; i += 1)
                     BUFF(xmt + i) = BUFF(rcv + i)

                  call x$tran(VCID(xmt), 0, BUFF(xmt), BUFFSIZE, XMTS(xmt))
DB                call print(STDOUT, "Packet passed on to next node*n"s)
DB                call print(STDOUT, "Transmitted (*i *i *i *i *i *i *i *i *i)*n"s,
DB                   PACKET(xmt), SOURCE(xmt), ADDRESS(xmt), NUMBER(xmt),
DB                   PROCESS(xmt), JOBNAME(xmt), COMMAND(xmt), STATUS(xmt),
DB                   RESULT(xmt))

                  HOLD(rcv) = NO
                  SENT(rcv) = YES
               }
               else
               {
                  HOLD(rcv) = YES
DB                call print(STDOUT, "Receive connection has been put on hold*n"s)
               }
            }
            else
               SENT(rcv) = YES

            if (SENT(rcv) == YES)
               if (ADDRESS(rcv) == Home_index)
                  if (PACKET(rcv) == REQUEST)
                  {
                     if (TOLD(rcv) == NO)
                        call perform(rcv)

                     if (TOLD(rcv) == YES)
                     {
                        STATUS(rcv) = COMPLETED
                        RESULT(rcv) = 0
DB                      call print(STDOUT, "Request complete*n"s)

                        call report(rcv)
                     }
                  }
                  else
                     call report(rcv)
               else
                  if (PACKET(rcv) == REQUEST && ADDRESS(rcv) == ALL)
                     if (TOLD(rcv) == NO)
                        call perform(rcv)

            if (HOLD(rcv) == NO)
            {
               call x$rcv(VCID(rcv), BUFF(rcv), BUFFSIZE, RCVS(rcv))
DB             call print(STDOUT, "Awaiting reception of packet*n"s)

               SENT(rcv) = NO
               EXEC(rcv) = NO
               TOLD(rcv) = NO
               DONE(rcv) = NO
            }
            else
               NUMBER(rcv) -= 1
         }
         else
         {
            call finish(rcv)

            if (HOLD(rcv) == NO)
            {
DB             call print(STDOUT, "Discarded exhausted packet*n"s)

               call x$rcv(VCID(rcv), BUFF(rcv), BUFFSIZE, RCVS(rcv))
DB             call print(STDOUT, "Awaiting reception of packet*n"s)

               SENT(rcv) = NO
               EXEC(rcv) = NO
               TOLD(rcv) = NO
               DONE(rcv) = NO
            }
         }
      }
   }
   else
   {
DB    call print(STDOUT, "Invalid receive status*n"s)

      call x$rcv(VCID(rcv), BUFF(rcv), BUFFSIZE, RCVS(rcv))
DB    call print(STDOUT, "Awaiting reception of packet*n"s)
   }

   return
   end


   subroutine finish(rcv)

#  finish --- complete processing of exhausted packet.

   pointer rcv

   include RING_COMMON

   logical valid

   pointer xmt

   if (COMMAND(rcv) == INITIALIZE)
   {
      if (PACKET(rcv) == REQUEST)
      {
         Synchronize = FALSE
         Terminated = FALSE

         if (SENT(rcv) == NO)
         {
            SEARCH(Transmit, TYPE, VALID, xmt, DUMMY)

            if (xmt ~= Transmit && valid(STAT(xmt)) && XMTS(xmt) ~= XS$IP)
            {
               PACKET(xmt) = REQUEST
               SOURCE(xmt) = Home_index
               ADDRESS(xmt) = ALL
               NUMBER(xmt) = 0
               PROCESS(xmt) = Home_pid
               JOBNAME(xmt) = 0
               COMMAND(xmt) = INITIALIZE
               STATUS(xmt) = INITIATED
               RESULT(xmt) = 0

               COUNT(xmt) = 0
               STATE(xmt) = 0

               call x$tran(VCID(xmt), 0, BUFF(xmt), BUFFSIZE, XMTS(xmt))
               call print(STDOUT, "Retransmitted INITIALIZE request*n"s)

               HOLD(rcv) = NO
               SENT(rcv) = YES
            }
            else
            {
               HOLD(rcv) = YES
DB             call print(STDOUT, "Receive connection has been put on hold*n"s)
            }
         }
      }
      else
         if (STATE(rcv) ~= 2)
         {
            Initialized = TRUE
            Synchronize = Priviledged
            Terminated = FALSE
            call print(STDOUT, "Ring initialized by default*n"s)
         }
   }
   else
      if (PACKET(rcv) == REQUEST)
      {
         if (TOLD(rcv) == NO)
         {
            if (ADDRESS(rcv) == ALL)
            {
               STATUS(rcv) = COMPLETED
DB             call print(STDOUT, "Request complete*n"s)
            }
            else
            {
               STATUS(rcv) = NOTFOUND
DB             call print(STDOUT, "Request not complete*n"s)
            }
            RESULT(rcv) = 0

            TOLD(rcv) = YES
         }

         call report(rcv)
      }

   return
   end


   subroutine generate

#  generate --- generate transmissions that originate here.

   include RING_COMMON

   logical valid

   character line(MAXLINE)

   integer i
   longint time
   pointer rcv, xmt

DB call print(STDOUT, "Generating necessary request packets*n"s)

   if (Priviledged)
   {
      SEARCH(Receive, TYPE, VALID, rcv, DUMMY)
      SEARCH(Transmit, TYPE, VALID, xmt, DUMMY)

      time = intl(Time_info(4)) * intl(60) + intl(Time_info(5))
      time %= intl(MODULUS)

      if (time >= intl(MODULUS - TOLERANCE) || time <= intl(TOLERANCE))
         if (rcv ~= Receive && valid(STAT(rcv)) && NODE(rcv) > Home_index)
            if (xmt ~= Transmit && valid(STAT(xmt)) && NODE(xmt) > Home_index)
                  Synchronize = TRUE

      if (Initialized && Synchronize)
         if (valid(STAT(xmt)) && XMTS(xmt) ~= XS$IP && Time_info(5) == 0)
         {
            TIME(xmt) = ELAPSED

            PACKET(xmt) = REQUEST
            SOURCE(xmt) = Home_index
            ADDRESS(xmt) = ALL
            NUMBER(xmt) = 1
            PROCESS(xmt) = Home_pid
            JOBNAME(xmt) = 0
            COMMAND(xmt) = SYNCHRONIZE
            STATUS(xmt) = INITIATED
            RESULT(xmt) = 0

            MONTH(xmt) = Time_info(1)
            DATE(xmt) = Time_info(2)
            YEAR(xmt) = Time_info(3)

            call encode(line, MAXLINE, "*2,,0i"s, Time_info(4) / 60)
            i = 1; call ctop(line, i, HOUR(xmt), 1)

            call encode(line, MAXLINE, "*2,,0i"s, mod(Time_info(4), 60))
            i = 1; call ctop(line, i, MINUTE(xmt), 1)

            call x$tran(VCID(xmt), 0, BUFF(xmt), BUFFSIZE, XMTS(xmt))
            call print(STDOUT,
               "Transmitted SYNCHRONIZE request at *,2h:*,2h on *,2h/*,2h/*,2h*n"s,
               HOUR(xmt), MINUTE(xmt), MONTH(xmt), DATE(xmt), YEAR(xmt))

            Synchronize = FALSE

            call sleep$(intl(TOLERANCE + 1) * intl(1000))
         }
   }

   return
   end


   subroutine identify(node)

#  identify --- determine PID and user name for USER circuit.

   pointer node

   include RING_COMMON

   integer ptoc
   logical valid

   character line(MAXLINE)
   integer circuit(64), vcinfo(13), procid(64), meter(43)
   logical known(64)

   integer number, count, status, i, j
   pointer req

   call x$stat(XI$AVC, number, Ring_address(Address_index(HOME)),
                   Address_size(HOME), circuit, count, status, i)
DB call print(STDOUT, "*i open virtual circuits to this system*n"s, number)

   count = 0
   for (i = 1; i <= number; i += 1)
   {
      call x$stat(XI$VCD, circuit(i), 0, 0, vcinfo, 13, status, j)

      if (status == XS$CMP)
         if (vcinfo(5) == USER && vcinfo(1) == 5 && vcinfo(2) ~= Home_pid)
         {
            count += 1

            known(count) = FALSE
            procid(count) = vcinfo(2)
         }
   }

   for (req = NEXT(Request); req ~= Request; req = NEXT(req))
      if (valid(STAT(req)))
         for (i = 1; i <= count; i += 1)
            if (~known(i) && procid(i) == PROC(req))
            {
               known(i) = TRUE

               break
            }

   for (i = 1; i <= count; i += 1)
      if (~known(i))
      {
         TYPE(node) = VALID
         PROC(node) = procid(i)

         call gmetr$(4, loc(meter), 43, status, procid(i))

         j = ptoc(meter(USERNAME), " "c, line, 2 * NAMESIZE + 1) + 1
         while (j <= 2 * NAMESIZE)
         {
            line(j) = " "c
            j += 1
         }
         line(j) = EOS

         call mapstr(line, UPPER)

         j = 1; call ctop(line, j, NAME(1, node), NAMESIZE)

         break
      }

   return
   end


   subroutine initialize

#  initialize --- initialize variables.

   include RING_COMMON

   integer equal

   integer status

   character line (MAXLINE)

   Terminated = FALSE

   call x$asgn(RING, 0, status)
   if (status ~= XS$CMP)
      call error("Can't assign Ring port"p)
DB call print(STDOUT, "Ring port assigned*n"s)

   call x$asgn(CHCK, 0, status)
   if (status ~= XS$CMP)
      call error("Can't assign Check port"p)
DB call print(STDOUT, "Check port assigned*n"s)

   call x$asgn(USER, 0, status)
   if (status ~= XS$CMP)
      call error("Can't assign User port"p)
DB call print(STDOUT, "User port assigned*n"s)

   call dsinit(HEAPSIZE)

   call timdat(Time_info, INFOSIZE)
   Home_pid = Time_info(12)

   Sequence = 0

   call expand("=GaTech="s, line, MAXLINE)
   Priviledged = (equal(line, "yes"s) == YES)

   Initialized = FALSE
   Synchronize = FALSE

   call allocate(Transmit)
   TYPE(Transmit) = DUMMY
   NEXT(Transmit) = Transmit
   BACK(Transmit) = Transmit
DB call print(STDOUT, "Transmit list initialized*n"s)

   call allocate(Receive)
   TYPE(Receive) = DUMMY
   NEXT(Receive) = Receive
   BACK(Receive) = Receive
DB call print(STDOUT, "Receive list initialized*n"s)

   call allocate(Validate)
   TYPE(Validate) = DUMMY
   NEXT(Validate) = Validate
   BACK(Validate) = Validate
DB call print(STDOUT, "Validate list initialized*n"s)

   call allocate(Response)
   TYPE(Response) = DUMMY
   NEXT(Response) = Response
   BACK(Response) = Response
DB call print(STDOUT, "Response list initialized*n"s)

   call allocate(Request)
   TYPE(Request) = DUMMY
   NEXT(Request) = Request
   BACK(Request) = Request
DB call print(STDOUT, "Request list initialized*n"s)

   call allocate(Complete)
   TYPE(Complete) = DUMMY
   NEXT(Complete) = Complete
   BACK(Complete) = Complete
DB call print(STDOUT, "Complete list initialized*n"s)

   return
   end


   subroutine insert(list, node)

#  insert --- insert node into doubly linked circular list.

   pointer list, node

   include RING_COMMON

   if (TYPE(node) == DUMMY)
      call error("Can't insert dummy header node into list"p)

   if (BACK(node) ~= NULL || NEXT(node) ~= NULL)
      call error("Node already inserted"p)

   BACK(node) = list
   NEXT(node) = NEXT(list)

   NEXT(BACK(node)) = node
   BACK(NEXT(node)) = node

   return
   end


   subroutine pause

#  pause --- wait until next network event occurs.

   include RING_COMMON

   logical valid

   integer name(NAMESIZE), status(2)

   integer vcid, port, size
   longint time
   pointer xmt, rcv, val, rsp, req

DB call print(STDOUT, "Waiting for next network event*n"s)

   SEARCH(Transmit, TYPE, VALID, xmt, DUMMY)
   if (xmt == Transmit)
      SEARCH(Transmit, TYPE, BOGUS, xmt, DUMMY)

   if (xmt == Transmit || ~valid(STAT(xmt)))
      return

   call xlgcon(XK$NAM, vcid, port, name, 2 * NAMESIZE, size,
                          0, 0, 0, 0, 0, 0, 0, 0, 0, status)
   if (status(1) == XS$CMP)
      return

   for (rcv = NEXT(Receive); rcv ~= Receive; rcv = NEXT(rcv))
      if (valid(STAT(rcv)) && (~valid(RCVS(rcv)) || RCVS(rcv) == XS$CMP))
      {
         if (HOLD(rcv) == YES)
            call x$wait(1)

         return
      }

   for (val = NEXT(Validate); val ~= Validate; val = NEXT(val))
      if (valid(STAT(val)) && STAT(val) ~= XS$IP && HOLD(val) == NO)
      {
         if (DONE(val) == YES)
            call x$wait(1)

         return
      }

   for (rsp = NEXT(Response); rsp ~= Response; rsp = NEXT(rsp))
      if (valid(STAT(rsp)) && (~valid(RCVS(rsp)) || (RCVS(rsp) == XS$CMP && HOLD(rsp) == NO)))
      {
         if (DONE(rsp) == YES)
            call x$wait(1)

         return
      }

   for (req = NEXT(Request); req ~= Request; req = NEXT(req))
      if (HOLD(req) == NO && valid(STAT(req)) && RCVS(req) == XS$CMP)
      {
         if (DONE(req) == YES)
            call x$wait(1)

         return
      }

   call timdat(Time_info, INFOSIZE)
   time = mod(intl(Time_info(4)) * intl(60) + intl(Time_info(5)), intl(INTERVAL))

   call x$wait(ints(intl(INTERVAL) - time) * 10)

   return
   end


   subroutine perform(vrcv)

#  perform --- perform action indicated by RING packet.

   pointer vrcv

   include RING_COMMON

   file_des mktemp, create
   integer sys$$, phantom
   logical valid

   character line(MAXLINE), name(MAXLINE)

   file_des temp
   integer status, time, i, j
   pointer brcv, val, list, ptr

   if (EXEC(vrcv) == NO)
   {
      select (COMMAND(vrcv))
         when (VALIDATE)
         {
DB          call print(STDOUT, "VALIDATE request received*n"s)

            SEARCH(Receive, TYPE, BOGUS, brcv, DUMMY)

            if (brcv ~= Receive && valid(STAT(brcv)) && NODE(brcv) == SOURCE(vrcv))
            {
               call terminate(brcv)
DB             call print(STDOUT, "Erroneous receive circuit cleared*n"s)
            }

            SEARCH(Validate, NODE, SOURCE(vrcv), val, 0)

            if (val ~= Validate && valid(STAT(val)))
            {
               call terminate(val)
DB             call print(STDOUT, "Validation circuit cleared*n"s)
            }

            STATUS(vrcv) = 0
            RESULT(vrcv) = 0
         }

         when (INITIALIZE)
         {
            call print(STDOUT, "INITIALIZE request received*n"s)

            Synchronize = FALSE
            Terminated = FALSE

            call build

            STATUS(vrcv) = 0
            RESULT(vrcv) = 0
         }

         when (SYNCHRONIZE)
         {
            call encode(line, MAXLINE, "SETIME -*,2h*,2h*,2h -*,2h*,2h"s,
               MONTH(vrcv), DATE(vrcv), YEAR(vrcv), HOUR(vrcv), MINUTE(vrcv))

            status = sys$$(line, ERR)
            call print(STDOUT, "Synchronized at *,2h:*,2h on *,2h/*,2h/*,2h*n"s,
               HOUR(vrcv), MINUTE(vrcv), MONTH(vrcv), DATE(vrcv), YEAR(vrcv))

            Initialized = TRUE

            call timdat(Time_info, INFOSIZE)
            time = ELAPSED

            list = Transmit
            repeat
            {
               for (ptr = NEXT(list); ptr ~= list; ptr = NEXT(ptr))
                  if (valid(STAT(ptr)))
                     TIME(ptr) = time

               select (list)
                  when (Transmit)
                     list = Receive

                  when (Receive)
                     list = Validate

                  when (Validate)
                     list = Response

                  when (Response)
                     list = Request

                  when (Request)
                     break
            }

            if (JOBNAME(vrcv) ~= 0)
               if (status == OK)
                  STATUS(vrcv) = SUCCEEDED
               else
                  STATUS(vrcv) = FAILED
            else
               STATUS(vrcv) = 0
            RESULT(vrcv) = 0
         }

         when (SHUTDOWN)
         {
            if (Terminated)
            {
               call print(STDOUT, "Ring SHUTDOWN initiated*n"s)
               call sleep$(intl(5000))

               list = Transmit
               repeat
               {
                  for (ptr = NEXT(list); ptr ~= list; ptr = NEXT(ptr))
                     if (valid(STAT(ptr)))
                        call terminate(ptr)

                  select (list)
                     when (Transmit)
                        list = Receive

                     when (Receive)
                        list = Validate

                     when (Validate)
                        list = Response

                     when (Response)
                        list = Request

                     when (Request)
                     {
                        call print(STDOUT, "Shutdown complete*n"s)

                        stop
                     }
               }
            }

            STATUS(vrcv) = 0
            RESULT(vrcv) = 0
         }

         when (BROADCAST)
         {
            if (TARGET(1, vrcv) ~= 0)
               call encode(line, MAXLINE, "MESSAGE *,#h -NOW -FORCE"s,
                  2 * NAMESIZE, TARGET(1, vrcv))
            else
               call encode(line, MAXLINE, "MESSAGE -ALL -NOW -FORCE"s)

            temp = mktemp(READWRITE)
            if (temp ~= ERR)
            {
               call print(temp, "*s*n"s, MESSAGE(1, vrcv))

               call rewind(temp)

               status = sys$$(line, temp)
               if (TARGET(1, vrcv) ~= 0)
                  call print(STDOUT, "Message broadcast to user *,#h*n"s,
                     2 * NAMESIZE, TARGET(1, vrcv))
               else
                  call print(STDOUT, "Message broadcast to ALL users*n"s)

               call rmtemp(temp)

               if (status == OK)
                  STATUS(vrcv) = SUCCEEDED
               else
                  STATUS(vrcv) = FAILED
               RESULT(vrcv) = 0
            }
            else
            {
               STATUS(vrcv) = FAILED
               RESULT(vrcv) = 0
DB             call print(STDOUT, "Cannot create temporary file for message*n"s)
            }
         }

         when (EXECUTE)
         {
            i = 0
            repeat
            {
               i += 1
               call encode(name, MAXLINE, "=temp=/rmph*3,,0i"s, i)

               temp = create(name, WRITE)
            }
            until (temp ~= ERR || i >= 999)

            if (temp ~= ERR)
            {
               call print(temp, "CHAP LOWER 2*n"s)
               call print(temp, "SWT -6*n"s)

               call print(temp, "*s*n"s, CMDLINE(1, vrcv))

               call print(temp, "stop *s*n"s, name)
               call close(temp)

               status = phantom(name, vrcv)
               if (status ~= ERR)
               {
                  STATUS(vrcv) = SUCCEEDED
                  RESULT(vrcv) = status

                  call print(STDOUT, "Phantom (*i) created for user *,#h*n"s,
                     status, 2 * NAMESIZE, USERID(1, vrcv))
               }
               else
               {
                  STATUS(vrcv) = FAILED
                  RESULT(vrcv) = 0

                  call print(STDOUT, "Phantom creation for user *,#h failed*n"s,
                     2 * NAMESIZE, USERID(1, vrcv))
               }
            }
            else
            {
               STATUS(vrcv) = FAILED
               RESULT(vrcv) = 0

DB             call print(STDOUT, "Cannot create temporary file for command*n"s)
            }
         }

         when (TERMINATE)
         {
            Terminated = TRUE
            call print(STDOUT, "TERMINATE request received*n"s)

            STATUS(vrcv) = SUCCEEDED
            RESULT(vrcv) = 0
         }

      EXEC(vrcv) = YES
   }

   if (STATUS(vrcv) ~= 0)
   {
      call report(vrcv)

      if (HOLD(vrcv) == NO)
         TOLD(vrcv) = YES
      DONE(vrcv) = NO
   }
   else
      TOLD(vrcv) = YES

   return
   end


   integer function phantom(file, node)

#  phantom --- spawn a phantom for a user.

   character file(MAXLINE)
   pointer node

   include RING_COMMON

   logical wizard

   character cname(33)
   integer buff(57), pname(16), vname(17), pword(3)

   integer attach, process, status, i

   buff(1) = 1

   call ptoc(USERID(1, node), " "c, cname, 2 * NAMESIZE + 1)
   i = 1; call ctov(cname, i, buff(2), 17)

   if (wizard(USERID(1, node)))
   {
      i = 1; call ctov("LAB"s, i, buff(19), 17)

      buff(40) = 1
      i = 1; call ctov(".GURU"s, i, buff(41), 17)
   }
   else
   {
      i = 1; call ctov("DEFAULT"s, i, buff(19), 17)

      buff(40) = 0
      i = 1; call ctov(""s, i, buff(41), 17)
   }

   buff(36) = 0
   buff(37) = 0
   buff(38) = 0
   buff(39) = 0

   call getto(file, pname, pword, attach)

   call ptoc(pname, " "c, cname, 33)
   i = 1; call ctov(cname, i, vname, 17)

   call spawn$(0, loc(buff), vname, 6, 0, process, status)

   if (attach == YES)
      call follow(""s, 0)

   if (status == 0)
      return (process)
   else
      return (ERR)
   end


   subroutine process(node)

#  process --- process user connection request.

   pointer node

   include RING_COMMON

   if (NODE(node) == Home_index)
   {
      call x$acpt(VCID(node), STAT(node))
DB    call print(STDOUT, "User connection accepted*n"s)

      call identify(node)

      if (TYPE(node) == VALID)
      {
         call insert(Request, node)
         call print(STDOUT, "User connection is from *,#h (*i)*n"s,
            2 * NAMESIZE, NAME(1, node), PROC(node))

         call x$rcv(VCID(node), BUFF(node), BUFFSIZE, RCVS(node))
DB       call print(STDOUT, "Awaiting reception of request*n"s)
      }
      else
      {
         call terminate(node)
DB       call print(STDOUT, "User connection cleared*n"s)

         call dispose(node)
      }
   }
   else
   {
      call terminate(node)
DB    call print(STDOUT, "User connection rejected*n"s)

      call dispose(node)
   }

   return
   end


   subroutine reform(brcv)

#  reform --- check validity of receiver and restructure ring.

   pointer brcv

   include RING_COMMON

   logical valid

   logical flag
   pointer vrcv, xmt, val, req

   if (valid(RCVS(brcv)))
      if (RCVS(brcv) == XS$CMP)
      {
         TIME(brcv) = ELAPSED

         flag = RCVL(brcv) == 0 & RCVN(brcv) == BUFFSIZE

         if (flag)
            flag =  SOURCE(brcv) == NODE(brcv) _
                 & ADDRESS(brcv) == Home_index _
                 &  NUMBER(brcv) == 1 _
                 & COMMAND(brcv) == VALIDATE

         if (flag)
         {
DB          call print(STDOUT, "Response password received*n"s)
DB          call print(STDOUT, "Response password is *i*n"s, RESULT(brcv))

            SEARCH(Validate, NODE, NODE(brcv), val, 0)

            if (val ~= Validate && valid(STAT(val)))
               flag = RESULT(brcv) == RESULT(val)
            else
               flag = FALSE

            if (flag)
            {
               call terminate(val)
DB             call print(STDOUT, "Validation circuit cleared*n"s)

               SEARCH(Receive, TYPE, VALID, vrcv, DUMMY)

               if (vrcv ~= Receive && valid(STAT(vrcv)))
               {
                  flag = FALSE

                  call terminate(vrcv)
DB                call print(STDOUT, "Previous receive circuit cleared*n"s)
               }
               else
                  flag = TRUE

               TYPE(brcv) = VALID
               call print(STDOUT, "Validated reception from *,#h*n"s,
                  Name_size(Index_ring(NODE(brcv))),
                  Node_name(1, Index_ring(NODE(brcv))))

               call x$rcv(VCID(brcv), BUFF(brcv), BUFFSIZE, RCVS(brcv))
DB             call print(STDOUT, "Awaiting reception of packet*n"s)

               if (NODE(brcv) == Home_index)
               {
                  Initialized = TRUE
                  Synchronize = FALSE
                  Terminated = FALSE

                  Active_ring = 1

                  for (req = NEXT(Request); req ~= Request; req = NEXT(req))
                     if (ANSR(req) > Active_ring)
                        ANSR(req) = Active_ring

                  call print(STDOUT, "Degenerate ring initialized*n"s)
               }
               else
               {
                  Synchronize = FALSE
                  Terminated = FALSE

                  SEARCH(Transmit, TYPE, VALID, xmt, DUMMY)

                  if (xmt ~= Transmit && valid(STAT(xmt)))
                  {
                     while (XMTS(xmt) == XS$IP)
                        call x$wait(1)

                     PACKET(xmt) = REQUEST
                     SOURCE(xmt) = Home_index
                     ADDRESS(xmt) = ALL
                     NUMBER(xmt) = 0
                     PROCESS(xmt) = Home_pid
                     JOBNAME(xmt) = 0
                     COMMAND(xmt) = INITIALIZE
                     STATUS(xmt) = INITIATED
                     RESULT(xmt) = 0

                     COUNT(xmt) = 0
                     STATE(xmt) = 0

                     call x$tran(VCID(xmt), 0, BUFF(xmt), BUFFSIZE, XMTS(xmt))
                     call print(STDOUT, "Transmitted INITIALIZE request*n"s)
                  }
               }

               flag = TRUE
            }
         }
         else
         {
            select
               when (RCVL(brcv) ~= 0)
                  call print(STDOUT, "Receive level is not 0*n"s)

               when (RCVN(brcv) ~= BUFFSIZE)
                  call print(STDOUT, "Response size is not BUFFSIZE*n"s)

               when (SOURCE(brcv) ~= NODE(brcv))
                  call print(STDOUT, "Response source is not correct*n"s)

               when (ADDRESS(brcv) ~= Home_index)
                  call print(STDOUT, "Response is not correctly addressed*n"s)

               when (NUMBER(brcv) ~= 1)
                  call print(STDOUT, "Response transmission count is not 1*n"s)

               when (COMMAND(brcv) ~= VALIDATE)
                  call print(STDOUT, "Response is not a validation request*n"s)
         }
      }
      else
         flag = TRUE
   else
   {
DB    call print(STDOUT, "Invalid receive status*n"s)
      flag = FALSE
   }

   if (~flag)
   {
      call terminate(brcv)
DB    call print(STDOUT, "Invalid receive circuit cleared*n"s)

      SEARCH(Validate, NODE, NODE(brcv), val, 0)

      if (val ~= Validate && valid(STAT(val)))
      {
         call terminate(val)
DB       call print(STDOUT, "Validation circuit cleared*n"s)
      }
   }

   return
   end


   subroutine remove

#  remove --- scan Complete VC's and delete all invalid circuits.

   include RING_COMMON

   logical valid

   pointer node, back

DB call print(STDOUT, "Checking for completed circuits*n"s)

   for (node = NEXT(Complete); node ~= Complete; node = NEXT(node))
      if (~valid(STAT(node)))
      {
         back = BACK(node)

         call delete(node)

         TYPE(node) = CLEAR
         call dispose(node)

         node = back
      }

   return
   end


   subroutine report(rcv)

#  report --- deliver status report to requesting user.

   pointer rcv

   include RING_COMMON

   logical valid

   integer i
   pointer xmt, req

   if (PACKET(rcv) == REQUEST && SOURCE(rcv) ~= Home_index)
   {
      if (DONE(rcv) == NO)
      {
         SEARCH(Transmit, TYPE, VALID, xmt, DUMMY)

         if (xmt ~= Transmit && valid(STAT(xmt)) && XMTS(xmt) ~= XS$IP)
         {
            TIME(xmt) = ELAPSED

            PACKET(xmt) = RESPONSE
            SOURCE(xmt) = Home_index
            ADDRESS(xmt) = SOURCE(rcv)
            NUMBER(xmt) = 0
            PROCESS(xmt) = PROCESS(rcv)
            JOBNAME(xmt) = JOBNAME(rcv)
            COMMAND(xmt) = COMMAND(rcv)
            STATUS(xmt) = STATUS(rcv)
            RESULT(xmt) = RESULT(rcv)

            call x$tran(VCID(xmt), 0, BUFF(xmt), BUFFSIZE, XMTS(xmt))
DB          call print(STDOUT, "Ring response transmitted*n"s)
DB          call print(STDOUT, "Transmitted (*i *i *i *i *i *i *i *i *i)*n"s,
DB             PACKET(xmt), SOURCE(xmt), ADDRESS(xmt), NUMBER(xmt),
DB             PROCESS(xmt), JOBNAME(xmt), COMMAND(xmt), STATUS(xmt),
DB             RESULT(xmt))

            HOLD(rcv) = NO
            DONE(rcv) = YES
         }
         else
         {
            HOLD(rcv) = YES
DB          call print(STDOUT, "Receive circuit has been put on hold*n"s)
         }
      }
   }
   else
      if ((PACKET(rcv) ==  REQUEST &&  SOURCE(rcv) == Home_index) ||
          (PACKET(rcv) == RESPONSE && ADDRESS(rcv) == Home_index))
         for (req = NEXT(Request); req ~= Request; req = NEXT(req))
            if (PROC(req) == PROCESS(rcv) && CODE(req) == JOBNAME(rcv))
            {
               if (DONE(rcv) == NO && valid(STAT(req)))
               {
                  do i = 1, NAMESIZE
                  {
                     INDX(req) += 1
                     BUFF(req + INDX(req)) = Node_name(i, Index_ring(SOURCE(rcv)))
                  }
                  INDX(req) += 1
                  BUFF(req + INDX(req)) = STATUS(rcv)
                  INDX(req) += 1
                  BUFF(req + INDX(req)) = RESULT(rcv)

                  if (STATUS(rcv) == NOTFOUND)
                     ANSR(req) -= 1

DB                call print(STDOUT, "*i words reported, *i expected*n"s,
DB                   INDX(req), (NAMESIZE + 2) * ANSR(req))

                  if (INDX(req) > (NAMESIZE + 2) * ANSR(req))
                     if (XMTS(req) ~= XS$IP)
                     {
                        TIME(req) = ELAPSED

                        call x$tran(VCID(req), 0, BUFF(req),
                           2 * (INDX(req) + 1), XMTS(req))
DB                      call print(STDOUT, "Response transmitted to user *,#h (*i)*n"s,
DB                         2 * NAMESIZE, NAME(1, req), PROC(req))

                        HOLD(rcv) = NO
                        DONE(rcv) = YES
                     }
                     else
                     {
                        HOLD(rcv) = YES
DB                      call print(STDOUT, "Receive circuit has been put on hold*n"s)
                     }
               }

               if (DONE(rcv) == YES)
                  call signal(rcv)

               break
            }

   return
   end


   subroutine respond(node)

#  respond --- respond to validation request.

   pointer node

   include RING_COMMON

   logical valid

   pointer rsp

   SEARCH(Response, NODE, NODE(node), rsp, 0)

   if (rsp == Response || ~valid(STAT(rsp)))
   {
      call x$acpt(VCID(node), STAT(node))
DB    call print(STDOUT, "Validation connection accepted*n"s)

      TYPE(node) = VALID
      call insert(Response, node)

      call x$rcv(VCID(node), BUFF(node), BUFFSIZE, RCVS(node))
DB    call print(STDOUT, "Awaiting reception of password*n"s)
   }
   else
   {
DB    call print(STDOUT, "Duplicate validation connection*n"s)

      call terminate(node)
DB    call print(STDOUT, "Validation connection cleared*n"s)
   }

   return
   end


   subroutine search

#  search --- search user connections for request reception.

   include RING_COMMON

   logical valid

   pointer req, xmt

DB call print(STDOUT, "Checking for user requests*n"s)

   for (req = NEXT(Request); req ~= Request; req = NEXT(req))
      if (HOLD(req) == NO && valid(STAT(req)))
         if (valid(RCVS(req)))
         {
            if (RCVS(req) == XS$CMP)
            {
               TIME(req) = ELAPSED
               HOLD(req) = YES
               DONE(req) = YES

               SEARCH(Transmit, TYPE, VALID, xmt, DUMMY)

               if (xmt ~= Transmit && valid(STAT(xmt)) && XMTS(xmt) ~= XS$IP)
               {
                  call translate(req, xmt)

                  if (BUFF(req + 1) == INITIATED)
                  {
                     call x$tran(VCID(xmt), 0, BUFF(xmt), BUFFSIZE, XMTS(xmt))
DB                   call print(STDOUT, "Ring request transmitted*n"s)

                     call x$tran(VCID(req), 0, BUFF(req), USERSIZE, XMTS(req))
                     call print(STDOUT, "User request made for *,#h (*i)*n"s,
                        2 * NAMESIZE, NAME(1, req), PROC(req))
                  }
                  else
                  {
                     call x$tran(VCID(req), 0, BUFF(req), USERSIZE, XMTS(req))
DB                   call print(STDOUT, "User request error status transmitted*n"s)
                  }
               }
               else
               {
                  HOLD(req) = NO
DB                call print(STDOUT, "User request will be retried*n"s)
               }
            }
         }
         else
         {
DB          call print(STDOUT, "Invalid receive status*n"s)

            call terminate(req)
DB          call print(STDOUT, "User connection cleared*n"s)
         }

   return
   end


   subroutine signal(rcv)

#  signal --- send packet signaling that response has been sent.

   pointer rcv

   include RING_COMMON

   logical valid

   pointer xmt

   if (COMMAND(rcv) == TERMINATE && STATUS(rcv) == COMPLETED)
   {
      SEARCH(Transmit, TYPE, VALID, xmt, DUMMY)

      if (xmt ~= Transmit && valid(STAT(xmt)) && XMTS(xmt) ~= XS$IP)
      {
         TIME(xmt) = ELAPSED

         PACKET(xmt) = REQUEST
         SOURCE(xmt) = Home_index
         ADDRESS(xmt) = ALL
         NUMBER(xmt) = 0
         PROCESS(xmt) = Home_pid
         JOBNAME(xmt) = 0
         COMMAND(xmt) = SHUTDOWN
         STATUS(xmt) = INITIATED
         RESULT(xmt) = 0

         call x$tran(VCID(xmt), 0, BUFF(xmt), BUFFSIZE, XMTS(xmt))
         call print(STDOUT, "SHUTDOWN request transmitted*n"s)

         HOLD(rcv) = NO
      }
      else
      {
         HOLD(rcv) = YES
DB       call print(STDOUT, "Receive circuit has been put on hold*n"s)
      }
   }

   return
   end


   subroutine terminate(node)

#  terminate --- clear a virtual circuit and wait for completion.

   pointer node

   include RING_COMMON

   integer status

   if (STAT(node) ~= XS$CLR)
   {
      call x$clr(VCID(node), 0, status)

      while (STAT(node) ~= XS$CLR)
         call x$wait(1)
   }

   TYPE(node) = CLEAR

   return
   end


   subroutine translate(req, xmt)

#  translate --- convert and copy user request into ring request.

   pointer req, xmt

   include RING_COMMON

   logical wizard

   integer status, i, j

   if (RCVN(req) >= USERSIZE)
      if (BUFF(req) > MINREQUEST && BUFF(req) < MAXREQUEST)
      {
         status = INITIATED

         if (BUFF(req) == TERMINATE || BUFF(req) == SETTIME)
            if (~wizard(NAME(1, req)))
            {
               status = REJECTED
DB             call print(STDOUT, "User is not validated to issue request*n"s)
            }

         if (status == INITIATED)
         {
            ADDRESS(xmt) = 0

            select (BUFF(req))
               when (EXECUTE, TERMINATE)
                  if (BUFF(req + 1) ~= 0)
                     do i = 1, Ring_size
                     {
                        do j = 1, NAMESIZE
                           if (Node_name(j, Index_ring(i)) ~= BUFF(req + j))
                              next 2

                        ADDRESS(xmt) = i
DB                      call print(STDOUT, "User request is addressed to *i*n"s, i)
                        break
                     }
                  else
                  {
                     ADDRESS(xmt) = ALL
DB                   call print(STDOUT, "User request is addressed to ALL*n"s)
                  }

               when (BROADCAST, SETTIME)
               {
                  ADDRESS(xmt) = ALL
DB                call print(STDOUT, "User request is addressed to ALL*n"s)
               }

            if (ADDRESS(xmt) ~= 0)
            {
               if (ADDRESS(xmt) == ALL)
                  ANSR(req) = Active_ring
               else
                  ANSR(req) = 1

               PACKET(xmt) = REQUEST
               SOURCE(xmt) = NODE(req)
               NUMBER(xmt) = 0
               PROCESS(xmt) = PROC(req)
               JOBNAME(xmt) = CODE(req)

               COMMAND(xmt) = BUFF(req)
               STATUS(xmt) = status
               RESULT(xmt) = 0

               select (COMMAND(xmt))
                  when (BROADCAST)
                  {
                     do i = 1, NAMESIZE
                        TARGET(i, xmt) = BUFF(req + i)

                     BUFF(req + (RCVN(req) + 1) / 2) = EOS
                     call strim(BUFF(req + 1 + NAMESIZE))

                     call ctoc(BUFF(req + 1 + NAMESIZE), MESSAGE(1, xmt), MAXLINE)
                  }

                  when (EXECUTE)
                  {
                     do i = 1, NAMESIZE
                        USERID(i, xmt) = NAME(i, req)

                     BUFF(req + (RCVN(req) + 1) / 2) = EOS
                     call strim(BUFF(req + 1 + NAMESIZE))

                     call ctoc(BUFF(req + 1 + NAMESIZE), CMDLINE(1, xmt), MAXLINE)
                  }

                  when (TERMINATE)
                     ;

                  when (SETTIME)
                     if (Priviledged)
                        if (RCVN(req) == TIMESIZE)
                        {
                           COMMAND(xmt) = SYNCHRONIZE

                           MONTH(xmt) = BUFF(req + 1)
                           DATE(xmt) = BUFF(req + 2)
                           YEAR(xmt) = BUFF(req + 3)
                           HOUR(xmt) = BUFF(req + 4)
                           MINUTE(xmt) = BUFF(req + 5)
                        }
                        else
                           status = WRONGSIZE
                     else
                     {
                        status = NOREQUEST
DB                      call print(STDOUT, "User request command is unknown*n"s)
                     }
            }
            else
            {
               status = NOTFOUND
DB             call print(STDOUT, "User request address is unknown*n"s)
            }
         }
      }
      else
      {
         status = NOREQUEST
DB       call print(STDOUT, "User request command is unknown*n"s)
      }
   else
   {
      status = WRONGSIZE
DB    call print(STDOUT, "User request packet is too small*n"s)
   }

   BUFF(req + 1) = status

   return
   end


   subroutine update

#  update --- scan node lists and process newly complete nodes.

   include RING_COMMON

   logical valid
   longint uniform

   logical flag
   pointer rcv, xmt, val, rsp

DB call print(STDOUT, "Checking reception connections*n"s)

   for (rcv = NEXT(Receive); rcv ~= Receive; rcv = NEXT(rcv))
      if (valid(STAT(rcv)))
      {
         select (TYPE(rcv))
            when (BOGUS)
               call reform(rcv)

            when (VALID)
               call execute(rcv)
      }

DB call print(STDOUT, "Checking validation connections*n"s)

   for (val = NEXT(Validate); val ~= Validate; val = NEXT(val))
      if (valid(STAT(val)) && STAT(val) ~= XS$IP && HOLD(val) == NO)
      {
         TIME(val) = ELAPSED
         HOLD(val) = YES
         DONE(val) = YES

         if (XMTS(val) ~= XS$IP)
         {
            PACKET(val) = REQUEST
            SOURCE(val) = Home_index
            ADDRESS(val) = NODE(val)
            NUMBER(val) = 0
            PROCESS(val) = Home_pid
            JOBNAME(val) = 0
            COMMAND(val) = VALIDATE
            STATUS(val) = INITIATED

            RESULT(val) = ints(uniform(intl(-32768), intl(32767)))
DB          call print(STDOUT, "Validation password is *i*n"s, RESULT(val))

            call x$tran(VCID(val), 0, BUFF(val), BUFFSIZE, XMTS(val))
DB          call print(STDOUT, "Validation password transmitted*n"s)
         }
         else
         {
            HOLD(val) = NO
DB          call print(STDOUT, "Validation password will be retransmitted*n"s)
         }
      }

DB call print(STDOUT, "Checking response connections*n"s)

   for (rsp = NEXT(Response); rsp ~= Response; rsp = NEXT(rsp))
      if (valid(STAT(rsp)))
      {
         if (valid(RCVS(rsp)))
            if (RCVS(rsp) == XS$CMP && HOLD(rsp) == NO)
            {
               TIME(rsp) = ELAPSED
               HOLD(rsp) = YES
               DONE(rsp) = YES

               flag = RCVL(rsp) == 0 & RCVN(rsp) == BUFFSIZE

               if (flag)
                  flag =  SOURCE(rsp) == NODE(rsp) _
                       & ADDRESS(rsp) == Home_index _
                       &  NUMBER(rsp) == 0 _
                       & COMMAND(rsp) == VALIDATE

               if (flag)
               {
DB                call print(STDOUT, "Validation password received*n"s)

                  SEARCH(Transmit, TYPE, BOGUS, xmt, DUMMY)

                  if (xmt ~= Transmit && valid(STAT(xmt)))
                     flag = NODE(rsp) == NODE(xmt)
                  else
                     flag = FALSE

                  if (~flag)
                  {
DB                   call print(STDOUT, "Circuit is not being validated*n"s)

                     SEARCH(Transmit, TYPE, VALID, xmt, DUMMY)

                     if (xmt ~= Transmit && valid(STAT(xmt)))
                        flag = TRUE
                     else
                        flag = FALSE
                  }

                  if (flag && XMTS(xmt) ~= XS$IP)
                  {
                     TIME(xmt) = ELAPSED

                     PACKET(xmt) = RESPONSE
                     SOURCE(xmt) = Home_index
                     ADDRESS(xmt) = NODE(rsp)
                     NUMBER(xmt) = 1
                     PROCESS(xmt) = Home_pid
                     JOBNAME(xmt) = 0
                     COMMAND(xmt) = VALIDATE
                     STATUS(xmt) = INITIATED

                     RESULT(xmt) = RESULT(rsp)

                     call x$tran(VCID(xmt), 0, BUFF(xmt), BUFFSIZE, XMTS(xmt))
DB                   call print(STDOUT, "Response password transmitted*n"s)

                     if (TYPE(xmt) == BOGUS)
                     {
                        TYPE(xmt) = VALID
                        call print(STDOUT, "Validated transmission to *,#h*n"s,
                           Name_size(Index_ring(NODE(xmt))),
                           Node_name(1, Index_ring(NODE(xmt))))
                     }
                  }
                  else
                  {
                     HOLD(rsp) = NO
DB                   call print(STDOUT, "Response password will be retransmitted*n"s)
                  }
               }
               else
               {
                  select
                     when (RCVL(rsp) ~= 0)
                        call print(STDOUT, "Receive level is not 0*n"s)

                     when (RCVN(rsp) ~= BUFFSIZE)
                        call print(STDOUT, "Request size is not BUFFSIZE*n"s)

                     when (SOURCE(rsp) ~= NODE(rsp))
                        call print(STDOUT, "Request source is not correct*n"s)

                     when (ADDRESS(rsp) ~= Home_index)
                        call print(STDOUT, "Request is not correctly addressed*n"s)

                     when (NUMBER(rsp) ~= 0)
                        call print(STDOUT, "Request transmission count is not 0*n"s)

                     when (COMMAND(rsp) ~= VALIDATE)
                        call print(STDOUT, "Request is not a validation request*n"s)
               }
            }
            else
               flag = TRUE
         else
         {
DB          call print(STDOUT, "Invalid receive status*n"s)
            flag = FALSE
         }

         if (~flag)
         {
            call terminate(rsp)
DB          call print(STDOUT, "Invalid response circuit cleared*n"s)

            SEARCH(Transmit, TYPE, BOGUS, xmt, DUMMY)

            if (xmt ~= Transmit && NODE(xmt) == NODE(rsp) && valid(STAT(xmt)))
            {
               call terminate(xmt)
DB             call print(STDOUT, "Transmission circuit cleared*n"s)
            }
         }
      }

   return
   end


   logical function valid(status)

#  valid --- return .TRUE. if status indicates VC is valid.

   integer status(2)

   include RING_COMMON

   integer code, whyc, diag
   logical flag

   code = status(1)
   whyc = and(status(2), 8r77400)
   diag = and(status(2), 8r00377)

   if (code == XS$CMP || code == XS$IP  || code == XS$RST || _
       code == XS$IDL || code == XS$NOP || code == XS$QUE)
      flag = TRUE
   else
      flag = FALSE

   select (code)
      when (XS$NET)
         call print(STDOUT, "Status is XS$NET*n"s)

DB    when (XS$CMP)
DB       call print(STDOUT, "Status is XS$CMP*n"s)

DB    when (XS$IP)
DB       call print(STDOUT, "Status is XS$IP*n"s)

      when (XS$BVC)
         call print(STDOUT, "Status is XS$BVC*n"s)

      when (XS$BPM)
         call print(STDOUT, "Status is XS$BPM*n"s)

DB    when (XS$CLR)
DB    {
DB       call print(STDOUT, "Status is XS$CLR, "s)
DB
DB       select (whyc)
DB          when (CC$CLR)
DB          {
DB             call print(STDOUT, "CC$CLR, "s)
DB
DB             select (diag)
DB                when (CD$PNA)
DB                   call print(STDOUT, "CD$PNA*n"s)
DB
DB                when (CD$SNU)
DB                   call print(STDOUT, "CD$SNU*n"s)
DB
DB                when (CD$BSY)
DB                   call print(STDOUT, "CD$BSY*n"s)
DB
DB                when (CD$NRU)
DB                   call print(STDOUT, "CD$NRU*n"s)
DB
DB                when (CD$IAD)
DB                   call print(STDOUT, "CD$IAD*n"s)
DB
DB                when (CD$DWN)
DB                   call print(STDOUT, "CD$DWN*n"s)
DB
DB                when (CD$LPE)
DB                   call print(STDOUT, "CD$LPE*n"s)
DB             else
DB                call print(STDOUT, "unknown (*,8i)*n"s, diag)
DB          }
DB
DB          when (CC$BSY)
DB             call print(STDOUT, "CC$BSY*n"s)
DB
DB          when (CC$DWN)
DB             call print(STDOUT, "CC$DWN*n"s)
DB
DB          when (CC$RPE)
DB             call print(STDOUT, "CC$RPE*n"s)
DB
DB          when (CC$RRC)
DB             call print(STDOUT, "CC$RRC*n"s)
DB
DB          when (CC$BAD)
DB             call print(STDOUT, "CC$BAD*n"s)
DB
DB          when (CC$BAR)
DB             call print(STDOUT, "CC$BAR*n"s)
DB
DB          when (CC$LPE)
DB             call print(STDOUT, "CC$LPE*n"s)
DB
DB          when (CC$NET)
DB             call print(STDOUT, "CC$NET*n"s)
DB
DB          when (CC$NOB)
DB             call print(STDOUT, "CC$NOB*n"s)
DB       else
DB          call print(STDOUT, "unknown (*,8i)*n"s, whyc)
DB    }

      when (XS$RST)
         call print(STDOUT, "Status is XS$RST*n"s)

DB    when (XS$IDL)
DB       call print(STDOUT, "Status is XS$IDL*n"s)

      when (XS$UNK)
         call print(STDOUT, "Status is XS$UNK*n"s)

      when (XS$MEM)
         call print(STDOUT, "Status is XS$MEM*n"s)

DB    when (XS$NOP)
DB       call print(STDOUT, "Status is XS$NOP*n"s)

      when (XS$ILL)
         call print(STDOUT, "Status is XS$ILL*n"s)

DB    when (XS$DWN)
DB       call print(STDOUT, "Status is XS$DWN*n"s)

      when (XS$MAX)
         call print(STDOUT, "Status is XS$MAX*n"s)

      when (XS$QUE)
         call print(STDOUT, "Status is XS$QUE*n"s)
DB else
DB    call print(STDOUT, "Unknown status (*i)*n"s, code)

   return (flag)
   end


   subroutine verify(node)

#  verify --- determine if RING connection is valid.

   pointer node

   include RING_COMMON

   logical valid

   pointer rcv, val

   SEARCH(Receive, NODE, NODE(node), rcv, 0)

   if (rcv == Receive || ~valid(STAT(rcv)))
   {
      call insert(Receive, node)

      call x$acpt(VCID(node), STAT(node))
DB    call print(STDOUT, "Ring connection accepted*n"s)

      call x$rcv(VCID(node), BUFF(node), BUFFSIZE, RCVS(node))
DB    call print(STDOUT, "Awaiting reception of password*n"s)

      SEARCH(Validate, NODE, NODE(node), val, 0)

      if (val ~= Validate && valid(STAT(val)))
      {
         call terminate(val)
DB       call print(STDOUT, "Invalid validation circuit cleared*n"s)
      }

      call allocate(val)
      TYPE(val) = VALID
      NODE(val) = NODE(node)
      call insert(Validate, val)

      call x$conn(VCID(val), CHCK, Node_name(1, Index_ring(NODE(val))),
                           Name_size(Index_ring(NODE(val))), STAT(val))
DB    call print(STDOUT, "Validation connection made to *,#h*n"s,
DB       Name_size(Index_ring(NODE(val))), Node_name(1, Index_ring(NODE(val))))
   }
   else
   {
      call terminate(node)
DB    call print(STDOUT, "Duplicate receive circuit cleared*n"s)

      call dispose(node)
   }

   return
   end


   logical function wizard(user)

#  wizard --- determine if user is validated for special requests.

   integer user(ARB)

   include RING_COMMON

   integer ptoc, equal

   character line(MAXLINE)

   integer i
   logical match

   string_table guru_index, guru_table, _
      /  "SYSTEM" _
      /  "TERREL" _
      /  "HUNT" _
      /  "JEFF" _
      /  "ROY" _
      /  "WAN"

   call ptoc(user, " "c, line, 2 * NAMESIZE + 1)

   i = 1
   repeat
   {
      i += 1

      match = equal(line, guru_table(guru_index(i))) == YES
   }
   until (i > guru_index(1) || match)

   return (match)
   end
