-- Copyright (C) 1984 by Xerox Corporation. All rights reserved.
-- TestTimeServer.mesa, HGM, 4-Nov-84 8:57:47
DIRECTORY
AddressTranslation USING [Error, PrintError, StringToNetworkAddress],
Format USING [StringProc],
FormSW USING [
AllocateItemDescriptor, ClientItemsProcType, CommandItem, ItemHandle, newLine,
ProcType, StringItem],
Heap USING [systemZone],
MsgSW USING [Post],
Put USING [Char, CR, Date, Decimal, Line, LongDecimal, NetworkAddress, Text],
Runtime USING [GetBcdTime],
String USING [AppendString],
System USING [
GetClockPulses, GetGreenwichMeanTime, gmtEpoch, GreenwichMeanTime,
NetworkAddress, nullNetworkAddress, nullSocketNumber,
Pulses, PulsesToMicroseconds, SocketNumber],
Time USING [Append, Packed, Unpack],
Tool USING [
Create, UnusedLogName, MakeFormSW, MakeFileSW, MakeMsgSW, MakeSWsProc],
ToolWindow USING [TransitionProcType],
Unformat USING [Error, NetworkAddress],
Window USING [Handle],
Buffer USING [NSBuffer],
NSConstants USING [timeServerSocket],
NSTypes USING [wordsPerExchangeHeader],
PacketExchange USING [
CreateRequestor, Delete, Error, ExchangeClientType, ExchangeHandle, SendRequest],
Socket USING [
AssignNetworkAddress, BroadcastAddressFromSocket, ChannelHandle, Create,
Delete, GetPacket, GetPacketBytes, GetSendBuffer, GetSource, PutPacket,
BroadcastPacketToAllConnectedNets, ReturnBuffer, SetDestination, SetPacketWords,
SetWaitTime, TimeOut],
TimeServerFormat USING [TSPacket, Version, WireToGMT, WireToLong],
TimeServerFormatOld USING [request, response, TimeFormat],
WireFormat USING [WireLongNumber, WireToMesaLongNumber];
TestTimeServer: PROGRAM
IMPORTS
AddressTranslation, FormSW, Heap, MsgSW, Put,
Runtime, String, System, Time, Tool, Unformat,
PacketExchange, Socket,
TimeServerFormat, WireFormat =
BEGIN
z: UNCOUNTED ZONE = Heap.systemZone;
-- global variable declarations
msg, log, form: Window.Handle ← NIL;
remoteAddress: LONG STRING ← NIL;
localAddr: System.NetworkAddress;
version: WORD = TimeServerFormat.Version;
Init: PROCEDURE =
BEGIN
herald: STRING = [100];
String.AppendString[herald, "TestTimeServer of "L];
Time.Append[herald, Time.Unpack[Runtime.GetBcdTime[]]];
[] ← Tool.Create[
name: herald, makeSWsProc: MakeSWs, clientTransition: Transition];
END;
MakeSWs: Tool.MakeSWsProc =
BEGIN
logFileName: STRING = [40];
msg ← Tool.MakeMsgSW[window: window, lines: 1];
form ← Tool.MakeFormSW[window: window, formProc: MakeItemArray];
Tool.UnusedLogName[logFileName, "TestTimeServer.log$"L];
log ← Tool.MakeFileSW[window: window, name: logFileName];
END;
MakeItemArray: FormSW.ClientItemsProcType =
BEGIN
nItems: CARDINAL = 8;
i: INTEGER ← -1;
items ← FormSW.AllocateItemDescriptor[nItems];
items[i ← i + 1] ← FormSW.CommandItem[
tag: "Statistics"L, place: FormSW.newLine, proc: Statistics];
items[i ← i + 1] ← FormSW.StringItem[
tag: "RemoteAddress"L, string: @remoteAddress, inHeap: TRUE];
items[i ← i + 1] ← FormSW.CommandItem[
tag: "PEXLocalBroadcast"L, place: FormSW.newLine, proc: PEXLocalBroadcast];
items[i ← i + 1] ← FormSW.CommandItem[tag: "PEXAskRemote"L, proc: PEXAskRemote];
items[i ← i + 1] ← FormSW.CommandItem[
tag: "LocalBroadcast"L, place: FormSW.newLine, proc: LocalBroadcast];
items[i ← i + 1] ← FormSW.CommandItem[tag: "AskRemote"L, proc: AskRemote];
items[i ← i + 1] ← FormSW.CommandItem[
tag: "OldLocalBroadcast"L, place: FormSW.newLine, proc: OldLocalBroadcast];
items[i ← i + 1] ← FormSW.CommandItem[tag: "OldAskRemote"L, proc: OldAskRemote];
IF (i + 1) # nItems THEN ERROR;
RETURN[items, TRUE];
END;
Transition: ToolWindow.TransitionProcType =
BEGIN
SELECT TRUE FROM
old = inactive =>
BEGIN
localAddr ← Socket.AssignNetworkAddress[];
remoteAddress ← z.NEW[StringBody[40]];
String.AppendString[remoteAddress, "0#*#"L];
END;
new = inactive =>
BEGIN z.FREE[@remoteAddress]; END;
ENDCASE => NULL;
END;
Statistics: FormSW.ProcType =
BEGIN
wordsInRequest: CARDINAL = SIZE[statisticRequest TimeServerFormat.TSPacket];
wordsInAnswer: CARDINAL = SIZE[statisticResponse TimeServerFormat.TSPacket];
request: LONG POINTER TO statisticRequest TimeServerFormat.TSPacket;
answer: LONG POINTER TO statisticResponse TimeServerFormat.TSPacket;
him: System.NetworkAddress;
soc: Socket.ChannelHandle;
b: Buffer.NSBuffer;
errFlag, hit: BOOLEAN ← FALSE;
MsgSW.Post[msg, ""L];
him ← GetAddress[remoteAddress, NSConstants.timeServerSocket !
Trouble =>
BEGIN
Put.Line[msg, reason];
errFlag ← TRUE;
CONTINUE;
END];
IF errFlag THEN RETURN;
MsgSW.Post[msg, "Here we go...."L];
Put.CR[log];
Put.Line[log, "Statistics.."L];
soc ← Socket.Create[local: localAddr, receive: 10];
Socket.SetWaitTime[soc, 5000]; -- milli-seconds
FOR i: CARDINAL IN [0..10) UNTIL hit DO
b ← Socket.GetSendBuffer[soc];
Socket.SetDestination[b, him];
b.ns.packetType ← packetExchange;
b.ns.exchangeID ← [1, 1];
b.ns.exchangeType ← timeService;
request ← LOOPHOLE[@b.ns.exchangeBody];
request↑ ← [version, statisticRequest[]];
Socket.SetPacketWords[b, NSTypes.wordsPerExchangeHeader + wordsInRequest];
Socket.PutPacket[soc, b];
DO
b ← Socket.GetPacket[
soc ! Socket.TimeOut => BEGIN IF ~hit THEN Put.Char[log, '?]; EXIT; END];
answer ← LOOPHOLE[@b.ns.exchangeBody];
SELECT TRUE FROM
b.ns.packetType # packetExchange
OR Socket.GetPacketBytes[b] # 2*(NSTypes.wordsPerExchangeHeader + wordsInAnswer)
OR (b.ns.exchangeType # timeService)
OR answer.version # version
OR answer.type # statisticResponse =>
BEGIN Put.Char[log, '#]; END;
ENDCASE =>
BEGIN -- the response we were looking for
hit ← TRUE;
PrintStatistics[answer, Socket.GetSource[b]];
END;
Socket.ReturnBuffer[b];
ENDLOOP;
ENDLOOP;
Put.CR[log];
Socket.Delete[soc];
MsgSW.Post[msg, "OK"L];
END;
PEXLocalBroadcast: FormSW.ProcType =
BEGIN
handle: PacketExchange.ExchangeHandle;
him: System.NetworkAddress;
bytesInRequest: CARDINAL = 2*SIZE[timeRequest TimeServerFormat.TSPacket];
bytesInAnswer: CARDINAL = 2*SIZE[timeResponse TimeServerFormat.TSPacket];
request: timeRequest TimeServerFormat.TSPacket ← [version, timeRequest[]];
answer: timeResponse TimeServerFormat.TSPacket;
bytes: CARDINAL;
response: PacketExchange.ExchangeClientType;
MsgSW.Post[msg, "Here we go...."L];
Put.CR[log];
Put.Line[log, "PEX Local Broadcast.."L];
handle ← PacketExchange.CreateRequestor[10000, 2000];
him ← Socket.BroadcastAddressFromSocket[
NSConstants.timeServerSocket];
BEGIN
start, stop: System.Pulses;
start ← System.GetClockPulses[];
[bytes, response] ← PacketExchange.SendRequest[
handle,
him,
[LOOPHOLE[LONG[@request]], 0, bytesInRequest],
[LOOPHOLE[LONG[@answer]], 0, bytesInAnswer],
timeService !
PacketExchange.Error =>
BEGIN
SELECT why FROM
timeout => Put.Line[log, "Timeout."L];
ENDCASE => Put.Line[log, "Strange error type."L];
GOTO Rejected;
END ];
SELECT TRUE FROM
bytes # bytesInAnswer => Put.Line[log, "Wrong size response."L];
response # timeService => Put.Line[log, "Wrong type response."L];
answer.version # version => Put.Line[log, "Wrong version."L];
ENDCASE =>
BEGIN
local: System.GreenwichMeanTime ← System.GetGreenwichMeanTime[];
delay: LONG CARDINAL;
stop ← System.GetClockPulses[];
delay ← System.PulsesToMicroseconds[[stop-start]]/1000;
PrintAnswer[@answer, System.nullNetworkAddress, local, delay];
END;
EXITS Rejected => NULL;
END;
PacketExchange.Delete[handle];
MsgSW.Post[msg, "OK"L];
END;
PEXAskRemote: FormSW.ProcType =
BEGIN
errFlag: BOOLEAN ← FALSE;
handle: PacketExchange.ExchangeHandle;
him: System.NetworkAddress;
bytesInRequest: CARDINAL = 2*SIZE[timeRequest TimeServerFormat.TSPacket];
bytesInAnswer: CARDINAL = 2*SIZE[timeResponse TimeServerFormat.TSPacket];
request: timeRequest TimeServerFormat.TSPacket ← [version, timeRequest[]];
answer: timeResponse TimeServerFormat.TSPacket;
bytes: CARDINAL;
response: PacketExchange.ExchangeClientType;
him ← GetAddress[remoteAddress, NSConstants.timeServerSocket !
Trouble =>
BEGIN
Put.Text[msg, "AddressTranslation troubles: "L];
Put.Line[msg, reason];
errFlag ← TRUE;
CONTINUE;
END];
IF errFlag THEN RETURN;
MsgSW.Post[msg, "Here we go...."L];
Put.CR[log];
Put.Line[log, "PEX Ask Remote.."L];
handle ← PacketExchange.CreateRequestor[10000, 2000];
BEGIN
start, stop: System.Pulses;
start ← System.GetClockPulses[];
[bytes, response] ← PacketExchange.SendRequest[
handle,
him,
[LOOPHOLE[LONG[@request]], 0, bytesInRequest],
[LOOPHOLE[LONG[@answer]], 0, bytesInAnswer],
timeService !
PacketExchange.Error =>
BEGIN
SELECT why FROM
timeout => Put.Line[log, "Timeout."L];
ENDCASE => Put.Line[log, "Strange error type."L];
GOTO Rejected;
END ];
SELECT TRUE FROM
bytes # bytesInAnswer => Put.Line[log, "Wrong size response."L];
response # timeService => Put.Line[log, "Wrong type response."L];
answer.version # version => Put.Line[log, "Wrong version."L];
ENDCASE =>
BEGIN
local: System.GreenwichMeanTime ← System.GetGreenwichMeanTime[];
delay: LONG CARDINAL;
stop ← System.GetClockPulses[];
delay ← System.PulsesToMicroseconds[[stop-start]]/1000;
PrintAnswer[@answer, System.nullNetworkAddress];
END;
EXITS Rejected => NULL;
END;
PacketExchange.Delete[handle];
MsgSW.Post[msg, "OK"L];
END;
LocalBroadcast: FormSW.ProcType =
BEGIN
wordsInRequest: CARDINAL = SIZE[timeRequest TimeServerFormat.TSPacket];
wordsInAnswer: CARDINAL = SIZE[timeResponse TimeServerFormat.TSPacket];
request: LONG POINTER TO timeRequest TimeServerFormat.TSPacket;
answer: LONG POINTER TO timeResponse TimeServerFormat.TSPacket;
soc: Socket.ChannelHandle;
b: Buffer.NSBuffer;
him: System.NetworkAddress;
hit: BOOLEAN ← FALSE;
MsgSW.Post[msg, "Here we go...."L];
Put.CR[log];
Put.Line[log, "Local Broadcast.."L];
soc ← Socket.Create[local: localAddr, receive: 10];
Socket.SetWaitTime[soc, 5000]; -- milli-seconds
him ← Socket.BroadcastAddressFromSocket[
NSConstants.timeServerSocket];
FOR i: CARDINAL IN [0..10) UNTIL hit DO
start, stop: System.Pulses;
b ← Socket.GetSendBuffer[soc];
Socket.SetDestination[b, him];
b.ns.packetType ← packetExchange;
b.ns.exchangeID ← [1, 1];
b.ns.exchangeType ← timeService;
request ← LOOPHOLE[@b.ns.exchangeBody];
request↑ ← [version, timeRequest[]];
Socket.SetPacketWords[b, NSTypes.wordsPerExchangeHeader + wordsInRequest];
start ← System.GetClockPulses[];
Socket.BroadcastPacketToAllConnectedNets[soc, b];
DO
b ← Socket.GetPacket[
soc ! Socket.TimeOut => BEGIN IF ~hit THEN Put.Char[log, '?]; EXIT; END];
answer ← LOOPHOLE[@b.ns.exchangeBody];
SELECT TRUE FROM
b.ns.packetType # packetExchange
OR Socket.GetPacketBytes[b] # 2*(NSTypes.wordsPerExchangeHeader + wordsInAnswer)
OR (b.ns.exchangeType # timeService)
OR answer.version # version
OR answer.type # timeResponse =>
BEGIN Put.Char[log, '#]; END;
ENDCASE =>
BEGIN -- the response we were looking for
local: System.GreenwichMeanTime ← System.GetGreenwichMeanTime[];
delay: LONG CARDINAL;
stop ← System.GetClockPulses[];
delay ← System.PulsesToMicroseconds[[stop-start]]/1000;
PrintAnswer[answer, Socket.GetSource[b], local, delay];
hit ← TRUE;
END;
Socket.ReturnBuffer[b];
ENDLOOP;
ENDLOOP;
Put.CR[log];
Socket.Delete[soc];
MsgSW.Post[msg, "OK"L];
END;
AskRemote: FormSW.ProcType =
BEGIN
wordsInRequest: CARDINAL = SIZE[timeRequest TimeServerFormat.TSPacket];
wordsInAnswer: CARDINAL = SIZE[timeResponse TimeServerFormat.TSPacket];
request: LONG POINTER TO timeRequest TimeServerFormat.TSPacket;
answer: LONG POINTER TO timeResponse TimeServerFormat.TSPacket;
him: System.NetworkAddress;
soc: Socket.ChannelHandle;
b: Buffer.NSBuffer;
errFlag, hit: BOOLEAN ← FALSE;
MsgSW.Post[msg, ""L];
him ← GetAddress[remoteAddress, NSConstants.timeServerSocket !
Trouble =>
BEGIN
Put.Text[msg, "AddressTranslation troubles: "L];
Put.Line[msg, reason];
errFlag ← TRUE;
CONTINUE;
END];
IF errFlag THEN RETURN;
MsgSW.Post[msg, "Here we go...."L];
Put.CR[log];
Put.Line[log, "Ask Remote.."L];
soc ← Socket.Create[local: localAddr, receive: 10];
Socket.SetWaitTime[soc, 5000]; -- milli-seconds
FOR i: CARDINAL IN [0..10) UNTIL hit DO
start, stop: System.Pulses;
b ← Socket.GetSendBuffer[soc];
Socket.SetDestination[b, him];
b.ns.packetType ← packetExchange;
b.ns.exchangeID ← [1, 1];
b.ns.exchangeType ← timeService;
request ← LOOPHOLE[@b.ns.exchangeBody];
request↑ ← [version, timeRequest[]];
Socket.SetPacketWords[b, NSTypes.wordsPerExchangeHeader + wordsInRequest];
start ← System.GetClockPulses[];
Socket.PutPacket[soc, b];
DO
b ← Socket.GetPacket[
soc ! Socket.TimeOut => BEGIN IF ~hit THEN Put.Char[log, '?]; EXIT; END];
answer ← LOOPHOLE[@b.ns.exchangeBody];
SELECT TRUE FROM
b.ns.packetType # packetExchange
OR Socket.GetPacketBytes[b] # 2*(NSTypes.wordsPerExchangeHeader + wordsInAnswer)
OR (b.ns.exchangeType # timeService)
OR answer.version # version
OR answer.type # timeResponse =>
BEGIN Put.Char[log, '#]; END;
ENDCASE =>
BEGIN -- the response we were looking for
local: System.GreenwichMeanTime ← System.GetGreenwichMeanTime[];
delay: LONG CARDINAL;
stop ← System.GetClockPulses[];
delay ← System.PulsesToMicroseconds[[stop-start]]/1000;
PrintAnswer[answer, Socket.GetSource[b], local, delay];
hit ← TRUE;
END;
Socket.ReturnBuffer[b];
ENDLOOP;
ENDLOOP;
Put.CR[log];
Socket.Delete[soc];
MsgSW.Post[msg, "OK"L];
END;
OldLocalBroadcast: FormSW.ProcType =
BEGIN
soc: Socket.ChannelHandle;
b: Buffer.NSBuffer;
him: System.NetworkAddress;
hit: BOOLEAN ← FALSE;
MsgSW.Post[msg, "Here we go...."L];
Put.CR[log];
Put.Line[log, "Old Local Broadcast.."L];
soc ← Socket.Create[local: localAddr, receive: 10];
Socket.SetWaitTime[soc, 5000]; -- milli-seconds
him ← Socket.BroadcastAddressFromSocket[
NSConstants.timeServerSocket];
FOR i: CARDINAL IN [0..10) UNTIL hit DO
b ← Socket.GetSendBuffer[soc];
Socket.SetDestination[b, him];
b.ns.packetType ← echo;
b.ns.nsWords[0] ← b.ns.nsWords[1] ← i;
b.ns.nsWords[2] ← TimeServerFormatOld.request;
Socket.SetPacketWords[b, 3];
Socket.BroadcastPacketToAllConnectedNets[soc, b];
DO
b ← Socket.GetPacket[
soc ! Socket.TimeOut => BEGIN IF ~hit THEN Put.Char[log, '?]; EXIT; END];
SELECT TRUE FROM
Socket.GetPacketBytes[b] # 2*(3 + SIZE[TimeServerFormatOld.TimeFormat])
OR (b.ns.nsWords[2] # TimeServerFormatOld.response) =>
BEGIN Put.Char[log, '#]; END;
ENDCASE =>
BEGIN -- the response we were looking for
PrintOldAnswer[LOOPHOLE[@b.ns.nsWords[3]], Socket.GetSource[b]];
hit ← TRUE;
END;
Socket.ReturnBuffer[b];
ENDLOOP;
ENDLOOP;
Put.CR[log];
Socket.Delete[soc];
MsgSW.Post[msg, "OK"L];
END;
OldAskRemote: FormSW.ProcType =
BEGIN
him: System.NetworkAddress;
soc: Socket.ChannelHandle;
b: Buffer.NSBuffer;
errFlag, hit: BOOLEAN ← FALSE;
MsgSW.Post[msg, ""L];
him ← GetAddress[remoteAddress, NSConstants.timeServerSocket !
Trouble =>
BEGIN
Put.Text[msg, "AddressTranslation troubles: "L];
Put.Line[msg, reason];
errFlag ← TRUE;
CONTINUE;
END];
IF errFlag THEN RETURN;
MsgSW.Post[msg, "Here we go...."L];
Put.CR[log];
Put.Line[log, "Old Ask Remote.."L];
soc ← Socket.Create[local: localAddr, receive: 10];
Socket.SetWaitTime[soc, 5000]; -- milli-seconds
FOR i: CARDINAL IN [0..10) UNTIL hit DO
b ← Socket.GetSendBuffer[soc];
Socket.SetDestination[b, him];
b.ns.packetType ← echo;
b.ns.nsWords[0] ← b.ns.nsWords[1] ← i;
b.ns.nsWords[2] ← TimeServerFormatOld.request;
Socket.SetPacketWords[b, 3];
Socket.PutPacket[soc, b];
DO
b ← Socket.GetPacket[
soc ! Socket.TimeOut => BEGIN IF ~hit THEN Put.Char[log, '?]; EXIT; END];
SELECT TRUE FROM
Socket.GetPacketBytes[b] # 2*(3 + SIZE[TimeServerFormatOld.TimeFormat])
OR (b.ns.nsWords[2] # TimeServerFormatOld.response) =>
BEGIN Put.Char[log, '#]; END;
ENDCASE =>
BEGIN -- the response we were looking for
hit ← TRUE;
PrintOldAnswer[LOOPHOLE[@b.ns.nsWords[3]], Socket.GetSource[b]];
END;
Socket.ReturnBuffer[b];
ENDLOOP;
ENDLOOP;
Put.CR[log];
Socket.Delete[soc];
MsgSW.Post[msg, "OK"L];
END;
PrintStatistics: PROCEDURE [
stats: LONG POINTER TO statisticResponse TimeServerFormat.TSPacket,
who: System.NetworkAddress] =
BEGIN
when: Time.Packed ← LOOPHOLE[TimeServerFormat.WireToGMT[stats.timeSet]];
IF who # System.nullNetworkAddress THEN
BEGIN
Put.Text[log, "Response from: "L];
Put.NetworkAddress[log, who];
Put.CR[log];
END;
Put.Text[log, "Requests: "L];
Put.LongDecimal[log, TimeServerFormat.WireToLong[stats.numberRequests]];
Put.Text[log, ", Active: "L];
Put.Text[log, IF stats.active THEN "TRUE"L ELSE "FALSE"L];
Put.Text[log, ", Resetting: "L];
Put.Text[log, IF stats.resetting THEN "TRUE"L ELSE "FALSE"L];
Put.CR[log];
Put.Text[log, "Time Last Set: "L];
Put.Date[log, when, full];
Put.Text[log, ", Last change: "L];
Put.LongDecimal[log, TimeServerFormat.WireToLong[stats.lastChange]];
Put.CR[log];
IF stats.source # System.nullNetworkAddress THEN
BEGIN
Put.Text[log, "Reset From: "L];
Put.NetworkAddress[log, stats.source];
Put.CR[log];
END;
END;
PrintAnswer: PROCEDURE [
wtf: LONG POINTER TO timeResponse TimeServerFormat.TSPacket,
who: System.NetworkAddress,
local: System.GreenwichMeanTime ← System.gmtEpoch,
flight: LONG CARDINAL ← 0] =
BEGIN
remote: Time.Packed ← LOOPHOLE[TimeServerFormat.WireToGMT[wtf.time]];
IF who # System.nullNetworkAddress THEN
BEGIN
Put.Text[log, "Response from: "L];
Put.NetworkAddress[log, who];
Put.CR[log];
END;
Put.Text[log, "Time: "L];
Put.Date[log, remote, full];
Put.Text[log, ", Zone: "L];
Put.Text[
log, SELECT wtf.zoneS FROM west => "W"L, east => "E"L, ENDCASE => ERROR];
Put.Decimal[log, wtf.zoneH];
Put.Char[log, ':];
Put.Decimal[log, wtf.zoneM];
Put.Text[log, ", DST: "L];
Put.Decimal[log, wtf.beginDST];
Put.Text[log, ", "L];
Put.Decimal[log, wtf.endDST];
Put.CR[log];
IF local # System.gmtEpoch THEN
BEGIN
delta: LONG INTEGER = remote - local;
Put.Text[log, "His clock is "L];
Put.LongDecimal[log, delta];
Put.Line[log, " seconds faster than ours."L];
END;
IF wtf.errorAccurate THEN
BEGIN
Put.Text[log, "Error is less than "L];
Put.LongDecimal[log, TimeServerFormat.WireToLong[wtf.absoluteError]];
Put.Line[log, " ms."L];
END;
IF flight # 0 THEN
BEGIN
Put.Text[log, "The flight time was "L];
Put.LongDecimal[log, flight];
Put.Line[log, " ms."L];
END;
END;
PrintOldAnswer: PROCEDURE [
wtf: LONG POINTER TO TimeServerFormatOld.TimeFormat,
who: System.NetworkAddress] =
BEGIN
now: Time.Packed ← LOOPHOLE[WireFormat.WireToMesaLongNumber[wtf.time]];
IF who # System.nullNetworkAddress THEN
BEGIN
Put.Text[log, "Response from: "L];
Put.NetworkAddress[log, who];
Put.CR[log];
END;
Put.Text[log, "Time: "L];
Put.Date[log, now, full];
Put.Text[log, ", Zone: "L];
Put.Text[
log, SELECT wtf.zoneS FROM west => "W"L, east => "E"L, ENDCASE => ERROR];
Put.Decimal[log, wtf.zoneH];
Put.Char[log, ':];
Put.Decimal[log, wtf.zoneM];
Put.Text[log, ", DST: "L];
Put.Decimal[log, wtf.beginDST];
Put.Text[log, ", "L];
Put.Decimal[log, wtf.endDST];
Put.CR[log];
END;
Trouble: ERROR [reason: LONG STRING] = CODE;
GetAddress: PROCEDURE [host: LONG STRING, socket: System.SocketNumber]
RETURNS [addr: System.NetworkAddress] =
BEGIN
localFailed: BOOLEAN ← FALSE;
IF host = NIL THEN ERROR Trouble["NIL => Address Fault"L];
addr ← Unformat.NetworkAddress[host, octal !
Unformat.Error => BEGIN localFailed ← TRUE; CONTINUE; END ];
IF localFailed THEN
BEGIN
addr ← AddressTranslation.StringToNetworkAddress[host !
AddressTranslation.Error =>
BEGIN
temp: STRING = [200];
proc: Format.StringProc = {String.AppendString[temp, s]};
AddressTranslation.PrintError[errorRecord, proc];
ERROR Trouble[temp];
END].addr;
addr.socket ← socket; -- CH returns trash in socket
END;
IF addr.socket = System.nullSocketNumber THEN addr.socket ← socket;
END;
Init[];
END...