PACKET basic net DEFINES (* D. Heinrichs *)
(* Version 10 (!) *) (* 18.02.87 *)
nam, (* 03.06.87 *)
max verbindungsnummer, (* *)
neuer start,
neue routen,
packet eingang,
neue sendung,
zeitueberwachung,
verbindung,
loesche verbindung:
TEXT PROC nam (TASK CONST t):
IF t = collector THEN name (t)
ELIF station (t) <> station (myself)
THEN "** fremd "+text(station(t))+" **"
ELSE name (t)
FI
END PROC nam;
INT PROC tasknr (TASK CONST t):
IF t = collector THEN maxtasks
ELSE index (t)
FI
END PROC tasknr;
LET
maxtasks = 127,
maxstat = 127,
max strom = 20,
max strom 1 = 21,
stx = ""2"",
code stx = 2,
error nak = 2,
seiten groesse = 512,
dr verwaltungslaenge = 8,
dr verwaltungslaenge2=10,
openlaenge = 24,
vorspannlaenge = 14,
ack laenge = 12,
min data length = 64,
(* Codes der Verbindungsebene *)
task id code = 6,
name code = 7,
task info code = 8,
routen liefern code = 9,
(* Typen von Kommunikationsströmen *)
send wait = 0,
zustellung = 1,
call pingpong = 2,
call im wait = 3,
call im abbruch = 4,
call in zustellung = 5,
(*quittungscodes*)
ok = 0,
von vorne = 1,
wiederhole = 2,
loesche = 3,
beende = 4;
LET STEUER =
STRUCT (
INT head,
zwischenziel,
zielrechner,
quellrechner,
strom,
sequenz,
seitennummer,
TASK quelle,ziel,
INT sende code);
BOUND STEUER VAR open block;
BOUND STRUCT (STEUER steuer, INT typ, maxseq) VAR info block;
BOUND STRUCT (
INT head,
zwischenziel,
zielrechner,
quellrechner,
strom,
sequenz,
seitennummer) VAR vorspann ;
LET ACK = STRUCT (
INT head,
zwischenziel,
zielrechner,
quellrechner,
strom,
code);
BOUND ACK VAR ack packet ;
BOUND ACK VAR transmitted ack packet;
BOUND STRUCT (ROW maxstat INT port,
ROW maxstat INT zwischen) VAR route;
INT CONST max verbindungsnummer := max strom;
INT VAR codet,net mode, nutzlaenge := data length,
data len via node := data length via node;
TEXT VAR buffer first;
DATASPACE VAR work space := nilspace;
DATASPACE VAR transmitted ack space := nilspace;
INT VAR pakete pro seite,
pakete pro seite minus 1,
packets per page via node,
packets per page via node minus 1,
datenpacketlaenge via node,
datenpacketlaenge ;
INT VAR strom;
INT VAR last data := -1;
INT VAR own:=station (myself) ,
quit max := 3,
quit zaehler := 3,
own256 := 256*own;
INT CONST stx open := code stx+256*openlaenge,
stx quit := code stx+256*acklaenge;
STEUER VAR opti;
ROW maxstrom1 STEUER VAR verbindungen;
ROW maxstrom1 DATASPACE VAR netz dr;
ROW maxstrom1 INT VAR zeit, typ, open try;
FOR strom FROM 1 UPTO maxstrom1 REP vdr := nilspace; forget (vdr) PER;
ROW maxstrom INT VAR dr page ;
ROW maxtasks INT VAR alter call;
.vx : verbindungen (strom).
vdr: netz dr (strom).
via node:
vx.zielrechner <= 0 OR vx.quellrechner <= 0 OR
transmit via node OR receive via node.
transmit via node:
route.zwischen (vx.zielrechner) <> vx.zielrechner AND vx.zielrechner <> own.
receive via node:
route.zwischen (vx.quellrechner) <> vx.quellrechner AND vx.quellrechner <> own.
falsche stromnummer: strom < 1 OR strom > maxstrom.
zielrechner ok: vorspann.zielrechner > 0 AND vorspann.zielrechner <= maxstat.
quellrechner ok: vorspann.quellrechner > 0
AND vorspann.quellrechner <= maxstat.
call aufruf: typ(strom) >= call pingpong.
alles raus: vx.seitennummer = -1 AND letztes packet der seite .
letztes packet der seite :
(vx.sequenz AND packets per page minus 1) = packets per page minus 1.
neue verbindung: code t = open laenge.
PROC neue routen:
route := old ("port intern");
END PROC neue routen;
PROC neuer start (INT CONST empfangsstroeme, mode):
net mode := mode;
strom := 1;
neue routen;
transmitted ack space := nilspace;
workspace := nilspace;
open block := workspace;
info block := workspace;
nutzlaenge := data length;
data len via node := data length via node;
pakete pro seite:= seitengroesse DIV nutzlaenge;
pakete pro seite minus 1 := pakete pro seite -1;
packets per page via node := seitengroesse DIV data len via node;
packets per page via node minus 1 := packets per page via node - 1;
datenpacketlaenge := vorspannlaenge + nutzlaenge;
datenpacketlaenge via node := vorspannlaenge + data len via node;
vorspann := workspace;
ack packet := workspace;
transmitted ack packet := transmitted ack space;
FOR strom FROM 1 UPTO maxstrom1 REP
vx.strom := 0; forget (vdr)
PER;
INT VAR i;
FOR i FROM 1 UPTO maxtasks REP alter call (i) := 0 PER;
quitmax := empfangsstroeme;
own:=station (myself);
quit zaehler := quit max;
own256 := 256*own;
reset box (net mode);
buffer first := "";
flush buffers;
INT VAR err;
fehlermeldung ruecksetzen.
fehlermeldung ruecksetzen:
control (12,0,0,err).
END PROC neuer start;
DATASPACE PROC verbindung (INT CONST nr):
INT VAR memory := strom;
strom := nr;
infoblock.steuer := verbindungen (nr);
infoblock.typ := typ (nr);
infoblock.maxseq := dspages (netzdr(nr)) * packets per page;
strom := memory;
workspace
END PROC verbindung;
PROC neue sendung (TASK CONST q,z, INT CONST cod,z stat, DATASPACE CONST dr):
naechste verbindung vorbereiten;
forget (vdr); vdr := dr;
sendung starten (q, z, z stat, cod)
END PROC neue sendung;
PROC zeitueberwachung
(INT VAR snr, TASK VAR q, z, INT VAR ant,DATASPACE VAR dr):
snr INCR 1;
FOR strom FROM snr UPTO maxstrom REP zeitkontrolle PER;
snr := 0.
zeitkontrolle:
IF vx.strom <> 0 AND zeit(strom) > 0
THEN
zeit(strom) DECR 1;
IF sendung noch nicht zugestellt
THEN
IF zeit(strom) = 0
THEN
empfangsreport ("Nicht zustellbar. ");
loesche verbindung (strom)
ELSE
snr := strom;
q := vx.quelle;
z := vx.ziel;
ant := vx.sendecode;
dr := vdr;
LEAVE zeitueberwachung
FI
ELIF zeit(strom) = 0
THEN wiederholen
FI
FI.
sendung noch nicht zugestellt:
typ (strom) = zustellung.
wiederholen:
IF sendeeintrag
THEN
sendung wiederholen
ELSE
empfangseintrag freigeben
FI.
sendeeintrag : vx.quellrechner = own .
sendung wiederholen:
IF wiederholung noch sinnvoll
THEN
IF frisch
THEN
time out bei open
ELSE
datenteil wiederholen
FI
ELSE
sendung loeschen
FI.
wiederholung noch sinnvoll:
task noch da AND bei call noch im call.
task noch da: vx.quelle = collector OR exists (vx.quelle).
bei call noch im call:
IF call aufruf
THEN
callee (vx.quelle) = vx.ziel
ELSE
TRUE
FI.
frisch: vx.sequenz = -1.
time out bei open:
IF vx.sendecode > -4 OR opentry (strom) > 0
THEN
open wiederholen ;
opentry (strom) DECR 1
ELSE
nak an quelle senden
FI.
nak an quelle senden:
dr := nilspace;
BOUND TEXT VAR erm := dr;
erm := "Station "+text(vx.zielrechner)+" antwortet nicht";
snr := strom;
q := vx.ziel;
z := vx.quelle;
ant := error nak;
sendung loeschen;
LEAVE zeitueberwachung .
open wiederholen:
sendereport ("wdh open");
IF opentry (strom) > 0 THEN zeit(strom) := 4 ELSE zeit(strom) := 40 FI;
openblock := vx;
openblock.head := stx open;
ab die post.
datenteil wiederholen:
sendereport ("wdh data. sqnr "+text (vx.sequenz));
senden .
empfangseintrag freigeben:
IF antwort auf call
THEN
weiter warten
ELSE
empfangsreport ("Empfangseintrag freigegeben");
loesche verbindung (strom)
FI.
antwort auf call: callee (vx.ziel) = vx.quelle.
weiter warten: zeit (strom) := 400.
END PROC zeitueberwachung;
PROC sendereport (TEXT CONST txt):
report (text (strom)+":"+txt+". Absender: """+nam (vx.quelle)+
""". Ziel "+text(vx.zielrechner) + " Taskindex: " +
text (index (vx.ziel)));
END PROC sendereport;
PROC empfangsreport (TEXT CONST txt):
report (text (strom)+":"+txt+". Empfänger: """
+nam (vx.ziel)+""". Quelle "+text (vx.quellrechner) +
" Taskindex: " + text (index (vx.quelle)));
END PROC empfangsreport ;
PROC sendung loeschen:
strom loeschen (tasknr (vx.quelle))
END PROC sendung loeschen;
PROC strom loeschen (INT CONST tasknr):
IF callaufruf CAND alter call (tasknr ) = strom
THEN
alter call (tasknr ) := 0
FI;
vx.strom := 0;
forget (vdr)
END PROC strom loeschen;
PROC empfang loeschen:
quit zaehler INCR 1;
strom loeschen (tasknr (vx.ziel))
END PROC empfang loeschen;
PROC loesche verbindung (INT CONST nr):
strom := nr;
IF sendeeintrag
THEN
sendung loeschen
ELSE
gegenstelle zum loeschen auffordern;
empfang loeschen
FI.
gegenstelle zum loeschen auffordern:
IF verbindung aktiv THEN quittieren (-loesche) FI.
verbindung aktiv: vx.strom > 0.
sendeeintrag: vx.quellrechner = own .
END PROC loesche verbindung;
PROC weiter senden:
IF NOT alles raus
THEN
sequenz zaehlung;
IF neue seite THEN seitennummer eintragen FI;
senden
FI.
sequenz zaehlung:
vx.sequenz INCR 1.
neue seite:
IF via node THEN (vx.sequenz AND packets per page via node minus 1) = 0
ELSE (vx.sequenz AND pakete pro seite minus 1) = 0
FI.
seitennummer eintragen:
dr page (strom) := vx.seiten nummer;
vx.seitennummer := next ds page (vdr, dr page (strom)).
END PROC weiter senden;
.packets per page:
IF via node THEN packets per page via node
ELSE pakete pro seite
FI.
packets per page minus 1:
IF via node THEN packets per page via node minus 1
ELSE pakete pro seite minus 1
FI.
used length:
IF via node THEN data len via node
ELSE nutzlaenge
FI.
PROC senden:
INT VAR nl;
zeit(strom) := 6;
openblock := vx;
nl := used length;
transmit header (workspace);
vorspann senden;
daten senden;
transmit trailer.
vorspann senden:
blockout (workspace, 1, dr verwaltungslaenge, vorspannlaenge).
daten senden:
blockout (vdr,dr page (strom),distanz,nl).
distanz: nl* (vx.sequenz AND packets per page minus 1).
END PROC senden;
PROC naechste verbindung vorbereiten:
FOR strom FROM 1 UPTO maxstrom REP
UNTIL vx.strom = 0 PER;
IF vx.strom <> 0 THEN errorstop ("Verbindungsengpass") FI.
END PROC naechste verbindung vorbereiten;
PROC sendung starten (TASK CONST quelle, ziel, INT CONST code):
sendung starten (quelle,ziel, station(ziel), code)
END PROC sendung starten;
PROC sendung starten (TASK CONST quelle, ziel, INT CONST ziel station,code):
IF ziel station = own
THEN
report ("Irrläufer: Sendung an eigene Station. Absender:"""+
nam (quelle)+""".");
vx.strom := 0;
forget (vdr)
ELSE
openblock.ziel := ziel;
openblock.quelle :=quelle;
openblock.sendecode := code;
openblock.zielrechner:= ziel station;
openblock.quellrechner :=own;
openblock.zwischenziel := route.zwischen (ziel station)+own256;
alten call loeschen (quelle);
IF call oder ping pong
THEN typ (strom) := call pingpong; call merken
ELSE typ (strom) := send wait FI;
sendung neu starten
FI.
call oder pingpong: openblock.ziel = callee (openblock.quelle).
call merken: alter call (tasknr (quelle)) := strom.
END PROC sendung starten;
PROC encode packet length (INT VAR val):
IF val < 96 THEN
ELIF val < 160 THEN val DECR 32
ELIF val < 288 THEN val DECR 128
ELIF val < 544 THEN val DECR 352
ELIF val < 1056 THEN val DECR 832
ELIF val < 2080 THEN val DECR 1824
FI;
rotate (val, 8)
ENDPROC encode packet length;
PROC sendung neu starten:
INT VAR value;
openblock.head:= stx open;
openblock.sequenz := -1;
openblock.seitennummer:= next ds page (vdr,-1);
openblock.strom := strom;
vx := open block;
schnelles nak bei routen liefern;
ab die post;
value := vorspannlaenge + used length;
encode packet length (value);
vx.head:=code stx+value.
schnelles nak bei routen liefern:
IF openblock.sendecode = -routen liefern code
THEN
openblock.zwischenziel := openblock.zielrechner+own256;
zeit(strom) := 2;
opentry (strom) := 0
ELSE
zeit (strom) :=8;
opentry (strom) := 2
FI.
END PROC sendung neu starten; .
ab die post:
transmit header (workspace);
block out (work space,1, dr verwaltungslaenge,open laenge);
transmit trailer.
PROC alten call loeschen (TASK CONST quelle):
IF alter call aktiv
THEN
INT VAR lstrom := strom;
vx:=openblock;
strom := alter call (tasknr (quelle));
IF in ausfuehrungsphase
THEN
sendereport ("Call-Löschung vorgemerkt");
loeschung vormerken
ELSE
report ("Call gelöscht."""+nam(quelle)+""". Strom "+text(strom));
loesche verbindung (strom)
FI;
strom := lstrom;
openblock := vx
FI.
in ausfuehrungsphase:
typ(strom) = call im wait OR typ (strom) = call in zustellung.
loeschung vormerken:
typ(strom) := call im abbruch;
alter call (tasknr (quelle)) := 0.
alter call aktiv:
alter call (tasknr (quelle)) > 0.
END PROC alten call loeschen;
PROC packet eingang
( INT VAR snr, TASK VAR q, z, INT VAR ant,DATASPACE VAR dr):
snr := 0;
fehlertest;
vorspann holen;
IF NOT ring logik THEN daten teil FI.
ring logik: FALSE.
fehlertest:
#
INT VAR c12;
control (12,0,0,c12);
IF c12 <> 0
THEN
flush buffers;
report ("E/A-Fehler "+text (c12));
control (12,0,0,c12);
LEAVE packet eingang
FI.
#.
vorspann holen:
sync;
IF NOT blockin (workspace, 1, dr verwaltungslaenge2, block laenge)
THEN LEAVE packeteingang
FI.
blocklaenge: IF code t > min data length
THEN
vorspannlaenge-2
ELSE
code t -2
FI.
sync:
IF NOT packet start already inspected
THEN
TEXT VAR skipped, t:= "";
skipped := next packet start;
IF skipped = "" THEN LEAVE packet eingang FI;
t := incharety (1);
code t := code (t);
ELSE
skipped := buffer first;
buffer first := "";
t := incharety (1);
code t := code (t);
FI;
decode packet length;
IF skipped=stx AND laenge ok THEN LEAVE sync FI;
REP
skipped CAT t;
t := incharety (1); (* next character *)
IF t = "" THEN
report ("skipped",skipped);
LEAVE packet eingang
FI ;
codet := code (t);
UNTIL blockanfang OR length (skipped) > 200 PER;
decode packet length;
IF skipped <> stx THEN report ("skipped bei sync:", skipped) FI.
decode packet length:
IF code t < 96 THEN
ELIF code t < 128 THEN code t INCR 32
ELIF code t < 160 THEN code t INCR 128
ELIF code t < 192 THEN code t INCR 352
ELIF code t < 224 THEN code t INCR 832
ELIF code t < 256 THEN code t INCR 1824
FI.
packet start already inspected: buffer first <> "".
blockanfang:
(skipped SUB length(skipped)) = stx AND laenge ok.
laenge ok:
(codet = datenpacketlaenge OR codet = datenpacketlaenge via node
OR codet = ack laenge OR code t = openlaenge).
zielnummer: vorspann.zielrechner.
daten teil:
IF zielnummer = own
THEN
ziel erreicht (openblock,snr,q,z,ant,dr)
ELSE
weiter faedeln
FI.
weiter faedeln:
INT VAR value;
IF zielrechner ok
THEN
IF neue verbindung
THEN
IF (openblock.sendecode = -routenlieferncode) OR NOT route ok
THEN LEAVE packet eingang
FI
FI;
value := code t;
encode packet length (value);
vorspann.head := code stx + value;
vorspann.zwischenziel := own256 + route.zwischen (vorspann.zielrechner);
nutzdaten einlesen;
dr := workspace;
snr := 1000;
ant := zielnummer
FI.
nutzdaten einlesen:
IF code t > data len via node
THEN
IF NOT blockin (workspace, 1, drverwaltungslaenge+vorspannlaenge, data len via node)
THEN
LEAVE packeteingang
FI;
IF NOT next packet ok THEN LEAVE packeteingang FI
FI.
END PROC packet eingang;
PROC ziel erreicht (STEUER CONST prefix,
INT VAR snr, TASK VAR q, z, INT VAR ant,DATASPACE VAR dr):
last data := -1;
IF NOT quellrechner ok
THEN
report ("Quellrechner "+text(prefix.quellrechner));
LEAVE ziel erreicht
FI;
IF neue verbindung
THEN
IF NOT route ok OR NOT quelltask ok
THEN report ("verbotene Route: " + text (prefix.quellrechner));
LEAVE ziel erreicht
FI;
verbindung bereitstellen
ELIF quittung
THEN
strom := ack packet.strom;
IF falsche stromnummer THEN report ("Strom falsch in Quittung");
LEAVE ziel erreicht FI;
IF vx.strom = 0 THEN LEAVE ziel erreicht FI;
IF ackpacket.code >= ok THEN weiter senden
ELIF NOT route ok THEN
sendereport ("verbotene Route bei Quittung");
LEAVE ziel erreicht
ELIF ackpacket.code = -von vorne THEN
sendereport ("Neustart");
openblock := vx;
sendung neu starten
ELIF ackpacket.code = -wiederhole THEN back 16
ELIF ackpacket.code = -loesche THEN fremdloeschung
ELIF ackpacket.code = -beende AND alles raus THEN strom abschliessen
FI
ELIF verbindung festgestellt
THEN
zeit(strom) := 400;
opti := vx;
datenpacket
ELSE
strom := maxstrom1;
vx:=prefix;
report ("Daten ohne Eroeffnung von " +text(prefix.quellrechner)
+" Sequenznr "+text(prefix.sequenz));
daten entfernen (used length);
IF alles raus THEN quittieren (-beende) ELSE quittieren(-von vorne) FI
FI.
quelltask ok:
prefix.quelle = collector OR antwort auf routen liefern
OR station (prefix.quelle) = prefix.quellrechner.
antwort auf routen liefern: prefix.quelle = myself.
verbindung bereitstellen:
IF (prefix.sendecode < 0 OR station (prefix.ziel) = own)
AND quellrechner ok
THEN
freie verbindungsnummer;
vdr := nilspace;
vx := open block;
zeit(strom) := 30;
quittieren falls genug pufferplatz;
vx.sequenz := 0 ;
opti := vx;
dr page (strom) :=-2;
IF abschluss THEN rueckmeldung FI
FI.
loeschung vorgemerkt: typ(strom) = call im abbruch.
strom abschliessen:
IF call aufruf
THEN
wdh data vor ablauf der zustellversuche bei der gegenstation;
ausfuehrungsphase merken
ELSE
wdh data sperren
FI.
wdh data sperren:
zeit (strom) := 12000.
wdh data vor ablauf der zustellversuche bei der gegenstation:
zeit (strom) := 80.
ausfuehrungsphase merken: typ(strom) := call in zustellung.
back16:
datenraum etwas rueckspulen;
opentry (strom) := 2;
nicht sofort senden (* wegen vagabundierender Quittungen *).
nicht sofort senden: zeit(strom) := 2.
datenraum etwas rueckspulen:
INT VAR pps := packets per page ;
sendereport ("etwas rueckgespult");
INT VAR vs :=-1;
dr page (strom) := -1;
INT VAR i;
FOR i FROM 1 UPTO vx.sequenz DIV pps - etwas REP
vs INCR pps;
dr page (strom) := next ds page (vdr, dr page (strom))
PER;
vx.seiten nummer := next ds page (vdr, dr page (strom)) ;
vx.sequenz := vs.
etwas: 3.
fremdloeschung:
IF fremdrechner ok und sendung
THEN
IF typ (strom) = call in zustellung
THEN
typ (strom) := call im wait
ELSE
IF NOT alles raus
THEN
sendereport ("Sendung von Gegenstelle geloescht")
FI;
sendung loeschen
FI
FI.
fremdrechner ok und sendung:
ackpacket.quellrechner = vx.zielrechner .
quittieren falls genug pufferplatz:
IF quit zaehler > 0 THEN
quit zaehler DECR 1;
open quittieren;
block vorab quittieren
ELSE
quittieren (-wiederhole)
FI.
open quittieren: quittieren (ok).
block vorab quittieren:
IF prio (myself) < 3 THEN quittieren (ok) FI.
quittung: code t <= ack laenge.
verbindung festgestellt:
FOR strom FROM maxstrom DOWNTO 1 REP
IF bekannter strom
THEN LEAVE verbindung festgestellt WITH TRUE FI
PER;
FALSE.
bekannter strom:
vx.strom = prefix.strom AND vom selben rechner.
vom selben rechner:
vx.quellrechner = prefix.quellrechner.
daten:
IF neue seite da THEN check for valid pagenr;
dr page(strom) := prefix.seitennummer;
ELIF prefix.seitennummer < dr page(strom)
THEN empfangsreport ("Falsche Seitennummer, Soll: " +
text(drpage(strom)) + " ist: " +
text (prefix.seitennummer)
+ " bei Sequenznr: " +
text(prefix.sequenz));
flush buffers;
quittieren (- wiederhole);
LEAVE ziel erreicht
FI;
sequenz zaehlung;
IF neue seite kommt
THEN
vx.seiten nummer := prefix.seiten nummer;
dr page(strom) := prefix.seitennummer;
FI;
quittieren(ok);
IF NOT blockin (vdr, opti.seiten nummer, distanz, nl)
COR NOT next packet ok
THEN quittieren (-wiederhole);
LEAVE ziel erreicht
FI;
last data := strom.
check for valid pagenr:
IF prefix.seitennummer < dr page(strom) AND prefix.seitennummer > -1
THEN report ("Absteigende Seitennummern, alt: " + text(drpage(strom))+
" neu: "+ text(prefix.seitennummer) + " Seq.nr: " +
text(vx.sequenz) ) ;
flush buffers;
quittieren (- von vorne);
LEAVE ziel erreicht;
FI.
datenpacket:
INT VAR nl := used length;
INT VAR pps1 := packets per page minus 1;
IF sendung wartet auf zustellung THEN auffrischen ELSE daten holen FI.
sendung wartet auf zustellung: typ (strom) = zustellung.
auffrischen: zeit (strom) := 200; daten entfernen (nl).
daten holen:
IF opti.sequenz >= prefix.sequenz AND opti.sequenz < prefix.sequenz+100
AND prefix.sequenz >= 0
THEN
IF opti.sequenz <> prefix.sequenz
THEN empfangsreport ("Sequenzreset von "+text(opti.sequenz)+" auf "+
text (prefix.sequenz));
vx.sequenz := prefix.sequenz;
IF pagenumber ok
THEN dr page (strom) := prefix.seitennummer
ELSE empfangsreport ("Blocknummer falsch, neu: "+
text (prefix.seitennummer) + ", alt : " +
text (drpage(strom)) );
FI;
vorabquittung regenerieren
FI;
daten ;
IF abschluss THEN rueckmeldung FI;
ELSE
empfangsreport ("Sequenzfehler: soll "+text(vx.sequenz)+" ist "+
text(prefix.sequenz));
quittieren (-wiederhole);
daten entfernen (nl)
FI.
pagenumber ok:
dr page (strom) >= prefix.seitennummer .
rueckmeldung:
snr := strom;
q := vx.quelle;
z := vx.ziel;
ant := vx.sendecode;
dr := vdr;
LEAVE ziel erreicht.
vorabquittung regenerieren:
IF prio (myself) < 3
THEN
quittieren (ok)
FI.
distanz: (opti.sequenz AND pps1 ) * nl.
sequenz zaehlung:
vx.sequenz INCR 1.
neue seite da:
neue seite kommt.
neue seite kommt:
(vx.sequenz AND pps1) = 0.
freie verbindungsnummer:
INT VAR h strom :=maxstrom1, cstrom := 0;
FOR strom FROM 1 UPTO maxstrom REP
IF vx.strom = 0 THEN h strom := strom ;
typ(strom) := send wait
ELIF bekannter strom
THEN empfangsreport ("Reopen");
quit zaehler INCR 1;
IF typ (strom) = zustellung THEN typ (strom) := send wait FI;
forget (vdr);
LEAVE freie verbindungsnummer
ELIF antwort auf call
THEN
IF loeschung vorgemerkt
THEN
vx := prefix;
loesche verbindung (strom);
LEAVE ziel erreicht
FI;
cstrom := strom;
typ (strom) := call pingpong;
forget (vdr);
FI
PER;
IF cstrom > 0 THEN strom := cstrom ELSE strom := h strom FI;
IF strom = maxstrom1 THEN
vx:=prefix;
empfangsreport ("Verbindungsengpass");
quittieren (-wiederhole);
LEAVE ziel erreicht
FI.
antwort auf call:
prefix.sendecode >= 0 AND
call aufruf AND vx.quelle = prefix.ziel AND vx.ziel = prefix.quelle.
END PROC ziel erreicht;
PROC daten entfernen (INT CONST wieviel):
BOOL VAR dummy ;
dummy:=blockin (workspace, 2, 0, wieviel)
END PROC daten entfernen;
BOOL PROC route ok:
INT VAR zwischenquelle := vorspann.zwischenziel DIV 256,
endquelle := vorspann.quellrechner;
zwischenquelle abgleichen;
endquelle abgleichen;
TRUE.
zwischenquelle abgleichen:
IF NOT zwischenroute gleich
THEN
IF NOT zwischenabgleich erlaubt THEN LEAVE route ok WITH FALSE FI;
route.port (zwischenquelle) := channel;
route.zwischen (zwischenquelle) := zwischenquelle;
abgleich (zwischenquelle, zwischenquelle)
FI.
zwischenabgleich erlaubt: route.port (zwischenquelle) < 256.
endquelle abgleichen:
IF NOT endroute gleich
THEN
IF NOT endabgleich erlaubt THEN LEAVE route ok WITH FALSE FI;
route.port (endquelle) := channel;
route.zwischen (endquelle) := zwischenquelle;
abgleich (endquelle, zwischenquelle)
FI.
endabgleich erlaubt: route.port (endquelle) < 256.
zwischenroute gleich:
(route.port (zwischenquelle) AND 255) = channel
AND
route.zwischen (zwischenquelle) = zwischenquelle.
endroute gleich:
(route.port (endquelle) AND 255) = channel
AND
route.zwischen (endquelle) = zwischenquelle.
END PROC route ok;
BOOL PROC abschluss:
last data := -1;
IF neue seite kommt AND vx.seiten nummer = -1
THEN
quittieren (-beende);
an ziel weitergeben
ELSE
FALSE
FI.
neue seite kommt:
(vx.sequenz AND packets per page minus 1) = 0.
an ziel weitergeben:
IF tasknummerfrage THEN taskfrage beantworten ;pufferplatz ; FALSE
ELIF tasknamenfrage THEN name senden ;pufferplatz ; FALSE
ELIF taskinfofrage THEN task info senden;pufferplatz ; FALSE
ELIF routenfrage THEN routen senden; pufferplatz; FALSE
ELSE senden ; TRUE
FI.
pufferplatz : quitzaehler INCR 1 .
senden:
IF callaufruf
THEN
ein versuch (* bei Antwort auf Call muß ein Zustellversuch reichen *)
ELSE
max 100 versuche;
typ (strom) := zustellung
FI.
tasknummerfrage:opti.sendecode = -taskid code.
tasknamenfrage: opti.sendecode = -name code.
taskinfofrage: opti.sendecode = -task info code.
routenfrage: opti.sendecode = -routen liefern code.
max 100 versuche: zeit(strom) := 100.
ein versuch: zeit (strom) := 1.
taskfrage beantworten:
disable stop;
BOUND TEXT VAR tsk := vdr;
TEXT VAR save tsk := tsk;
forget (vdr); vdr := nilspace;
BOUND TASK VAR task id := vdr;
task id := task(save tsk);
IF is error THEN
clear error; enable stop;
forget (vdr); vdr := nilspace;
BOUND TEXT VAR errtxt := vdr;
errtxt := text(own)+"/"""+save tsk+""" gibt es nicht";
sendung starten (collector, opti.quelle, 2)
ELSE
enable stop;
sendung starten (collector, opti.quelle, 0)
FI.
name senden:
quittieren (-loesche);
forget (vdr); vdr := nilspace;
tsk := vdr;
tsk := nam (opti.ziel);
sendung starten (collector, opti.quelle, 0).
routen senden:
forget (vdr); vdr := old ("port intern");
sendung starten (opti.ziel, opti.quelle, 0).
task info senden:
disable stop;
BOUND INT VAR ti code := vdr;
INT VAR ti cd := ti code;
forget (vdr); vdr := nilspace;
FILE VAR task inf := sequential file (output,vdr);
head line (task inf,"Station "+text(own));
task info (ti cd, task inf);
IF is error
THEN
forget (vdr); vdr := nilspace;
errtxt := vdr;
errtxt := errormessage;
clear error;
sendung starten (collector, opti.quelle, 2)
ELSE
sendung starten (collector,opti.quelle,0)
FI;
enable stop
END PROC abschluss ;
PROC quittieren(INT CONST code) :
INT VAR quell := vx.quellrechner ;
transmitted ackpacket := ACK:(stx quit, route.zwischen (quell)+own256, quell, own,
vx.strom, code);
transmit header (transmitted ack space);
blockout (transmitted ack space,1,dr verwaltungslaenge, ack laenge);
transmit trailer;
END PROC quittieren;
BOOL PROC next packet ok:
buffer first := next packet start;
buffer first = "" COR normal packet start.
normal packet start:
IF buffer first = stx
THEN
TRUE
ELSE
buffer first := ""; flush buffers; FALSE
FI.
END PROC next packet ok;
END PACKET basic net;