// GateConNet.bcpl -- miscellaneous network-related stuff
// Last modified July 2, 1983  10:19 PM by Boggs

get "Pup0.decl"
get "Pup1.decl"
get "GateConServ.decl"

external
[
// outgoing procedures
SendCommand; MiscCmd; Gateway; PrintPort
OtherPup; OtherPupCtx; GetBuf

// incoming procedures
MoveBlock; MultEq; Enqueue; Dequeue; FlushQueue
SetTimer; TimerHasExpired; Block
GetPBI; ReleasePBI; CompletePup
GetPartner; OpenLevel1Socket; CloseLevel1Socket
Ws; Puts; PutTemplate; GetString; Error
ExtractSubstring; Free
RestartGateConUser; RestartRoute; RestartEcho
RestartName; RestartTime; RestartBoot; TopLevel

// outgoing statics
gcNet; gcHost; gcName; otherPupQ

// incoming statics
dsp; errorDsp; sysZone
]

static [ gcNet; gcHost; gcName; gcID; otherPupQ ]

//----------------------------------------------------------------------------
let SendCommand(pbi, type, length, retries; numargs na) = valof
//----------------------------------------------------------------------------
// returns response pbi or 0
[
if na ls 4 then retries = 3
if na ge 3 then pbi>>PBI.pup.length = length
if na ge 2 then pbi>>PBI.pup.type = type

if pbi>>PBI.pup.dPort.net eq 0 & pbi>>PBI.pup.dPort.host eq 0 then
   [
   pbi>>PBI.pup.dPort.net = gcNet
   pbi>>PBI.pup.dPort.host = gcHost
   ]
if pbi>>PBI.pup.dPort.socket↑1 eq 0 & pbi>>PBI.pup.dPort.socket↑2 eq 0 then
   [
   pbi>>PBI.pup.dPort.socket↑1 = gcSocket1
   pbi>>PBI.pup.dPort.socket↑2 = gcSocket2
   ]

pbi>>PBI.pup.id↑1 = gcPassword
pbi>>PBI.pup.id↑2 = gcID
gcID = gcID+1
let soc = pbi>>PBI.socket
let tQ = vec 1; tQ!0 = 0
pbi>>PBI.queue = tQ
Enqueue(tQ, pbi)
let ipbi = 0

for i = 1 to retries do
   [
   Block() repeatwhile tQ!0 eq 0
   CompletePup(Dequeue(tQ))

   let timer = nil; SetTimer(lv timer, 200)  //2 sec
      [
      Block() repeatuntil TimerHasExpired(lv timer) % soc>>PupSoc.iQ.head ne 0
      ipbi = Dequeue(lv soc>>PupSoc.iQ)
      if ipbi eq 0 break  //timeout - retransmit
      if MultEq(lv ipbi>>PBI.pup.id, lv pbi>>PBI.pup.id) then
         if ipbi>>PBI.pup.type ne typeError break
      test ipbi ne 0
         ifso OtherPup(ipbi)
         ifnot ReleasePBI(ipbi)
      ipbi = 0
      ] repeat
   if ipbi ne 0 break
   ]

Block() repeatwhile tQ!0 eq 0
ReleasePBI(Dequeue(tQ))
resultis ipbi
]

//----------------------------------------------------------------------------
and MiscCmd(requestType, replyType, Proc, data, length; numargs na) be
//----------------------------------------------------------------------------
[
if na ls 5 then length = 0
let soc = vec lenPupSoc; OpenLevel1Socket(soc)
let pbi = GetBuf(soc)
pbi>>PBI.pup.dPort.socket↑2 = 4  // psMiscServ
if length ne 0 then MoveBlock(lv pbi>>PBI.pup.words, data, (length+1)/2)
pbi = SendCommand(pbi, requestType, pupOvBytes+length)
test pbi ne 0 & pbi>>PBI.pup.type eq replyType
   ifso Proc(pbi)
   ifnot Ws(" - the server doesn't answer")
if pbi then ReleasePBI(pbi)
CloseLevel1Socket(soc)
]

//---------------------------------------------------------------------------
and GetBuf(soc, returnIfNone; numargs na) = valof
//---------------------------------------------------------------------------
[
let pbi = GetPBI(soc, true)
if pbi ne 0 resultis pbi
if na eq 2 & returnIfNone resultis 0
FlushQueue(lv soc>>PupSoc.iQ)
Block()
] repeat

//---------------------------------------------------------------------------
and OtherPup(pbi) be Enqueue(otherPupQ, pbi)
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
and OtherPupCtx(ctx) be
//---------------------------------------------------------------------------
[
Block() repeatuntil otherPupQ!0 ne 0
let pbi = Dequeue(otherPupQ) 
if pbi>>PBI.pup.type eq typeError then
   [
   Error("Error Pup from ")
   PutTemplate(errorDsp, "$P: ", PrintPort, lv pbi>>PBI.pup.sPort)
   for i = 25 to pbi>>PBI.pup.length-pupOvBytes do
      Puts(errorDsp, pbi>>PBI.pup.bytes↑i)
   ]
ReleasePBI(pbi)
] repeat

//----------------------------------------------------------------------------
and PrintPort(stream, port) be
//----------------------------------------------------------------------------
PutTemplate(stream, "[$UO#$UO#$UEO]", port>>Port.net, port>>Port.host,
 lv port>>Port.socket)

//----------------------------------------------------------------------------
and Gateway() be
//----------------------------------------------------------------------------
[
let doTopLevel = gcHost eq 0
let name = vec 128
if GetString("*NGateway: ", name) then
   [
   let port = vec lenPort
   if GetPartner(name, dsp, port, gcSocket1, gcSocket2) then
      [
      gcNet = port>>Port.net
      gcHost = port>>Port.host
      if gcName ne 0 then Free(sysZone, gcName)
      gcName = ExtractSubstring(name)
      RestartGateConUser()
      RestartRoute()
      RestartEcho()
      RestartName()
      RestartTime()
      RestartBoot()
      if doTopLevel then TopLevel()
      FlushQueue(otherPupQ)
      ]
   ]
]