changeset 1323:16a975af0355

* src/sntp.c: Added DHCP support for SNTP unicast mode. * src/sntp.cdl: Added DHCP support for SNTP unicast mode. * src/sntp.h: Removed UDP port constant. * src/sntp1.c: Added test code for SNTP unicast mode. * src/sntp.sgml: Added documentation for SNTP unicast mode.
author asl
date Tue, 21 Oct 2003 17:51:51 +0000
parents 69a4719c04ad
children f5a5cdd6afe0
files packages/net/sntp/current/ChangeLog packages/net/sntp/current/cdl/sntp.cdl packages/net/sntp/current/doc/sntp.sgml packages/net/sntp/current/include/sntp.h packages/net/sntp/current/src/sntp.c packages/net/sntp/current/tests/sntp1.c
diffstat 6 files changed, 204 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/packages/net/sntp/current/ChangeLog
+++ b/packages/net/sntp/current/ChangeLog
@@ -1,3 +1,12 @@
+2003-10-15  Dan Jakubiec  <djakubiec@yahoo.com>
+            Andrew Lunn   <andrew.lunn@ascom.ch>
+
+	* src/sntp.c: Added DHCP support for SNTP unicast mode.
+	* src/sntp.cdl: Added DHCP support for SNTP unicast mode.
+	* src/sntp.h: Removed UDP port constant.
+	* src/sntp1.c: Added test code for SNTP unicast mode.
+	* src/sntp.sgml: Added documentation for SNTP unicast mode.
+
 2003-09-29  Dan Jakubiec  <firstname.lastname@systech.com>
 
 	* src/sntp.c: Added support for SNTP unicast mode.
