summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/libntp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ntp/libntp')
-rw-r--r--contrib/ntp/libntp/Makefile.in4
-rw-r--r--contrib/ntp/libntp/atolfp.c2
-rw-r--r--contrib/ntp/libntp/audio.c13
-rw-r--r--contrib/ntp/libntp/authkeys.c12
-rw-r--r--contrib/ntp/libntp/authreadkeys.c89
-rw-r--r--contrib/ntp/libntp/caljulian.c2
-rw-r--r--contrib/ntp/libntp/caltontp.c14
-rw-r--r--contrib/ntp/libntp/decodenetnum.c9
-rw-r--r--contrib/ntp/libntp/emalloc.c2
-rw-r--r--contrib/ntp/libntp/icom.c28
-rw-r--r--contrib/ntp/libntp/machines.c6
-rw-r--r--contrib/ntp/libntp/msyslog.c24
-rw-r--r--contrib/ntp/libntp/ntp_calendar.c786
-rw-r--r--contrib/ntp/libntp/ntp_intres.c24
-rw-r--r--contrib/ntp/libntp/ntp_lineedit.c2
-rw-r--r--contrib/ntp/libntp/ntp_rfc2553.c2
-rw-r--r--contrib/ntp/libntp/ntp_worker.c2
-rw-r--r--contrib/ntp/libntp/prettydate.c2
-rw-r--r--contrib/ntp/libntp/recvbuff.c2
-rw-r--r--contrib/ntp/libntp/socket.c4
-rw-r--r--contrib/ntp/libntp/socktohost.c2
-rw-r--r--contrib/ntp/libntp/statestr.c2
22 files changed, 653 insertions, 380 deletions
diff --git a/contrib/ntp/libntp/Makefile.in b/contrib/ntp/libntp/Makefile.in
index b4b1d81..6e40cd4 100644
--- a/contrib/ntp/libntp/Makefile.in
+++ b/contrib/ntp/libntp/Makefile.in
@@ -117,6 +117,7 @@ am__aclocal_m4_deps = $(top_srcdir)/sntp/libopts/m4/libopts.m4 \
$(top_srcdir)/sntp/m4/ntp_locinfo.m4 \
$(top_srcdir)/sntp/m4/ntp_openssl.m4 \
$(top_srcdir)/sntp/m4/ntp_pkg_config.m4 \
+ $(top_srcdir)/sntp/m4/ntp_problemtests.m4 \
$(top_srcdir)/sntp/m4/ntp_prog_cc.m4 \
$(top_srcdir)/sntp/m4/ntp_rlimit.m4 \
$(top_srcdir)/sntp/m4/ntp_sntp.m4 \
@@ -345,6 +346,7 @@ AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
+BUILD_THREAD = @BUILD_THREAD@
CALC_TICKADJ_DB = @CALC_TICKADJ_DB@
CALC_TICKADJ_DL = @CALC_TICKADJ_DL@
CALC_TICKADJ_DS = @CALC_TICKADJ_DS@
@@ -353,6 +355,7 @@ CALC_TICKADJ_NI = @CALC_TICKADJ_NI@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
+CFLAGS_LIBEVENT = @CFLAGS_LIBEVENT@
CFLAGS_NTP = @CFLAGS_NTP@
CHUTEST = @CHUTEST@
CONFIG_SHELL = @CONFIG_SHELL@
@@ -414,6 +417,7 @@ LIBTOOL_DEPS = @LIBTOOL_DEPS@
LIPO = @LIPO@
LN_S = @LN_S@
LSCF = @LSCF@
+LTHREAD_LIBS = @LTHREAD_LIBS@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
MAKE_ADJTIMED = @MAKE_ADJTIMED@
diff --git a/contrib/ntp/libntp/atolfp.c b/contrib/ntp/libntp/atolfp.c
index 3a65f6b..9a2f691 100644
--- a/contrib/ntp/libntp/atolfp.c
+++ b/contrib/ntp/libntp/atolfp.c
@@ -40,7 +40,7 @@ atolfp(
int isneg;
static const char *digits = "0123456789";
- NTP_REQUIRE(str != NULL);
+ REQUIRE(str != NULL);
isneg = 0;
dec_i = dec_f = 0;
diff --git a/contrib/ntp/libntp/audio.c b/contrib/ntp/libntp/audio.c
index 6f2262c..726dfa9 100644
--- a/contrib/ntp/libntp/audio.c
+++ b/contrib/ntp/libntp/audio.c
@@ -377,7 +377,9 @@ audio_gain(
#ifdef PCM_STYLE_SOUND
int l, r;
- rval = 0;
+# ifdef GCC
+ rval = 0; /* GCC thinks rval is used uninitialized */
+# endif
r = l = 100 * gain / 255; /* Normalize to 0-100 */
# ifdef DEBUG
@@ -392,10 +394,11 @@ audio_gain(
if (cf_agc[0] != '\0')
rval = ioctl(ctl_fd, agc, &l);
else
- if (2 == port)
- rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_LINE, &l);
- else
- rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_MIC, &l);
+ rval = ioctl(ctl_fd
+ , (2 == port)
+ ? SOUND_MIXER_WRITE_LINE
+ : SOUND_MIXER_WRITE_MIC
+ , &l);
if (-1 == rval) {
printf("audio_gain: agc write: %s\n", strerror(errno));
return rval;
diff --git a/contrib/ntp/libntp/authkeys.c b/contrib/ntp/libntp/authkeys.c
index 68771ff..667ca29 100644
--- a/contrib/ntp/libntp/authkeys.c
+++ b/contrib/ntp/libntp/authkeys.c
@@ -534,6 +534,12 @@ MD5auth_setkey(
bucket = &key_hash[KEYHASH(keyno)];
for (sk = *bucket; sk != NULL; sk = sk->hlink) {
if (keyno == sk->keyid) {
+ /* TALOS-CAN-0054: make sure we have a new buffer! */
+ if (NULL != sk->secret) {
+ memset(sk->secret, 0, sk->secretsize);
+ free(sk->secret);
+ }
+ sk->secret = emalloc(len);
sk->type = (u_short)keytype;
secretsize = len;
sk->secretsize = (u_short)secretsize;
@@ -593,12 +599,14 @@ auth_delkeys(void)
}
/*
- * Don't lose info as to which keys are trusted.
+ * Don't lose info as to which keys are trusted. Make
+ * sure there are no dangling pointers!
*/
if (KEY_TRUSTED & sk->flags) {
if (sk->secret != NULL) {
- memset(sk->secret, '\0', sk->secretsize);
+ memset(sk->secret, 0, sk->secretsize);
free(sk->secret);
+ sk->secret = NULL; /* TALOS-CAN-0054 */
}
sk->secretsize = 0;
sk->lifetime = 0;
diff --git a/contrib/ntp/libntp/authreadkeys.c b/contrib/ntp/libntp/authreadkeys.c
index e8ddc94..1c4c07c 100644
--- a/contrib/ntp/libntp/authreadkeys.c
+++ b/contrib/ntp/libntp/authreadkeys.c
@@ -62,6 +62,40 @@ nexttok(
}
+/* TALOS-CAN-0055: possibly DoS attack by setting the key file to the
+ * log file. This is hard to prevent (it would need to check two files
+ * to be the same on the inode level, which will not work so easily with
+ * Windows or VMS) but we can avoid the self-amplification loop: We only
+ * log the first 5 errors, silently ignore the next 10 errors, and give
+ * up when when we have found more than 15 errors.
+ *
+ * This avoids the endless file iteration we will end up with otherwise,
+ * and also avoids overflowing the log file.
+ *
+ * Nevertheless, once this happens, the keys are gone since this would
+ * require a save/swap strategy that is not easy to apply due to the
+ * data on global/static level.
+ */
+
+static const size_t nerr_loglimit = 5u;
+static const size_t nerr_maxlimit = 15;
+
+static void log_maybe(size_t*, const char*, ...) NTP_PRINTF(2, 3);
+
+static void
+log_maybe(
+ size_t *pnerr,
+ const char *fmt ,
+ ...)
+{
+ va_list ap;
+ if (++(*pnerr) <= nerr_loglimit) {
+ va_start(ap, fmt);
+ mvsyslog(LOG_ERR, fmt, ap);
+ va_end(ap);
+ }
+}
+
/*
* authreadkeys - (re)read keys from a file.
*/
@@ -79,7 +113,7 @@ authreadkeys(
u_char keystr[32]; /* Bug 2537 */
size_t len;
size_t j;
-
+ size_t nerr;
/*
* Open file. Complain and return if it can't be opened.
*/
@@ -99,7 +133,10 @@ authreadkeys(
/*
* Now read lines from the file, looking for key entries
*/
+ nerr = 0;
while ((line = fgets(buf, sizeof buf, fp)) != NULL) {
+ if (nerr > nerr_maxlimit)
+ break;
token = nexttok(&line);
if (token == NULL)
continue;
@@ -109,15 +146,16 @@ authreadkeys(
*/
keyno = atoi(token);
if (keyno == 0) {
- msyslog(LOG_ERR,
- "authreadkeys: cannot change key %s", token);
+ log_maybe(&nerr,
+ "authreadkeys: cannot change key %s",
+ token);
continue;
}
if (keyno > NTP_MAXKEY) {
- msyslog(LOG_ERR,
- "authreadkeys: key %s > %d reserved for Autokey",
- token, NTP_MAXKEY);
+ log_maybe(&nerr,
+ "authreadkeys: key %s > %d reserved for Autokey",
+ token, NTP_MAXKEY);
continue;
}
@@ -126,8 +164,9 @@ authreadkeys(
*/
token = nexttok(&line);
if (token == NULL) {
- msyslog(LOG_ERR,
- "authreadkeys: no key type for key %d", keyno);
+ log_maybe(&nerr,
+ "authreadkeys: no key type for key %d",
+ keyno);
continue;
}
#ifdef OPENSSL
@@ -139,13 +178,15 @@ authreadkeys(
*/
keytype = keytype_from_text(token, NULL);
if (keytype == 0) {
- msyslog(LOG_ERR,
- "authreadkeys: invalid type for key %d", keyno);
+ log_maybe(&nerr,
+ "authreadkeys: invalid type for key %d",
+ keyno);
continue;
}
if (EVP_get_digestbynid(keytype) == NULL) {
- msyslog(LOG_ERR,
- "authreadkeys: no algorithm for key %d", keyno);
+ log_maybe(&nerr,
+ "authreadkeys: no algorithm for key %d",
+ keyno);
continue;
}
#else /* !OPENSSL follows */
@@ -155,8 +196,9 @@ authreadkeys(
* 'm' for compatibility.
*/
if (!(*token == 'M' || *token == 'm')) {
- msyslog(LOG_ERR,
- "authreadkeys: invalid type for key %d", keyno);
+ log_maybe(&nerr,
+ "authreadkeys: invalid type for key %d",
+ keyno);
continue;
}
keytype = KEY_TYPE_MD5;
@@ -170,8 +212,8 @@ authreadkeys(
*/
token = nexttok(&line);
if (token == NULL) {
- msyslog(LOG_ERR,
- "authreadkeys: no key for key %d", keyno);
+ log_maybe(&nerr,
+ "authreadkeys: no key for key %d", keyno);
continue;
}
len = strlen(token);
@@ -195,13 +237,24 @@ authreadkeys(
keystr[j / 2] = temp << 4;
}
if (j < jlim) {
- msyslog(LOG_ERR,
- "authreadkeys: invalid hex digit for key %d", keyno);
+ log_maybe(&nerr,
+ "authreadkeys: invalid hex digit for key %d",
+ keyno);
continue;
}
MD5auth_setkey(keyno, keytype, keystr, jlim / 2);
}
}
fclose(fp);
+ if (nerr > nerr_maxlimit) {
+ msyslog(LOG_ERR,
+ "authreadkeys: emergency break after %u errors",
+ nerr);
+ return (0);
+ } else if (nerr > nerr_loglimit) {
+ msyslog(LOG_ERR,
+ "authreadkeys: found %u more error(s)",
+ nerr - nerr_loglimit);
+ }
return (1);
}
diff --git a/contrib/ntp/libntp/caljulian.c b/contrib/ntp/libntp/caljulian.c
index 6463699..4a30603 100644
--- a/contrib/ntp/libntp/caljulian.c
+++ b/contrib/ntp/libntp/caljulian.c
@@ -28,7 +28,7 @@ caljulian(
ntpcal_split split;
- NTP_INSIST(NULL != jt);
+ INSIST(NULL != jt);
/*
* Unfold ntp time around current time into NTP domain. Split
diff --git a/contrib/ntp/libntp/caltontp.c b/contrib/ntp/libntp/caltontp.c
index 4246a6a..808c94c 100644
--- a/contrib/ntp/libntp/caltontp.c
+++ b/contrib/ntp/libntp/caltontp.c
@@ -40,14 +40,14 @@ caltontp(
int32_t eraday; /* CE Rata Die number */
vint64 ntptime;/* resulting NTP time */
- NTP_INSIST(jt != NULL);
+ REQUIRE(jt != NULL);
- NTP_REQUIRE(jt->month <= 13); /* permit month 0..13! */
- NTP_REQUIRE(jt->monthday <= 32);
- NTP_REQUIRE(jt->yearday <= 366);
- NTP_REQUIRE(jt->hour <= 24);
- NTP_REQUIRE(jt->minute <= MINSPERHR);
- NTP_REQUIRE(jt->second <= SECSPERMIN);
+ REQUIRE(jt->month <= 13); /* permit month 0..13! */
+ REQUIRE(jt->monthday <= 32);
+ REQUIRE(jt->yearday <= 366);
+ REQUIRE(jt->hour <= 24);
+ REQUIRE(jt->minute <= MINSPERHR);
+ REQUIRE(jt->second <= SECSPERMIN);
/*
* First convert the date to he corresponding RataDie
diff --git a/contrib/ntp/libntp/decodenetnum.c b/contrib/ntp/libntp/decodenetnum.c
index 187d5ca..35b908f 100644
--- a/contrib/ntp/libntp/decodenetnum.c
+++ b/contrib/ntp/libntp/decodenetnum.c
@@ -35,8 +35,11 @@ decodenetnum(
char *np;
char name[80];
- NTP_REQUIRE(num != NULL);
- NTP_REQUIRE(strlen(num) < sizeof(name));
+ REQUIRE(num != NULL);
+
+ if (strlen(num) >= sizeof(name)) {
+ return 0;
+ }
port_str = NULL;
if ('[' != num[0]) {
@@ -72,7 +75,7 @@ decodenetnum(
err = getaddrinfo(cp, "ntp", &hints, &ai);
if (err != 0)
return 0;
- NTP_INSIST(ai->ai_addrlen <= sizeof(*netnum));
+ INSIST(ai->ai_addrlen <= sizeof(*netnum));
ZERO(*netnum);
memcpy(netnum, ai->ai_addr, ai->ai_addrlen);
freeaddrinfo(ai);
diff --git a/contrib/ntp/libntp/emalloc.c b/contrib/ntp/libntp/emalloc.c
index 95d293f..8b7ef99 100644
--- a/contrib/ntp/libntp/emalloc.c
+++ b/contrib/ntp/libntp/emalloc.c
@@ -76,8 +76,6 @@ ereallocz(
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdint.h>
-
/*
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
diff --git a/contrib/ntp/libntp/icom.c b/contrib/ntp/libntp/icom.c
index 8070011..2e95db5 100644
--- a/contrib/ntp/libntp/icom.c
+++ b/contrib/ntp/libntp/icom.c
@@ -6,14 +6,16 @@
* frequency. All other parameters must be manually set before use.
*/
#include <config.h>
-#include "icom.h"
+#include <ntp_stdlib.h>
+#include <ntp_tty.h>
+#include <l_stdlib.h>
+#include <icom.h>
+
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
-#include "ntp_tty.h"
-#include "l_stdlib.h"
#ifdef SYS_WINNT
#undef write /* ports/winnt/include/config.h: #define write _write */
@@ -60,9 +62,14 @@ static void doublefreq (double, u_char *, int);
/*
* icom_freq(fd, ident, freq) - load radio frequency
+ *
+ * returns:
+ * 0 (ok)
+ * -1 (error)
+ * 1 (short write to device)
*/
int
-icom_freq( /* returns 0 (ok), EIO (error) */
+icom_freq(
int fd, /* file descriptor */
int ident, /* ICOM radio identifier */
double freq /* frequency (MHz) */
@@ -71,6 +78,7 @@ icom_freq( /* returns 0 (ok), EIO (error) */
u_char cmd[] = {PAD, PR, PR, 0, TX, V_SFREQ, 0, 0, 0, 0, FI,
FI};
int temp;
+ int rc;
cmd[3] = (char)ident;
if (ident == IC735)
@@ -78,9 +86,17 @@ icom_freq( /* returns 0 (ok), EIO (error) */
else
temp = 5;
doublefreq(freq * 1e6, &cmd[6], temp);
- temp = write(fd, cmd, temp + 7);
+ rc = write(fd, cmd, temp + 7);
+ if (rc == -1) {
+ msyslog(LOG_ERR, "icom_freq: write() failed: %m");
+ return -1;
+ } else if (rc != temp + 7) {
+ msyslog(LOG_ERR, "icom_freq: only wrote %d of %d bytes.",
+ rc, temp+7);
+ return 1;
+ }
- return (0);
+ return 0;
}
diff --git a/contrib/ntp/libntp/machines.c b/contrib/ntp/libntp/machines.c
index 43944f9..7a29ac0 100644
--- a/contrib/ntp/libntp/machines.c
+++ b/contrib/ntp/libntp/machines.c
@@ -40,7 +40,7 @@ struct hostent *gethostbyname(char *name)
{
struct hostent *host1;
h_errno = 0; /* we are always successful!!! */
- host1 = (struct hostent *) malloc (sizeof(struct hostent));
+ host1 = (struct hostent *) emalloc (sizeof(struct hostent));
host1->h_name = name;
host1->h_addrtype = AF_INET;
host1->h_aliases = name;
@@ -54,7 +54,7 @@ struct hostent *gethostbyaddr(char *name, int size, int addr_type)
{
struct hostent *host1;
h_errno = 0; /* we are always successful!!! */
- host1 = (struct hostent *) malloc (sizeof(struct hostent));
+ host1 = (struct hostent *) emalloc (sizeof(struct hostent));
host1->h_name = name;
host1->h_addrtype = AF_INET;
host1->h_aliases = name;
@@ -66,7 +66,7 @@ struct hostent *gethostbyaddr(char *name, int size, int addr_type)
struct servent *getservbyname (char *name, char *type)
{
struct servent *serv1;
- serv1 = (struct servent *) malloc (sizeof(struct servent));
+ serv1 = (struct servent *) emalloc (sizeof(struct servent));
serv1->s_name = "ntp"; /* official service name */
serv1->s_aliases = NULL; /* alias list */
serv1->s_port = 123; /* port # */
diff --git a/contrib/ntp/libntp/msyslog.c b/contrib/ntp/libntp/msyslog.c
index 283414d..cc8868f 100644
--- a/contrib/ntp/libntp/msyslog.c
+++ b/contrib/ntp/libntp/msyslog.c
@@ -38,7 +38,7 @@ char * syslog_abs_fname;
#define INIT_NTP_SYSLOGMASK ~(u_int32)0
u_int32 ntp_syslogmask = INIT_NTP_SYSLOGMASK;
-extern char * progname;
+extern char const * progname;
/* Declare the local functions */
void addto_syslog (int, const char *);
@@ -145,8 +145,8 @@ addto_syslog(
const char * msg
)
{
- static char * prevcall_progname;
- static char * prog;
+ static char const * prevcall_progname;
+ static char const * prog;
const char nl[] = "\n";
const char empty[] = "";
FILE * term_file;
@@ -357,6 +357,18 @@ msyslog(
addto_syslog(level, buf);
}
+void
+mvsyslog(
+ int level,
+ const char * fmt,
+ va_list ap
+ )
+{
+ char buf[1024];
+ mvsnprintf(buf, sizeof(buf), fmt, ap);
+ addto_syslog(level, buf);
+}
+
/*
* Initialize the logging
@@ -371,7 +383,7 @@ init_logging(
)
{
static int was_daemon;
- const char * cp;
+ char * cp;
const char * pname;
/*
@@ -402,7 +414,7 @@ init_logging(
#ifdef SYS_WINNT /* strip ".exe" */
cp = strrchr(progname, '.');
if (NULL != cp && !strcasecmp(cp, ".exe"))
- progname[cp - progname] = '\0';
+ *cp = '\0';
#endif
#if !defined(VMS)
@@ -454,7 +466,7 @@ change_logfile(
size_t octets;
#endif /* POSIX */
- NTP_REQUIRE(fname != NULL);
+ REQUIRE(fname != NULL);
log_fname = fname;
/*
diff --git a/contrib/ntp/libntp/ntp_calendar.c b/contrib/ntp/libntp/ntp_calendar.c
index ff91fcf..ff6ead3 100644
--- a/contrib/ntp/libntp/ntp_calendar.c
+++ b/contrib/ntp/libntp/ntp_calendar.c
@@ -3,7 +3,55 @@
*
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
* The contents of 'html/copyright.html' apply.
+ *
+ * --------------------------------------------------------------------
+ * Some notes on the implementation:
+ *
+ * Calendar algorithms thrive on the division operation, which is one of
+ * the slowest numerical operations in any CPU. What saves us here from
+ * abysmal performance is the fact that all divisions are divisions by
+ * constant numbers, and most compilers can do this by a multiplication
+ * operation. But this might not work when using the div/ldiv/lldiv
+ * function family, because many compilers are not able to do inline
+ * expansion of the code with following optimisation for the
+ * constant-divider case.
+ *
+ * Also div/ldiv/lldiv are defined in terms of int/long/longlong, which
+ * are inherently target dependent. Nothing that could not be cured with
+ * autoconf, but still a mess...
+ *
+ * Furthermore, we need floor division in many places. C either leaves
+ * the division behaviour undefined (< C99) or demands truncation to
+ * zero (>= C99), so additional steps are required to make sure the
+ * algorithms work. The {l,ll}div function family is requested to
+ * truncate towards zero, which is also the wrong direction for our
+ * purpose.
+ *
+ * For all this, all divisions by constant are coded manually, even when
+ * there is a joined div/mod operation: The optimiser should sort that
+ * out, if possible. Most of the calculations are done with unsigned
+ * types, explicitely using two's complement arithmetics where
+ * necessary. This minimises the dependecies to compiler and target,
+ * while still giving reasonable to good performance.
+ *
+ * The implementation uses a few tricks that exploit properties of the
+ * two's complement: Floor division on negative dividents can be
+ * executed by using the one's complement of the divident. One's
+ * complement can be easily created using XOR and a mask.
+ *
+ * Finally, check for overflow conditions is minimal. There are only two
+ * calculation steps in the whole calendar that suffer from an internal
+ * overflow, and these conditions are checked: errno is set to EDOM and
+ * the results are clamped/saturated in this case. All other functions
+ * do not suffer from internal overflow and simply return the result
+ * truncated to 32 bits.
+ *
+ * This is a sacrifice made for execution speed. Since a 32-bit day
+ * counter covers +/- 5,879,610 years and the clamp limits the effective
+ * range to +/-2.9 million years, this should not pose a problem here.
+ *
*/
+
#include <config.h>
#include <sys/types.h>
@@ -13,6 +61,33 @@
#include "ntp_fp.h"
#include "ntp_unixtime.h"
+/* For now, let's take the conservative approach: if the target property
+ * macros are not defined, check a few well-known compiler/architecture
+ * settings. Default is to assume that the representation of signed
+ * integers is unknown and shift-arithmetic-right is not available.
+ */
+#ifndef TARGET_HAS_2CPL
+# if defined(__GNUC__)
+# if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+# define TARGET_HAS_2CPL 1
+# else
+# define TARGET_HAS_2CPL 0
+# endif
+# elif defined(_MSC_VER)
+# if defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM)
+# define TARGET_HAS_2CPL 1
+# else
+# define TARGET_HAS_2CPL 0
+# endif
+# else
+# define TARGET_HAS_2CPL 0
+# endif
+#endif
+
+#ifndef TARGET_HAS_SAR
+# define TARGET_HAS_SAR 0
+#endif
+
/*
*---------------------------------------------------------------------
* replacing the 'time()' function
@@ -47,6 +122,117 @@ now(void)
/*
*---------------------------------------------------------------------
+ * Get sign extension mask and unsigned 2cpl rep for a signed integer
+ *---------------------------------------------------------------------
+ */
+
+static inline uint32_t
+int32_sflag(
+ const int32_t v)
+{
+# if TARGET_HAS_2CPL && TARGET_HAS_SAR && SIZEOF_INT >= 4
+
+ /* Let's assume that shift is the fastest way to get the sign
+ * extension of of a signed integer. This might not always be
+ * true, though -- On 8bit CPUs or machines without barrel
+ * shifter this will kill the performance. So we make sure
+ * we do this only if 'int' has at least 4 bytes.
+ */
+ return (uint32_t)(v >> 31);
+
+# else
+
+ /* This should be a rather generic approach for getting a sign
+ * extension mask...
+ */
+ return UINT32_C(0) - (uint32_t)(v < 0);
+
+# endif
+}
+
+static inline uint32_t
+int32_to_uint32_2cpl(
+ const int32_t v)
+{
+ uint32_t vu;
+
+# if TARGET_HAS_2CPL
+
+ /* Just copy through the 32 bits from the signed value if we're
+ * on a two's complement target.
+ */
+ vu = (uint32_t)v;
+
+# else
+
+ /* Convert from signed int to unsigned int two's complement. Do
+ * not make any assumptions about the representation of signed
+ * integers, but make sure signed integer overflow cannot happen
+ * here. A compiler on a two's complement target *might* find
+ * out that this is just a complicated cast (as above), but your
+ * mileage might vary.
+ */
+ if (v < 0)
+ vu = ~(uint32_t)(-(v + 1));
+ else
+ vu = (uint32_t)v;
+
+# endif
+
+ return vu;
+}
+
+static inline int32_t
+uint32_2cpl_to_int32(
+ const uint32_t vu)
+{
+ int32_t v;
+
+# if TARGET_HAS_2CPL
+
+ /* Just copy through the 32 bits from the unsigned value if
+ * we're on a two's complement target.
+ */
+ v = (int32_t)vu;
+
+# else
+
+ /* Convert to signed integer, making sure signed integer
+ * overflow cannot happen. Again, the optimiser might or might
+ * not find out that this is just a copy of 32 bits on a target
+ * with two's complement representation for signed integers.
+ */
+ if (vu > INT32_MAX)
+ v = -(int32_t)(~vu) - 1;
+ else
+ v = (int32_t)vu;
+
+# endif
+
+ return v;
+}
+
+/* Some of the calculations need to multiply the input by 4 before doing
+ * a division. This can cause overflow and strange results. Therefore we
+ * clamp / saturate the input operand. And since we do the calculations
+ * in unsigned int with an extra sign flag/mask, we only loose one bit
+ * of the input value range.
+ */
+static inline uint32_t
+uint32_saturate(
+ uint32_t vu,
+ uint32_t mu)
+{
+ static const uint32_t limit = UINT32_MAX/4u;
+ if ((mu ^ vu) > limit) {
+ vu = mu ^ limit;
+ errno = EDOM;
+ }
+ return vu;
+}
+
+/*
+ *---------------------------------------------------------------------
* Convert between 'time_t' and 'vint64'
*---------------------------------------------------------------------
*/
@@ -60,7 +246,7 @@ time_to_vint64(
tt = *ptt;
-#if SIZEOF_TIME_T <= 4
+# if SIZEOF_TIME_T <= 4
res.D_s.hi = 0;
if (tt < 0) {
@@ -70,11 +256,11 @@ time_to_vint64(
res.D_s.lo = (uint32_t)tt;
}
-#elif defined(HAVE_INT64)
+# elif defined(HAVE_INT64)
res.q_s = tt;
-#else
+# else
/*
* shifting negative signed quantities is compiler-dependent, so
* we better avoid it and do it all manually. And shifting more
@@ -90,7 +276,7 @@ time_to_vint64(
res.D_s.hi = (uint32_t)(tt >> 32);
}
-#endif
+# endif
return res;
}
@@ -103,19 +289,19 @@ vint64_to_time(
{
time_t res;
-#if SIZEOF_TIME_T <= 4
+# if SIZEOF_TIME_T <= 4
res = (time_t)tv->D_s.lo;
-#elif defined(HAVE_INT64)
+# elif defined(HAVE_INT64)
res = (time_t)tv->q_s;
-#else
+# else
res = ((time_t)tv->d_s.hi << 32) | tv->D_s.lo;
-#endif
+# endif
return res;
}
@@ -153,11 +339,11 @@ ntpcal_get_build_date(
* problem.
*
*/
-#ifdef MKREPRO_DATE
+# ifdef MKREPRO_DATE
static const char build[] = MKREPRO_TIME "/" MKREPRO_DATE;
-#else
+# else
static const char build[] = __TIME__ "/" __DATE__;
-#endif
+# endif
static const char mlist[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
char monstr[4];
@@ -167,16 +353,16 @@ ntpcal_get_build_date(
* so using 'uint16_t' is contra-indicated!
*/
-#ifdef DEBUG
+# ifdef DEBUG
static int ignore = 0;
-#endif
+# endif
ZERO(*jd);
jd->year = 1970;
jd->month = 1;
jd->monthday = 1;
-#ifdef DEBUG
+# ifdef DEBUG
/* check environment if build date should be ignored */
if (0 == ignore) {
const char * envstr;
@@ -185,7 +371,7 @@ ntpcal_get_build_date(
}
if (ignore > 1)
return FALSE;
-#endif
+# endif
if (6 == sscanf(build, "%hu:%hu:%hu/%3s %hu %hu",
&hour, &minute, &second, monstr, &day, &year)) {
@@ -254,37 +440,8 @@ static const uint16_t real_month_table[2][13] = {
* (day number). This is the number of days elapsed since 0000-12-31
* in the proleptic Gregorian calendar. The begin of the Christian Era
* (0001-01-01) is RD(1).
- *
- *
- * Some notes on the implementation:
- *
- * Calendar algorithms thrive on the division operation, which is one of
- * the slowest numerical operations in any CPU. What saves us here from
- * abysmal performance is the fact that all divisions are divisions by
- * constant numbers, and most compilers can do this by a multiplication
- * operation. But this might not work when using the div/ldiv/lldiv
- * function family, because many compilers are not able to do inline
- * expansion of the code with following optimisation for the
- * constant-divider case.
- *
- * Also div/ldiv/lldiv are defined in terms of int/long/longlong, which
- * are inherently target dependent. Nothing that could not be cured with
- * autoconf, but still a mess...
- *
- * Furthermore, we need floor division while C demands truncation to
- * zero, so additional steps are required to make sure the algorithms
- * work.
- *
- * For all this, all divisions by constant are coded manually, even when
- * there is a joined div/mod operation: The optimiser should sort that
- * out, if possible.
- *
- * Finally, the functions do not check for overflow conditions. This
- * is a sacrifice made for execution speed; since a 32-bit day counter
- * covers +/- 5,879,610 years, this should not pose a problem here.
*/
-
/*
* ==================================================================
*
@@ -363,22 +520,23 @@ ntpcal_periodic_extend(
* Get absolute difference as unsigned quantity and
* the complement flag. This is done by always
* subtracting the smaller value from the bigger
- * one. This implementation works only on a two's
- * complement machine!
+ * one.
*/
if (value >= pivot) {
- diff = (uint32_t)value - (uint32_t)pivot;
+ diff = int32_to_uint32_2cpl(value)
+ - int32_to_uint32_2cpl(pivot);
} else {
- diff = (uint32_t)pivot - (uint32_t)value;
+ diff = int32_to_uint32_2cpl(pivot)
+ - int32_to_uint32_2cpl(value);
cpl ^= 1;
}
diff %= (uint32_t)cycle;
if (diff) {
if (cpl)
- diff = cycle - diff;
+ diff = (uint32_t)cycle - diff;
if (neg)
diff = ~diff + 1;
- pivot += diff;
+ pivot += uint32_2cpl_to_int32(diff);
}
}
return pivot;
@@ -405,7 +563,7 @@ ntpcal_ntp_to_time(
{
vint64 res;
-#ifdef HAVE_INT64
+# if defined(HAVE_INT64)
res.q_s = (pivot != NULL)
? *pivot
@@ -415,7 +573,7 @@ ntpcal_ntp_to_time(
ntp -= res.D_s.lo; /* cycle difference */
res.Q_s += (uint64_t)ntp; /* get expanded time */
-#else /* no 64bit scalars */
+# else /* no 64bit scalars */
time_t tmp;
@@ -428,7 +586,7 @@ ntpcal_ntp_to_time(
ntp -= res.D_s.lo; /* cycle difference */
M_ADD(res.D_s.hi, res.D_s.lo, 0, ntp);
-#endif /* no 64bit scalars */
+# endif /* no 64bit scalars */
return res;
}
@@ -454,7 +612,7 @@ ntpcal_ntp_to_ntp(
{
vint64 res;
-#ifdef HAVE_INT64
+# if defined(HAVE_INT64)
res.q_s = (pivot)
? *pivot
@@ -464,7 +622,7 @@ ntpcal_ntp_to_ntp(
ntp -= res.D_s.lo; /* cycle difference */
res.Q_s += (uint64_t)ntp; /* get expanded time */
-#else /* no 64bit scalars */
+# else /* no 64bit scalars */
time_t tmp;
@@ -477,7 +635,7 @@ ntpcal_ntp_to_ntp(
ntp -= res.D_s.lo; /* cycle difference */
M_ADD(res.D_s.hi, res.D_s.lo, 0, ntp);
-#endif /* no 64bit scalars */
+# endif /* no 64bit scalars */
return res;
}
@@ -505,78 +663,75 @@ ntpcal_daysplit(
)
{
ntpcal_split res;
+ uint32_t Q;
+
+# if defined(HAVE_INT64)
+
+ /* Manual floor division by SECSPERDAY. This uses the one's
+ * complement trick, too, but without an extra flag value: The
+ * flag would be 64bit, and that's a bit of overkill on a 32bit
+ * target that has to use a register pair for a 64bit number.
+ */
+ if (ts->q_s < 0)
+ Q = ~(uint32_t)(~ts->Q_s / SECSPERDAY);
+ else
+ Q = (uint32_t)(ts->Q_s / SECSPERDAY);
-#ifdef HAVE_INT64
+# else
- /* manual floor division by SECSPERDAY */
- res.hi = (int32_t)(ts->q_s / SECSPERDAY);
- res.lo = (int32_t)(ts->q_s % SECSPERDAY);
- if (res.lo < 0) {
- res.hi -= 1;
- res.lo += SECSPERDAY;
- }
+ uint32_t ah, al, sflag, A;
-#else
+ /* get operand into ah/al (either ts or ts' one's complement,
+ * for later floor division)
+ */
+ sflag = int32_sflag(ts->d_s.hi);
+ ah = sflag ^ ts->D_s.hi;
+ al = sflag ^ ts->D_s.lo;
+
+ /* Since 86400 == 128*675 we can drop the least 7 bits and
+ * divide by 675 instead of 86400. Then the maximum remainder
+ * after each devision step is 674, and we need 10 bits for
+ * that. So in the next step we can shift in 22 bits from the
+ * numerator.
+ *
+ * Therefore we load the accu with the top 13 bits (51..63) in
+ * the first shot. We don't have to remember the quotient -- it
+ * would be shifted out anyway.
+ */
+ A = ah >> 19;
+ if (A >= 675)
+ A = (A % 675u);
+
+ /* Now assemble the remainder with bits 29..50 from the
+ * numerator and divide. This creates the upper ten bits of the
+ * quotient. (Well, the top 22 bits of a 44bit result. But that
+ * will be truncated to 32 bits anyway.)
+ */
+ A = (A << 19) | (ah & 0x0007FFFFu);
+ A = (A << 3) | (al >> 29);
+ Q = A / 675u;
+ A = A % 675u;
- /*
- * since we do not have 64bit ops, we have to this by hand.
- * Luckily SECSPERDAY is 86400 is 675*128, so we do the division
- * using chained 32/16 bit divisions and shifts.
+ /* Now assemble the remainder with bits 7..28 from the numerator
+ * and do a final division step.
*/
- vint64 op;
- uint32_t q, r, a;
- int isneg;
+ A = (A << 22) | ((al >> 7) & 0x003FFFFFu);
+ Q = (Q << 22) | (A / 675u);
- memcpy(&op, ts, sizeof(op));
- /* fix sign */
- isneg = M_ISNEG(op.D_s.hi);
- if (isneg)
- M_NEG(op.D_s.hi, op.D_s.lo);
-
- /* save remainder of DIV 128, shift for divide */
- r = op.D_s.lo & 127; /* save remainder bits */
- op.D_s.lo = (op.D_s.lo >> 7) | (op.D_s.hi << 25);
- op.D_s.hi = (op.D_s.hi >> 7);
-
- /* now do a mnual division, trying to remove as many ops as
- * possible -- division is always slow! An since we do not have
- * the advantage of a specific 64/32 bit or even a specific 32/16
- * bit division op, but must use the general 32/32bit division
- * even if we *know* the divider fits into unsigned 16 bits, the
- * exra code pathes should pay off.
+ /* The last 7 bits get simply dropped, as they have no affect on
+ * the quotient when dividing by 86400.
*/
- a = op.D_s.hi;
- if (a > 675u)
- a = a % 675u;
- if (a) {
- a = (a << 16) | op.W_s.lh;
- q = a / 675u;
- a = a % 675u;
-
- a = (a << 16) | op.W_s.ll;
- q = (q << 16) | (a / 675u);
- } else {
- a = op.D_s.lo;
- q = a / 675u;
- }
- a = a % 675u;
-
- /* assemble remainder */
- r |= a << 7;
-
- /* fix sign of result */
- if (isneg) {
- if (r) {
- r = SECSPERDAY - r;
- q = ~q;
- } else
- q = ~q + 1;
- }
- res.hi = q;
- res.lo = r;
+ /* apply sign correction and calculate the true floor
+ * remainder.
+ */
+ Q ^= sflag;
+
+# endif
+
+ res.hi = uint32_2cpl_to_int32(Q);
+ res.lo = ts->D_s.lo - Q * SECSPERDAY;
-#endif
return res;
}
@@ -593,25 +748,28 @@ priv_timesplit(
int32_t ts
)
{
- int32_t days = 0;
-
- /* make sure we have a positive offset into a day */
- if (ts < 0 || ts >= SECSPERDAY) {
- days = ts / SECSPERDAY;
- ts = ts % SECSPERDAY;
- if (ts < 0) {
- days -= 1;
- ts += SECSPERDAY;
- }
- }
+ /* Do 3 chained floor divisions by positive constants, using the
+ * one's complement trick and factoring out the intermediate XOR
+ * ops to reduce the number of operations.
+ */
+ uint32_t us, um, uh, ud, sflag;
- /* get secs, mins, hours */
- split[2] = (uint8_t)(ts % SECSPERMIN);
- ts /= SECSPERMIN;
- split[1] = (uint8_t)(ts % MINSPERHR);
- split[0] = (uint8_t)(ts / MINSPERHR);
+ sflag = int32_sflag(ts);
+ us = int32_to_uint32_2cpl(ts);
- return days;
+ um = (sflag ^ us) / SECSPERMIN;
+ uh = um / MINSPERHR;
+ ud = uh / HRSPERDAY;
+
+ um ^= sflag;
+ uh ^= sflag;
+ ud ^= sflag;
+
+ split[0] = (int32_t)(uh - ud * HRSPERDAY );
+ split[1] = (int32_t)(um - uh * MINSPERHR );
+ split[2] = (int32_t)(us - um * SECSPERMIN);
+
+ return uint32_2cpl_to_int32(ud);
}
/*
@@ -630,46 +788,45 @@ ntpcal_split_eradays(
int *isleapyear
)
{
- ntpcal_split res;
- int32_t n400, n100, n004, n001, yday; /* calendar year cycles */
-
- /*
- * Split off calendar cycles, using floor division in the first
- * step. After that first step, simple division does it because
- * all operands are positive; alas, we have to be aware of the
- * possibe cycle overflows for 100 years and 1 year, caused by
- * the additional leap day.
+ /* Use the fast cyclesplit algorithm here, to calculate the
+ * centuries and years in a century with one division each. This
+ * reduces the number of division operations to two, but is
+ * susceptible to internal range overflow. We make sure the
+ * input operands are in the safe range; this still gives us
+ * approx +/-2.9 million years.
*/
- n400 = days / GREGORIAN_CYCLE_DAYS;
- yday = days % GREGORIAN_CYCLE_DAYS;
- if (yday < 0) {
- n400 -= 1;
- yday += GREGORIAN_CYCLE_DAYS;
- }
- n100 = yday / GREGORIAN_NORMAL_CENTURY_DAYS;
- yday = yday % GREGORIAN_NORMAL_CENTURY_DAYS;
- n004 = yday / GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
- yday = yday % GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
- n001 = yday / DAYSPERYEAR;
- yday = yday % DAYSPERYEAR;
-
- /*
- * check for leap cycle overflows and calculate the leap flag
- * if needed
+ ntpcal_split res;
+ int32_t n100, n001; /* calendar year cycles */
+ uint32_t uday, Q, sflag;
+
+ /* split off centuries first */
+ sflag = int32_sflag(days);
+ uday = uint32_saturate(int32_to_uint32_2cpl(days), sflag);
+ uday = (4u * uday) | 3u;
+ Q = sflag ^ ((sflag ^ uday) / GREGORIAN_CYCLE_DAYS);
+ uday = uday - Q * GREGORIAN_CYCLE_DAYS;
+ n100 = uint32_2cpl_to_int32(Q);
+
+ /* Split off years in century -- days >= 0 here, and we're far
+ * away from integer overflow trouble now. */
+ uday |= 3;
+ n001 = uday / GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
+ uday = uday % GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
+
+ /* Assemble the year and day in year */
+ res.hi = n100 * 100 + n001;
+ res.lo = uday / 4u;
+
+ /* Eventually set the leap year flag. Note: 0 <= n001 <= 99 and
+ * Q is still the two's complement representation of the
+ * centuries: The modulo 4 ops can be done with masking here.
+ * We also shift the year and the century by one, so the tests
+ * can be done against zero instead of 3.
*/
- if ((n001 | n100) > 3) {
- /* hit last day of leap year */
- n001 -= 1;
- yday += DAYSPERYEAR;
- if (isleapyear)
- *isleapyear = 1;
- } else if (isleapyear)
- *isleapyear = (n001 == 3) && ((n004 != 24) || (n100 == 3));
-
- /* now merge the cycles to elapsed years, using horner scheme */
- res.hi = ((4*n400 + n100)*25 + n004)*4 + n001;
- res.lo = yday;
-
+ if (isleapyear)
+ *isleapyear = !((n001+1) & 3)
+ && ((n001 != 99) || !((Q+1) & 3));
+
return res;
}
@@ -719,11 +876,9 @@ ntpcal_rd_to_date(
)
{
ntpcal_split split;
- int leaps;
- int retv;
+ int leapy;
+ u_int ymask;
- leaps = 0;
- retv = 0;
/* Get day-of-week first. Since rd is signed, the remainder can
* be in the range [-6..+6], but the assignment to an unsigned
* variable maps the negative values to positive values >=7.
@@ -731,26 +886,28 @@ ntpcal_rd_to_date(
* causes the needed wrap-around into the desired value range of
* zero to six, both inclusive.
*/
- jd->weekday = rd % 7;
- if (jd->weekday >= 7) /* unsigned! */
- jd->weekday += 7;
-
- split = ntpcal_split_eradays(rd - 1, &leaps);
- retv = leaps;
- /* get year and day-of-year */
- jd->year = (uint16_t)split.hi + 1;
- if (jd->year != split.hi + 1) {
- jd->year = 0;
- retv = -1; /* bletch. overflow trouble. */
- }
+ jd->weekday = rd % DAYSPERWEEK;
+ if (jd->weekday >= DAYSPERWEEK) /* weekday is unsigned! */
+ jd->weekday += DAYSPERWEEK;
+
+ split = ntpcal_split_eradays(rd - 1, &leapy);
+ /* Get year and day-of-year, with overflow check. If any of the
+ * upper 16 bits is set after shifting to unity-based years, we
+ * will have an overflow when converting to an unsigned 16bit
+ * year. Shifting to the right is OK here, since it does not
+ * matter if the shift is logic or arithmetic.
+ */
+ split.hi += 1;
+ ymask = 0u - ((split.hi >> 16) == 0);
+ jd->year = (uint16_t)(split.hi & ymask);
jd->yearday = (uint16_t)split.lo + 1;
/* convert to month and mday */
- split = ntpcal_split_yeardays(split.lo, leaps);
+ split = ntpcal_split_yeardays(split.lo, leapy);
jd->month = (uint8_t)split.hi + 1;
jd->monthday = (uint8_t)split.lo + 1;
- return retv ? retv : leaps;
+ return ymask ? leapy : -1;
}
/*
@@ -765,25 +922,24 @@ ntpcal_rd_to_tm(
)
{
ntpcal_split split;
- int leaps;
+ int leapy;
- leaps = 0;
/* get day-of-week first */
- utm->tm_wday = rd % 7;
+ utm->tm_wday = rd % DAYSPERWEEK;
if (utm->tm_wday < 0)
- utm->tm_wday += 7;
+ utm->tm_wday += DAYSPERWEEK;
/* get year and day-of-year */
- split = ntpcal_split_eradays(rd - 1, &leaps);
+ split = ntpcal_split_eradays(rd - 1, &leapy);
utm->tm_year = split.hi - 1899;
utm->tm_yday = split.lo; /* 0-based */
/* convert to month and mday */
- split = ntpcal_split_yeardays(split.lo, leaps);
+ split = ntpcal_split_yeardays(split.lo, leapy);
utm->tm_mon = split.hi; /* 0-based */
utm->tm_mday = split.lo + 1; /* 1-based */
- return leaps;
+ return leapy;
}
/*
@@ -918,13 +1074,13 @@ ntpcal_dayjoin(
{
vint64 res;
-#ifdef HAVE_INT64
+# if defined(HAVE_INT64)
res.q_s = days;
res.q_s *= SECSPERDAY;
res.q_s += secs;
-#else
+# else
uint32_t p1, p2;
int isneg;
@@ -963,47 +1119,57 @@ ntpcal_dayjoin(
}
M_ADD(res.D_s.hi, res.D_s.lo, p2, p1);
-#endif
+# endif
return res;
}
/*
*---------------------------------------------------------------------
- * Convert elapsed years in Era into elapsed days in Era.
- *
- * To accomodate for negative values of years, floor division would be
- * required for all division operations. This can be eased by first
- * splitting the years into full 400-year cycles and years in the
- * cycle. Only this operation must be coded as a full floor division; as
- * the years in the cycle is a non-negative number, all other divisions
- * can be regular truncated divisions.
+ * get leap years since epoch in elapsed years
*---------------------------------------------------------------------
*/
int32_t
-ntpcal_days_in_years(
+ntpcal_leapyears_in_years(
int32_t years
)
{
- int32_t cycle; /* full gregorian cycle */
-
- /* split off full calendar cycles, using floor division */
- cycle = years / 400;
- years = years % 400;
- if (years < 0) {
- cycle -= 1;
- years += 400;
- }
+ /* We use the in-out-in algorithm here, using the one's
+ * complement division trick for negative numbers. The chained
+ * division sequence by 4/25/4 gives the compiler the chance to
+ * get away with only one true division and doing shifts otherwise.
+ */
- /*
- * Calculate days in cycle. years now is a non-negative number,
- * holding the number of years in the 400-year cycle.
+ uint32_t sflag, sum, uyear;
+
+ sflag = int32_sflag(years);
+ uyear = int32_to_uint32_2cpl(years);
+ uyear ^= sflag;
+
+ sum = (uyear /= 4u); /* 4yr rule --> IN */
+ sum -= (uyear /= 25u); /* 100yr rule --> OUT */
+ sum += (uyear /= 4u); /* 400yr rule --> IN */
+
+ /* Thanks to the alternation of IN/OUT/IN we can do the sum
+ * directly and have a single one's complement operation
+ * here. (Only if the years are negative, of course.) Otherwise
+ * the one's complement would have to be done when
+ * adding/subtracting the terms.
*/
- return cycle * GREGORIAN_CYCLE_DAYS
- + years * DAYSPERYEAR /* days inregular years */
- + years / 4 /* 4 year leap rule */
- - years / 100; /* 100 year leap rule */
- /* the 400-year rule does not apply due to full-cycle split-off */
+ return uint32_2cpl_to_int32(sflag ^ sum);
+}
+
+/*
+ *---------------------------------------------------------------------
+ * Convert elapsed years in Era into elapsed days in Era.
+ *---------------------------------------------------------------------
+ */
+int32_t
+ntpcal_days_in_years(
+ int32_t years
+ )
+{
+ return years * DAYSPERYEAR + ntpcal_leapyears_in_years(years);
}
/*
@@ -1029,26 +1195,22 @@ ntpcal_days_in_months(
{
ntpcal_split res;
- /* normalize month into range */
- res.hi = 0;
- res.lo = m;
- if (res.lo < 0 || res.lo >= 12) {
- res.hi = res.lo / 12;
- res.lo = res.lo % 12;
- if (res.lo < 0) {
- res.hi -= 1;
- res.lo += 12;
- }
- }
+ /* Add ten months and correct if needed. (It likely is...) */
+ res.lo = m + 10;
+ res.hi = (res.lo >= 12);
+ if (res.hi)
+ res.lo -= 12;
- /* add 10 month for year starting with march */
- if (res.lo < 2)
- res.lo += 10;
- else {
- res.hi += 1;
- res.lo -= 2;
+ /* if still out of range, normalise by floor division ... */
+ if (res.lo < 0 || res.lo >= 12) {
+ uint32_t mu, Q, sflag;
+ sflag = int32_sflag(res.lo);
+ mu = int32_to_uint32_2cpl(res.lo);
+ Q = sflag ^ ((sflag ^ mu) / 12u);
+ res.hi += uint32_2cpl_to_int32(Q);
+ res.lo = mu - Q * 12u;
}
-
+
/* get cummulated days in year with unshift */
res.lo = shift_month_table[res.lo] - 306;
@@ -1451,37 +1613,42 @@ int32_t
isocal_weeks_in_years(
int32_t years
)
-{
+{
/*
* use: w = (y * 53431 + b[c]) / 1024 as interpolation
*/
- static const int32_t bctab[4] = { 449, 157, 889, 597 };
- int32_t cycle; /* full gregorian cycle */
- int32_t cents; /* full centuries */
- int32_t weeks; /* accumulated weeks */
-
- /* split off full calendar cycles, using floor division */
- cycle = years / 400;
- years = years % 400;
- if (years < 0) {
- cycle -= 1;
- years += 400;
- }
-
- /* split off full centuries */
- cents = years / 100;
- years = years % 100;
-
- /*
- * calculate elapsed weeks, taking into account that the
- * first, third and fourth century have 5218 weeks but the
- * second century falls short by one week.
+ static const uint16_t bctab[4] = { 157, 449, 597, 889 };
+
+ int32_t cs, cw;
+ uint32_t cc, ci, yu, sflag;
+
+ sflag = int32_sflag(years);
+ yu = int32_to_uint32_2cpl(years);
+
+ /* split off centuries, using floor division */
+ cc = sflag ^ ((sflag ^ yu) / 100u);
+ yu -= cc * 100u;
+
+ /* calculate century cycles shift and cycle index:
+ * Assuming a century is 5217 weeks, we have to add a cycle
+ * shift that is 3 for every 4 centuries, because 3 of the four
+ * centuries have 5218 weeks. So '(cc*3 + 1) / 4' is the actual
+ * correction, and the second century is the defective one.
+ *
+ * Needs floor division by 4, which is done with masking and
+ * shifting.
+ */
+ ci = cc * 3u + 1;
+ cs = uint32_2cpl_to_int32(sflag ^ ((sflag ^ ci) / 4u));
+ ci = ci % 4u;
+
+ /* Get weeks in century. Can use plain division here as all ops
+ * are >= 0, and let the compiler sort out the possible
+ * optimisations.
*/
- weeks = (years * 53431 + bctab[cents]) / 1024;
+ cw = (yu * 53431u + bctab[ci]) / 1024u;
- return cycle * GREGORIAN_CYCLE_WEEKS
- + cents * 5218 - (cents > 1)
- + weeks;
+ return uint32_2cpl_to_int32(cc) * 5217 + cs + cw;
}
/*
@@ -1498,35 +1665,41 @@ isocal_split_eraweeks(
/*
* use: y = (w * 157 + b[c]) / 8192 as interpolation
*/
- static const int32_t bctab[4] = { 85, 131, 17, 62 };
+
+ static const uint16_t bctab[4] = { 85, 130, 17, 62 };
+
ntpcal_split res;
- int32_t cents;
+ int32_t cc, ci;
+ uint32_t sw, cy, Q, sflag;
- /*
- * split off 400-year cycles, using the fact that a 400-year
- * cycle has 146097 days, which is exactly 20871 weeks.
+ /* Use two fast cycle-split divisions here. This is again
+ * susceptible to internal overflow, so we check the range. This
+ * still permits more than +/-20 million years, so this is
+ * likely a pure academical problem.
+ *
+ * We want to execute '(weeks * 4 + 2) /% 20871' under floor
+ * division rules in the first step.
*/
- res.hi = weeks / GREGORIAN_CYCLE_WEEKS;
- res.lo = weeks % GREGORIAN_CYCLE_WEEKS;
- if (res.lo < 0) {
- res.hi -= 1;
- res.lo += GREGORIAN_CYCLE_WEEKS;
- }
- res.hi *= 400;
-
- /*
- * split off centuries, taking into account that the first,
- * third and fourth century have 5218 weeks but that the
- * second century falls short by one week.
+ sflag = int32_sflag(weeks);
+ sw = uint32_saturate(int32_to_uint32_2cpl(weeks), sflag);
+ sw = 4u * sw + 2;
+ Q = sflag ^ ((sflag ^ sw) / GREGORIAN_CYCLE_WEEKS);
+ sw -= Q * GREGORIAN_CYCLE_WEEKS;
+ ci = Q % 4u;
+ cc = uint32_2cpl_to_int32(Q);
+
+ /* Split off years; sw >= 0 here! The scaled weeks in the years
+ * are scaled up by 157 afterwards.
+ */
+ sw = (sw / 4u) * 157u + bctab[ci];
+ cy = sw / 8192u; /* ws >> 13 , let the compiler sort it out */
+ sw = sw % 8192u; /* ws & 8191, let the compiler sort it out */
+
+ /* assemble elapsed years and downscale the elapsed weeks in
+ * the year.
*/
- res.lo += (res.lo >= 10435);
- cents = res.lo / 5218;
- res.lo %= 5218; /* res.lo is weeks in century now */
-
- /* convert elapsed weeks in century to elapsed years and weeks */
- res.lo = res.lo * 157 + bctab[cents];
- res.hi += cents * 100 + res.lo / 8192;
- res.lo = (res.lo % 8192) / 157;
+ res.hi = 100*cc + cy;
+ res.lo = sw / 157u;
return res;
}
@@ -1544,6 +1717,7 @@ isocal_ntp64_to_date(
{
ntpcal_split ds;
int32_t ts[3];
+ uint32_t uw, ud, sflag;
/*
* Split NTP time into days and seconds, shift days into CE
@@ -1557,16 +1731,18 @@ isocal_ntp64_to_date(
id->minute = (uint8_t)ts[1];
id->second = (uint8_t)ts[2];
- /* split date part */
- ds.lo = ds.hi + DAY_NTP_STARTS - 1; /* elapsed era days */
- ds.hi = ds.lo / 7; /* elapsed era weeks */
- ds.lo = ds.lo % 7; /* elapsed week days */
- if (ds.lo < 0) { /* floor division! */
- ds.hi -= 1;
- ds.lo += 7;
- }
+ /* split days into days and weeks, using floor division in unsigned */
+ ds.hi += DAY_NTP_STARTS - 1; /* shift from NTP to RDN */
+ sflag = int32_sflag(ds.hi);
+ ud = int32_to_uint32_2cpl(ds.hi);
+ uw = sflag ^ ((sflag ^ ud) / DAYSPERWEEK);
+ ud -= uw * DAYSPERWEEK;
+ ds.hi = uint32_2cpl_to_int32(uw);
+ ds.lo = ud;
+
id->weekday = (uint8_t)ds.lo + 1; /* weekday result */
+ /* get year and week in year */
ds = isocal_split_eraweeks(ds.hi); /* elapsed years&week*/
id->year = (uint16_t)ds.hi + 1; /* shift to current */
id->week = (uint8_t )ds.lo + 1;
diff --git a/contrib/ntp/libntp/ntp_intres.c b/contrib/ntp/libntp/ntp_intres.c
index eea88a1..b0f5620 100644
--- a/contrib/ntp/libntp/ntp_intres.c
+++ b/contrib/ntp/libntp/ntp_intres.c
@@ -249,12 +249,12 @@ getaddrinfo_sometime(
size_t servsize;
time_t now;
- NTP_REQUIRE(NULL != node);
+ REQUIRE(NULL != node);
if (NULL != hints) {
- NTP_REQUIRE(0 == hints->ai_addrlen);
- NTP_REQUIRE(NULL == hints->ai_addr);
- NTP_REQUIRE(NULL == hints->ai_canonname);
- NTP_REQUIRE(NULL == hints->ai_next);
+ REQUIRE(0 == hints->ai_addrlen);
+ REQUIRE(NULL == hints->ai_addr);
+ REQUIRE(NULL == hints->ai_canonname);
+ REQUIRE(NULL == hints->ai_next);
}
idx = get_dnschild_ctx();
@@ -420,7 +420,7 @@ blocking_getaddrinfo(
ai = ai_res;
while (NULL != ai) {
- NTP_INSIST(ai->ai_addrlen <= sizeof(sockaddr_u));
+ INSIST(ai->ai_addrlen <= sizeof(sockaddr_u));
memcpy(cp, ai->ai_addr, ai->ai_addrlen);
cp += sizeof(sockaddr_u);
@@ -568,7 +568,7 @@ getaddrinfo_sometime_complete(
ai[i].ai_canonname += (size_t)canon_start;
}
- NTP_ENSURE((char *)psau == canon_start);
+ ENSURE((char *)psau == canon_start);
if (!gai_resp->ai_count)
ai = NULL;
@@ -634,8 +634,8 @@ getnameinfo_sometime(
dnschild_ctx * child_ctx;
time_t time_now;
- NTP_REQUIRE(hostoctets);
- NTP_REQUIRE(hostoctets + servoctets < 1024);
+ REQUIRE(hostoctets);
+ REQUIRE(hostoctets + servoctets < 1024);
idx = get_dnschild_ctx();
child_ctx = dnschild_contexts[idx];
@@ -699,7 +699,7 @@ blocking_getnameinfo(
* large allocations. We only need room for the host
* and service names.
*/
- NTP_REQUIRE(octets < sizeof(host));
+ REQUIRE(octets < sizeof(host));
service = host + gni_req->hostoctets;
worker_ctx = get_worker_context(c, gni_req->dns_idx);
@@ -775,8 +775,8 @@ blocking_getnameinfo(
cp += gni_resp->servoctets;
}
- NTP_INSIST((size_t)(cp - (char *)resp) == resp_octets);
- NTP_INSIST(resp_octets - sizeof(*resp) == gni_resp->octets);
+ INSIST((size_t)(cp - (char *)resp) == resp_octets);
+ INSIST(resp_octets - sizeof(*resp) == gni_resp->octets);
rc = queue_blocking_response(c, resp, resp_octets, req);
if (rc)
diff --git a/contrib/ntp/libntp/ntp_lineedit.c b/contrib/ntp/libntp/ntp_lineedit.c
index e3bc002..a2b2d29 100644
--- a/contrib/ntp/libntp/ntp_lineedit.c
+++ b/contrib/ntp/libntp/ntp_lineedit.c
@@ -36,7 +36,7 @@
* external references
*/
-extern char * progname;
+extern char const * progname;
/*
* globals, private prototypes
diff --git a/contrib/ntp/libntp/ntp_rfc2553.c b/contrib/ntp/libntp/ntp_rfc2553.c
index f267999..a9ebb4b 100644
--- a/contrib/ntp/libntp/ntp_rfc2553.c
+++ b/contrib/ntp/libntp/ntp_rfc2553.c
@@ -221,7 +221,7 @@ copy_addrinfo_common(
}
++ai_cpy;
}
- NTP_ENSURE(pcanon == ((char *)dst + octets));
+ ENSURE(pcanon == ((char *)dst + octets));
return dst;
}
diff --git a/contrib/ntp/libntp/ntp_worker.c b/contrib/ntp/libntp/ntp_worker.c
index bb1cb87..32970da 100644
--- a/contrib/ntp/libntp/ntp_worker.c
+++ b/contrib/ntp/libntp/ntp_worker.c
@@ -278,7 +278,7 @@ blocking_child_common(
req = receive_blocking_req_internal(c);
if (NULL == req) {
say_bye = TRUE;
- break;
+ continue;
}
DEBUG_REQUIRE(BLOCKING_REQ_MAGIC == req->magic_sig);
diff --git a/contrib/ntp/libntp/prettydate.c b/contrib/ntp/libntp/prettydate.c
index 5da5ecc..25b085e 100644
--- a/contrib/ntp/libntp/prettydate.c
+++ b/contrib/ntp/libntp/prettydate.c
@@ -141,7 +141,7 @@ get_struct_tm(
return NULL; /* That's truly pathological! */
/* 'tm' surely not NULL here! */
- NTP_INSIST(tm != NULL);
+ INSIST(tm != NULL);
if (folds != 0) {
tm->tm_year += folds * SOLAR_CYCLE_YEARS;
if (tm->tm_year <= 0 || tm->tm_year >= 200)
diff --git a/contrib/ntp/libntp/recvbuff.c b/contrib/ntp/libntp/recvbuff.c
index 83a9ee1..73ebe88 100644
--- a/contrib/ntp/libntp/recvbuff.c
+++ b/contrib/ntp/libntp/recvbuff.c
@@ -216,7 +216,7 @@ get_free_recv_buffer_alloc(void)
create_buffers(RECV_INC);
buffer = get_free_recv_buffer();
}
- NTP_ENSURE(buffer != NULL);
+ ENSURE(buffer != NULL);
return (buffer);
}
#endif
diff --git a/contrib/ntp/libntp/socket.c b/contrib/ntp/libntp/socket.c
index de678c6..11fb0046 100644
--- a/contrib/ntp/libntp/socket.c
+++ b/contrib/ntp/libntp/socket.c
@@ -78,7 +78,7 @@ move_fd(
static SOCKET socket_boundary = -1;
SOCKET newfd;
- NTP_REQUIRE((int)fd >= 0);
+ REQUIRE((int)fd >= 0);
/*
* check whether boundary has be set up
@@ -115,7 +115,7 @@ move_fd(
socket_boundary));
} while (socket_boundary > 0);
#else
- NTP_REQUIRE((int)fd >= 0);
+ ENSURE((int)fd >= 0);
#endif /* !defined(SYS_WINNT) && defined(F_DUPFD) */
return fd;
}
diff --git a/contrib/ntp/libntp/socktohost.c b/contrib/ntp/libntp/socktohost.c
index c61e571..3d9ab960 100644
--- a/contrib/ntp/libntp/socktohost.c
+++ b/contrib/ntp/libntp/socktohost.c
@@ -79,7 +79,7 @@ socktohost(
if (a_info)
goto forward_fail;
- NTP_INSIST(alist != NULL);
+ INSIST(alist != NULL);
for (ai = alist; ai != NULL; ai = ai->ai_next) {
/*
diff --git a/contrib/ntp/libntp/statestr.c b/contrib/ntp/libntp/statestr.c
index cd98eb3..313cd46 100644
--- a/contrib/ntp/libntp/statestr.c
+++ b/contrib/ntp/libntp/statestr.c
@@ -60,7 +60,7 @@ static const struct codestring select_codes[] = {
{ CTL_PST_SEL_REJECT, "sel_reject" },
{ CTL_PST_SEL_SANE, "sel_falsetick" },
{ CTL_PST_SEL_CORRECT, "sel_excess" },
- { CTL_PST_SEL_SELCAND, "sel_outlyer" },
+ { CTL_PST_SEL_SELCAND, "sel_outlier" },
{ CTL_PST_SEL_SYNCCAND, "sel_candidate" },
{ CTL_PST_SEL_EXCESS, "sel_backup" },
{ CTL_PST_SEL_SYSPEER, "sel_sys.peer" },
OpenPOWER on IntegriCloud