XNSRouterImpl.mesa
Copyright Ó 1989, 1991, 1992 by Xerox Corporation. All rights reserved.
Demers, October 19, 1990 11:44 am PDT
Tim Diebert: November 29, 1989 7:01:13 am PST
Willie-s, January 9, 1992 1:13 pm PST
DIRECTORY
Basics,
Convert,
IO,
RefText,
Rope,
XNS,
XNSRouter;
XNSRouterImpl: CEDAR MONITOR
IMPORTS Basics, Convert, IO, RefText, Rope
EXPORTS XNSRouter
~ {
ToDo
This is an interim implementation that tries to work around an apparent bug in the Mentat router code (it seems to return the info for the wrong network in response to any query except "xr←nets𡤊t←hop"). Here everything is implemented by enumerating the nets by distance, assuming there's only one connected network (so the "immediate" field an a RoutingTableEntry is uninteresting) and using the default 0.5 sec overhead and 1.0 sec internet hop delay time values. The commented procs below ought to be used when the Mentat code gets fixed.
ConvertDotCardFromCLiteral and ConvertDotCLiteralFromCard ought to move to Convert.
Parameters and global data
smallBufSize: CARD ~ 100; -- this is big enough for most things ...
largeBufSize: CARD ~ 4096; -- this is the largest buffer Unix(tm) stream ioctl accepts ...
byteAddressedOrElse: BOOL[TRUE..TRUE] ¬ (BYTES[CARD32] = UNITS[CARD32]);
smallBuf: REF TEXT ¬ RefText.New[smallBufSize];
largeBuf: REF TEXT ¬ RefText.New[largeBufSize];
Types
Hops: TYPE ~ XNSRouter.Hops;
maxHops: Hops ~ XNSRouter.maxHops;
unreachable: Hops ~ XNSRouter.unreachable;
Net: TYPE ~ XNS.Net;
unknownNet: Net ~ XNS.unknownNet;
RoutingTableEntry: TYPE ~ XNSRouter.RoutingTableEntry;
ROPE: TYPE ~ Rope.ROPE;
Glue
XNSRouterHandle: TYPE ~ RECORD[h: INT]; -- opaque
ReturnCode: TYPE ~ INT;
BytePtr: TYPE ~ LONG POINTER TO BYTE;
IsError: PROC [rc: ReturnCode] RETURNS [err: BOOL] ~ INLINE { err ¬ (rc < 0) };
ReturnCodeFromHandle: PROC [h: XNSRouterHandle] RETURNS [ReturnCode] ~ INLINE { RETURN [MIN[0, h.h]] };
XRCreateXNSRouterHandle: PROC RETURNS [h: XNSRouterHandle] ~ TRUSTED MACHINE CODE { "XR𡤌reateXNSRouterHandle" };
XRDestroyXNSRouterHandle: PROC [h: XNSRouterHandle] ~ TRUSTED MACHINE CODE { "XR�stroyXNSRouterHandle" };
XRGetXNSRouterParameter: UNSAFE PROC [h: XNSRouterHandle, buf: BytePtr, nBytes: CARD32] RETURNS [rc: ReturnCode] ~ UNCHECKED MACHINE CODE { "XR←GetXNSRouterParameter" };
XRSetXNSRouterParameter: PROC [h: XNSRouterHandle, buf: BytePtr, nBytes: CARD32] RETURNS [rc: ReturnCode] ~ TRUSTED MACHINE CODE { "XR←SetXNSRouterParameter" };
Utilities that ought to be in Convert
ConvertDotCardFromCLiteral: PROC [r: ROPE, defaultBase: Convert.Base ¬ 10]
RETURNS [ans: CARD] ~ {
pos, len, lim: INT;
pos ¬ Rope.SkipTo[r, 0, "0123456789"];
len ¬ Rope.Length[r];
IF pos >= len THEN ERROR Convert.Error[syntax, len];
lim ¬ Rope.SkipOver[r, pos, "0123456789abcdefABCDEFxX"];
IF (pos > 0) OR (lim < len) THEN r ¬ Rope.Substr[r, pos, lim-pos];
SELECT TRUE FROM
Rope.IsPrefix["0x", r, FALSE] => {
ans ¬ Convert.CardFromRope[Rope.Substr[r, 2], 16];
};
(Rope.Fetch[r, 0] = '0) => {
ans ¬ Convert.CardFromRope[r, 8];
};
ENDCASE => {
ans ¬ Convert.CardFromRope[r, defaultBase];
};
};
ConvertDotCLiteralFromCard: PROC [card: CARD, base: CARD ¬ 10] RETURNS [r: ROPE] ~ {
IF card = 0 THEN RETURN ["0"];
SELECT base FROM
8 => r ¬ IO.PutFR1["0%%b", IO.card[card]];
10 => r ¬ IO.PutFR1["%d", IO.card[card]];
16 => r ¬ IO.PutFR1["0x%x", IO.card[card]];
ENDCASE => ERROR Convert.Error[invalidBase, 0];
};
Private Procs
NetFromNDString: PROC [nds: ROPE] RETURNS [net: Net] ~ {
DBMsg[NIL, IO.PutFR["NetFromNDString %s", IO.rope[nds]]];
net ¬ Basics.FFromCard32[Convert.CardFromRope[nds, 16]];
};
NDStringFromNet: PROC [net: Net] RETURNS [ndString: ROPE] ~ {
temp: ROPE ¬ IO.PutFR1["%x", IO.card[Basics.Card32FromF[net]]];
len: INT ¬ Rope.Length[temp];
ndString ¬ IF len >= 8 THEN temp ELSE Rope.Replace["00000000", 8-len, len, temp];
};
AppendWord: PROC [t: REF TEXT, w: ROPE] RETURNS [new: REF TEXT] ~ {
new ¬ RefText.AppendRope[to~t, from~w];
new ¬ RefText.AppendChar[to~new, from~VAL[0]];
};
FetchWord: PROC [t: REF TEXT, start: CARD] RETURNS [next: CARD, w: ROPE] ~ {
IF start >= t.length THEN RETURN[start, NIL];
FOR next ¬ start, next.SUCC WHILE (next < t.length) AND (t[next] # VAL[0]) DO NULL ENDLOOP;
RETURN[w~Rope.FromRefText[t, start, (next-start)], next~next.SUCC];
};
Exported to XNSRouter
GetRouterParameterInternal: INTERNAL PROC [h: XNSRouterHandle, buf: REF TEXT, key: ROPE, subKey: ROPE ¬ NIL] RETURNS [ok: BOOL ¬ FALSE] ~ {
rc: ReturnCode;
buf.length ¬ 0;
buf ¬ AppendWord[buf, key];
buf ¬ AppendWord[buf, subKey];
buf ¬ AppendWord[buf, NIL]; -- n.b. appending two NILs is okay ...
{ temp: REF TEXT;
temp ¬ RefText.Append[to~RefText.New[buf.length], from~buf];
DBMsg[temp, "calling GetRouterParameterInternal"];
};
TRUSTED {
rc ¬ XRGetXNSRouterParameter[ h, LOOPHOLE[buf, BytePtr]+BYTES[TEXT[0]], buf.maxLength];
};
IF NOT IsError[rc] THEN {
buf.length ¬ buf.maxLength;
ok ¬ TRUE;
};
};
NewGetHops: PUBLIC ENTRY PROC [net: Net] RETURNS [hops: Hops] ~ {
h: XNSRouterHandle;
hops ¬ unreachable;
h ¬ XRCreateXNSRouterHandle[];
IF NOT IsError[ReturnCodeFromHandle[h]] THEN {
{ ENABLE Convert.Error => {
DBMsg[smallBuf, "convert.err"];
CONTINUE;
};
netLiteral, r: ROPE;
netLiteral ¬ NDStringFromNet[net];
IF GetRouterParameterInternal[h, smallBuf, "xr←hops", netLiteral].ok THEN {
[w~r] ¬ FetchWord[smallBuf, 0];
hops ¬ Convert.CardFromDecimalLiteral[r];
};
};
XRDestroyXNSRouterHandle[h];
};
};
NewGetRouting: PUBLIC ENTRY PROC [net: Net] RETURNS [rte: RoutingTableEntry] ~ {
h: XNSRouterHandle;
rte ¬ [hops~unreachable, immediate~unknownNet, delay~CARD.LAST];
h ¬ XRCreateXNSRouterHandle[];
IF NOT IsError[ReturnCodeFromHandle[h]] THEN {
{
r, netRope: ROPE;
netRope ¬ NDStringFromNet[net];
IF GetRouterParameterInternal[h, smallBuf, "xr←hops", netRope].ok THEN {
ENABLE Convert.Error => CONTINUE;
[w~r] ¬ FetchWord[smallBuf, 0];
rte.hops ¬ Convert.CardFromDecimalLiteral[r];
};
IF GetRouterParameterInternal[h, smallBuf, "xr�st←relative←netid", netRope].ok THEN {
ENABLE Convert.Error => CONTINUE;
[w~r] ¬ FetchWord[smallBuf, 0];
rte.immediate ¬ NetFromNDString[r];
};
IF GetRouterParameterInternal[h, smallBuf, "xr←rtt", netRope].ok THEN {
ENABLE Convert.Error => CONTINUE;
[w~r] ¬ FetchWord[smallBuf, 0];
rte.delay ¬ ConvertDotCardFromCLiteral[r];
};
};
XRDestroyXNSRouterHandle[h];
};
};
EnumerateInner: INTERNAL PROC [low, high: Hops, proc: PROC[Net, RoutingTableEntry] RETURNS [BOOL]] ~ {
h: XNSRouterHandle;
rte: RoutingTableEntry;
pos: INT;
netRope: ROPE;
h ¬ XRCreateXNSRouterHandle[];
IF NOT IsError[ReturnCodeFromHandle[h]] THEN {
directlyConnectedNet: Net;
IF NOT GetRouterParameterInternal[h, largeBuf, "xr←nets𡤊t←hop", "0"].ok
THEN GOTO Out;
[w~netRope] ¬ FetchWord[largeBuf, 0];
directlyConnectedNet ¬ NetFromNDString[netRope ! Convert.Error => GOTO Out];
FOR hops: Hops IN [low .. high] DO -- for each distance
hopsLiteral: ROPE ¬ ConvertDotCLiteralFromCard[hops];
IF GetRouterParameterInternal[h, largeBuf, "xr←nets𡤊t←hop", hopsLiteral].ok THEN {
pos ¬ 0;
DO -- for each net at that distance
[pos, netRope] ¬ FetchWord[largeBuf, pos];
IF Rope.IsEmpty[netRope] THEN EXIT;
rte ¬ [hops~hops, immediate~unknownNet, delay~CARD.LAST];
IF GetRouterParameterInternal[h, smallBuf, "xr�st←relative←netid", netRope].ok THEN {
immRope: ROPE;
[w~immRope] ← FetchWord[smallBuf, 0];
rte.immediate ← NetFromNDString[immRope ! Convert.Error => CONTINUE];
};
rte.immediate ¬ directlyConnectedNet; -- TEMPORARY KLUDGE
IF GetRouterParameterInternal[h, smallBuf, "xr←rtt", netRope].ok THEN {
delayRope: ROPE;
[w~delayRope] ← FetchWord[smallBuf, 0];
rte.delay ← ConvertDotCardFromCLiteral[delayRope ! Convert.Error => CONTINUE];
};
rte.delay ¬ 1000 * hops + 500; -- TEMPORARY KLUDGE
{ ENABLE Convert.Error => CONTINUE;
net: Net ¬ NetFromNDString[netRope];
IF NOT proc[ net, rte ] THEN GOTO Out
};
ENDLOOP; -- for each net at that distance
};
ENDLOOP; -- for each distance
GOTO Out;
EXITS
Out => XRDestroyXNSRouterHandle[h];
};
};
Enumerate: PUBLIC ENTRY PROC [low, high: Hops, proc: PROC[Net, RoutingTableEntry]] ~ {
ENABLE UNWIND => NULL;
MyProc: PROC [n: Net, rte: RoutingTableEntry] RETURNS [continue: BOOL] ~ {
proc[n, rte];
RETURN[TRUE];
};
EnumerateInner[low, high, MyProc];
};
GetHops: PUBLIC ENTRY PROC [net: Net] RETURNS [hops: Hops ¬ unreachable] ~ {
ENABLE UNWIND => NULL;
MyProc: PROC [n: Net, rte: RoutingTableEntry] RETURNS[BOOL] ~ {
IF n = net THEN { hops ¬ rte.hops; RETURN [FALSE] };
RETURN [TRUE];
};
EnumerateInner[0, maxHops, MyProc];
};
GetRouting: PUBLIC ENTRY PROC [net: Net] RETURNS [entry: RoutingTableEntry] ~ {
ENABLE UNWIND => NULL;
MyProc: PROC [n: Net, rte: RoutingTableEntry] RETURNS[BOOL] ~ {
IF n = net THEN { entry ¬ rte; RETURN [FALSE] };
RETURN [TRUE];
};
entry ¬ [unreachable, unknownNet, CARD.LAST];
EnumerateInner[0, maxHops, MyProc];
};
GetNetsAtHops: ENTRY PROC [hops: Hops] RETURNS [list: LIST OF ROPE ¬ NIL] ~ {
ENABLE UNWIND => NULL;
MyProc: PROC [n: Net, rte: RoutingTableEntry] RETURNS [BOOL] ~ {
list ¬ CONS[NDStringFromNet[n], list];
RETURN [TRUE];
};
EnumerateInner[hops, hops, MyProc];
};
}.