QueryServicesImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Hal Murray May 16, 1985 3:20:40 am PDT
John Larson, July 21, 1987 5:01:47 pm PDT
Sharon Johnson, July 22, 1987 3:22:05 pm PDT
DIRECTORY
IO USING [Close, EndOf, EndOfStream, Error, Flush, GetChar, PutFR, PutChar, PutRope, rope, RopeFromROS, ROS, STREAM],
Rope USING [ROPE, Cat, Concat, Fetch, Find, Length, Substr],
IPDefs USING [Address],
IPName USING [LoadCacheFromName, NameToAddress],
IPRouter USING [BestAddress],
Process USING [SecondsToTicks],
TCP USING [AbortTCPStream, CreateTCPStream, Error, ErrorFromStream, neverTimeout, Reason, Timeout, WaitForListenerOpen],
QueryServices;
QueryServicesImpl: CEDAR MONITOR
IMPORTS IO, IPName, IPRouter, Process, Rope, TCP
EXPORTS QueryServices
=
BEGIN
whoIsSocket: INT = 43;
fingerSocket: INT = 79;
whoisServerName: Rope.ROPE = "SRI-NIC.ARPA";
nRetries: INT ← 4;
seconds: CARDINAL ← 2;
Whois: PUBLIC ENTRY PROC [pattern: Rope.ROPE] RETURNS[rope: Rope.ROPE] = {
snooz: CONDITION ← [timeout: Process.SecondsToTicks[seconds]];
FOR i: INT IN [0..nRetries) DO
rope ← QueryOnce[whoisServerName, pattern, whoIsSocket];
IF rope # NIL THEN RETURN[rope];
WAIT snooz;
ENDLOOP;
RETURN[IO.PutFR["Problems connecting to %g. Try again later.", IO.rope[whoisServerName]]];
};
Finger: PUBLIC ENTRY PROC [pattern: Rope.ROPE] RETURNS[rope: Rope.ROPE] = {
snooz: CONDITION ← [timeout: Process.SecondsToTicks[seconds]];
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"];
FOR i: INT IN [0..nRetries) DO
rope ← QueryOnce[host, user, fingerSocket];
IF rope # NIL THEN RETURN[rope];
WAIT snooz;
ENDLOOP;
RETURN[IO.PutFR["Problems connecting to %g. Try again later.", IO.rope[host]]];
};
QueryOnce: PROC [host, pattern: Rope.ROPE, socket: INT] RETURNS[rope: Rope.ROPENIL] = {
server: IO.STREAM;
cr: TCP.Reason ← neverOpen;
out: IO.STREAMIO.ROS[];
where: LIST OF IPDefs.Address;
IF host = NIL THEN RETURN["Need host name."];
SELECT IPName.LoadCacheFromName[host, TRUE, TRUE] 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]]];
mxOk => {
where ← IPName.NameToAddress[host];
IF where = NIL THEN
RETURN[IO.PutFR["%g is for mail forwarding only. (Not on internet.)", IO.rope[host]]];
};
ENDCASE => {where ← IPName.NameToAddress[host];};
IF where = NIL THEN {
RETURN[IO.PutFR["Can't find IP Address for %G.", IO.rope[host]]];
};
BEGIN
ENABLE {
TCP.Timeout => {
out.PutRope["[TCP.Timeout.]\n"];
GO TO GiveUp; };
TCP.Error => {
out.PutRope["[TCP.Error.]\n"];
cr ← reason;
GO TO GiveUp; };
IO.Error => {
out.PutRope["[IO.Error.]\n"];
cr ← TCP.ErrorFromStream[server];
GOTO GiveUp; };
};
server ← TCP.CreateTCPStream[[
matchLocalPort: FALSE,
localPort: 0,
matchForeignAddr: TRUE,
foreignAddress: IPRouter.BestAddress[where],
matchForeignPort: TRUE,
foreignPort: socket,
active: TRUE,
timeout: 120000]];
TCP.WaitForListenerOpen[server, TCP.neverTimeout];
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]
ENDLOOP;
rope ← IO.RopeFromROS[out];
server.Close[];
out.Close[];
EXITS GiveUp => {
IF server # NIL THEN TCP.AbortTCPStream[server];
SELECT cr FROM
remoteAbort => RETURN[Rope.Cat[host, " refused connection.\n"]];
ENDCASE => 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.