iOS Question Timeserver (solved)

Filippo

Expert
Licensed User
Hi,

I can query the time from a time server and other not, someone know why?
B4X:
Sub GetAtomtime
    Socket1.Initialize("Socket1")
   
    'All Server work
    Socket1.Connect("time-a.nist.gov", 13, 10000)
'    Socket1.Connect("time.nist.gov", 13, 10000)
'    Socket1.Connect("time-a.timefreq.bldrdoc.gov", 13, 10000)
'    Socket1.Connect("ntp-nist.ldsbc.edu", 13, 10000)
'    Socket1.Connect("nist-time-server.eoni.com", 13, 10000)

    'All server not work
'    Socket1.Connect("de.pool.ntp.org", 13, 10000)
'    Socket1.Connect("it.pool.ntp.org", 13, 10000)
'    Socket1.Connect("uk.pool.ntp.org", 13, 10000)
End Sub
 

Attachments

Filippo

Expert
Licensed User
What happens when you try to connect to the ones that do not work?
Nothing happens.
This event will not fire.
B4X:
Sub Socket1_Connected (Successful As Boolean)
    Log("Successful=" & Successful)
    If Successful Then
        AStreams.Initialize(Socket1.InputStream, Socket1.OutputStream, "AStreams")
    Else
        Socket1.Close
    End If
End Sub
 

Filippo

Expert
Licensed User
I tried it with: de.pool.ntp.org

The event is raised with Successful = false (the same when tested with B4J). Make sure that the iNetwork version is 1.10.
But why bring "Successful = false"?
With the Library "SPSntp" it works without problems, what's different?
 

Filippo

Expert
Licensed User
Are you sure that it listens on this port to TCP connections?
I tried also with port 123 (see java-class), unfortunately without success.
B4X:
package anywheresoftware.b4a.specci48.spsntp;

import android.os.SystemClock;
import android.util.Log;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.ActivityObject;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BA.Version;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

@BA.ActivityObject
@BA.ShortName("SPSntp")
@BA.Version(1.03F)
public class SPSntp
{
  private static String mNtpServerName = "0.us.pool.ntp.org";

  private static int mTimeOut = 30000;
  private static long mNtpTime;
  private static long mNtpTimeReference;
  private static long mRoundTripTime;

  private static class SntpClient
  {
    private static final String TAG = "SntpClient";
    private static final int ORIGINATE_TIME_OFFSET = 24;
    private static final int RECEIVE_TIME_OFFSET = 32;
    private static final int TRANSMIT_TIME_OFFSET = 40;
    private static final int NTP_PACKET_SIZE = 48;
    private static final int NTP_PORT = 123;
    private static final int NTP_MODE_CLIENT = 3;
    private static final int NTP_VERSION = 3;
    private static final long OFFSET_1900_TO_1970 = 2208988800L;

    public boolean requestTime(String host, int timeout)
    {
      try
      {
        DatagramSocket socket = new DatagramSocket();
        socket.setSoTimeout(timeout);
        InetAddress address = InetAddress.getByName(host);
        byte[] buffer = new byte[48];
        DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, 123);

        buffer[0] = 27;

        long requestTime = System.currentTimeMillis();
        long requestTicks = SystemClock.elapsedRealtime();
        writeTimeStamp(buffer, 40, requestTime);

        socket.send(request);

        DatagramPacket response = new DatagramPacket(buffer, buffer.length);
        socket.receive(response);
        long responseTicks = SystemClock.elapsedRealtime();
        long responseTime = requestTime + responseTicks - requestTicks;
        socket.close();

        long originateTime = readTimeStamp(buffer, 24);
        long receiveTime = readTimeStamp(buffer, 32);
        long transmitTime = readTimeStamp(buffer, 40);
        long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime);

        long clockOffset = (receiveTime - originateTime + transmitTime - responseTime) / 2L;

        SPSntp.mNtpTime = responseTime + clockOffset;
        SPSntp.mNtpTimeReference = responseTicks;
        SPSntp.mRoundTripTime = roundTripTime;
      }
      catch (Exception e) {
        Log.d("SntpClient", "request time failed: " + e);

        return false;
      }

