Jump to content
ertank

Internet time sync - with some timeout

Recommended Posts

Hello,

 

I have following code running in a thread when application starts.

procedure TMainForm.SetSystemTime();
var
  Sntp: TIdSNTP;
begin
  Sntp := TIdSNTP.Create(nil);
  try
    Sntp.Host := 'pool.ntp.org';
    try
      Sntp.SyncTime();
    except
      // eat exception, we are in thread
    end;
  finally
    Sntp.Free();
  end;
end;

When there is no internet connection, thread above code runs is never terminated. I could not find some connection timeout setting for IdSNTP.

 

Is there any other way to terminate Sntp.SyncTime() if it is not completed for a certain period of time like 10 seconds.

 

There is a location with a corporate firewall (with some weird settings I believe) where check for an internet connection is true, but above code still hangs.

 

Thanks & Regards,

Ertan

Share this post


Link to post

TIdSNTP.ReceiveTimeout defaults to IdTimeoutInfinite; (-2).

Try setting it to the desired timeout interval in milliseconds?

Share this post


Link to post

I forgot to mention in my initial post that I have already tried to change ReceiveTimeout to 2000 with no success. Sorry about that.

Since ReceiveTimeout did not work that makes me believe there is a kind of a problem like privilege or initial connection. I do not know though. I cannot access to computers in that location for better understanding.

Share this post


Link to post

I just read it. Thanks for sharing.

 

It seems similar. But, in this thread, code continues and not hangs like in my case. If I had same problem, thread would terminate without clock being synced. My problem is thread not terminating.

 

One additional information I should share is that procedure is threaded using ITask like below.

uses
  System.Threading,
  uUtils.Log;

procedure TForm2.FormCreate(Sender: TObject);
var
  Task: ITask;
begin
  Log('Creating thread');
  Task := TTask.Create(SetSystemTime);
  Task.Start();
  Log('Thread started');
end;

procedure TForm2.IdSNTP1Connected(Sender: TObject);
begin
  Log('SNTP Connected');
end;

procedure TForm2.IdSNTP1Disconnected(Sender: TObject);
begin
  Log('SNTP Disconnected');
end;

procedure TForm2.IdSNTP1Status(ASender: TObject; const AStatus: TIdStatus;
  const AStatusText: string);
begin
  Log('SNTP status: ' + AStatusText);
end;

procedure TForm2.SetSystemTime();
var
  Sntp: TIdSNTP;
begin
  Log('SetSystemTime(): System clock sync starting');
  Sntp := TIdSNTP.Create(nil);
  try
    Sntp.OnConnected := IdSNTP1Connected;
    Sntp.OnDisconnected := IdSNTP1Disconnected;
    Sntp.OnStatus := IdSNTP1Status;
    Sntp.Host := 'pool.ntp.org';
    Sntp.ReceiveTimeout := 2000;
    try
      Log('SetSystemTime(): Running actual time sync...');
      Sntp.SyncTime();
      Log('SetSystemTime(): System clock sync completed');
    except
      on E: Exception do
      begin
        Log('SetSystemTime(): ' + E.Message);
      end;
    end;
  finally
    Sntp.Free();
  end;
  Log('SetSystemTime(): Done');
end;

That code sample is from a project that I am preparing with detailed logging to help identifying the problem.

 

That code running on my system produces with following lines:

2021-01-20 14:56:58.949  Creating thread
2021-01-20 14:56:58.952  Thread started
2021-01-20 14:56:58.953  SetSystemTime(): System clock sync starting
2021-01-20 14:56:58.953  SetSystemTime(): Running actual time sync...
2021-01-20 14:56:59.067  SetSystemTime(): System clock sync completed
2021-01-20 14:56:59.068  SetSystemTime(): Done

As you can see, there is no connection or disconnection here. Problem might be privilege but, this should not hang whole thread and should just exit from it.

 

BTW, I just learned (by chance talking to a colleague) that problem occurs only on Windows 10 OSes and not on Windows 7 or Windows XP.

Share this post


Link to post

So - on the problem system - the log stops before "sync completed" ?

Is the process running elevated?

Is there anything in the windows logs?

What about the local firewall settings on the problem PC - does it allow UDP through?

 

Share this post


Link to post

I was forced to throw out my own timesync service on Windows when servers my apps are running on were joined to domain. Even with allowing domain policy I couldn't get time changing working. So first check if your app is able to change time at all (just call SetSystemTime without any network requests).

Share this post


Link to post
4 hours ago, ertank said:

My problem is thread not terminating.

But WHERE is it hanging exactly?  You need to determine that.  Is it on the actual transmission of the request packet?  On the receiving of the response packet?  On the setting of the PC clock?  Your code is calling only 1 method (SyncTime), but that method does multiple things internally, so there are multiple points of failure.  Have you tried to use a packet sniffer, like Wireshark, to make sure the SNTP request is actually being sent, and an SNTP response is being received?

4 hours ago, ertank said:

As you can see, there is no connection or disconnection here.

That is because SNTP runs over UDP, so there is no connection, like you are thinking of.  A UDP socket can be "connected" to a remote peer by assigning the peer's IP address statically to the UDP socket, thus sends/receives via that socket will interact only with that particular IP.  But that is optional.  Your code is not calling the TIdSNTP.Connect() method to establish such a static association, which is why you are not seeing the OnConnected/OnDisconnected events being fired.  By default, TIdSNTP will simply write a datagram to the network and then wait for a responding datagram to come back from any peer to TIdSNTP's sending port, which is usually fine in most cases.

Share this post


Link to post

Thank you to all.

 

My request to have access to problematic computer will not be possible until March 15 due to Covid-19 close down.

 

I will be able to do further analysis after I do have access.

Edited by ertank

Share this post


Link to post

You might also want to test the success of SyncTime..

...
....
      if Sntp.SyncTime() then
      Log('SetSystemTime(): System clock sync completed')
      else
      Log('SetSystemTime(): System clock sync failed');
....
....

It fails on my Win 10 PC and on a 2012 Server.

It is OK if the App is run as Administrator.

 

I wonder if there is a way to have just the routine run at elevated level???

 

Ian

Edited by Ian Branch

Share this post


Link to post
12 hours ago, Ian Branch said:

I wonder if there is a way to have just the routine run at elevated level???

That would require moving the routine into a separate process or COM object that can then run elevated.

 

Share this post


Link to post

Hi Remy,

Ahh.  Thank you.  At least I know it is possible. :-)

Pardon my ignorance but which would be the easiest to achieve?

Without giving me the answer, can you point me where to look?

Regards,

Ian

Share this post


Link to post
3 hours ago, Ian Branch said:

Pardon my ignorance but which would be the easiest to achieve?

Starting a new elevated process can be done using the Win32 API ShellExecute/Ex() with the "runas" verb.

 

Instantiating an elevated COM object can be done using the COM Elevation Moniker.

 

 

Share this post


Link to post

Hi Remy,

Ahhh.  I see it now.  Didn't think at all of a separate App.

Regards & Tks.

Ian

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×