-- Copyright (C) 1981, 1983, 1985  by Xerox Corporation. All rights reserved. 
-- EnquiryPup.mesa, HGM,  8-Feb-85 11:48:07 
-- From OthelloPup.mesa of 12-Jul-83 16:44:29. 

DIRECTORY
  Ascii USING [CR],
  Buffer USING [GetBuffer, ReturnBuffer],
  Driver USING [Network, GetDeviceChain],
  EnquiryDefs USING [Handle],
  EthernetDriverFriends USING [EtherStatsInfo],
  Format USING [NetworkNumber],
  Process USING [Detach, Yield],
  PupDefs USING [
    AppendPupAddress, DataWordsPerPupBuffer, GetPupAddress,
    GetPupContentsBytes, PupBuffer, PupNameTrouble,
    PupSocket, PupSocketDestroy, PupSocketMake,
    SecondsToTocks, SetPupContentsBytes],
  PupRouterDefs USING [GetRoutingTable, RoutingTableEntry, RoutingTableObject],
  PupPktOps USING [pupBuffers],
  PupTypes USING [echoSoc, fillInSocketID, maxDataWordsPerGatewayPup, PupAddress],
  String USING [AppendNumber],
  System USING [NetworkNumber];

EnquiryPup: PROGRAM
  IMPORTS Buffer, Driver, Format, Process, PupDefs, PupPktOps, PupRouterDefs, String
  EXPORTS EnquiryDefs =
  BEGIN

  PupEcho: PUBLIC PROC [str: EnquiryDefs.Handle, target: LONG STRING] =
    BEGIN OPEN PupDefs, PupTypes;
    bytesPerBuffer: CARDINAL;
    funny, late: LONG CARDINAL ← 0;
    recv, sent: LONG CARDINAL ← 0;
    wrong: LONG CARDINAL ← 0;
    me, where: PupAddress ← [, , echoSoc];
    mySoc: PupSocket;
    packetNumber: CARDINAL ← 0;
    pleaseStop: BOOLEAN ← FALSE;
    routing: PupRouterDefs.RoutingTableEntry;
    Watch: PROC = {[] ← str.ReadChar[]; pleaseStop ← TRUE};
    PrintErrorPup: PROC [b: PupDefs.PupBuffer] = {
      source: PupTypes.PupAddress ← b.pup.source;
      str.WriteChar[Ascii.CR];
      IF b.pup.pupType = error THEN {
        len: CARDINAL = PupDefs.GetPupContentsBytes[b];
        str.WriteString["[Error Pup, code="L];
        WriteOctal[str, LOOPHOLE[b.pup.errorCode]];
        str.WriteString[", from: "L];
        PrintPupAddress[str, source];
        str.WriteString["] "L];
        FOR i: CARDINAL IN [0..len - 2*(10 + 1 + 1)) DO
          str.WriteChar[b.pup.errorText[i]] ENDLOOP}
      ELSE {
        str.WriteString[" ***** "L];
        str.WriteString["Funny PupType = "L];
        WriteOctal[str, LOOPHOLE[b.pup.pupType]];
        str.WriteString[" ***** "L]; };
      str.WriteChar[Ascii.CR]; };

    str.WriteChar[Ascii.CR];
    PupDefs.GetPupAddress[
      @where, target ! PupNameTrouble => {
        FOR i: CARDINAL IN [0..e.length) DO str.WriteChar[e[i]]; ENDLOOP;
        str.WriteChar[Ascii.CR];
        GOTO Return;}];
    mySoc ← PupSocketMake[fillInSocketID, where, SecondsToTocks[2]];
    me ← mySoc.getLocalAddress[];
    str.WriteString[".   ["L];
    PrintPupAddress[str, me];
    str.WriteString["] => ["L];
    routing ← @PupRouterDefs.GetRoutingTable[][where.net];
    IF routing = NIL OR routing.network = NIL THEN {
      str.WriteString["Can't reach that network"L]; GOTO Return;};
    IF routing.hop # 0 THEN {
      WriteOctal[str, routing.network.pupNetNumber];
      str.WriteChar['#];
      WriteOctal[str, routing.route];
      str.WriteChar['#];
      str.WriteString["] => ["L]; };
    PrintPupAddress[str, where];
    str.WriteChar[']];
    str.WriteChar[Ascii.CR];
    Process.Detach[FORK Watch[]];
    bytesPerBuffer ← 2*MIN[DataWordsPerPupBuffer[], maxDataWordsPerGatewayPup];
    UNTIL pleaseStop DO
      FOR len: CARDINAL IN [0..bytesPerBuffer] UNTIL pleaseStop DO
        b: PupBuffer ← Buffer.GetBuffer[
	  type: pup, function: send, aH: PupPktOps.pupBuffers];
        b.pup.pupID.a ← b.pup.pupID.b ← (packetNumber ← packetNumber + 1);
        b.pup.pupType ← echoMe;
        SetPupContentsBytes[b, len];
        FOR i: CARDINAL IN [0..len) DO b.pup.pupBytes[i] ← i ENDLOOP;
        mySoc.put[b];
        sent ← sent + 1;
        Process.Yield[];  -- be sure we don't hog machine
        UNTIL (b ← mySoc.get[]) = NIL DO
          SELECT TRUE FROM
            (b.pup.pupType # iAmEcho) => {funny ← funny + 1; PrintErrorPup[b]; };
            ((b.pup.pupID.a # packetNumber) OR (b.pup.pupID.b # packetNumber)
              OR (len # GetPupContentsBytes[b])) => {
              str.WriteChar['#]; late ← late + 1};
            ENDCASE => {
              FOR i: CARDINAL IN [0..len) DO
                IF b.pup.pupBytes[i] # (i MOD 400B) THEN {
                  wrong ← wrong + 1; str.WriteChar['~]; GOTO Wrong};
                ENDLOOP;
              str.WriteChar['!];
              recv ← recv + 1;
              EXIT};
          Buffer.ReturnBuffer[b];
          REPEAT Wrong => NULL;
          ENDLOOP;
        IF b # NIL THEN Buffer.ReturnBuffer[b] ELSE str.WriteChar['?];
       str.SendNow[];
       ENDLOOP;
      str.WriteChar[Ascii.CR];
      ENDLOOP;
    PupSocketDestroy[mySoc];
    str.WriteString["Out: "L];
    str.WriteLongDecimal[sent];
    str.WriteString[", In: "L];
    str.WriteLongDecimal[recv];
    IF sent # 0 THEN { -- Avoid divide by 0
      str.WriteString[" ("L];
      str.WriteLongDecimal[(recv*100)/sent];
      str.WriteString["%)"L];
      IF late # 0 THEN {
        str.WriteString["\nLate: "L];
        str.WriteLongDecimal[late];
        str.WriteString[" ("L];
        str.WriteLongDecimal[(late*100)/sent];
        str.WriteString["%)"L]; }; };
    str.WriteString["\n"L];
    IF funny # 0 THEN {str.WriteLongDecimal[funny]; str.WriteString[" funny.\n"L];};
    IF wrong # 0 THEN {str.WriteLongDecimal[wrong]; str.WriteString[" wrong data.\n"L];};
    EXITS Return => NULL;
    END;

  PupRoutingTable: PUBLIC PROC [str: EnquiryDefs.Handle] =
    BEGIN
    pupRt: LONG DESCRIPTOR FOR ARRAY OF PupRouterDefs.RoutingTableObject;
    k: CARDINAL ← 0;

    str.WriteChar[Ascii.CR];
    str.WriteString["|  Net   Via   Hops |  Net   Via   Hops |  Net   Via   Hops |\n"L];
    str.WriteString["|-------------------|-------------------|-------------------|\n"L];
    pupRt ← PupRouterDefs.GetRoutingTable[];
    FOR i: CARDINAL IN [0..LENGTH[pupRt]) DO
      -- prints 4 chars, octal, no trailing B
      O4: PROC [n: CARDINAL] =
        BEGIN
        temp: STRING ← [50];
        String.AppendNumber[temp, n, 8];
	FOR i: CARDINAL IN [temp.length..4) DO str.WriteChar[' ]; ENDLOOP;
        str.WriteString[temp];
	END;
      O3Z: PROC [n: CARDINAL] = {
        n ← n MOD 1000B;
	THROUGH [0..3) DO str.WriteChar['0 + (n/100B) MOD 10B]; n ← n*10B ENDLOOP};
      r: PupRouterDefs.RoutingTableEntry = @pupRt[i];
      network: Driver.Network = r.network;
      IF network = NIL THEN LOOP;
      IF k = 0 THEN str.WriteChar['|];
      O4[i]; O4[network.pupNetNumber];
      str.WriteChar['#];
      O3Z[IF r.hop # 0 THEN r.route ELSE network.pupHostNumber];
      str.WriteChar['#];
      O4[r.hop]; str.WriteString["  |"L];
      IF (k ← k + 1) = 3 THEN {str.WriteChar[Ascii.CR]; k ← 0};
      ENDLOOP;
    IF k # 0 THEN str.WriteChar[Ascii.CR];
    END;

  DriverStats: PUBLIC PROC [str: EnquiryDefs.Handle] =
    BEGIN
    firstNetwork: Driver.Network ← Driver.GetDeviceChain[];
    str.WriteChar[Ascii.CR];
    FOR network: Driver.Network ← firstNetwork, network.next UNTIL network = NIL DO
      SELECT network.device FROM
        ethernet, ethernetOne =>
	  BEGIN
          stats: LONG POINTER TO EthernetDriverFriends.EtherStatsInfo ← network.statsLevel0;
	  str.WriteString["Ethernet"L];
	  IF network.device = ethernetOne THEN str.WriteString["One"L];
	  str.WriteString[" Statistics for Pup "L];
	  WriteOctal[str, network.pupNetNumber];
	  str.WriteString["#"L];
	  WriteOctal[str, network.pupHostNumber];
	  str.WriteString["#, NS net "L];
	  WriteNetNumbers[str, network.netNumber];
	  str.WriteChar[Ascii.CR];
	  IF stats = NIL THEN
	    BEGIN
	    str.WriteString["*** NO DRIVER STATS ***\n"L];
	    LOOP;
	    END;
	  str.WriteString["  Rcv: pkts "L];
	  str.WriteLongDecimal[stats.packetsRecv];
	  str.WriteString[", words "L];
	  str.WriteLongDecimal[stats.wordsRecv];
	  str.WriteString[", bad "L];
	  str.WriteLongDecimal[stats.badRecvStatus];
	  str.WriteString[", missed "L];
	  str.WriteLongDecimal[stats.packetsMissed];
	  IF stats.idleInput # 0 THEN
            BEGIN
            str.WriteString[", idle "L];
            str.WriteLongDecimal[stats.idleInput];
            END;
	  str.WriteChar[Ascii.CR];
	  IF stats.badRecvStatus # 0 OR stats.okButDribble # 0 THEN
            BEGIN
            str.WriteString["    crc "L];
            str.WriteLongDecimal[stats.badCrc];
            str.WriteString[", bad alignment but ok crc "L];
            str.WriteLongDecimal[stats.badAlignmentButOkCrc];
            str.WriteString[", crc and bad alignment "L];
            str.WriteLongDecimal[stats.crcAndBadAlignment];
            str.WriteChar[Ascii.CR];
            str.WriteString["    ok but dribble "L];
            str.WriteLongDecimal[stats.okButDribble];
            str.WriteString[", too long "L];
            str.WriteLongDecimal[stats.packetTooLong];
            str.WriteString[", overrun "L];
            str.WriteLongDecimal[stats.overrun];
            str.WriteChar[Ascii.CR];
            END;
	  str.WriteString["  Xmit: pkts "L];
	  str.WriteLongDecimal[stats.packetsSent];
	  str.WriteString[", words "L];
	  str.WriteLongDecimal[stats.wordsSent];
	  str.WriteString[", bad "L];
	  str.WriteLongDecimal[stats.badSendStatus];
	  str.WriteChar[Ascii.CR];
	  IF stats.stuckOutput # 0 OR stats.badSendStatus # 0
	    OR stats.tooManyCollisions # 0 THEN
            BEGIN
            str.WriteString["    underrun "L];
            str.WriteLongDecimal[stats.underrun];
            str.WriteString[", stuck "L];
            str.WriteLongDecimal[stats.stuckOutput];
            str.WriteString[", too many collisions "L];
            str.WriteLongDecimal[stats.tooManyCollisions];
            str.WriteChar[Ascii.CR];
            END;
	  str.WriteString["  Lds:"L];
	  FOR i: CARDINAL IN [0..16) DO
            str.WriteChar[' ]; str.WriteLongDecimal[stats.loadTable[i]]; ENDLOOP;
	  str.WriteChar[Ascii.CR];
          END;
        ENDCASE => NULL;
      ENDLOOP;
    END;

  WriteNetNumbers: PROCEDURE [str: EnquiryDefs.Handle, net: System.NetworkNumber] =
    BEGIN
    Push: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] =
      BEGIN FOR i: CARDINAL IN [0..s.length) DO str.WriteChar[s[i]]; ENDLOOP; END;
    Format.NetworkNumber[Push, net, productSoftware];
    str.WriteString["="L];
    Format.NetworkNumber[Push, net, octal];
    END;
      
  WriteOctal: PROC [str: EnquiryDefs.Handle, n: CARDINAL] =
    BEGIN
    temp: STRING ← [50];
    String.AppendNumber[temp, n, 8];
    str.WriteString[temp];
    END;

  PrintPupAddress: PROC [str: EnquiryDefs.Handle, a: PupTypes.PupAddress] =
    BEGIN
    temp: STRING ← [50];
    PupDefs.AppendPupAddress[temp, a];
    str.WriteString[temp];
    END;

  END.....