-- Pupwatch: communications and user interface -- [Indigo]PupWatch>Cedar>Looker.mesa -- Andrew Birrell February 17, 1983 1:14 pm -- DIRECTORY -- Look on [ivy]n.n>User> for Pine bcds (currently n.n = 6.1). Ascii USING[ CR, SP ], BufferDefs USING[ Buffer, PupBuffer ], --CommonPineDefs USING[DataRequest, Parameters], ConvertUnsafe USING[ ToRope ], DriverDefs USING[ ChangeNumberOfInputBuffers, GetDeviceChain ], Heap USING[ systemZone ], Inline USING[ BITAND, LongCOPY, HighHalf, LowHalf ], LookerDefs USING[ Clear, DiskChar, DiskCommit, DiskMultiple, DiskPos, GetLength, InputAction, NotePausing, NoteSlow, ScreenLines, SendNow, SetPos, DisplayChar, DisplayMultiple, WriteTitle ], --PrivateCommonPineDefs USING[pLeader], Process USING[ Abort, EnableAborts, Priority, priorityBackground, SetPriority ], PupDefs USING[ GetLocalPupAddress, GetPupAddress, PupAddress, PupNameTrouble, PupPackageMake ], PupTypes, Rope USING[ Fetch, Length, ROPE ], RPCWatch USING[ SetSpyProc ], Runtime USING[ IsBound ], Space USING[ Create, CreateUniformSwapUnits, Delete, Handle, LongPointer, Map, virtualMemory, wordsPerPage ], SpecialCommunication USING[ SetEthernetOneListener, SetSpyProc ], String, System USING[ Pulses, PulsesToMicroseconds ], TeledebugProtocol; Looker: MONITOR IMPORTS ConvertUnsafe, DriverDefs, Heap, Inline, LookerDefs, Process, PupDefs, Rope, RPCWatch, Runtime, Space, SpecialCommunication, String, System EXPORTS LookerDefs SHARES BufferDefs = BEGIN MSec: PROC[rawClock: System.Pulses] RETURNS[ LONG CARDINAL ] = INLINE { RETURN[System.PulsesToMicroseconds[rawClock]/1000] }; -- Pup level -- bufferSize: CARDINAL; maxPupLength: CARDINAL; bigPupLength: CARDINAL = PupTypes.maxDataBytesPerGatewayPup; smallPupLength: CARDINAL = 54; BufferData: TYPE = MACHINE DEPENDENT RECORD[ pupLength: CARDINAL, pupTransportControl: [0..256), pupType: PupTypes.PupType, pupID: PupTypes.Pair, dest: PupDefs.PupAddress, source: PupDefs.PupAddress, pupBody: SELECT OVERLAID * FROM big => [bigChars: PACKED ARRAY[0..bigPupLength) OF CHARACTER], small => [smallChars: PACKED ARRAY[0..smallPupLength) OF CHARACTER], pupChars => [pupChars: PACKED ARRAY[0..0) OF CHARACTER], pupBytes => [pupBytes: PACKED ARRAY[0..0) OF [0..377B]], pupWords => [pupWords: ARRAY[0..0) OF CARDINAL], pupString => [pupString: StringBody], rfc => [address: PupDefs.PupAddress ], ack => [maximumBytesPerPup, numberOfPupsAhead, numberOfBytesAhead: CARDINAL ], abort => [abortCode: CARDINAL, abortText: PACKED ARRAY [0..0) OF CHARACTER ], error => [errorHeader: ARRAY [0..9] OF WORD, errorCode: PupTypes.PupErrorCode, errorOptions: WORD, errorText: PACKED ARRAY [0..0) OF CHARACTER], nameIs => [nameIs: ARRAY [0..0) OF PupDefs.PupAddress ], ENDCASE ]; Buffer: TYPE = LONG POINTER TO BufferData; ContentsBytes: PROC[b: Buffer] RETURNS[CARDINAL] = INLINE { RETURN[ b.pupLength - 22 ] }; nBuffers: CARDINAL = 300; BufferIndex: TYPE = [0..nBuffers); bufferSpace: Space.Handle; buffers: LONG POINTER TO --ARRAY BufferIndex OF-- BufferData _ NIL; times: LONG POINTER TO ARRAY BufferIndex OF System.Pulses _ NIL; lost: PACKED ARRAY BufferIndex OF BOOLEAN _ ALL[FALSE]; logged: PACKED ARRAY BufferIndex OF BOOLEAN _ ALL[FALSE]; wBuffer: BufferIndex _ 0; -- buffer being written by ethernet driver -- rBuffer: BufferIndex _ 0; -- buffer Looker wants to read -- fullBuffers: [0..nBuffers] _ 0; bufferChange: CONDITION; lookerWaiting: BOOLEAN _ FALSE; allUsed: BOOLEAN _ FALSE; -- whether all buffers have been written -- AllocBuffers: ENTRY PROC[big: BOOLEAN] = BEGIN IF buffers # NIL THEN FreeBuffers[]; bufferSize _ IF big THEN SIZE[big BufferData] ELSE SIZE[small BufferData]; bufferSpace _ Space.Create[ size: (LONG[nBuffers] * bufferSize + Space.wordsPerPage-1) / Space.wordsPerPage, parent: Space.virtualMemory]; Space.Map[bufferSpace]; IF big THEN Space.CreateUniformSwapUnits[size: 20, parent: bufferSpace]; buffers _ Space.LongPointer[bufferSpace]; maxPupLength _ IF big THEN bigPupLength ELSE smallPupLength; times _ Heap.systemZone.NEW[ARRAY BufferIndex OF System.Pulses]; InnerFlush[]; END; FreeBuffers: PROC = BEGIN Space.Delete[bufferSpace]; Heap.systemZone.FREE[@times]; END; GetBuffer: ENTRY PROC RETURNS[BufferIndex] = --INLINE-- BEGIN ENABLE UNWIND => lookerWaiting _ FALSE; WHILE fullBuffers = 0 DO lookerWaiting _ TRUE; WAIT bufferChange ENDLOOP; lookerWaiting _ FALSE; RETURN[ rBuffer ] END; ReturnBuffer: ENTRY PROC = --INLINE-- { rBuffer _ IF rBuffer = LAST[BufferIndex] THEN 0 ELSE SUCC[rBuffer]; fullBuffers _ fullBuffers-1; NOTIFY bufferChange }; ReplayBuffers: ENTRY PROC = BEGIN rBuffer _ IF allUsed THEN IF wBuffer = LAST[BufferIndex] THEN 0 ELSE SUCC[wBuffer] ELSE 0; fullBuffers _ (wBuffer+nBuffers-rBuffer) MOD nBuffers; IF lookerWaiting THEN NOTIFY bufferChange; END; FlushBuffers: ENTRY PROC = { InnerFlush[] }; InnerFlush: INTERNAL PROC = BEGIN rBuffer _ wBuffer _ 0; fullBuffers _ 0; allUsed _ FALSE; lost _ ALL[FALSE]; logged _ ALL[FALSE]; waitingForBuffers _ FALSE; NOTIFY bufferChange; END; waitingForBuffers: BOOLEAN _ FALSE; NextBuffer: INTERNAL PROC = --INLINE-- BEGIN IF fullBuffers >= nBuffers/2 OR ( waitingForBuffers AND fullBuffers+50 >= nBuffers/2 --make sure we have 50 free--) THEN { waitingForBuffers _ TRUE; lost[wBuffer] _ TRUE; RETURN }; waitingForBuffers _ FALSE; IF wBuffer = LAST[BufferIndex] THEN { allUsed _ TRUE; wBuffer _ 0 } ELSE wBuffer _ SUCC[wBuffer]; fullBuffers _ fullBuffers+1; IF lookerWaiting THEN NOTIFY bufferChange; logged[wBuffer] _ lost[wBuffer] _ FALSE; END; wanted: PupDefs.PupAddress; myNet: CARDINAL _ 0; broadcast: BOOLEAN _ FALSE; ShowBroadcast: PUBLIC --ENTRY-- PROC[wanted: BOOLEAN] = BEGIN broadcast _ wanted; END; Driver: ENTRY PROC[b: BufferDefs.Buffer] RETURNS[BOOLEAN] = BEGIN IF b.encapsulation.ethernetType = pup AND ( ( (b.dest.host = wanted.host OR (broadcast AND b.dest.host = 0) OR wanted.host=0) AND ( b.dest.net = wanted.net OR ( b.dest.net = 0 AND wanted.net = myNet ) OR wanted.net = 0 ) ) OR ( ( b.source.host = wanted.host OR wanted.host = 0 ) AND ( b.source.net = wanted.net OR ( b.source.net = 0 AND wanted.net = myNet ) OR wanted.net = 0 ) ) ) THEN BEGIN myBuffer: BufferIndex = wBuffer; times[myBuffer] _ b.time; Inline.LongCOPY[from: @b.bufferBody, to: buffers + myBuffer * bufferSize, nwords: MIN[ (b.pupLength+1)/2, bufferSize ] ]; NextBuffer[]; END; RETURN[TRUE]--pkt still belongs to dispatcher-- END; RPCDriver: PROC[b: BufferDefs.PupBuffer] = BEGIN [] _ Driver[LOOPHOLE[b]]; --TEMP: patch to prevent RPCRuntime getting confused -- IF b.dest.host # 0 AND b.dest.host # realHost THEN b.pupType _ LOOPHOLE[0]; END; realHost: CARDINAL; TakeEthernet: ENTRY PROC = BEGIN realHost _ DriverDefs.GetDeviceChain[].hostNumber; DriverDefs.ChangeNumberOfInputBuffers[TRUE]; IF NOT SpecialCommunication.SetEthernetOneListener[ physicalOrder: 1, newHostNumber: 0--promiscuous--] THEN ERROR; SpecialCommunication.SetSpyProc[Driver]; IF Runtime.IsBound[RPCWatch.SetSpyProc] THEN RPCWatch.SetSpyProc[RPCDriver]; END; GiveEthernet: ENTRY PROC = BEGIN DriverDefs.ChangeNumberOfInputBuffers[FALSE]; IF NOT SpecialCommunication.SetEthernetOneListener[ physicalOrder: 1, newHostNumber: realHost] THEN ERROR; SpecialCommunication.SetSpyProc[NIL]; IF Runtime.IsBound[RPCWatch.SetSpyProc] THEN RPCWatch.SetSpyProc[NIL]; END; -- Synchronization with user type-in -- inputActive: BOOLEAN _ FALSE; lookerActive: BOOLEAN _ FALSE; pauseWanted: BOOLEAN _ FALSE; inputChange: CONDITION; lookerChange: CONDITION; wantedPriority: Process.Priority _ Process.priorityBackground; lookerPriority: Process.Priority; ActivateLooker: ENTRY PROC RETURNS[ BOOLEAN ] = --INLINE-- BEGIN ENABLE UNWIND => NULL; IF lookerPriority # wantedPriority THEN Process.SetPriority[lookerPriority _ wantedPriority]; IF inputActive OR pauseWanted THEN BEGIN WHILE inputActive OR pauseWanted DO WAIT inputChange ENDLOOP; RETURN[FALSE] END ELSE BEGIN lookerActive _ TRUE; RETURN[TRUE] END; END; DeactivateLooker: ENTRY PROC = INLINE { lookerActive _ FALSE; IF inputActive THEN NOTIFY lookerChange }; ActivateInput: ENTRY PROC = BEGIN ENABLE UNWIND => NULL; WHILE inputActive DO WAIT inputChange ENDLOOP; inputActive _ TRUE; WHILE lookerActive DO WAIT lookerChange ENDLOOP; END; DeactivateInput: ENTRY PROC = BEGIN inputActive _ FALSE; BROADCAST inputChange; END; NewPriority: PUBLIC ENTRY PROC[new: Process.Priority] = BEGIN wantedPriority _ new; END; -- Output subroutines -- mode: { display, disk} _ display; -- Display line layout is: -- 7777: from 77#377#777 [aData,L:777,to:177777]abcdefghijklmn -- 7777: to 77#377#777 [aData,L:777,to:177777]abcdefghijklmn tabFrom: REAL; tabTo: REAL; tabAddr: REAL; tabPkt: REAL; tabData: REAL; -- Disk log line layout is: -- 7777: from 377#377#377 [aData,L:1024,to:177777] abcdefghijklmn -- 7777: to 377#377#377 [aData,L:1024,to:177777] abcdefghijklmn diskFrom: CARDINAL; diskPkt: CARDINAL; diskDetails: CARDINAL; InitTabs: PROC = BEGIN tabFrom _ LookerDefs.GetLength["7777: "]; tabTo _ tabFrom + (LookerDefs.GetLength["from"]-LookerDefs.GetLength["to"]); tabAddr _ tabFrom + LookerDefs.GetLength["from "]; tabPkt _ tabAddr + LookerDefs.GetLength["77#777#777 "]; tabData _ tabPkt + LookerDefs.GetLength["[aData,L:777,to:177777]"]; diskFrom _ 6; -- "7777: " -- diskPkt _ diskFrom + 17; -- "from 377#377#377 " -- diskDetails _ diskPkt + 25; -- "[aData,L:1024,to:177777] " -- END; WriteChar: PROC[CHARACTER] _ LookerDefs.DisplayChar; WriteMultiple: PROC[LONG DESCRIPTOR FOR PACKED ARRAY OF CHARACTER] _ LookerDefs.DisplayMultiple; WriteString: PROC[s: LONG STRING] = { WriteMultiple[DESCRIPTOR[@(s.text),s.length]] }; WritePup: PROC[b: Buffer] = INLINE { WriteMultiple[DESCRIPTOR[@(b.pupChars), MIN[ContentsBytes[b],maxPupLength]]] }; WriteOctal777: PROC[n: CARDINAL] = BEGIN IF n >= 10B THEN BEGIN IF n >= 100B THEN WriteChar['0 + n / 100B]; WriteChar['0 + (n/10B) MOD 10B]; END; WriteChar['0 + n MOD 10B]; END; WriteOctal: PROC[n: CARDINAL] = INLINE BEGIN IF n < 1000B THEN WriteOctal777[n] ELSE WriteFullOctal[n]; END; WriteFullOctal: PROC[n: CARDINAL] = BEGIN WriteOctal777[n/1000B]; WriteChar['0 + ((n/100B) MOD 10B)]; WriteChar['0 + ((n/10B) MOD 10B)]; WriteChar['0 + n MOD 10B]; END; WriteLongOctal: PROC[n: LONG CARDINAL] = INLINE BEGIN IF Inline.HighHalf[n] # 0 THEN WriteOctal[Inline.HighHalf[n]]; WriteOctal[Inline.LowHalf[n]]; END; WritePair: PROC[p: PupTypes.Pair] = { WriteOctal[p.a]; WriteChar[',]; WriteOctal[p.b] }; WriteDecimal: PROC[n: CARDINAL] = INLINE { s: STRING = [5]; String.AppendDecimal[s,n]; WriteString[s] }; WriteAddr: PROC[addr: PupDefs.PupAddress] = INLINE BEGIN WriteOctal777[addr.net]; WriteChar['#]; WriteOctal777[addr.host]; WriteChar['#]; WriteOctal777[Inline.BITAND[addr.socket.b,777B]]; END; WriteID: PROC[n: CARDINAL] = INLINE BEGIN WriteString["to:"]; WriteOctal[n]; END; prevMS: LONG CARDINAL _ 0; -- layout of Pup id's for Sequin/Leaf protocol -- SequinID: TYPE = MACHINE DEPENDENT RECORD[ allocate: Byte, receiveSequence: Byte, control: SequinControl, sendSequence: Byte ]; Byte: TYPE = [0..256); SequinControl: TYPE = MACHINE DEPENDENT { data(0), ack(1), nop(2), restart(3), check(4), open(5), break(6), close(7), closed(8), destroy(9), dallying(10), quit(11), broken(12), retransmit(13), stifle(14), openclose(15), opendestroy(16), (255) }; leafSocket: PupTypes.PupSocketID = [a:0,b:43B]; lookupFileSocket: PupTypes.PupSocketID = [a:0,b:61B]; teleSwatSocket: PupTypes.PupSocketID = TeledebugProtocol.teleSwatSocket; Watch: PROC[ b: Buffer, time: System.Pulses ] = BEGIN DefaultBodyPrintout: PROC[b: Buffer] = INLINE { WriteString["L:"]; WriteOctal[ContentsBytes[b]] }; BEGIN mscSrv: BOOLEAN = b.source.socket = PupTypes.miscSrvSoc OR b.dest.socket = PupTypes.miscSrvSoc; leaf: BOOLEAN = b.source.socket = leafSocket OR b.dest.socket = leafSocket; lookupFile: BOOLEAN = b.source.socket = lookupFileSocket OR b.dest.socket = lookupFileSocket; teleSwat: BOOLEAN = b.source.socket = teleSwatSocket OR b.dest.socket = teleSwatSocket; newMS: LONG CARDINAL = MSec[time]; IF newMS >= prevMS + 10000 THEN IF newMS >= prevMS + 1000*LONG[1000] -- 1000 seconds -- THEN WriteString[IF prevMS = 0 THEN "first"L ELSE "long"L] ELSE BEGIN WriteDecimal[Inline.LowHalf[(newMS-prevMS)/1000]]; WriteChar['s]; END ELSE WriteDecimal[Inline.LowHalf[ (newMS-prevMS) MOD 10000 ]]; prevMS _ newMS; WriteChar[':]; IF mode = display THEN BEGIN IF b.source.host = wanted.host AND b.source.net = wanted.net THEN { LookerDefs.SetPos[tabTo]; WriteString["to"]; LookerDefs.SetPos[tabAddr]; WriteAddr[b.dest] } ELSE { LookerDefs.SetPos[tabFrom]; WriteString["from"]; LookerDefs.SetPos[tabAddr]; WriteAddr[b.source] }; LookerDefs.SetPos[tabPkt]; END ELSE BEGIN LookerDefs.DiskPos[diskFrom]; IF b.source.host = wanted.host AND b.source.net = wanted.net THEN { WriteString[" to "]; WriteAddr[b.dest] } ELSE { WriteString["from "]; WriteAddr[b.source] }; LookerDefs.DiskPos[diskPkt]; END; WriteChar['[]; BEGIN type: STRING = SELECT b.pupType FROM -- registered pup types echoMe => "echoMe", iAmEcho => "iAmEcho", badEcho => "badEcho", error => "error", rfc => "rfc", abort => "abort", end => "end", endRep => "endRep", data => "data", aData => "aData", ack => "ack", mark => "mark", int => "int", intRep => "intRep", aMark => "aMark", eData => "eData", eAck => "eAck", eEnd => "eEnd", eAbort => "eAbort", rpp => "rpp", -- Cedar RPC pup types. Bits are: -- 8..10: 3 (=> start at pt140) -- 11: {end(0),notEnd(1)} -- 12: {dontAck(0),pleaseAck(1)} -- 13..15: {call,data,ack,spare,rfa} LOOPHOLE[140B] => "RPC-call-end", LOOPHOLE[141B] => "RPC-data-end", LOOPHOLE[142B] => "RPC-ack", LOOPHOLE[143B] => "RPC-spare", LOOPHOLE[144B] => "RPC-RFA", LOOPHOLE[150B] => "RPC-a-call-end", LOOPHOLE[151B] => "RPC-a-data-end", LOOPHOLE[152B] => "RPC-ping", LOOPHOLE[153B] => "RPC-a-spare", LOOPHOLE[154B] => "RPC-a-RFA", LOOPHOLE[160B] => "RPC-call-more", LOOPHOLE[161B] => "RPC-data-more", LOOPHOLE[170B] => "RPC-a-call-more", LOOPHOLE[171B] => "RPC-a-data-more", -- unregistered pup types (possible overlap) gatewayRequest--200-- => IF lookupFile THEN "fileLookup" ELSE "gatewayRequest", --also dateTextRequest (socket 4), statisticsRequest (socket 22) gatewayInfo--201-- => IF lookupFile THEN "fileInfo" ELSE "gatewayInfo", --also dateTextIs (socket 4), statisticsAre (socket 22) dateTenexRequest--202-- => IF lookupFile THEN "fileError" ELSE IF teleSwat THEN "go" ELSE "dateTenexRequest", dateTenexIs--203-- => IF teleSwat THEN "goReply" ELSE "dateTenexIs", LOOPHOLE[204B] => IF teleSwat THEN "ack" ELSE "pt204", dateAltoRequest--206-- => "dateAltoRequest", dateAltoIs--207-- => "dateAltoIs", mailCheck--210-- => "mailCheck", mailIsNew--211-- => "mailIsNew", mailNotNew--212-- => "mailNotNew", mailError--213-- => "mailError", mailCheckLaurel--214-- => "mailCheckL", nameLookup--220-- => "nameLookup", nameIs--221-- => "nameIs", nameError--222-- => "nameError", addressLookup--223-- => "addrLookup", addressIs--224-- => "addrIs", whereIsUser--230-- => "whereIsUser", userIs--231-- => "userIs", userError--232-- => "userError", netDirVersion--240-- => "netDirVersion", --also eventReport (socket 30) sendNetDir--241-- => "sendNetDir", --also eventReportReply (socket 30) bootFileSend--244-- => "bootFileSend", kissOfDeath--247-- => "kissOfDeath", request--250-- => IF mscSrv THEN "userAuthReq" ELSE "request", result--251-- => IF mscSrv THEN "userAuthOk" ELSE "result", unsolicited--252-- => IF mscSrv THEN "userAuthBad" ELSE "unsolicited", custodian--253-- => "custodian", sync--254-- => "sync", pineAck--255-- => "pineAck", noop--256-- => "noop", bootDirReq--257-- => "bootDirReq", bootDirReply--260-- => IF NOT leaf THEN "bootDirReply" ELSE SELECT LOOPHOLE[b.pupID,SequinID].control FROM data=> "lData", ack=> "lAck", nop=> "nop", restart=> "restart", check=> "check", open=> "open", break=> "break", close=> "close", closed=>"closed", destroy=> "destroy", dallying=>"dallying", quit=> "quit", broken=>"broken", retransmit=> "retransmit", stifle=>"stifle", openclose=> "openClose", opendestroy=>"opendestroy", ENDCASE => "leaf?", TeledebugProtocol.coreStoreRequest--300-- => "wCore", TeledebugProtocol.coreFetchRequest--301-- => "rCore", TeledebugProtocol.diskAddressSetRequest--302-- => "diskAddr", TeledebugProtocol.diskStoreRequest--303-- => "wDisk", TeledebugProtocol.diskFetchRequest--304-- => "rDisk", ENDCASE => NIL; IF type = NIL THEN BEGIN WriteString["pt"]; WriteOctal[LOOPHOLE[b.pupType, CARDINAL]]; END ELSE WriteString[type]; END; WriteChar[',]; SELECT b.pupType FROM error => SELECT b.errorCode FROM badChecksumPupErrorCode => WriteString["badChecksum"]; noProcessPupErrorCode => WriteString["noSuchPort"]; resourceLimitsPupErrorCode => WriteString["resourceLimits"]; inconsistentPupErrorCode => WriteString["inconsistentPup"]; cantGetTherePupErrorCode => WriteString["cantGetThere"]; hostDownPupErrorCode => WriteString["hostDown"]; eightHopsPupErrorCode => WriteString["sixteenHops"]; tooBigPupErrorCode => WriteString["tooBigPup"]; iAmNotAGatewayPupErrorCode => WriteString["iAmNotAGateway"]; gatewayResourceLimitsPupErrorCode => WriteString["gatewayResources"]; ENDCASE => WriteOctal[LOOPHOLE[b.errorCode]]; mailCheck, mailCheckLaurel, nameLookup => IF mode # disk THEN WritePup[b]; nameIs => WriteAddr[b.nameIs[0]]; abort => WriteOctal[b.abortCode]; data, aData => BEGIN l: CARDINAL = ContentsBytes[b]; WriteID[b.pupID.b+l]; WriteString[",L:"]; WriteOctal[l]; END; ack => BEGIN WriteID[b.pupID.b]; WriteString[",pups:"]; WriteOctal777[b.numberOfPupsAhead]; END; mark, aMark => BEGIN WriteID[b.pupID.b+1]; WriteString[",mk:"]; WriteOctal777[b.pupBytes[0]]; END; rfc, echoMe => BEGIN wellKnown: STRING = SELECT b.dest.socket FROM PupTypes.telnetSoc => "telnet", PupTypes.gatewaySoc => "gateway", PupTypes.ftpSoc => "ftp", PupTypes.miscSrvSoc => "miscSrv", PupTypes.echoSoc => "echo", PupTypes.bspTestSoc => "bspTest", PupTypes.mailSoc => "mail", PupTypes.eftpReceiveSoc => "eftp", PupTypes.copyDiskSoc => "copyDisk", PupTypes.rpcpSoc => "rpcp", PupTypes.librarianSoc => "librarian", PupTypes.pineSoc => "pine", ENDCASE => NIL; IF wellKnown # NIL THEN WriteString[wellKnown] ELSE BEGIN IF b.dest.socket.b IN [50B..57B] AND b.dest.socket.a IN [0..1] THEN BEGIN -- RFC or EchoMe on a Grapevine socket -- gvSoc: STRING = SELECT b.dest.socket.b FROM 50B => "RS-enquire", 51B => "RS-update", 52B => "RS-poll", 53B => "GV-Lily", 54B => "MS-poll", 55B => "MS-forward", 56B => "MS-send", 57B => "MS-retrieve", ENDCASE => ERROR; IF b.dest.socket.a = 1 THEN WriteString["Test-"]; WriteString[gvSoc]; END ELSE IF b.dest.socket.a = 0 AND b.dest.socket.b IN [0 .. 256) THEN WriteOctal777[b.dest.socket.b]; END; END; end, endRep, int, intRep => NULL; IN [ LOOPHOLE[140B]..LOOPHOLE[171B] ] => --Cedar RPC packet-- BEGIN --*** RPC header layout, stolen from RPCPkt.mesa -- RPCHeader: TYPE = MACHINE DEPENDENT RECORD[ length (0:0..14): [0..77777B], oddByte (0:15..15): { no(0), yes(1) }, type (1): RPCPktType, destPSB (2): CARDINAL--PSB.PsbIndex--,-- field has 6 extra bits srcePSB (3): CARDINAL--PSB.PsbIndex--,-- field has 6 extra bits destHost (4): CARDINAL--Machine--, destSoc (5): PupTypes.PupSocketID, srceHost (7): CARDINAL--Machine--, srceSoc (8): PupTypes.PupSocketID, -- end of standard Pup header -- convLS (10): CARDINAL--PktConversationID--, convMS (11): CARDINAL, -- For secure conversations, the remainder of the packet must be encrypted -- pktID (12): RPCPktID, dispatcher (16): DispatcherDetails ]; RPCPktType: TYPE = MACHINE DEPENDENT RECORD[ -- "type" word of a Pup -- transport (0:0..7): [0..255], -- should be zero before sending -- subType (0:8..10): { rpc(3B), (7B) }, eom (0:11..11): { end(0), notEnd(1) }, ack (0:12..12): { dontAck(0), pleaseAck(1) }, class (0:13..15): { call(0), data(1), ack(2), rfa(4), (7) } ]; RPCPktID: TYPE = MACHINE DEPENDENT RECORD[ -- [ConversationID,PktID] uniquely identifies pkt for all hosts and time -- activity(0): CARDINAL--PSB.PsbIndex--,-- field has 6 extra bits-- callSeqLS(1): CARDINAL--CallCount--, callSeqMS(2): CARDINAL, pktSeq(3): CARDINAL ]; DispatcherDetails: TYPE = MACHINE DEPENDENT RECORD[ mds: CARDINAL, -- top half of dispatcher's MDS base address -- dispatcherID: LONG CARDINAL--DispatcherID--, dispatcherHint: CARDINAL--ExportHandle-- -- hint to exporter host's export table -- ]; --*** -- h: LONG POINTER TO RPCHeader = LOOPHOLE[b]; overhead: CARDINAL = SIZE[RPCHeader]+1--checksum--; WriteString["Len:"]; IF h.length < overhead THEN { WriteString["?-"L]; WriteOctal777[overhead-h.length] } ELSE WriteOctal777[h.length-overhead]; WriteString[",Cnv:"]; WriteOctal777[h.convLS MOD 1000B]; WriteString[",Call:"]; WriteOctal777[h.pktID.callSeqLS MOD 1000B]; WriteString[",Pkt:"]; WriteOctal777[h.pktID.pktSeq MOD 1000B]; IF h.type.class = call THEN { WriteString[",Disp:"]; WriteOctal777[h.dispatcher.dispatcherHint MOD 1000B] }; END; addressLookup => WriteAddr[b.nameIs[0]]; gatewayRequest => IF lookupFile AND mode # disk THEN WritePup[b]; bootDirReply => IF leaf THEN BEGIN id: SequinID = LOOPHOLE[b.pupID]; IF b.dest.socket = leafSocket THEN BEGIN WriteString["rec:"]; WriteOctal777[id.receiveSequence]; WriteString[",send:"]; WriteOctal777[id.sendSequence]; END ELSE BEGIN WriteString["send:"]; WriteOctal777[id.sendSequence]; WriteString[",rec:"]; WriteOctal777[id.receiveSequence]; END; -- WriteString[",alloc:"]; -- WriteOctal777[id.allocate]; IF id.control = data THEN BEGIN l: CARDINAL = ContentsBytes[b]; WriteString[",L:"]; WriteOctal[l]; END; END; request => IF mscSrv THEN WriteString[@(b.pupString)] --userAuthReq-- ELSE { -- Pine stuff commented out to save space - otherwise the compiler runs out -- Wr: PROC[s: STRING] = { WriteString[s] }; -- L: PrivateCommonPineDefs.pLeader = LOOPHOLE[@b.pupBody]; -- P: POINTER TO CommonPineDefs.Parameters = LOOPHOLE[@L.params]; -- WITH R: P.requestP SELECT FROM -- ReadPage => { Wr["ReadPage "]; WriteOctal[R.pageNumber] }; -- WritePage => { Wr["WritePage "]; WriteOctal[R.pageNumber] }; -- SetLength => { Wr["SetLength "]; WriteLongOctal[R.byteCount] }; -- ReadLength => Wr["ReadLength"]; -- CloseFile => Wr["CloseFile"]; -- DestroyAnonymousFile => Wr["DestroyAnonymousFile"]; -- ReadData => { Wr["ReadData "]; WriteLongOctal[R.firstBytePosition]; -- WriteString[" for "]; WriteOctal[R.byteCount] }; -- WriteData => { Wr["WriteData "]; WriteLongOctal[R.firstBytePosition]; -- WriteString[" for "]; WriteOctal[R.byteCount] }; -- ReadAttribute => { Wr["ReadAttribute "]; WriteOctal[R.attributeNumber] }; -- WriteAttribute => { Wr["WriteAttribute "]; WriteOctal[R.attributeNumber] }; -- SetReadLock => Wr["SetReadLock"]; -- SetWriteLock => Wr["SetWriteLock"]; -- ReleaseReadLock => Wr["ReleaseReadLock"]; -- ObtainCapability => Wr["ObtainCapability"]; -- Room => Wr["Room"]; -- ChangePassword => Wr["ChangePassword"]; -- OpenFile => Wr["OpenFile"]; -- CreateAnonymousFile => Wr["CreateAnonymousFile"]; -- FindFile => Wr["FindFile"]; -- LockQuery => Wr["LockQuery"]; -- TransCompletionQuery => Wr["TransCompletionQuery"]; -- OpenFileFromCapability => Wr["OpenFileFromCapability"]; -- Logout => Wr["Logout"]; -- CloseTransaction => Wr["CloseTransaction"]; -- AbortTransaction => Wr["AbortTransaction"]; -- LookupFile => Wr["LookupFile"]; -- CreateFile => Wr["CreateFile"]; -- DestroyFile => Wr["DestroyFile"]; -- RenameFile => Wr["RenameFile"]; -- NextFile => Wr["NextFile"]; -- NextFewFiles => Wr["NextFewFiles"]; -- ValidateYourLocks => Wr["ValidateYourLocks"]; -- ReleaseYourReadLocks => Wr["ReleaseYourReadLocks"]; -- ENDCASE => Wr["Unknown Request Variant"]; -- IF P.requestP.code IN CommonPineDefs.DataRequest THEN { -- Wr[" sfh "]; WriteOctal[P.h] }; }; result => IF mscSrv THEN DefaultBodyPrintout[b] --userAuthOk-- ELSE { -- More Pine stuff commented out ... -- Wr: PROC[s: STRING] = { WriteString[s] }; -- L: PrivateCommonPineDefs.pLeader = LOOPHOLE[@b.pupBody]; -- P: POINTER TO CommonPineDefs.Parameters = LOOPHOLE[@L.params]; -- WITH R: P.resultP SELECT FROM -- HeresData => { Wr["HeresData "]; WriteOctal[R.length] }; -- HeresLFH => Wr["HeresLFH"]; -- HeresEntry => Wr["HeresEntry"]; -- HeresFileList => { Wr["HeresFileList "]; WriteOctal[R.count] }; -- HeresFile => { Wr["HeresFile "]; WriteOctal[R.f] }; -- HeresLength => { Wr["HeresLength "]; WriteLongOctal[R.length] }; -- CommandAck => Wr["CommandAck"]; -- CommandNak => { Wr["CommandNak "]; WriteOctal[LOOPHOLE[R.en]] }; -- LoginResponse => Wr["LoginResponse"]; -- TransactionClosed => Wr["TransactionClosed"]; -- LogoutResponse => Wr["LogoutResponse"]; -- ResourceData => Wr["ResourceData"]; -- TransCompletionInfo => Wr["TransCompletionInfo"]; -- HeresRoom => Wr["HeresRoom"]; -- LockQueryResponse => Wr["LockQueryResponse"]; -- ENDCASE => Wr["Unknown Result Variant"]; }; unsolicited => IF mscSrv THEN DefaultBodyPrintout[b] --userAuthBad-- ELSE { -- More Pine stuff commented out ... -- L: PrivateCommonPineDefs.pLeader = LOOPHOLE[@b.pupBody]; -- P: POINTER TO CommonPineDefs.Parameters = LOOPHOLE[@L.params]; -- WITH R: P.unsolicitedP SELECT FROM -- TransactionAborted => WriteString["TransactionAborted"]; -- ReadLockBroken => WriteString["ReadLockBroken"]; -- ENDCASE => WriteString["Unknown Unsolicited Variant"]; }; custodian => { -- More Pine stuff commented out ... -- L: PrivateCommonPineDefs.pLeader = LOOPHOLE[@b.pupBody]; -- P: POINTER TO CommonPineDefs.Parameters = LOOPHOLE[@L.params]; -- WITH R: P.custodianP SELECT FROM -- Login => WriteString["Login"]; -- AddServer => WriteString["AddServer"]; -- ResourceLocation => WriteString["ResourceLocation"]; -- ENDCASE => WriteString["Unknown Custodian Variant"]; }; sync => NULL; pineAck => NULL; noop => NULL; TeledebugProtocol.coreStoreRequest, TeledebugProtocol.coreFetchRequest => IF teleSwat THEN WriteLongOctal[LOOPHOLE[@b.pupBody, LONG POINTER TO TeledebugProtocol.CoreStoreRequest].page]; TeledebugProtocol.diskAddressSetRequest, TeledebugProtocol.diskFetchRequest => IF teleSwat AND ContentsBytes[b] = 2*SIZE[TeledebugProtocol.DiskAddressSetRequest] THEN WriteLongOctal[LOOPHOLE[@b.pupBody, LONG POINTER TO TeledebugProtocol.DiskAddressSetRequest].page]; ENDCASE => DefaultBodyPrintout[b]; WriteChar[']]; IF mode = disk THEN BEGIN LookerDefs.DiskPos[diskDetails]; WriteString["ID="]; WritePair[b.pupID]; WriteString[" from="]; WritePair[LOOPHOLE[b.source.socket]]; WriteString[" to="]; WritePair[LOOPHOLE[b.dest.socket]]; BEGIN l: CARDINAL = MIN[ContentsBytes[b],maxPupLength]; WriteChar[Ascii.CR]; LookerDefs.DiskPos[diskFrom]; LookerDefs.DiskPos[diskPkt]; IF l = 0 THEN WriteString["{empty}"] ELSE WritePup[b]; WriteChar[Ascii.CR]; LookerDefs.DiskPos[diskFrom]; LookerDefs.DiskPos[diskPkt]; WriteString["Bytes="]; IF l = 0 THEN WriteString["{empty}"] ELSE FOR i: CARDINAL IN [0..l) DO WriteOctal777[b.pupBytes[i]]; WriteChar[Ascii.SP] ENDLOOP; WriteChar[Ascii.CR]; LookerDefs.DiskPos[diskFrom]; LookerDefs.DiskPos[diskPkt]; WriteString["Words="]; IF l = 0 THEN WriteString["{empty}"] ELSE FOR i: CARDINAL IN [0..l/2) DO WriteOctal[b.pupWords[i]]; WriteChar[Ascii.SP] ENDLOOP; END; END ELSE IF b.pupType = data OR b.pupType = aData THEN { LookerDefs.SetPos[tabData]; WritePup[b] }; WriteChar[Ascii.CR]; END; END; speed: {slow, fast} _ fast; lookerCount: CARDINAL; StartPause: PROC = BEGIN WriteString["Pausing ..."L]; LookerDefs.SendNow[]; LookerDefs.NotePausing[TRUE]; pauseWanted _ TRUE; END; LookerMain: PROC = BEGIN countLimit: CARDINAL = 40; Process.SetPriority[lookerPriority _ wantedPriority]; DO ENABLE ABORTED => EXIT; this: BufferIndex = GetBuffer[]; IF ActivateLooker[] THEN BEGIN IF lost[this] THEN { WriteString["Lost packet(s)"L]; WriteChar[Ascii.CR] }; Watch[buffers + this * bufferSize, times[this]]; ReturnBuffer[]; IF speed = slow AND (lookerCount _ lookerCount+1) >= (LookerDefs.ScreenLines[] * 3) / 4 THEN StartPause[]; DeactivateLooker[]; END; ENDLOOP; END; WriteDiskLog: PROC = BEGIN WriteChar _ LookerDefs.DiskChar; WriteMultiple _ LookerDefs.DiskMultiple; mode _ disk; WriteChar[Ascii.CR]; ReplayBuffers[]; IF logged[GetBuffer[]] THEN BEGIN WriteString["{ continued from previous logged packets }"L]; WriteChar[Ascii.CR]; THROUGH [1..fullBuffers] DO this: BufferIndex = GetBuffer[]; IF logged[this] THEN prevMS _ MSec[times[this]] ELSE EXIT; ReturnBuffer[]; ENDLOOP; END ELSE BEGIN WriteString["Watching host "L]; WriteOctal777[wanted.net]; WriteChar['#]; WriteOctal777[wanted.host]; WriteChar['#]; WriteChar[Ascii.CR]; END; THROUGH [1..fullBuffers] DO this: BufferIndex = GetBuffer[]; IF lost[this] THEN { WriteString["Lost packet(s)"L]; WriteChar[Ascii.CR] }; Watch[buffers + this * bufferSize, times[this]]; logged[this] _ TRUE; ReturnBuffer[]; ENDLOOP; WriteChar _ LookerDefs.DisplayChar; WriteMultiple _ LookerDefs.DisplayMultiple; mode _ display; LookerDefs.DiskCommit[]; END; -- user command input -- WriteTitle: PROC = BEGIN myTitle: STRING = [50]; String.AppendString[myTitle, "PUPWatch: watching host "L]; String.AppendNumber[myTitle, wanted.net, 8]; String.AppendChar[myTitle, '#]; String.AppendNumber[myTitle, wanted.host, 8]; String.AppendChar[myTitle, '#]; LookerDefs.WriteTitle[ConvertUnsafe.ToRope[myTitle]]; END; DoAction: PUBLIC PROC[act: LookerDefs.InputAction] = -- InputAction: TYPE = RECORD[SELECT act: * FROM -- fast => NULL, -- newHost => [name: Rope.ROPE], -- pauseContinue => NULL, -- quit => NULL, -- replay => NULL, -- slow => NULL, -- writeLog => NULL, -- pktSize => [big: BOOL], -- ENDCASE]; BEGIN alreadyPaused: BOOLEAN; ActivateInput[]; alreadyPaused _ pauseWanted; IF pauseWanted AND act.act # pauseContinue THEN WriteChar[Ascii.CR]; lookerCount _ 0; WITH act: act SELECT FROM fast => BEGIN WriteString["Fast"L]; speed _ fast; LookerDefs.NoteSlow[FALSE]; pauseWanted _ FALSE; END; newHost => BEGIN WriteString["Host ... "]; LookerDefs.SendNow[]; GiveEthernet[]; -- stops driver -- BEGIN outcome: LookupOutcome; net, host: [0..255]; [outcome, net, host] _ Lookup[act.name]; SELECT outcome FROM ok => BEGIN WriteString["ok"L]; LookerDefs.SendNow[]; wanted.net _ [net]; wanted.host _ [host]; LookerDefs.Clear[]; FlushBuffers[]; WriteTitle[]; pauseWanted _ FALSE; END; noResponse => WriteString["no name-lookup response"L]; badName => WriteString["name not found"L]; noRoute => WriteString["no route to that host"L]; ENDCASE => ERROR; END; TakeEthernet[]; -- starts driver -- END; pktSize => AllocBuffers[big: act.big]; replay => BEGIN LookerDefs.Clear[]; WriteString["Replay (Slow)"L]; ReplayBuffers[]; speed _ slow; LookerDefs.NoteSlow[TRUE]; pauseWanted _ FALSE; END; slow => BEGIN WriteString["Slow"L]; speed _ slow; LookerDefs.NoteSlow[TRUE]; pauseWanted _ FALSE; END; start => BEGIN InitTabs[]; AllocBuffers[big: FALSE]; PupDefs.PupPackageMake[]; wanted _ PupDefs.GetLocalPupAddress[,NIL]; myNet _ wanted.net; WriteTitle[]; pauseWanted _ FALSE; lookerProcess _ FORK LookerMain[]; TakeEthernet[]; END; stop => BEGIN Process.Abort[lookerProcess]; JOIN lookerProcess; GiveEthernet[]; FreeBuffers[]; END; writeLog => IF version = boot THEN WriteString["""Write log"" isn't implemented in this version"L] ELSE BEGIN WriteString["Writing log file ... "L]; LookerDefs.SendNow[]; WriteDiskLog[]; WriteString["ok"L]; END; pauseContinue => IF pauseWanted THEN { WriteString[" continuing"L]; pauseWanted _ FALSE; } ELSE StartPause[]; ENDCASE => ERROR; IF NOT pauseWanted OR alreadyPaused THEN WriteChar[Ascii.CR]; IF NOT pauseWanted AND act.act # stop THEN LookerDefs.NotePausing[FALSE]; DeactivateInput[]; END; -- Address Lookup -- LookupOutcome: TYPE = { ok, badName, noResponse, noRoute }; Lookup: PROC[name: Rope.ROPE] RETURNS[outcome: LookupOutcome, net, host: [0..255]] = BEGIN addr: PupDefs.PupAddress; s: STRING = [99]; length: INT = Rope.Length[name]; FOR i: INT IN [0..IF s.maxlength > length THEN length ELSE s.maxlength) DO s[i] _ Rope.Fetch[name, i]; s.length _ i+1; ENDLOOP; outcome _ ok; PupDefs.GetPupAddress[@addr, IF s.length = 0 THEN "ME"L ELSE s ! PupDefs.PupNameTrouble => { outcome _ SELECT code FROM noRoute => noRoute, noResponse => noResponse, ENDCASE => badName; CONTINUE } ]; net _ addr.net; host _ addr.host; END; -- Initialisation -- version: { bcd, image, boot } _ bcd; lookerProcess: PROCESS; -- Our display module hasn't been started yet -- SELECT version FROM image => { STOP }; bcd => { NULL }; boot => { NULL }; ENDCASE => ERROR; -- We're now fully running, possibly after ether-booting -- Process.EnableAborts[@bufferChange]; Process.EnableAborts[@inputChange]; Process.EnableAborts[@lookerChange]; END.