      return true;
    }

    private long read32(byte[] buffer, int offset)
    {
      byte b0 = buffer[offset];
      byte b1 = buffer[(offset + 1)];
      byte b2 = buffer[(offset + 2)];
      byte b3 = buffer[(offset + 3)];

      int i0 = (b0 & 0x80) == 128 ? (b0 & 0x7F) + 128 : b0;
      int i1 = (b1 & 0x80) == 128 ? (b1 & 0x7F) + 128 : b1;
      int i2 = (b2 & 0x80) == 128 ? (b2 & 0x7F) + 128 : b2;
      int i3 = (b3 & 0x80) == 128 ? (b3 & 0x7F) + 128 : b3;

      return (i0 << 24) + (i1 << 16) + (i2 << 8) + i3;
    }

    public long readTimeStamp(byte[] buffer, int offset)
    {
      long seconds = read32(buffer, offset);
      long fraction = read32(buffer, offset + 4);
      return (seconds - 2208988800L) * 1000L + fraction * 1000L / 4294967296L;
    }

    private void writeTimeStamp(byte[] buffer, int offset, long time)
    {
      long seconds = time / 1000L;
      long milliseconds = time - seconds * 1000L;
      seconds += 2208988800L;

      buffer[(offset++)] = (byte)(int)(seconds >> 24);
      buffer[(offset++)] = (byte)(int)(seconds >> 16);
      buffer[(offset++)] = (byte)(int)(seconds >> 8);
      buffer[(offset++)] = (byte)(int)(seconds >> 0);

      long fraction = milliseconds * 4294967296L / 1000L;

      buffer[(offset++)] = (byte)(int)(fraction >> 24);
      buffer[(offset++)] = (byte)(int)(fraction >> 16);
      buffer[(offset++)] = (byte)(int)(fraction >> 8);

      buffer[(offset++)] = (byte)(int)(Math.random() * 255.0D);
    }
  }

  @BA.ActivityObject
  @BA.ShortName("SntpTime")
  public static class SntpTime
  {
    public long getGmtNtpTime(BA ba)
    {
      SPSntp.SntpClient client = new SPSntp.SntpClient(null);

      SPSntp.mNtpTime = Long.valueOf(-1L).longValue();
      SPSntp.mNtpTimeReference = Long.valueOf(-1L).longValue();
      SPSntp.mRoundTripTime = Long.valueOf(-1L).longValue();
      try {
        client.requestTime(SPSntp.mNtpServerName, SPSntp.mTimeOut);
      }
      catch (Exception localException)
      {
      }

      return SPSntp.mNtpTime;
    }

    public long getNtpTimeReference()
    {
      return SPSntp.mNtpTimeReference;
    }

    public long getRoundTripTime()
    {
      return SPSntp.mRoundTripTime;
    }

    public void setNtpServerName(String ntpServerName)
    {
      SPSntp.mNtpServerName = ntpServerName;
    }

    public void setTimeOut(int timeOut)
    {
      SPSntp.mTimeOut = timeOut;
    }
  }
}
 

Filippo

Expert
Licensed User

Filippo

Expert
Licensed User
Use UDPPacket instead of Socket.
Do you think it could work?
B4X:
  Private UDPSocket1 As UDPSocket

Sub GetUDPatomtime
    Dim data() As Byte
    Dim UDPPacket1 As UDPPacket
    UDPSocket1.Initialize("UDPSocket1", 123, 48)
  
    UDPPacket1.Initialize(data, "de.pool.ntp.org", 123)

    UDPSocket1.Send(UDPPacket1)
End Sub

Sub UDPSocket1_PacketArrived(Packet As UDPPacket)
    Dim msg As String
    msg = BytesToString(Packet.Data, 0, Packet.Data.Length, "UTF8")
    TextView1.Text = TextView1.Text & msg & CRLF
End Sub
 

Filippo

Expert
Licensed User
The java code you posted writes some date (27, time stamp). You will probably need to implement this protocol.
I've done it!
Only the packet format is not correct.
B4X:
Sub GetUDPatomtime
    Dim data(48) As Byte
    Dim UDPPacket1 As UDPPacket
    UDPSocket1.Initialize("UDPSocket1", 0, 48)
   
    data(0) = 27
    UDPPacket1.Initialize(data, "de.pool.ntp.org", 123)

    UDPSocket1.Send(UDPPacket1)
End Sub

Sub UDPSocket1_PacketArrived(Packet As UDPPacket)
    Dim msg As String
    msg = BytesToString(Packet.Data, 0, Packet.Data.Length, "UTF-8")
    EditText1.Text = EditText1.Text & msg & CRLF
    Log(msg)
End Sub
Log:
???????????5gh?"?Xp9???????????????????"??_????"??_?%@
 

Filippo

Expert
Licensed User
Hi Erel,

I need really your help.
I have the same code once in B4a and once in B4i. Both code bring different results and both wrong.
Where could be the problem?

