Переглянути джерело

【修改】修改 ntp 支持 3 个服务器

zylx 7 роки тому
батько
коміт
d4d8392d8d
1 змінених файлів з 125 додано та 87 видалено
  1. 125 87
      ntp/ntp.c

+ 125 - 87
ntp/ntp.c

@@ -39,6 +39,18 @@
 #define NTP_HOSTNAME                   NETUTILS_NTP_HOSTNAME
 #endif
 
+#ifdef NETUTILS_NTP_HOSTNAME2
+#define NTP_HOSTNAME2                   NETUTILS_NTP_HOSTNAME2
+#else
+#define NTP_HOSTNAME2                   RT_NULL
+#endif
+
+#ifdef NETUTILS_NTP_HOSTNAME3
+#define NTP_HOSTNAME3                   NETUTILS_NTP_HOSTNAME3
+#else
+#define NTP_HOSTNAME3                   RT_NULL
+#endif
+
 #define NTP_TIMESTAMP_DELTA            2208988800ull
 #define NTP_GET_TIMEOUT                5
 
@@ -60,9 +72,9 @@
 typedef struct {
 
     uint8_t li_vn_mode;      // Eight bits. li, vn, and mode.
-                         // li.   Two bits.   Leap indicator.
-                         // vn.   Three bits. Version number of the protocol.
-                         // mode. Three bits. Client will pick mode 3 for client.
+                             // li.   Two bits.   Leap indicator.
+                             // vn.   Three bits. Version number of the protocol.
+                             // mode. Three bits. Client will pick mode 3 for client.
 
     uint8_t stratum;         // Eight bits. Stratum level of the local clock.
     uint8_t poll;            // Eight bits. Maximum interval between successive messages.
@@ -100,114 +112,140 @@ static ntp_packet packet = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  */
 time_t ntp_get_time(const char *host_name)
 {
-    int sockfd, n; // Socket file descriptor and the n return result from writing/reading from the socket.
+    int sockfd, n;
 
-    int portno = 123; // NTP UDP port number.
+    /* NTP UDP port number. */
+    int portno = 123;
+    struct hostent *server;
+    struct sockaddr_in serv_addr[3];
 
+    int server_num = 1;
+    rt_tick_t start = 0;
     time_t new_time = 0;
-    struct timeval timeout;
+    int addr_len = sizeof(struct sockaddr_in);
 
-    // Using default host name when host_name is NULL
+    /* Using default host name when host_name is NULL */
     if (host_name == NULL)
     {
         host_name = NTP_HOSTNAME;
     }
 
-    // Create and zero out the packet. All 48 bytes worth.
-
-    memset(&packet, 0, sizeof(ntp_packet));
-
-    // Set the first byte's bits to 00,011,011 for li = 0, vn = 3, and mode = 3. The rest will be left set to zero.
-
-    *((char *) &packet + 0) = 0x1b; // Represents 27 in base 10 or 00011011 in base 2.
-
-    // Create a UDP socket, convert the host-name to an IP address, set the port number,
-    // connect to the server, send the packet, and then read in the return packet.
-
-    struct sockaddr_in serv_addr; // Server address data structure.
-    struct hostent *server;      // Server data structure.
-
-    sockfd = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP); // Create a UDP socket.
-
-    if (sockfd < 0) {
-        ntp_error("opening socket");
-        return 0;
-    }
-
-    timeout.tv_sec = NTP_GET_TIMEOUT;
-    timeout.tv_usec = 0;
-
-    /* set receive and send timeout option */
-    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (void *) &timeout,
-               sizeof(timeout));
-    setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (void *) &timeout,
-               sizeof(timeout));
-
-    server = gethostbyname(host_name); // Convert URL to IP.
-
-    if (server == NULL) {
+    server = gethostbyname(host_name);
+    if (server == NULL)
+    {
         ntp_error("no such host");
-        goto __exit;
+        server_num --;
+    }
+    else
+    {
+        /* Zero out the server address structure. */
+        memset((char *) &serv_addr[server_num - 1], 0, addr_len);
+        
+        serv_addr[server_num - 1].sin_family = AF_INET;
+        
+        /* Convert the port number integer to network big-endian style and save it to the server address structure. */
+        serv_addr[server_num - 1].sin_port = htons(portno);
+        
+        /* Copy the server's IP address to the server address structure. */
+        memcpy(&serv_addr[server_num - 1].sin_addr.s_addr, (char *) server->h_addr, server->h_length);
+    }
+    
+    if (NTP_HOSTNAME2 != NULL)
+    {
+        server_num++;
+        server = gethostbyname(NTP_HOSTNAME2);
+        if (server == NULL)
+        {
+            ntp_error("no such host");
+            server_num --;
+        }
+        else
+        {
+            /* Zero out the server address structure. */
+            memset((char *) &serv_addr[server_num - 1], 0, addr_len);
+            
+            serv_addr[server_num - 1].sin_family = AF_INET;
+            
+            /* Convert the port number integer to network big-endian style and save it to the server address structure. */
+            serv_addr[server_num - 1].sin_port = htons(portno);
+            /* Copy the server's IP address to the server address structure. */
+            memcpy(&serv_addr[server_num - 1].sin_addr.s_addr, (char *) server->h_addr, server->h_length);
+        }
     }
 
-    // Zero out the server address structure.
-
-    memset((char *) &serv_addr, 0, sizeof(serv_addr));
-
-    serv_addr.sin_family = AF_INET;
-
-    // Copy the server's IP address to the server address structure.
-
-    memcpy((char *) &serv_addr.sin_addr.s_addr, (char *) server->h_addr, server->h_length);
-
-    // Convert the port number integer to network big-endian style and save it to the server address structure.
-
-    serv_addr.sin_port = htons(portno);
-
-    // Call up the server using its IP address and port number.
-
-    if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
-        ntp_error("connecting");
-        goto __exit;
+    if (NTP_HOSTNAME3 != NULL)
+    {
+        server_num++;
+        server = gethostbyname(NTP_HOSTNAME3);
+        if (server == NULL)
+        {
+            ntp_error("no such host");
+            server_num --;
+        }
+        else
+        {
+            /* Zero out the server address structure. */
+            memset((char *) &serv_addr[server_num - 1], 0, addr_len);
+            
+            serv_addr[server_num - 1].sin_family = AF_INET;
+            
+            /* Convert the port number integer to network big-endian style and save it to the server address structure. */
+            serv_addr[server_num - 1].sin_port = htons(portno);
+            /* Copy the server's IP address to the server address structure. */
+            memcpy(&serv_addr[server_num - 1].sin_addr.s_addr, (char *) server->h_addr, server->h_length);
+        }
     }
 
-    // Send it the NTP packet it wants. If n == -1, it failed.
+    /* Create and zero out the packet. All 48 bytes worth. */
+    memset(&packet, 0, sizeof(ntp_packet));
 
-    n = send(sockfd, (char*) &packet, sizeof(ntp_packet), 0);
+    /* Set the first byte's bits to 00,011,011 for li = 0, vn = 3, and mode = 3. The rest will be left set to zero.
+       Represents 27 in base 10 or 00011011 in base 2. */
+    *((char *) &packet + 0) = 0x1b;
 
-    if (n < 0) {
-        ntp_error("writing to socket");
-        goto __exit;
+    /* Create a UDP socket. */
+    sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);  
+    if (sockfd < 0)
+    {
+        ntp_error("opening socket");
+        return 0;
     }
 
-    // Wait and receive the packet back from the server. If n == -1, it failed.
-
-    n = recv(sockfd, (char*) &packet, sizeof(ntp_packet), 0);
+    /* Send it the NTP packet it wants. If n == -1, it failed. */
+    for (int i = 0; i < server_num; i++)
+    {
+        n = sendto(sockfd, (char *) &packet, sizeof(ntp_packet), 0, (const struct sockaddr *)&serv_addr[i], addr_len);
+    }
 
-    if (n < 0) {
-        if (errno == EWOULDBLOCK || errno == EAGAIN) {
-            ntp_error("receive the socket timeout(%ds)", NTP_GET_TIMEOUT);
-        } else {
-            ntp_error("reading from socket, error code %d.", n);
+    start = rt_tick_get();
+    while (rt_tick_get() <= start + NTP_GET_TIMEOUT)
+    {
+        for (int i = 0; i < server_num; i++)
+        {
+            /* receive the packet back from the server. If n == -1, it failed. */
+            n = recvfrom(sockfd, (char *) &packet, sizeof(ntp_packet), 0, (struct sockaddr *)&serv_addr[i], (socklen_t *)&addr_len);
+            if (n < 0)
+            {
+                ntp_error("reading from server %d, error code %d.", i, n);
+            }
+            else
+            {
+                break;
+            }
         }
-        goto __exit;
     }
 
-    // These two fields contain the time-stamp seconds as the packet left the NTP server.
-    // The number of seconds correspond to the seconds passed since 1900.
-    // ntohl() converts the bit/byte order from the network's to host's "endianness".
-
+    /* These two fields contain the time-stamp seconds as the packet left the NTP server.
+       The number of seconds correspond to the seconds passed since 1900.
+       ntohl() converts the bit/byte order from the network's to host's "endianness". */
     packet.txTm_s = ntohl(packet.txTm_s); // Time-stamp seconds.
     packet.txTm_f = ntohl(packet.txTm_f); // Time-stamp fraction of a second.
 
-    // Extract the 32 bits that represent the time-stamp seconds (since NTP epoch) from when the packet left the server.
-    // Subtract 70 years worth of seconds from the seconds since 1900.
-    // This leaves the seconds since the UNIX epoch of 1970.
-    // (1900)------------------(1970)**************************************(Time Packet Left the Server)
-
-    new_time = (time_t) (packet.txTm_s - NTP_TIMESTAMP_DELTA);
-
-__exit:
+    /* Extract the 32 bits that represent the time-stamp seconds (since NTP epoch) from when the packet left the server.
+       Subtract 70 years worth of seconds from the seconds since 1900.
+       This leaves the seconds since the UNIX epoch of 1970.
+       (1900)------------------(1970)**************************************(Time Packet Left the Server) */
+    new_time = (time_t)(packet.txTm_s - NTP_TIMESTAMP_DELTA);
 
     closesocket(sockfd);
 
@@ -273,7 +311,7 @@ static void ntp_sync(const char *host_name)
 
     if (cur_time)
     {
-        rt_kprintf("Get local time from NTP server: %s", ctime((const time_t*) &cur_time));
+        rt_kprintf("Get local time from NTP server: %s", ctime((const time_t *) &cur_time));
 
 #ifdef RT_USING_RTC
         rt_kprintf("The system time is updated. Timezone is %d.\n", NTP_TIMEZONE);