--- a/packages/net/sntp/current/cdl/sntp.cdl
+++ b/packages/net/sntp/current/cdl/sntp.cdl
@@ -62,22 +62,35 @@ cdl_package CYGPKG_NET_SNTP {
     requires      CYGSEM_LIBC_TIME_SETTIME_WORKING
     compile       sntp.c
     
+    cdl_component CYGPKG_NET_SNTP_UNICAST {
+        display "Enable SNTP client unicast support"
+        flavor  bool
+        default_value 0
+        description   "
+            This option enables SNTP unicast mode in
+            for the SNTP client.  This mode will send
+            SNTP requests to NTP/SNTP servers in
+            addition to listening for SNTP broadcasts."
+
+        cdl_option CYGNUM_NET_SNTP_UNICAST_MAXDHCP {
+            display "Maximum number of NTP servers to use from DHCP"
+            flavor  booldata
+            requires CYGPKG_NET_DHCP
+            legal_values 1 to 8
+            default_value 2
+            description   "
+                This option specifies the maximum number of
+                NTP servers to get from DHCP.  These servers
+                are used to configure the unicast SNTP client.
+                Disabling this option disables DHCP usage."
+        }
+    }
+
     cdl_component CYGPKG_NET_SNTP_OPTIONS {
         display "SNTP support build options"
         flavor  none
         no_define
 
-        cdl_option CYGPKG_NET_SNTP_UNICAST {
-            display "Enable SNTP client unicast support"
-            flavor  bool
-            default_value 0
-            description   "
-                This option enables SNTP unicast mode in
-                for the SNTP client.  This mode will send
-                SNTP requests to NTP/SNTP servers in
-                addition to listening for SNTP broadcasts."
-        }
-
         cdl_option CYGPKG_NET_SNTP_CFLAGS_ADD {
             display "Additional compiler flags"
             flavor  data
--- a/packages/net/sntp/current/doc/sntp.sgml
+++ b/packages/net/sntp/current/doc/sntp.sgml
@@ -36,7 +36,8 @@
 The SNTP package provides implementation of a client for RFC 2030, the
 Simple Network Time Protocol (SNTP). The client listens for broadcasts
 or IPv6 multicasts from an NTP server and uses the information received to
-set the system clock.
+set the system clock.  It can also be configured to send SNTP time
+requests to specific NTP servers using SNTP's unicast mode.
 </PARA>
 </PARTINTRO>
 <CHAPTER id="net-sntp">
@@ -45,16 +46,20 @@ set the system clock.
 <TITLE>Starting the SNTP client</TITLE>
 <para>
 The sntp client is implemented as a thread which listens for NTP
-broadcasts and IPv6 multicasts. This thread is not automatically start by the
-system. Instead it must be started by the user application. The header
-file <filename>cyg/sntp/sntp.h</filename> declares the function to be
+broadcasts and IPv6 multicasts, and optionally sends SNTP unicast
+requests to specific NTP servers. This thread may be automatically
+started by the system if it receives a list of (S)NTP servers from the
+DHCP server and unicast mode is enabled. Otherwise it must be started
+by the user application. The header file
+<filename>cyg/sntp/sntp.h</filename> declares the function to be
 called.  The thread is then started by calling the function:
 </para>
 <programlisting>
 void cyg_sntp_start(void);
 </programlisting>
 <para>
-Once started, the thread will run forever.
+It is safe to call this function multiple times. Once started, the
+thread will run forever.
 </para>
 </sect1>
 
@@ -62,8 +67,8 @@ Once started, the thread will run foreve
 <title>What it does</title>
 <para>
 The SNTP client listens for NTP IPv4 broadcasts from any NTP servers,
-or IPv6 multicasts using the address fe0x:0X::101, where X can be 1
-(Node Local), 2 (Link Local), 5 (Site-Local) or 0xe (Global). Such
+or IPv6 multicasts using the address fe0x:0X::101, where X can be
+2 (Link Local), 5 (Site-Local) or 0xe (Global). Such
 packets contain a timestamp indicating the current time. The packet
 also contains information about where the server is in the hierarchy
 of time servers. A server at the root of the time server tree normally
@@ -73,8 +78,19 @@ stratum 1 etc. The client will accept an
 servers using version 3 or 4 of the protocol. When receiving packets
 from multiple servers, it will use the packets from the server with
 the lowest stratum. However, if there are no packets from this server
-for 10 minute and another server is sending packets, the client will
-change server.
+for 10 minutes and another server is sending packets, the client will
+change servers.
+</para>
+<para>
+If SNTP unicast mode is enabled via the CYGPKG_NET_SNTP_UNICAST
+option, the SNTP client can additionally be configured with a list
+of specific NTP servers to query.  The general algorithm is as follows: if
+the system clock has not yet been set via an NTP time update, then
+the client will send out NTP requests every 30 seconds to all
+configured NTP servers.  Once an NTP time update has been received,
+the client will send out additional NTP requests every 30 minutes
+in order to update the system clock.  These requests are resent
+every 30 seconds until a response is received.
 </para>
 <para>
 The system clock in eCos is accurate to 1 second. The SNTP client will
@@ -83,6 +99,53 @@ timestamp is greater than 2 seconds. The
 </para>
 </sect1>
 
+<sect1 id="net-sntp-unicast">
+<title>Configuring the unicast list of NTP servers</title>
+<para>
+If SNTP unicast mode is enabled via the CYGPKG_NET_SNTP_UNICAST
+option, the SNTP client can be configured with a list of
+NTP servers to contact for time updates.
+</para>
+<para>
+By default, this list is configured with NTP server information
+received from DHCP.  The number of NTP servers that are extracted
+from DHCP can be configured with the CYGOPT_NET_SNTP_UNICAST_MAXDHCP
+option.  This option can also be used to disable DHCP usage entirely.
+</para>
+<para>
+The list of NTP servers can be manually configured with the following
+API function.  Note that manual configuration will override any
+servers that were automatically configured by DHCP. But later
+reconfigurations by DHCP will override manual configurations. Hence it
+is not recommended to manually configure servers when
+CYGOPT_NET_SNTP_UNICAST is enabled.
+</para>
+<programlisting>
+#include &lt;cyg/sntp/sntp.h&gt;
+
+void cyg_sntp_set_servers(struct sockaddr *server_list, cyg_uint32 num_servers);
+</programlisting>
+<para>
+This function takes an array of sockaddr structures specifying the
+IP address and UDP port of each NTP server to query.  Currently,
+both IPv4 and IPv6 sockaddr structures are supported.  The
+num_servers argument specifies how many sockaddr's are contained
+in the array.  The server_list array must be maintained by the caller.
+Once the array is registered with this function, it must not be
+modified by the caller until it is replaced or unregistered
+by another call to this function.
+</para>
+<para>
+Calling this function with a server_list of NULL and a num_servers
+value of 0 unregisters any previously configured server_list array.
+</para>
+<para>
+Finally, note that if this function is called with a non-empty server
+list, it will implicitly start the SNTP client if it has not already
+been started (i.e. it will call cyg_sntp_start()).
+</para>
+</sect1>
+
 <sect1 id="net-sntp-warning">
 <title>Warning: timestamp wrap around</title>
 <para>
@@ -90,7 +153,7 @@ The timestamp in the NTP packet is a 32b
 the number of seconds after 00:00 01/01/1900. This 32bit number will
 wrap around at 06:28:16 Feb 7 2036. At this point in time, the eCos
 time will jump back to around 00:00:00 Jan 1 1900 when the next
-NTP packett is received. 
+NTP packet is received. 
 </para>
 <para>
 YOU HAVE BEEN WARNED!
@@ -129,6 +192,16 @@ check the build date for the test. This 
 else fails check that the computer used to build the test has the
 correct time. 
 </para>
+<para>
+If SNTP unicast mode is enabled, the above tests are run twice.  The
+first time, the SNTP client is configured with NTP server addresses
+from DHCP.  The second time, unicast mode is disabled and only
+multicasts are listened for.  Note that the unicast test is partially
+bogus in the sense that any multicast packet received will also make
+the unicast test pass.  To reduce the chance of this happening the
+test will wait for a sorter time for replies. This is not ideal, but
+it is the best that can be done with an automated test.
+</para>
 </SECT1>
 </CHAPTER>
-</PART>
\ No newline at end of file
+</PART>
--- a/packages/net/sntp/current/include/sntp.h
+++ b/packages/net/sntp/current/include/sntp.h
@@ -53,9 +53,6 @@
 #include <pkgconf/net_sntp.h>
 #include <cyg/infra/cyg_type.h>
 
-/* General Definitions */
-#define NTP_UDP_PORT            123
-
 // Multicast address used by IPv6
 #define IN6ADDR_NTP_MULTICAST \
 	{{{ 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
--- a/packages/net/sntp/current/src/sntp.c
+++ b/packages/net/sntp/current/src/sntp.c
@@ -480,7 +480,6 @@ void cyg_sntp_start(void) {
 }
 
 #ifdef CYGPKG_NET_SNTP_UNICAST
-
 /*
  *	FUNCTION cyg_sntp_set_servers
  *
@@ -497,8 +496,10 @@ void cyg_sntp_start(void) {
  *		array can be unregistered by calling this
  *		function again with different parameters.
  *
- *      NOTE: This function must be called AFTER
- *      cyg_sntp_start().
+ *      NOTE: If cyg_sntp_start() has not been called
+ * 		already, and this function is called with a
+ *		list of 1 or more servers, then cyg_sntp_start()
+ *		will be called by this function to start the client.
  *
  *	PARAMETERS
  *		server_list - Array of IPv4 and/or IPv6 sockaddr's
@@ -510,9 +511,21 @@ void cyg_sntp_start(void) {
 void cyg_sntp_set_servers(struct sockaddr *server_list,
         cyg_uint32 num_servers)
 {
-    /* Get the server list mutex */
+	/* If we haven't already started the SNTP client, then
+	 * start it now.
+	 */
     if (!sntp_initialized)
-        return;
+	{
+		/* If we haven't started already and we don't
+		 * have a list of servers, then don't start
+		 * anything up.
+		 */
+		if (num_servers == 0)
+			return;
+		cyg_sntp_start();
+	}
+
+    /* Get the server list mutex */
     cyg_mutex_lock(&sntp_mutex);
 
 	/* Record the new server list */
@@ -526,3 +539,6 @@ void cyg_sntp_set_servers(struct sockadd
 }
 #endif /* CYGPKG_NET_SNTP_UNICAST */
 
+
+
+
--- a/packages/net/sntp/current/tests/sntp1.c
+++ b/packages/net/sntp/current/tests/sntp1.c
@@ -66,7 +66,7 @@ net_test(cyg_addrword_t param)
   int seconds;
   time_t now, build_time;
   struct tm tm={ 0,0,0,0,0,0,0,0,0 };
-  int i;
+  int i, loop, waittime;
   char month[4];
   char months[12][4] = { "Jan", "Feb", "Mar", 
 			 "Apr", "May", "Jun", 
@@ -82,39 +82,78 @@ net_test(cyg_addrword_t param)
 
   cyg_sntp_start();
 
-  for (seconds = 20; seconds > 0; seconds--) {
+  /* The SNTP client will try to obtain NTP time updates by
+   * listening for multicasts.  It can also be configured
+   * to send unicast requests to specific NTP servers.  By
+   * default, unicast NTP servers are obtained from DHCP.
+   *
+   * If unicast mode is enabled, the run the test loop twice.
+   * The first time, unicast requests will be sent.  The
+   * second time, the unicast list will be unconfigured and
+   * the client will listen only for multicasts.
+   *
+   * Note that this test is somewhat bogus since multicast
+   * NTP packets will actually allow both test loops to
+   * pass.  But it is the best we can do for the automated
+   * test, so consider this more of a usage example.
+   */
+#ifdef CYGPKG_NET_SNTP_UNICAST
+  loop = 2;
+#else
+  loop = 1;
+#endif
+  while (loop-- > 0)
+  {
+    if (loop == 1) {
+      CYG_TEST_INFO("Testing SNTP unicast mode.");
+      waittime=14;
+    } else {
+      CYG_TEST_INFO("Testing SNTP multicast mode.");
+      waittime=20;
+    }
+    for (seconds = waittime; seconds > 0; seconds--) {
+      now = time(NULL);
+      ctime_r(&now, time_info);
+      time_info[strlen(time_info)-1] = '\0';  // Strip \n
+      CYG_TEST_INFO(time_info);
+      cyg_thread_delay(100);
+    }
+  
     now = time(NULL);
-    ctime_r(&now, time_info);
-    time_info[strlen(time_info)-1] = '\0';  // Strip \n
-    CYG_TEST_INFO(time_info);
-    cyg_thread_delay(100);
-  }
-  
-  now = time(NULL);
 
-  if ( now < (5 * 60)) {
-    CYG_TEST_FAIL_FINISH("Nothing recieved from the SNTP server");
-  } else {
+    if ( now < (5 * 60)) {
+      CYG_TEST_FAIL_FINISH("Nothing recieved from the SNTP server");
+    } else {
     
-    i=sscanf(__DATE__, "%s %d %d",month,&tm.tm_mday,&tm.tm_year);
-    CYG_ASSERT(3==i,"sscanf did not return enough results");
-    for (i=0; i < 12; i++) {
-      if (!strcmp(month,months[i])) 
-	break;
-    }
-    tm.tm_mon = i;
-    tm.tm_year -= 1900;
+      i=sscanf(__DATE__, "%s %d %d",month,&tm.tm_mday,&tm.tm_year);
+      CYG_ASSERT(3==i,"sscanf did not return enough results");
+      for (i=0; i < 12; i++) {
+        if (!strcmp(month,months[i])) 
+          break;
+      }
+      tm.tm_mon = i;
+      tm.tm_year -= 1900;
 
-    build_time = mktime(&tm);
-    CYG_ASSERT(-1 != build_time,"mktime returned -1");
+      build_time = mktime(&tm);
+      CYG_ASSERT(-1 != build_time,"mktime returned -1");
 
-    if (build_time > time(NULL)) {
-      CYG_TEST_FAIL_FINISH("Build time is ahead of SNTP time");
-    } else {
-      if ((build_time + 60 * 60 * 24 * 90) < time(NULL)) {
-	CYG_TEST_FAIL_FINISH("Build time is more than 90 days old");
+      if (build_time > time(NULL)) {
+        CYG_TEST_FAIL_FINISH("Build time is ahead of SNTP time");
+      } else {
+        if ((build_time + 60 * 60 * 24 * 90) < time(NULL)) {
+  	      CYG_TEST_FAIL_FINISH("Build time is more than 90 days old");
+        }
       }
     }
+
+#ifdef CYGPKG_NET_SNTP_UNICAST
+    /* For the second pass of the test, we set the time
+     * back to epoch and unconfigure the list of SNTP
+     * unicast servers.  This will test non-unicast mode.
+     */
+    cyg_sntp_set_servers(NULL, 0);
+    cyg_libc_time_settime(0);
+#endif
   }
   CYG_TEST_PASS_FINISH("sntp1 test is complete");
 }