-- RPCTest.mesa
-- Andrew Birrell  January 27, 1983 10:40 am

DIRECTORY
Process, MesaRPC, RPCLupine, Runtime, SpyClient, System;

RPCTest: MONITOR
IMPORTS Process, MesaRPC, RPCLupine, Runtime, SpyClient, System =

BEGIN

-- ******** Test program ******** --

Finished: SIGNAL = CODE;
signalFinished: BOOLEAN ← TRUE;
extraArgPkts:   CARDINAL ← 0;
extraArgLength: RPCLupine.DataLength ← RPCLupine.maxDataLength-1;
argLength:      RPCLupine.DataLength ← 1;
extraResPkts:   CARDINAL ← 0;
extraResLength: RPCLupine.DataLength ← RPCLupine.maxDataLength;
resLength:      RPCLupine.DataLength ← 2;
callDelaySecs:  CARDINAL ← 0;
senderGapSecs:  CARDINAL ← 0;
receiverGapSecs:CARDINAL ← 0;
callGapSecs:    CARDINAL ← 0;
tries:          CARDINAL ← 1000;
quit:           BOOLEAN ← FALSE;
raiseSignal:    BOOLEAN ← FALSE;
resumeSignal:   BOOLEAN ← TRUE;
authenticate:   BOOLEAN ← TRUE;
gvExport:       BOOLEAN ← TRUE;
gvInstance:     STRING = "RPCRuntime.pa";
nongvInstance:  STRING = "Tokay";
callerName:     MesaRPC.Principal ← "Test.pa";
callerKey:      MesaRPC.EncryptionKey ← MesaRPC.MakeKey["Test"L];
exporterName:   MesaRPC.Principal ← "RPCRuntime.pa";
exporterKey:    MesaRPC.EncryptionKey ← MesaRPC.MakeKey["zzy"L];
userTest:       BOOLEAN ← TRUE;
spyWanted:      BOOLEAN ← FALSE;
minWanted:      BOOLEAN ← TRUE;
caller: PROCESS;

pktSpace: ARRAY[1..RPCLupine.pktOverhead+RPCLupine.maxDataLength] OF WORD;
pkt: RPCLupine.StubPkt = RPCLupine.GetStubPkt[@pktSpace];
import: RPCLupine.ImportHandle ← NIL;
conversation: MesaRPC.Conversation;


-- Test version of stub code --

RemoteSignal: SIGNAL = CODE;

SignalDispatcher: RPCLupine.Dispatcher =
  BEGIN
  UNTIL lastPkt
  DO [callLength,lastPkt] ← RPCLupine.ReceiveExtraPkt[pkt] ENDLOOP;
  SIGNAL RemoteSignal[];
  RETURN[0]
  END;

Send: PROC =
  BEGIN
  [] ← RPCLupine.StartCall[pkt, import, conversation];
  FOR p: CARDINAL IN [1..extraArgPkts]
  DO RPCLupine.SendPrelimPkt[pkt, extraArgLength];
     IF senderGapSecs > 0
     THEN Process.Pause[Process.SecondsToTicks[senderGapSecs]];
  ENDLOOP;
  BEGIN
    length: RPCLupine.DataLength;
    last: BOOLEAN;
    [length, last] ← RPCLupine.Call[pkt, argLength, RPCLupine.maxDataLength, SignalDispatcher];
    UNTIL last
    DO IF receiverGapSecs > 0
       THEN Process.Pause[Process.SecondsToTicks[receiverGapSecs]];
       [length, last] ← RPCLupine.ReceiveExtraPkt[pkt];
    ENDLOOP;
  END;
  END;

