// GateConServ.bcpl -- Gateway control server // Last modified December 26, 1981 10:30 PM by Boggs get "PupEFTP.decl" get "PupServEftp.decl" get "GateConServ.decl" external [ // outgoing procedures GateConServCtx; HaltGateway // incoming procedures LockNameServ; UnlockNameServ; GetTime LockBootServ; UnlockBootServ GatewayFinish; PupServReceive; PupServSend InitializeContext; Block Allocate; Free; MoveBlock; Zero Enqueue; Dequeue; Unqueue; QueueLength SetTimer; TimerHasExpired GetPBI; ReleasePBI; CompletePup; SetPupID ExchangePorts // outgoing statics @gcs // incoming statics sysZone; ctxQ; versionText; CtxRunning pbiFreeQ; gatewayGoingDown ] static @gcs manifest [ restart = 1000 quit = 12345b ] structure GCTX: // GateControl CTX [ blank word 3 pbi word ] manifest GCTXextra = size GCTX/16 -3 //--------------------------------------------------------------------------- let HaltGateway() be //--------------------------------------------------------------------------- [ gcs>>GCS.quitCode = quit gatewayGoingDown = true // Dally for 15 seconds while we broadcast routing tables that say we are // a terrible route to everywhere so that people can find ways around us. SetTimer(lv gcs>>GCS.restartTimer, 1500) ] //--------------------------------------------------------------------------- and GateConServCtx() be //--------------------------------------------------------------------------- [ [ // idle loop Block() if gcs>>GCS.stats.startTime↑0 eq 0 then GetTime(lv gcs>>GCS.stats.startTime) if gcs>>GCS.eftpCtx ne 0 & gcs>>GCS.stats.eftpStatus ne statusBusy then [ Free(sysZone, gcs>>GCS.eftpCtx) gcs>>GCS.eftpCtx = 0 ] if gcs>>GCS.quitCode ne 0 & gcs>>GCS.eftpCtx eq 0 & TimerHasExpired(lv gcs>>GCS.restartTimer) then [ LockBootServ() LockNameServ() GatewayFinish(gcs>>GCS.quitCode) ] ] repeatuntil gcs>>GCS.soc>>PupSoc.iQ.head ne 0 let pbi = Dequeue(lv gcs>>GCS.soc>>PupSoc.iQ) if pbi>>PBI.pup.dPort.host eq 0 % pbi>>PBI.pup.id↑1 ne gcPassword then [ ReleasePBI(pbi); loop ] ExchangePorts(pbi) //do this here rather than in each case switchon pbi>>PBI.pup.type into [ case ptExamine: [ //examine a block of words whose starting address //and length are given in the first 2 words of the //request Pup. return the block starting in word 3. MoveBlock(lv pbi>>PBI.pup.words↑3, pbi>>PBI.pup.words↑1, pbi>>PBI.pup.words↑2) CompletePup(pbi, ptAck, pbi>>PBI.pup.words↑2 lshift 1 + pupOvBytes+4) endcase ] case ptDeposit: [ //deposit a block of words whose starting address //and length are given in the first 2 words of the //request Pup. the data starts at word 3. MoveBlock(pbi>>PBI.pup.words↑1, lv pbi>>PBI.pup.words↑3, pbi>>PBI.pup.words↑2) CompletePup(pbi, ptAck, pupOvBytes) endcase ] case ptHalt: [ //halt the gateway program HaltGateway() CompletePup(pbi, ptAck, pupOvBytes) endcase ] case ptRestart: [ //restart the Gateway program gcs>>GCS.quitCode = restart SetTimer(lv gcs>>GCS.restartTimer, 500) // dally for 5 seconds CompletePup(pbi, ptAck, pupOvBytes) endcase ] // GateConServ (cont'd) case ptStore: //Store a file on the gateway disk whose name is given // in the Pup contents. The server responds with an ack // containing the port to which the file should be EFTP'ed. case ptRetrieve: //Retrieve a file from the gateway disk whose name is given // in the Pup contents. The server generates no ack: it just starts // EFTPing the file to the source port of the incoming packet. [ if gcs>>GCS.eftpCtx eq 0 & gcs>>GCS.quitCode eq 0 then [ let ctx = Allocate(sysZone, 1200, true) if ctx ne 0 then [ gcs>>GCS.eftpCtx = ctx gcs>>GCS.stats.eftpStatus = statusBusy ctx>>GCTX.pbi = pbi for i = pbi>>PBI.pup.length-pupOvBytes to 1 by -1 do pbi>>PBI.pup.bytes↑(i+1) = pbi>>PBI.pup.bytes↑i pbi>>PBI.pup.bytes↑1 = pbi>>PBI.pup.length-pupOvBytes Enqueue(ctxQ, InitializeContext(ctx, 1200, (pbi>>PBI.pup.type eq ptStore? GCSStore, GCSRetrieve), GCTXextra)) endcase ] ] ReleasePBI(pbi) endcase ] case ptStats: [ let stats = lv pbi>>PBI.pup.words MoveBlock(stats, lv gcs>>GCS.stats, lenStats) stats>>Stats.freePBIs = QueueLength(pbiFreeQ) let lenVersionText = versionText>>String.length rshift 1 +1 MoveBlock(lv stats>>Stats.versionText, versionText, lenVersionText) CompletePup(pbi, ptAck, pupOvBytes+(lenStats+lenVersionText)*2) endcase ] default: ReleasePBI(pbi) ] ] repeat //--------------------------------------------------------------------------- and GCSStore(ctx) be //--------------------------------------------------------------------------- // A separate context that does the file transfer. // It signals that it is done by changing gcs>>GCS.stats.eftpStatus // to anything other than statusBusy. [ let pbi = ctx>>GCTX.pbi let eftp = vec lenEFTP; Zero(eftp, lenEFTP) eftp>>EFTP.frnPort = lv pbi>>PBI.pup.dPort Zero(lv pbi>>PBI.pup.sPort.socket, 2) //let OpenLevel1Socket pick the socket eftp>>EFTP.lclPort = lv pbi>>PBI.pup.sPort //but use net,host in request pup eftp>>EFTP.realName = lv pbi>>PBI.pup.bytes eftp>>EFTP.tempName = "TEMP.GC" eftp>>EFTP.timeOut1 = 100 eftp>>EFTP.timeOut2 = 2000 //20 seconds eftp>>EFTP.proc1 = GateConStart eftp>>EFTP.proc2 = GateConEnd let status = PupServReceive(eftp)? statusYes, statusNo if status eq statusYes then [ UnlockBootServ(lv pbi>>PBI.pup.bytes) UnlockNameServ() ] ReleasePBI(pbi) Unqueue(ctxQ, ctx) gcs>>GCS.stats.eftpStatus = status //signal that we are done // returning from a context causes an implicit Block() ] //--------------------------------------------------------------------------- and GateConStart(soc) be //--------------------------------------------------------------------------- // This is where the ack containing the EFTP port gets generated. [ let pbi = GetPBI(soc, true); if pbi ne 0 then [ SetPupID(pbi, lv CtxRunning>>GCTX.pbi>>PBI.pup.id) MoveBlock(lv pbi>>PBI.pup.words, lv soc>>PupSoc.lclPort, lenPort) CompletePup(pbi, ptAck, pupOvBytes+lenPort*2) ] ] //--------------------------------------------------------------------------- and GateConEnd(stream) be //--------------------------------------------------------------------------- [ LockBootServ() LockNameServ() ] //--------------------------------------------------------------------------- and GCSRetrieve(ctx) be //--------------------------------------------------------------------------- // A separate context that does the file transfer. // It signals that it is done by changing gcs>>GCS.stats.eftpStatus // to anything other than statusBusy. [ let pbi = ctx>>GCTX.pbi let eftp = vec lenEFTP; Zero(eftp, lenEFTP) eftp>>EFTP.frnPort = lv pbi>>PBI.pup.dPort Zero(lv pbi>>PBI.pup.sPort.socket, 2) //let OpenLevel1Socket pick the socket eftp>>EFTP.lclPort = lv pbi>>PBI.pup.sPort //but use net,host in request pup eftp>>EFTP.realName = lv pbi>>PBI.pup.bytes eftp>>EFTP.timeOut1 = 500 //5 seconds eftp>>EFTP.timeOut2 = 2000 //20 seconds let status = PupServSend(eftp)? statusYes, statusNo ReleasePBI(pbi) Unqueue(ctxQ, ctx) gcs>>GCS.stats.eftpStatus = status //signal that we are done // returning from a context causes an implicit Block() ]