locked
socket plugin to access ntp server RRS feed

  • Question

  • User2148 posted

    @RyanDavis I'have take a look to your SocketForPcl plugin (I hope you are the author :)). I need to connect, via socket, to a ntp server. I've found this code that should works

        public static DateTime GetNetworkTime()
        {
            //default Windows time server
            const string ntpServer = "time.windows.com";
    
            // NTP message size - 16 bytes of the digest (RFC 2030)
            var ntpData = new byte[48];
    
            //Setting the Leap Indicator, Version Number and Mode values
            ntpData[0] = 0x1B; //LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)
    
            var addresses = Dns.GetHostEntry(ntpServer).AddressList;
    
            //The UDP port number assigned to NTP is 123
            var ipEndPoint = new IPEndPoint(addresses[0], 123);
            //NTP uses UDP
            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    
            socket.Connect(ipEndPoint);
    
            //Stops code hang if NTP is blocked
            socket.ReceiveTimeout = 3000;     
    
            socket.Send(ntpData);
            socket.Receive(ntpData);
            socket.Close();
    
            //Offset to get to the "Transmit Timestamp" field (time at which the reply 
            //departed the server for the client, in 64-bit timestamp format."
            const byte serverReplyTime = 40;
    
            //Get the seconds part
            ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);
    
            //Get the seconds fraction
            ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);
    
            //Convert From big-endian to little-endian
            intPart = SwapEndianness(intPart);
            fractPart = SwapEndianness(fractPart);
    
            var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
    
            //**UTC** time
            var networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds);
    
            return networkDateTime.ToLocalTime();
        }
    
        // stackoverflow.com/a/3294698/162671
        static uint SwapEndianness(ulong x)
        {
            return (uint) (((x & 0x000000ff) << 24) +
                           ((x & 0x0000ff00) << 8) +
                           ((x & 0x00ff0000) >> 8) +
                           ((x & 0xff000000) >> 24));
        }
    

    Is it possible to "translate " this code using your plugin? Can you help me ? Thanks Alessandro

    Tuesday, April 7, 2015 11:07 PM

