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
Sharon Johnson, August 5, 1988 11:58:33 am 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.
ROPE ←
NIL, abort:
REF
BOOL]
RETURNS[rope: Rope.ROPE] = {
whoisServer: Rope.ROPE ← IF ~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.ROPE ← NIL;
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.
ROPE←
NIL] = {
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.ROPE←NIL] = {
server: IO.STREAM;
status: ArpaName.ReplyStatus;
cr: ArpaTCP.Reason ← neverOpen;
out: IO.STREAM ← IO.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 => {
cr ← ArpaTCP.ErrorFromStream[server];
GO TO 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.