DIRECTORY Basics, Convert, IO, RefText, Rope, XNS, XNSRouter; XNSRouterImpl: CEDAR MONITOR IMPORTS Basics, Convert, IO, RefText, Rope EXPORTS XNSRouter ~ { 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]; 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; 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_CreateXNSRouterHandle" }; XRDestroyXNSRouterHandle: PROC [h: XNSRouterHandle] ~ TRUSTED MACHINE CODE { "XR_DestroyXNSRouterHandle" }; 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" }; 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]; }; NetFromNDString: PROC [nds: ROPE] RETURNS [net: Net] ~ { 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]; }; 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]; }; 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 => { 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_dest_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_at_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_at_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]; rte.immediate ¬ directlyConnectedNet; -- TEMPORARY KLUDGE 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]; }; }. ό 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 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_at_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 Types Glue Utilities that ought to be in Convert Private Procs DBMsg[NIL, IO.PutFR["NetFromNDString %s", IO.rope[nds]]]; Exported to XNSRouter DBMsg[temp, "calling GetRouterParameterInternal"]; DBMsg[smallBuf, "convert.err"]; IF GetRouterParameterInternal[h, smallBuf, "xr_dest_relative_netid", netRope].ok THEN { immRope: ROPE; [w~immRope] _ FetchWord[smallBuf, 0]; rte.immediate _ NetFromNDString[immRope ! Convert.Error => CONTINUE]; }; IF GetRouterParameterInternal[h, smallBuf, "xr_rtt", netRope].ok THEN { delayRope: ROPE; [w~delayRope] _ FetchWord[smallBuf, 0]; rte.delay _ ConvertDotCardFromCLiteral[delayRope ! Convert.Error => CONTINUE]; }; Κ ¨–(cedarcode) style•NewlineDelimiter ™code™Kšœ Οeœ=™HJ™%K™-K™%K˜—šΟk ˜ K˜K˜Kšžœ˜K˜K˜Kšžœ˜Kšœ ˜ K˜—šΟn œžœž˜Kšžœžœ˜*Kšžœ ˜K˜head™K™ŸK™S—™KšœžœΟc)˜CKšœžœ  "Πcu ˜ZKšœžœžœžœžœžœžœžœ˜HKšœ žœžœ˜/Kšœ žœžœ˜/—™šœžœ˜Kšœ"˜"Kšœ*˜*—šœžœžœ˜Kšœžœ ˜!—Kšœžœ˜6Kšžœžœžœ˜—™Kšœžœžœžœ  ˜1Kšœ žœžœ˜Kš œ žœžœžœžœžœ˜%K˜š Ÿœžœžœžœžœ˜OK˜—Kš Ÿœžœžœžœžœžœ ˜gK˜š Ÿœžœžœžœžœžœ ˜qK˜—Kš Ÿœžœžœžœžœ!˜kK˜šŸœž œ,žœžœž œžœžœ ˜©K˜—KšŸœžœ,žœžœžœžœžœ ˜ —™%š Ÿœžœžœ"žœžœ˜bKšœžœ˜K˜&Kšœ˜Kšžœ žœžœ˜4K˜8Kšžœ žœ žœ"˜Bšžœžœž˜šœžœ˜"K˜2K˜—šœ˜K˜!K˜—šžœ˜ K˜+K˜——K˜K˜—š Ÿœžœžœžœžœžœ˜TKšžœ žœžœ˜šžœž˜Kšœ žœžœ ˜*Kšœ žœžœ ˜)Kšœ žœžœ ˜+Kšžœžœ˜/—K˜——™ šŸœžœžœžœ˜8Kšœžœžœžœ ™9K˜8K˜K˜—šŸœžœ žœ žœ˜=Kšœžœžœžœ ˜?Kšœžœ˜Kšœ žœ žœžœ,˜QK˜K˜—šŸ œžœžœžœžœžœžœžœ˜CK˜'Kšœ&žœ˜.K˜K˜—šŸ œžœžœžœ žœžœžœžœ˜LKšžœžœžœžœ˜-Kšžœžœžœžœ žœžœžœžœ˜[Kšžœ7žœ˜CK˜——™šŸœžœžœžœžœžœ žœžœžœžœžœ˜‹K˜K˜K˜Kšœ˜Kšœžœ &˜Bšœžœžœ˜K˜