B4i-Code:
B4X:
Sub GetUDPatomtime
    Dim data(48) As Byte
    Dim UDPPacket1 As UDPPacket
    UDPSocket1.Initialize("UDPSocket1", 0, 48)
   
    data(0) = 27
    UDPPacket1.Initialize(data, "de.pool.ntp.org", 123)

    UDPSocket1.Send(UDPPacket1)
End Sub

Sub UDPSocket1_PacketArrived(Packet As UDPPacket)
    Dim offsetTransmitTime As Byte = 40
    Dim intpart As Long = 0
    Dim fractpart As Long = 0
    For i = 0 To 3
        intpart = 256 * intpart + Packet.data(offsetTransmitTime + i)
    Next

    For i = 4 To 7
        fractpart = 256 * fractpart + Packet.data(offsetTransmitTime + i)
    Next

    Dim milliseconds As Long = (intpart * 1000 + (fractpart * 1000) / 4294967296)

    Dim timeSpan__1 As Long = milliseconds '* 1000
    Dim DateTime1 As Long = DateTime.DateParse("1900-01-01")
    DateTime1 = DateTime1 + timeSpan__1
    Log("DateTime1= " & DateTime1)

    lngTimer = DateTime.Now - (DateTime.TimeZoneOffset * DateTime.TicksPerHour) - DateTime1

    Log("lngTimer= " & lngTimer)

    UDPSocket1.Close
End Sub
B4i-Log:
Application_Start
DateTime1= 1434166760857
lngTimer= -3599926
Application_Active
B4a-Code:

B4X:
Sub GetUDPatomtime
    Dim data(48) As Byte
    Dim UDPPacket1 As UDPPacket
    UDPSocket1.Initialize("UDPSocket1", 0, 48)
   
    data(0) = 27
    UDPPacket1.Initialize(data, "de.pool.ntp.org", 123)

    UDPSocket1.Send(UDPPacket1)
End Sub

Sub UDPSocket1_PacketArrived(Packet As UDPPacket)
    Dim offsetTransmitTime As Byte = 40
    Dim intpart As Long = 0
    Dim fractpart As Long = 0
    For i = 0 To 3
        intpart = 256 * intpart + Packet.Data(offsetTransmitTime + i)
    Next

    For i = 4 To 7
        fractpart = 256 * fractpart + Packet.Data(offsetTransmitTime + i)
    Next

    Dim milliseconds As Long = (intpart * 1000 + (fractpart * 1000) / 4294967296)

    Dim timeSpan__1 As Long = milliseconds '* 1000
    Dim DateTime1 As Long = DateTime.DateParse("1900-01-01")
    DateTime1 = DateTime1 + timeSpan__1
    Log("DateTime1= " & DateTime1)

    lngTimer = DateTime.Now - (DateTime.TimeZoneOffset * DateTime.TicksPerHour) - DateTime1
   
    Log("lngTimer= " & lngTimer)

    UDPSocket1.Close
End Sub
B4a-Log:
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
DateTime1= -2860800543252
lngTimer= 4294963694622
 

Filippo

Expert
Licensed User
I have it solved. :)

B4X:
Sub GetUDPatomtime
    Dim data(48) As Byte
    Dim UDPPacket1 As UDPPacket
    UDPSocket1.Initialize("UDPSocket1", 0, 48)
   
    data(0) = 27
    UDPPacket1.Initialize(data, "de.pool.ntp.org", 123)

    UDPSocket1.Send(UDPPacket1)
End Sub

Sub UDPSocket1_PacketArrived(Packet As UDPPacket)
    '++++++ Test ++++++
'    Dim str As String = ""
'    For i = 0 To Packet.data.Length - 1
'        str = str & Packet.data(i) & " "
'    Next
'    Log(str)
    '++++++ Test ++++++

    Dim offsetTransmitTime As Byte = 40
    Dim OFFSET_1900_TO_1970 As Long = 2208988800
    Dim Year_1900_01_01 As Long = 4294967296
    Dim seconds As Long = 0
    Dim fraction As Long = 0
    For i = 0 To 3
        seconds = 256 * seconds + Packet.data(offsetTransmitTime + i)
    Next

    For i = 4 To 7
        fraction = 256 * fraction + Packet.data(offsetTransmitTime + i)
    Next

    Dim ntpTime As Long
    ntpTime = (seconds - OFFSET_1900_TO_1970) * 1000 + (fraction * 1000) / Year_1900_01_01

    lngTimer = DateTime.Now - ntpTime

    Log("lngTimer= " & lngTimer)

    UDPSocket1.Close
End Sub
 
Top