;-*-midas-*-
title arpa
;chaosnet to arpanet server, rfc has hostname and optional (octal) socket number
;data is just forwarded from chaosnet connection to arpanet connection and vice versa,
;except:
; data opcode 201 from the chaosnet means do an INS on the arpanet connection
; the rest of this packet is treated normally
; data opcode 210 means establish auxiliary connection (for gateway FTP), the
; the data portion of this packet contains 8 bytes of the (gensym'ed presumably)
; contact name for the chaos end of the auxiliary connection, the server will do
; a listen on that name; and 2 words of the arpanet socket number to connect to.
; when a rfc is received for that contact name, a half-duplex arpanet connection
; is established and data then forwarded from/to it to/from the chaosnet connection
; in the same manner as the main connection.
; For TCP it is much worse, it starts listening on TCP and chaos and waits for a
; 211 packet before checking that TCP is open and opening chaos. This is needed
; with the screwy way TCP FTP works.
; Using 212 instead of 210 gensyms the local port and sends it back as
; a 300 packet on the main data connection.
; Made it send local internet host number in 300 packet, as four bytes
; following the local port. (Users must check packet length since other
; servers might not have it) -GZ 10/2/84
;
; hacked a little in preparation for TCP. -dcp 12/29/82
f=0
a=1
b=2
c=3
d=4
e=5
n=6
bp=7
t=10
tt=11
s=12
cch=13
nch=14
p=17
frauxo==400000
frcaxo==200000
.insrt system;chsdef
%cobrk==%codat+1 ;R11 net INS magic
icpch==0
netich==2
netoch==3
auxich==4
auxoch==5
filech==7
chaich==10
chaoch==11
caxich==12
caxoch==13
call=pushj p,
ret=popj p,
return=popj p,
define syscal name,args
.call [setz ? sixbit /name/ ? args ((setz))]
termin
$$hst3==1
$$allnet==1 ;let them go anyplace
$$arpa==1 ;support Arpanet, we do Chaos net ourselves
$$icp==1 ;icp routine
$$tcp==1
$$connect==1
$$hostnm==1 ;hostname lookup routines
$$ownhst==1 ;Own hostname in standard format
$$symlook==1
$$hstsix==1
$$analyze==1 ;analyze routine
ifndef $$logging,$$logging==0
.insrt syseng;netwrk >
;storage
debug: 0 ;non-zero => .value on barfage
whoami: 0 ;sixbit of program name (ARPA, NCP or TCP)
usrhst: 0 ;user host number
lclhst: 0 ;local host number
frnhst: 0 ;arpanet host number
icpskt: 0 ;icp socket
chapkt: block %cpmxw ;chaosnet packet goes here
hstnam: block 10 ;stick the host name here
npdl==100
pdl: block npdl
;interrupt handler
tsint: loc 42
-tsintl,,tsint
loc tsint
p
%piioc ? 0 ? -1 ? -1 ? iocerr ;iocerr ints highest priority
0 ? 1_netich ? 0 ? 1_chaich\1_netich\1_caxich\1_auxich ? netint
0 ? 1_chaich ? 0 ? 1_netich\1_chaich\1_caxich\1_auxich ? chaint
0 ? 1_auxich ? 0 ? 1_chaich\1_netich\1_caxich\1_auxich ? auxint
0 ? 1_caxich ? 0 ? 1_netich\1_chaich\1_caxich\1_auxich ? caxint
tsintl==.-tsint
;error handler
die: 0
skipe debug
.value
passon: .logout ;natural causes
.value
sndpkt: setz ? 'pktiot ? movei 1(cch) ? setzi chapkt
rcvpkt: setz ? 'pktiot ? movei 0(cch) ? setzi chapkt
;main program
go: .close 1, ;this can still be open from loading us
move p,[-npdl,,pdl-1]
call getme ;get my job info
trz f,frauxo\frcaxo ;neither auxiliary conn open yet
call getcha ;get the chaos connection
call logmein ;I know it's seven characters
call gethst ;get the host we are trying to send to
call getskt ;get the socket number to connect to
call getcon ;get the NCP or TCP connection
call getrdy ;get ready for main loop
jfcl
.hang
getme: .suset [.rsname,,whoami]
return ;maybe error check someday
getcha: movei cch,chaich
movei nch,netich
syscal chaoso,[movei chaich ? movei chaoch ? movei 5]
jsr die
move t,[.byte 8 ? %colsn ? 0 ? 0 ? 0]
movem t,chapkt
move t,[440600,,whoami] ;better not take up all six characters
move tt,[440800,,chapkt+%cpkdt]
ildb s,t
jumpn s,[addi s,"A-'a ;'"
idpb s,tt
movei s,1_4
addm s,chapkt ;increment length
jrst .-1]
.call sndpkt
jsr die
movei t,30.*60.
skipe debug
hrloi t,177777 ;wait forever if debugging
syscal netblk,[movei chaich ? movei %cslsn ? t ? movem t]
jsr die
caie t,%csrfc ;did we get an rfc for this?
jsr die
.call rcvpkt ;yes, read it in
jsr die
syscal rfname,[ %climm,,chaich ;Examine Chaosnet conn
%clout,,a ? ;(Should be CHAOS device)
%clout,,tt ? %clout,,tt ;Ignore index nums
%clout,,usrhst ] ;Find user host address
return
ifn $$logging, netwrk"log CH2TCP,[usrhst]
return
logmein: ;and tell the system other things
movei a,hstpag
movei b,filech
call netwrk"hstmap ;get the hosttable
jsr die
skipe debug ;debugging?
return
ldb a,[chapkt+$cpksa] ;get source host address
tlo a,netwrk"nw%chs_9
pushj p,netwrk"hstsix ;Get sixbit of it
.lose
move tt,[sixbit /000_00/] ;convert host number to sixbit
ldb t,[.bp ,whoami] ;get first character
dpb t,[.bp ,tt] ;set it
ldb t,[$cpksa chapkt] ;get source host address
dpb t,[220300,,tt]
lsh t,-3
dpb t,[300300,,tt]
lsh t,-3
dpb t,[360300,,tt]
.suset [.ruind,,t] ;incoroporate user index also
dpb t,[000300,,tt]
lsh t,-3
dpb t,[060300,,tt]
move t,tt ;save copy for xuname
.suset [.sjname,,whoami]
movei n,100(tt) ;loop at most 100 times
login: cain n,(tt)
jsr die
.call [setz
sixbit /LOGIN/
tt ? a ? setz t]
aoja tt,login ;error, perhaps need to try other uname
syscal detach,[movsi 3 ? movei %jself]
jsr die
return
;now look at the connection name string and find out where the guy wants to go
gethst: move bp,[440800,,chapkt+%cpkdt] ;point to packet's data
ldb n,[chapkt+$cpknb] ;get number of bytes in it
geths1: sojl n,nohost ;didnt give enough information
ildb t,bp
caie t,40 ;look for space
jrst geths1
jumpe n,nohost
move a,[440700,,hstnam]
geths2: ildb t,bp ;get char from packet
idpb t,a ;build ascii of hostname
caie t,40
sojge n,geths2
movei t,0
dpb t,a ;make null terminated string
move a,[440700,,hstnam]
call netwrk"hstlook ;go lookup hostname
jrst badhst
movem a,frnhst
move a,[netwrk"nw%arp]
call netwrk"ownhst ;look up our name
setz a,
tlz a,740000 ;Flush any format info
movem a,lclhst
setzm netwrk"hstadr ;can now flush hosttable
.core hstpag
jsr die
return
;now look for socket to hook up to
getskt: setz a, ;accumulate it here
getsk1: sojle n,getsk2
ildb t,bp
cain t,40
jrst getsk2
cail t,"0
caile t,"7
jrst badskt
lsh a,3
addi a,-"0(t)
jrst getsk1
getsk2: skipn a
movei a,1 ;default to logger
movem a,icpskt
return
;now we attempt the connection
getcon: move a,whoami
camn a,[sixbit /ARPA/]
jrst gtcarp
camn a,[sixbit /NCP/]
jrst gtcncp
camn a,[sixbit /TCP/]
jrst gtctcp
movei a,[asciz /Unknown gateway protocol request/]
call sndcls
jsr die
gtcncp: movei a,icpch ;first of 4 channels to use
move b,frnhst ;host
move c,icpskt ;icp socket
move d,[40+.uai,,40+.uao] ;8 bit mode
move nch,a ;arg to doanal
call netwrk"arpicp ;try to connect up
jrst doanal ;failed, send CLS of why
return
gtcarp: call gtttcp ;try tcp first
jrst [ move t,[sixbit /NCP/] ;tcp failed
movem t,whoami
jrst gtcncp] ;else try NCP
move t,[sixbit /TCP/] ;tcp succeeded
movem t,whoami
return
gtctcp: call gtttcp
jrst fail
return
gtttcp:
IFN 0,[ syscal tcpopn,[movei netich ? movei netoch
[-1] ? icpskt ;local, foreign
frnhst]
jsr die ;failed (should timeout!)
movei t,15.*30. ;15 seconds
syscal netblk,[movei netich ? movei %nsrfs ? t ? movem tt ? movem t]
jsr die
jumple t,tcptmo
tlz tt,-1 ;cflush left half??
caie tt,%nsopn
cain tt,%nsinp
jrst gtctc2 ;winning
cain tt,%nscli ;CLS but input?
jrst gtctc2 ;still winning
return ;failure
];IFN 0
movei a,netich
move b,frnhst
move c,icpskt
call netwrk"tcpcon
return ;failure
gtctc2: aos (p) ;skip return
return
;set up interrupts
getrdy: .suset [.smask,,[%piioc]]
.suset [.smsk2,,[1_netich\1_chaich]]
.suset [.ropti,,t]
tlo t,optint ;turn on new-style interrupts
.suset [.sopti,,t]
;won, send back opn on chaosnet connection
movei t,%coopn
dpb t,[chapkt+$cpkop]
.call sndpkt
jsr die
return
fail: movei a,[asciz /TCP connection to foreign host failed/]
jrst sndcls
tcptmo: movei a,[asciz /Timeout while trying to TCP connect/]
jrst sndcls
badhst: skipa a,[[asciz /No such host/]] ;gave a bad host name
badskt: movei a,[asciz /Bad icp socket/]
jrst sndcls
nohost: movei a,[asciz /No host name specified/] ;didnt give a hostname
sndcls: hrli a,440700
movei n,0 ;initialize byte count
move bp,[440800,,chapkt+%cpkdt] ;and byte pointer for packet
sndcl1: ildb t,a
jumpe t,sndcl2
idpb t,bp
aoja n,sndcl1
sndcl2: dpb n,[chapkt+$cpknb] ;store byte count
movei t,%cocls
dpb t,[chapkt+$cpkop] ;and opcode
.call sndpkt
jsr die
sndcl3: cain cch,chaich
jrst passon
jrst auxfls
doeof: movei cch,chaich-netich(nch)
movsi t,(.byte 8 ? %coeof ? 0)
movem t,chapkt
.call sndpkt
.lose %lssys
.call [ setz ;wait for output to get there
sixbit /FINISH/
setzi 1(cch)]
jrst sndcl3 ;dont need to close if other side does
;send cls of reason for arpanet connection losing
doanal: movei n,0
move bp,[440800,,chapkt+%cpkdt] ;init byte count and pointer
movei a,(nch)
call netwrk"analyz
jsr die
movei cch,chaich-netich(nch)
cail cch,chaich
caile cch,caxoch
movei cch,chaich
jrst sndcl2 ;and go send that off
;guys for netwrk
popj1: aos (p)
cpopj: ret
putchr: idpb t,bp
aoja n,cpopj
;here if get an ioc error, check the state of the arpanet connections
iocerr: aosn iocflg
jsr die ;recursive IOC errors, go away
.call [setz ? 'whyint ? movei netich ? movem s ? setzm s]
jsr die
tlz s,400000 ;ignore network interrupt bit
caie s,%nsopn ;still intact?
jrst iocer1 ;no, go tell chaosnet connection why it lost
.call [setz ? 'whyint ? movei netoch ? movem s ? setzm s]
jsr die
tlz s,400000
caie s,%nsrfn
cain s,%nsopn
jsr die ;random ioc error, just go away
iocer1: ;;undefer interrupts so can get another ioc ok
setom iocflg' ;If recursive IOC error, give up and go away, don't loop
move a,-2(p) ;previous DF1 word
.suset [.sdf1,,a] ;undefer this first so can get IOC if get I/O int
move a,-1(p) ;previous DF2 word
.suset [.sdf2,,a]
jrst doeof
;network interrupt, get input from arpanet and send to chaosnet
auxint: movei nch,auxich
movei cch,caxich
jrst netin0
netint: movei nch,netich
movei cch,chaich
netin0: .call [setz ? 'whyint ? movei 0(nch) ? movem s ? movem s ? setzm n]
jsr die
tlz s,400000
cain s,%nsopn ;still open?
jrst intx ;yes, spurious i guess
caie s,%nscli
cain s,%nsinp
jrst netin1 ;input waiting, get some
jrst doeof ;in some wedged state, flush it
netin1: move t,whoami
came t,[sixbit /NCP/]
jrst ntitcp ;not NCP, go handle TCP
jumple n,netin2 ;no bytes waiting, forget it
caig n,%cpmxc ;more than a packet's worth?
skipa t,n
movei t,%cpmxc
subi n,(t)
dpb t,[chapkt+$cpknb] ;number of bytes we will send
movei tt,%codat
dpb tt,[chapkt+$cpkop]
move tt,[440800,,chapkt+%cpkdt]
.call [setz ? sixbit/siot/ ? movei 0(nch) ? tt ? setz t]
jsr die
.call sndpkt
jsr die
jrst netin1 ;go see if there is more to come
ntitcp: movei t,%cpmxc ;assume we'll read in a chaos packet's worth
move tt,[440800,,chapkt+%cpkdt]
syscal siot,[movsi 10 ? movei 0(nch) ? tt ? t] ;don't hang
jsr die
cain t,%cpmxc ;read anything
jrst netin2 ;nope, finish up
subi t,%cpmxc
movn t,t ;now number of characters read
dpb t,[$cpknb chapkt]
movei tt,%codat
dpb tt,[$cpkop chapkt]
.call sndpkt
jrst die
jrst ntitcp
netin2: cain s,%nscli ;was is closed except for that input?
jrst doeof ;yes, finish up then
intx: .call [setz ? 'dismis ? setz p]
jsr die
;chaosnet interrupt
caxint: movei cch,caxich
movei nch,auxich
jrst chain0
chaint: movei cch,chaich
movei nch,netich
chain0: .call [setz ? 'whyint ? movei 0(cch) ? movem s ? movem s ? setzm n]
jsr die
cain s,%csinc ;did chaosnet go away?
jrst chain3 ;yes, flush it i guess
hlres n ;get number of receive packets waiting
jumple n,intx
chain1: .call rcvpkt ;read the next packet out
jsr die
ldb t,[chapkt+$cpkop] ;get opcode
caie t,%cocls
cain t,%colos
jrst chain3 ;connection gone or losing, go away
caie t,212
cain t,210 ;special escape?
jrst opnaux ;yes, open aux conn
cain t,211
jrst tcaux2 ;open aux conn, part two
caige t,%codat ;data packet?
jrst chain2 ;no, just ignore it
cain t,%cobrk ;send network INS, then treat packet as data
.call [setz ? sixbit/netint/ ? setzi 1(nch)]
jfcl
ldb t,[chapkt+$cpknb] ;get byte count
move tt,[440800,,chapkt+%cpkdt] ;point to data
.call [setz ? sixbit/siot/ ? movei 1(nch) ? tt ? setz t]
jsr die
chain2: sojg n,chain1
.nets netoch, ;send off the buffered output
jrst chain0 ;go look for more
chain3: caie cch,chaich ;main connection?
jrst auxfls ;no, just close aux
.close netoch, ;close the arpanet connections
.close netich,
jrst passon ;and go away quietly
auxfls: .suset [.samsk,,[1_auxich\1_caxich]]
.close auxoch,
.close auxich,
.close caxich,
.close caxoch,
setzm iocflg ;DOne processing ioc error I guess
jrst intx
;special escape, open an aux connection
opnaux: movem t,opnaxo' ;save opcode
move c,chapkt+%cpkdt+2 ;get the foreign socket
lsh c,-4 ;normalize it
movei cch,caxich
movei nch,auxich
.call [setz ? 'chaoso ? movei caxich ? movei caxoch ? setzi 5]
jsr die
ldb t,[chapkt+$cpknb]
subi t,4
dpb t,[chapkt+$cpknb]
movei t,%colsn
dpb t,[chapkt+$cpkop]
.call sndpkt
jsr die
movei t,30.*60.
skipe debug
hrloi t,177777 ;wait forever if debugging
.call [setz ? 'netblk ? movei caxich ? movei %cslsn ? t ? setzm t]
jsr die
caie t,%csrfc ;did we get an rfc for this?
jrst intx ;no, forget it
.call rcvpkt ;yes, read it in
jsr die
move b,frnhst
move t,whoami
camn t,[sixbit /TCP/]
jrst tcpaux
movei a,auxich
trnn c,1 ;is this going to be receive?
movei a,auxoch ;no, send
movei d,140+.uai
trnn c,1
movei d,140+.uao
call netwrk"arpcon
jrst doanal ;failed, send a cls for rfc
movei t,%coopn
dpb t,[chapkt+$cpkop]
.call sndpkt
jsr die
.suset [.simsk,,[1_caxich\1_auxich]]
jrst intx
tcpaux: syscal rfname,[movei netich ? movem d ? movem d]
.lose %lssys
move t,opnaxo ;opcode 212?
cain t,212
seto d, ;yes, use gensym local port
syscal tcpopn,[movsi 100 ? movei auxich ? movei auxoch
d ? c ;otherwise same local port, specified foreign port
b]
jrst doanal
caie t,212
jrst intx ;dismiss now, wait when told to
syscal rfname,[movei auxich ? movem t ? movem t]
jsr die
;Send back a packet containing the local port number
lsh t,16.+4
movem t,chapkt+%cpkdt
movei t,2
skipn tt,lclhst
jrst tcaux1
lsh tt,-16.+4
iorm tt,chapkt+%cpkdt
move tt,lclhst
lsh tt,16.+4
movem tt,chapkt+%cpkdt+1
movei t,6
tcaux1: dpb t,[chapkt+$cpknb]
movei t,300 ;binary data
dpb t,[chapkt+$cpkop]
syscal pktiot,[movei chaoch ? movei chapkt]
jsr die
jrst intx
;;; TCP open, part two.
tcaux2: movei cch,caxich
movei nch,auxich
movei b,30.*30. ;only gets called from aux connection
movei c,%nslsn
tcax2b: syscal netblk,[movei auxich ? c ? b ? movem c ? movem b]
jrst doanal
jumple b,doanal
tlz c,-1
cain c,%nsrfc ;transient state
jrst tcax2b
caie c,%nsopn ;open, or
cain c,%nsinp ;open with input
jrst tcax2a
caie c,%nscli ;also closed with input
jrst doanal
tcax2a: movei t,%coopn ;open response to chaos
dpb t,[chapkt+$cpkop]
.call sndpkt
jsr die
.suset [.simsk,,[1_caxich\1_auxich]] ;enable interrupts
jrst auxint ;exit through interrupt code in case closed with input
pat": patch": block 100
variables
constants
hstpag==<.+1777>/2000 ;place to map in the hosts1 file.
end go