// GateConServ.bcpl -- Gateway control server // Last modified March 7, 1979 4:11 PM by Boggs get "PupEFTP.decl" get "PupServFtp.decl" get "GateConServ.decl" external [ // outgoing procedures GateConServCtx; HaltGateway // incoming procedures LockNameServ; UnlockNameServ; GetTime LockBootServ; UnlockBootServ; StringCompare GatewayFinish; Chatr; PupServReceive; PupServSend InitializeContext; Block Allocate; Free; MoveBlock; Zero Enqueue; Dequeue; Unqueue; QueueLength SetTimer; TimerHasExpired GetPBI; ReleasePBI; CompletePup; SetPupID ExchangePorts; AppendStringToPup // outgoing statics @gcs // incoming statics sysZone; ctxQ; versionText; CtxRunning pbiTQ; pbiFreeQ; gatewayGoingDown; lenPup ] static @gcs manifest [ // DOS .ertn codes quit = 12345 restart = 1000 ] 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.ftpCtx ne 0 & gcs>>GCS.stats.ftpStatus ne statusBusy then [ compiletest nova ifso [ ReleasePBI(gcs>>GCS.ftpCtx-offset PBI.pup/16) ] ifnot [ Free(sysZone, gcs>>GCS.ftpCtx) ] gcs>>GCS.ftpCtx = 0 ] if gcs>>GCS.quitCode ne 0 & gcs>>GCS.ftpCtx 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.ftpCtx eq 0 & gcs>>GCS.quitCode eq 0 then [ let ctx = alto? Allocate(sysZone, 1200, true), valof [ let pbi = GetPBI(gcs>>GCS.soc, true) resultis pbi eq 0? 0, lv pbi>>PBI.pup ] if ctx ne 0 then [ gcs>>GCS.ftpCtx = ctx gcs>>GCS.stats.ftpStatus = 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, (alto? 1200, lenPup), (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.ftpStatus // to anything other than statusBusy. [ let pbi = ctx>>GCTX.pbi let ftp = vec lenFTP; Zero(ftp, lenFTP) ftp>>FTP.frnPort = lv pbi>>PBI.pup.dPort Zero(lv pbi>>PBI.pup.sPort.socket, 2) //let OpenLevel1Socket pick the socket ftp>>FTP.lclPort = lv pbi>>PBI.pup.sPort //but use net,host in request pup ftp>>FTP.realName = lv pbi>>PBI.pup.bytes ftp>>FTP.tempName = "TEMP.GC" ftp>>FTP.timeOut1 = 100 ftp>>FTP.timeOut2 = 2000 //20 seconds ftp>>FTP.proc1 = GateConStart ftp>>FTP.proc2 = GateConEnd let status = PupServReceive(ftp)? statusYes, statusNo if status eq statusYes then [ UnlockBootServ(lv pbi>>PBI.pup.bytes) UnlockNameServ() ] ReleasePBI(pbi) Unqueue(ctxQ, ctx) gcs>>GCS.stats.ftpStatus = 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 //--------------------------------------------------------------------------- [ compileif nova then [ let fn = lv CtxRunning>>GCTX.pbi>>PBI.pup.bytes if StringCompare(fn, ".SV", fn>>String.length-2) eq 0 then Chatr(stream, 20000b) // set "S" attribute for .SV file ] 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.ftpStatus // to anything other than statusBusy. [ let pbi = ctx>>GCTX.pbi let ftp = vec lenFTP; Zero(ftp, lenFTP) ftp>>FTP.frnPort = lv pbi>>PBI.pup.dPort Zero(lv pbi>>PBI.pup.sPort.socket, 2) //let OpenLevel1Socket pick the socket ftp>>FTP.lclPort = lv pbi>>PBI.pup.sPort //but use net,host in request pup ftp>>FTP.realName = lv pbi>>PBI.pup.bytes ftp>>FTP.timeOut1 = 500 //5 seconds ftp>>FTP.timeOut2 = 2000 //20 seconds let status = PupServSend(ftp)? statusYes, statusNo ReleasePBI(pbi) Unqueue(ctxQ, ctx) gcs>>GCS.stats.ftpStatus = status //signal that we are done // returning from a context causes an implicit Block() ]