-- Copyright (C) 1984, 1985 by Xerox Corporation. All rights reserved. -- TestTimeServer.mesa, HGM, 25-Jun-85 15:35:38 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 [ 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; 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 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[socket: System.nullSocketNumber, 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[socket: System.nullSocketNumber, 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[socket: System.nullSocketNumber, 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[socket: System.nullSocketNumber, 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[socket: System.nullSocketNumber, 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...