-- Copyright (C) 1984, 1985  by Xerox Corporation. All rights reserved. 
-- OthelloOpsTime.mesa, HGM,  3-Jul-85  0:57:47

DIRECTORY
  Buffer USING [NSBuffer],
  Environment,
  NSConstants USING [timeServerSocket],
  NSTypes USING [wordsPerExchangeHeader],
  OthelloOps USING [TimeServerErrorType],
  ProcessorFace USING [GreenwichMeanTime, SetGreenwichMeanTime],
  Socket USING [
    BroadcastAddressFromSocket, ChannelHandle,
    Create, Delete, GetPacket, GetPacketBytes, GetSendBuffer,
    BroadcastPacketToAllConnectedNets, ReturnBuffer, SetDestination,
    SetPacketWords, SetWaitTime, TimeOut],
  System USING [
    gmtEpoch, GetGreenwichMeanTime, GreenwichMeanTime,
    LocalTimeParameters, NetworkAddress, nullSocketNumber, WestEast],
  TimeServerFormat USING [TSPacket, WireToGMT, Version];

OthelloOpsTime: PROGRAM
  IMPORTS ProcessorFace, Socket, System, TimeServerFormat
  EXPORTS OthelloOps =
  BEGIN


  IsTimeValid: PUBLIC PROC RETURNS [valid: BOOLEAN] = {
    RETURN[System.GetGreenwichMeanTime[]#System.gmtEpoch]};
    
  SetProcessorTime: PUBLIC PROC [time: System.GreenwichMeanTime] = {
    ProcessorFace.SetGreenwichMeanTime[time]};
    
  TimeServerError: PUBLIC ERROR [error: OthelloOps.TimeServerErrorType] = CODE;
  
  GetTimeFromTimeServer: PUBLIC PROC RETURNS[
    serverTime: System.GreenwichMeanTime,
    serverLTPs: System.LocalTimeParameters] = {
    isValid:    BOOLEAN;
    [isValid, serverTime, serverLTPs] ← GetNSTime[];
    IF ~isValid THEN ERROR TimeServerError[noResponse];
    RETURN};
      
  GetNSTime: PROC RETURNS [
    valid: BOOLEAN ← FALSE, time: System.GreenwichMeanTime,
    ltp: System.LocalTimeParameters] =
    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;
    soc ← Socket.Create[socket: System.nullSocketNumber, receive: 1];
    Socket.SetWaitTime[soc, 700]; -- milli-seconds
    FOR i: CARDINAL IN [0..3) DO
      him: System.NetworkAddress ← Socket.BroadcastAddressFromSocket[
        NSConstants.timeServerSocket];
      b: Buffer.NSBuffer ← Socket.GetSendBuffer[soc];
      Socket.SetDestination[b, him];
      b.ns.packetType ← packetExchange;
      b.ns.exchangeID ← [0, i];
      b.ns.exchangeType ← timeService;
      request ← LOOPHOLE[@b.ns.exchangeBody];
      request↑ ← [TimeServerFormat.Version, timeRequest[]];
      Socket.SetPacketWords[b, NSTypes.wordsPerExchangeHeader + wordsInRequest];
      Socket.BroadcastPacketToAllConnectedNets[soc, b];
      DO
	b ← Socket.GetPacket[soc ! Socket.TimeOut => EXIT];
	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 # TimeServerFormat.Version
	  OR answer.type # timeResponse => NULL;
          ENDCASE =>
	    BEGIN OPEN t: LOOPHOLE[time, Environment.LongNumber];
	    valid ← TRUE;
	    time ← TimeServerFormat.WireToGMT[answer.time];
	    ltp ← [
	      zone: answer.zoneH,
	      direction: answer.zoneS,
	      zoneMinutes: answer.zoneM,
	      beginDST: answer.beginDST,
	      endDST: answer.endDST];
	    Socket.ReturnBuffer[b];
	    GOTO Done;
	    END;
        Socket.ReturnBuffer[b];
	ENDLOOP;
      REPEAT Done => NULL;
      ENDLOOP;
    Socket.Delete[soc];
    END;

  END....