conststring (13) vsn = "ftps....2a " #datestring #timestring !******************************** !* emas-2900 fep ftp server * !* file: fpt3s/fpt3y * !* * !******************************** !#options ! prep versions are:- ! ! k = kent (no uflag) ! e = ERCC ! r = ring ! n = nsi ! x = Transport Service ! m = Full Monitoring ! i = new imp compiler ! #if ~(k!e) ! ~(r!n!x) ! (r&n) ! (k&e) ! (k&n) #if "incompatible prep options" #fi #fi #if i control x'4001' #else control 1 #fi #if i include "b_deimosspecs" #else include "deimosperm" #fi begin externalstring (255) fnspec itos(integer n,j) recordformat am1f(integer rxs, rxd, txs, txd) ownrecord (am1f) name l == 1; ! supplied by am1 handler #if n recordformat lev3f(byteinteger fn, sufl, st, ss, c (byte sn, dn, dt, ds, lfl, luflag, bytearray aa(0:241) or byte sfl, suflag, c (byteintegerarray a(0:241) or c integer x1, x2, x3, x4, users, state, cpu, pkts, sbr, byt, ftpo, ftpi))) #fi #if r #if k recordformat lev3f(integer st,ds,rc,tc, c (byteintegerarray a(0:241) or c integer x1, x2, x3, x4, users, state, cpu, pkts, sbr, byt, ftpo, ftpi)) #else recordformat lev3f(integer st,ds,rc,tc,uflag, c (byteintegerarray a(0:241) or c integer x1, x2, x3, x4, users, state, cpu, pkts, sbr, byt, ftpo, ftpi)) #fi #fi #if x recordformat lev3f(bytearray reserved(0:7), bytearray a(0:241)) #fi #if r #if e recordformat ssmessagef(integer sou,prt,c,prt r,ds,st,sn, c byteintegerarray a(0:237)); !$e #else recordformat ssmessagef(integer sou,prt,c,prt r,ds, c byteintegerarray a(0:239)) #fi #fi recordformat mef(record (mef) name link, c byteinteger len, type, (record (lev3f)lev3 or c bytearray params(0:231))) recordformat m2900f(record (mef) name l, byteinteger len, type, c integer stream, sub ident, c (integer p2a, p2b, p3a, p3b,p4a, p4b, p5a, p5b, p6a, p6b or c bytearray b(0:19))) recordformat maf(record (mef)name l, byteinteger mlen, c mtype, (byte len, type, c (bytearray m(0:242) or c integer ref, in ident, out ident, string (63) address) or c bytearray a(0:240))) #if ~x recordformat pe(byteinteger ser, reply, c fn, gate port, record (mef) name mes, (byte c1, s1 or c integer c)) #else recordformat pe(byteinteger ser, reply, c (integer a, b, (integer c or byte c1, c2) or byte fn, a2, c (record (mef)name mes, byte gate port, task port or c string (3) facility))) #fi recordformat qf(record (mef) name e) !******************************************************** !* formats of tables, ie stream descriptors, tcps etc * !******************************************************** recordformat con desf(record (mef) name hold, c integer index, stream, permit, node, term, first, istate, c o state, port, mode, kill, direction, in, n, icount, ref, outlen, c cpos, count, nc, secadd, c record (mef) name holdi, record (qf) inp q) !************************************************************ !* upper level (itp&ftp) handler messages to gate !************************************************************ #if ~x constinteger enable facility = 1; ! enable the facility ! %constinteger disable facility = 2; ! the reverse constinteger call reply = 3; ! reply to a 'call connect' constinteger enable input = 4; ! allow a block to be read constinteger put output = 5; ! send a block of output constinteger close call = 6; ! terminate a call constinteger abort call = 7; ! abort the call constinteger open call = 8; ! open up a call constinteger open message = 9; ! send a message !********************************************************** !* messages from gate to upper level protocols !********************************************************** constinteger incoming call = 2 constinteger input recd = 3; ! block arrived from node constinteger output transmitted = 4; ! prepared to accept more constinteger call closed = 5; ! either end has closed down constinteger call aborted = 6; ! other end has aborted constinteger open call a = 7 constinteger open call b = 8; ! reply from remote constinteger message r = 9; ! message rec'd constinteger message reply = 10; ! message reply from gate #else #if k include "tsbsp_tscodes" #else include "b_ygatecalls" #fi #fi !************************************************************** !* buffer manager calls (from and to) * !************************************************************** ! %constinteger buffer here = 0 !********** to buffer manager *********** constinteger request buffer = 0 constinteger release buffer = 1 !************************************************************** !* calls to 2900 link handler * !************************************************************** constinteger send data = 0 constinteger low level control = 1 constinteger here i am = 2 constinteger return control = 3 !************************************************************** !* replies from 2900 link handler * !**************************************************************** constinteger interf addr = 0 constinteger do input = 1 constinteger do output = 2 constinteger message = 3 constinteger mainframe up = 4 constinteger mainframe down = 5 !**************************************************************** !********** various service numbers ************* #if ~x ! k constinteger gate ser = 16 #else constinteger gate ser = 24 #fi constinteger buffer manager = 17 constinteger link handler = 18 constinteger t3 ser = 21 constinteger comm bit = k'1' constinteger accept char = k'002' constinteger acfy = k'010'; ! peter calls it rxfy constinteger xopl = k'020'; ! x operable - latched ! %constinteger xop = k'040'; ! x operable constinteger ready = k'200' !********************* FTP Transfer Control Commands ************* constinteger ss = x'40'; ! Start of Data constinteger cs = x'42'; ! Code Select constinteger es = x'43'; ! End of Data constinteger qr = x'46'; ! Quit constinteger er = x'47'; ! End Acknowledge !******************* FTP Initialisation and Termination *************** constinteger p stop = X'00'; ! Request Termination (from p) constinteger q Stopack = X'05'; ! Acknowledge Termination (from q) !*********************************************************** !* 2900 states * !*********************************************************** own integer host state = 0; ! holds 2900 state constinteger down = 0 constinteger up = 1 !****************** comms control states ******************** constinteger unused = 0 constinteger disconnecting = 1 constinteger connecting = 2 constinteger suspending = 4; ! end of section or file constinteger aborting = 5 constinteger enabling = 7 constinteger enabled = 8 !* s t a t e s constinteger not alloc = -1 constinteger idle = 0 constinteger op ready = 1; ! applies to the connection constinteger input ready = 1; ! input streams only constinteger trying = 2; ! awaiting network reply constinteger timing = 3; ! connection refused, waiting for clock constinteger aborted = 4; ! 2900 has gone down constinteger connect 1 = 5; ! lev3 connected, waiting for ! 2900 connect&enable constinteger connected = 6; ! in file constinteger enabld = 7; ! 2900 has started file constinteger close ready = 8; ! fep is ready to accept a close constinteger closing = 9; ! close has been sent to network !****************************************** !* reasons for waiting for a buffer * !****************************************** constinteger low level ip transfer = 22 constinteger low level op transfer = 23 constinteger get op block = 24 constinteger send abort = 25; ! ask emas to abort stream constinteger do input connect = 27 constinteger connecting reply = 29; ! keep this odd (see from buffer manager) constinteger connecting reply 2 = 30 constinteger connecting reply failed = 31 constinteger connecting reply 2 failed = 32 #if x constinteger get connect buffer = 33 #if k constinteger send push = 34 #fi #fi !************************************************************** routinespec to gate(integer fn, record (mef) name mes, c integer flag) routinespec to 2900(integer fn, record (m2900f) name m2900) routinespec get buffer(integer reason) routinespec free buffer(record (mef) name mes) routinespec who and state routinespec tell routinespec from gate routinespec from 2900 routinespec do connect record (con desf) mapspec get free des routinespec flush file routinespec from buffer manager(record (pe) name p) integerfnspec allocate stream(record (con desf) name d) routinespec tidy buffers routinespec retrieve(record (con desf) name d) routinespec do repm(integer flag) routinespec clear all streams routinespec read from am1 routinespec write to am1 routinespec read message from am1 routinespec write message to am1 routinespec mon mes(record (mef) name mes) !****************************************************** record (pe) p owninteger con sub id reply = 1; ! picks up from actual mess ownrecord (con desf) name d ownrecord (con desf) name d4, d5 constinteger con lim = 16; ! number of active terminals (see fixed top) ownrecord (con desf) array con desa(0:con lim) ownrecord (qf) name free des; ! pts to list of free con desa record (qf) name q frig #if x ownstring (63) array adda(0:conlim) #fi #if ~x constinteger max ports = 50 ownbyteintegerarray porta(0:max ports) ! cross index from port to tcp #fi constinteger fixed = 350; ! 1st available stream constinteger fixed top = 400; ! number of 2900 streams in eam5 ! was 281 ! ownbyteintegerarray am1a(fixed:fixed top) = k'377'(*) ownbyteintegerarray alloc(fixed:fixed top) = 0(*) !* * * * * * * * * * * * * * * * * * ownrecord (qf) name buffer pool; ! =k'142472' owninteger no of buff = 0 #if k owninteger mon = 0; ! monitoring flag off #else owninteger mon = 1; ! monitoring flag (set to 'P') #fi owninteger data len = 120; ! cut down length for pss owninteger spec mon = 0 owninteger ftpi = 0; ! no of ftp packets owninteger ftpo = 0 #if r constinteger initial permit = 2 #if k constinteger header len = 0, header m len = 0 #else constinteger header len = 2, header m len = 2 #fi #else #if x constinteger initial permit = 2 constinteger header len = 0 #else constinteger initial permit = 1; ! = 2 for ring constinteger header len = 6, header m len = 10 #fi #fi ownstring (1) snil = "" ownstring (63) called, calling, qual ownstring (1) disqual ! l o g g i n g o n integer i conststring (7) array ostates(-1:closing) = "not all", "waiting", "ready", "asking", "timing", "abortng", "chcking", "conning", "going", "clserdy", "close" ownstring (15) ad1, ad2, ad3 !********************************************** !* initialisation * !********************************************** #if i use tt(t3 ser) #else change out zero = t3 ser #fi cycle i = con lim, -1, 2 con desa(i)_index = i; con desa(i)_o state = not alloc qfrig == con desa(i) qfrig_e == free des free des == qfrig repeat con desa(1)_index = 1 condesa(0)_stream = 6 con desa(1)_stream = 7 printstring(vsn) #if e printstring(" ERCC") #else printstring(" kent") #fi #if r printstring(" ring ") #else #if x printstring(" ts") #else printstring(" nsi") #fi #fi printstring(datestring) newline map hwr(0); ! map am1 to segment 3 i = map virt(buffer manager, 5, 4); ! map buff man stack to seg 4 i = map virt(buffer manager, 6, 5) d == con desa(0) d4 == d d5 == con desa(1) p_c = 6; ! param for 'here i am' to 2900(here i am, null) p_c = 7 to 2900(here i am, null) redo enable: #if ~x to gate(enable facility, null, 16) #else p_ser = gate ser; p_reply = own id p_fn = enable facility; p_a2 = 0; p_facility = "FTP" pon(p) #fi alarm(500); ! set clock for 10 secs !********************************************** !* main loop * !********************************************** cycle p_ser = 0; poff(p) if int = 'K' start data len = 100; ! so safefor gateway int = 0 finish if 'M' <= int <= 'P' start mon = int-'O'; int = 0 printstring("ok ") finish if int = '?' start cycle i = 2, 1, con lim d == con desa(i) if d_o state # not alloc start printstring("ftp:") who and state printstring("p ="); write(d_port, 1) printstring(", oc ="); write(d_nc, 1) printstring(", istate ="); write(d_istate, 1) printstring(", omode ="); write(d_mode, 1) printstring(", ifirst ="); write(d_first, 1) printstring(", operm ="); write(d_permit, 1) newline finish repeat int = 0 newline finish if int = 'C' start ; ! close output select output(1); ! select it close output printstring("done ") int = 0 finish if p_reply = link handler start from 2900 finish else if p_reply = gate ser start from gate finish else if p_reply = buffer manager start from buffer manager(p) finish else if p_reply = 0 start ; ! clock tick if int='R' then int = 0 and ->redo enable; ! horrible cycle i = con lim, -1, 0 d == con desa(i) if d_o state = timing then do connect repeat alarm(1000); ! 20 secs finish repeat !************************************************* !* routines to do the work * !************************************************* routine crunch integer i who and state; newline cycle i = 1, 1, 10 printstring("**** ftps failed - dump it *** ") repeat wait end routine to gate(integer fn, record (mef) name mes, c integer flag) if mon < 0 start select output(1); printstring("To gate:"); write(fn, 1) printstring(" on task port "); write(d_index, 1) printstring(", Gate Port"); write(d_port, 1) printstring(", Flag"); write(flag, 1); newline select output(0) finish if fn = put output start ; ! queue these as necessary if mon = -1 or spec mon # 0 start spec mon = 0 select output(1) printstring("io "); mon mes(mes) finish ftpo = ftpo+1 if addr(mes)&k'140000'=k'140000' or addr(mes)&k'77'#0 then crunch finish p_ser = gate ser; p_reply = own id #if ~x p_fn = fn; p_gate port = d_port; p_mes == mes; p_s1 = flag #else p_fn = fn; p_gate port = d_port; p_task port = d_index p_mes == mes; p_a2 = flag #fi pon(p) end routine to 2900(integer fn, record (m2900f) name m2900) p_ser = link handler; p_reply = own id p_fn = fn; p_mes == m2900 pon(p) end routine get buffer(integer reason) record (pe) p !******************************************************* !* hold a pool, so can call buffer here immedialtely* !* otherwise hold the activity until it arrives* !******************************************************* #if ~x if reason = get op block then p_c1 = 0 else p_c1 = 1 #else if reason = get op block then p_c1 = 0 else p_c1 = 1 #fi ! ****** watch the above line ******** #if ~x p_s1 = reason; p_gate port = d_index if buffer pool == null or p_c1 # 0 start ; ! have to ask for it #else p_c2 = reason; p_a2 = d_index if buffer pool == null or p_c1 # 0 start ; ! have to ask for it #fi p_ser = buffer manager; p_reply = own id p_fn = request buffer pon(p) else p_mes == buffer pool; buffer pool == p_mes_link p_mes_link == null no of buff = noof buff-1; from buffer manager(p) finish end routine free buffer(record (mef) name mes) record (pe) p if addr(mes)&k'140000'=k'140000' or addr(mes)&k'77'#0 then crunch if mes_type # 0 or no of buff > 3 start p_ser = buffer manager; p_reply = own id !! queue it if it is a long buffer p_fn = release buffer; p_mes == mes pon(p) else !! long buffer, so queue it mes_link == buffer pool; buffer pool == mes no of buff = no of buff+1 finish end !! routine tell write(d_index, 2); space if d_direction = 0 then printstring("ftp-Q") else c printstring("ftp-P") #if ~x write(d_term, 1) #else space; printstring(adda(d_index)) #fi space end routine who and state tell printsymbol('(') printstring(ostates(d_o state)) printstring(") ") end routine plant fail(integer type, record (mef) name mes) #if ~x #if n record (lev3f) name ssmessage ssmessage == mes_lev3 ssmessage_aa(0) = 1; ssmessage_aa(1) = type mes_len = header m len + 2 #else record (SSMESSAGEF) name ssmessage ssmessage == mes_lev3 ssmessage_a(0) = 1; ssmessage_a(1) = type mes_len = header m len+2-1; !$e #fi #else disqual = to string(type) #fi end #if ~x ! k integer fn stoi(string (*)name s) integer x,y,sum sum = 0 result = 0 if s = "" cycle x = 1, 1, length(s) sum = sum*10+(charno(s, x)-'0') repeat result = sum end #fi #if x string (127) fn unpack(record (mef) name mes, integer no) integer i, l unless mes == null or mes_len<=0 or no<=0 start l = 0 while no>1 cycle l=l+mes_params(l)+1 no = no-1 repeat result = string(addr(mes_params(l))) finish else result = "" end routine pack(record (mef) name mes, string (*) name s) string(addr(mes_params(mes_len))) = s mes_len = mes_len+length(s)+1 end #fi ! r o u t i n e f r o m g a t e routine from gate record (mef) name mes #if n!x record (lev3f) name ssmessage #else record (ssmessagef) name ssmessage #fi recordformat p3f(byteinteger ser,reply,fn,port,a,b,c,d) record (p3f) name p3 integer fn, flag, strm, i, trm, fac integer node #if ~x switch fns(incoming call:message reply) #else switch fns(connect:datagram) #fi fn = p_fn #if ~x strm = p_gate port d == con desa(porta(strm)) #else strm = p_task port d == con desa(strm) #fi #if m if mon < 0 start select output(1) printstring("From Gate, fn="); write(fn, 1) printstring(", G Port ="); write(p_gate port, 1) printstring(", T Port ="); write(p_task port, 1) printstring(", Flag ="); write(p_a2, 1) newline select output(0) finish #fi ->fns(fn) #if ~x fns(incoming call): #else fns(Connect): strm = p_gate port; ! remember gate port no #fi flag = 0; ! reject if all else fails !! There are two possible conditions, !! 1) The specific device has already send in a file. !! 2) the 2900 has to be asked to validate the device #if x disqual = "" mes == p_mes #fi if host state = down start plant fail('d', p_mes) -> reply finish #if ~x ssmessage == p_mes_lev3 #if e #if r node = ssmessage_sn; trm = ssmessage_st; ! nsi mod if node=0 then trm = p_c1; ! source is on ring #else; ! nsi node = p_mes_lev3_sn; trm = p_mes_lev3_st #fi #else node = 0; trm = p_c1; #fi #else calling = unpack(mes, 2) qual = unpack(mes, 3) #fi d == get free des if d == null then plant fail('f', p_mes) and -> reply ! No free descriptors #if n d_permit = p_c1; ! remember the for/rev buff lim (nsi mod) #fi #if n i = p_mes_lev3_luflag; ! pickup 'f' number d_secadd = i&x'7f'; ! nb: in the network, x'80' is not present #else #if ~x d_secadd = ssmessage_ds>>8; ! Fn portion of address is here #fi #fi !! construct a message to the 2900 ******* i = allocate stream(d); ! both streams d_direction = 0; ! 0 = incoming, 1 = outgoing #if ~x d_node = node; d_term = trm #else d_holdi == mes; ! retain the message adda(d_index) = calling #fi d_o state = connect 1; ! wait for confirmation d_nc = 0 if mon < 0 start #if ~x tell; printstring("asking ") #else write(d_index, 2); printstring("Call from:"); printstring(calling) printstring(", Called ="); printstring(unpack(mes, 1)) printstring(", qual:"); printstring(qual); newline #fi finish #if ~x d_port = p_gate port; ! remember gate port no porta(p_gate port) = d_index; ! backward mapping #else d_port = strm; ! remember gate port no #fi get buffer(do input connect) return ; ! Asking the 2900, so wait reply: #if x d_holdi == mes #fi do repm(flag) return #if ~x fns(input recd): #else fns(Input Here): #fi ftpi = ftpi+1 mes == p_mes if d_o state = not alloc start ; ! X-over (tighten up check ????) free buffer(mes) printstring("Ftps: Invalid Buffer from Gate, stream =") write(d_index, 1); newline finish if d_inp q_e == null and d_holdi == null start !! stream is waiting for a network buffer get buffer(low level ip transfer) if d_o state = enabld d_in = 0; ! into buffer pointer, and kick 2900 ! if the stream is able to go finish if mon = -1 start select output(1) printstring("In "); mon mes(mes) select output(0) finish push(d_inp q, mes); ! q buffer anyway d_nc = d_nc+1; ! count it return #if ~x fns(output transmitted): d_permit = d_permit+1 if d_permit = 1 and d_o state = enabld then c get buffer(get op block) #else fns(Enable Output): d_permit = d_permit + p_a2 if d_permit = p_a2 and d_o state = enabld thenc get buffer(get op block) #fi return #if ~x fns(call closed): fns(call aborted): ! all is lost #else fns(Disconnect): unless p_mes == null then free buffer(p_mes) #fi if d_o state = closing start if mon#0 start tell; printstring("close ack ") finish if host state = down then retrieve(d) and return to 2900(low level control, d_hold) d_o state = idle; d_hold == null else #if x if d_o state = trying start d_nc = d_nc+1; d_port = flag; ! remember reason d_o state = timing; ! try again soon return finish #fi who and state printstring("network abort ") #if x to gate(Disconnect, null, 1); !ack to gate #fi if d_o state = not alloc then return ; ! very nasty *************** if d_o state >= connected or d_o state = input ready c start get buffer(send abort); ! get 2900 to abort stream #if ~x to gate(abort call, null, 0); ! reply to gate to clear port #fi finish if d_o state = aborted or host state = down then c retrieve(d) else d_o state = idle finish return #if ~x fns(open call a): ! allocated port no d == con desa(p_gate port) !! p_gate port < 0 (ie failed!) #if n d_port = p_s1; ! note: nsi difference (and 2 lines below) #else p3 == p d_port = p3_a #fi if d_port = 0 then p_s1 = 125 else start porta(d_port) = p_gate port return finish !* d_port = 0 => no gate ports, so treat as a open call b !* with error flag = 125 fns(open call b): ! reply from remote device flag = p_s1; ! success/fail flag #else fns(Accept Call): #fi if d_o state # trying start tell; printstring("Invalid call reply ! ") return finish return if d == d4; ! not assigned #if x free buffer(p_mes) unless p_mes == null d_port = p_Gate Port #fi if d_o state = aborted or host state = down start !! connection established ! #if ~x if flag#0 then retrieve(d) else start to gate(abort call, null, 0) d_nc = 98 finish #else to gate(Disconnect, null, 1) d_nc = 98 #fi return finish #if ~x if flag # 0 start d_nc = d_nc+1; d_port = flag; ! remember reason d_o state = timing else #fi #if ~k if mon # 0 start tell; printstring("connected ") finish #else tell; printstring("connected to"); write(p_a2,2); newline #fi get buffer(connecting reply); ! get buffer to reply to spoolr get buffer(connecting reply 2); ! and for other stream d_permit = initial permit; ! nsi change d_o state = connected d_nc = 0 #if ~x finish #fi return #if ~x fns(message r): ! incoming login or enquiry fns(message reply): ! reply to sendmessage #else fns(reset): tell; printstring("Reset ! ") to gate(Disconnect, null, 1) d_o state = idle get buffer(send abort); ! and tell 2900 call gone return fns(*): #fi crunch end !! r o u t i n e from 2900 !! all messages from the 2900 come to this routine routine from 2900 record (m2900f) name m2900 record (m2900f) name m2900b integer stream, sub ident, state, mode, am1c, type, nsta integer p2a, p2b, ioflag switch link fns(interf addr:mainframe down) switch com state(disconnecting:enabled) switch com state b(disconnecting:enabled) m2900 == p_mes; m2900b == m2900 if p_fn = message start stream = m2900_stream; ! get first stream no finish else stream = p_c am1c = am1a(stream) if am1c = k'377' then d == null else c d == con desa(am1c) -> link fns(p_fn) link fns(interf addr): ! interface addr from eam5 l == record(addr(p_mes)&k'17777'); ! force to seg 0 return link fns(do output): ! -> 11/34 if stream = 7 then read message from am1 else c read from am1 return link fns(do input): ! -> 2900 if stream = 6 then write message to am1 else c write to am1 return link fns(mainframe down): link fns(mainframe up): host state = down clear all streams return link fns(message): sub ident = m2900_sub ident state = m2900b_b(1); mode = m2900b_b(0)&x'f0' ! mode = 0 - seq, 1 - circ, 2 - seq cont ! = x'10' - iso, x'20' - ebc, x'30' - bin ! = x'40' - normal FTP (data phase) ! = x'50' - default emas to emas FTP (data) ! = x'60' - Negitiation Phase FTP p2a = m2900_p2a; p2b = m2900_p2b m2900_p2a = 0; m2900_p2b = 0 if sub ident # 0 start ; ! low level !****************************************** !* l o w l e v e l control message !****************************************** ioflag = stream&1; ! ioflag = 1 => 2900 o/p if mon < 0 start select output(1) printstring("from 2900 "); who and state write(stream, 2) write(sub ident, 2); write(state, 2); write(mode, 2) newline select output(0) finish if stream <= 7 start if stream = 6 then d ==d4 else d == d5 ->com state b(state) finish if d == null start printstring("ftps: stream? ") -> control reply finish -> com state(state) com state(enabling): -> control reply if d_o state = idle d_o state = enabld if mon < 0 start tell; printstring(" enab") write(mode, 2) finish if ioflag # 0 start if mon < 0 then write(p2b, 1) and printstring(" o ") d_mode = mode; ! remember type (output only, istate on input) d_outlen = p2b; ! length of output trans (for monit) if d_permit > 0 start if d_hold == null start get buffer(get op block) else type = low level op transfer do trans and reply: to 2900(low level control, m2900) get buffer(type) return finish finish else if mode = x'40' then nsta = 10; ! normal Ftp data if mode = x'50' then nsta = 5; ! Default Emas-Emas if mode = x'60' then nsta = 0; ! Neg phase if d_icount = 0 start d_istate = nsta; ! accept new state if mon < 0 then newline else if mon < 0 then printstring(" (nsc) ") finish d_first = x'ff' unless d_holdi == null and d_inp q_e == null c then type = low level ip transfer and -> do trans and reply finish -> control reply com state(connecting): con sub id reply = m2900_sub ident; ! retain for reply if ioflag # 0 start ; ! output d_nc = 0 if d_direction # 0 start if mon # 0 then tell and printstring("out conn ") do connect finish else -> control reply else ; ! input d_icount = 0; ! always allow state change after conn if d_o state = connect 1 start p_gate port = d_port; ! for repm #if n do repm(d_permit); !ok - nsi mod #else do repm(1); ! ok #if k tell; printstring("connect accepted ") #fi #fi d_o state = connected d_permit = initial permit ->control reply finish finish free buffer(m2900); ! reply is made up later return com state(disconnecting): if aborted # d_o state # idle and ioflag # 0 start ! this must only be done on one stream !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! d_o state = closing d_hold == m2900 if mon # 0 then tell and printstring("Disconnecting call ") #if ~x to gate(abort call, null, 0); ! issue to gate #else to gate(Disconnect, null, 0) #fi return ; ! hold reply till later finish if mon # 0 and ioflag # 0 start who and state; printstring("Disconnect ignored ") finish -> control reply com state(aborting): if mon < 0 start tell; printstring("aborting ") finish ->suspd com state(suspending): flush file if ioflag # 0 suspd: d_o state = connected if d_o state # idle and ioflag = 0 ! susp on output does not stop input d_kill = state unless d_kill = aborting; !remember type of call ! stop transfers unless its idle anyway control reply: to 2900(low level control, m2900) return !! *********************************************** !! the following are all stream 6 & 7 manipulations !! ************************************************ com state b(enabling): d_o state = enabling d_mode = p2b; ! bUFFER SIZE host state = up -> junk m com state b(connecting): d_o state = connected d_n = 0; d_nc = 0; d_count = 0; d_mode = 0; d_cpos = 0 printstring("ftp: logon stream"); write(stream, 1) printstring(" connected ") -> junk m com stateb(aborting): com stateb(suspending): com stateb(disconnecting): d_o state = idle host state = down clear all streams junk m: tidy buffers -> control reply finish !! high level control message d == d5 free buffer(m2900) get buffer(get op block) if d_nc = d_count; ! dont do twice d_nc = p2b; ! update pointer end #if x routine do connect #if ~k printstring("Connect called ! ") #fi get buffer(get connect buffer) end routine do actual connect(record (mef) name mes) record (pe) p ownstring (11) ef = "EMAS - ftp" #if k called=adda(d_index) calling=snil #else qual = adda(d_index) called = string(addr(qual)+1) calling = string(addr(qual)+length(called)+2) #fi if mon # 0 start printstring("Connect to:"); printstring(called) printstring(", from:"); printstring(calling) newline finish mes_len = 0 pack(mes, called) pack(mes, calling) pack(mes, snil) pack(mes, ef) d_port = 0; ! ensure it goes out on port 0 to Gate(Connect, mes, 0) d_o state = trying end #else routine do connect #if n recordformat p3f(byteinteger ser, reply, c fn, port, (byteinteger facility, flag or c record (mef) name mes), byteinteger node, term) #else recordformat p3f(byteinteger ser, reply, c fn, port, (byteinteger node, flag or c record (mef) name mes), byteinteger term, facility) #fi record (p3f) p3 ! note on se of 'flag' ! flag < 128 - standard NSI use - not used on ring ! flag > 128 - 128+F number - put in 'user flags' used as ! address extension for psse p3_ser = gate ser; p3_reply = own id #if ~x p3_fn = open call; p3_port = d_index p3_term = d_term p3_facility = 16 p3_node = d_node; !overwritten by k&r option below #fi #if r #if e if d_secadd # 0 then p3_flag = x'80'!d_secadd #else p3_facility=255; !16 bit facility number p3_flag=d_secadd; p3_node=16; !big facility no. #fi #else p3_flag = x'80'!d_secadd #fi d_o state = trying pon(p3) end #fi record (con des f) map get free des qfrig == free des if qfrig == null start printstring("ftps: out of descriptors! **** ") result == null finish free des == qfrig_e qfrig_e == null result == qfrig end routine flush file integer len record (mef) name mes ! This pushes out the last block when 2900 sends suspend mes == d_hold unless mes == null start d_hold == null len = d_n if d_mode=x'50' and d_n = d_cpos+1 then len = len-1 ! 1 dummy length byte present #if k & x if len<=0 then len=0; #else if len <= 0 then free buffer(mes) else start #fi #if n mes_lev3_suflag = 1 #else #if e&(~x) mes_lev3_uflag = x'0100' #fi #fi mes_len = len+header len; d_n = 0 d_permit = d_permit-1; ! for mode changing #if k & x to gate(put output, mes, 0) #else to gate(put output, mes, 0) #fi #if ~( k & x) finish #fi #if k & x else ! get buffer(send push); !send push (null data) #fi finish end routine kick 2900 message(record (maf) name log) !! this routine sends 'log' to the 2900 by inserting !! it in the input q for stream 4, and kicking it if !! necessary d == d4 if (d_hold == null and d_inp q_e == null) or d_cpos>5 then c get buffer(do output) push(d_inp q, log) d_cpos = d_cpos+1 end !! r o u t i n e from buffer manager !! all requests for buffers come back through here routine from buffer manager(record (pe) name p) integer reason, type, strm record (m2900f) name m2900 record (maf) name log integer lc1, lc2 #if ~x reason = p_s1; ! get reason for calling strm = p_gate port #else reason = p_c2; ! get reason for calling strm = p_a2 #fi d == con desa(strm); ! and map to descriptor if mon < 0 start select output(1) printstring("from bm: reason, index") write(reason, 2); write(strm, 2); newline select output(0) finish if reason = get op block start d_hold == p_mes; d_n = 0 get buffer(low level op transfer) return finish if reason = do input connect start log == p_mes #if x log_type = 4; ! new type for packed strings #else log_type = 1 #fi log_in ident = swab(d_stream) log_out ident = swab(d_stream+1) log_ref = 0 #if ~x log_address = "N" log_address = log_address.itos(d_node, -1) log_address = log_address."T" log_address = log_address.itos(d_term, -1) if d_secadd # 0 start log_address = log_address.".F" log_address = log_address.itos(d_secadd, -1) finish #else called = unpack(d_holdi, 1) calling = unpack(d_holdi, 2) lc1 = length(called); lc2 = length(calling) ! temp frig as butler is letting '.' thru on end of string if charno(calling, lc2) = '.' then lc2=lc2-1 ! end if lc1+lc2 > 59 start printstring("Incoming length too long - truncated ! ") printstring(calling); newline length(calling) = 0 finish string(addr(log_address)+1) = called string(addr(log_address)+lc1+2) = calling length(log_address) = lc1+lc2+2 #fi #if m printstring("Incoming call from:"); printstring(log_address) newline #fi log_len = 5+2+1+length(log_address) kick 2900 message(log) return finish #if x if reason = get connect buffer start do actual connect(p_mes) return finish #if k if reason = send push start p_mes_len=0 d_permit = d_permit - 1 to gate(put output, p_mes, 0); !push null data return finish #fi #fi !! message to 2900 reason !! note: streams 6&7 also use this mechanism m2900 == p_mes m2900_stream = d_stream m2900_sub ident = 10; m2900_p2a = 0; m2900_p2b = 0 type = low level control if reason = low level op transfer and d_stream > 7 then c m2900_stream = m2900_stream+1 if reason = send abort start m2900_sub ident = 0 m2900_p3a = 0 m2900_p3b = 1 type = send data finish if connecting reply <= reason <= connecting reply 2 failed start m2900_sub ident = con sub id reply if reason >= connecting reply failed then c m2900_p2b = x'0a00'; ! = swab(10) if reason&1 = 0 then m2900_stream = m2900_stream+1 if reason = connecting reply 2 failed then retrieve(d) finish if mon < 0 start select output(1) printstring("to 2900, str, subid, p2b:") write(m2900_stream, 1); write(m2900_sub ident, 1) write(m2900_p2b, 1); newline select output(0) finish to 2900(type, m2900) end integerfn allocate stream(record (con desf) name d) !! nb: allocates two streams, one odd and the other even integer i cycle i = fixed, 2, fixed top-2 if alloc(i) = 0 start alloc(i) = d_index d_stream = i p_c = i; ! claim the stream to 2900(here i am, null) am1a(i) = d_index p_c = i+1 to 2900(here i am, null) am1a(i+1) = d_index result = i finish repeat result = 0 end routine tidy buffers free buffer(pop(d_inp q)) while not d_inp q_e == null free buffer(d_hold) unless d_hold == null d_hold == null free buffer(d_holdi) unless d_holdi == null d_holdi == null end routine retrieve(record (con desf) name d) !! sever link between 2900 and descriptor and !! free the descriptor if d_stream <= 7 start ; ! illegae crunch finish am1a(d_stream) = k'377'; ! mark unused am1a(d_stream+1) = k'377' tidy buffers d_o state = not alloc; d_term = -1 alloc(d_stream) = 0; alloc(d_stream+1) = 0 qfrig == d qfrig_e == free des free des == qfrig end routine do repm(integer flag) !! sends a 'call reply' to gate, nb: assumes p_gate port = port number #if x record (mef) name mes integer fn #fi p_ser = gate ser; p_reply = own id #if ~x p_fn = call reply; p_s1 = flag #else if flag = 0 then fn = Disconnect else fn = Accept Call p_fn = fn; p_a2 = 0 p_task port = d_index mes == d_holdi; d_holdi == null qual = unpack(mes,3) mes_len = 0 pack(mes, snil) pack(mes, qual) pack(mes, snil) p_mes == mes #if m if mon < 0 start select output(1) printstring("Call reply:"); if flag = 0 then printstring c ("Failed") else printstring("Ok") write(p_task port, 1); write(p_gate port, 1); newline select output(0) finish #fi #fi pon(p) end routine clear all streams !! used when emas goes down integer i switch sts(not alloc:closing) cycle i = 2, 1, con lim d == con desa(i) if mon < 0 and d_o state # not alloc start who and state; newline finish ->sts(d_o state) sts(close ready): sts(connect 1): p_gate port = d_port do repm(0); ! reply 'reject' to connect sts(idle): sts(op ready): sts(timing): retrieve(d) continue sts(connected): sts(enabld): #if ~x to gate(abort call, null, 0) #else to gate(Disconnect, null, 1) #fi d_o state = aborted continue sts(trying): d_o state = aborted continue sts(aborted): sts(closing): ! must wait for network sts(not alloc): repeat host state = down end routine read from am1 record (am1f) name l2 integer max ad, adr, adr2 record (mef) name mes record (lev3f) name lev3 #if i label cyc, parity, commbt, xopdwn, exit2, y1, y3 constinteger r0=0,r1=1,r2=2,r3=3, xopl = k'20', acfy = k'10' #fi integer n, cpos, t, max2 if d == null then mes == null else c mes == d_hold if mes == null start printstring("ftp: seq1! ") t = 0!128; -> skip2 finish lev3 == mes_lev3 !! (cater for partial block rec'd) if d_n # 0 start n = d_n; cpos = d_cpos else n = 0 n = n+1 if d_mode = x'50'; ! default mode cpos = 0 finish if mon = -1 start select output(1) printstring("read from, n cpos:"); write(n, 1); write(cpos, 1) newline; select output(0) finish !! next section is in assembler in a file 'ercc14.ftpassm' ! acfy =10 ! xopl =20 l2 == l adr2 = addr(lev3_a(0)); !$e lev3_a(0) max ad = adr2+data len; max2 = max ad rep cycle: adr = adr2+n; ! lev3_a(n) if d_mode = x'50' then max ad = adr2+n+63 if max ad > max2 then max ad = max2; ! mode 50 really ! #if i *mov_adr,r1 *mov_l2,r3 cyc: *mov_@r3,r2; ! r2 = status *bit_#k'220',r2; ! ready or xopl set? *beq_cyc; ! no, so wait *bit_#xopl,r2; ! was it xop? *bne_xopdwn; ! it was set, so get out *mov_2(r3),r0; ! pick up char *bit_#acfy,@r3; ! did it fail to read? *beq_y1; ! no, so carry on *mov_2(r3),r0; ! read it again *bit_#acfy,@r3; ! failed again? *bne_parity; ! hard failure, so get out y1: *asr_r2; ! get comm bit (9th bit) *bcs_commbt; ! set, so exit *movb_r0,(r1)+; ! store char in array y3: *cmp_r1,maxad; ! at end of array? *bhis_exit2; ! yes, so get out *bis_#2,(r3); ! accept the last char *br_cyc; ! go for the next one exit2: *mov_r1,adr -> exit parity: *mov_r1,adr t = 3; -> skip commbt: *mov_r1,adr t = 2!128; -> skip xopdwn: *mov_r1,adr t = 64 #else *=k'016401';*=k'10'; ! mov 10(r4),r1 ! r1 == nss_a(n) *=k'016403';*=k'4'; ! mov 4(r4),r3 ! l2 = -4(r5) *=k'011302' ; ! cycle: mov (r3),r2 ! stat=r2 *=k'032702';*=k'000220'; ! bit #200+xopl,r2 *=k'001774' ; ! beq cycle ! nothing set, so wait *=k'032702';*=k'000020'; ! bit #xopl,r2 ! xopl set? *=k'001034' ; ! bne xopdwn ! yes, so fail it ! *=k'016300';*=k'000002'; ! mov 2(r3),r0 ! sym=r0 *=k'032713';*=k'000010'; ! bit #acfy,@r3 ! failed to read? *=k'001405' ; ! beq y1 ! no, so carry on *=k'016300';*=k'000002'; ! mov 2(r3),r0 ! read it again *=k'032713';*=k'000010'; ! bit #acfy,@r3 ! failed again? *=k'001014' ; ! bne parity ! yes, so fails ! y1: *=k'006202' ; ! asr r2 ! get comm bit *=k'103415' ; ! bcs commbt ! comm bit seen *=k'110021' ; ! movb r0,(r1)+ ! nss_a(n) = sym! n=n+1 *=k'020164';*=k'6'; ! y3: cmp r1,6(r4) ! end of cuurent record *=k'103003' ; ! bhis exit ! yes, so exit *=k'052713';*=k'000002'; ! bis #2,(r3) ! accept char *=k'000746' ; ! br cycle ! ! exit: ! etc *=k'010164';*=k'10'; ! mov r1,10(r4) ! restore 'adr' -> exit ! parity: s1: *=k'010164';*=k'10'; ! mov r1,10(r4) l1: ->parity ! commbt: s2: *=k'010164';*=k'10'; ! mov r1,10(r4) l3: ->comm bit ! xopdwn: xopdwn: t = 64; -> skip; ! send unsuccessfull parity: t = 3; -> skip comm bit: t = 2!128 #fi skip: n = adr-adr2; ! recomput n if d_mode=x'50' start lev3_a(cpos) = (n-cpos-1)!128 d_cpos = n; ! start new record here d_n = n+1; ! leave one byte for length of next finish else d_n = n skip2: p_c1 = t; ! long block+accept last to 2900(return control, null) return exit: n = adr-adr2; ! recompute n if mon = -1 start select output(1); printstring("in data: n, cpos:") write(n, 1); write(cpos, 1); newline select output(0) finish if d_mode = x'50' start lev3_a(cpos) = (n-cpos-1)!128 finish if n < data len-5 start cpos = n; n = n+1 if d_mode = x'50' l_rxs = l_rxs!accept char; ! accept the last char -> rep cycle finish d_hold == null p_c1 = 0!128; ! done+accept last to 2900(return control, null) d_n = 0 #if n lev3_suflag = 1; ! allways binary mode - nsi mod #else #if e&(~x) lev3_uflag = x'0100' #fi #fi mes_len = n+header len; !$e if n < 3 and d_outlen < 10 start printstring("ftps: output inconsistency! Outlen =") write(d_outlen, 1); printstring("Block =") mon mes(mes) finish to gate(put output, mes, 0) d_nc = d_nc+1 d_permit = d_permit-1 if d_permit > 0 then get buffer(get op block) end routine write to am1 record (mef) name mes record (lev3f) name lev3 integer n, end, gate reply, am1 reply, stat, sym switch data state(0:13) am1 reply = 0; ! "normal" reply while d_o state = enabld cycle mes == d_holdi if mes == null then mes == pop(d_inp q) if mes == null then exit !! terminate with "normal" (shouldnt happen) lev3 == mes_lev3 end = mes_len-header len; !$e gate reply = enable input; ! allow next to gate n = d_in; ! start of block - d_in = 0 cycle cycle stat = l_rxs if stat&xopl#0 start am1 reply = 64 d_holdi == mes; ! retain for retry d_in = n; ! and the pointer -> am1 rep finish if stat&ready # 0 start !! l i m i t sent am1 reply = 2; ! long block d_in = n d_holdi == mes; ! retain for later -> am1 rep finish if l_txs&ready # 0 then exit repeat skip: if n >= end start !! send go ahead #if ~x gate rep: to gate(gate reply, null, 0); ! enable input or close call #else gate rep: to gate(Gate reply, null, 1); ! one buffer ack #fi free buffer(mes) d_holdi == null; d_in = 0 if d_inp q_e == null then ->am1 rep exit finish sym = lev3_a(n); n = n+1 if mon = -1 start ; ! int = 'N' select output(1) printstring("di:"); write(d_istate, 1) write(n, 1) write(d_icount, 1); write(sym, 3) space and printsymbol(sym) if sym > 32 newline; select output(0) finish ->data state(d_istate) data state(0): ! beginning of record (neg phase) d_icount = sym&63 if sym&128 # 0 then d_istate = 2; ! ie 3 - get 1stchar d_istate = d_istate+1 if d_icount = 0 start if d_istate = 3 then -> kick d_istate = 0 finish -> send it data state(1): ! 1st char of sub/record (neg phase) data state(3): ! 1st char of last record/sub record d_first = sym if d_first = x'ff' d_istate = d_istate+1 -> ds4 if d_istate = 4 data state(2): ! chars in block (neg phase) d_icount = d_icount-1 if d_icount = 0 start d_istate = 0 finish if d_icount < 0 start printstring("ftps: phase error ") -> had it; ! temp expedient finish -> send it data state(4): ! chars in block (last block) ds4: d_icount = d_icount-1 if d_icount = 0 start kick: d_o state = connected; ! no more i/p until a new enable if mon < 0 start select output(1); tell; printstring("kick ") select output(0) finish d_istate = 0 am1 reply = 4; ! kick 2900 l_txd = sym; ! pass to 2900 if n >= end then ->gate rep; ! block fin, reply to gate d_in = n d_holdi == mes; ! retain the block & pointer -> am1 rep; ! tell the 2900 finish -> send it ! * * * Now the states for the Defaut Emas-Emas data transfer data state(5): ! record/sub record count (default phase) if sym = 128 start ; ! horrible frig for dec-10 (0 len) sym = nl; ! implant a nl -> send it; ! expect a record headernext finish d_icount = sym&63 if d_icount = 0 start ; ! transfer command d_istate = 7 finish else d_istate = d_istate+1 -> skip; ! record count is not part of the data data state(6): ! subsequent data chars (default phase) d_icount = d_icount-1 if d_icount = 0 then d_istate = 5 -> send it data state(7): ! 1st char of transfer comm (default phase) if sym = es or sym = qr or sym = er then c d_istate = d_istate+2 and -> send it if sym # ss and sym # cs start ; ! illegal - halt for now printstring("ftps:illegal tcc =") write(sym, 1); newline had it: printstring("ptr ="); write(n, 1); printstring(" block = ") mon mes(mes) -> kick finish d_istate = d_istate+1; ! rubbish - so junk the last byte -> skip data state(8): ! skip mode of transfer command d_istate = 5 -> skip data state(9): ! end of transfer (default phase) -> kick; ! nb: state -> 0 as expect disconnect next ! * * * Now the states for the non-default, full Ftp Data transfer * * * data state(10): ! 1st char - length of record/sub/tcc if sym = 0 start ; ! TCC d_istate = 12; ! get the next 2 chars f tcc -> send it; ! send the first thru finish d_icount = sym&63; ! pickup record length if d_icount # 0 start ; ! zero-length record is valid if sym&64 # 0 start ; ! compression d_icount = 1; ! only one to go finish d_istate = d_istate+1; ! go to 'into block' state finish -> send it data state(11): ! inside record/sub record d_icount = d_icount-1; ! count it down if d_icount = 0 then d_istate = 10; ! eor, to length next if d_icount < 0 then printstring("FTPS:Non-default Phase error ") and -> kick ! on error, give up by kicking 2900 -> send it data state(12): ! 2nd byte of tcc d_istate = d_istate+1; ! pickup 3rd byte -> send it data state(13): ! 3rd and last byte of tcc -> kick; ! tell 2900 send it: l_txd = sym repeat repeat am1 rep: p_c1 = am1 reply to 2900(return control, null) end !! r e a d m e s s a g e f r o m a m 1 routine read message from am1 record (maf) name m integer n, sym, t, stat, x integer type, strm switch swd(not alloc:closing) switch hlm(1:5) d == d5; ! messages on stream 7 m == d_hold if m == null start printstring("ftp: seq2! ") stat = l_rxs t = 0!128; -> reply finish !! (cater for partial block rec'd) n = d_n if n = 0 then d_cpos = 0 cycle cycle stat = l_rxs exit if stat&(ready!xopl) # 0 repeat if stat&xopl # 0 start ; ! xop gone down t = 64; ! send unsuccessfull printstring("ftps: xop d ") -> skip finish sym = l_rxd; ! read the char if l_rxs&acfy # 0 start ; ! failed to read sym = l_rxd; ! read it again if l_rxs&acfy # 0 start ; ! hard failure - parity t = 3 printstring("ftps: parity ") -> skip finish finish if stat&comm bit # 0 start t = 2!128 skip: d_n = n reply: p_c1 = t; ! long block+accept last to 2900(return control, null) return finish if d_count = d_mode then d_count = -1 if d_count = d_nc then -> badm d_count = d_count+1 m_a(n) = sym; n = n+1 if n = 1 start ; ! Got the total length d_cpos = m_a(0)+1; ! max = 256 - length is like string unless 5 < d_cpos <= 256-18 start badm: printstring("***ftps: message fails -") write(d_cpos, 1); write(d_count, 1); write(d_mode, 1) write(d_nc, 1); write(type, 1) printstring(" all ftp messages lost ") -> reply finish else if n = d_cpos then -> exit3; ! Got the whole message finish l_rxs = l_rxs!accept char; ! accept the last char repeat exit3: d_hold == null t = 0!128; ! normal+accept last if d_count # d_nc start ; ! Another message waiting get buffer(get op block) finish type = m_type; ! max = 256 unless 1 <= type <= 5 then ->badm -> hlm(type) hlm(2): ! Allocate stream - reply n = swab(m_in ident); ! this is known to ftp allready d == con desa(alloc(n)) -> free it if d == d4; ! null ! if m_ref = 0 start if mon < 0 then c tell and printstring("refused ") p_gate port = d_port; do repm(0) retrieve(d) else d_ref = m_ref; ! remember spoolers ref no finish free it: free buffer(m); -> reply hlm(1): ! allocate new (output) pair hlm(4): ! new packed string number ! set d_direction = 1 %if an outgoing connection to be made ?? d == get free des if d == null start ; ! failed ! flag it ???? else i = allocate stream(d); ! get both streams d_o state = idle #if ~x if m_address -> ("N").ad1 and ad1 -> ad1.("T").ad2 start if ad2 -> ad2.(".F").ad3 then d_secadd = stoi(ad3) c else d_secadd = 0 d_node = stoi(ad1); d_term = stoi(ad2) if mon # 0 start printstring("ftps:address N"); write(d_node, 1) printstring(" T"); write(d_term, 1) if d_secadd # 0 start printstring(" F"); write(d_secadd, 1) finish newline finish else printstring("ftps:address ? "); printstring(m_address) newline finish #else if length(m_address) > 63 start printstring("FTP: Outgoing address overflow, address TRUNCATED:") printstring(m_address); newline length(m_address) = 63 finish #if k !special kent code to use addresses of the form N0Txx the F number if present !is converted to the full facility code (F*256 + 16) if m_address -> ad1.(".F").ad2 start n=stoi(ad2) << 8 + 16 m_address=ad1 else n=16 finish adda(d_index) = m_address.".F".itos(n, -1) #else adda(d_index) = m_address #fi #fi m_in ident = swab(d_stream) m_out ident = swab(d_stream+1) d_direction = 1 d_ref = m_ref finish -> move it hlm(3): ! spoolr requests deallocation strm = swab(m_in ident) d == con desa(alloc(strm)) if d == d4 start printstring("ftps:Spoolr deallocate on an idle strm, =") write(strm, 1); newline -> move it; ! ignore finish if mon # 0 start who and state printstring(" deallocated ") finish -> swd(d_o state) swd(not alloc): crunch swd(idle): ! ok, so do it retrieve(d) -> move it swd(op ready): swd(timing): ! its trying to connect get buffer(connecting reply failed) get buffer(connecting reply 2 failed) ! retrieve the descriptor AFTER the connect reply sent -> move it swd(trying): ! connect outstanding d_o state = aborted d_nc = 99 -> move it swd(aborted): crunch swd(connect 1): p_gate port = d_port do repm(0) retrieve(d); ! and get the descriptor back -> move it swd(connected): swd(enabld): swd(closing): ! send failed ( x over ) who and state; printstring(" Deallocate error 6 ") m_out ident = 999 move it: kick 2900 message(m) -> reply end !! w r i t e m e s s a g e t o a m 1 routine write message to am1 record (maf) name m integer n, max, am1 reply, stat d == d4; ! messages on stream 4 am1 reply = 4; ! "condition y" cycle m == d_hold if m == null then m == pop(d_inp q) and d_cpos = d_cpos-1 if m == null then exit !! terminate with "normal" (shouldnt happen) n = d_n; ! start of block - d_n = 0 cycle cycle stat = l_rxs if stat&xopl#0 start d_hold == m; ! retain buffer for retry am1 reply = 64; d_kill = n; ->am1 rep finish if stat&ready # 0 start !! l i m i t sent am1 reply = 2; ! long block d_n = n; d_count = max d_hold == m; ! retain for later -> am1 rep finish if l_txs&ready # 0 then exit repeat if n > m_a(0) start free buffer(m) d_hold == null; d_n = 0; d_kill = 0 if d_inp q_e == null then ->am1 rep exit finish l_txd = m_a(n); n=n+1 repeat repeat am1 rep: p_c1 = am1 reply to 2900(return control, null) end routine mon mes(record (mef) name mes) integer i, j, k, n record (lev3f) name lev3 k = mes_len; lev3 == mes_lev3 write(k, 1); printstring(": ") j = 0 cycle i = 0, 1, k-1 write(lev3_a(i), 1) j = j+1; if j = 20 then j = 0 and newline repeat newline; select output(0) end endofprogram