// Pup1OpenClose.bcpl -- Pup level 1 // This module contains infrequently executed code which can be swapped // without affecting performance. // Copyright Xerox Corporation 1979, 1981 // Last modified November 21, 1981 10:58 AM by Taft get "pup0.decl" get "pup1.decl" external [ // outgoing procedures OpenLevel1Socket; CloseLevel1Socket; FlushQueue SetAllocation; AppendStringToPup // incoming procedures CompletePup; ReleasePBI Zero; MoveBlock; SysErr; DefaultArgs Enqueue; Dequeue; Unqueue; Block HLookup // outgoing statics lPupSoc; socketSequence // incoming statics ndbQ; socketQ; dPSIB; pupRT; numNets ] static [ lPupSoc = lenPupSoc // so client doesn't need to get Pup1.decl socketSequence // for making unique local socket numbers ] //---------------------------------------------------------------------------- let OpenLevel1Socket(soc, lclPort, frnPort, transient; numargs na) = valof //---------------------------------------------------------------------------- // soc is a pointer to storage of size lenPupSoc. // lclPort and frnPort point at port structures and may be omitted. // If the local net and host or local socket are zero, they // are defaulted to reasonable values (socket guaranteed unique). // If the foreign net is zero, it is defaulted to be the same as // the local net (which is assumed to be directly connected!). // If transient then the PupSoc is expected to have only a short lifetime, // and Pups arriving for this socket after it is closed should not be // answered with Error Pups. This works only if lclPort.socket is defaulted. [ DefaultArgs(lv na, -1, 0, 0, false) Zero(soc, lenPupSoc) MoveBlock(lv soc>>PupSoc.psib, dPSIB, lenPSIB) if lclPort ne 0 then MoveBlock(lv soc>>PupSoc.lclPort, lclPort, lenPort) if frnPort ne 0 then MoveBlock(lv soc>>PupSoc.frnPort, frnPort, lenPort) if soc>>PupSoc.lclPort.net eq 0 & soc>>PupSoc.lclPort.host eq 0 then [ // net and host unspecified, select reasonable default let ndb = nil compiletest multipleNets ifso [ // pick same net as foreign port, if possible let rte = HLookup(pupRT, soc>>PupSoc.frnPort.net) ndb = rte ne 0? rte>>RTE.ndb, ndbQ!0 ] ifnot [ // only connected to one net so use that ndb = ndbQ!0 ] soc>>PupSoc.lclPort.net = ndb>>NDB.localNet soc>>PupSoc.lclPort.host = ndb>>NDB.localHost ] if soc>>PupSoc.lclPort.socket↑1 eq 0 & soc>>PupSoc.lclPort.socket↑2 eq 0 then [ // local socket unspecified, make a unique one soc>>PupSoc.lclPort.socket↑1 = transient? socTransient, soc soc>>PupSoc.lclPort.socket↑2 = socketSequence socketSequence = socketSequence+1 ] if soc>>PupSoc.frnPort.net eq 0 then // foreign net unspecified soc>>PupSoc.frnPort.net = soc>>PupSoc.lclPort.net Enqueue(socketQ, soc) ] //---------------------------------------------------------------------------- and CloseLevel1Socket(soc) be //---------------------------------------------------------------------------- [ unless Unqueue(socketQ, soc) do SysErr(soc, ecNoSuchSocket) [ // repeat FlushQueue(lv soc>>PupSoc.iQ) Block() ] repeatuntil soc>>PupSoc.numTPBI eq soc>>PupSoc.maxTPBI ] //---------------------------------------------------------------------------- and FlushQueue(q) be while q!0 ne 0 do ReleasePBI(Dequeue(q)) //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- and SetAllocation(soc, total, input, output) be //---------------------------------------------------------------------------- [ if input gr total % output gr total do SysErr(soc, ecBadAllocation) // Devious means to add change in allocation to both "max" and "num" // simultaneously. Depends on max being in lh and num in rh. soc>>PupSoc.tAll = soc>>PupSoc.tAll + (total - soc>>PupSoc.maxTPBI)*401B soc>>PupSoc.iAll = soc>>PupSoc.iAll + (input - soc>>PupSoc.maxIPBI)*401B soc>>PupSoc.oAll = soc>>PupSoc.oAll + (output - soc>>PupSoc.maxOPBI)*401B ] //---------------------------------------------------------------------------- and AppendStringToPup(pbi, firstByte, string) be //---------------------------------------------------------------------------- // Appends the given string to the pup, starting at content byte // firstByte (i.e., pbi>>PBI.pup.bytes↑firstByte), and sets the // pup length appropriately [ for i = 1 to string>>String.length do pbi>>PBI.pup.bytes↑(firstByte+i-1) = string>>String.char↑i pbi>>PBI.pup.length = pupOvBytes+firstByte+string>>String.length-1 ] compileif multipleNets then [ external [ BroadcastNextNet; PupChecksum ] //---------------------------------------------------------------------------- let BroadcastNextNet(pbi, ndb) be //---------------------------------------------------------------------------- // Called from PupLevel1 and CompletePup for a pbi being broadcast // on all directly connected networks [ while ndb ne 0 do [ unless ndb>>NDB.localNet eq 0 & pbi>>PBI.bypassZeroNet do [ pbi>>PBI.ndb = ndb pbi>>PBI.pup.sPort.net = ndb>>NDB.localNet pbi>>PBI.pup.sPort.host = ndb>>NDB.localHost pbi>>PBI.pup.dPort.net = ndb>>NDB.localNet pbi!(lenPBIOverhead + (pbi>>PBI.pup.length-1) rshift 1) = pbi>>PBI.socket>>PupSoc.doChecksum? PupChecksum(lv pbi>>PBI.pup), -1 ndb>>NDB.encapsulatePup(pbi, pbi>>PBI.pup.dPort.host) ndb>>NDB.level0Transmit(pbi) return ] ndb = ndb!0 ] ReleasePBI(pbi) ] ] // compileif multipleNets