QueryServicesImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Hal Murray May 16, 1985 3:20:40 am PDT
John Larson, March 13, 1988 7:48:02 pm PST
Doug Terry, September 23, 1987 3:17:06 pm PDT
DIRECTORY
Arpa USING [Address, nullAddress],
ArpaConfig USING [ resolv ],
ArpaName USING [NameToAddress, ReplyStatus],
ArpaTCP USING [AbortTCPStream, CreateTCPStream, Error, ErrorFromStream, neverTimeout, Reason, Timeout, WaitForListenerOpen],
IO USING [Close, EndOf, EndOfStream, Error, Flush, GetChar, PutFR, PutChar, PutRope, rope, RopeFromROS, ROS, STREAM],
Rope USING [ROPE, Cat, Concat, IsEmpty, Fetch, Find, Length, Substr],
Process USING [SecondsToTicks],
QueryServices;
QueryServicesImpl: CEDAR MONITOR
IMPORTS ArpaConfig, ArpaName, ArpaTCP, IO, Process, Rope
EXPORTS QueryServices
=
BEGIN
OPEN QueryServices;
whoIsSocket: INT = 43;
fingerSocket: INT = 79;
whoisServerDefault: Rope.ROPE = "SRI-NIC.ARPA";
nRetries: INT ← 4;
seconds: CARDINAL ← 2;
Whois: PUBLIC PROC [pattern: Rope.ROPE, server: Rope.ROPENIL, abort: REF BOOL]
RETURNS[rope: Rope.ROPE] = {
whoisServer: Rope.ROPEIF ~Rope.IsEmpty[server] THEN server ELSE whoisServerDefault;
rope ← QueryWait[whoisServer, pattern, whoIsSocket, abort];
IF rope # NIL THEN RETURN[rope];
IF abort^ THEN RETURN[NIL];
RETURN[IO.PutFR["Problems connecting to %g. Try again later.", IO.rope[whoisServer]]];
};
Finger: PUBLIC PROC [pattern: Rope.ROPE, abort: REF BOOL]
RETURNS[rope: Rope.ROPE] = {
host, user: Rope.ROPENIL;
IF Rope.Find[pattern,"@"] > -1 THEN [user, host] ← BreakName[pattern, '@]
ELSE host ← pattern;
IF host = NIL THEN RETURN["Please provide host name."];
IF Rope.Find[host, "."] = -1 THEN host ← Rope.Concat[host, ".ARPA"];
rope ← QueryWait[host, user, fingerSocket, abort];
IF rope # NIL THEN RETURN[rope];
IF abort^ THEN RETURN[NIL];
RETURN[IO.PutFR["Problems connecting to %g. Try again later.", IO.rope[host]]];
};
QueryWait: ENTRY PROC [host, pattern: Rope.ROPE, socket: INT, abort: REF BOOL] RETURNS[rope: Rope.ROPENIL] = {
snooz: CONDITION ← [timeout: Process.SecondsToTicks[seconds]];
FOR i: INT IN [0..nRetries) DO
rope ← QueryOnce[host, pattern, socket, abort];
IF rope # NIL THEN EXIT;
IF abort^ THEN EXIT;
WAIT snooz;
ENDLOOP;
};
QueryOnce: PROC [host, pattern: Rope.ROPE, socket: INT, abort: REF BOOL]
RETURNS[rope: Rope.ROPENIL] = {
server: IO.STREAM;
status: ArpaName.ReplyStatus;
cr: ArpaTCP.Reason ← neverOpen;
out: IO.STREAMIO.ROS[];
where: Arpa.Address;
lastChar: CHAR ← '1;
i: INT ← 0;
IF host = NIL THEN RETURN["Need host name."];
[where, status,] ← ArpaName.NameToAddress[host, ArpaConfig.resolv^];
SELECT status FROM
bogus => RETURN[IO.PutFR["%g is not a valid name.", IO.rope[host]]];
down => RETURN[IO.PutFR["Name servers for %g are down. Try again later", IO.rope[host]]];
other => {
RETURN[IO.PutFR["%g has no address", IO.rope[host]]];
};
ENDCASE;
IF where = Arpa.nullAddress THEN {
RETURN[IO.PutFR["Can't find IP Address for %G.", IO.rope[host]]];
};
BEGIN
ENABLE {
ArpaTCP.Timeout => {
out.PutRope["[TCP.Timeout.]\n"];
GO TO GiveUp; };
ArpaTCP.Error => {
out.PutRope["[TCP.Error.]\n"];
cr ← reason;
GO TO GiveUp; };
IO.Error => {
out.PutRope["[IO.Error.]\n"];
cr ← ArpaTCP.ErrorFromStream[server];
GOTO GiveUp; };
};
server ← ArpaTCP.CreateTCPStream[[
matchLocalPort: FALSE,
localPort: 0,
matchForeignAddr: TRUE,
foreignAddress: where,
matchForeignPort: TRUE,
foreignPort: socket,
active: TRUE,
timeout: 140000]];
ArpaTCP.WaitForListenerOpen[server, ArpaTCP.neverTimeout];
IF abort^ THEN GOTO Abort;
IF pattern # NIL THEN server.PutRope[pattern];
server.PutRope["\n\l"];
server.Flush[];
WHILE NOT server.EndOf[] DO
c: CHAR ← server.GetChar[ ! IO.EndOfStream => EXIT];
IF c # '\l THEN out.PutChar[c] ELSE {
IF lastChar # '\n THEN out.PutChar['\n]}; -- Unix, convert LF to CR
lastChar ← c;
ENDLOOP;
rope ← IO.RopeFromROS[out];
server.Close[];
out.Close[];
EXITS
GiveUp => {
IF server # NIL THEN ArpaTCP.AbortTCPStream[server];
IF out # NIL THEN out.Close[];
SELECT cr FROM
remoteAbort => RETURN[Rope.Cat[host, " refused connection.\n"]];
ENDCASE => RETURN[NIL];};
Abort => {
IF server # NIL THEN ArpaTCP.AbortTCPStream[server];
IF out # NIL THEN out.Close[];
RETURN[NIL]};
END;
};
BreakName: PROC[name: Rope.ROPE, char: CHAR ← '.] RETURNS[left, right: Rope.ROPE] =
BEGIN
length: INT = name.Length[];
FOR i: INT DECREASING IN [0..length) DO
IF name.Fetch[i] = char THEN RETURN[
left: name.Substr[start: 0, len: i],
right: name.Substr[start: i+1, len: length-(i+1)] ];
ENDLOOP;
RETURN[left: NIL, right: NIL];
END;
END.