TestDispatcher: RPCLupine.Dispatcher =
  BEGIN
  -- Dummy dispatcher: consumes args and sends dummy result --
  UNTIL lastPkt
  DO IF receiverGapSecs > 0
     THEN Process.Pause[Process.SecondsToTicks[receiverGapSecs]];
     [callLength,lastPkt] ← RPCLupine.ReceiveExtraPkt[pkt];
  ENDLOOP;
  Client[ ! RemoteSignal =>
          BEGIN
	  RPCLupine.StartSignal[pkt];
	  [callLength,lastPkt] ← RPCLupine.Call[pkt, 0, RPCLupine.maxDataLength, NIL];
	  UNTIL lastPkt
	  DO [callLength,lastPkt] ← RPCLupine.ReceiveExtraPkt[pkt] ENDLOOP;
	  RESUME
	  END ];
  IF callDelaySecs > 0
  THEN Process.Pause[Process.SecondsToTicks[callDelaySecs]];
  FOR res: CARDINAL IN [1..extraResPkts]
  DO RPCLupine.SendPrelimPkt[pkt,extraResLength];
     IF senderGapSecs > 0
     THEN Process.Pause[Process.SecondsToTicks[senderGapSecs]];
  ENDLOOP;
  RETURN[resLength];
  END;


-- Test version of client code --

Client: PROC = { IF raiseSignal THEN SIGNAL RemoteSignal[] };
-- remote procedure being called! --

instance: STRING ← IF gvExport THEN gvInstance ELSE nongvInstance;

exported: BOOLEAN ← FALSE;
expHandle: RPCLupine.ExportHandle;

Work: PROC =
  BEGIN
  import ← RPCLupine.ImportInterface[["RPC-Test"L, instance], [0,0] !
     MesaRPC.ImportFailed =>
       IF why = unbound OR why = communications
       THEN BEGIN
            expHandle ← RPCLupine.ExportInterface[exporterName, exporterKey,
		                    ["RPC-Test"L, instance], TestDispatcher, [0,0]];
	    exported ← TRUE;
            import ← RPCLupine.ImportInterface[["RPC-Test"L, instance],[0,0]];
            CONTINUE
            END ];


   BEGIN
     spyAvailable: BOOLEAN = Runtime.IsBound[SpyClient.StartSpy];
     DO UNTIL userTest OR quit DO Process.Pause[Process.SecondsToTicks[5]] ENDLOOP;
	IF quit THEN EXIT;
        conversation ← IF authenticate
                       THEN MesaRPC.StartConversation[callerName, callerKey, exporterName, CBCCheck]
	               ELSE MesaRPC.unencrypted;
	Send[! RemoteSignal => IF resumeSignal THEN RESUME ELSE CONTINUE];
	Send[! RemoteSignal => IF resumeSignal THEN RESUME ELSE CONTINUE];
        IF spyWanted AND spyAvailable THEN SpyClient.StartSpy[];
        BEGIN
	    start:     System.Pulses = System.GetClockPulses[];
            end:       System.Pulses;
	    minPulses: LONG CARDINAL ← LAST[LONG CARDINAL];
            elapsed:   System.Microseconds;
	    minTime:   System.Microseconds;  
	    FOR call: CARDINAL IN [1..tries]
            DO thisStart: System.Pulses;
	       thisPulses:  LONG CARDINAL;
	       IF minWanted THEN thisStart ← System.GetClockPulses[];
	       Send[! RemoteSignal => IF resumeSignal THEN RESUME ELSE CONTINUE];
	       IF minWanted
	       THEN BEGIN
	            IF thisPulses < minPulses THEN minPulses ← thisPulses;
		    thisPulses ← System.GetClockPulses[] - thisStart;
		    END;
               IF callGapSecs > 0
               THEN Process.Pause[Process.SecondsToTicks[callGapSecs]];
            ENDLOOP;
            end ← System.GetClockPulses[];
	    IF spyWanted AND spyAvailable THEN SpyClient.StopSpy[];
            elapsed ← System.PulsesToMicroseconds[[end-start]];
	    minTime ← System.PulsesToMicroseconds[[minPulses]];
	    IF authenticate THEN MesaRPC.EndConversation[conversation];
            IF signalFinished THEN SIGNAL Finished[];
	  END;
       ENDLOOP;
     
  END;
  IF exported THEN [] ← RPCLupine.UnexportInterface[expHandle];
  END;

caller ← FORK Work[];

END.