getting network time using socket that supports IPv4 and IPv6

Hi all,

I spent a whole day on this and got nowhere so I hope someone here can help. I was using a c# socket to get the network time ntp.org. Was working fine (I thought) but Apple rejected the app because of the new requirement to support IPv6 only networks. This was the code I had that was working fine for me.

string ntpServer = attempt+".pool.ntp.org";
        var ntpData = new byte[48];
        ntpData[0] = 0x1B; //LeapIndicator = 0 (no warning), VersionNum = 3 (IPv4 only), Mode = 3 (Client Mode)
        try {
                var addresses = Dns.GetHostEntry(ntpServer).AddressList;
                var ipEndPoint = new IPEndPoint(addresses[0], 123);
                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();
                ulong intPart = (ulong)ntpData[40] << 24 | (ulong)ntpData[41] << 16 | (ulong)ntpData[42] << 8 | (ulong)ntpData[43];
                ulong fractPart = (ulong)ntpData[44] << 24 | (ulong)ntpData[45] << 16 | (ulong)ntpData[46] << 8 | (ulong)ntpData[47];
                var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
                var networkDateTime = (new DateTime(1900, 1, 1)).AddMilliseconds((long)milliseconds);
                DateTime startDate = new DateTime(2016, 1, 1);
                long elapsedTicks = networkDateTime.Ticks - startDate.Ticks;
                TimeSpan elapsedSpan = new TimeSpan(elapsedTicks);
                return (int)elapsedSpan.TotalSeconds;
        } catch(ArgumentNullException ae) {
            Debug.Log("ArgumentNullException");
            return -1;
        } catch(SocketException se) {
            Debug.Log("SocketException");
            return -1;
        } catch(Exception e) {
            Debug.Log("Exception");
            return -1;
        }

To try to accommodate IPv6 I tried about 10 different things, with this being the latest.

string ntpServer = attempt+".pool.ntp.org";
 var ntpData = new byte[48];
 ntpData[0] = 0x1B; //LeapIndicator=0(nowarning),VersionNum=3(IPv4only),Mode=3(ClientMode)
 try {

 if(System.Net.Sockets.Socket.OSSupportsIPv6){
 Debug.Log("v6");
 string localIP = "";
 IPHostEntry host = Dns.GetHostEntry("2.pool.ntp.org");
 foreach (IPAddress ip in host.AddressList)
 {
 Debug.Log("ip"+ip.ToString());
 if (ip.AddressFamily == AddressFamily.InterNetworkV6)
 {
 Debug.Log("UpdatingLocalIPto"+ip.ToString());
 localIP = ip.ToString();
 }else{
 Debug.Log("ip.AddressFamily"+ip.AddressFamily);
 }
 }
 Debug.Log("LocalIPis"+localIP);
 const int PORT = 123;
 //conststringIPv6_ADDR=localIP;
 IPAddress ipa = IPAddress.Parse(localIP);
 IPEndPoint ipeh = new IPEndPoint(ipa, PORT);
 Debug.Log("ipeh"+ipeh);
 Socket connection = new Socket(
 AddressFamily.InterNetworkV6,
 SocketType.Stream,
 ProtocolType.Tcp);
 connection.Connect(ipeh);
 connection.SendTimeout = 3000;
 connection.ReceiveTimeout = 3000; 
 //connection.Send(ntpData);
 connection.Receive(ntpData);

 connection.Close();

 //StopscodehangifNTPis blocked

 connection.Close();
 ulong intPart = (ulong)ntpData[40] << 24 | (ulong)ntpData[41] << 16 | (ulong)ntpData[42] << 8 | (ulong)ntpData[43];
 ulong fractPart = (ulong)ntpData[44] << 24 | (ulong)ntpData[45] << 16 | (ulong)ntpData[46] << 8 | (ulong)ntpData[47];

 var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
 var networkDateTime = (new DateTime(1900, 1, 1)).AddMilliseconds((long)milliseconds);
 DateTime startDate = new DateTime(2016, 1, 1);


 long elapsedTicks = networkDateTime.Ticks - startDate.Ticks;
 TimeSpan elapsedSpan = new TimeSpan(elapsedTicks);

 return (int)elapsedSpan.TotalSeconds;
 }else{
 
 Debug.Log("v4");
 var addresses = Dns.GetHostEntry(ntpServer).AddressList;
 var ipEndPoint = new IPEndPoint(addresses[0], 123);

 var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
 socket.Connect(ipEndPoint);
 //StopscodehangifNTPis blocked

 socket.ReceiveTimeout = 3000; 
 socket.Send(ntpData);
 socket.Receive(ntpData);
 socket.Close();
 ulong intPart = (ulong)ntpData[40] << 24 | (ulong)ntpData[41] << 16 | (ulong)ntpData[42] << 8 | (ulong)ntpData[43];
 ulong fractPart = (ulong)ntpData[44] << 24 | (ulong)ntpData[45] << 16 | (ulong)ntpData[46] << 8 | (ulong)ntpData[47];

 var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
 var networkDateTime = (new DateTime(1900, 1, 1)).AddMilliseconds((long)milliseconds);
 DateTime startDate = new DateTime(2016, 1, 1);


 long elapsedTicks = networkDateTime.Ticks - startDate.Ticks;
 TimeSpan elapsedSpan = new TimeSpan(elapsedTicks);

 return (int)elapsedSpan.TotalSeconds;
 }

 } catch(ArgumentNullException ae) {
 Debug.Log("ArgumentNullException");
 return -1;
 } catch(SocketException se) {
 Debug.Log("SocketException");
 return -1;
 } catch(Exception e) {
 Debug.Log("Exception");
 return -1;
 }

I can see that it gets into the V6 part but as it loops through all the IPs in the host address list, none of them are InterNetworkV6. I am using 2.pool.ntp.org because I read somewhere that all the IPv6 addresses are delivered through the 2. host, but I’ve tried number other things for that host as well. Even once I have an IPv6 address for one of the time servers, I’m unsure if the code below that will extract the values properly. I’m concerned about this line:

ntpData[0] = 0x1B; //LeapIndicator=0(nowarning),VersionNum=3(IPv4only),Mode=3(ClientMode)

I got it from stackoverflow and the comment says “IPv4only” but I can’t find any documentation regarding how to set the value sent to the server.

Any help would be greatly appreciated.
Thanks

decided to avoid using sockets and found an answer here that should be fine with Apple.

http://stackoverflow.com/questions/6435099/how-to-get-datetime-from-the-internet