// GateConEcho.bcpl // Last modified February 28, 1979 2:43 AM by Boggs get "Pup0.decl" get "Pup1.decl" get "AltoDefs.d" get "PupEchoServ.decl" external [ // outgoing procedures CreateEchoCtx; Echo; EchoSummary; RestartEcho // incoming procedures Puts; Endofs; PutTemplate; Ws; Resets MoveBlock; Zero; Allocate; Free InitializeContext; Block SetTimer; TimerHasExpired; Enqueue; Dequeue GetBuf; ReleasePBI; CompletePup OpenLevel1Socket; CloseLevel1Socket HLookup; Divide32x16; DoubleIncrement; MultEq OtherPup; PrintPort; SendCommand GetPartner; GetString ResetCmdMenu; CreateCmdBox; TopLevel; ReturnFrom; BoxProc // incoming statics pupRT; errorDsp; dsp; keys; sysZone; ctxQ; gcHost; oldStatsQ ] static @eu structure EU: // eu -> this 'global frame' for the Echo process [ soc word // -> PupSoc stats word // -> Echo stats block timer word // update stats when this expires flags word = [ blank bit 14 checksum bit // Generate and check Pup Checksum checkData bit // Generate and check Pup data ] ] manifest lenEU = size EU/16 //---------------------------------------------------------------------------- let CreateEchoCtx() be //---------------------------------------------------------------------------- [ Enqueue(ctxQ, InitializeContext(Allocate(sysZone, 150), 150, EchoCtx)) eu = Allocate(sysZone, lenEU); Zero(eu, lenEU) eu>>EU.soc = Allocate(sysZone, lenPupSoc); OpenLevel1Socket(eu>>EU.soc) ] //---------------------------------------------------------------------------- and RestartEcho() be //---------------------------------------------------------------------------- [ SetTimer(lv eu>>EU.timer, 0) if eu>>EU.stats ne 0 then [ Enqueue(oldStatsQ, eu>>EU.stats); eu>>EU.stats = 0 ] ] //---------------------------------------------------------------------------- and Echo() be //---------------------------------------------------------------------------- [ ResetCmdMenu() CreateCmdBox(TopLevel, "TopLevel") CreateCmdBox(EchoUser, "EchoUser") CreateCmdBox(Checksum, (eu>>EU.checksum? "DontChecksum", "Checksum")) CreateCmdBox(CheckData, (eu>>EU.checkData? "DontCheckData", "CheckData")) // ResetCmdMenu destroyed the BoxQ which BoxProc is following. // If we just return now, BoxProc will get horribly confused. // So don't let it continue: force a return from BoxProc. ReturnFrom(BoxProc) ] //---------------------------------------------------------------------------- and EchoCtx(ctx) be // a context //---------------------------------------------------------------------------- [ Block() repeatuntil TimerHasExpired(lv eu>>EU.timer) & gcHost ne 0 SetTimer(lv eu>>EU.timer, 1000) //10 sec let pbi = GetBuf(eu>>EU.soc) pbi>>PBI.pup.dPort.socket↑2 = psEchoServ pbi = SendCommand(pbi, ptStatsRequest, pupOvBytes, 1) if pbi ne 0 then [ let stats = lv pbi>>PBI.pup.words if pbi>>PBI.pup.type eq ptStatsReply & stats>>Stats.version eq echoStatsVersion then [ if eu>>EU.stats then Enqueue(oldStatsQ, eu>>EU.stats) let lenStatBlock = pbi>>PBI.pup.length - pupOvBytes eu>>EU.stats = Allocate(sysZone, lenStatBlock) MoveBlock(eu>>EU.stats, lv pbi>>PBI.pup.words, lenStatBlock) ] ReleasePBI(pbi) ] ] repeat //---------------------------------------------------------------------------- and EchoSummary(stream) be //---------------------------------------------------------------------------- [ if eu>>EU.stats ne 0 then PutTemplate(stream, "Echo: $EUD ", lv eu>>EU.stats>>Stats.packetsEchoed) ] //---------------------------------------------------------------------------- and CheckData(box) be //---------------------------------------------------------------------------- [ eu>>EU.checkData = not eu>>EU.checkData Echo() ] //---------------------------------------------------------------------------- and Checksum(box) be //---------------------------------------------------------------------------- [ eu>>EU.checksum = not eu>>EU.checksum Echo() ] //---------------------------------------------------------------------------- and EchoUser() be //---------------------------------------------------------------------------- [ let name = vec 128 unless GetString("*NEcho to: ", name) return let port = vec lenPort unless GetPartner(name, dsp, port, 0, psEchoServ) return let soc = vec lenPupSoc; OpenLevel1Socket(soc, 0, port) soc>>PupSoc.doChecksum = eu>>EU.checksum PutTemplate(dsp, "$P -> ", PrintPort, lv soc>>PupSoc.lclPort) let rte = HLookup(pupRT, soc>>PupSoc.frnPort.net) if rte ne 0 & rte>>RTE.hops ne 0 then PutTemplate(dsp, "[$UO#$UO#] -> ", rte>>RTE.ndb>>NDB.localNet, rte>>RTE.host) PrintPort(dsp, lv soc>>PupSoc.frnPort) let out = vec 6; Zero(out, 6) let in, inTimes100 = out+2, out+4 let pupLength, pupID = -1, -1 let dataBuffer = vec 532/2 structure Byte↑0,532 byte for i = 0 to 531 do dataBuffer>>Byte↑i = i let cursor = vec 15; MoveBlock(cursor, cursorBitMap, 16) for i = 0 to 7 do cursorBitMap!i = 377b for i = 10b to 17b do cursorBitMap!i = 177400b [ let pbi = GetBuf(soc) pupLength = pupLength +1 if pupLength gr 532 then pupLength = 0 pupID = pupID +1 pbi>>PBI.pup.id↑1 = 0 pbi>>PBI.pup.id↑2 = pupID MoveBlock(lv pbi>>PBI.pup.bytes, dataBuffer, (pupLength+1)/2) CompletePup(pbi, ptEchoMe, pupOvBytes+pupLength) DoubleIncrement(out) let time = nil; SetTimer(lv time, 150) [ Block() repeatuntil soc>>PupSoc.iQ.head % TimerHasExpired(lv time) pbi = Dequeue(lv soc>>PupSoc.iQ) if pbi eq 0 then [ Puts(dsp, $?); break ] if pbi>>PBI.pup.type ne ptImAnEcho then [ OtherPup(pbi); loop ] DoubleIncrement(in); DoubleIncrement(inTimes100, 100) test pbi>>PBI.pup.id↑2 eq pupID ifnot [ Puts(dsp, $#); ReleasePBI(pbi) ] ifso [ if pupLength gr 0 then unless MultEq(lv pbi>>PBI.pup.words, dataBuffer, (pupLength+1)/2) do Ws("*NDate compare error") for i = 0 to 17b do cursorBitMap!i = not cursorBitMap!i Puts(dsp, $!) ReleasePBI(pbi) break ] ] repeat ] repeatwhile Endofs(keys) Resets(keys) CloseLevel1Socket(soc) PutTemplate(dsp, "*NOut: $ED, In: $ED", out, in) while out!0 ne 0 do //scale so denominator is ls 2↑16 [ Divide32x16(inTimes100, 10); Divide32x16(out, 10) ] Divide32x16(inTimes100, out!1) PutTemplate(dsp, ", $UD%", inTimes100!1) MoveBlock(cursorBitMap, cursor, 16) ]