! TCP echo process.  Open a socket, repeatedly read, and echo everything
! straight back again.

%option "-NonStandard-NoCheck-NoTrace-NoDiag"

%constinteger echo port = 7
%constinteger echo key  = 1234

%include "Moose:Mouse.Inc"
%include "INet:INet.Inc"

%externalpredicatespec FS lookup(%string(31) what, %integername value)

%systemroutinespec phex(%integer x)

%recordformat connect fm(%integer ra, rp, lp)

%ownrecord(semaphore fm) semaphore = 0
%ownrecord(mailbox fm) reply box = 0
%ownrecord(mailbox fm)%name INet box

%begin
   %record(connect fm) c
   %record(INet user request fm) r = 0
   %record(INet user request fm)%name reply
   %integer i, unit = -1, port = -1
   %bytearray buffer(1 : 1024)
      open input(2, ":N");  select input(2)
      open output(2, ":T");  select output(2)

      setup semaphore(semaphore)
      setup mailbox(reply box, semaphore)
      setup message(r, size of(r))
      %if FS lookup(INet mailbox name, i) %start
         INet box == record(i)
      %else
         printstring("No INet mailbox?");  newline
         %stop
      %finish
      !! printstring("Echo: INet mailbox at ");  phex(addr(INet box))
      !! newline

the top:
      r_code = TCP allocate unit request
      r_key = echo key
      send message(r, INet box, reply box)
      reply == receive message(reply box)
      %if reply_status < 0 %start
         printstring("Allocate status ");  write(reply_status, 0);  newline
         %stop
      %finish
      !! printstring("Echo: Allocated unit ");  write(reply_unit, 0);  newline
      unit = reply_unit

      c_ra = 0;  c_rp = 0;  ! Passive
      c_lp = echo port
      r_code = TCP open request
      r_key = echo key
      r_unit = unit
      r_buffer == byteinteger(addr(c))
      r_bytes = 12
      send message(r, INet box, reply box)
      reply == receive message(reply box)
      %if reply_status < 0 %start
         printstring("Echo: Open status ");  write(reply_status, 0);  newline
         -> done
      %finish
      !! printstring("Echo: Opened to ");  phex(c_ra);  print symbol('.')
      !! write(c_rp, 0);  newline

      %cycle
         r_code = TCP receive request
         r_key = echo key
         r_unit = unit
         r_buffer == buffer(1)
         send message(r, INet box, reply box)
         reply == receive message(reply box)
         %if reply ## r %start
            printstring("Echo: Suspect reply at ");  phex(addr(reply))
            printstring(" ## ");  phex(addr(r));  newline
            %stop
         %finish
         %exit %if reply_status = closing error
         %if reply_status < 0 %start
            printstring("Echo: Receive status ");  write(reply_status, 0);  newline
            -> done
         %finish
         %if reply_bytes <= 0 %start
            printstring("Echo: received ");  write(reply_bytes, 0);  newline
            -> done
         %finish
         !! printstring("Echo: received ");  write(reply_bytes, 0);  newline
         r_code = TCP send request
         r_key = echo key
         r_unit = unit
         send message(r, INet box, reply box)
         reply == receive message(reply box)
         %if reply_status < 0 %start
            printstring("Echo: Send status ");  write(reply_status, 0);  newline
            -> done
         %finish
      %repeat

      !! printstring("Echo: Closed in, closing out...");  newline
      r_code = TCP close request
      r_key = echo key
      r_unit = unit
      send message(r, INet box, reply box)
      reply == receive message(reply box)
      %if reply_status < 0 %start
         printstring("Echo: Close status ");  write(reply_status, 0);  newline
         -> done
      %finish
      !! printstring("Echo: Closed out");  newline
      -> the top

done: r_code = TCP abort request
      r_key = echo key
      r_unit = unit
      send message(r, INet box, reply box)
      reply == receive message(reply box)
      %if reply_status < 0 %start
         printstring("Echo: Abort (done) status ");  write(reply_status, 0);  newline
      %finish
      !! printstring("Echo: Aborted");  newline
      -> the top
%end %of %program
