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

%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, bytes
   %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("INet mailbox at ");  phex(addr(INet box))
      !! newline

the top:
      r_code = UDP 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("Allocated unit ");  write(reply_unit, 0);  newline
      unit = reply_unit
   
      %cycle
         c_ra = 0;  c_rp = 0;  ! Wild
         c_lp = echo port
         r_code = UDP define context 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("Define status ");  write(reply_status, 0);  newline
            -> done
         %finish
   
         r_code = UDP 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)
         %exit %if reply_status = closing error
         %if reply_status < 0 %start
            printstring("Receive status ");  write(reply_status, 0);  newline
            -> done
         %finish
         %if reply ## r %start
            printstring("Suspect reply at ");  phex(addr(reply))
            printstring(" ## ");  phex(addr(r));  newline
            %stop
         %finish
         bytes = r_bytes

         !! r_code = UDP query context 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("Define status ");  write(reply_status, 0);  newline
         !!    -> done
         !! %finish
         !! printstring("Echo data from ");  phex(c_ra)
         !! print symbol('.');  write(c_rp, 0);  newline
   
         r_code = UDP data request
         r_key = echo key
         r_unit = unit
         r_buffer == buffer(1)
         r_bytes = bytes
         send message(r, INet box, reply box)
         reply == receive message(reply box)
         %if reply_status < 0 %start
            printstring("Send status ");  write(reply_status, 0);  newline
            -> done
         %finish
      %repeat

done: r_code = UDP forget context 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("Abort (done) status ");  write(reply_status, 0);  newline
      %finish
      -> the top
%end %of %program
