-- File: PupErrors.mesa,  Last Edit: BLyon January 16, 1981  2:50 PM

DIRECTORY
  StatsDefs USING [StatIncr],
  PupRouterDefs USING [SneakySendUnlocked],
  PupStream USING [CloseReason],
  PupDefs,
  CommFlags USING [doStats, doDebug],
  DriverDefs USING [Glitch, Network, PutOnGlobalDoneQueue, GetDeviceChain],
  BufferDefs, -- SHARES
  PupTypes USING [allHosts, PupErrorCode, PupSocketID],
  DriverTypes USING [bufferSeal];

PupErrors: PROGRAM
  IMPORTS StatsDefs, PupRouterDefs, DriverDefs, PupDefs
  EXPORTS BufferDefs, PupRouterDefs, PupStream, PupDefs
  SHARES BufferDefs =
  BEGIN OPEN DriverDefs, PupDefs;

  Network: PUBLIC TYPE = DriverDefs.Network;

  -- PktStream/ByteStream SIGNALs live here so they are defined only once
  StreamClosing: PUBLIC ERROR [why: PupStream.CloseReason, text: STRING] = CODE;
  RejectThisRequest: PUBLIC ERROR [error: STRING] = CODE;


  suppressErrors: BOOLEAN ← FALSE;
  suppressBufferFull: BOOLEAN ← FALSE;

  BufferSealBroken: PUBLIC ERROR = CODE;
  BufferDidntArrive: PUBLIC ERROR = CODE;

  SetErrorSuppression: PUBLIC PROCEDURE [dontSendErrors: BOOLEAN] =
    BEGIN suppressErrors ← dontSendErrors; END;

  SetBufferFullSuppression: PUBLIC PROCEDURE [dontSend: BOOLEAN] =
    BEGIN suppressBufferFull ← dontSend; END;


  RejectPupWithBadChecksum: PUBLIC PROCEDURE [b: PupBuffer] =
    BEGIN Reject[b, badChecksumPupErrorCode]; END;

  Reject: PUBLIC PROCEDURE [b: PupBuffer, code: PupTypes.PupErrorCode] =
    BEGIN
    IF BuildErrorPup[b, code, NIL] THEN PupRouterDefs.SneakySendUnlocked[b];
    END;

  SendErrorPup: PUBLIC PROCEDURE [
    b: PupBuffer, code: PupTypes.PupErrorCode, text: STRING] =
    BEGIN IF BuildErrorPup[b, code, text] THEN PupRouterSendThis[b]; END;

  BuildErrorPup: PUBLIC PROCEDURE [
    b: PupBuffer, code: PupTypes.PupErrorCode, text: STRING]
    RETURNS [ok: BOOLEAN] =
    BEGIN
    i: CARDINAL;
    p: LONG POINTER TO ARRAY [0..9] OF WORD = LOOPHOLE[@b.pupLength];
    temp: PupTypes.PupSocketID;
    network: Network ← b.network;
    IF CommFlags.doDebug AND b.seal # DriverTypes.bufferSeal THEN
      Glitch[BufferSealBroken];
    IF suppressErrors OR
      (suppressBufferFull AND code = resourceLimitsPupErrorCode) OR b.pupType =
      error OR b.dest.host = PupTypes.allHosts THEN
      BEGIN DriverDefs.PutOnGlobalDoneQueue[b]; RETURN[FALSE]; END;
    IF CommFlags.doDebug AND network = NIL THEN Glitch[BufferDidntArrive];
    IF network.netNumber.b > 377B THEN network ← DriverDefs.GetDeviceChain[];
    FOR i: CARDINAL IN [0..9] DO b.errorHeader[i] ← p[i]; ENDLOOP;
    b.pupType ← error;
    b.errorCode ← code;
    b.errorOptions ← 0;
    temp ← b.dest.socket;
    b.dest ← b.source;
    b.source ← [[network.netNumber.b], [network.hostNumber], temp];
    IF text = NIL THEN
      SELECT code FROM
	badChecksumPupErrorCode => text ← "Bad Software Checksum"L;
	noProcessPupErrorCode => text ← "No such Port"L;
	resourceLimitsPupErrorCode => text ← "Buffers full"L;
	ENDCASE => NULL;
    IF text # NIL THEN
      BEGIN
      FOR i ← 0, i + 1 UNTIL i = text.length DO b.errorText[i] ← text[i]; ENDLOOP;
      END
    ELSE i ← 0;
    SetPupContentsBytes[b, 2*(10 + 1 + 1) + i]; -- Yetch
    IF CommFlags.doStats THEN StatsDefs.StatIncr[statErrorPupsSent];
    RETURN[TRUE];
    END;

  END.