All replies

  • User42871 posted

    Hi Alessandro,

    Yes, I am the author! You can use sockets-for-pcl for this with a few modifications to the original code. I'm assuming you are coding in a PCL, and you have installed sockets-for-pcl in your PCL class and your platform projects.

    Firstly, the method signature should be made async-friendly: csharp public static async Task<DateTime> GetNetworkTimeAsync()

    Then you should replace ```csharp var addresses = Dns.GetHostEntry(ntpServer).AddressList;

    //The UDP port number assigned to NTP is 123 var ipEndPoint = new IPEndPoint(addresses[0], 123); //NTP uses UDP var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

    socket.Connect(ipEndPoint);

    //Stops code hang if NTP is blocked socket.ReceiveTimeout = 3000;

    socket.Send(ntpData); socket.Receive(ntpData); socket.Close(); ```

    with

    ```csharp var tcs = new TaskCompletionSource(); using(var socket = new UdpSocketReceiver()) { socket.MessageReceived += async (sender, args) => { await socket.StopListeningAsync(); tcs.SetResult(args.ByteData); };

    await socket.StartListeningAsync(11000); // any free port >1000 will do await socket.SendToAsync(ntpData, ntpServer, 123);

    ntpData = await tcs.Task.TimeoutAfter(TimeSpan.FromSeconds(3)); } ```

    where TimeoutAfter is just an extension method on Task:

    ```csharp public static class AsyncExtensions { public static async Task TimeoutAfter(this Task task, TimeSpan timeout, CancellationTokenSource cancellationTokenSource = null) { if (task == await Task.WhenAny(task, Task.Delay(timeout))) return await task; else { if (cancellationTokenSource != null) cancellationTokenSource.Cancel();

                throw new TimeoutException();
            }
        }
    }
    

    ```

    Of course - TimeoutAfter throws TimeoutException, so you should be ready for that in your calling code.

    I tested this with Xamarin Forms on Android and it worked fine.

    Hope that helps!

    Tuesday, April 7, 2015 11:57 PM
  • User3466 posted

    @AlessandroCaliaro: Thanks for getting this figured out; and @RyanDavis thanks for the great work on the sockets PCL.

    I created a small repro here (mostly so I would not loose the code and idea).

    Wednesday, April 8, 2015 7:04 PM
  • User2148 posted

    @MitchMilam thanks to you.

    Wednesday, April 8, 2015 7:14 PM
  • User2148 posted

    @RyanDavis Thanks a lot for your help

    Wednesday, April 8, 2015 7:15 PM
  • User2148 posted

    @RyanDavis, I'm trying to use @MitchMilam example, but I've 2 exception.

    One exception when wifi is down

        Unhandled Exception:
        [mono] System.ObjectDisposedException: The object was used after being disposed.
        [mono]   at System.Net.Sockets.UdpClient.CheckDisposed () [0x00000] in <filename unknown>:0 
        [mono]   at System.Net.Sockets.UdpClient.EndReceive (IAsyncResult asyncResult, System.Net.IPEndPoint& remoteEP) [0x00000] in <filename unknown>:0 
        [mono]   at System.Net.Sockets.UdpClient.<ReceiveAsync>m__0 (IAsyncResult r) [0x00000] in <filename unknown>:0 
        [mono]   at (wrapper delegate-invoke) System.Func`2<System.IAsyncResult, System.Net.Sockets.UdpReceiveResult>:invoke_TResult_T (System.IAsyncResult)
        [mono]   at System.Threading.Tasks.TaskFactory`1[System.Net.Sockets.UdpReceiveResult].InnerInvoke (System.Threading.Tasks.TaskCompletionSource`1 tcs, System.Func`2 endMethod, IAsyncResult l) [0x00000] in <filename unknown>:0 
        [mono] --- End of stack trace from previous location where exception was thrown ---
        [mono]   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x00000] in <filename unknown>:0 
        [mono]   at System.Runtime.CompilerServices.TaskAwaiter`1[System.Net.Sockets.UdpReceiveResult].GetResult () [0x00000] in <filename unknown>:0 
        [mono]   at Sockets.Plugin.UdpSocketBase+<RunMessageReceiver>d__0.MoveNext () [0x00030] in c:\Users\rdavis\Dropbox\code\Sockets\Sockets\Sockets.Implementation.NET\UdpSocketBase.cs:37 
    

    One exception when wifi is up and, after some good read from ntp server, i receive this:

        Unhandled Exception:
        [mono] System.ObjectDisposedException: The object was used after being disposed.
        [mono]   at System.Net.Sockets.UdpClient.CheckDisposed () [0x00000] in <filename unknown>:0 
        [mono]   at System.Net.Sockets.UdpClient.EndReceive (IAsyncResult asyncResult, System.Net.IPEndPoint& remoteEP) [0x00000] in <filename unknown>:0 
        [mono]   at System.Net.Sockets.UdpClient.<ReceiveAsync>m__0 (IAsyncResult r) [0x00000] in <filename unknown>:0 
        [mono]   at (wrapper delegate-invoke) System.Func`2<System.IAsyncResult, System.Net.Sockets.UdpReceiveResult>:invoke_TResult_T (System.IAsyncResult)
        [mono]   at System.Threading.Tasks.TaskFactory`1[System.Net.Sockets.UdpReceiveResult].InnerInvoke (System.Threading.Tasks.TaskCompletionSource`1 tcs, System.Func`2 endMethod, IAsyncResult l) [0x00000] in <filename unknown>:0 
        [mono] --- End of stack trace from previous location where exception was thrown ---
        [mono]   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x00000] in <filename unknown>:0 
        [mono]   at System.Runtime.CompilerServices.TaskAwaiter`1[System.Net.Sockets.UdpReceiveResult].GetResult () [0x00000] in <filename unknown>:0 
        [mono]   at Sockets.Plugin.UdpSocketBase+<RunMessageReceiver>d__0.MoveNext () [0x00030] in c:\Users\rdavis\Dropbox\code\Sockets\Sockets\Sockets.Implementation.NET\UdpSocketBase.cs:37 
        [OpenGLRenderer] prepareDirty (0.00, 0.00, 600.00, 976.00) opaque 1 <0x664bea88>
        [OpenGLRenderer] finish <0x664bea88>
        [libc] bionic/libstdc++/src/pure_virtual.cpp:6: void __cxa_pure_virtual(): assertion "!"Pure virtual function called. Are you calling virtual methods from a destructor?"" failed
        [libc] Fatal signal 6 (SIGABRT) at 0x00000d0d (code=-6), thread 3341 (ePresenze.Droid)
        [libc] Send stop signal to pid:3341 in void debuggerd_signal_handler(int, siginfo_t*, void*)
    

    Can you help me? Thanks

    Thursday, April 9, 2015 11:06 PM
  • User2148 posted

    @RyanDavis, I'm trying to use @MitchMilam example, but I've 2 exception.

    One exception when wifi is down

        Unhandled Exception:
        [mono] System.ObjectDisposedException: The object was used after being disposed.
        [mono]   at System.Net.Sockets.UdpClient.CheckDisposed () [0x00000] in <filename unknown>:0 
        [mono]   at System.Net.Sockets.UdpClient.EndReceive (IAsyncResult asyncResult, System.Net.IPEndPoint& remoteEP) [0x00000] in <filename unknown>:0 
        [mono]   at System.Net.Sockets.UdpClient.<ReceiveAsync>m__0 (IAsyncResult r) [0x00000] in <filename unknown>:0 
        [mono]   at (wrapper delegate-invoke) System.Func`2<System.IAsyncResult, System.Net.Sockets.UdpReceiveResult>:invoke_TResult_T (System.IAsyncResult)
        [mono]   at System.Threading.Tasks.TaskFactory`1[System.Net.Sockets.UdpReceiveResult].InnerInvoke (System.Threading.Tasks.TaskCompletionSource`1 tcs, System.Func`2 endMethod, IAsyncResult l) [0x00000] in <filename unknown>:0 
        [mono] --- End of stack trace from previous location where exception was thrown ---
        [mono]   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x00000] in <filename unknown>:0 
        [mono]   at System.Runtime.CompilerServices.TaskAwaiter`1[System.Net.Sockets.UdpReceiveResult].GetResult () [0x00000] in <filename unknown>:0 
        [mono]   at Sockets.Plugin.UdpSocketBase+<RunMessageReceiver>d__0.MoveNext () [0x00030] in c:\Users\rdavis\Dropbox\code\Sockets\Sockets\Sockets.Implementation.NET\UdpSocketBase.cs:37 
    

    One exception when wifi is up and, after some good read from ntp server, i receive this:

        Unhandled Exception:
        [mono] System.ObjectDisposedException: The object was used after being disposed.
        [mono]   at System.Net.Sockets.UdpClient.CheckDisposed () [0x00000] in <filename unknown>:0 
        [mono]   at System.Net.Sockets.UdpClient.EndReceive (IAsyncResult asyncResult, System.Net.IPEndPoint& remoteEP) [0x00000] in <filename unknown>:0 
        [mono]   at System.Net.Sockets.UdpClient.<ReceiveAsync>m__0 (IAsyncResult r) [0x00000] in <filename unknown>:0 
        [mono]   at (wrapper delegate-invoke) System.Func`2<System.IAsyncResult, System.Net.Sockets.UdpReceiveResult>:invoke_TResult_T (System.IAsyncResult)
        [mono]   at System.Threading.Tasks.TaskFactory`1[System.Net.Sockets.UdpReceiveResult].InnerInvoke (System.Threading.Tasks.TaskCompletionSource`1 tcs, System.Func`2 endMethod, IAsyncResult l) [0x00000] in <filename unknown>:0 
        [mono] --- End of stack trace from previous location where exception was thrown ---
        [mono]   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x00000] in <filename unknown>:0 
        [mono]   at System.Runtime.CompilerServices.TaskAwaiter`1[System.Net.Sockets.UdpReceiveResult].GetResult () [0x00000] in <filename unknown>:0 
        [mono]   at Sockets.Plugin.UdpSocketBase+<RunMessageReceiver>d__0.MoveNext () [0x00030] in c:\Users\rdavis\Dropbox\code\Sockets\Sockets\Sockets.Implementation.NET\UdpSocketBase.cs:37 
        [OpenGLRenderer] prepareDirty (0.00, 0.00, 600.00, 976.00) opaque 1 <0x664bea88>
        [OpenGLRenderer] finish <0x664bea88>
        [libc] bionic/libstdc++/src/pure_virtual.cpp:6: void __cxa_pure_virtual(): assertion "!"Pure virtual function called. Are you calling virtual methods from a destructor?"" failed
        [libc] Fatal signal 6 (SIGABRT) at 0x00000d0d (code=-6), thread 3341 (ePresenze.Droid)
        [libc] Send stop signal to pid:3341 in void debuggerd_signal_handler(int, siginfo_t*, void*)
    

    Can you help me? Thanks

    Thursday, April 9, 2015 11:06 PM
  • User42871 posted

    Hi @AlessandroCaliaro,

    Thanks for posting these. I've been away from my machine the last couple of days but should be able to take a look tonight/tomorrow!

    Saturday, April 11, 2015 9:28 PM
  • User2148 posted

    no problem @RyanDavis . I can say that the method to retrive NTP is inside a timer (it is called every X seconds)

    Saturday, April 11, 2015 9:54 PM
  • User42871 posted

    @AlessandroCaliaro I have pushed version 1.1.7 of sockets-for-pcl to NuGet; I think should address the problems you found.

    I have also added support to UdpSocketReceiver for delegating the choice of listening port to the operating system. Querying NTP time is definitely a situation in which you should take advantage of this. To do so, change

    csharp await socket.StartListeningAsync(11000); // any free port >1000 will do

    to

    csharp await socket.StartListeningAsync();

    @MitchMilam, can you update your sample with the above change?

    Sunday, April 12, 2015 4:44 AM
  • User3466 posted

    @AlessandroCaliaro, @RyanDavis done.

    Sunday, April 12, 2015 4:45 PM
  • User2148 posted

    @ryandavis, how are you? I'm here again for a "problem" accessing NTP. I'm using @MitchMilam example you have already worked for. The problem is: when , for some reason, I have no data from NTP server, the socket never goes in timeout, and it waits, and waits... In the log I have StartListening SendTo

    and nothing else...

    Can you help me? Thanks Alessandro

            using (var socket = new UdpSocketReceiver())
            {
                socket.MessageReceived += async (sender, args) =>
                {
                    await socket.StopListeningAsync();
                    tcs.SetResult(args.ByteData);
                };
    
                Debug.WriteLine ("StartListening " + DateTime.Now);
    
                await socket.StartListeningAsync(); // any free port >1000 will do 
    
                Debug.WriteLine ("SendTo " + DateTime.Now);
                await socket.SendToAsync(ntpData, ntpServer, 123);
    
                ntpData = await tcs.Task.TimeoutAfter(TimeSpan.FromSeconds(3));
            }
    
            //Offset to get to the "Transmit Timestamp" field (time at which the reply 
            //departed the server for the client, in 64-bit timestamp format."
            const byte serverReplyTime = 40;
    
            //Get the seconds part
            ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);
    
            //Get the seconds fraction
            ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);
    
            //Convert From big-endian to little-endian
            intPart = SwapEndianness(intPart);
            fractPart = SwapEndianness(fractPart);
    
            var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
    
            //**UTC** time
            var networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds);
    
            Debug.WriteLine ("Esco da GetNTP " + DateTime.Now);
            return networkDateTime.ToLocalTime();
    
    Friday, June 19, 2015 2:27 PM
  • User42871 posted

    Hi @AlessandroCaliaro, all is well thanks!

    First I would add a log statement after await socket.SendToAsync(ntpData, ntpServer, 123); to confirm that you are making it past that call. Then, it would be useful to just check the method signature and the location where you call this code. Can you include the full method that you have sampled above, and the full method of the caller (or at least the signature and the line where you call this code)?

    Sunday, June 21, 2015 3:43 AM
  • User2148 posted

    Thanks @RyanDavis for your answer. Correct, a "log" after SendToAsync is good. Anyway, the "log" before "return networkDateTime.ToLocalTime()" is not reached. If I remember correctly, I have had the problem only on Samsung galaxy s5

    public static class NtpClient
    {
        public static async Task<DateTime> GetNetworkTimeAsync()
        {
    
            Debug.WriteLine ("Entro in GetNTP " + DateTime.Now);
            //default Windows time server
            const string ntpServer = "time.windows.com";
    
            // NTP message size - 16 bytes of the digest (RFC 2030)
            var ntpData = new byte[48];
    
            //Setting the Leap Indicator, Version Number and Mode values
            ntpData[0] = 0x1B; //LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)
    
            var tcs = new TaskCompletionSource<byte[]>();
    
            using (var socket = new UdpSocketReceiver())
            {
                socket.MessageReceived += async (sender, args) =>
                {
                    await socket.StopListeningAsync();
                    tcs.SetResult(args.ByteData);
                };
    
                Debug.WriteLine ("StartListening " + DateTime.Now);
    
                await socket.StartListeningAsync(); // any free port >1000 will do 
    
                Debug.WriteLine ("SendTo " + DateTime.Now);
                await socket.SendToAsync(ntpData, ntpServer, 123);
    
                ntpData = await tcs.Task.TimeoutAfter(TimeSpan.FromSeconds(3));
            }
    
            //Offset to get to the "Transmit Timestamp" field (time at which the reply 
            //departed the server for the client, in 64-bit timestamp format."
            const byte serverReplyTime = 40;
    
            //Get the seconds part
            ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);
    
            //Get the seconds fraction
            ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);
    
            //Convert From big-endian to little-endian
            intPart = SwapEndianness(intPart);
            fractPart = SwapEndianness(fractPart);
    
            var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
    
            //**UTC** time
            var networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds);
    
            Debug.WriteLine ("Esco da GetNTP " + DateTime.Now);
            return networkDateTime.ToLocalTime();
        }
    

    I use this static method here

        private static async Task ntp(){
            App.UltimaDataOraNtp = await NtpClient.GetNetworkTimeAsync();
        }
    

    And I call ntp() here

        public static async Task UpdateDateTime(bool allinvio = false){
    
            Debug.WriteLine ("ENTRO IN UPDATETIME " + DateTime.Now);
            App.UltimaDataOraDispositivo = DateTime.Now;
            App.UltimaDataOraNtp = DateTime.MinValue;
    
    
            try {
    
                //bool isNtpOk = false;
                bool trovataDataOra = false ;
                try{
                    Debug.WriteLine("Verifico connettività");
                    if(Connectivity.Plugin.CrossConnectivity.Current.IsConnected){
                        Debug.WriteLine("Connettività presente");
                        await **ntp();**
                    //  isNtpOk = true;
                        if(App.UltimaDataOraNtp != DateTime.MinValue){
                            App.Globali.UltimaDataOraElaborata = App.UltimaDataOraNtp;
                            App.TipoDataOra = App.EnumTipoDataOra.Ntp;
                            App.Globali.Provenienza = "NTP";
                            trovataDataOra = true;
                        }
    
                    }
                    else {
                        Debug.WriteLine("Connettività assente");
                        throw new Exception("NORETE");
                    }
                }
                catch{
                }
    
                //bool isGpsOk = false;
                bool readGps = false; // Quando sono all'invio dei dati, leggo il gps solo se i dati sono più vecchi dell'ultimo minuto
                if(allinvio){
                    if(App.UltimaDataOraDispositivo.Subtract(App.UltimaRilevazioneGps).TotalMinutes > 1)
                        readGps = true;
                }
    
                if(!allinvio || 
                    !trovataDataOra || 
                    readGps){
                    try{
                        await gps();
                //      isGpsOk = true;
                        if(!trovataDataOra && App.Globali.Gps.DateTime != DateTimeOffset.MinValue){
                            App.Globali.UltimaDataOraElaborata = App.Globali.Gps.DateTime.DateTime.ToLocalTime();
                            if(DateTime.Now.IsDaylightSavingTime() && DeviceInfo.Plugin.CrossDeviceInfo.Current.Platform == DeviceInfo.Plugin.Abstractions.Platform.iOS)
                                App.Globali.UltimaDataOraElaborata = App.Globali.UltimaDataOraElaborata.Subtract(new TimeSpan(1,0,0));
                            App.TipoDataOra = App.EnumTipoDataOra.Gps;
                            App.Globali.Provenienza = "GPS";
                            trovataDataOra = true;
                        }
                        if(App.Globali.Gps.DateTime != DateTimeOffset.MinValue)
                            App.UltimaRilevazioneGps = DateTime.Now; // Memorizzo ultima dataora di rilevazione gps
    
                    }
                    catch{
                    }
                }
    
                if(!trovataDataOra){
                    App.Globali.UltimaDataOraElaborata = App.UltimaDataOraDispositivo;
                    App.TipoDataOra = App.EnumTipoDataOra.Dispositivo;
                    App.Globali.Provenienza = "DISPOSITIVO";
                    trovataDataOra = true;
                    }
    
            }
            catch(Exception ex){
                Debug.WriteLine(ex.Message);
            }
            finally{
            }
    
        }
    
    Sunday, June 21, 2015 8:40 AM
  • User42871 posted

    Hi @AlessandroCaliaro

    If I'm not mistaken, your await ntp() call is wrapped in a try block with an empty catch clause. If your ntp() call times out, it will throw a TimeoutException but it will be swallowed. If you check for the exception there, it might be that it did timeout after all. As for why it times out.. that can be the next problem :)

    If not -- you mentioned the Samsung Galaxy - does that mean you don't have the problem in the emulator? I have seen a few instances of socket/networking functions not working well on some specific android devices at certain versions, but I haven't been able to pinpoint the exact details. What version of Android your Galaxy running on?

    Sunday, June 21, 2015 9:21 AM
  • User2148 posted

    No, in the emulator it never stop. I say "it never stop" because I call "UpdateDateTime" (where there is the empty catch) every minute with this Task

        async void TimerRunning(int delay, CancellationToken token)
        {
            //var startTime = DateTime.Now;
            //var watch = Stopwatch.StartNew();
            Debug.WriteLine ("Timer attivato");
            while (!token.IsCancellationRequested)
            {
                try
                {
                    //await Task.Delay(60000 - (int)(watch.ElapsedMilliseconds%1000), token);
                    await Task.Delay(delay , token);
                    delay = 60000;
                    Debug.WriteLine (DateTime.Now.ToLocalTime ().ToString () + " DELAY: " + delay);
    
                }
                catch (TaskCanceledException)
                {
                }
    
                //Device.BeginInvokeOnMainThread(() => this.lblTimerText.Text = (DateTime.Now - startTime).ToString());
                //Device.BeginInvokeOnMainThread(() => this._labelOra.Text = watch.Elapsed.ToString());
                if (!token.IsCancellationRequested) {
                    await **App.UpdateDateTime** ();
                    Debug.WriteLine ("TimerRunning ");// + watch.Elapsed.ToString ());
                }
            }
        }
    

    Also if the socket goes in timeout, The timer should restart the next minute and call again UpdateDateTime(). But it does not restart. As it was "blocked" somewhere.

    Sunday, June 21, 2015 10:27 AM
  • User2148 posted

    @RyanDavis, I've inserted a Log after SendToAsync and a Log in "empty catch".

                Debug.WriteLine ("SendTo " + DateTime.Now);
                await socket.SendToAsync(ntpData, ntpServer, 123);
                Debug.WriteLine ("SendTo conclusa");
    

    Normally I have

    SendTo 21/06/2015 13:46:03 SendTo 21/06/2015 13:46:03 SendTo conclusa (ended) SendTo conclusa

    If I disable wifi on my mac (I', working with emulator...), I have the exception

    SendTo 21/06/2015 13:47:04 SendTo 21/06/2015 13:47:04 Errore in NTP(): Could not resolve host 'time.windows.com' Errore in NTP(): Could not resolve host 'time.windows.com'

    And the timer goes on. If I activate the wifi on my mac, I have again a correct log

    SendTo 21/06/2015 13:51:04 SendTo 21/06/2015 13:51:04 SendTo conclusa SendTo conclusa

    Sunday, June 21, 2015 11:57 AM
  • User42871 posted

    @AlessandroCaliaro

    Ah ok, yeah I see what you mean.

    I noticed that the timer method is an async void, which should usually be avoided and if an exception were to somehow bubble up to that method it could break the timer. It doesn't look like there are any points where that can happen, but just to be sure you should change it to async Task and check any exceptions. Since you want to loop "forever" (until cancelled), you can't await the method but you can set it and see the exceptions that come back.

    I have used an approach here (see L64 for the 'forever' method, and L34 for the invocation). Change your method signature to async Task TimerRunning. and where you call it, wrap it in Task.Run() and add a ContinueWith to handle any exception that occurs. Something like this:

    csharp Task.Run(()=> TimerRunning()) .ContinueWith(t=> { var ex = t.Exception.InnerException; Debug.WriteLine("com'e' morto il timer? - " + ex.Message); // if there is an exception, we will see it here }, TaskContinuationOptions.OnlyOnFaulted);

    For this you will have to test on the physical device again!

    Sunday, June 21, 2015 12:44 PM
  • User2148 posted

    Thanks Ryan. I take a look.

    Monday, June 22, 2015 7:22 PM
  • User2148 posted

    @RyanDavis Hi my friend. I am here again... to disturb you.

    The problem is always on NTP server. The code I use is the same but with more "logs"

        public static async Task<DateTime> GetNetworkTimeAsync()
        {
    
            Debug.WriteLine ("Entro in GetNTP " + DateTime.Now);
            //default Windows time server
            const string ntpServer = "time.windows.com";
    
            // NTP message size - 16 bytes of the digest (RFC 2030)
            var ntpData = new byte[48];
    
            //Setting the Leap Indicator, Version Number and Mode values
            ntpData[0] = 0x1B; //LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)
    
            var tcs = new TaskCompletionSource<byte[]>();
    
            using (var socket = new UdpSocketReceiver())
            {
                socket.MessageReceived += async (sender, args) =>
                {
                    await socket.StopListeningAsync();
                    tcs.SetResult(args.ByteData);
                };
    
                Debug.WriteLine ("StartListening " + DateTime.Now);
    
                await socket.StartListeningAsync(); // any free port >1000 will do 
    
                Debug.WriteLine ("SendTo " + DateTime.Now);
                await socket.SendToAsync(ntpData, ntpServer, 123);
                Debug.WriteLine ("SendTo conclusa");
    
                ntpData = await tcs.Task.TimeoutAfter(TimeSpan.FromSeconds(3));
            }
    
            //Offset to get to the "Transmit Timestamp" field (time at which the reply 
            //departed the server for the client, in 64-bit timestamp format."
            const byte serverReplyTime = 40;
    
            //Get the seconds part
            ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);
    
            //Get the seconds fraction
            ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);
    
            //Convert From big-endian to little-endian
            intPart = SwapEndianness(intPart);
            fractPart = SwapEndianness(fractPart);
    
            var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
    
            //**UTC** time
            var networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds);
    
            Debug.WriteLine ("Esco da GetNTP " + DateTime.Now + " - " + networkDateTime + " - LOCALTIME: " + networkDateTime.ToLocalTime() + " - UTC: " + networkDateTime.ToUniversalTime());
            return networkDateTime.ToLocalTime();
        }
    

    I think to have found a situation where log are Debug.WriteLine ("StartListening " + DateTime.Now); Debug.WriteLine ("SendTo " + DateTime.Now);

    and stop!

                Debug.WriteLine ("SendTo conclusa");
    

    does not appear.

    If you would like to try, I have a android or iOS phone connected via wifi to a router. All works fine, (timer continue to works every minute and NTP return the time), but if I remove the internet cable from the router, the problem appears. It seems that phone is connected to router but is not connected to internet. This situation block the communication with NTP and I don't receive any timeout exception.

    I think you can test the GetNetworkTimeAsync also without use a "timer". I've it in a Task.Run(async....) in OnStart method.

    Thanks for your help Alessandro.

    Thursday, June 25, 2015 3:22 PM
  • User2148 posted

    @RyanDavis , sorry if I disturb you again. Have you an answer for my problem? Thanks Alessandro

    Saturday, June 27, 2015 1:49 PM
  • User42871 posted

    Hi @AlessandroCaliaro,

    I haven't had time to look closely, but if you are not connected to the internet you may receive a different exception immediately at the SendTo call; or it may hang. Can you add .TimeoutAfter() to the SendToAsync call as well, and see whether it times out?

    csharp await socket.SendToAsync(ntpData, ntpServer, 123) .TimeoutAfter(TimeSpan.FromSeconds(3));

    Sunday, June 28, 2015 2:53 AM
  • User2148 posted

    Thansk Ryan. Is Sunday, I know you are there :)

    If I modify

        await socket.SendToAsync(ntpData, ntpServer, 123)
    

    to

        await socket.SendToAsync(ntpData, ntpServer, 123).TimeoutAfter(TimeSpan.FromSeconds(3));
    

    I have a compile error

    /Users/alessandrocaliaro/Projects/Soluzione1/IWapp/IWapp/NTPClient.cs(55,55): Error CS0411: The type arguments for method `IWapp.AsyncExtensions.TimeoutAfter(this System.Threading.Tasks.Task, System.TimeSpan, System.Threading.CancellationTokenSource)' cannot be inferred from the usage. Try specifying the type arguments explicitly (CS0411) (IWapp)

    If i press "." after ,123) intellisense does not give me "TimeoutAfter" method.

    Alessandro

    Sunday, June 28, 2015 7:20 AM
  • User2148 posted

    I don't know what there is... Now I have always a "timeout" every time I try to access to NTP server. I have also downloaded from github @MitchMilam demo project. It also goes in timeout. Could be down the Microsoft NTP server?

    Sunday, June 28, 2015 9:31 PM
  • User2148 posted

    ok, the last post was a wifi problem. Sorry. Exist alway the problem here https://forums.xamarin.com/discussion/comment/135615/#Comment_135615

    Thanks Alessandro

    Sunday, June 28, 2015 10:00 PM
  • User42871 posted

    Hi @AlessandroCaliaro,

    Sorry I didn't realise you had replied the other day.

    I didn't think of it before - but TimeoutAfter expects Task<T> whereas SendToAsync is just Task. You will need another overload for TimeoutAfter that expects just Task. From memory this was a little more painful to create than expected so in the meantime, just for debugging purposes, can you change it to this:

    csharp await socket.SendToAsync(ntpData, ntpServer, 123) .ContinueWith(_=> Task.FromResult(true)) // so we return Task<bool> .TimeoutAfter(TimeSpan.FromSeconds(3));

    which I expect will compile. Then we can see again whether it times out.

    Wednesday, July 1, 2015 7:58 AM
  • User2148 posted

    No problem Ryan and thanks always for your help. I have this news. With your suggestion, now the thread does not block. It's very good. I have only a delay between the SendTo and SendTo Conclusa. It's 30 seconds... Where it takes this timeout? I aspect 3 seconds...

    SendTo 7/2/2015 5:17:58 PM 2015-07-02 17:18:28.417 IWapp.iOS[6700:284949] SendTo conclusa SendTo conclusa 2015-07-02 17:18:31.418 IWapp.iOS[6700:284949] Errore in NTP(): The operation has timed-out. Errore in NTP(): The operation has timed-out.

    Thursday, July 2, 2015 3:25 PM