From cea6a95c467dfcc1cc82ef3df0f76fccb85f5f04 Mon Sep 17 00:00:00 2001
From: Rob Landley <rob@landley.net>
Date: Tue, 5 Feb 2019 08:40:34 -0600
Subject: Promote sntp to net.

---
 toys/net/sntp.c     | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 toys/pending/sntp.c | 269 ----------------------------------------------------
 2 files changed, 269 insertions(+), 269 deletions(-)
 create mode 100644 toys/net/sntp.c
 delete mode 100644 toys/pending/sntp.c

diff --git a/toys/net/sntp.c b/toys/net/sntp.c
new file mode 100644
index 00000000..edccd209
--- /dev/null
+++ b/toys/net/sntp.c
@@ -0,0 +1,269 @@
+/* sntp.c - sntp client and server
+ *
+ * Copyright 2019 Rob Landley <rob@landley.net>
+ *
+ * See https://www.ietf.org/rfc/rfc4330.txt
+
+  modes: oneshot display, oneshot set, persist, serve, multi
+
+USE_SNTP(NEWTOY(sntp, "m:Sp:asdDqr#<4>17=10[!as]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config SNTP
+  bool "sntp"
+  default y
+  help
+    usage: sntp [-saSdDqm] [-r SHIFT] [-m ADDRESS] [-p PORT] [SERVER]
+
+    Simple Network Time Protocol client. Query SERVER and display time.
+
+    -p	Use PORT (default 123)
+    -s	Set system clock suddenly
+    -a	Adjust system clock gradually
+    -S	Serve time instead of querying (bind to SERVER address if specified)
+    -m	Wait for updates from multicast ADDRESS (RFC 4330 says use 224.0.1.1)
+    -d	Daemonize (run in background re-querying )
+    -D	Daemonize but stay in foreground: re-query time every 1000 seconds
+    -r	Retry shift (every 1<<SHIFT seconds)
+    -q	Quiet (don't display time)
+*/
+
+#define FOR_sntp
+#include "toys.h"
+
+GLOBALS(
+  long r;
+  char *p, *m;
+)
+
+// Seconds from 1900 to 1970, including appropriate leap days
+#define SEVENTIES 2208988800L
+
+union socksaddr {
+  struct sockaddr_in in;
+  struct sockaddr_in6 in6;
+};
+
+// timeout in milliseconds
+int xrecvwait(int fd, char *buf, int len, union socksaddr *sa, int timeout)
+{
+  socklen_t sl = sizeof(*sa);
+
+  if (timeout >= 0) {
+    struct pollfd pfd;
+
+    pfd.fd = fd;
+    pfd.events = POLLIN;
+    if (!xpoll(&pfd, 1, timeout)) return 0;
+  }
+
+  len = recvfrom(fd, buf, len, 0, (void *)sa, &sl);
+  if (len<0) perror_exit("recvfrom");
+
+  return len;
+}
+
+// Adjust timespec by nanosecond offset
+static void nanomove(struct timespec *ts, long long offset)
+{
+  long long nano = ts->tv_nsec + offset, secs = nano/1000000000;
+
+  ts->tv_sec += secs;
+  nano %= 1000000000;
+  if (nano<0) {
+    ts->tv_sec--;
+    nano += 1000000000;
+  }
+  ts->tv_nsec = nano;
+}
+
+// Get time and return ntptime (saving timespec in pointer if not null)
+// NTP time is high 32 bits = seconds since 1970 (blame RFC 868), low 32 bits
+// fraction of a second.
+// diff is how far off we think our clock is from reality (in nanoseconds)
+static unsigned long long lunchtime(struct timespec *television, long long diff)
+{
+  struct timespec tv;
+
+  clock_gettime(CLOCK_REALTIME, &tv);
+  if (diff) nanomove(&tv, diff);
+
+  if (television) *television = tv;
+
+  // Unix time is 1970 but RFCs 868 and 958 said 1900 so add seconds 1900->1970
+  // If they'd done a 34/30 bit split the Y2036 problem would be centuries
+  // from now and still give us nanosecond accuracy, but no...
+  return ((tv.tv_sec+SEVENTIES)<<32)+(((long long)tv.tv_nsec)<<32)/1000000000;
+}
+
+// convert ntptime back to struct timespec.
+static void doublyso(unsigned long long now, struct timespec *tv)
+{
+  // Y2036 fixup: if time wrapped, it's in the future
+  tv->tv_sec = (now>>32) + (1LL<<32)*!(now&(1LL<<63));
+  tv->tv_sec -= SEVENTIES; // Force signed math for Y2038 fixup
+  tv->tv_nsec = ((now&0xFFFFFFFF)*1000000000)>>32;
+}
+
+// return difference between two timespecs in nanosecs
+static long long nanodiff(struct timespec *old, struct timespec *new)
+{
+  return (new->tv_sec - old->tv_sec)*1000000000LL+(new->tv_nsec - old->tv_nsec);
+}
+
+void sntp_main(void)
+{
+  struct timespec tv, tv2;
+  unsigned long long *pktime = (void *)toybuf, now, then, before = before;
+  long long diff = 0;
+  struct addrinfo *ai;
+  union socksaddr sa;
+  int fd, tries = 0;
+
+  if (!(FLAG(S)||FLAG(m)) && !*toys.optargs)
+    error_exit("Need -Sm or SERVER address");
+
+  // Lookup address and open server or client UDP socket
+  if (!TT.p || !*TT.p) TT.p = "123";
+  ai = xgetaddrinfo(*toys.optargs, TT.p, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
+    AI_PASSIVE*!*toys.optargs);
+
+  if (FLAG(d) && daemon(0, 0)) perror_exit("daemonize");
+
+  // Act as server if necessary
+  if (FLAG(S)|FLAG(m)) {
+    fd = xbind(ai);
+    if (TT.m) {
+      struct ip_mreq group;
+
+      // subscribe to multicast group
+      memset(&group, 0, sizeof(group));
+      group.imr_multiaddr.s_addr = inet_addr(TT.m);
+      xsetsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group));
+    }
+  } else fd = xsocket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP);
+
+  // -Sm = loop waiting for input
+  // -Dd = loop polling time and waiting until next poll period
+  // Otherwise poll up to 3 times to get 2 responses, then exit
+
+  // loop sending/receiving packets
+  for (;;) {
+    now = millitime();
+
+    // Figure out if we're in server and multicast modes don't poll
+    if (FLAG(m) || FLAG(S)) then = -1;
+
+    // daemon and oneshot modes send a packet each time through outer loop
+    else {
+      then = now + 3000;
+      if (FLAG(d) || FLAG(D)) then = now + (1<<TT.r)*1000;
+
+      // Send NTP query packet
+      memset(toybuf, 0, 48);
+      *toybuf = 0xe3; // li = 3 (unsynchronized), version = 4, mode = 3 (client)
+      toybuf[2] = 8;  // poll frequency 1<<8 = 256 seconds
+      pktime[5] = SWAP_BE64(before = lunchtime(&tv, diff));
+      xsendto(fd, toybuf, 48, ai->ai_addr);
+    }
+
+    // Loop receiving packets until it's time to send the next one.
+    for (;;) {
+      int strike;
+
+      // Wait to receive a packet
+
+      if (then>0 && then<(now = millitime())) break;;
+      strike = xrecvwait(fd, toybuf, sizeof(toybuf), &sa, then-now);
+      if (strike<1) {
+        if (!(FLAG(S)||FLAG(m)||FLAG(D)||FLAG(d)) && ++tries == 3)
+          error_exit("no reply from %s", *toys.optargs);
+        break;
+      }
+      if (strike<48) continue;
+
+      // Validate packet
+      if (!FLAG(S) || FLAG(m)) {
+        char buf[128];
+        int mode = 7&*toybuf;
+
+        // Is source address what we expect?
+        xstrncpy(buf, ntop(ai->ai_addr), 128);
+        strike = strcmp(buf, ntop((void *)&sa));
+        // Does this reply's originate timestamp match the packet we sent?
+        if (!FLAG(S) && !FLAG(m) && before != SWAP_BE64(pktime[3])) continue;
+        // Ignore packets from wrong address or with wrong mode
+        if (strike && !FLAG(S)) continue;
+        if (!((FLAG(m) && mode==5) || (FLAG(S) && mode==3) ||
+            (!FLAG(m) && !FLAG(S) && mode==4))) continue;
+      }
+
+      // If received a -S request packet, send server packet
+      if (strike) {
+        char *buf = toybuf+48;
+
+        *buf = 0x24;  // LI 0 VN 4 mode 4.
+        buf[1] = 3;   // stratum 3
+        buf[2] = 10;  // recommended retry every 1<<10=1024 seconds
+        buf[3] = 250; // precision -6, minimum allowed
+        strcpy(buf+12, "LOCL");
+        pktime[6+3] = pktime[5]; // send back reference time they sent us
+        // everything else is current time
+        pktime[6+2] = pktime[6+4] = pktime[6+5] = SWAP_BE64(lunchtime(0, 0));
+        xsendto(fd, buf, 48, (void *)&sa);
+
+      // Got a time packet from a recognized server
+      } else {
+        int unset = !diff;
+
+        // First packet: figure out how far off our clock is from what server
+        // said and try again. Don't set clock, just record offset to use
+        // generating second reuest. (We know this time is in the past
+        // because transmission took time, but it's a start. And if time is
+        // miraculously exact, don't loop.)
+ 
+        lunchtime(&tv2, diff);
+        diff = nanodiff(&tv, &tv2);
+        if (unset && diff) break;
+
+        // Second packet: determine midpoint of packet transit time according
+        // to local clock, assuming each direction took same time so midpoint
+        // is time server reported. The first television was the adjusted time
+        // we sent the packet at, tv2 is what server replied, so now diff
+        // is round trip time.
+
+        // What time did the server say and how far off are we?
+        nanomove(&tv, diff/2);
+        doublyso(SWAP_BE64(pktime[5]), &tv2);
+        diff = nanodiff(&tv, &tv2);
+
+        if (FLAG(s)) {
+          // Do read/adjust/set to lose as little time as possible.
+          clock_gettime(CLOCK_REALTIME, &tv2);
+          nanomove(&tv2, diff);
+          if (clock_settime(CLOCK_REALTIME, &tv2))
+            perror_exit("clock_settime");
+        } else if (FLAG(a)) {
+          struct timeval why;
+
+          // call adjtime() to move the clock gradually, copying nanoseconds
+          // into gratuitous microseconds structure for sad historical reasons
+          memset(&tv2, 0, sizeof(tv2));
+          nanomove(&tv2, diff);
+          why.tv_sec = tv2.tv_sec;
+          why.tv_usec = tv2.tv_nsec/1000;
+          if (adjtime(&why, 0)) perror_exit("adjtime");
+        }
+
+        // Display the time and offset
+        if (!FLAG(q)) {
+          format_iso_time(toybuf, sizeof(toybuf)-1, &tv2);
+          printf("%s offset %c%lld.%09lld secs\n", toybuf, (diff<0) ? '-' : '+',
+            llabs(diff/1000000000), llabs(diff%1000000000));
+        }
+
+        // If we're not in daemon mode, we're done. (Can't get here for -S.)
+        if (!FLAG(d) && !FLAG(D)) return;
+      }
+    }
+  }
+}
diff --git a/toys/pending/sntp.c b/toys/pending/sntp.c
deleted file mode 100644
index f1415332..00000000
--- a/toys/pending/sntp.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/* sntp.c - sntp client and server
- *
- * Copyright 2019 Rob Landley <rob@landley.net>
- *
- * See https://www.ietf.org/rfc/rfc4330.txt
-
-  modes: oneshot display, oneshot set, persist, serve, multi
-
-USE_SNTP(NEWTOY(sntp, "m:Sp:asdDqr#<4>17=10[!as]", TOYFLAG_USR|TOYFLAG_BIN))
-
-config SNTP
-  bool "sntp"
-  default n
-  help
-    usage: sntp [-saSdDqm] [-r SHIFT] [-m ADDRESS] [-p PORT] [SERVER]
-
-    Simple Network Time Protocol client. Query SERVER and display time.
-
-    -p	Use PORT (default 123)
-    -s	Set system clock suddenly
-    -a	Adjust system clock gradually
-    -S	Serve time instead of querying (bind to SERVER address if specified)
-    -m	Wait for updates from multicast ADDRESS (RFC 4330 says use 224.0.1.1)
-    -d	Daemonize (run in background re-querying )
-    -D	Daemonize but stay in foreground: re-query time every 1000 seconds
-    -r	Retry shift (every 1<<SHIFT seconds)
-    -q	Quiet (don't display time)
-*/
-
-#define FOR_sntp
-#include "toys.h"
-
-GLOBALS(
-  long r;
-  char *p, *m;
-)
-
-// Seconds from 1900 to 1970, including appropriate leap days
-#define SEVENTIES 2208988800L
-
-union socksaddr {
-  struct sockaddr_in in;
-  struct sockaddr_in6 in6;
-};
-
-// timeout in milliseconds
-int xrecvwait(int fd, char *buf, int len, union socksaddr *sa, int timeout)
-{
-  socklen_t sl = sizeof(*sa);
-
-  if (timeout >= 0) {
-    struct pollfd pfd;
-
-    pfd.fd = fd;
-    pfd.events = POLLIN;
-    if (!xpoll(&pfd, 1, timeout)) return 0;
-  }
-
-  len = recvfrom(fd, buf, len, 0, (void *)sa, &sl);
-  if (len<0) perror_exit("recvfrom");
-
-  return len;
-}
-
-// Adjust timespec by nanosecond offset
-static void nanomove(struct timespec *ts, long long offset)
-{
-  long long nano = ts->tv_nsec + offset, secs = nano/1000000000;
-
-  ts->tv_sec += secs;
-  nano %= 1000000000;
-  if (nano<0) {
-    ts->tv_sec--;
-    nano += 1000000000;
-  }
-  ts->tv_nsec = nano;
-}
-
-// Get time and return ntptime (saving timespec in pointer if not null)
-// NTP time is high 32 bits = seconds since 1970 (blame RFC 868), low 32 bits
-// fraction of a second.
-// diff is how far off we think our clock is from reality (in nanoseconds)
-static unsigned long long lunchtime(struct timespec *television, long long diff)
-{
-  struct timespec tv;
-
-  clock_gettime(CLOCK_REALTIME, &tv);
-  if (diff) nanomove(&tv, diff);
-
-  if (television) *television = tv;
-
-  // Unix time is 1970 but RFCs 868 and 958 said 1900 so add seconds 1900->1970
-  // If they'd done a 34/30 bit split the Y2036 problem would be centuries
-  // from now and still give us nanosecond accuracy, but no...
-  return ((tv.tv_sec+SEVENTIES)<<32)+(((long long)tv.tv_nsec)<<32)/1000000000;
-}
-
-// convert ntptime back to struct timespec.
-static void doublyso(unsigned long long now, struct timespec *tv)
-{
-  // Y2036 fixup: if time wrapped, it's in the future
-  tv->tv_sec = (now>>32) + (1LL<<32)*!(now&(1LL<<63));
-  tv->tv_sec -= SEVENTIES; // Force signed math for Y2038 fixup
-  tv->tv_nsec = ((now&0xFFFFFFFF)*1000000000)>>32;
-}
-
-// return difference between two timespecs in nanosecs
-static long long nanodiff(struct timespec *old, struct timespec *new)
-{
-  return (new->tv_sec - old->tv_sec)*1000000000LL+(new->tv_nsec - old->tv_nsec);
-}
-
-void sntp_main(void)
-{
-  struct timespec tv, tv2;
-  unsigned long long *pktime = (void *)toybuf, now, then, before = before;
-  long long diff = 0;
-  struct addrinfo *ai;
-  union socksaddr sa;
-  int fd, tries = 0;
-
-  if (!(FLAG(S)||FLAG(m)) && !*toys.optargs)
-    error_exit("Need -Sm or SERVER address");
-
-  // Lookup address and open server or client UDP socket
-  if (!TT.p || !*TT.p) TT.p = "123";
-  ai = xgetaddrinfo(*toys.optargs, TT.p, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
-    AI_PASSIVE*!*toys.optargs);
-
-  if (FLAG(d) && daemon(0, 0)) perror_exit("daemonize");
-
-  // Act as server if necessary
-  if (FLAG(S)|FLAG(m)) {
-    fd = xbind(ai);
-    if (TT.m) {
-      struct ip_mreq group;
-
-      // subscribe to multicast group
-      memset(&group, 0, sizeof(group));
-      group.imr_multiaddr.s_addr = inet_addr(TT.m);
-      xsetsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group));
-    }
-  } else fd = xsocket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP);
-
-  // -Sm = loop waiting for input
-  // -Dd = loop polling time and waiting until next poll period
-  // Otherwise poll up to 3 times to get 2 responses, then exit
-
-  // loop sending/receiving packets
-  for (;;) {
-    now = millitime();
-
-    // Figure out if we're in server and multicast modes don't poll
-    if (FLAG(m) || FLAG(S)) then = -1;
-
-    // daemon and oneshot modes send a packet each time through outer loop
-    else {
-      then = now + 3000;
-      if (FLAG(d) || FLAG(D)) then = now + (1<<TT.r)*1000;
-
-      // Send NTP query packet
-      memset(toybuf, 0, 48);
-      *toybuf = 0xe3; // li = 3 (unsynchronized), version = 4, mode = 3 (client)
-      toybuf[2] = 8;  // poll frequency 1<<8 = 256 seconds
-      pktime[5] = SWAP_BE64(before = lunchtime(&tv, diff));
-      xsendto(fd, toybuf, 48, ai->ai_addr);
-    }
-
-    // Loop receiving packets until it's time to send the next one.
-    for (;;) {
-      int strike;
-
-      // Wait to receive a packet
-
-      if (then>0 && then<(now = millitime())) break;;
-      strike = xrecvwait(fd, toybuf, sizeof(toybuf), &sa, then-now);
-      if (strike<1) {
-        if (!(FLAG(S)||FLAG(m)||FLAG(D)||FLAG(d)) && ++tries == 3)
-          error_exit("no reply from %s", *toys.optargs);
-        break;
-      }
-      if (strike<48) continue;
-
-      // Validate packet
-      if (!FLAG(S) || FLAG(m)) {
-        char buf[128];
-        int mode = 7&*toybuf;
-
-        // Is source address what we expect?
-        xstrncpy(buf, ntop(ai->ai_addr), 128);
-        strike = strcmp(buf, ntop((void *)&sa));
-        // Does this reply's originate timestamp match the packet we sent?
-        if (!FLAG(S) && !FLAG(m) && before != SWAP_BE64(pktime[3])) continue;
-        // Ignore packets from wrong address or with wrong mode
-        if (strike && !FLAG(S)) continue;
-        if (!((FLAG(m) && mode==5) || (FLAG(S) && mode==3) ||
-            (!FLAG(m) && !FLAG(S) && mode==4))) continue;
-      }
-
-      // If received a -S request packet, send server packet
-      if (strike) {
-        char *buf = toybuf+48;
-
-        *buf = 0x24;  // LI 0 VN 4 mode 4.
-        buf[1] = 3;   // stratum 3
-        buf[2] = 10;  // recommended retry every 1<<10=1024 seconds
-        buf[3] = 250; // precision -6, minimum allowed
-        strcpy(buf+12, "LOCL");
-        pktime[6+3] = pktime[5]; // send back reference time they sent us
-        // everything else is current time
-        pktime[6+2] = pktime[6+4] = pktime[6+5] = SWAP_BE64(lunchtime(0, 0));
-        xsendto(fd, buf, 48, (void *)&sa);
-
-      // Got a time packet from a recognized server
-      } else {
-        int unset = !diff;
-
-        // First packet: figure out how far off our clock is from what server
-        // said and try again. Don't set clock, just record offset to use
-        // generating second reuest. (We know this time is in the past
-        // because transmission took time, but it's a start. And if time is
-        // miraculously exact, don't loop.)
- 
-        lunchtime(&tv2, diff);
-        diff = nanodiff(&tv, &tv2);
-        if (unset && diff) break;
-
-        // Second packet: determine midpoint of packet transit time according
-        // to local clock, assuming each direction took same time so midpoint
-        // is time server reported. The first television was the adjusted time
-        // we sent the packet at, tv2 is what server replied, so now diff
-        // is round trip time.
-
-        // What time did the server say and how far off are we?
-        nanomove(&tv, diff/2);
-        doublyso(SWAP_BE64(pktime[5]), &tv2);
-        diff = nanodiff(&tv, &tv2);
-
-        if (FLAG(s)) {
-          // Do read/adjust/set to lose as little time as possible.
-          clock_gettime(CLOCK_REALTIME, &tv2);
-          nanomove(&tv2, diff);
-          if (clock_settime(CLOCK_REALTIME, &tv2))
-            perror_exit("clock_settime");
-        } else if (FLAG(a)) {
-          struct timeval why;
-
-          // call adjtime() to move the clock gradually, copying nanoseconds
-          // into gratuitous microseconds structure for sad historical reasons
-          memset(&tv2, 0, sizeof(tv2));
-          nanomove(&tv2, diff);
-          why.tv_sec = tv2.tv_sec;
-          why.tv_usec = tv2.tv_nsec/1000;
-          if (adjtime(&why, 0)) perror_exit("adjtime");
-        }
-
-        // Display the time and offset
-        if (!FLAG(q)) {
-          format_iso_time(toybuf, sizeof(toybuf)-1, &tv2);
-          printf("%s offset %c%lld.%09lld secs\n", toybuf, (diff<0) ? '-' : '+',
-            llabs(diff/1000000000), llabs(diff%1000000000));
-        }
-
-        // If we're not in daemon mode, we're done. (Can't get here for -S.)
-        if (!FLAG(d) && !FLAG(D)) return;
-      }
-    }
-  }
-}
-- 
cgit v1.2.3