-- TeleLoadImpl6.mesa
-- Last Modified By L. Stewart On September 7, 1982  10:34 PM

DIRECTORY
  PupDefs,
  PupTypes,
  PupStream,
  Storage,
  TeleLoad6;

TeleLoadImpl6: PROGRAM
  IMPORTS PupDefs, PupStream, Storage
  EXPORTS TeleLoad6 =
  BEGIN OPEN TeleLoad6;

  MDSZoneRec: TYPE = MACHINE DEPENDENT RECORD [
    procs(0:0..15): POINTER TO MDSZoneProcsRec
    ];

  MDSZoneProcsRec: TYPE = MACHINE DEPENDENT RECORD [
    alloc(0): PROC [zone: MDSZone, size: CARDINAL] RETURNS [POINTER],
    dealloc(1): PROC [zone: MDSZone, object: POINTER]
    ];

  myMDSZoneRec: MDSZoneRec ← [procs: @myMDSZoneProcsRec];
  myMDSZoneProcsRec: MDSZoneProcsRec ← [alloc: myAlloc, dealloc: myDeAlloc];

  GetZone: PUBLIC PROC RETURNS [MDSZone] = { RETURN [LOOPHOLE[@myMDSZoneRec]]; };

  myAlloc: PROC [zone: MDSZone, size: CARDINAL] RETURNS [POINTER] = {
    RETURN [Storage.Node[size]];
    };

  myDeAlloc: PROC [zone: MDSZone, object: POINTER] = {
    Storage.Free[object];
    };

  Start: PUBLIC PROC [hostName: STRING]
    RETURNS [h: Handle] = {
    sendHim: PupTypes.PupAddress;
    sid: PupDefs.PupSocketID;
    allok: BOOLEAN ← TRUE;
    PupDefs.PupPackageMake[];
    sid ← PupDefs.UniqueLocalPupSocketID[];
    sendHim ← [
      PupTypes.fillInNetID, PupTypes.fillInHostID, teleSwatSocket];
    IF hostName.length = 0 THEN RETURN[NIL];
    PupStream.GetPupAddress[@sendHim, hostName !
      PupStream.PupNameTrouble => {allok ← FALSE; CONTINUE; }];
    IF NOT allok THEN RETURN[NIL];
    h ← Storage.Node[SIZE[TLObject]];
    IF h = NIL THEN ERROR;
    h.socket ← PupDefs.PupSocketMake[
      local: teleSwatSocket, remote: sendHim, ticks: PupDefs.SecondsToTocks[1]];
    IF h.socket = NIL THEN ERROR;
    h.myID.a ← LOOPHOLE[sid.a, CARDINAL]+LOOPHOLE[sid.b, CARDINAL];
    h.myID.b ← 0;
    h.attempts ← 5;
    RETURN[h];
    };

  Stop: PUBLIC PROC [h: Handle] = {
    IF h=NIL OR h.socket=NIL THEN RETURN;
    PupDefs.PupSocketDestroy[h.socket];
    PupDefs.PupPackageDestroy[];
    h.socket ← NIL;
    Storage.Free[h];
    };

  Store: PUBLIC PROC [h: Handle, cb: CoreBlock] RETURNS [Result] = {
    RETURN[GStore[h: h, requestcb: cb, type: coreStoreRequest]];
    };

  Fetch: PUBLIC PROC [h: Handle, cb: CoreBlock] RETURNS [Result] = {
    RETURN[GFetch[h: h, requestcb: cb, type: coreFetchRequest]];
    };

  StoreState: PUBLIC PROC [h: Handle, cb: CoreBlock] RETURNS [Result] = {
    RETURN[GStore[h: h, requestcb: cb, type: stateStoreRequest]];
    };

  FetchState: PUBLIC PROC [h: Handle, cb: CoreBlock] RETURNS [Result] = {
    RETURN[GFetch[h: h, requestcb: cb, type: stateFetchRequest]];
    };

  GStore: PUBLIC PROC [h: Handle, requestcb: CoreBlock, type: PupTypes.PupType] RETURNS [a: Result] = {
    b: PupDefs.PupBuffer ← NIL;
    replycb: CorePkt;
    IF h=NIL OR h.socket=NIL THEN RETURN[[success: FALSE, attempts: 0]];
    NewPupID[h];
    a.success ← TRUE;
    a.attempts ← 0;
    FOR i: INTEGER IN [1..h.attempts] DO
      a.attempts ← i;
      IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b];
      b ← PupDefs.GetFreePupBuffer[];
      replycb ← LOOPHOLE[@b.pupBody];
      replycb.address ← requestcb.address;
      replycb.count ← requestcb.count;
      FOR j: CARDINAL IN [0..requestcb.count) DO
        replycb.data[j] ← requestcb.data[j];
        ENDLOOP;
      PupDefs.SetPupContentsWords[b, SIZE[CorePktObject]+((requestcb.count+1)/2)];
      b ← Exchange[h, b, type];
      IF b=NIL THEN LOOP;
      replycb ← LOOPHOLE[@b.pupBody];
      IF NOT Check[requestcb, replycb] THEN LOOP;
      EXIT;
      REPEAT
      FINISHED => a.success ← FALSE;
      ENDLOOP;
    IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b];
    };

  GFetch: PUBLIC PROC [h: Handle, requestcb: CoreBlock, type: PupTypes.PupType] RETURNS [a: Result] = {
    b: PupDefs.PupBuffer ← NIL;
    replycb: CorePkt;
    IF h=NIL OR h.socket=NIL THEN RETURN[[success: FALSE, attempts: 0]];
    NewPupID[h];
    a.success ← TRUE;
    a.attempts ← 0;
    FOR i: INTEGER IN [1..h.attempts] DO
      a.attempts ← i;
      IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b];
      b ← PupDefs.GetFreePupBuffer[];
      replycb ← LOOPHOLE[@b.pupBody];
      replycb.address ← requestcb.address;
      replycb.count ← requestcb.count;
      PupDefs.SetPupContentsWords[b, SIZE[CorePktObject]];
      b ← Exchange[h, b, type];
      IF b=NIL THEN LOOP;
      replycb ← LOOPHOLE[@b.pupBody];
      IF replycb.address # requestcb.address THEN LOOP;
      IF replycb.count # requestcb.count THEN LOOP;
      FOR j: CARDINAL IN [0..requestcb.count) DO
        requestcb.data[j] ← replycb.data[j];
        ENDLOOP;
      EXIT;
      REPEAT
      FINISHED => a.success ← FALSE;
      ENDLOOP;
    IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b];
    };

  Exchange: PROC [h: Handle, request: PupDefs.PupBuffer, type: PupTypes.PupType] RETURNS[PupDefs.PupBuffer] = {
    reply: PupDefs.PupBuffer ← NIL;
    request.pupID ← h.myID;
    request.pupType ← type;
    h.socket.put[request];
    DO
      IF reply#NIL THEN PupDefs.ReturnFreePupBuffer[reply];
      reply ← h.socket.get[];
      IF reply = NIL THEN RETURN[NIL];
      IF reply.pupType # LOOPHOLE[LOOPHOLE[type, CARDINAL]+1] THEN LOOP;
      IF reply.pupID # h.myID THEN LOOP;
      RETURN[reply];
      ENDLOOP;
    };

  Check: PROC [a: CoreBlock, b: CorePkt]  RETURNS [BOOLEAN] = {
    IF a.address # b.address THEN RETURN[FALSE];
    IF a.count # b.count THEN RETURN[FALSE];
    FOR i: CARDINAL IN [0..a.count) DO
      IF a.data[i] # b.data[i] THEN RETURN[FALSE];
      ENDLOOP;
    RETURN[TRUE];
    };

  NewPupID: PROC [h: Handle] = { h.myID.b ← h.myID.b + 1; };

  END.
December 30, 1981  3:14 PM, Stewart, created from AudioSocket.mesa
July 20, 1982  10:23 AM, Stewart, Mesa6
July 27, 1982  3:59 PM, Stewart, MDSZone
September 7, 1982  10:34 PM, Stewart, added attempt counters