Use non-blocking socket for recvfrom.
[novacoin.git] / src / ntp.cpp
index b60e80d..b125e35 100644 (file)
@@ -13,6 +13,7 @@
 #endif
 
 #include "netbase.h"
+#include "util.h"
 
 extern int GetRandInt(int nMax);
 
@@ -57,12 +58,6 @@ inline void Ntp2Unix(uint32_t &n, time_t &u)
     u = n - 0x83aa7e80; // 2208988800 1970 - 1900 in seconds
 }
 
-inline void HTONL_FP(l_fp *h, l_fp *n)
-{
-    (n)->Ul_i.Xl_ui = htonl((h)->Ul_i.Xl_ui);
-    (n)->Ul_f.Xl_uf = htonl((h)->Ul_f.Xl_uf);
-}
-
 inline void ntohl_fp(l_fp *n, l_fp *h)
 {
     (h)->Ul_i.Xl_ui = ntohl((n)->Ul_i.Xl_ui);
@@ -169,11 +164,7 @@ std::string NtpServers[65] = {
     // ... To be continued
 };
 
-#ifdef WIN32
-bool InitWithRandom(int &sockfd, int &servlen, struct sockaddr *pcliaddr)
-#else
-bool InitWithRandom(int &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr)
-#endif
+bool InitWithRandom(SOCKET &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr)
 {
     int nAttempt = 0;
 
@@ -207,7 +198,7 @@ bool InitWithRandom(int &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr)
 
         sockfd = socket(AF_INET, SOCK_DGRAM, 0);
 
-        if (sockfd == -1)
+        if (sockfd == INVALID_SOCKET)
             continue; // socket initialization error
 
         if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1 )
@@ -223,11 +214,7 @@ bool InitWithRandom(int &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr)
     return false;
 }
 
-#ifdef WIN32
-bool InitWithHost(std::string &strHostName, int &sockfd, int &servlen, struct sockaddr *pcliaddr)
-#else
-bool InitWithHost(std::string &strHostName, int &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr)
-#endif
+bool InitWithHost(std::string &strHostName, SOCKET &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr)
 {
     sockfd = -1;
 
@@ -254,7 +241,7 @@ bool InitWithHost(std::string &strHostName, int &sockfd, socklen_t &servlen, str
 
     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
 
-    if (sockfd == -1)
+    if (sockfd == INVALID_SOCKET)
         return false; // socket initialization error
 
     if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1 )
@@ -262,6 +249,7 @@ bool InitWithHost(std::string &strHostName, int &sockfd, socklen_t &servlen, str
         return false; // "connection" error
     }
 
+
     *pcliaddr = *((struct sockaddr *) &servaddr);
     servlen = sizeof(servaddr);
 
@@ -269,12 +257,22 @@ bool InitWithHost(std::string &strHostName, int &sockfd, socklen_t &servlen, str
 }
 
 
+int64_t DoReq(SOCKET sockfd, socklen_t servlen, struct sockaddr cliaddr)
+{
+
 #ifdef WIN32
-int64_t DoReq(int sockfd, int servlen, struct sockaddr cliaddr)
+    u_long nOne = 1;
+    if (ioctlsocket(sockfd, FIONBIO, &nOne) == SOCKET_ERROR)
+    {
+        printf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError());
 #else
-int64_t DoReq(int sockfd, socklen_t servlen, struct sockaddr cliaddr)
+    if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
+    {
+        printf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno);
 #endif
-{
+        return -2;
+    }
+
     struct pkt *msg = new pkt;
     struct pkt *prt  = new pkt;
 
@@ -295,8 +293,26 @@ int64_t DoReq(int sockfd, socklen_t servlen, struct sockaddr cliaddr)
     msg->xmt.Ul_f.Xl_f=0;
 
     int len=48;
-    sendto(sockfd, (char *) msg, len, 0, &cliaddr, servlen);
-    int n = recvfrom(sockfd, msg, len, 0, NULL, NULL);
+    int retcode = sendto(sockfd, (char *) msg, len, 0, &cliaddr, servlen);
+    if (retcode < 0) {
+        printf("sendto() failed: %d", retcode);
+        return -3;
+    }
+
+    retcode = 0;
+    int nWait = 0;
+
+    while(retcode <= 0) {
+        Sleep(1000);
+        retcode = recvfrom(sockfd, (char *) msg, len, 0, NULL, NULL);
+
+        if (nWait > 4) {
+            printf("recvfrom() timeout");
+            return -4;
+        }
+
+        nWait++;
+    }
 
     ntohl_fp(&msg->rec, &prt->rec);
     ntohl_fp(&msg->xmt, &prt->xmt);
@@ -315,50 +331,34 @@ int64_t DoReq(int sockfd, socklen_t servlen, struct sockaddr cliaddr)
 
 int64_t NtpGetTime()
 {
-    int sockfd;
     struct sockaddr cliaddr;
 
-#ifdef WIN32
-    int servlen;
-#else
+    SOCKET sockfd;
     socklen_t servlen;
-#endif
 
     if (!InitWithRandom(sockfd, servlen, &cliaddr))
         return -1;
 
     int64_t nTime = DoReq(sockfd, servlen, cliaddr);
 
-#ifdef WIN32
     closesocket(sockfd);
-#else
-    close(sockfd);
-#endif
 
     return nTime;
 }
 
 int64_t NtpGetTime(std::string &strHostName)
 {
-    int sockfd;
     struct sockaddr cliaddr;
 
-#ifdef WIN32
-    int servlen;
-#else
+    SOCKET sockfd;
     socklen_t servlen;
-#endif
 
     if (!InitWithHost(strHostName, sockfd, servlen, &cliaddr))
         return -1;
 
     int64_t nTime = DoReq(sockfd, servlen, cliaddr);
 
-#ifdef WIN32
     closesocket(sockfd);
-#else
-    close(sockfd);
-#endif
 
     return nTime;
 }