; -*- Midas -*- title NETIME - Get the time from the network. rdtim=:702200,, ; KS10 clock instructions. wrtim=:702600,, clk==:500 ; PD clock on KA10s and MX-KL a=:1 b=:2 c=:3 d=:4 e=:5 t=:6 tt=:7 count=:10 p=:17 ttyoch==:1 netoch==:2 nnetch==:<20-netoch>/2 netich==:netoch+nnetch utilch==:2 call=:pushj p, return=:popj p, save==:push p, rest==:pop p, flose=:.lose %lsfil slose=:.lose %lssys pause=:.break 16,100000 quit=:.logout 1, tyo=:.iot ttyoch, define conc foo,bar foo!bar!termin %f==:1,,525252 ; Flags in LH(0) %fhsts==:000002 ; Host table loaded? %ftime==:000004 ; Timer repeat nnetch, conc %fnet,\.rpcnt,==:1_ netmsk==:<1_nnetch-1>_netich define syscall name,args .call [setz ? sixbit /name/ ? args(400000)] termin popbj1: rest b popj1: aosa (p) popbj: rest b cpopj: return datime"$$svng==:1 datime"$$out==:1 datime"$$abs==:1 .insrt dsk:syseng;datime > format"$$time==:1 format"datime==:datime"twdasc format"time==:datime"timasc format"date==:datime"datasc format"$$pcode==:1 .insrt dsk:syseng;format > outstr: syscall siot,[movei ttyoch ? a ? b] slose return define format &string&,args call [ call $format .zzz.==-1 irp arg,,[args] save arg .zzz.==.irpcnt termin hrroi a,[ascii string] movei b,.length string movni c,.zzz.+1 jrst format"format] termin $forma: save a save b save c save [.+2] jrst @-4(p) rest c rest b rest a rest (p) return ; Hosts are arranged first into groups by approximate speed and ; reliability. Each group is in random order. Until I can get ; dqdev working right, I'm putting the IP#'s here. /Paul hosts: ; Ask local machines first. [asciz "cloud.svensson.org"] [asciz "home.svensson.org"] [asciz "192.168.2.13"] ; korpilombolo.svensson.org [asciz "192.168.2.17"] ; seventeen.svensson.org ; Other ITSes [asciz "up.update.uu.se"] ; Lysator machines tend to be up. [asciz "130.236.254.3"] ; mail.lysator.liu.se [asciz "130.236.254.50"] ; ftp.lysator.liu.se [asciz "130.236.254.106"] ; hetzer.lysator.liu.se [asciz "130.236.254.167"] ; blaskan.lysator.liu.se [asciz "130.236.254.250"] ; nazgul.lysator.liu.se ; Some random hosts. [asciz "158.121.106.20"] ; delysid.gnu.org [asciz "207.202.214.131"] ; otaku.freeshell.org [asciz "12.17.138.171"] ; kappa.unlambda.com [asciz "209.251.101.202"] ; sakura.lunar-tokyo.net [asciz "207.202.214.132"] ; sdf.lonestar.org [asciz "192.207.126.3"] ; dinky.musenki.com [asciz "199.232.76.164"] ; fencepost.gnu.org [asciz "18.24.10.26"] ; mc.lcs.mit.edu [asciz "63.222.128.227"] ; alembic.crystel.com [asciz "194.236.34.19"] ; realpanic.nocrew.org ; Keeping these at the end keeps them from acting as a bottleneck. ; (It also gives them less time to respond...) <(sixbit /SV/)>,,[asciz "SV"] <(sixbit /SX/)>,,[asciz "SX"] <(sixbit /UP/)>,,[asciz "UP"] <(sixbit /PI/)>,,[asciz "PI"] <(sixbit /DX/)>,,[asciz "DX"] nhosts==:.-hosts ;;; Parameters that can be patched: setp: -1 ; 0 => don't actually set the time. wait: 10.*60. ; Wait 10 seconds polling other hosts. 0 ? 0 ? 0 ; Zeros for .REALT just in case... numerq: 2 ; Ceiling of 2/3 of the hosts that respond denomq: 3 ; must agree on the time. minq: 2 ; Insist on at least 2 hosts with times in ; agreement. spread: 10. ; Times agree if they differ by less than ; 10 seconds days: 7 ; If machine looks like it was down for ; this many days, then require a human to ; set the time. filesn: sixbit /DRAGON/ ; The creation date of this file is some filen1: sixbit /DRAGON/ ; indication of what time the system last filen2: sixbit /HOARD/ ; thought it was. .scalar lstime ; Creation date of above file. .insrt dsk:system;chsdef > .vector opkt(%cpmxw) ; Output packet .vector ipkt(%cpmxw) ; Input packet .vector state(nnetch) ; What each net channel is working on. .vector times(nhosts) ; The time reported by each host. ; In seconds since January 1, 1900, GMT. .vector atimes(nhosts) ; The time we believe the host looked at ; his clock. In 60ths of a second since ; system was booted. lpdl==:100. .vector pdl(lpdl) ; The usual. .scalar itsnam ; The name of this machine in SIXBIT. usrvar: sixbit /OPTION/ ? tlo %opint\%opopc sixbit /MASK/ ? move [%pirlt\%piioc\%piwro\%pimpv\%pilos\%piilo] sixbit /MSK2/ ? movei netmsk lusrvar==:.-usrvar go: .pdtime b, .suset [.rsuppro,,a] came b,[-1] jumpl a,[quit] movsi b,(sixbit /T00/) skipl a movsi b,(sixbit /TTY/) syscall open,[[.uao\%tjdis,,ttyoch] ? b] skipa jrst go1 movei tt,5*30. .sleep tt, jrst go go1: move tt,[%rlfls\%rlset,,wait] .realt tt, movsi 0,netmsk ; initial flags move p,[-lpdl,,pdl-1] move tt,[-lusrvar,,usrvar] syscall usrvar,[movei %jself ? tt] slose syscall sstatu,[repeat 6,[ ? movem itsnam]] slose syscall open,[[.uai\%donrf,,utilch] ? [sixbit /DSK/] filen1 ? filen2 ? filesn] jrst nofile syscall rfdate,[movei utilch ? movem lstime] flose .close utilch, irps sym,,[ka10p,kl10p,ks10p,pdtime,fyear] .scalar sym move tt,[squoze 0,sym] .eval tt, .lose movem tt,sym termin move tt,[squoze 0,ksfreq] .eval tt, movei tt,<<1000._12.>+30.>/60. movem tt,ksfreq movei a,netgo movem a,state+0 move tt,[state+0,,state+1] blt tt,state+nnetch-1 setzm times+0 move tt,[times+0,,times+1] blt tt,times+nhosts-1 movei a,%corfc dpb a,[$cpkop opkt] movei a,4 dpb a,[$cpknb opkt] move a,[.byte 8 ? "T ? "I ? "M ? "E] movem a,opkt+%cpkdt setz count, hrloi c,-1-nhosts ; C: aobjn into hosts loop: tlnn netmsk\%ftime .hang tlze %ftime jrst timout jffo .+1 movei b,17.-netich sub b,a ; B: current net channel move t,state(b) hlrz d,t ; D: usually current host jrst (t) tsint: loc 42 -ltsint,,tsint loc tsint 0,,p %piioc ? 0 ? 0 ? 0 ? iocint ; synchronous %pirlt ? 0 ? 0 ? 0 ? timint 0 ? netmsk ? 0 ? 0 ? netint %piwro\%pimpv\%pilos\%piilo ? 0 ? -1 ? -1 ? badint ltsint==:.-tsint dismis: setz ? sixbit /DISMIS/ ? setz p badint: .close ttyoch, ; Close TTY channel to let hacker log in .value ; Leave a corpse netint: tso -3(p) .call dismis slose timint: tlo %ftime .call dismis slose iocint: save t hrrz t,-1(p) caie t,ioc1 cain t,ioc2 caia jrst badint rest t aos (p) .call dismis slose netgo: aobjp c,nomore hllz a,hosts(c) camn a,itsnam ; Is this us? jrst netgo hrrz a,hosts(c) call look jrst netgo ; Must be gone or something? tlnn a,<-1>_14. tlnn a,<-1>_6. jrst [dpb a,[$cpkda opkt] syscall chaoso,[movei netich(b) ? movei netoch(b)] jrst netgo ; Chaosnet full? Broken? tdz netbit(b) syscall pktiot,[movei netoch(b) ? movei opkt] slose hrrzi a,netin jrst opnok] tdz netbit(b) syscall tcpopn,[movei netich(b) ? movei netoch(b) ? move [-1] ? movei 37. ? move a] jrst netgo ; Net full? Broken? hrrzi a,tcpin opnok:: hrli a,(c) movem a,state(b) .rdtime tt, movem tt,atimes(c) ; Begin our wait aoja count,loop tcpin: tdz netbit(b) syscal whyint,[movei netich(b) ? movem a ? movem a ? movem e] slose caie a,%ntcls cain a,%ntclu soja count,netgo caie a,%ntinp cain a,%ntcli caia jrst loop caige e,4 jrst loop ; Ick... busy waiting here caie e,4 soja count,netgo setz a, ioc1:: syscal iot,[movei netich(b) ? t] soja count,netgo ; IOC ints return to here. lsh a,8. ior a,t sojg e,ioc1 .rdtime tt, addm tt,atimes(d) ; End our wait (computes average in 60ths) movem a,times(d) aos d soja count,netgo netin: sos count ioc2:: syscall pktiot,[movei netich(b) ? movei ipkt] jrst netgo ; IOC ints return to here. .rdtime tt, addm tt,atimes(d) ; End our wait (computes average in 60ths) ldb t,[$cpkop ipkt] caie t,%coans jrst netgo ldb t,[341000,,ipkt+%cpkdt] dpb t,[001000,,times(d)] ldb t,[241000,,ipkt+%cpkdt] dpb t,[101000,,times(d)] ldb t,[141000,,ipkt+%cpkdt] dpb t,[201000,,times(d)] ldb t,[041000,,ipkt+%cpkdt] dpb t,[301000,,times(d)] aoja d,netgo netbit: repeat nnetch, 1_,,0 nomore: syscall close,[movei netich(b)] slose syscall close,[movei netoch(b)] slose tdz netbit(b) movei a,[ jfcl ? .lose ] movem a,state(b) jumpe count,setime jrst loop .vector sorted(nhosts) ; Sorted indices of times. timout:: setime: skipn setp jrst sort setoi tt, .iotlsr tt, ;; Set time relative to -now-. skipe ks10p rdtim kstime skipn ks10p datai clk,clktim sort: .rdtime e, lsh e,1 ; E: system time in 60ths addi e,30. ; (for rounding later) setzi b, ; B: # entries sorted so far movsi a,-nhosts ; A: aobjn into TIMES skipn c,times(a) ; C: time sortlp: aobjn a,.-1 ; Skip people who didn't answer jumpge a,vote move t,e ; Compute time since he looked at his clock sub t,atimes(a) idivi t,60. ; Convert to seconds (rounded) add c,t movem c,times(a) skipn d,b ; D: candidate index for insertion jrst sort0 sort1: move tt,sorted-1(d) camge c,times(tt) sojg d,sort1 sort0: movei tt,(d) subi tt,1(b) hrli d,(tt) ; D: aobjn into part or SORTED to move movei tt,(a) ; The index to insert exch tt,sorted(d) aobjn d,.-1 aoja b,sortlp .scalar ntimes ; The number of people who responded. .scalar quorum ; The size of a quorum vote: movem b,ntimes imul b,numerq add b,denomq soj b, idiv b,denomq camge b,minq move b,minq movem b,quorum setzi a,0 ; A: index of possible lowest good time soj b, ; B: must agree with A for quorum low: caml b,ntimes jrst nogo move tt,sorted(b) move t,times(tt) move tt,sorted(a) sub t,times(tt) camg t,spread jrst gotlow aoj a, aoja b,low gotlow: move b,ntimes movei c,-1(b) ; C: index of possible highest good time sub b,quorum ; B: must agree with C for quorum high: move tt,sorted(c) move t,times(tt) move tt,sorted(b) sub t,times(tt) camg t,spread jrst gotime soj b, soja c,high .scalar lowest ; Index of lowest of good times. .scalar highest ; Index of highest of good times. .scalar median ; Index of median of good times. .scalar host ; Pointer to ASCIZ name of winning host. .scalar time ; Winning network time. .scalar qtime ; Winning network time in disk format. .scalar qzone ; SIXBIT timezone of QTIME. .scalar year ; Year of winner. .scalar ticks ; PD-ticks since January 1 of winner. .scalar ksfreq ; KS-tick per PD-tick .vector kstime(2) ; Set time relative to this. .scalar clktim ; Or this. s%d==:24.*60.*60. s%y==:365.*s%d s%est==:datime"estdif*60.*60. gotime: movem a,lowest movem c,highest addi c,1(a) lsh c,-1 movem c,median move tt,sorted(c) hrro a,hosts(tt) movem a,host move a,times(tt) movem a,time call cvtime movem e,qzone movem a,qtime move b,lstime call datime"timsub add a,spread ; Allow for the usual fuzz... jumpl a,past move tt,days imuli tt,s%d camle a,tt jrst future ldb b,[.bp datime"tm%yr,qtime] ; EST and EDT always agree about movei tt,1900.(b) ; the year! movem tt,year subi b,1 ; (Compensates for the fact that 1900. was idivi b,4 ; not a leap year. (Screws up if you give addi c,1 ; a time in 1900., but who cares?)) imul b,[4*s%y+s%d] imul c,[s%y] add b,c ; B: Seconds from 1/1/00 to this year. move a,time subi a,s%est ; GMT -> EST sub a,b imuli a,60. movem a,ticks skipn setp jrst nsetp skipn ks10p jrst notks dmove a,kstime hrrz a,a ; Clear possible gubbish from high bits. div a,ksfreq ; KS-ticks -> PD-ticks jrst doit notks: move a,clktim tlz a,600000 ; Clear possible gubbish from high bits. ;; On a KA if this is zero then apparently the PD clock is off. ;; Fix this code to deal with that if you try to bring this code up ;; on a KA (see PDSET program). (Where did you find a working ITS ;; KA10 anyway?) skipe ka10p .lose doit: sub a,ticks ; A: offset for loading into PDTIME format "~&Setting the time to be ~Q ~S ~ (supplied by ~A).~&",[qtime,qzone,host] move tt,fyear hrli tt,year .setloc tt, move tt,pdtime hrli tt,a .setloc tt, skipa ; This is supposed to give the SETLOC skipa ; a chance to happen before starting the .hang ; clock. setoi tt, .iotlsr tt, skipe kl10p cono clk,400007 ; Start clock on KL skipn ks10p quit rdtim t hrli t,1729. wrtim t quit nsetp: format "~&Would have set the time to be ~Q ~S (supplied by ~A).~ ~& FYEAR/ ~D. PDTIME/ ~D.~&",[qtime,qzone,host,year,ticks] call table quit notset: format " Attention! Attention! The time could not be set because:" call (a) format "~&It will be necessary for someone to set the time~@ manually by logging in and running :PDSET.~2&" quit nofile: jsp a,notset format "~&There was an error accessing the file ~ ~S;~S ~S.",[filesn,filen1,filen2] return bogus: format "~&The best time, ~Q ~S (supplied by ~A),",[qtime,qzone,host] call (a) format "~Q, the creation date of ~ ~S;~S ~S.",[lstime,filesn,filen1,filen2] return future: jsp a,notset jsp a,bogus format " was more than~&~D day~P beyond ",[days] return past: jsp a,notset jsp a,bogus format " was~&prior to " return nogo: jsp a,notset skipn t,ntimes jrst nogo0 camge t,quorum jrst nogo1 format "~&Of the ~D answer~P recieved, ~ no ~D agreed to within ~D seconds.",[ntimes,quorum,spread] return nogo0: format "~&No host responded." return nogo1: format "~&Only ~D host~P responded.",ntimes return ;;; CALL TABLE: Print a table of everything we know. table: save a save b save e format "~&~D host~P responded.",ntimes caie count, format " ~D outstanding request~P.",count movei b,0 tablel: caml b,ntimes jrst tablex move tt,sorted(b) move a,times(tt) call cvtime move tt,sorted(b) hrro t,hosts(tt) format "~&~3<~D~>: ~Q ~S ~A",[b,a,e,t] aoja b,tablel tablex: format "~&Low=~D High=~D Median=~D",[lowest,highest,median] format "~&Quorum=~D Spread=~D sec.~&",[quorum,spread] rest e rest b rest a return ;;; CALL CVTIME: Convert network time to local disk format time word. ;;; A (arg): network time ;;; A (val): disk format date ;;; E (val): SIXBIT of timezone cvtime: subi a,s%est ; GMT -> EST call datime"sectim ; -> disk format date save b movei b,60.*60. call datime"odayl skipa e,[sixbit /EDT/] skipa e,[sixbit /EST/] call datime"timadd rest b return netwrk"$$hstmap==:1 netwrk"$$hostnm==:1 netwrk"$$symlook==:1 netwrk"$$chaos==:1 netwrk"$$arpa==:1 .insrt dsk:syseng;netwrk > ;;; CALL LOOK: Look up the Chaosnet address of a host. ;;; A (arg): address of ASCIZ string ;;; A (val): host number ;;; Skips if the host is found. look: save b tloe %fhsts jrst look1 save a movei a,ffpage movei b,utilch .iopush utilch, call netwrk"hstmap .lose .iopop utilch, rest a look1: call netwrk"hstlook jrst popbj rest b aos (p) return cnstnts: constants patch:: pat: block 100. variables ffaddr: -1 ; Make memory exist ffpage==:_-12 end go