PACKET net manager DEFINES stop,net manager,frei, routen aufbauen, (* 175 net manager 8 (!) *) start, definiere netz, aktiviere netz, list option, erlaube, sperre, starte kanal, routen: TEXT VAR stand := "Netzsoftware vom 10.06.87 "; (*Heinrichs *) LET maxstat = 127, ack = 0, (* nak = 1, *) error nak = 2, (* zeichen eingang = 4, *) list code = 15, (* fetch code = 11, *) freigabecode = 29, tabellencode = 500, continue code = 100, erase code = 14, report code = 99, abgleichcode = 98, neue routen code = 97, dr verwaltungslaenge = 8, (* Codes der Verbindungsebene *) task id code = 6, name code = 7, task info code = 8, routen liefern code = 9, (* Weitergabecodes für Netzknoten *) route code = 1001, out code = 1003, (* Typen von Kommunikationsströmen *) zustellung = 1, call im wait = 3, call im abbruch = 4, call in zustellung = 5; LET STEUER = STRUCT ( INT head, zwischenziel, zielrechner, quellrechner, strom, INT sequenz, seiten nummer, TASK quelle,ziel, INT sende code); LET INFO = STRUCT (STEUER steuer, INT typ,maxseq); LET PARA = STRUCT (TASK quelle, ziel, INT sendecode, zielstation); TASK VAR sohn; INT VAR strom,c,kanalmode, rzaehler := 20; BOUND STRUCT (ROW maxstat INT port, ROW maxstat INT zwischen) VAR route; TASK PROC netport (INT CONST ziel): INT VAR kan := route.port (ziel) AND 255; IF kan < 1 OR kan > 15 THEN niltask ELSE IF NOT exists (nettask (kan)) THEN access catalogue; nettask (kan) := task (kan); IF NOT (nettask (kan) < father) THEN nettask (kan) := niltask FI; FI; nettask (kan) FI END PROC netport; PROC frei (INT CONST stat,lvl): DATASPACE VAR ds := nilspace; BOUND STRUCT (INT x,y) VAR msg := ds; msg.x := stat; msg.y := lvl; INT VAR return; call (netport (stat), freigabecode, ds, return) ; forget (ds) END PROC frei; PROC net manager (DATASPACE VAR ds, INT CONST order, phase, TASK CONST ordertask): IF order = report code AND ordertask < myself THEN IF storage (old("report")) > 20 THEN forget ("report", quiet) FI; FILE VAR rp := sequential file (output, "report"); BOUND TEXT VAR rpt := ds; putline (rp, rpt); send (ordertask, ack, ds) ELIF order = abgleichcode AND ordertask < myself THEN BOUND STRUCT (INT ende, zwischen) VAR x := ds; route.port (x.ende) := channel (ordertask); route.zwischen (x.ende) := x.zwischen; send (ordertask, ack, ds) ELIF order = neue routen code AND ordertask < myself THEN forget ("port intern"); copy (ds,"port intern"); route := old ("port intern"); send (ordertask, ack, ds) ELIF station (ordertask) = station (myself) THEN IF ordertask < myself OR order = list code OR order > continue code THEN IF order = list code THEN enable stop; forget (ds); ds := old ("report"); FILE VAR ff := sequential file (output,ds); putline (ff,"bekannte Stationen:"); stationen; line (ff); putline (ff,"--------"); putline (ff,"Eingestellte Netzmodi:"); kanaele ; paketgroessen; line (ff); putline (ff,"********"); putline (ff,stand); putline (ff,"Rechner "+text(station(myself))+" um "+time of day); send (ordertask, ack, ds) ELSE free manager (ds,order,phase,order task) FI ELSE errorstop ("nur 'list' ist erlaubt") FI FI . stationen: INT VAR stat; INT VAR mystation := station (myself); FOR stat FROM 1 UPTO maxstat REP IF route.port (stat) > 0 AND stat <> mystation THEN put (ff,text(stat)+"("+text (route.port (stat) AND 255)+","+ text(route.zwischen(stat))+")") FI PER. paketgroessen: line(ff); put (ff, "Nutzlaenge bei indirekter Verbindung "+ text (data length via node) + " Byte "); line (ff). kanaele: INT VAR portnummer; TASK VAR tsk; FOR portnummer FROM 1 UPTO 15 REP tsk := task (portnummer); IF tsk < myself THEN beschreibe kanal FI; PER. beschreibe kanal: putline (ff, name (tsk) + " haengt an Kanal " + text (channel (tsk)) + ", " + mode text (netz mode (portnummer))). END PROC net manager; TASK VAR cd,stask; ROW maxstat INT VAR erlaubt; PROC communicate: enable stop; INT VAR scode, merken :=0; DATASPACE VAR dr := nilspace; neuer start (quit max, kanalmode); REP forget (dr); telegrammfreigabe; wait (dr, scode, stask); cd := collected destination; IF weiterleitung steht noch aus THEN send (netport (merken), out code, mds, reply); IF reply <> -2 THEN forget (mds); merken := 0 FI FI; IF zeichen da OR zeit abgelaufen THEN packet ELIF cd = myself THEN netz info und steuerung ELSE sendung untersuchen (stask, cd, scode, dr) FI PER. telegrammfreigabe: INT VAR dummy; control (22,0,0,dummy). zeichen da: scode < 0 . zeit abgelaufen: scode = ack AND cd = myself. packet: INT VAR snr, ant,err; TASK VAR quelle, ziel; snr := 0; IF NOT zeichen da THEN routen erneuern FI; REP IF NOT zeichen da THEN forget (dr); zeitueberwachung (snr, quelle, ziel, ant, dr); ELIF NOT weiterleitung steht noch aus THEN packet eingang (snr, quelle, ziel, ant, dr); FI; IF snr = 1000 THEN packet weiterleiten ELIF snr > 0 THEN IF ant > 6 AND erlaubt(station (quelle)) < 0 THEN unerlaubt ELSE send (quelle,ziel,ant,dr,err); fehlerbehandlung ; FI FI UNTIL snr = 0 OR zeichen da PER. routen erneuern: rzaehler DECR 1; IF rzaehler = 0 THEN rzaehler := 20; neue routen holen FI. weiterleitung steht noch aus: merken <> 0. packet weiterleiten: INT VAR reply; IF NOT ((route.port (ant) AND 255) = channel OR route.port (ant) < 0) THEN send (netport (ant), out code, dr, reply); IF reply = -2 THEN merken := ant; DATASPACE VAR mds := dr FI ELSE report ("Weiterleitung nicht möglich für "+text(ant)) FI. fehlerbehandlung: IF ok oder ziel nicht da THEN loesche verbindung (snr) FI. ok oder ziel nicht da: err=0 OR err=-1. netz info und steuerung: IF scode = list code THEN list status ELIF scode = erase code THEN strom beenden ELIF scode = freigabe code AND stask = father THEN freigabelevel ELIF scode >= route code THEN weitergaben ELIF scode > tabellencode THEN routen ausliefern ELSE forget (dr); ablehnen ("nicht möglich") FI. weitergaben: IF stask < father THEN IF scode = out code THEN BOUND INT VAR stx lng := dr; INT VAR decoded lng := stx lng; decode packet length (decoded lng); transmit header (dr); blockout (dr,1,drverwaltungslaenge,decoded lng); transmit trailer ELIF scode = route code THEN BOUND PARA VAR parah := dr; PARA VAR para := parah; pingpong (stask, ack, dr, reply); neue sendung (para.quelle, para.ziel, para.sendecode, para.zielstation, dr); forget (dr); dr := nilspace; send (stask, ack, dr) FI ELSE forget (dr); ablehnen ("nicht Sohn von "+name(father)) FI. routen ausliefern: neue sendung (stask, myself, -routen liefern code, scode-tabellencode,dr). freigabelevel: BOUND STRUCT (INT stat,lvl) VAR lv := dr; IF lv.stat > 0 AND lv.stat <= maxstat THEN erlaubt (lv.stat) := lv.lvl FI; send (stask,ack,dr). unerlaubt: report ("Fremdzugriff von "+text(station (quelle))+" auf "+nam(ziel) +" code "+text(ant)); loesche verbindung (snr); forget (dr); dr := nilspace; BOUND TEXT VAR errtxt := dr; errtxt:="Kein Zugriff auf Station "+text (station (myself)); neue sendung (ziel, quelle, error nak, station (quelle), dr). strom beenden: BOUND TEXT VAR stromtext := dr; INT VAR erase strom := int (stromtext); forget (dr); strom := erase strom; IF falsche stromnummer THEN ablehnen ("Strom gibt es nicht") ELSE BOUND INFO VAR v := verbindung (strom); IF stask < supervisor OR stask = vx.quelle OR stask = vx.ziel THEN loeschen ELSE ablehnen ("Nur Empfänger/Absender darf löschen") FI FI. loeschen: IF sendeeintrag THEN IF callee (vx.quelle) = vx.ziel THEN absender warnen FI; loesche verbindung (strom) ELSE IF callee (vx.ziel) = vx.quelle THEN warnen FI; loesche verbindung (strom) FI; dr := nilspace; send (stask,ack,dr). absender warnen: dr := nilspace; send(vx.ziel,vx.quelle,1,dr,err) . warnen: dr := nilspace; errtxt := dr; errtxt:= "Station antwortet nicht"; send (vx.quelle,vx.ziel,error nak, dr, err). falsche stromnummer: strom < 1 OR strom > max verbindungsnummer. sendeeintrag: vx.quellrechner = station (myself). vx: v.steuer. END PROC communicate; PROC list option: begin ("net list",PROC list net, sohn) END PROC list option; PROC list net: disable stop; DATASPACE VAR ds ; INT VAR scode; REP wait (ds, scode, stask); forget (ds); ds := nilspace; FILE VAR f := sequential file (output, ds); list (f, father); list netports; IF is error THEN clear error; forget(ds); ds := nilspace; f := sequential file (output, ds); output (f); putline (f,errormessage); clear error FI; send (stask, ack, ds) PER. list netports: INT VAR k; FOR k FROM 1 UPTO 15 REP TASK VAR tsk := task (k); IF tsk < father THEN putline (f, name (tsk)); list (f,tsk) FI PER. END PROC list net; PROC neue routen holen: forget ("port intern", quiet); fetch ("port intern"); route := old ("port intern"); neue routen END PROC neue routen holen; PROC sendung untersuchen (TASK CONST q, z, INT CONST cod, DATASPACE VAR dr): IF z = collector THEN verbindungsebene ELIF station (z) <> 0 THEN sendung (q,z,cod,station (z),dr) ELSE ablehnen ("Station 0") FI. verbindungsebene: IF cod = 256 THEN name von fremdstation ELIF cod > 256 THEN taskinfo fremd ELIF callee (q) = z (* gegen errornak an collector *) THEN task id von fremd FI. taskinfo fremd: sendung (q, collector, -task info code,cod-256,dr). task id von fremd: sendung (q, collector, -task id code, zielstation, dr) . name von fremdstation: BOUND TASK VAR tsk := dr; TASK VAR tsk1 := tsk; forget (dr); dr := nilspace; sendung (q, tsk1, -name code, station (tsk1), dr). zielstation: cod. END PROC sendung untersuchen; PROC sendung (TASK CONST q, z, INT CONST code, z stat, DATASPACE VAR dr): IF z stat < 1 OR z stat > maxstat THEN ablehnen ("ungültige Stationsnummer"); LEAVE sendung FI; INT VAR reply; INT VAR rp := route.port (z stat) AND 255; IF rp = 255 THEN neue routen holen ;rp := route.port (z stat) AND 255 FI; IF rp = channel THEN sendung selbst betreiben ELIF rp > 0 AND rp < 16 THEN sendung weitergeben ELSE ablehnen ("Station "+text(z stat)+" gibt es nicht") FI. sendung selbst betreiben: neue sendung (q, z, code, z stat, dr). sendung weitergeben: DATASPACE VAR ds := nilspace; BOUND PARA VAR p := ds; p.quelle := q; p.ziel := z; p.zielstation := z stat; p.sendecode := code; call (netport (z stat), route code, ds, reply); forget (ds); pingpong (netport (z stat), 0, dr, reply); forget (dr); IF reply < 0 THEN ablehnen ("netport "+text(route.port(zstat)AND255) + " fehlt") FI END PROC sendung; PROC ablehnen (TEXT CONST t): DATASPACE VAR vdr := nilspace; BOUND TEXT VAR errtxt := vdr; INT VAR err; errtxt := t; send (cd,stask, error nak, vdr,err); forget (vdr). END PROC ablehnen; PROC stop: access catalogue; IF exists task ("net timer") THEN TASK VAR nets := father (/"net timer"); ELSE nets := myself FI; nets := son (nets); WHILE NOT (nets = niltask) REP IF text (name (nets),3) = "net" OR name (nets) = "router" THEN end (nets) FI; nets := brother (nets) PER END PROC stop; PROC list status: DATASPACE VAR ds := nilspace; FILE VAR f:=sequential file (output, ds); line(f); FOR strom FROM 1 UPTO max verbindungsnummer REP IF strom > 0 THEN BOUND INFO VAR v := verbindung (strom); IF vx.strom <> 0 THEN info FI FI; PER; send (stask, ack, ds). info: put (f,"Strom "+text(strom)); put (f,"(sqnr"+text(vx.sequenz)+"/"+text (v.maxseq)+")"); IF sendeeintrag THEN sendeinfo ELSE empfangsinfo FI; line (f). sendeeintrag: vx.quellrechner = station(myself) . sendeinfo: IF v.typ = call im wait THEN put (f,"erwartet Antwort von") ELIF v.typ = call in zustellung THEN put (f,"Ziel busy. Zielstation:") ELIF v.typ = call im abbruch THEN put (f,"wird gelöscht bei Antwort von") ELSE put (f,"sendet an") FI; put (f,vx.zielrechner); put (f,". Absender ist """+nam (vx.quelle)+"""."). empfangsinfo: IF v.typ = zustellung THEN put (f,"Sendung noch nicht zustellbar") ELSE put (f,"empfängt von"); put (f,vx.quellrechner); FI; put (f,". Empfaenger ist """+nam (vx.ziel)+"""."). vx: v.steuer. END PROC list status; INT VAR quitmax := 3; ROW 15 TASK VAR net task; ROW 15 INT VAR netz mode; PROC erlaube (INT CONST von, bis): IF ein kanal gestartet THEN putline ("Warnung: 'erlaube' muß vor 'starte kanal'") FI; test (von); test (bis); INT VAR i; FOR i FROM von UPTO bis REP erlaubt (i) := 0 PER END PROC erlaube; PROC sperre (INT CONST von, bis): IF ein kanal gestartet THEN putline ("Warnung: 'sperre' muß vor 'starte kanal'") FI; test (von); test (bis); INT VAR i; FOR i FROM von UPTO bis REP erlaubt (i) :=-1 PER END PROC sperre ; BOOL VAR alte routen, ein kanal gestartet; PROC definiere netz: stop; INT VAR i; FOR i FROM 1 UPTO 15 REP net task (i) := niltask PER; ein kanal gestartet := FALSE; FILE VAR s := sequential file (output,"report"); putline (s," N e u e r S t a r t " + date + " " + time of day ); alte routen := exists ("port intern"); IF alte routen THEN route := old ("port intern") ELSE route := new ("port intern"); initialize routes FI. initialize routes: FOR i FROM 1 UPTO maxstat REP route.zwischen(i) := i PER. END PROC definiere netz; PROC starte kanal (INT CONST k,modus,stroeme): ein kanal gestartet := TRUE; IF exists (canal (k)) THEN end (canal (k)) FI; IF stroeme <= 0 THEN errorstop ("3.Parameter negativ") FI; quitmax := stroeme; c := k; IF c < 1 OR c > 15 THEN errorstop ("unzulässiger Kanal:"+text(c)) FI; kanalmode := modus; IF kanalmode < 1 OR kanalmode > max mode THEN errorstop ("unzulässiger Netzbetriebsmodus:"+text(kanalmode)) ELSE netz mode (c) := kanalmode FI; IF NOT exists task ("net port") THEN begin ("net port",PROC net io, net task (c)); define collector (/"net port") ELSE begin ("net port "+text (c),PROC net io, net task (c)) FI. END PROC starte kanal; PROC routen (INT CONST von, bis, kanal, zw): INT VAR i; IF kanal < 0 OR kanal > 15 THEN errorstop ("Kanal unzulässig") FI; test (von); test (bis); FOR i FROM von UPTO bis REP route.port (i) := kanal+256; IF zw=0 THEN route.zwischen (i) := i ELSE test (zw); route.zwischen (i) := zw FI PER. END PROC routen; PROC routen (INT CONST von, bis, kanal): routen (von, bis, kanal, 0) END PROC routen; PROC test (INT CONST station): IF station < 1 OR station > maxstat THEN errorstop (text (station) + " als Stationsnummer unzulässig") FI END PROC test; PROC aktiviere netz: vorgegebene routen pruefen; IF existstask ("net timer") THEN end (/"net timer") FI; begin ("net timer",PROC timer,sohn); IF NOT alte routen THEN routen aufbauen ELSE IF online THEN break FI FI. vorgegebene routen pruefen: INT VAR i; FOR i FROM 1 UPTO maxstat REP INT VAR s := route.port (i) AND 255; IF s > 0 AND s <= 15 CAND nettask (s) = niltask THEN errorstop ("Kanal "+text(s)+" nicht gestartet, steht aber in Routen") FI PER. END PROC aktiviere netz; PROC routen aufbauen: alte routen := TRUE; c := channel; break (quiet); begin ("router", PROC rout0, sohn). END PROC routen aufbauen; PROC rout0: disable stop; rout; IF is error THEN put error FI; end (myself) END PROC rout0; PROC rout: IF c>0 THEN continue (c) FI; clear error; enable stop; fetch ("port intern"); route := old ("port intern"); routen aufbauen; ds := old ("port intern"); call (father, neue routen code, ds, reply). routen aufbauen: access catalogue; TASK VAR port := brother (myself); WHILE NOT (port = niltask) REP IF text (name (port),8) = "net port" THEN nachbarn FI; port := brother (port) PER; IF online THEN putline ("Fertig. Weiter mit SV !") FI. aenderbar: route.port (st) < 256. nachbarn: INT VAR st,reply; FOR st FROM 1 UPTO maxstat REP IF erlaubt (st) >= 0 AND st <> station (myself) AND aenderbar THEN IF online THEN put (name (port)); put (st) FI; DATASPACE VAR ds := nilspace; call (port, tabellencode+st, ds, reply); IF reply = ack THEN BOUND STRUCT (ROW maxstat INT port, ROW maxstat INT zwischen) VAR fremd := ds; route.port (st) := channel(port); route.zwischen (st) := st; indirekte ziele ELIF reply < 0 THEN errorstop ("netz läuft nicht (Kanalnummer falsch)") ELSE BOUND TEXT VAR xt := ds; IF online THEN put (xt) FI; FI; IF online THEN line FI; forget (ds) FI PER. indirekte ziele: INT VAR kanal := fremd.port (station (myself)) AND 255; INT VAR ind; FOR ind FROM 1 UPTO maxstat REP IF ind bei st bekannt AND NOT ((fremd.port (ind) AND 255) = kanal) AND route.port (ind) < 256 THEN route.port (ind) := channel (port); route.zwischen (ind) := st FI PER. ind bei st bekannt: NOT (fremd.port (ind) = -1). END PROC rout; PROC timer: disable stop; access catalogue; INT VAR old session := 1; REP IF session <> old session THEN define collector (/"net port"); old session := session FI; clear error; pause (30); sende tick an alle ports PER. sende tick an alle ports : TASK VAR fb := son (father); REP IF NOT exists (fb) THEN access catalogue;LEAVE sende tick an alle portsFI; IF channel (fb) > 0 THEN DATASPACE VAR ds := nilspace; send (fb, ack, ds); pause (10) FI; fb := brother (fb) UNTIL fb = niltask PER. END PROC timer; PROC net io: disable stop; set net mode (kanalmode); fetch ("port intern"); route := old ("port intern"); commanddialogue (FALSE); continue (c); communicate; TEXT VAR emsg := "++++++ "+error message +" Zeile "+text(errorline); clear error; report (emsg); end (myself) END PROC net io; PROC start: run ("netz") END PROC start; END PACKET net manager;