original files of m241
This commit is contained in:
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* digest support for NTP, MD5 and with OpenSSL more
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "ntp_string.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp.h"
|
||||
#include "ntp_md5.h" /* provides OpenSSL digest API */
|
||||
#include "isc/string.h"
|
||||
|
||||
#include "ipntp.h"
|
||||
|
||||
typedef struct {
|
||||
const void * buf;
|
||||
size_t len;
|
||||
} robuffT;
|
||||
|
||||
typedef struct {
|
||||
void * buf;
|
||||
size_t len;
|
||||
} rwbuffT;
|
||||
|
||||
#if defined(OPENSSL) && defined(ENABLE_CMAC)
|
||||
static size_t
|
||||
cmac_ctx_size(
|
||||
CMAC_CTX * ctx)
|
||||
{
|
||||
size_t mlen = 0;
|
||||
|
||||
if (ctx) {
|
||||
EVP_CIPHER_CTX * cctx;
|
||||
if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx)))
|
||||
mlen = EVP_CIPHER_CTX_block_size(cctx);
|
||||
}
|
||||
return mlen;
|
||||
}
|
||||
#endif /*OPENSSL && ENABLE_CMAC*/
|
||||
|
||||
static size_t
|
||||
make_mac(
|
||||
const rwbuffT * digest,
|
||||
int ktype,
|
||||
const robuffT * key,
|
||||
const robuffT * msg)
|
||||
{
|
||||
/*
|
||||
* Compute digest of key concatenated with packet. Note: the
|
||||
* key type and digest type have been verified when the key
|
||||
* was created.
|
||||
*/
|
||||
size_t retlen = 0;
|
||||
|
||||
#ifdef OPENSSL
|
||||
|
||||
INIT_SSL();
|
||||
|
||||
/* Check if CMAC key type specific code required */
|
||||
# ifdef ENABLE_CMAC
|
||||
if (ktype == NID_cmac) {
|
||||
CMAC_CTX * ctx = NULL;
|
||||
void const * keyptr = key->buf;
|
||||
u_char keybuf[AES_128_KEY_SIZE];
|
||||
|
||||
/* adjust key size (zero padded buffer) if necessary */
|
||||
if (AES_128_KEY_SIZE > key->len) {
|
||||
memcpy(keybuf, keyptr, key->len);
|
||||
memset((keybuf + key->len), 0,
|
||||
(AES_128_KEY_SIZE - key->len));
|
||||
keyptr = keybuf;
|
||||
}
|
||||
|
||||
if (NULL == (ctx = CMAC_CTX_new())) {
|
||||
msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC);
|
||||
goto cmac_fail;
|
||||
}
|
||||
if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) {
|
||||
msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.", CMAC);
|
||||
goto cmac_fail;
|
||||
}
|
||||
if (cmac_ctx_size(ctx) > digest->len) {
|
||||
msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.", CMAC);
|
||||
goto cmac_fail;
|
||||
}
|
||||
if (!CMAC_Update(ctx, msg->buf, msg->len)) {
|
||||
msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.", CMAC);
|
||||
goto cmac_fail;
|
||||
}
|
||||
if (!CMAC_Final(ctx, digest->buf, &retlen)) {
|
||||
msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.", CMAC);
|
||||
retlen = 0;
|
||||
}
|
||||
cmac_fail:
|
||||
if (ctx)
|
||||
CMAC_CTX_free(ctx);
|
||||
}
|
||||
else
|
||||
# endif /*ENABLE_CMAC*/
|
||||
{ /* generic MAC handling */
|
||||
EVP_MD_CTX * ctx = EVP_MD_CTX_new();
|
||||
u_int uilen = 0;
|
||||
|
||||
if ( ! ctx) {
|
||||
msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest CTX new failed.",
|
||||
OBJ_nid2sn(ktype));
|
||||
goto mac_fail;
|
||||
}
|
||||
|
||||
#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
|
||||
/* make sure MD5 is allowd */
|
||||
EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
|
||||
#endif
|
||||
/* [Bug 3457] DON'T use plain EVP_DigestInit! It would
|
||||
* kill the flags! */
|
||||
if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(ktype), NULL)) {
|
||||
msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Init failed.",
|
||||
OBJ_nid2sn(ktype));
|
||||
goto mac_fail;
|
||||
}
|
||||
if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) {
|
||||
msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.",
|
||||
OBJ_nid2sn(ktype));
|
||||
goto mac_fail;
|
||||
}
|
||||
if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) {
|
||||
msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.",
|
||||
OBJ_nid2sn(ktype));
|
||||
goto mac_fail;
|
||||
}
|
||||
if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) {
|
||||
msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.",
|
||||
OBJ_nid2sn(ktype));
|
||||
goto mac_fail;
|
||||
}
|
||||
if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) {
|
||||
msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.",
|
||||
OBJ_nid2sn(ktype));
|
||||
uilen = 0;
|
||||
}
|
||||
mac_fail:
|
||||
retlen = (size_t)uilen;
|
||||
|
||||
if (ctx)
|
||||
EVP_MD_CTX_free(ctx);
|
||||
}
|
||||
|
||||
#else /* !OPENSSL follows */
|
||||
|
||||
if (ktype == NID_md5)
|
||||
{
|
||||
EVP_MD_CTX * ctx = EVP_MD_CTX_new();
|
||||
u_int uilen = 0;
|
||||
|
||||
if (digest->len < 16) {
|
||||
msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
|
||||
}
|
||||
else if ( ! ctx) {
|
||||
msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 Digest CTX new failed.");
|
||||
}
|
||||
else {
|
||||
EVP_DigestInit(ctx, EVP_get_digestbynid(ktype));
|
||||
EVP_DigestUpdate(ctx, key->buf, key->len);
|
||||
EVP_DigestUpdate(ctx, msg->buf, msg->len);
|
||||
EVP_DigestFinal(ctx, digest->buf, &uilen);
|
||||
}
|
||||
if (ctx)
|
||||
EVP_MD_CTX_free(ctx);
|
||||
retlen = (size_t)uilen;
|
||||
}
|
||||
else
|
||||
{
|
||||
msyslog(LOG_ERR, "MAC encrypt: invalid key type %d" , ktype);
|
||||
}
|
||||
|
||||
#endif /* !OPENSSL */
|
||||
|
||||
return retlen;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MD5authencrypt - generate message digest
|
||||
*
|
||||
* Returns length of MAC including key ID and digest.
|
||||
*/
|
||||
size_t
|
||||
MD5authencrypt(
|
||||
int type, /* hash algorithm */
|
||||
const u_char * key, /* key pointer */
|
||||
size_t klen, /* key length */
|
||||
u_int32 * pkt, /* packet pointer */
|
||||
size_t length /* packet length */
|
||||
)
|
||||
{
|
||||
u_char digest[EVP_MAX_MD_SIZE];
|
||||
rwbuffT digb = { digest, sizeof(digest) };
|
||||
robuffT keyb = { key, klen };
|
||||
robuffT msgb = { pkt, length };
|
||||
size_t dlen = 0;
|
||||
|
||||
dlen = make_mac(&digb, type, &keyb, &msgb);
|
||||
/* If the MAC is longer than the MAX then truncate it. */
|
||||
if (dlen > MAX_MDG_LEN)
|
||||
dlen = MAX_MDG_LEN;
|
||||
memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest, dlen);
|
||||
return (dlen + KEY_MAC_LEN);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MD5authdecrypt - verify MD5 message authenticator
|
||||
*
|
||||
* Returns one if digest valid, zero if invalid.
|
||||
*/
|
||||
int
|
||||
MD5authdecrypt(
|
||||
int type, /* hash algorithm */
|
||||
const u_char * key, /* key pointer */
|
||||
size_t klen, /* key length */
|
||||
u_int32 * pkt, /* packet pointer */
|
||||
size_t length, /* packet length */
|
||||
size_t size /* MAC size */
|
||||
)
|
||||
{
|
||||
u_char digest[EVP_MAX_MD_SIZE];
|
||||
rwbuffT digb = { digest, sizeof(digest) };
|
||||
robuffT keyb = { key, klen };
|
||||
robuffT msgb = { pkt, length };
|
||||
size_t dlen = 0;
|
||||
|
||||
dlen = make_mac(&digb, type, &keyb, &msgb);
|
||||
|
||||
/* If the MAC is longer than the MAX then truncate it. */
|
||||
if (dlen > MAX_MDG_LEN)
|
||||
dlen = MAX_MDG_LEN;
|
||||
if (size != (size_t)dlen + KEY_MAC_LEN) {
|
||||
msyslog(LOG_ERR,
|
||||
"MAC decrypt: MAC length error");
|
||||
return (0);
|
||||
}
|
||||
return !isc_tsmemcmp(digest,
|
||||
(u_char *)pkt + length + KEY_MAC_LEN, dlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the reference id from the address. If it is an IPv4
|
||||
* address, use it as is. If it is an IPv6 address, do a md5 on
|
||||
* it and use the bottom 4 bytes.
|
||||
* The result is in network byte order.
|
||||
*/
|
||||
u_int32
|
||||
addr2refid(sockaddr_u *addr)
|
||||
{
|
||||
u_char digest[EVP_MAX_MD_SIZE];
|
||||
u_int32 addr_refid;
|
||||
EVP_MD_CTX *ctx;
|
||||
u_int len;
|
||||
|
||||
if (IS_IPV4(addr))
|
||||
return (NSRCADR(addr));
|
||||
|
||||
INIT_SSL();
|
||||
|
||||
ctx = EVP_MD_CTX_new();
|
||||
# ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
|
||||
/* MD5 is not used as a crypto hash here. */
|
||||
EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
|
||||
# endif
|
||||
/* [Bug 3457] DON'T use plain EVP_DigestInit! It would kill the
|
||||
* flags! */
|
||||
if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) {
|
||||
msyslog(LOG_ERR,
|
||||
"MD5 init failed");
|
||||
EVP_MD_CTX_free(ctx); /* pedantic... but safe */
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
|
||||
EVP_DigestUpdate(ctx, (u_char *)PSOCK_ADDR6(addr),
|
||||
sizeof(struct in6_addr));
|
||||
EVP_DigestFinal(ctx, digest, &len);
|
||||
EVP_MD_CTX_free(ctx);
|
||||
memcpy(&addr_refid, digest, sizeof(addr_refid));
|
||||
return (addr_refid);
|
||||
}
|
||||
@@ -0,0 +1,702 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#ifdef MPE
|
||||
/*
|
||||
* MPE lacks adjtime(), so we define our own. But note that time slewing has
|
||||
* a sub-second accuracy bug documented in SR 5003462838 which prevents ntpd
|
||||
* from being able to maintain clock synch. Because of the bug, this adjtime()
|
||||
* implementation as used by ntpd has a side-effect of screwing up the hardware
|
||||
* PDC clock, which will need to be reset with a reboot.
|
||||
*
|
||||
* This problem affects all versions of MPE at the time of this writing (when
|
||||
* MPE/iX 7.0 is the most current). It only causes bad things to happen when
|
||||
* doing continuous clock synchronization with ntpd; note that you CAN run ntpd
|
||||
* with "disable ntp" in ntp.conf if you wish to provide a time server.
|
||||
*
|
||||
* The one-time clock adjustment functionality of ntpdate and ntp_timeset can
|
||||
* be used without screwing up the PDC clock.
|
||||
*
|
||||
*/
|
||||
#include <time.h>
|
||||
|
||||
int adjtime(struct timeval *delta, struct timeval *olddelta);
|
||||
|
||||
int adjtime(struct timeval *delta, struct timeval *olddelta)
|
||||
|
||||
{
|
||||
/* Documented, supported MPE system intrinsics. */
|
||||
|
||||
extern void GETPRIVMODE(void);
|
||||
extern void GETUSERMODE(void);
|
||||
|
||||
/* Undocumented, unsupported MPE internal functions. */
|
||||
|
||||
extern long long current_correction_usecs(void);
|
||||
extern long long get_time(void);
|
||||
extern void get_time_change_info(long long *, char *, char *);
|
||||
extern long long pdc_time(int *);
|
||||
extern void set_time_correction(long long, int, int);
|
||||
extern long long ticks_to_micro(long long);
|
||||
|
||||
long long big_sec, big_usec, new_correction = 0LL;
|
||||
long long prev_correction;
|
||||
|
||||
if (delta != NULL) {
|
||||
/* Adjustment required. Convert delta to 64-bit microseconds. */
|
||||
big_sec = (long)delta->tv_sec;
|
||||
big_usec = delta->tv_usec;
|
||||
new_correction = (big_sec * 1000000LL) + big_usec;
|
||||
}
|
||||
|
||||
GETPRIVMODE();
|
||||
|
||||
/* Determine how much of a previous correction (if any) we're interrupting. */
|
||||
prev_correction = current_correction_usecs();
|
||||
|
||||
if (delta != NULL) {
|
||||
/* Adjustment required. */
|
||||
|
||||
#if 0
|
||||
/* Speculative code disabled until bug SR 5003462838 is fixed. This bug
|
||||
prevents accurate time slewing, and indeed renders ntpd inoperable. */
|
||||
|
||||
if (prev_correction != 0LL) {
|
||||
/* A previous adjustment did not complete. Since the PDC UTC clock was
|
||||
immediately jumped at the start of the previous adjustment, we must
|
||||
explicitly reset it to the value of the MPE local time clock minus the
|
||||
time zone offset. */
|
||||
|
||||
char pwf_since_boot, recover_pwf_time;
|
||||
long long offset_ticks, offset_usecs, pdc_usecs_current, pdc_usecs_wanted;
|
||||
int hpe_status;
|
||||
|
||||
get_time_change_info(&offset_ticks, &pwf_since_boot, &recover_pwf_time);
|
||||
offset_usecs = ticks_to_micro(offset_ticks);
|
||||
pdc_usecs_wanted = get_time() - offset_usecs;
|
||||
pdc_usecs_current = pdc_time(&hpe_status);
|
||||
if (hpe_status == 0)
|
||||
/* Force new PDC time by starting an extra correction. */
|
||||
set_time_correction(pdc_usecs_wanted - pdc_usecs_current,0,1);
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
/* Immediately jump the PDC time to the new value, and then initiate a
|
||||
gradual MPE time correction slew. */
|
||||
set_time_correction(new_correction,0,1);
|
||||
}
|
||||
|
||||
GETUSERMODE();
|
||||
|
||||
if (olddelta != NULL) {
|
||||
/* Caller wants to know remaining amount of previous correction. */
|
||||
(long)olddelta->tv_sec = prev_correction / 1000000LL;
|
||||
olddelta->tv_usec = prev_correction % 1000000LL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* MPE */
|
||||
|
||||
#ifdef NEED_HPUX_ADJTIME
|
||||
/*************************************************************************/
|
||||
/* (c) Copyright Tai Jin, 1988. All Rights Reserved. */
|
||||
/* Hewlett-Packard Laboratories. */
|
||||
/* */
|
||||
/* Permission is hereby granted for unlimited modification, use, and */
|
||||
/* distribution. This software is made available with no warranty of */
|
||||
/* any kind, express or implied. This copyright notice must remain */
|
||||
/* intact in all versions of this software. */
|
||||
/* */
|
||||
/* The author would appreciate it if any bug fixes and enhancements were */
|
||||
/* to be sent back to him for incorporation into future versions of this */
|
||||
/* software. Please send changes to tai@iag.hp.com or ken@sdd.hp.com. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
* Revision history
|
||||
*
|
||||
* 9 Jul 94 David L. Mills, Unibergity of Delabunch
|
||||
* Implemented variable threshold to limit age of
|
||||
* corrections; reformatted code for readability.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char RCSid[] = "adjtime.c,v 3.1 1993/07/06 01:04:42 jbj Exp";
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
#include "adjtime.h"
|
||||
|
||||
#define abs(x) ((x) < 0 ? -(x) : (x))
|
||||
|
||||
/*
|
||||
* The following paramters are appropriate for an NTP adjustment
|
||||
* interval of one second.
|
||||
*/
|
||||
#define ADJ_THRESH 200 /* initial threshold */
|
||||
#define ADJ_DELTA 4 /* threshold decrement */
|
||||
|
||||
static long adjthresh; /* adjustment threshold */
|
||||
static long saveup; /* corrections accumulator */
|
||||
|
||||
/*
|
||||
* clear_adjtime - reset accumulator and threshold variables
|
||||
*/
|
||||
void
|
||||
_clear_adjtime(void)
|
||||
{
|
||||
saveup = 0;
|
||||
adjthresh = ADJ_THRESH;
|
||||
}
|
||||
|
||||
/*
|
||||
* adjtime - hp-ux copout of the standard Unix adjtime() system call
|
||||
*/
|
||||
int
|
||||
adjtime(
|
||||
register struct timeval *delta,
|
||||
register struct timeval *olddelta
|
||||
)
|
||||
{
|
||||
struct timeval newdelta;
|
||||
|
||||
/*
|
||||
* Corrections greater than one second are done immediately.
|
||||
*/
|
||||
if (delta->tv_sec) {
|
||||
adjthresh = ADJ_THRESH;
|
||||
saveup = 0;
|
||||
return(_adjtime(delta, olddelta));
|
||||
}
|
||||
|
||||
/*
|
||||
* Corrections less than one second are accumulated until
|
||||
* tripping a threshold, which is initially set at ADJ_THESH and
|
||||
* reduced in ADJ_DELTA steps to zero. The idea here is to
|
||||
* introduce large corrections quickly, while making sure that
|
||||
* small corrections are introduced without excessive delay. The
|
||||
* idea comes from the ARPAnet routing update algorithm.
|
||||
*/
|
||||
saveup += delta->tv_usec;
|
||||
if (abs(saveup) >= adjthresh) {
|
||||
adjthresh = ADJ_THRESH;
|
||||
newdelta.tv_sec = 0;
|
||||
newdelta.tv_usec = saveup;
|
||||
saveup = 0;
|
||||
return(_adjtime(&newdelta, olddelta));
|
||||
} else {
|
||||
adjthresh -= ADJ_DELTA;
|
||||
}
|
||||
|
||||
/*
|
||||
* While nobody uses it, return the residual before correction,
|
||||
* as per Unix convention.
|
||||
*/
|
||||
if (olddelta)
|
||||
olddelta->tv_sec = olddelta->tv_usec = 0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* _adjtime - does the actual work
|
||||
*/
|
||||
int
|
||||
_adjtime(
|
||||
register struct timeval *delta,
|
||||
register struct timeval *olddelta
|
||||
)
|
||||
{
|
||||
register int mqid;
|
||||
MsgBuf msg;
|
||||
register MsgBuf *msgp = &msg;
|
||||
|
||||
/*
|
||||
* Get the key to the adjtime message queue (note that we must
|
||||
* get it every time because the queue might have been removed
|
||||
* and recreated)
|
||||
*/
|
||||
if ((mqid = msgget(KEY, 0)) == -1)
|
||||
return (-1);
|
||||
msgp->msgb.mtype = CLIENT;
|
||||
msgp->msgb.tv = *delta;
|
||||
if (olddelta)
|
||||
msgp->msgb.code = DELTA2;
|
||||
else
|
||||
msgp->msgb.code = DELTA1;
|
||||
|
||||
/*
|
||||
* Tickle adjtimed and snatch residual, if indicated. Lots of
|
||||
* fanatic error checking here.
|
||||
*/
|
||||
if (msgsnd(mqid, &msgp->msgp, MSGSIZE, 0) == -1)
|
||||
return (-1);
|
||||
if (olddelta) {
|
||||
if (msgrcv(mqid, &msgp->msgp, MSGSIZE, SERVER, 0) == -1)
|
||||
return (-1);
|
||||
*olddelta = msgp->msgb.tv;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
#else
|
||||
# if NEED_QNX_ADJTIME
|
||||
/*
|
||||
* Emulate adjtime() using QNX ClockAdjust().
|
||||
* Chris Burghart <burghart@atd.ucar.edu>, 11/2001
|
||||
* Miroslaw Pabich <miroslaw_pabich@o2.pl>, 09/2005
|
||||
*
|
||||
* This is an implementation of adjtime() for QNX.
|
||||
* ClockAdjust() is used to tweak the system clock for about
|
||||
* 1 second period until the desired delta is achieved.
|
||||
* Time correction slew is limited to reasonable value.
|
||||
* Internal rounding and relative errors are reduced.
|
||||
*/
|
||||
# include <sys/neutrino.h>
|
||||
# include <sys/time.h>
|
||||
|
||||
# include <ntp_stdlib.h>
|
||||
|
||||
/*
|
||||
* Time correction slew limit. QNX is a hard real-time system,
|
||||
* so don't adjust system clock too fast.
|
||||
*/
|
||||
#define CORR_SLEW_LIMIT 0.02 /* [s/s] */
|
||||
|
||||
/*
|
||||
* Period of system clock adjustment. It should be equal to adjtime
|
||||
* execution period (1s). If slightly less than 1s (0.95-0.99), then olddelta
|
||||
* residual error (introduced by execution period jitter) will be reduced.
|
||||
*/
|
||||
#define ADJUST_PERIOD 0.97 /* [s] */
|
||||
|
||||
int
|
||||
adjtime (struct timeval *delta, struct timeval *olddelta)
|
||||
{
|
||||
double delta_nsec;
|
||||
double delta_nsec_old;
|
||||
struct _clockadjust adj;
|
||||
struct _clockadjust oldadj;
|
||||
|
||||
/*
|
||||
* How many nanoseconds are we adjusting?
|
||||
*/
|
||||
if (delta != NULL)
|
||||
delta_nsec = 1e9 * (long)delta->tv_sec + 1e3 * delta->tv_usec;
|
||||
else
|
||||
delta_nsec = 0;
|
||||
|
||||
/*
|
||||
* Build the adjust structure and call ClockAdjust()
|
||||
*/
|
||||
if (delta_nsec != 0)
|
||||
{
|
||||
struct _clockperiod period;
|
||||
long count;
|
||||
long increment;
|
||||
long increment_limit;
|
||||
int isneg = 0;
|
||||
|
||||
/*
|
||||
* Convert to absolute value for future processing
|
||||
*/
|
||||
if (delta_nsec < 0)
|
||||
{
|
||||
isneg = 1;
|
||||
delta_nsec = -delta_nsec;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the current clock period (nanoseconds)
|
||||
*/
|
||||
if (ClockPeriod (CLOCK_REALTIME, 0, &period, 0) == -1)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Compute count and nanoseconds increment
|
||||
*/
|
||||
count = 1e9 * ADJUST_PERIOD / period.nsec;
|
||||
increment = delta_nsec / count + .5;
|
||||
/* Reduce relative error */
|
||||
if (count > increment + 1)
|
||||
{
|
||||
increment = 1 + (long)((delta_nsec - 1) / count);
|
||||
count = delta_nsec / increment + .5;
|
||||
}
|
||||
|
||||
/*
|
||||
* Limit the adjust increment to appropriate value
|
||||
*/
|
||||
increment_limit = CORR_SLEW_LIMIT * period.nsec;
|
||||
if (increment > increment_limit)
|
||||
{
|
||||
increment = increment_limit;
|
||||
count = delta_nsec / increment + .5;
|
||||
/* Reduce relative error */
|
||||
if (increment > count + 1)
|
||||
{
|
||||
count = 1 + (long)((delta_nsec - 1) / increment);
|
||||
increment = delta_nsec / count + .5;
|
||||
}
|
||||
}
|
||||
|
||||
adj.tick_nsec_inc = isneg ? -increment : increment;
|
||||
adj.tick_count = count;
|
||||
}
|
||||
else
|
||||
{
|
||||
adj.tick_nsec_inc = 0;
|
||||
adj.tick_count = 0;
|
||||
}
|
||||
|
||||
if (ClockAdjust (CLOCK_REALTIME, &adj, &oldadj) == -1)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Build olddelta
|
||||
*/
|
||||
delta_nsec_old = (double)oldadj.tick_count * oldadj.tick_nsec_inc;
|
||||
if (olddelta != NULL)
|
||||
{
|
||||
if (delta_nsec_old != 0)
|
||||
{
|
||||
/* Reduce rounding error */
|
||||
delta_nsec_old += (delta_nsec_old < 0) ? -500 : 500;
|
||||
olddelta->tv_sec = delta_nsec_old / 1e9;
|
||||
olddelta->tv_usec = (long)(delta_nsec_old - 1e9
|
||||
* (long)olddelta->tv_sec) / 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
olddelta->tv_sec = 0;
|
||||
olddelta->tv_usec = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
# else /* no special adjtime() needed */
|
||||
int adjtime_bs;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_VXWORKS_ADJTIME
|
||||
|
||||
#include <ipcom_type.h>
|
||||
#include <ipcom_time.h>
|
||||
#include "ntp_syslog.h"
|
||||
#include "declcond.h"
|
||||
|
||||
/* clear system clock adjustment to be 0 */
|
||||
void adjtime_clear (void)
|
||||
{
|
||||
struct timeval tm;
|
||||
|
||||
tm.tv_sec = 0;
|
||||
tm.tv_usec = 0;
|
||||
(void)ipcom_adjtime(&tm, IP_NULL);
|
||||
}
|
||||
|
||||
int adjtime (struct timeval *delta, struct timeval *olddelta)
|
||||
{
|
||||
if (ipcom_adjtime(delta, olddelta) < 0)
|
||||
{
|
||||
#ifdef NTP_DEBUG
|
||||
if (debug > 3)
|
||||
msyslog(LOG_ERR, "Failed in calling ipcom_adjtime: (%li:%li) old(%li:%li)",
|
||||
delta->tv_sec, delta->tv_usec, olddelta->tv_sec, olddelta->tv_usec);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
||||
#define IPCOM_USE_CLIB_PROTO
|
||||
#include <ipcom_clib.h>
|
||||
#include <ipcom_err.h>
|
||||
|
||||
#include <time.h>
|
||||
#include "ntp_syslog.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_vxworks.h"
|
||||
|
||||
#define SinMS 1000000L
|
||||
|
||||
int adjtime( struct timeval *delta, struct timeval *olddelta )
|
||||
{
|
||||
struct Ip_timeval tm;
|
||||
|
||||
(void)ipcom_gettimeofday(&tm, IP_NULL);
|
||||
if (delta->tv_sec > 0 || (delta->tv_sec == 0 && delta->tv_usec > 0))
|
||||
{
|
||||
tm.tv_sec += delta->tv_sec;
|
||||
tm.tv_usec += delta->tv_usec;
|
||||
if (tm.tv_usec > SinMS)
|
||||
{
|
||||
tm.tv_usec -= SinMS;
|
||||
tm.tv_sec += 1;
|
||||
}
|
||||
}
|
||||
else /* delta is a negative value. */
|
||||
{
|
||||
tm.tv_sec += delta->tv_sec;
|
||||
tm.tv_usec += delta->tv_usec;
|
||||
if (tm.tv_usec < 0)
|
||||
{
|
||||
tm.tv_usec += SinMS;
|
||||
tm.tv_sec -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NTP_DEBUG
|
||||
if (debug > 3)
|
||||
msyslog(LOG_DEBUG, "%s1: (%li:%li) old(%li:%li)",
|
||||
__FUNCTION__, delta->tv_sec, delta->tv_usec,
|
||||
olddelta->tv_sec, olddelta->tv_usec);
|
||||
#endif
|
||||
(void)ipcom_settimeofday(&tm, IP_NULL);
|
||||
return 0;
|
||||
}
|
||||
#endif /* !HAVE_VXWORKS_ADJTIME */
|
||||
|
||||
/* The software precision is low. These following codes is suitable for HW adjust time */
|
||||
#if 0
|
||||
|
||||
#define USECS_PER_SEC 1000000
|
||||
#define ADJTIME_MAX (0x7fffffff/(USECS_PER_SEC*NTP_SYSCLKRATEGET)) /* = ~35 s at 60 Hz */
|
||||
|
||||
static Ip_s32 adjTime = 0; /* Time left to adjust in clocke ticks */
|
||||
static Ipcom_mutex adjTimeMsem = IP_NULL;
|
||||
static Ip_pid_t adjTime_tid = 0;
|
||||
|
||||
int adj_debug = 0;
|
||||
|
||||
void usrTimeAdj(void)
|
||||
{
|
||||
struct Ip_timeval tm;
|
||||
struct Ip_timeval tm_res;
|
||||
|
||||
ipcom_proc_init();
|
||||
|
||||
/* assume that clock resolution is <= 1 second */
|
||||
tm_res.tv_sec = 0;
|
||||
tm_res.tv_usec = (1000000 / NTP_SYSCLKRATEGET);
|
||||
|
||||
#ifdef NTP_DEBUG
|
||||
if (debug > 3)
|
||||
msyslog(LOG_DEBUG, "tadjTime task start");
|
||||
#endif
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (adjTime == 0)
|
||||
{
|
||||
adjTime_tid = 0;
|
||||
#ifdef NTP_DEBUG
|
||||
if (debug > 3)
|
||||
msyslog(LOG_DEBUG, "tadjTime task exit");
|
||||
#endif
|
||||
goto exit;
|
||||
}
|
||||
|
||||
(void)ipcom_millisleep(250);
|
||||
(void)ipcom_gettimeofday(&tm, IP_NULL);
|
||||
|
||||
if (adjTime > 0)
|
||||
{
|
||||
tm.tv_usec += tm_res.tv_usec;
|
||||
if (tm.tv_usec > SinMS)
|
||||
{
|
||||
tm.tv_usec -= SinMS;
|
||||
tm.tv_sec += 1;
|
||||
}
|
||||
ipcom_mutex_lock(adjTimeMsem);
|
||||
{
|
||||
adjTime--;
|
||||
}
|
||||
ipcom_mutex_unlock(adjTimeMsem);
|
||||
}
|
||||
else
|
||||
{
|
||||
tm.tv_usec -= tm_res.tv_usec;
|
||||
if (tm.tv_usec < 0)
|
||||
{
|
||||
tm.tv_usec += SinMS;
|
||||
tm.tv_sec -= 1;
|
||||
}
|
||||
ipcom_mutex_lock(adjTimeMsem);
|
||||
{
|
||||
adjTime++;
|
||||
}
|
||||
ipcom_mutex_unlock(adjTimeMsem);
|
||||
}
|
||||
|
||||
/*printf("adjTime %d set %d,%d\n", adjTime, tv.tv_sec,tv.tv_nsec );*/
|
||||
(void)ipcom_settimeofday(&tm, IP_NULL);
|
||||
} /* FOREVER */
|
||||
|
||||
exit:
|
||||
ipcom_proc_exit();
|
||||
}
|
||||
|
||||
Ip_s32 adjtime( struct timeval *delta, struct timeval *olddelta )
|
||||
{
|
||||
int adjTime_in_usec = adjTime * USECS_PER_SEC;
|
||||
double adjTime2;
|
||||
|
||||
#ifdef NTP_DEBUG
|
||||
if (adj_debug)
|
||||
msyslog(LOG_DEBUG, "%s1: %i (%li:%li) old(%li:%li)",
|
||||
__FUNCTION__, adjTime,
|
||||
delta->tv_sec, delta->tv_usec,
|
||||
olddelta->tv_sec, olddelta->tv_usec);
|
||||
|
||||
if (delta->tv_sec)
|
||||
msyslog(LOG_DEBUG, "%s1: %i (%li:%li) old(%li:%li)",
|
||||
__FUNCTION__, adjTime,
|
||||
delta->tv_sec, delta->tv_usec,
|
||||
olddelta->tv_sec, olddelta->tv_usec);
|
||||
#endif
|
||||
|
||||
|
||||
if ( (delta->tv_sec > ADJTIME_MAX) || (delta->tv_sec < -ADJTIME_MAX) )
|
||||
{
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if(adjTimeMsem == IP_NULL)
|
||||
{
|
||||
if (ipcom_mutex_create(&adjTimeMsem) != IPCOM_SUCCESS)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ipcom_mutex_lock(adjTimeMsem);
|
||||
{
|
||||
olddelta->tv_sec = (adjTime_in_usec / USECS_PER_SEC);
|
||||
olddelta->tv_usec = (adjTime_in_usec % USECS_PER_SEC);
|
||||
|
||||
adjTime2 = (double)(((delta->tv_sec * (double)USECS_PER_SEC) + delta->tv_usec) * NTP_SYSCLKRATEGET)/
|
||||
(double)USECS_PER_SEC;
|
||||
|
||||
if (adj_debug)
|
||||
msyslog(LOG_DEBUG, "%s1: %.6f", __FUNCTION__, adjTime2);
|
||||
|
||||
/* round up */
|
||||
if (adjTime2 > 0)
|
||||
adjTime2 += 0.5;
|
||||
else
|
||||
adjTime2 -= 0.5;
|
||||
|
||||
if (adj_debug)
|
||||
msyslog(LOG_DEBUG, "%s1: %.6f", __FUNCTION__, adjTime2);
|
||||
|
||||
adjTime = (int) adjTime2;
|
||||
}
|
||||
ipcom_mutex_unlock(adjTimeMsem);
|
||||
|
||||
#ifdef NTP_DEBUG
|
||||
if (adj_debug)
|
||||
msyslog(LOG_DEBUG, "%s1: %i",
|
||||
__FUNCTION__, adjTime);
|
||||
#endif
|
||||
|
||||
if (!adjTime)
|
||||
{
|
||||
/* if the adjustment is less then the resolution it can't be adjusted */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (adjTime_tid == 0)
|
||||
{
|
||||
Ipcom_proc_attr attr;
|
||||
|
||||
ipcom_proc_attr_init(&attr);
|
||||
attr.priority = IPCOM_PRIORITY_MIN;
|
||||
attr.flags |= IPCOM_PROC_FLAG_FP;
|
||||
attr.stacksize = IPCOM_PROC_STACK_DEFAULT;
|
||||
if(ipcom_proc_acreate("tAdjTime", (Ipcom_proc_func)usrTimeAdj, &attr, &adjTime_tid))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NTP_DEBUG
|
||||
if (adj_debug)
|
||||
msyslog(LOG_DEBUG, "%s2: %i (%li:%li) old(%li:%li)",
|
||||
__FUNCTION__, adjTime,
|
||||
delta->tv_sec, delta->tv_usec,
|
||||
olddelta->tv_sec, olddelta->tv_usec);
|
||||
#endif
|
||||
|
||||
return( 0 );
|
||||
} /* adjtime() */
|
||||
|
||||
|
||||
void kill_adjtimeTask ( void )
|
||||
{
|
||||
if (adjTime_tid != 0)
|
||||
{
|
||||
ipcom_mutex_lock(adjTimeMsem);
|
||||
adjTime = 0;
|
||||
ipcom_mutex_unlock(adjTimeMsem);
|
||||
/* call ipcom_sleep to make the tAdjTime task exit */
|
||||
ipcom_millisleep(100);
|
||||
|
||||
/*
|
||||
if (adjTimeMsem != IP_NULL)
|
||||
(void)ipcom_mutex_delete(&adjTimeMsem);
|
||||
adjTimeMsem = IP_NULL;
|
||||
*/
|
||||
adjTime_tid = 0;
|
||||
}
|
||||
|
||||
adjTime = 0; /* Time left to adjust in clocke ticks */
|
||||
adj_debug = 0;
|
||||
}
|
||||
|
||||
/* test codes */
|
||||
void adjtimetest(int s)
|
||||
{
|
||||
struct timeval delta;
|
||||
struct timeval olddelta;
|
||||
|
||||
delta.tv_sec = s;
|
||||
delta.tv_usec = 0;
|
||||
|
||||
printf("new: %li:%li\n", delta.tv_sec, delta.tv_usec);
|
||||
if (adjtime( &delta, &olddelta ) != 0)
|
||||
{
|
||||
printf("ADJTIME ERROR\n");
|
||||
return;
|
||||
}
|
||||
printf("old: %li:%li -> new %li:%li\n", olddelta.tv_sec, olddelta.tv_usec, delta.tv_sec, delta.tv_usec);
|
||||
}
|
||||
|
||||
void setdate(char* str)
|
||||
{
|
||||
struct tm tm ;
|
||||
struct timespec tv ;
|
||||
|
||||
tm.tm_sec = (str[10] -'0')*10 + str[11] - '0' ;
|
||||
tm.tm_min = (str[8] -'0')*10 + str[9] - '0' ;
|
||||
tm.tm_hour = (str[6] -'0')*10 + str[7] - '0' ;
|
||||
tm.tm_mday = (str[4] -'0')*10 + str[5] - '0' ;
|
||||
tm.tm_mon = (str[2] -'0')*10 + str[3] - '0' - 1; /* Jan == 0 */
|
||||
tm.tm_year = (str[0] -'0')*10 + str[1] - '0' + 100;
|
||||
tm.tm_wday = 0 ;
|
||||
tm.tm_yday = 0 ;
|
||||
tm.tm_isdst = 0 ;
|
||||
|
||||
tv.tv_sec = mktime( &tm );
|
||||
tv.tv_nsec = 0;
|
||||
printf("sec: %li\n",tv.tv_sec);
|
||||
clock_settime( CLOCK_REALTIME, &tv );
|
||||
}
|
||||
#endif /* 0 */
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 1983 Regents of the University of California.
|
||||
* All rights reserved. The Berkeley software License Agreement
|
||||
* specifies the terms and conditions for redistribution.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
_sccsid:.asciz "11/19/91 ULTRIX @(#)adjtime.c 6.1"
|
||||
#endif not lint
|
||||
|
||||
#include "SYS.h"
|
||||
|
||||
SYSCALL(adjtimex)
|
||||
ret
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* atoint - convert an ascii string to a signed long, with error checking
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ntp_types.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
int
|
||||
atoint(
|
||||
const char *str,
|
||||
long *ival
|
||||
)
|
||||
{
|
||||
register long u;
|
||||
register const char *cp;
|
||||
register int isneg;
|
||||
register int oflow_digit;
|
||||
|
||||
cp = str;
|
||||
|
||||
if (*cp == '-') {
|
||||
cp++;
|
||||
isneg = 1;
|
||||
oflow_digit = '8';
|
||||
} else {
|
||||
isneg = 0;
|
||||
oflow_digit = '7';
|
||||
}
|
||||
|
||||
if (*cp == '\0')
|
||||
return 0;
|
||||
|
||||
u = 0;
|
||||
while (*cp != '\0') {
|
||||
if (!isdigit((unsigned char)*cp))
|
||||
return 0;
|
||||
if (u > 214748364 || (u == 214748364 && *cp > oflow_digit))
|
||||
return 0; /* overflow */
|
||||
u = (u << 3) + (u << 1);
|
||||
u += *cp++ - '0'; /* ascii dependent */
|
||||
}
|
||||
|
||||
if (isneg)
|
||||
*ival = -u;
|
||||
else
|
||||
*ival = u;
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* atolfp - convert an ascii string to an l_fp number
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "ntp_string.h"
|
||||
#include "ntp_assert.h"
|
||||
|
||||
/*
|
||||
* Powers of 10
|
||||
*/
|
||||
static u_long ten_to_the_n[10] = {
|
||||
0,
|
||||
10,
|
||||
100,
|
||||
1000,
|
||||
10000,
|
||||
100000,
|
||||
1000000,
|
||||
10000000,
|
||||
100000000,
|
||||
1000000000,
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
atolfp(
|
||||
const char *str,
|
||||
l_fp *lfp
|
||||
)
|
||||
{
|
||||
register const char *cp;
|
||||
register u_long dec_i;
|
||||
register u_long dec_f;
|
||||
char *ind;
|
||||
int ndec;
|
||||
int isneg;
|
||||
static const char *digits = "0123456789";
|
||||
|
||||
REQUIRE(str != NULL);
|
||||
|
||||
isneg = 0;
|
||||
dec_i = dec_f = 0;
|
||||
ndec = 0;
|
||||
cp = str;
|
||||
|
||||
/*
|
||||
* We understand numbers of the form:
|
||||
*
|
||||
* [spaces][-|+][digits][.][digits][spaces|\n|\0]
|
||||
*/
|
||||
while (isspace((unsigned char)*cp))
|
||||
cp++;
|
||||
|
||||
if (*cp == '-') {
|
||||
cp++;
|
||||
isneg = 1;
|
||||
}
|
||||
|
||||
if (*cp == '+')
|
||||
cp++;
|
||||
|
||||
if (*cp != '.' && !isdigit((unsigned char)*cp))
|
||||
return 0;
|
||||
|
||||
while (*cp != '\0' && (ind = strchr(digits, *cp)) != NULL) {
|
||||
dec_i = (dec_i << 3) + (dec_i << 1); /* multiply by 10 */
|
||||
dec_i += (u_long)(ind - digits);
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (*cp != '\0' && !isspace((unsigned char)*cp)) {
|
||||
if (*cp++ != '.')
|
||||
return 0;
|
||||
|
||||
while (ndec < 9 && *cp != '\0'
|
||||
&& (ind = strchr(digits, *cp)) != NULL) {
|
||||
ndec++;
|
||||
dec_f = (dec_f << 3) + (dec_f << 1); /* *10 */
|
||||
dec_f += (u_long)(ind - digits);
|
||||
cp++;
|
||||
}
|
||||
|
||||
while (isdigit((unsigned char)*cp))
|
||||
cp++;
|
||||
|
||||
if (*cp != '\0' && !isspace((unsigned char)*cp))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ndec > 0) {
|
||||
register u_long tmp;
|
||||
register u_long bit;
|
||||
register u_long ten_fact;
|
||||
|
||||
ten_fact = ten_to_the_n[ndec];
|
||||
|
||||
tmp = 0;
|
||||
bit = 0x80000000;
|
||||
while (bit != 0) {
|
||||
dec_f <<= 1;
|
||||
if (dec_f >= ten_fact) {
|
||||
tmp |= bit;
|
||||
dec_f -= ten_fact;
|
||||
}
|
||||
bit >>= 1;
|
||||
}
|
||||
if ((dec_f << 1) > ten_fact)
|
||||
tmp++;
|
||||
dec_f = tmp;
|
||||
}
|
||||
|
||||
if (isneg)
|
||||
M_NEG(dec_i, dec_f);
|
||||
|
||||
lfp->l_ui = dec_i;
|
||||
lfp->l_uf = dec_f;
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <ipntp_config.h>
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ntp_types.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
/*
|
||||
* atouint() - convert an ascii string representing a whole base 10
|
||||
* number to u_long *uval, returning TRUE if successful.
|
||||
* Does not modify *uval and returns FALSE if str is not
|
||||
* a positive base10 integer or is too large for a u_int32.
|
||||
* this function uses u_long but should use u_int32, and
|
||||
* probably be renamed.
|
||||
*/
|
||||
int
|
||||
atouint(
|
||||
const char *str,
|
||||
u_long *uval
|
||||
)
|
||||
{
|
||||
u_long u;
|
||||
const char *cp;
|
||||
|
||||
cp = str;
|
||||
if ('\0' == *cp)
|
||||
return 0;
|
||||
|
||||
u = 0;
|
||||
while ('\0' != *cp) {
|
||||
if (!isdigit((unsigned char)*cp))
|
||||
return 0;
|
||||
if (u > 429496729 || (u == 429496729 && *cp >= '6'))
|
||||
return 0; /* overflow */
|
||||
/* hand-optimized u *= 10; */
|
||||
u = (u << 3) + (u << 1);
|
||||
u += *cp++ - '0'; /* not '\0' */
|
||||
}
|
||||
|
||||
*uval = u;
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,519 @@
|
||||
/*
|
||||
* audio.c - audio interface for reference clock audio drivers
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SYS_AUDIOIO_H) || defined(HAVE_SUN_AUDIOIO_H) || \
|
||||
defined(HAVE_SYS_SOUNDCARD_H) || defined(HAVE_MACHINE_SOUNDCARD_H)
|
||||
|
||||
#include "audio.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_syslog.h"
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include "ntp_string.h"
|
||||
|
||||
#ifdef HAVE_SYS_AUDIOIO_H
|
||||
# include <sys/audioio.h>
|
||||
#endif /* HAVE_SYS_AUDIOIO_H */
|
||||
|
||||
#ifdef HAVE_SUN_AUDIOIO_H
|
||||
# include <sys/ioccom.h>
|
||||
# include <sun/audioio.h>
|
||||
#endif /* HAVE_SUN_AUDIOIO_H */
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
# include <sys/ioctl.h>
|
||||
#endif /* HAVE_SYS_IOCTL_H */
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef HAVE_MACHINE_SOUNDCARD_H
|
||||
# include <machine/soundcard.h>
|
||||
# define PCM_STYLE_SOUND
|
||||
#else
|
||||
# ifdef HAVE_SYS_SOUNDCARD_H
|
||||
# include <sys/soundcard.h>
|
||||
# define PCM_STYLE_SOUND
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef PCM_STYLE_SOUND
|
||||
# include <ctype.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* 4.4BSD-Lite switched to an unsigned long ioctl arg. Detect common
|
||||
* derivatives here, and apply that type. To make the following code
|
||||
* less verbose we make a proper typedef.
|
||||
* The joy of IOCTL programming...
|
||||
*/
|
||||
# if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__) || defined __OpenBSD__
|
||||
typedef unsigned long ioctl_arg_T;
|
||||
#else
|
||||
typedef int ioctl_arg_T;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
#ifdef HAVE_SYS_AUDIOIO_H
|
||||
static struct audio_device device; /* audio device ident */
|
||||
#endif /* HAVE_SYS_AUDIOIO_H */
|
||||
#ifdef PCM_STYLE_SOUND
|
||||
# define INIT_FILE "/etc/ntp.audio"
|
||||
|
||||
static ioctl_arg_T agc = SOUND_MIXER_WRITE_RECLEV; /* or IGAIN or LINE */
|
||||
static ioctl_arg_T audiomonitor = SOUND_MIXER_WRITE_VOLUME; /* or OGAIN */
|
||||
static int devmask = 0;
|
||||
static int recmask = 0;
|
||||
static char cf_c_dev[100], cf_i_dev[100], cf_agc[100], cf_monitor[100];
|
||||
|
||||
static const char *m_names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
|
||||
#else /* not PCM_STYLE_SOUND */
|
||||
static struct audio_info info; /* audio device info */
|
||||
#endif /* not PCM_STYLE_SOUND */
|
||||
static int ctl_fd; /* audio control file descriptor */
|
||||
|
||||
#ifdef PCM_STYLE_SOUND
|
||||
static void audio_config_read (int, const char **, const char **);
|
||||
static int mixer_name (const char *, int);
|
||||
|
||||
|
||||
int
|
||||
mixer_name(
|
||||
const char *m_name,
|
||||
int m_mask
|
||||
)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SOUND_MIXER_NRDEVICES; ++i)
|
||||
if (((1 << i) & m_mask)
|
||||
&& !strcmp(m_names[i], m_name))
|
||||
break;
|
||||
|
||||
return (SOUND_MIXER_NRDEVICES == i)
|
||||
? -1
|
||||
: i
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check:
|
||||
*
|
||||
* /etc/ntp.audio# where # is the unit number
|
||||
* /etc/ntp.audio.# where # is the unit number
|
||||
* /etc/ntp.audio
|
||||
*
|
||||
* for contents of the form:
|
||||
*
|
||||
* idev /dev/input_device
|
||||
* cdev /dev/control_device
|
||||
* agc pcm_input_device {igain,line,line1,...}
|
||||
* monitor pcm_monitor_device {ogain,...}
|
||||
*
|
||||
* The device names for the "agc" and "monitor" keywords
|
||||
* can be found by running either the "mixer" program or the
|
||||
* util/audio-pcm program.
|
||||
*
|
||||
* Great hunks of this subroutine were swiped from refclock_oncore.c
|
||||
*/
|
||||
static void
|
||||
audio_config_read(
|
||||
int unit,
|
||||
const char **c_dev, /* Control device */
|
||||
const char **i_dev /* input device */
|
||||
)
|
||||
{
|
||||
FILE *fd;
|
||||
char device[20], line[100], ab[100];
|
||||
|
||||
snprintf(device, sizeof(device), "%s%d", INIT_FILE, unit);
|
||||
if ((fd = fopen(device, "r")) == NULL) {
|
||||
printf("audio_config_read: <%s> NO\n", device);
|
||||
snprintf(device, sizeof(device), "%s.%d", INIT_FILE,
|
||||
unit);
|
||||
if ((fd = fopen(device, "r")) == NULL) {
|
||||
printf("audio_config_read: <%s> NO\n", device);
|
||||
snprintf(device, sizeof(device), "%s",
|
||||
INIT_FILE);
|
||||
if ((fd = fopen(device, "r")) == NULL) {
|
||||
printf("audio_config_read: <%s> NO\n",
|
||||
device);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("audio_config_read: reading <%s>\n", device);
|
||||
while (fgets(line, sizeof line, fd)) {
|
||||
char *cp, *cc, *ca;
|
||||
int i;
|
||||
|
||||
/* Remove comments */
|
||||
if ((cp = strchr(line, '#')))
|
||||
*cp = '\0';
|
||||
|
||||
/* Remove any trailing spaces */
|
||||
for (i = strlen(line);
|
||||
i > 0 && isascii((unsigned char)line[i - 1]) && isspace((unsigned char)line[i - 1]);
|
||||
)
|
||||
line[--i] = '\0';
|
||||
|
||||
/* Remove leading space */
|
||||
for (cc = line; *cc && isascii((unsigned char)*cc) && isspace((unsigned char)*cc); cc++)
|
||||
continue;
|
||||
|
||||
/* Stop if nothing left */
|
||||
if (!*cc)
|
||||
continue;
|
||||
|
||||
/* Uppercase the command and find the arg */
|
||||
for (ca = cc; *ca; ca++) {
|
||||
if (isascii((unsigned char)*ca)) {
|
||||
if (islower((unsigned char)*ca)) {
|
||||
*ca = toupper((unsigned char)*ca);
|
||||
} else if (isspace((unsigned char)*ca) || (*ca == '='))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove space (and possible =) leading the arg */
|
||||
for (; *ca && isascii((unsigned char)*ca) && (isspace((unsigned char)*ca) || (*ca == '=')); ca++)
|
||||
continue;
|
||||
|
||||
if (!strncmp(cc, "IDEV", 4) &&
|
||||
1 == sscanf(ca, "%99s", ab)) {
|
||||
strlcpy(cf_i_dev, ab, sizeof(cf_i_dev));
|
||||
printf("idev <%s>\n", ab);
|
||||
} else if (!strncmp(cc, "CDEV", 4) &&
|
||||
1 == sscanf(ca, "%99s", ab)) {
|
||||
strlcpy(cf_c_dev, ab, sizeof(cf_c_dev));
|
||||
printf("cdev <%s>\n", ab);
|
||||
} else if (!strncmp(cc, "AGC", 3) &&
|
||||
1 == sscanf(ca, "%99s", ab)) {
|
||||
strlcpy(cf_agc, ab, sizeof(cf_agc));
|
||||
printf("agc <%s> %d\n", ab, i);
|
||||
} else if (!strncmp(cc, "MONITOR", 7) &&
|
||||
1 == sscanf(ca, "%99s", ab)) {
|
||||
strlcpy(cf_monitor, ab, sizeof(cf_monitor));
|
||||
printf("monitor <%s> %d\n", ab, mixer_name(ab, -1));
|
||||
}
|
||||
}
|
||||
fclose(fd);
|
||||
return;
|
||||
}
|
||||
#endif /* PCM_STYLE_SOUND */
|
||||
|
||||
/*
|
||||
* audio_init - open and initialize audio device
|
||||
*
|
||||
* This code works with SunOS 4.x, Solaris 2.x, and PCM; however, it is
|
||||
* believed generic and applicable to other systems with a minor twid
|
||||
* or two. All it does is open the device, set the buffer size (Solaris
|
||||
* only), preset the gain and set the input port. It assumes that the
|
||||
* codec sample rate (8000 Hz), precision (8 bits), number of channels
|
||||
* (1) and encoding (ITU-T G.711 mu-law companded) have been set by
|
||||
* default.
|
||||
*/
|
||||
int
|
||||
audio_init(
|
||||
const char *dname, /* device name */
|
||||
int bufsiz, /* buffer size */
|
||||
int unit /* device unit (0-3) */
|
||||
)
|
||||
{
|
||||
#ifdef PCM_STYLE_SOUND
|
||||
# define ACTL_DEV "/dev/mixer%d"
|
||||
char actl_dev[30];
|
||||
# ifdef HAVE_STRUCT_SND_SIZE
|
||||
struct snd_size s_size;
|
||||
# endif
|
||||
# ifdef AIOGFMT
|
||||
snd_chan_param s_c_p;
|
||||
# endif
|
||||
#endif
|
||||
int fd;
|
||||
int rval;
|
||||
const char *actl =
|
||||
#ifdef PCM_STYLE_SOUND
|
||||
actl_dev
|
||||
#else
|
||||
"/dev/audioctl"
|
||||
#endif
|
||||
;
|
||||
|
||||
#ifdef PCM_STYLE_SOUND
|
||||
snprintf(actl_dev, sizeof(actl_dev), ACTL_DEV, unit);
|
||||
|
||||
audio_config_read(unit, &actl, &dname);
|
||||
/* If we have values for cf_c_dev or cf_i_dev, use them. */
|
||||
if (*cf_c_dev)
|
||||
actl = cf_c_dev;
|
||||
if (*cf_i_dev)
|
||||
dname = cf_i_dev;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Open audio device
|
||||
*/
|
||||
fd = open(dname, O_RDWR | O_NONBLOCK, 0777);
|
||||
if (fd < 0) {
|
||||
msyslog(LOG_ERR, "audio_init: %s %m", dname);
|
||||
return (fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open audio control device.
|
||||
*/
|
||||
ctl_fd = open(actl, O_RDWR);
|
||||
if (ctl_fd < 0) {
|
||||
msyslog(LOG_ERR, "audio_init: invalid control device <%s>",
|
||||
actl);
|
||||
close(fd);
|
||||
return(ctl_fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set audio device parameters.
|
||||
*/
|
||||
#ifdef PCM_STYLE_SOUND
|
||||
printf("audio_init: <%s> bufsiz %d\n", dname, bufsiz);
|
||||
rval = fd;
|
||||
|
||||
# ifdef HAVE_STRUCT_SND_SIZE
|
||||
if (ioctl(fd, AIOGSIZE, &s_size) == -1)
|
||||
printf("audio_init: AIOGSIZE: %s\n", strerror(errno));
|
||||
else
|
||||
printf("audio_init: orig: play_size %d, rec_size %d\n",
|
||||
s_size.play_size, s_size.rec_size);
|
||||
|
||||
s_size.play_size = s_size.rec_size = bufsiz;
|
||||
printf("audio_init: want: play_size %d, rec_size %d\n",
|
||||
s_size.play_size, s_size.rec_size);
|
||||
|
||||
if (ioctl(fd, AIOSSIZE, &s_size) == -1)
|
||||
printf("audio_init: AIOSSIZE: %s\n", strerror(errno));
|
||||
else
|
||||
printf("audio_init: set: play_size %d, rec_size %d\n",
|
||||
s_size.play_size, s_size.rec_size);
|
||||
# endif /* HAVE_STRUCT_SND_SIZE */
|
||||
|
||||
# ifdef SNDCTL_DSP_SETFRAGMENT
|
||||
{
|
||||
int tmp = (16 << 16) + 6; /* 16 fragments, each 2^6 bytes */
|
||||
if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1)
|
||||
printf("audio_init: SNDCTL_DSP_SETFRAGMENT: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
# endif /* SNDCTL_DSP_SETFRAGMENT */
|
||||
|
||||
# ifdef AIOGFMT
|
||||
if (ioctl(fd, AIOGFMT, &s_c_p) == -1)
|
||||
printf("audio_init: AIOGFMT: %s\n", strerror(errno));
|
||||
else
|
||||
printf("audio_init: play_rate %lu, rec_rate %lu, play_format %#lx, rec_format %#lx\n",
|
||||
s_c_p.play_rate, s_c_p.rec_rate, s_c_p.play_format, s_c_p.rec_format);
|
||||
# endif
|
||||
|
||||
/* Grab the device and record masks */
|
||||
|
||||
if (ioctl(ctl_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
|
||||
printf("SOUND_MIXER_READ_DEVMASK: %s\n", strerror(errno));
|
||||
if (ioctl(ctl_fd, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
|
||||
printf("SOUND_MIXER_READ_RECMASK: %s\n", strerror(errno));
|
||||
|
||||
/* validate and set any specified config file stuff */
|
||||
if (cf_agc[0] != '\0') {
|
||||
int i;
|
||||
|
||||
/* recmask */
|
||||
i = mixer_name(cf_agc, recmask);
|
||||
if (i >= 0)
|
||||
agc = MIXER_WRITE(i);
|
||||
else
|
||||
printf("input %s not in recmask %#x\n",
|
||||
cf_agc, recmask);
|
||||
}
|
||||
|
||||
if (cf_monitor[0] != '\0') {
|
||||
int i;
|
||||
|
||||
/* devmask */
|
||||
i = mixer_name(cf_monitor, devmask);
|
||||
if (i >= 0)
|
||||
audiomonitor = MIXER_WRITE(i);
|
||||
else
|
||||
printf("monitor %s not in devmask %#x\n",
|
||||
cf_monitor, devmask);
|
||||
}
|
||||
|
||||
#else /* not PCM_STYLE_SOUND */
|
||||
AUDIO_INITINFO(&info);
|
||||
info.play.gain = AUDIO_MAX_GAIN;
|
||||
info.play.port = AUDIO_SPEAKER;
|
||||
# ifdef HAVE_SYS_AUDIOIO_H
|
||||
info.record.buffer_size = bufsiz;
|
||||
# endif /* HAVE_SYS_AUDIOIO_H */
|
||||
rval = ioctl(ctl_fd, AUDIO_SETINFO, (char *)&info);
|
||||
if (rval < 0) {
|
||||
msyslog(LOG_ERR, "audio: invalid control device parameters");
|
||||
close(ctl_fd);
|
||||
close(fd);
|
||||
return(rval);
|
||||
}
|
||||
rval = fd;
|
||||
#endif /* not PCM_STYLE_SOUND */
|
||||
return (rval);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* audio_gain - adjust codec gains and port
|
||||
*/
|
||||
int
|
||||
audio_gain(
|
||||
int gain, /* volume level (gain) 0-255 */
|
||||
int mongain, /* input to output mix (monitor gain) 0-255 */
|
||||
int port /* selected I/O port: 1 mic/2 line in */
|
||||
)
|
||||
{
|
||||
int rval;
|
||||
static int o_mongain = -1;
|
||||
static int o_port = -1;
|
||||
|
||||
#ifdef PCM_STYLE_SOUND
|
||||
int l, r;
|
||||
|
||||
rval = 0;
|
||||
|
||||
r = l = 100 * gain / 255; /* Normalize to 0-100 */
|
||||
# ifdef NTP_DEBUG
|
||||
if (debug > 1)
|
||||
printf("audio_gain: gain %d/%d\n", gain, l);
|
||||
# endif
|
||||
#if 0 /* not a good idea to do this; connector wiring dependency */
|
||||
/* figure out what channel(s) to use. just nuke right for now. */
|
||||
r = 0 ; /* setting to zero nicely mutes the channel */
|
||||
#endif
|
||||
l |= r << 8;
|
||||
if (cf_agc[0] != '\0')
|
||||
rval = ioctl(ctl_fd, agc, &l);
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
if (o_mongain != mongain) {
|
||||
r = l = 100 * mongain / 255; /* Normalize to 0-100 */
|
||||
# ifdef NTP_DEBUG
|
||||
if (debug > 1)
|
||||
printf("audio_gain: mongain %d/%d\n", mongain, l);
|
||||
# endif
|
||||
l |= r << 8;
|
||||
if (cf_monitor[0] != '\0')
|
||||
rval = ioctl(ctl_fd, audiomonitor, &l );
|
||||
else
|
||||
rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_VOLUME,
|
||||
&l);
|
||||
if (-1 == rval) {
|
||||
printf("audio_gain: mongain write: %s\n",
|
||||
strerror(errno));
|
||||
return (rval);
|
||||
}
|
||||
o_mongain = mongain;
|
||||
}
|
||||
|
||||
if (o_port != port) {
|
||||
# ifdef NTP_DEBUG
|
||||
if (debug > 1)
|
||||
printf("audio_gain: port %d\n", port);
|
||||
# endif
|
||||
l = (1 << ((port == 2) ? SOUND_MIXER_LINE : SOUND_MIXER_MIC));
|
||||
rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_RECSRC, &l);
|
||||
if (rval == -1) {
|
||||
printf("SOUND_MIXER_WRITE_RECSRC: %s\n",
|
||||
strerror(errno));
|
||||
return (rval);
|
||||
}
|
||||
# ifdef NTP_DEBUG
|
||||
if (debug > 1) {
|
||||
if (ioctl(ctl_fd, SOUND_MIXER_READ_RECSRC, &l) == -1)
|
||||
printf("SOUND_MIXER_WRITE_RECSRC: %s\n",
|
||||
strerror(errno));
|
||||
else
|
||||
printf("audio_gain: recsrc is %d\n", l);
|
||||
}
|
||||
# endif
|
||||
o_port = port;
|
||||
}
|
||||
#else /* not PCM_STYLE_SOUND */
|
||||
ioctl(ctl_fd, AUDIO_GETINFO, (char *)&info);
|
||||
info.record.encoding = AUDIO_ENCODING_ULAW;
|
||||
info.record.error = 0;
|
||||
info.record.gain = gain;
|
||||
if (o_mongain != mongain)
|
||||
o_mongain = info.monitor_gain = mongain;
|
||||
if (o_port != port)
|
||||
o_port = info.record.port = port;
|
||||
rval = ioctl(ctl_fd, AUDIO_SETINFO, (char *)&info);
|
||||
if (rval < 0) {
|
||||
msyslog(LOG_ERR, "audio_gain: %m");
|
||||
return (rval);
|
||||
}
|
||||
rval = info.record.error;
|
||||
#endif /* not PCM_STYLE_SOUND */
|
||||
return (rval);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* audio_show - display audio parameters
|
||||
*
|
||||
* This code doesn't really do anything, except satisfy curiousity and
|
||||
* verify the ioctl's work.
|
||||
*/
|
||||
void
|
||||
audio_show(void)
|
||||
{
|
||||
#ifdef PCM_STYLE_SOUND
|
||||
int recsrc = 0;
|
||||
|
||||
printf("audio_show: ctl_fd %d\n", ctl_fd);
|
||||
if (ioctl(ctl_fd, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
|
||||
printf("SOUND_MIXER_READ_RECSRC: %s\n", strerror(errno));
|
||||
|
||||
#else /* not PCM_STYLE_SOUND */
|
||||
# ifdef HAVE_SYS_AUDIOIO_H
|
||||
ioctl(ctl_fd, AUDIO_GETDEV, &device);
|
||||
printf("audio: name %s, version %s, config %s\n",
|
||||
device.name, device.version, device.config);
|
||||
# endif /* HAVE_SYS_AUDIOIO_H */
|
||||
ioctl(ctl_fd, AUDIO_GETINFO, (char *)&info);
|
||||
printf(
|
||||
"audio: rate %d, chan %d, prec %d, code %d, gain %d, mon %d, port %d\n",
|
||||
info.record.sample_rate, info.record.channels,
|
||||
info.record.precision, info.record.encoding,
|
||||
info.record.gain, info.monitor_gain, info.record.port);
|
||||
printf(
|
||||
"audio: samples %d, eof %d, pause %d, error %d, waiting %d, balance %d\n",
|
||||
info.record.samples, info.record.eof,
|
||||
info.record.pause, info.record.error,
|
||||
info.record.waiting, info.record.balance);
|
||||
#endif /* not PCM_STYLE_SOUND */
|
||||
}
|
||||
#else
|
||||
int audio_bs;
|
||||
#endif /* HAVE_{SYS_AUDIOIO,SUN_AUDIOIO,MACHINE_SOUNDCARD,SYS_SOUNDCARD}_H */
|
||||
@@ -0,0 +1,954 @@
|
||||
/*
|
||||
* authkeys.c - routines to manage the storage of authentication keys
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntp.h"
|
||||
#include "ntp_fp.h"
|
||||
#include "ntpd.h"
|
||||
#include "ntp_lists.h"
|
||||
#include "ntp_string.h"
|
||||
#include "ntp_malloc.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_keyacc.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ntp_mem.h"
|
||||
/*
|
||||
* Structure to store keys in in the hash table.
|
||||
*/
|
||||
typedef struct savekey symkey;
|
||||
|
||||
struct savekey {
|
||||
symkey * hlink; /* next in hash bucket */
|
||||
DECL_DLIST_LINK(symkey, llink); /* for overall & free lists */
|
||||
u_char * secret; /* shared secret */
|
||||
KeyAccT * keyacclist; /* Private key access list */
|
||||
u_long lifetime; /* remaining lifetime */
|
||||
keyid_t keyid; /* key identifier */
|
||||
u_short type; /* OpenSSL digest NID */
|
||||
size_t secretsize; /* secret octets */
|
||||
u_short flags; /* KEY_ flags that wave */
|
||||
};
|
||||
|
||||
/* define the payload region of symkey beyond the list pointers */
|
||||
#define symkey_payload secret
|
||||
|
||||
#define KEY_TRUSTED 0x001 /* this key is trusted */
|
||||
|
||||
#ifdef NTP_DEBUG
|
||||
typedef struct symkey_alloc_tag symkey_alloc;
|
||||
|
||||
struct symkey_alloc_tag {
|
||||
symkey_alloc * link;
|
||||
void * mem; /* enable free() atexit */
|
||||
};
|
||||
|
||||
symkey_alloc * authallocs;
|
||||
#endif /* NTP_DEBUG */
|
||||
|
||||
static u_short auth_log2(size_t);
|
||||
static void auth_resize_hashtable(void);
|
||||
static void allocsymkey(keyid_t, u_short,
|
||||
u_short, u_long, size_t, u_char *, KeyAccT *);
|
||||
static void freesymkey(symkey *);
|
||||
void free_auth_mem(void);
|
||||
|
||||
|
||||
symkey key_listhead; /* list of all in-use keys */;
|
||||
/*
|
||||
* The hash table. This is indexed by the low order bits of the
|
||||
* keyid. We make this fairly big for potentially busy servers.
|
||||
*/
|
||||
#define DEF_AUTHHASHSIZE 64
|
||||
/*#define HASHMASK ((HASHSIZE)-1)*/
|
||||
#define KEYHASH(keyid) ((keyid) & authhashmask)
|
||||
|
||||
int authhashdisabled;
|
||||
u_short authhashbuckets = DEF_AUTHHASHSIZE;
|
||||
u_short authhashmask = DEF_AUTHHASHSIZE - 1;
|
||||
symkey **key_hash;
|
||||
|
||||
u_long authkeynotfound; /* keys not found */
|
||||
u_long authkeylookups; /* calls to lookup keys */
|
||||
u_long authnumkeys; /* number of active keys */
|
||||
u_long authkeyexpired; /* key lifetime expirations */
|
||||
u_long authkeyuncached; /* cache misses */
|
||||
u_long authnokey; /* calls to encrypt with no key */
|
||||
u_long authencryptions; /* calls to encrypt */
|
||||
u_long authdecryptions; /* calls to decrypt */
|
||||
|
||||
/*
|
||||
* Storage for free symkey structures. We malloc() such things but
|
||||
* never free them.
|
||||
*/
|
||||
symkey *authfreekeys;
|
||||
int authnumfreekeys;
|
||||
|
||||
#define MEMINC 16 /* number of new free ones to get */
|
||||
|
||||
/*
|
||||
* The key cache. We cache the last key we looked at here.
|
||||
* Note: this should hold the last *trusted* key. Also the
|
||||
* cache is only loaded when the digest type / MAC algorithm
|
||||
* is valid.
|
||||
*/
|
||||
keyid_t cache_keyid; /* key identifier */
|
||||
u_char *cache_secret; /* secret */
|
||||
size_t cache_secretsize; /* secret length */
|
||||
int cache_type; /* OpenSSL digest NID */
|
||||
u_short cache_flags; /* flags that wave */
|
||||
KeyAccT *cache_keyacclist; /* key access list */
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* manage key access lists
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
/* allocate and populate new access node and pushes it on the list.
|
||||
* Returns the new head.
|
||||
*/
|
||||
KeyAccT*
|
||||
keyacc_new_push(
|
||||
KeyAccT * head,
|
||||
const sockaddr_u * addr,
|
||||
unsigned int subnetbits
|
||||
)
|
||||
{
|
||||
KeyAccT * node = emalloc(sizeof(KeyAccT));
|
||||
|
||||
memcpy(&node->addr, addr, sizeof(sockaddr_u));
|
||||
node->subnetbits = subnetbits;
|
||||
node->next = head;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
/* pop and deallocate the first node of a list of access nodes, if
|
||||
* the list is not empty. Returns the tail of the list.
|
||||
*/
|
||||
KeyAccT*
|
||||
keyacc_pop_free(
|
||||
KeyAccT *head
|
||||
)
|
||||
{
|
||||
KeyAccT * next = NULL;
|
||||
if (head) {
|
||||
next = head->next;
|
||||
efree(head);
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
/* deallocate the list; returns an empty list. */
|
||||
KeyAccT*
|
||||
keyacc_all_free(
|
||||
KeyAccT * head
|
||||
)
|
||||
{
|
||||
while (head)
|
||||
head = keyacc_pop_free(head);
|
||||
return head;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
/* scan a list to see if it contains a given address. Return the
|
||||
* default result value in case of an empty list.
|
||||
*/
|
||||
int /*BOOL*/
|
||||
keyacc_contains(
|
||||
const KeyAccT *head,
|
||||
const sockaddr_u *addr,
|
||||
int defv)
|
||||
{
|
||||
if (head) {
|
||||
do {
|
||||
if (keyacc_amatch(&head->addr, addr,
|
||||
head->subnetbits))
|
||||
return TRUE;
|
||||
} while (NULL != (head = head->next));
|
||||
return FALSE;
|
||||
} else {
|
||||
return !!defv;
|
||||
}
|
||||
}
|
||||
|
||||
#if CHAR_BIT != 8
|
||||
# error "don't know how to handle bytes with that bit size"
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
/* check two addresses for a match, taking a prefix length into account
|
||||
* when doing the compare.
|
||||
*
|
||||
* The ISC lib contains a similar function with not entirely specified
|
||||
* semantics, so it seemed somewhat cleaner to do this from scratch.
|
||||
*
|
||||
* Note 1: It *is* assumed that the addresses are stored in network byte
|
||||
* order, that is, most significant byte first!
|
||||
*
|
||||
* Note 2: "no address" compares unequal to all other addresses, even to
|
||||
* itself. This has the same semantics as NaNs have for floats: *any*
|
||||
* relational or equality operation involving a NaN returns FALSE, even
|
||||
* equality with itself. "no address" is either a NULL pointer argument
|
||||
* or an address of type AF_UNSPEC.
|
||||
*/
|
||||
int/*BOOL*/
|
||||
keyacc_amatch(
|
||||
const sockaddr_u * a1,
|
||||
const sockaddr_u * a2,
|
||||
unsigned int mbits
|
||||
)
|
||||
{
|
||||
const uint8_t * pm1;
|
||||
const uint8_t * pm2;
|
||||
uint8_t msk;
|
||||
unsigned int len;
|
||||
|
||||
/* 1st check: If any address is not an address, it's inequal. */
|
||||
if ( !a1 || (AF_UNSPEC == AF(a1)) ||
|
||||
!a2 || (AF_UNSPEC == AF(a2)) )
|
||||
return FALSE;
|
||||
|
||||
/* We could check pointers for equality here and shortcut the
|
||||
* other checks if we find object identity. But that use case is
|
||||
* too rare to care for it.
|
||||
*/
|
||||
|
||||
/* 2nd check: Address families must be the same. */
|
||||
if (AF(a1) != AF(a2))
|
||||
return FALSE;
|
||||
|
||||
/* type check: address family determines buffer & size */
|
||||
switch (AF(a1)) {
|
||||
case AF_INET:
|
||||
/* IPv4 is easy: clamp size, get byte pointers */
|
||||
if (mbits > sizeof(NSRCADR(a1)) * 8)
|
||||
mbits = sizeof(NSRCADR(a1)) * 8;
|
||||
pm1 = (const void*)&NSRCADR(a1);
|
||||
pm2 = (const void*)&NSRCADR(a2);
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
/* IPv6 is slightly different: Both scopes must match,
|
||||
* too, before we even consider doing a match!
|
||||
*/
|
||||
if ( ! SCOPE_EQ(a1, a2))
|
||||
return FALSE;
|
||||
if (mbits > sizeof(NSRCADR6(a1)) * 8)
|
||||
mbits = sizeof(NSRCADR6(a1)) * 8;
|
||||
pm1 = (const void*)&NSRCADR6(a1);
|
||||
pm2 = (const void*)&NSRCADR6(a2);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* don't know how to compare that!?! */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Split bit length into byte length and partial byte mask.
|
||||
* Note that the byte mask extends from the MSB of a byte down,
|
||||
* and that zero shift (--> mbits % 8 == 0) results in an
|
||||
* all-zero mask.
|
||||
*/
|
||||
msk = 0xFFu ^ (0xFFu >> (mbits & 7));
|
||||
len = mbits >> 3;
|
||||
|
||||
/* 3rd check: Do memcmp() over full bytes, if any */
|
||||
if (len && memcmp(pm1, pm2, len))
|
||||
return FALSE;
|
||||
|
||||
/* 4th check: compare last incomplete byte, if any */
|
||||
if (msk && ((pm1[len] ^ pm2[len]) & msk))
|
||||
return FALSE;
|
||||
|
||||
/* If none of the above failed, we're successfully through. */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* init_auth - initialize internal data
|
||||
*/
|
||||
void
|
||||
init_auth(void)
|
||||
{
|
||||
size_t newalloc;
|
||||
|
||||
|
||||
authhashdisabled = 0;
|
||||
authhashbuckets = DEF_AUTHHASHSIZE;
|
||||
authhashmask = DEF_AUTHHASHSIZE - 1;
|
||||
authkeynotfound = 0;
|
||||
authkeylookups = 0;
|
||||
authnumkeys = 0;
|
||||
authkeyexpired = 0;
|
||||
authkeyuncached = 0;
|
||||
authnokey = 0;
|
||||
authencryptions = 0;
|
||||
authdecryptions = 0;
|
||||
|
||||
authfreekeys = NULL;
|
||||
authnumfreekeys = 0;
|
||||
memset(&cache_keyid, 0, sizeof(keyid_t));
|
||||
cache_secret = NULL;
|
||||
cache_secretsize = 0;
|
||||
cache_type = 0;
|
||||
cache_flags = 0;
|
||||
|
||||
|
||||
/*
|
||||
* Initialize hash table and free list
|
||||
*/
|
||||
newalloc = authhashbuckets * sizeof(key_hash[0]);
|
||||
|
||||
key_hash = emalloc(newalloc);
|
||||
memset(key_hash, '\0', newalloc);
|
||||
|
||||
memset(&key_listhead, 0, sizeof(symkey));
|
||||
INIT_DLIST(key_listhead, llink);
|
||||
|
||||
#ifdef NTP_DEBUG
|
||||
atexit(&free_auth_mem);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* free_auth_mem - assist in leak detection by freeing all dynamic
|
||||
* allocations from this module.
|
||||
*/
|
||||
void
|
||||
free_auth_mem(void)
|
||||
{
|
||||
symkey * sk;
|
||||
#ifdef NTP_DEBUG
|
||||
symkey_alloc * alloc;
|
||||
symkey_alloc * next_alloc;
|
||||
#endif
|
||||
while (NULL != (sk = HEAD_DLIST(key_listhead, llink))) {
|
||||
freesymkey(sk);
|
||||
}
|
||||
efree(key_hash);
|
||||
key_hash = NULL;
|
||||
cache_keyid = 0;
|
||||
cache_flags = 0;
|
||||
cache_keyacclist = NULL;
|
||||
#ifdef NTP_DEBUG
|
||||
for (alloc = authallocs; alloc != NULL; alloc = next_alloc) {
|
||||
next_alloc = alloc->link;
|
||||
efree(alloc->mem);
|
||||
}
|
||||
#endif
|
||||
authfreekeys = NULL;
|
||||
authnumfreekeys = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* auth_moremem - get some more free key structures
|
||||
*/
|
||||
void
|
||||
auth_moremem(
|
||||
int keycount
|
||||
)
|
||||
{
|
||||
symkey * sk;
|
||||
int i;
|
||||
#ifdef NTP_DEBUG
|
||||
void * base;
|
||||
symkey_alloc * allocrec;
|
||||
# define MOREMEM_EXTRA_ALLOC (sizeof(*allocrec))
|
||||
#else
|
||||
# define MOREMEM_EXTRA_ALLOC (0)
|
||||
#endif
|
||||
|
||||
i = (keycount > 0)
|
||||
? keycount
|
||||
: MEMINC;
|
||||
sk = eallocarrayxz(i, sizeof(*sk), MOREMEM_EXTRA_ALLOC);
|
||||
#ifdef NTP_DEBUG
|
||||
base = sk;
|
||||
#endif
|
||||
authnumfreekeys += i;
|
||||
|
||||
for (; i > 0; i--, sk++) {
|
||||
LINK_SLIST(authfreekeys, sk, llink.f);
|
||||
}
|
||||
|
||||
#ifdef NTP_DEBUG
|
||||
allocrec = (void *)sk;
|
||||
allocrec->mem = base;
|
||||
LINK_SLIST(authallocs, allocrec, link);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* auth_prealloc_symkeys
|
||||
*/
|
||||
void
|
||||
auth_prealloc_symkeys(
|
||||
int keycount
|
||||
)
|
||||
{
|
||||
int allocated;
|
||||
int additional;
|
||||
|
||||
allocated = authnumkeys + authnumfreekeys;
|
||||
additional = keycount - allocated;
|
||||
if (additional > 0)
|
||||
auth_moremem(additional);
|
||||
auth_resize_hashtable();
|
||||
}
|
||||
|
||||
|
||||
static u_short
|
||||
auth_log2(size_t x)
|
||||
{
|
||||
/*
|
||||
** bithack to calculate floor(log2(x))
|
||||
**
|
||||
** This assumes
|
||||
** - (sizeof(size_t) is a power of two
|
||||
** - CHAR_BITS is a power of two
|
||||
** - returning zero for arguments <= 0 is OK.
|
||||
**
|
||||
** Does only shifts, masks and sums in integer arithmetic in
|
||||
** log2(CHAR_BIT*sizeof(size_t)) steps. (that is, 5/6 steps for
|
||||
** 32bit/64bit size_t)
|
||||
*/
|
||||
int s;
|
||||
int r = 0;
|
||||
size_t m = ~(size_t)0;
|
||||
|
||||
for (s = sizeof(size_t) / 2 * CHAR_BIT; s != 0; s >>= 1) {
|
||||
m <<= s;
|
||||
if (x & m)
|
||||
r += s;
|
||||
else
|
||||
x <<= s;
|
||||
}
|
||||
return (u_short)r;
|
||||
}
|
||||
|
||||
int/*BOOL*/
|
||||
ipaddr_match_masked(const sockaddr_u *,const sockaddr_u *,
|
||||
unsigned int mbits);
|
||||
|
||||
static void
|
||||
authcache_flush_id(
|
||||
keyid_t id
|
||||
)
|
||||
{
|
||||
if (cache_keyid == id) {
|
||||
cache_keyid = 0;
|
||||
cache_type = 0;
|
||||
cache_flags = 0;
|
||||
cache_secret = NULL;
|
||||
cache_secretsize = 0;
|
||||
cache_keyacclist = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* auth_resize_hashtable
|
||||
*
|
||||
* Size hash table to average 4 or fewer entries per bucket initially,
|
||||
* within the bounds of at least 4 and no more than 15 bits for the hash
|
||||
* table index. Populate the hash table.
|
||||
*/
|
||||
static void
|
||||
auth_resize_hashtable(void)
|
||||
{
|
||||
u_long totalkeys;
|
||||
u_short hashbits;
|
||||
u_short hash;
|
||||
size_t newalloc;
|
||||
symkey * sk;
|
||||
|
||||
totalkeys = authnumkeys + authnumfreekeys;
|
||||
hashbits = auth_log2(totalkeys / 4) + 1;
|
||||
hashbits = max(4, hashbits);
|
||||
hashbits = min(15, hashbits);
|
||||
|
||||
authhashbuckets = 1 << hashbits;
|
||||
authhashmask = authhashbuckets - 1;
|
||||
newalloc = authhashbuckets * sizeof(key_hash[0]);
|
||||
|
||||
key_hash = erealloc(key_hash, newalloc);
|
||||
memset(key_hash, '\0', newalloc);
|
||||
|
||||
ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
|
||||
hash = KEYHASH(sk->keyid);
|
||||
LINK_SLIST(key_hash[hash], sk, hlink);
|
||||
ITER_DLIST_END()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* allocsymkey - common code to allocate and link in symkey
|
||||
*
|
||||
* secret must be allocated with a free-compatible allocator. It is
|
||||
* owned by the referring symkey structure, and will be free()d by
|
||||
* freesymkey().
|
||||
*/
|
||||
static void
|
||||
allocsymkey(
|
||||
keyid_t id,
|
||||
u_short flags,
|
||||
u_short type,
|
||||
u_long lifetime,
|
||||
size_t secretsize,
|
||||
u_char * secret,
|
||||
KeyAccT * ka
|
||||
)
|
||||
{
|
||||
symkey * sk;
|
||||
symkey ** bucket;
|
||||
|
||||
bucket = &key_hash[KEYHASH(id)];
|
||||
|
||||
|
||||
if (authnumfreekeys < 1)
|
||||
auth_moremem(-1);
|
||||
UNLINK_HEAD_SLIST(sk, authfreekeys, llink.f);
|
||||
DEBUG_ENSURE(sk != NULL);
|
||||
sk->keyid = id;
|
||||
sk->flags = flags;
|
||||
sk->type = type;
|
||||
sk->secretsize = secretsize;
|
||||
sk->secret = secret;
|
||||
sk->keyacclist = ka;
|
||||
sk->lifetime = lifetime;
|
||||
LINK_SLIST(*bucket, sk, hlink);
|
||||
LINK_TAIL_DLIST(key_listhead, sk, llink);
|
||||
authnumfreekeys--;
|
||||
authnumkeys++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* freesymkey - common code to remove a symkey and recycle its entry.
|
||||
*/
|
||||
static void
|
||||
freesymkey(
|
||||
symkey * sk
|
||||
)
|
||||
{
|
||||
symkey ** bucket;
|
||||
symkey * unlinked;
|
||||
|
||||
if (NULL == sk)
|
||||
return;
|
||||
|
||||
authcache_flush_id(sk->keyid);
|
||||
keyacc_all_free(sk->keyacclist);
|
||||
|
||||
bucket = &key_hash[KEYHASH(sk->keyid)];
|
||||
if (sk->secret != NULL) {
|
||||
memset(sk->secret, '\0', sk->secretsize);
|
||||
efree((void *)sk->secret);
|
||||
}
|
||||
UNLINK_SLIST(unlinked, *bucket, sk, hlink, symkey);
|
||||
DEBUG_ENSURE(sk == unlinked);
|
||||
UNLINK_DLIST(sk, llink);
|
||||
memset((char *)sk + offsetof(symkey, symkey_payload), '\0',
|
||||
sizeof(*sk) - offsetof(symkey, symkey_payload));
|
||||
LINK_SLIST(authfreekeys, sk, llink.f);
|
||||
authnumkeys--;
|
||||
authnumfreekeys++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* auth_findkey - find a key in the hash table
|
||||
*/
|
||||
struct savekey *
|
||||
auth_findkey(
|
||||
keyid_t id
|
||||
)
|
||||
{
|
||||
symkey * sk;
|
||||
|
||||
for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink)
|
||||
if (id == sk->keyid)
|
||||
return sk;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* auth_havekey - return TRUE if the key id is zero or known. The
|
||||
* key needs not to be trusted.
|
||||
*/
|
||||
int
|
||||
auth_havekey(
|
||||
keyid_t id
|
||||
)
|
||||
{
|
||||
return
|
||||
(0 == id) ||
|
||||
(cache_keyid == id) ||
|
||||
(NULL != auth_findkey(id));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* authhavekey - return TRUE and cache the key, if zero or both known
|
||||
* and trusted.
|
||||
*/
|
||||
int
|
||||
authhavekey(
|
||||
keyid_t id
|
||||
)
|
||||
{
|
||||
symkey * sk;
|
||||
|
||||
authkeylookups++;
|
||||
if (0 == id || cache_keyid == id)
|
||||
return !!(KEY_TRUSTED & cache_flags);
|
||||
|
||||
/*
|
||||
* Search the bin for the key. If not found, or found but the key
|
||||
* type is zero, somebody marked it trusted without specifying a
|
||||
* key or key type. In this case consider the key missing.
|
||||
*/
|
||||
authkeyuncached++;
|
||||
sk = auth_findkey(id);
|
||||
if ((sk == NULL) || (sk->type == 0)) {
|
||||
authkeynotfound++;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the key is not trusted, the key is not considered found.
|
||||
*/
|
||||
if ( ! (KEY_TRUSTED & sk->flags)) {
|
||||
authnokey++;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* The key is found and trusted. Initialize the key cache.
|
||||
*/
|
||||
cache_keyid = sk->keyid;
|
||||
cache_type = sk->type;
|
||||
cache_flags = sk->flags;
|
||||
cache_secret = sk->secret;
|
||||
cache_secretsize = sk->secretsize;
|
||||
cache_keyacclist = sk->keyacclist;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* authtrust - declare a key to be trusted/untrusted
|
||||
*/
|
||||
void
|
||||
authtrust(
|
||||
keyid_t id,
|
||||
u_long trust
|
||||
)
|
||||
{
|
||||
symkey * sk;
|
||||
u_long lifetime;
|
||||
|
||||
/*
|
||||
* Search bin for key; if it does not exist and is untrusted,
|
||||
* forget it.
|
||||
*/
|
||||
|
||||
sk = auth_findkey(id);
|
||||
if (!trust && sk == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* There are two conditions remaining. Either it does not
|
||||
* exist and is to be trusted or it does exist and is or is
|
||||
* not to be trusted.
|
||||
*/
|
||||
if (sk != NULL) {
|
||||
/*
|
||||
* Key exists. If it is to be trusted, say so and update
|
||||
* its lifetime. If no longer trusted, return it to the
|
||||
* free list. Flush the cache first to be sure there are
|
||||
* no discrepancies.
|
||||
*/
|
||||
authcache_flush_id(id);
|
||||
if (trust > 0) {
|
||||
sk->flags |= KEY_TRUSTED;
|
||||
if (trust > 1)
|
||||
sk->lifetime = current_time + trust;
|
||||
else
|
||||
sk->lifetime = 0;
|
||||
} else {
|
||||
freesymkey(sk);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* keyid is not present, but the is to be trusted. We allocate
|
||||
* a new key, but do not specify a key type or secret.
|
||||
*/
|
||||
if (trust > 1) {
|
||||
lifetime = current_time + trust;
|
||||
} else {
|
||||
lifetime = 0;
|
||||
}
|
||||
allocsymkey(id, KEY_TRUSTED, 0, lifetime, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* authistrusted - determine whether a key is trusted
|
||||
*/
|
||||
int
|
||||
authistrusted(
|
||||
keyid_t id
|
||||
)
|
||||
{
|
||||
symkey * sk;
|
||||
|
||||
if (id == cache_keyid)
|
||||
return !!(KEY_TRUSTED & cache_flags);
|
||||
|
||||
authkeyuncached++;
|
||||
sk = auth_findkey(id);
|
||||
if (sk == NULL || !(KEY_TRUSTED & sk->flags)) {
|
||||
authkeynotfound++;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* authistrustedip - determine if the IP is OK for the keyid
|
||||
*/
|
||||
int
|
||||
authistrustedip(
|
||||
keyid_t keyno,
|
||||
sockaddr_u * sau
|
||||
)
|
||||
{
|
||||
symkey * sk;
|
||||
|
||||
if (keyno == cache_keyid) {
|
||||
return (KEY_TRUSTED & cache_flags) &&
|
||||
keyacc_contains(cache_keyacclist, sau, TRUE);
|
||||
}
|
||||
|
||||
if (NULL != (sk = auth_findkey(keyno))) {
|
||||
authkeyuncached++;
|
||||
return (KEY_TRUSTED & sk->flags) &&
|
||||
keyacc_contains(sk->keyacclist, sau, TRUE);
|
||||
}
|
||||
|
||||
authkeynotfound++;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Note: There are two locations below where 'strncpy()' is used. While
|
||||
* this function is a hazard by itself, it's essential that it is used
|
||||
* here. Bug 1243 involved that the secret was filled with NUL bytes
|
||||
* after the first NUL encountered, and 'strlcpy()' simply does NOT have
|
||||
* this behaviour. So disabling the fix and reverting to the buggy
|
||||
* behaviour due to compatibility issues MUST also fill with NUL and
|
||||
* this needs 'strncpy'. Also, the secret is managed as a byte blob of a
|
||||
* given size, and eventually truncating it and replacing the last byte
|
||||
* with a NUL would be a bug.
|
||||
* perlinger@ntp.org 2015-10-10
|
||||
*/
|
||||
void
|
||||
MD5auth_setkey(
|
||||
keyid_t keyno,
|
||||
int keytype,
|
||||
const u_char *key,
|
||||
size_t secretsize,
|
||||
KeyAccT *ka
|
||||
)
|
||||
{
|
||||
symkey * sk;
|
||||
u_char * secret;
|
||||
|
||||
DEBUG_ENSURE(keytype <= USHRT_MAX);
|
||||
DEBUG_ENSURE(secretsize < 4 * 1024);
|
||||
/*
|
||||
* See if we already have the key. If so just stick in the
|
||||
* new value.
|
||||
*/
|
||||
sk = auth_findkey(keyno);
|
||||
if (sk != NULL && keyno == sk->keyid) {
|
||||
/* TALOS-CAN-0054: make sure we have a new buffer! */
|
||||
if (NULL != sk->secret) {
|
||||
memset(sk->secret, 0, sk->secretsize);
|
||||
efree(sk->secret);
|
||||
}
|
||||
sk->secret = emalloc(secretsize + 1);
|
||||
sk->type = (u_short)keytype;
|
||||
sk->secretsize = secretsize;
|
||||
/* make sure access lists don't leak here! */
|
||||
if (ka != sk->keyacclist) {
|
||||
keyacc_all_free(sk->keyacclist);
|
||||
sk->keyacclist = ka;
|
||||
}
|
||||
#ifndef DISABLE_BUG1243_FIX
|
||||
memcpy(sk->secret, key, secretsize);
|
||||
#else
|
||||
/* >MUST< use 'strncpy()' here! See above! */
|
||||
strncpy((char *)sk->secret, (const char *)key,
|
||||
secretsize);
|
||||
#endif
|
||||
authcache_flush_id(keyno);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Need to allocate new structure. Do it.
|
||||
*/
|
||||
secret = emalloc(secretsize + 1);
|
||||
#ifndef DISABLE_BUG1243_FIX
|
||||
memcpy(secret, key, secretsize);
|
||||
#else
|
||||
/* >MUST< use 'strncpy()' here! See above! */
|
||||
strncpy((char *)secret, (const char *)key, secretsize);
|
||||
#endif
|
||||
allocsymkey(keyno, 0, (u_short)keytype, 0,
|
||||
secretsize, secret, ka);
|
||||
#ifdef NTP_DEBUG
|
||||
if (debug >= 4) {
|
||||
size_t j;
|
||||
|
||||
printf("auth_setkey: key %d type %d len %d ", (int)keyno,
|
||||
keytype, (int)secretsize);
|
||||
for (j = 0; j < secretsize; j++) {
|
||||
printf("%02x", secret[j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* auth_delkeys - delete non-autokey untrusted keys, and clear all info
|
||||
* except the trusted bit of non-autokey trusted keys, in
|
||||
* preparation for rereading the keys file.
|
||||
*/
|
||||
void
|
||||
auth_delkeys(void)
|
||||
{
|
||||
symkey * sk;
|
||||
|
||||
ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
|
||||
if (sk->keyid > NTP_MAXKEY) { /* autokey */
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
efree(sk->secret);
|
||||
sk->secret = NULL; /* TALOS-CAN-0054 */
|
||||
}
|
||||
sk->keyacclist = keyacc_all_free(sk->keyacclist);
|
||||
sk->secretsize = 0;
|
||||
sk->lifetime = 0;
|
||||
} else {
|
||||
freesymkey(sk);
|
||||
}
|
||||
ITER_DLIST_END()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* auth_agekeys - delete keys whose lifetimes have expired
|
||||
*/
|
||||
void
|
||||
auth_agekeys(void)
|
||||
{
|
||||
symkey * sk;
|
||||
|
||||
ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
|
||||
if (sk->lifetime > 0 && current_time > sk->lifetime) {
|
||||
freesymkey(sk);
|
||||
authkeyexpired++;
|
||||
}
|
||||
ITER_DLIST_END()
|
||||
DPRINTF(1, ("auth_agekeys: at %lu keys %lu expired %lu\n",
|
||||
current_time, authnumkeys, authkeyexpired));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* authencrypt - generate message authenticator
|
||||
*
|
||||
* Returns length of authenticator field, zero if key not found.
|
||||
*/
|
||||
size_t
|
||||
authencrypt(
|
||||
keyid_t keyno,
|
||||
u_int32 * pkt,
|
||||
size_t length
|
||||
)
|
||||
{
|
||||
/*
|
||||
* A zero key identifier means the sender has not verified
|
||||
* the last message was correctly authenticated. The MAC
|
||||
* consists of a single word with value zero.
|
||||
*/
|
||||
authencryptions++;
|
||||
pkt[length / 4] = htonl(keyno);
|
||||
if (0 == keyno) {
|
||||
return 4;
|
||||
}
|
||||
if (!authhavekey(keyno)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return MD5authencrypt(cache_type,
|
||||
cache_secret, cache_secretsize,
|
||||
pkt, length);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* authdecrypt - verify message authenticator
|
||||
*
|
||||
* Returns TRUE if authenticator valid, FALSE if invalid or not found.
|
||||
*/
|
||||
int
|
||||
authdecrypt(
|
||||
keyid_t keyno,
|
||||
u_int32 * pkt,
|
||||
size_t length,
|
||||
size_t size
|
||||
)
|
||||
{
|
||||
/*
|
||||
* A zero key identifier means the sender has not verified
|
||||
* the last message was correctly authenticated. For our
|
||||
* purpose this is an invalid authenticator.
|
||||
*/
|
||||
authdecryptions++;
|
||||
if (0 == keyno || !authhavekey(keyno) || size < 4) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return MD5authdecrypt(cache_type,
|
||||
cache_secret, cache_secretsize,
|
||||
pkt, length, size);
|
||||
}
|
||||
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* authreadkeys.c - routines to support the reading of the key file
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*#include "ntpd.h"*/ /* Only for DPRINTF */
|
||||
/*#include "ntp_fp.h"*/
|
||||
#include "ntp.h"
|
||||
#include "ntp_syslog.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_keyacc.h"
|
||||
#include "ntp_mem.h"
|
||||
|
||||
|
||||
#ifdef OPENSSL
|
||||
#include "openssl/objects.h"
|
||||
#include "openssl/evp.h"
|
||||
#endif /* OPENSSL */
|
||||
|
||||
/* Forwards */
|
||||
static char *nexttok (char **);
|
||||
|
||||
/*
|
||||
* nexttok - basic internal tokenizing routine
|
||||
*/
|
||||
static char *
|
||||
nexttok(
|
||||
char **str
|
||||
)
|
||||
{
|
||||
register char *cp;
|
||||
char *starttok;
|
||||
|
||||
cp = *str;
|
||||
|
||||
/*
|
||||
* Space past white space
|
||||
*/
|
||||
while (*cp == ' ' || *cp == '\t')
|
||||
cp++;
|
||||
|
||||
/*
|
||||
* Save this and space to end of token
|
||||
*/
|
||||
starttok = cp;
|
||||
while (*cp != '\0' && *cp != '\n' && *cp != ' '
|
||||
&& *cp != '\t' && *cp != '#')
|
||||
cp++;
|
||||
|
||||
/*
|
||||
* If token length is zero return an error, else set end of
|
||||
* token to zero and return start.
|
||||
*/
|
||||
if (starttok == cp)
|
||||
return NULL;
|
||||
|
||||
if (*cp == ' ' || *cp == '\t')
|
||||
*cp++ = '\0';
|
||||
else
|
||||
*cp = '\0';
|
||||
|
||||
*str = cp;
|
||||
return starttok;
|
||||
}
|
||||
|
||||
|
||||
/* 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 u_int nerr_loglimit = 5u;
|
||||
static const u_int nerr_maxlimit = 15;
|
||||
|
||||
static void log_maybe(u_int*, const char*, ...) NTP_PRINTF(2, 3);
|
||||
|
||||
typedef struct keydata KeyDataT;
|
||||
struct keydata {
|
||||
KeyDataT *next; /* queue/stack link */
|
||||
KeyAccT *keyacclist; /* key access list */
|
||||
keyid_t keyid; /* stored key ID */
|
||||
u_short keytype; /* stored key type */
|
||||
u_short seclen; /* length of secret */
|
||||
u_char secbuf[1]; /* begin of secret (formal only)*/
|
||||
};
|
||||
|
||||
static void
|
||||
log_maybe(
|
||||
u_int *pnerr,
|
||||
const char *fmt ,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
if ((NULL == pnerr) || (++(*pnerr) <= nerr_loglimit)) {
|
||||
va_start(ap, fmt);
|
||||
mvsyslog(LOG_ERR, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
free_keydata(
|
||||
KeyDataT *node
|
||||
)
|
||||
{
|
||||
KeyAccT *kap;
|
||||
|
||||
if (node) {
|
||||
while (node->keyacclist) {
|
||||
kap = node->keyacclist;
|
||||
node->keyacclist = kap->next;
|
||||
efree(kap);
|
||||
}
|
||||
|
||||
/* purge secrets from memory before free()ing it */
|
||||
memset(node, 0, sizeof(*node) + node->seclen);
|
||||
efree(node);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* authreadkeys - (re)read keys from a file.
|
||||
*/
|
||||
int
|
||||
authreadkeys(
|
||||
const char *file
|
||||
)
|
||||
{
|
||||
FILE *fp;
|
||||
char *line;
|
||||
char *token;
|
||||
keyid_t keyno;
|
||||
int keytype;
|
||||
char buf[512]; /* lots of room for line */
|
||||
u_char keystr[32]; /* Bug 2537 */
|
||||
size_t len;
|
||||
size_t j;
|
||||
u_int nerr;
|
||||
KeyDataT *list = NULL;
|
||||
KeyDataT *next = NULL;
|
||||
|
||||
/*
|
||||
* Open file. Complain and return if it can't be opened.
|
||||
*/
|
||||
fp = fopen(file, "r");
|
||||
if (fp == NULL) {
|
||||
msyslog(LOG_ERR, "authreadkeys: file '%s': %m",
|
||||
file);
|
||||
goto onerror;
|
||||
}
|
||||
INIT_SSL();
|
||||
|
||||
/*
|
||||
* Now read lines from the file, looking for key entries. Put
|
||||
* the data into temporary store for later propagation to avoid
|
||||
* two-pass processing.
|
||||
*/
|
||||
nerr = 0;
|
||||
while ((line = fgets(buf, sizeof buf, fp)) != NULL) {
|
||||
if (nerr > nerr_maxlimit)
|
||||
break;
|
||||
token = nexttok(&line);
|
||||
if (token == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* First is key number. See if it is okay.
|
||||
*/
|
||||
keyno = atoi(token);
|
||||
if (keyno < 1) {
|
||||
log_maybe(&nerr,
|
||||
"authreadkeys: cannot change key %s",
|
||||
token);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (keyno > NTP_MAXKEY) {
|
||||
log_maybe(&nerr,
|
||||
"authreadkeys: key %s > %d reserved for Autokey",
|
||||
token, NTP_MAXKEY);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Next is keytype. See if that is all right.
|
||||
*/
|
||||
token = nexttok(&line);
|
||||
if (token == NULL) {
|
||||
log_maybe(&nerr,
|
||||
"authreadkeys: no key type for key %d",
|
||||
(int)keyno);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We want to silently ignore keys where we do not
|
||||
* support the requested digest type. OTOH, we want to
|
||||
* make sure the file is well-formed. That means we
|
||||
* have to process the line completely and have to
|
||||
* finally throw away the result... This is a bit more
|
||||
* work, but it also results in better error detection.
|
||||
*/
|
||||
#ifdef OPENSSL
|
||||
/*
|
||||
* The key type is the NID used by the message digest
|
||||
* algorithm. There are a number of inconsistencies in
|
||||
* the OpenSSL database. We attempt to discover them
|
||||
* here and prevent use of inconsistent data later.
|
||||
*/
|
||||
keytype = keytype_from_text(token, NULL);
|
||||
if (keytype == 0) {
|
||||
log_maybe(NULL,
|
||||
"authreadkeys: invalid type for key %d",
|
||||
(int)keyno);
|
||||
# ifdef ENABLE_CMAC
|
||||
} else if (NID_cmac != keytype &&
|
||||
EVP_get_digestbynid(keytype) == NULL) {
|
||||
log_maybe(NULL,
|
||||
"authreadkeys: no algorithm for key %d",
|
||||
(int)keyno);
|
||||
keytype = 0;
|
||||
# endif /* ENABLE_CMAC */
|
||||
}
|
||||
#else /* !OPENSSL follows */
|
||||
/*
|
||||
* The key type is unused, but is required to be 'M' or
|
||||
* 'm' for compatibility.
|
||||
*/
|
||||
if (!(*token == 'M' || *token == 'm')) {
|
||||
log_maybe(NULL,
|
||||
"authreadkeys: invalid type for key %d",
|
||||
(int)keyno);
|
||||
keytype = 0;
|
||||
} else {
|
||||
keytype = KEY_TYPE_MD5;
|
||||
}
|
||||
#endif /* !OPENSSL */
|
||||
|
||||
/*
|
||||
* Finally, get key and insert it. If it is longer than 20
|
||||
* characters, it is a binary string encoded in hex;
|
||||
* otherwise, it is a text string of printable ASCII
|
||||
* characters.
|
||||
*/
|
||||
token = nexttok(&line);
|
||||
if (token == NULL) {
|
||||
log_maybe(&nerr,
|
||||
"authreadkeys: no key for key %d", (int)keyno);
|
||||
continue;
|
||||
}
|
||||
next = NULL;
|
||||
len = strlen(token);
|
||||
if (len <= 20) { /* Bug 2537 */
|
||||
next = emalloc(sizeof(KeyDataT) + len);
|
||||
next->keyacclist = NULL;
|
||||
next->keyid = keyno;
|
||||
next->keytype = keytype;
|
||||
next->seclen = len;
|
||||
memcpy(next->secbuf, token, len);
|
||||
} else {
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
u_char temp;
|
||||
char *ptr;
|
||||
size_t jlim;
|
||||
|
||||
jlim = min(len, 2 * sizeof(keystr));
|
||||
for (j = 0; j < jlim; j++) {
|
||||
ptr = strchr(hex, tolower((unsigned char)token[j]));
|
||||
if (ptr == NULL)
|
||||
break; /* abort decoding */
|
||||
temp = (u_char)(ptr - hex);
|
||||
if (j & 1)
|
||||
keystr[j / 2] |= temp;
|
||||
else
|
||||
keystr[j / 2] = temp << 4;
|
||||
}
|
||||
if (j < jlim) {
|
||||
log_maybe(&nerr,
|
||||
"authreadkeys: invalid hex digit for key %d",
|
||||
(int)keyno);
|
||||
continue;
|
||||
}
|
||||
len = jlim/2; /* hmmmm.... what about odd length?!? */
|
||||
next = emalloc(sizeof(KeyDataT) + len);
|
||||
next->keyacclist = NULL;
|
||||
next->keyid = keyno;
|
||||
next->keytype = keytype;
|
||||
next->seclen = len;
|
||||
memcpy(next->secbuf, keystr, len);
|
||||
}
|
||||
|
||||
token = nexttok(&line);
|
||||
if (token != NULL) { /* A comma-separated IP access list */
|
||||
char *tp = token;
|
||||
|
||||
while (tp) {
|
||||
char *i;
|
||||
char *snp; /* subnet text pointer */
|
||||
unsigned int snbits;
|
||||
sockaddr_u addr;
|
||||
|
||||
i = strchr(tp, (int)',');
|
||||
if (i) {
|
||||
*i = '\0';
|
||||
}
|
||||
snp = strchr(tp, (int)'/');
|
||||
if (snp) {
|
||||
char *sp;
|
||||
|
||||
*snp++ = '\0';
|
||||
snbits = 0;
|
||||
sp = snp;
|
||||
|
||||
while (*sp != '\0') {
|
||||
if (!isdigit((unsigned char)*sp))
|
||||
break;
|
||||
if (snbits > 1000)
|
||||
break; /* overflow */
|
||||
snbits = 10 * snbits + (*sp++ - '0'); /* ascii dependent */
|
||||
}
|
||||
if (*sp != '\0') {
|
||||
log_maybe(&nerr,
|
||||
"authreadkeys: Invalid character in subnet specification for <%s/%s> in key %d",
|
||||
sp, snp, keyno);
|
||||
goto nextip;
|
||||
}
|
||||
} else {
|
||||
snbits = UINT_MAX;
|
||||
}
|
||||
|
||||
if (is_ip_address(tp, AF_UNSPEC, &addr)) {
|
||||
/* Make sure that snbits is valid for addr */
|
||||
if ((snbits < UINT_MAX) &&
|
||||
( (IS_IPV4(&addr) && snbits > 32) ||
|
||||
(IS_IPV6(&addr) && snbits > 128))) {
|
||||
log_maybe(NULL,
|
||||
"authreadkeys: excessive subnet mask <%s/%s> for key %d",
|
||||
tp, snp, keyno);
|
||||
}
|
||||
next->keyacclist = keyacc_new_push(
|
||||
next->keyacclist, &addr, snbits);
|
||||
} else {
|
||||
log_maybe(&nerr,
|
||||
"authreadkeys: invalid IP address <%s> for key %d",
|
||||
tp, keyno);
|
||||
}
|
||||
|
||||
nextip:
|
||||
if (i) {
|
||||
tp = i + 1;
|
||||
} else {
|
||||
tp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check if this has to be weeded out... */
|
||||
if (0 == keytype) {
|
||||
free_keydata(next);
|
||||
next = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
INSIST(NULL != next);
|
||||
next->next = list;
|
||||
list = next;
|
||||
}
|
||||
fclose(fp);
|
||||
if (nerr > 0) {
|
||||
const char * why = "";
|
||||
if (nerr > nerr_maxlimit)
|
||||
why = " (emergency break)";
|
||||
msyslog(LOG_ERR,
|
||||
"authreadkeys: rejecting file '%s' after %u error(s)%s",
|
||||
file, nerr, why);
|
||||
goto onerror;
|
||||
}
|
||||
|
||||
/* first remove old file-based keys */
|
||||
auth_delkeys();
|
||||
/* insert the new key material */
|
||||
while (NULL != (next = list)) {
|
||||
list = next->next;
|
||||
MD5auth_setkey(next->keyid, next->keytype,
|
||||
next->secbuf, next->seclen, next->keyacclist);
|
||||
next->keyacclist = NULL; /* consumed by MD5auth_setkey */
|
||||
free_keydata(next);
|
||||
}
|
||||
return (1);
|
||||
|
||||
onerror:
|
||||
/* Mop up temporary storage before bailing out. */
|
||||
while (NULL != (next = list)) {
|
||||
list = next->next;
|
||||
free_keydata(next);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* authusekey - decode a key from ascii and use it
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ntp_types.h"
|
||||
#include "ntp_string.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
/*
|
||||
* Types of ascii representations for keys. "Standard" means a 64 bit
|
||||
* hex number in NBS format, i.e. with the low order bit of each byte
|
||||
* a parity bit. "NTP" means a 64 bit key in NTP format, with the
|
||||
* high order bit of each byte a parity bit. "Ascii" means a 1-to-8
|
||||
* character string whose ascii representation is used as the key.
|
||||
*/
|
||||
int
|
||||
authusekey(
|
||||
keyid_t keyno,
|
||||
int keytype,
|
||||
const u_char *str
|
||||
)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = strlen((const char *)str);
|
||||
if (0 == len)
|
||||
return 0;
|
||||
|
||||
MD5auth_setkey(keyno, keytype, str, len, NULL);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* buftvtots - pull a Unix-format (struct timeval) time stamp out of
|
||||
* an octet stream and convert it to a l_fp time stamp.
|
||||
* This is useful when using the clock line discipline.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "ipntp_config.h"
|
||||
#endif
|
||||
#include "ntp_fp.h"
|
||||
#include "ntp_string.h"
|
||||
#include "timevalops.h"
|
||||
|
||||
#ifndef SYS_WINNT
|
||||
int
|
||||
buftvtots(
|
||||
const char *bufp,
|
||||
l_fp *ts
|
||||
)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
/*
|
||||
* copy to adhere to alignment restrictions
|
||||
*/
|
||||
memcpy(&tv, bufp, sizeof(tv));
|
||||
|
||||
/*
|
||||
* and use it
|
||||
*/
|
||||
if (tv.tv_usec > MICROSECONDS - 1)
|
||||
return FALSE;
|
||||
|
||||
*ts = tval_stamp_to_lfp(tv);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif /* !SYS_WINNT */
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* caljulian - determine the Julian date from an NTP time.
|
||||
*
|
||||
* (Note: since we use the GREGORIAN calendar, this should be renamed to
|
||||
* 'calgregorian' eventually...)
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "ntp_types.h"
|
||||
#include "ntp_calendar.h"
|
||||
|
||||
#if !(defined(ISC_CHECK_ALL) || defined(ISC_CHECK_NONE) || \
|
||||
defined(ISC_CHECK_ENSURE) || defined(ISC_CHECK_INSIST) || \
|
||||
defined(ISC_CHECK_INVARIANT))
|
||||
# define ISC_CHECK_ALL
|
||||
#endif
|
||||
|
||||
#include "ntp_assert.h"
|
||||
|
||||
void
|
||||
caljulian(
|
||||
uint32_t ntp,
|
||||
struct calendar * jt
|
||||
)
|
||||
{
|
||||
vint64 vlong;
|
||||
ntpcal_split split;
|
||||
|
||||
|
||||
INSIST(NULL != jt);
|
||||
|
||||
/*
|
||||
* Unfold ntp time around current time into NTP domain. Split
|
||||
* into days and seconds, shift days into CE domain and
|
||||
* process the parts.
|
||||
*/
|
||||
vlong = ntpcal_ntp_to_ntp(ntp, NULL);
|
||||
split = ntpcal_daysplit(&vlong);
|
||||
ntpcal_daysplit_to_date(jt, &split, DAY_NTP_STARTS);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* caltontp - convert a date to an NTP time
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "ntp_types.h"
|
||||
#include "ntp_calendar.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_assert.h"
|
||||
#include "ntp_unixtime.h"
|
||||
|
||||
/*
|
||||
* Juergen Perlinger, 2008-11-12
|
||||
* Add support for full calendar calculatios. If the day-of-year is provided
|
||||
* (that is, not zero) it will be used instead of month and day-of-month;
|
||||
* otherwise a full turn through the calendar calculations will be taken.
|
||||
*
|
||||
* I know that Harlan Stenn likes to see assertions in production code, and I
|
||||
* agree there, but it would be a tricky thing here. The algorithm is quite
|
||||
* capable of producing sensible answers even to seemingly weird inputs: the
|
||||
* date <any year here>-03-00, the 0.th March of the year, will be automtically
|
||||
* treated as the last day of February, no matter whether the year is a leap
|
||||
* year or not. So adding constraints is merely for the benefit of the callers,
|
||||
* because the only thing we can check for consistency is our input, produced
|
||||
* by somebody else.
|
||||
*
|
||||
* BTW: A total roundtrip using 'caljulian' would be a quite shaky thing:
|
||||
* Because of the truncation of the NTP time stamp to 32 bits and the epoch
|
||||
* unfolding around the current time done by 'caljulian' the roundtrip does
|
||||
* *not* necessarily reproduce the input, especially if the time spec is more
|
||||
* than 68 years off from the current time...
|
||||
*/
|
||||
|
||||
uint32_t
|
||||
caltontp(
|
||||
const struct calendar *jt
|
||||
)
|
||||
{
|
||||
int32_t eraday; /* CE Rata Die number */
|
||||
vint64 ntptime;/* resulting NTP time */
|
||||
|
||||
REQUIRE(jt != NULL);
|
||||
|
||||
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
|
||||
* number. If yearday is not zero, assume that it contains a
|
||||
* useable value and avoid all calculations involving month
|
||||
* and day-of-month. Do a full evaluation otherwise.
|
||||
*/
|
||||
if (jt->yearday)
|
||||
eraday = ntpcal_year_to_ystart(jt->year)
|
||||
+ jt->yearday - 1;
|
||||
else
|
||||
eraday = ntpcal_date_to_rd(jt);
|
||||
|
||||
ntptime = ntpcal_dayjoin(eraday - DAY_NTP_STARTS,
|
||||
ntpcal_etime_to_seconds(jt->hour, jt->minute,
|
||||
jt->second));
|
||||
return ntptime.d_s.lo;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* calyearstart - determine the NTP time at midnight of January 1 in
|
||||
* the year of the given date.
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "ntp_types.h"
|
||||
#include "ntp_calendar.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_assert.h"
|
||||
|
||||
/*
|
||||
* Juergen Perlinger, 2010-05-02
|
||||
*
|
||||
* Redone in terms of the calendar functions. It's rather simple:
|
||||
* - expand the NTP time stamp
|
||||
* - split into days and seconds since midnight, dropping the partial day
|
||||
* - get full number of days before year start in NTP epoch
|
||||
* - convert to seconds, truncated to 32 bits.
|
||||
*/
|
||||
u_int32
|
||||
calyearstart(u_int32 ntptime, const time_t *pivot)
|
||||
{
|
||||
u_int32 ndays; /* elapsed days since NTP starts */
|
||||
vint64 vlong;
|
||||
ntpcal_split split;
|
||||
|
||||
vlong = ntpcal_ntp_to_ntp(ntptime, pivot);
|
||||
split = ntpcal_daysplit(&vlong);
|
||||
ndays = ntpcal_rd_to_ystart(split.hi + DAY_NTP_STARTS)
|
||||
- DAY_NTP_STARTS;
|
||||
|
||||
return (u_int32)(ndays * SECSPERDAY);
|
||||
}
|
||||
|
||||
/*
|
||||
* calmonthstart - get NTP time at midnight of the first day of the
|
||||
* current month.
|
||||
*/
|
||||
u_int32
|
||||
calmonthstart(u_int32 ntptime, const time_t *pivot)
|
||||
{
|
||||
u_int32 ndays; /* elapsed days since NTP starts */
|
||||
vint64 vlong;
|
||||
ntpcal_split split;
|
||||
|
||||
vlong = ntpcal_ntp_to_ntp(ntptime, pivot);
|
||||
split = ntpcal_daysplit(&vlong);
|
||||
ndays = ntpcal_rd_to_mstart(split.hi + DAY_NTP_STARTS)
|
||||
- DAY_NTP_STARTS;
|
||||
|
||||
return (u_int32)(ndays * SECSPERDAY);
|
||||
}
|
||||
|
||||
/*
|
||||
* calweekstart - get NTP time at midnight of the last Monday on or
|
||||
* before the current date.
|
||||
*/
|
||||
u_int32
|
||||
calweekstart(u_int32 ntptime, const time_t *pivot)
|
||||
{
|
||||
u_int32 ndays; /* elapsed days since NTP starts */
|
||||
vint64 vlong;
|
||||
ntpcal_split split;
|
||||
|
||||
vlong = ntpcal_ntp_to_ntp(ntptime, pivot);
|
||||
split = ntpcal_daysplit(&vlong);
|
||||
ndays = ntpcal_weekday_le(split.hi + DAY_NTP_STARTS, CAL_MONDAY)
|
||||
- DAY_NTP_STARTS;
|
||||
|
||||
return (u_int32)(ndays * SECSPERDAY);
|
||||
}
|
||||
|
||||
/*
|
||||
* caldaystart - get NTP time at midnight of the current day.
|
||||
*/
|
||||
u_int32
|
||||
caldaystart(u_int32 ntptime, const time_t *pivot)
|
||||
{
|
||||
vint64 vlong;
|
||||
ntpcal_split split;
|
||||
|
||||
vlong = ntpcal_ntp_to_ntp(ntptime, pivot);
|
||||
split = ntpcal_daysplit(&vlong);
|
||||
|
||||
return ntptime - split.lo;
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* clocktime - compute the NTP date from a day of year, hour, minute
|
||||
* and second.
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include "ntp_fp.h"
|
||||
#include "ntp_unixtime.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_calendar.h"
|
||||
|
||||
/*
|
||||
* We check that the time be within CLOSETIME seconds of the receive
|
||||
* time stamp. This is about 4 hours, which hopefully should be wide
|
||||
* enough to collect most data, while close enough to keep things from
|
||||
* getting confused.
|
||||
*/
|
||||
#define CLOSETIME (4u*60u*60u)
|
||||
|
||||
/*
|
||||
* Since we try to match years, the result of a full search will not
|
||||
* change when we are already less than a half year from the receive
|
||||
* time stamp. Since the length of a year is variable we use a
|
||||
* slightly narrower limit; this might require a full evaluation near
|
||||
* the edge, but will make sure we always get the correct result.
|
||||
*/
|
||||
#define NEARTIME (182u * SECSPERDAY)
|
||||
|
||||
/*
|
||||
* local calendar helpers
|
||||
*/
|
||||
static int32 ntp_to_year(u_int32);
|
||||
static u_int32 year_to_ntp(int32);
|
||||
|
||||
/*
|
||||
* Take a time spec given as day-of-year, hour, minute and second as
|
||||
* well as a GMT offset in hours and convert it to a NTP time stamp in
|
||||
* '*ts_ui'. The value will be in the range (rec_ui-0.5yrs) to
|
||||
* (rec_ui+0.5yrs). A hint for the current start-of-year will be
|
||||
* read from '*yearstart'.
|
||||
*
|
||||
* On return '*ts_ui' will always the best matching solution, and
|
||||
* '*yearstart' will receive the associated start-of-year.
|
||||
*
|
||||
* The function will tell if the result in 'ts_ui' is in CLOSETIME
|
||||
* (+/-4hrs) around the receive time by returning a non-zero value.
|
||||
*
|
||||
* Note: The function puts no constraints on the value ranges for the
|
||||
* time specification, but evaluates the effective seconds in
|
||||
* 32-bit arithmetic.
|
||||
*/
|
||||
int
|
||||
clocktime(
|
||||
int yday , /* day-of-year */
|
||||
int hour , /* hour of day */
|
||||
int minute , /* minute of hour */
|
||||
int second , /* second of minute */
|
||||
int tzoff , /* hours west of GMT */
|
||||
u_int32 rec_ui , /* pivot value */
|
||||
u_long *yearstart, /* cached start-of-year, should be fixed to u_int32 */
|
||||
u_int32 *ts_ui ) /* effective time stamp */
|
||||
{
|
||||
u_int32 ystt[3]; /* year start */
|
||||
u_int32 test[3]; /* result time stamp */
|
||||
u_int32 diff[3]; /* abs difference to receive */
|
||||
int32 y, tmp, idx, min;
|
||||
|
||||
/*
|
||||
* Compute the offset into the year in seconds. Note that
|
||||
* this could come out to be a negative number.
|
||||
*/
|
||||
tmp = ((int32)second +
|
||||
SECSPERMIN * ((int32)minute +
|
||||
MINSPERHR * ((int32)hour + (int32)tzoff +
|
||||
HRSPERDAY * ((int32)yday - 1))));
|
||||
/*
|
||||
* Based on the cached year start, do a first attempt. Be
|
||||
* happy and return if this gets us better than NEARTIME to
|
||||
* the receive time stamp. Do this only if the cached year
|
||||
* start is not zero, which will not happen after 1900 for the
|
||||
* next few thousand years.
|
||||
*/
|
||||
if (*yearstart) {
|
||||
/* -- get time stamp of potential solution */
|
||||
test[0] = (u_int32)(*yearstart) + tmp;
|
||||
/* -- calc absolute difference to receive time */
|
||||
diff[0] = test[0] - rec_ui;
|
||||
if (diff[0] >= 0x80000000u)
|
||||
diff[0] = ~diff[0] + 1;
|
||||
/* -- can't get closer if diff < NEARTIME */
|
||||
if (diff[0] < NEARTIME) {
|
||||
*ts_ui = test[0];
|
||||
return diff[0] < CLOSETIME;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now the dance begins. Based on the receive time stamp and
|
||||
* the seconds offset in 'tmp', we make an educated guess
|
||||
* about the year to start with. This takes us on the spot
|
||||
* with a fuzz of +/-1 year.
|
||||
*
|
||||
* We calculate the effective timestamps for the three years
|
||||
* around the guess and select the entry with the minimum
|
||||
* absolute difference to the receive time stamp.
|
||||
*/
|
||||
y = ntp_to_year(rec_ui - tmp);
|
||||
for (idx = 0; idx < 3; idx++) {
|
||||
/* -- get year start of potential solution */
|
||||
ystt[idx] = year_to_ntp(y + idx - 1);
|
||||
/* -- get time stamp of potential solution */
|
||||
test[idx] = ystt[idx] + tmp;
|
||||
/* -- calc absolute difference to receive time */
|
||||
diff[idx] = test[idx] - rec_ui;
|
||||
if (diff[idx] >= 0x80000000u)
|
||||
diff[idx] = ~diff[idx] + 1;
|
||||
}
|
||||
/* -*- assume current year fits best, then search best fit */
|
||||
for (min = 1, idx = 0; idx < 3; idx++)
|
||||
if (diff[idx] < diff[min])
|
||||
min = idx;
|
||||
/* -*- store results and update year start */
|
||||
*ts_ui = test[min];
|
||||
*yearstart = ystt[min];
|
||||
|
||||
/* -*- tell if we could get into CLOSETIME*/
|
||||
return diff[min] < CLOSETIME;
|
||||
}
|
||||
|
||||
static int32
|
||||
ntp_to_year(
|
||||
u_int32 ntp)
|
||||
{
|
||||
vint64 t;
|
||||
ntpcal_split s;
|
||||
|
||||
t = ntpcal_ntp_to_ntp(ntp, NULL);
|
||||
s = ntpcal_daysplit(&t);
|
||||
s = ntpcal_split_eradays(s.hi + DAY_NTP_STARTS - 1, NULL);
|
||||
return s.hi + 1;
|
||||
}
|
||||
|
||||
static u_int32
|
||||
year_to_ntp(
|
||||
int32 year)
|
||||
{
|
||||
u_int32 days;
|
||||
days = ntpcal_days_in_years(year-1) - DAY_NTP_STARTS + 1;
|
||||
return days * SECSPERDAY;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Data for pretty printing clock types
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "ntp.h"
|
||||
#include "lib_strbuf.h"
|
||||
#include "ntp_refclock.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
struct clktype clktypes[] = {
|
||||
{ REFCLK_NONE, "unspecified type (0)",
|
||||
"UNKNOWN" },
|
||||
{ REFCLK_LOCALCLOCK, "Undisciplined local clock (1)",
|
||||
"LOCAL" },
|
||||
{ REFCLK_GPS_TRAK, "TRAK 8810 GPS Receiver (2)",
|
||||
"GPS_TRAK" },
|
||||
{ REFCLK_WWV_PST, "PSTI/Traconex WWV/WWVH Receiver (3)",
|
||||
"WWV_PST" },
|
||||
{ REFCLK_SPECTRACOM, "Spectracom (generic) Receivers (4)",
|
||||
"SPECTRACOM" },
|
||||
{ REFCLK_TRUETIME, "TrueTime (generic) Receivers (5)",
|
||||
"TRUETIME" },
|
||||
{ REFCLK_IRIG_AUDIO, "IRIG Audio Decoder (6)",
|
||||
"IRIG_AUDIO" },
|
||||
{ REFCLK_CHU_AUDIO, "CHU Audio Demodulator/Decoder (7)",
|
||||
"CHU_AUDIO" },
|
||||
{ REFCLK_PARSE, "Generic reference clock driver (8)",
|
||||
"GENERIC" },
|
||||
{ REFCLK_GPS_MX4200, "Magnavox MX4200 GPS Receiver (9)",
|
||||
"GPS_MX4200" },
|
||||
{ REFCLK_GPS_AS2201, "Austron 2201A GPS Receiver (10)",
|
||||
"GPS_AS2201" },
|
||||
{ REFCLK_GPS_ARBITER, "Arbiter 1088A/B GPS Receiver (11)",
|
||||
"GPS_ARBITER" },
|
||||
{ REFCLK_IRIG_TPRO, "KSI/Odetics TPRO/S IRIG Interface (12)",
|
||||
"IRIG_TPRO" },
|
||||
{ REFCLK_ATOM_LEITCH, "Leitch CSD 5300 Master Clock Controller (13)",
|
||||
"ATOM_LEITCH" },
|
||||
{ REFCLK_MSF_EES, "EES M201 MSF Receiver (14)",
|
||||
"MSF_EES" },
|
||||
{ REFCLK_NONE, "not used (15)",
|
||||
"NOT_USED" },
|
||||
{ REFCLK_IRIG_BANCOMM, "Bancomm GPS/IRIG Receiver (16)",
|
||||
"GPS_BANC" },
|
||||
{ REFCLK_GPS_DATUM, "Datum Precision Time System (17)",
|
||||
"GPS_DATUM" },
|
||||
{ REFCLK_ACTS, "Automated Computer Time Service (18)",
|
||||
"ACTS_MODEM" },
|
||||
{ REFCLK_WWV_HEATH, "Heath WWV/WWVH Receiver (19)",
|
||||
"WWV_HEATH" },
|
||||
{ REFCLK_GPS_NMEA, "Generic NMEA GPS Receiver (20)",
|
||||
"GPS_NMEA" },
|
||||
{ REFCLK_GPS_VME, "TrueTime GPS-VME Interface (21)",
|
||||
"GPS_VME" },
|
||||
{ REFCLK_ATOM_PPS, "PPS Clock Discipline (22)",
|
||||
"PPS" },
|
||||
{ REFCLK_NONE, "not used (23)",
|
||||
"NOT_USED" },
|
||||
{ REFCLK_NONE, "not used (24)",
|
||||
"NOT_USED" },
|
||||
{ REFCLK_NONE, "not used (25)",
|
||||
"NOT_USED" },
|
||||
{ REFCLK_GPS_HP, "HP 58503A GPS Time & Frequency Receiver (26)",
|
||||
"GPS_HP" },
|
||||
{ REFCLK_ARCRON_MSF, "ARCRON MSF (and DCF77) Receiver (27)",
|
||||
"MSF_ARCRON" },
|
||||
{ REFCLK_SHM, "Clock attached thru shared Memory (28)",
|
||||
"SHM" },
|
||||
{ REFCLK_PALISADE, "Trimble Navigation Palisade GPS (29)",
|
||||
"GPS_PALISADE" },
|
||||
{ REFCLK_ONCORE, "Motorola UT Oncore GPS (30)",
|
||||
"GPS_ONCORE" },
|
||||
{ REFCLK_GPS_JUPITER, "Rockwell Jupiter GPS (31)",
|
||||
"GPS_JUPITER" },
|
||||
{ REFCLK_CHRONOLOG, "Chrono-log K (32)",
|
||||
"CHRONOLOG" },
|
||||
{ REFCLK_DUMBCLOCK, "Dumb generic hh:mm:ss local clock (33)",
|
||||
"DUMBCLOCK" },
|
||||
{ REFCLK_ULINK, "Ultralink M320 WWVB receiver (34)",
|
||||
"ULINK_M320"},
|
||||
{ REFCLK_PCF, "Conrad parallel port radio clock (35)",
|
||||
"PCF"},
|
||||
{ REFCLK_WWV_AUDIO, "WWV/H Audio Demodulator/Decoder (36)",
|
||||
"WWV_AUDIO"},
|
||||
{ REFCLK_FG, "Forum Graphic GPS Dating Station (37)",
|
||||
"GPS_FG"},
|
||||
{ REFCLK_HOPF_SERIAL, "hopf Elektronic serial line receiver (38)",
|
||||
"HOPF_S"},
|
||||
{ REFCLK_HOPF_PCI, "hopf Elektronic PCI receiver (39)",
|
||||
"HOPF_P"},
|
||||
{ REFCLK_JJY, "JJY receiver (40)",
|
||||
"JJY"},
|
||||
{ REFCLK_TT560, "TrueTime 560 IRIG-B decoder (41)",
|
||||
"TT_IRIG"},
|
||||
{ REFCLK_ZYFER, "Zyfer GPStarplus receiver (42)",
|
||||
"GPS_ZYFER" },
|
||||
{ REFCLK_RIPENCC, "RIPE NCC Trimble driver (43)",
|
||||
"GPS_RIPENCC" },
|
||||
{ REFCLK_NEOCLOCK4X, "NeoClock4X DCF77 / TDF receiver (44)",
|
||||
"NEOCLK4X"},
|
||||
{ REFCLK_TSYNCPCI, "Spectracom TSYNC PCI timing board (45)",
|
||||
"PCI_TSYNC"},
|
||||
{ REFCLK_GPSDJSON, "GPSD JSON socket (46)",
|
||||
"GPSD_JSON"},
|
||||
{ -1, "", "" }
|
||||
};
|
||||
|
||||
const char *
|
||||
clockname(
|
||||
int num
|
||||
)
|
||||
{
|
||||
register struct clktype *clk;
|
||||
|
||||
for (clk = clktypes; clk->code != -1; clk++) {
|
||||
if (num == clk->code)
|
||||
return (clk->abbrev);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* decodenetnum - return a net number (this is crude, but careful)
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include "ntp.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
|
||||
/* If the given string position points to a decimal digit, parse the
|
||||
* number. If this is not possible, or the parsing did not consume the
|
||||
* whole string, or if the result exceeds the maximum value, return the
|
||||
* default value.
|
||||
*/
|
||||
static unsigned long
|
||||
_num_or_dflt(
|
||||
char * sval,
|
||||
unsigned long maxval,
|
||||
unsigned long defval
|
||||
)
|
||||
{
|
||||
char * ep;
|
||||
unsigned long num;
|
||||
|
||||
if (!(sval && isdigit(*(unsigned char*)sval)))
|
||||
return defval;
|
||||
|
||||
num = strtoul(sval, &ep, 10);
|
||||
if (!*ep && num <= maxval)
|
||||
return num;
|
||||
|
||||
return defval;
|
||||
}
|
||||
|
||||
/* If the given string position is not NULL and does not point to the
|
||||
* terminator, replace the character with NUL and advance the pointer.
|
||||
* Return the resulting position.
|
||||
*/
|
||||
static inline char*
|
||||
_chop(
|
||||
char * sp)
|
||||
{
|
||||
if (sp && *sp)
|
||||
*sp++ = '\0';
|
||||
return sp;
|
||||
}
|
||||
|
||||
/* If the given string position points to the given char, advance the
|
||||
* pointer and return the result. Otherwise, return NULL.
|
||||
*/
|
||||
static inline char*
|
||||
_skip(
|
||||
char * sp,
|
||||
int ch)
|
||||
{
|
||||
if (sp && *(unsigned char*)sp == ch)
|
||||
return (sp + 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* decodenetnum convert text IP address and port to sockaddr_u
|
||||
*
|
||||
* Returns FALSE (->0) for failure, TRUE (->1) for success.
|
||||
*/
|
||||
int
|
||||
decodenetnum(
|
||||
const char *num,
|
||||
sockaddr_u *net
|
||||
)
|
||||
{
|
||||
/* Building a parser is more fun in Haskell, but here we go...
|
||||
*
|
||||
* This works through 'inet_pton()' taking the brunt of the
|
||||
* work, after some string manipulations to split off URI
|
||||
* brackets, ports and scope identifiers. The heuristics are
|
||||
* simple but must hold for all _VALID_ addresses. inet_pton()
|
||||
* will croak on bad ones later, but replicating the whole
|
||||
* parser logic to detect errors is wasteful.
|
||||
*/
|
||||
|
||||
sockaddr_u netnum;
|
||||
char buf[64]; /* working copy of input */
|
||||
char *haddr=buf;
|
||||
unsigned int port=NTP_PORT, scope=0;
|
||||
unsigned short afam=AF_UNSPEC;
|
||||
|
||||
/* copy input to working buffer with length check */
|
||||
if (strlcpy(buf, num, sizeof(buf)) >= sizeof(buf))
|
||||
return FALSE;
|
||||
|
||||
/* Identify address family and possibly the port, if given. If
|
||||
* this results in AF_UNSPEC, we will fail in the next step.
|
||||
*/
|
||||
if (*haddr == '[') {
|
||||
char * endp = strchr(++haddr, ']');
|
||||
if (endp) {
|
||||
port = _num_or_dflt(_skip(_chop(endp), ':'),
|
||||
0xFFFFu, port);
|
||||
afam = strchr(haddr, ':') ? AF_INET6 : AF_INET;
|
||||
}
|
||||
} else {
|
||||
char *col = strchr(haddr, ':');
|
||||
char *dot = strchr(haddr, '.');
|
||||
if (col == dot) {
|
||||
/* no dot, no colon: bad! */
|
||||
afam = AF_UNSPEC;
|
||||
} else if (!col) {
|
||||
/* no colon, only dot: IPv4! */
|
||||
afam = AF_INET;
|
||||
} else if (!dot || col < dot) {
|
||||
/* no dot or 1st colon before 1st dot: IPv6! */
|
||||
afam = AF_INET6;
|
||||
} else {
|
||||
/* 1st dot before 1st colon: must be IPv4 with port */
|
||||
afam = AF_INET;
|
||||
port = _num_or_dflt(_chop(col), 0xFFFFu, port);
|
||||
}
|
||||
}
|
||||
|
||||
/* Since we don't know about additional members in the address
|
||||
* structures, we wipe the result buffer thoroughly:
|
||||
*/
|
||||
memset(&netnum, 0, sizeof(netnum));
|
||||
|
||||
/* For AF_INET6, evaluate and remove any scope suffix. Have
|
||||
* inet_pton() do the real work for AF_INET and AF_INET6, bail
|
||||
* out otherwise:
|
||||
*/
|
||||
switch (afam) {
|
||||
case AF_INET:
|
||||
if (inet_pton(afam, haddr, &netnum.sa4.sin_addr) <= 0)
|
||||
return FALSE;
|
||||
netnum.sa4.sin_port = htons((unsigned short)port);
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
scope = _num_or_dflt(_chop(strchr(haddr, '%')), 0xFFFFFFFFu, scope);
|
||||
if (inet_pton(afam, haddr, &netnum.sa6.sin6_addr) <= 0)
|
||||
return FALSE;
|
||||
netnum.sa6.sin6_port = htons((unsigned short)port);
|
||||
netnum.sa6.sin6_scope_id = scope;
|
||||
break;
|
||||
|
||||
case AF_UNSPEC:
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Collect the remaining pieces and feed the output, which was
|
||||
* not touched so far:
|
||||
*/
|
||||
netnum.sa.sa_family = afam;
|
||||
memcpy(net, &netnum, sizeof(netnum));
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* dofptoa - do the grunge work to convert an fp number to ascii
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "lib_strbuf.h"
|
||||
#include "ntp_string.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
char *
|
||||
dofptoa(
|
||||
u_fp fpv,
|
||||
char sign,
|
||||
short ndec,
|
||||
int msec
|
||||
)
|
||||
{
|
||||
register u_char *cp, *cpend;
|
||||
register u_long val;
|
||||
register short dec;
|
||||
u_char cbuf[12];
|
||||
u_char *cpdec;
|
||||
char *buf;
|
||||
char *bp;
|
||||
|
||||
/*
|
||||
* Get a string buffer before starting
|
||||
*/
|
||||
LIB_GETBUF(buf);
|
||||
|
||||
/*
|
||||
* Zero out the buffer
|
||||
*/
|
||||
ZERO(cbuf);
|
||||
|
||||
/*
|
||||
* Set the pointers to point at the first
|
||||
* decimal place. Get a local copy of the value.
|
||||
*/
|
||||
cp = cpend = &cbuf[5];
|
||||
val = fpv;
|
||||
|
||||
/*
|
||||
* If we have to, decode the integral part
|
||||
*/
|
||||
if (!(val & 0xffff0000))
|
||||
cp--;
|
||||
else {
|
||||
register u_short sv = (u_short)(val >> 16);
|
||||
register u_short tmp;
|
||||
register u_short ten = 10;
|
||||
|
||||
do {
|
||||
tmp = sv;
|
||||
sv = (u_short) (sv/ten);
|
||||
*(--cp) = (u_char)(tmp - ((sv<<3) + (sv<<1)));
|
||||
} while (sv != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out how much of the fraction to do
|
||||
*/
|
||||
if (msec) {
|
||||
dec = (short)(ndec + 3);
|
||||
if (dec < 3)
|
||||
dec = 3;
|
||||
cpdec = &cbuf[8];
|
||||
} else {
|
||||
dec = ndec;
|
||||
cpdec = cpend;
|
||||
}
|
||||
|
||||
if (dec > 6)
|
||||
dec = 6;
|
||||
|
||||
if (dec > 0) {
|
||||
do {
|
||||
val &= 0xffff;
|
||||
val = (val << 3) + (val << 1);
|
||||
*cpend++ = (u_char)(val >> 16);
|
||||
} while (--dec > 0);
|
||||
}
|
||||
|
||||
if (val & 0x8000) {
|
||||
register u_char *tp;
|
||||
/*
|
||||
* Round it. Ick.
|
||||
*/
|
||||
tp = cpend;
|
||||
--tp;
|
||||
*tp = (u_char)(*tp + 1);
|
||||
while (*tp >= 10) {
|
||||
*tp = 0;
|
||||
--tp;
|
||||
*tp = (u_char)(*tp + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove leading zeroes if necessary
|
||||
*/
|
||||
while (cp < (cpdec -1) && *cp == 0)
|
||||
cp++;
|
||||
|
||||
/*
|
||||
* Copy it into the buffer, asciizing as we go.
|
||||
*/
|
||||
bp = buf;
|
||||
if (sign)
|
||||
*bp++ = sign;
|
||||
|
||||
while (cp < cpend) {
|
||||
if (cp == cpdec)
|
||||
*bp++ = '.';
|
||||
*bp++ = (char)(*cp++ + '0');
|
||||
}
|
||||
*bp = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
fptoa(
|
||||
s_fp fpv,
|
||||
short ndec
|
||||
)
|
||||
{
|
||||
u_fp plusfp;
|
||||
int neg;
|
||||
|
||||
neg = (fpv < 0);
|
||||
if (neg) {
|
||||
plusfp = (u_fp)(-fpv);
|
||||
} else {
|
||||
plusfp = (u_fp)fpv;
|
||||
}
|
||||
|
||||
return dofptoa(plusfp, (neg?'-':0), ndec, FALSE);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
fptoms(
|
||||
s_fp fpv,
|
||||
short ndec
|
||||
)
|
||||
{
|
||||
u_fp plusfp;
|
||||
int neg;
|
||||
|
||||
neg = (fpv < 0);
|
||||
if (neg) {
|
||||
plusfp = (u_fp)(-fpv);
|
||||
} else {
|
||||
plusfp = (u_fp)fpv;
|
||||
}
|
||||
|
||||
return dofptoa(plusfp, (neg?'-':0), ndec, TRUE);
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* dolfptoa - do the grunge work of converting an l_fp number to decimal
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "lib_strbuf.h"
|
||||
#include "ntp_string.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
char *
|
||||
dolfptoa(
|
||||
u_int32 fpi,
|
||||
u_int32 fpv,
|
||||
char sign,
|
||||
short ndec,
|
||||
int msec
|
||||
)
|
||||
{
|
||||
u_char *cp, *cpend, *cpdec;
|
||||
int dec;
|
||||
u_char cbuf[24];
|
||||
char *buf, *bp;
|
||||
|
||||
/*
|
||||
* Get a string buffer before starting
|
||||
*/
|
||||
LIB_GETBUF(buf);
|
||||
|
||||
/*
|
||||
* Zero the character buffer
|
||||
*/
|
||||
ZERO(cbuf);
|
||||
|
||||
/*
|
||||
* Work on the integral part. This should work reasonable on
|
||||
* all machines with 32 bit arithmetic. Please note that 32 bits
|
||||
* can *always* be represented with at most 10 decimal digits,
|
||||
* including a possible rounding from the fractional part.
|
||||
*/
|
||||
cp = cpend = cpdec = &cbuf[10];
|
||||
for (dec = (int)(cp - cbuf); dec > 0 && fpi != 0; dec--) {
|
||||
/* can add another digit */
|
||||
u_int32 digit;
|
||||
|
||||
digit = fpi;
|
||||
fpi /= 10U;
|
||||
digit -= (fpi << 3) + (fpi << 1); /* i*10 */
|
||||
*--cp = (u_char)digit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Done that, now deal with the problem of the fraction. First
|
||||
* determine the number of decimal places.
|
||||
*/
|
||||
dec = ndec;
|
||||
if (dec < 0)
|
||||
dec = 0;
|
||||
if (msec) {
|
||||
dec += 3;
|
||||
cpdec += 3;
|
||||
}
|
||||
if ((size_t)dec > sizeof(cbuf) - (cpend - cbuf))
|
||||
dec = (int)(sizeof(cbuf) - (cpend - cbuf));
|
||||
|
||||
/*
|
||||
* If there's a fraction to deal with, do so.
|
||||
*/
|
||||
for (/*NOP*/; dec > 0 && fpv != 0; dec--) {
|
||||
u_int32 digit, tmph, tmpl;
|
||||
|
||||
/*
|
||||
* The scheme here is to multiply the fraction
|
||||
* (0.1234...) by ten. This moves a junk of BCD into
|
||||
* the units part. record that and iterate.
|
||||
* multiply by shift/add in two dwords.
|
||||
*/
|
||||
digit = 0;
|
||||
M_LSHIFT(digit, fpv);
|
||||
tmph = digit;
|
||||
tmpl = fpv;
|
||||
M_LSHIFT(digit, fpv);
|
||||
M_LSHIFT(digit, fpv);
|
||||
M_ADD(digit, fpv, tmph, tmpl);
|
||||
*cpend++ = (u_char)digit;
|
||||
}
|
||||
|
||||
/* decide whether to round or simply extend by zeros */
|
||||
if (dec > 0) {
|
||||
/* only '0' digits left -- just reposition end */
|
||||
cpend += dec;
|
||||
} else {
|
||||
/* some bits remain in 'fpv'; do round */
|
||||
u_char *tp = cpend;
|
||||
int carry = ((fpv & 0x80000000) != 0);
|
||||
|
||||
for (dec = (int)(tp - cbuf); carry && dec > 0; dec--) {
|
||||
--tp;
|
||||
*tp = (u_char)(*tp + 1);
|
||||
if (*tp == 10)
|
||||
*tp = 0;
|
||||
else
|
||||
carry = FALSE;
|
||||
}
|
||||
|
||||
if (tp < cp) /* rounding from 999 to 1000 or similiar? */
|
||||
cp = tp;
|
||||
}
|
||||
|
||||
/*
|
||||
* We've now got the fraction in cbuf[], with cp pointing at
|
||||
* the first character, cpend pointing past the last, and
|
||||
* cpdec pointing at the first character past the decimal.
|
||||
* Remove leading zeros, then format the number into the
|
||||
* buffer.
|
||||
*/
|
||||
while (cp < cpdec && *cp == 0)
|
||||
cp++;
|
||||
if (cp >= cpdec)
|
||||
cp = cpdec - 1;
|
||||
|
||||
bp = buf;
|
||||
if (sign)
|
||||
*bp++ = sign;
|
||||
while (cp < cpend) {
|
||||
if (cp == cpdec)
|
||||
*bp++ = '.';
|
||||
*bp++ = (char)(*cp++) + '0';
|
||||
}
|
||||
*bp = '\0';
|
||||
|
||||
/*
|
||||
* Done!
|
||||
*/
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
mfptoa(
|
||||
u_int32 fpi,
|
||||
u_int32 fpf,
|
||||
short ndec
|
||||
)
|
||||
{
|
||||
int isneg;
|
||||
|
||||
isneg = M_ISNEG(fpi);
|
||||
if (isneg) {
|
||||
M_NEG(fpi, fpf);
|
||||
}
|
||||
|
||||
return dolfptoa(fpi, fpf, (isneg?'-':'+'), ndec, FALSE);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
mfptoms(
|
||||
u_int32 fpi,
|
||||
u_int32 fpf,
|
||||
short ndec
|
||||
)
|
||||
{
|
||||
int isneg;
|
||||
|
||||
isneg = M_ISNEG(fpi);
|
||||
if (isneg) {
|
||||
M_NEG(fpi, fpf);
|
||||
}
|
||||
|
||||
return dolfptoa(fpi, fpf, (isneg?'-':'+'), ndec, TRUE);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* emalloc - return new memory obtained from the system. Belch if none.
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include "ntp_types.h"
|
||||
#include "ntp_malloc.h"
|
||||
#include "ntp_syslog.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
|
||||
extern void ipntp_exit_callback(Ip_pid_t pid);
|
||||
|
||||
#ifndef _WRS_CONFIG_LP64
|
||||
#define SIZE_MAX 0xFFFFFFFFU
|
||||
#else
|
||||
#define SIZE_MAX 0xFFFFFFFFFFFFFFFFULL
|
||||
#endif /* _WRS_CONFIG_LP64 */
|
||||
|
||||
|
||||
/*
|
||||
* When using the debug MS CRT allocator, each allocation stores the
|
||||
* callsite __FILE__ and __LINE__, which is then displayed at process
|
||||
* termination, to track down leaks. We don't want all of our
|
||||
* allocations to show up as coming from emalloc.c, so we preserve the
|
||||
* original callsite's source file and line using macros which pass
|
||||
* __FILE__ and __LINE__ as parameters to these routines.
|
||||
* Other debug malloc implementations can be used by defining
|
||||
* EREALLOC_IMPL() as ports/winnt/include/config.h does.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
void *
|
||||
ereallocz(
|
||||
void * ptr,
|
||||
size_t newsz,
|
||||
size_t priorsz,
|
||||
int zero_init
|
||||
#ifdef EREALLOC_CALLSITE /* ntp_malloc.h */
|
||||
,
|
||||
const char * file,
|
||||
int line
|
||||
#endif
|
||||
)
|
||||
{
|
||||
char * mem;
|
||||
size_t allocsz;
|
||||
|
||||
if (0 == newsz)
|
||||
allocsz = 1;
|
||||
else
|
||||
allocsz = newsz;
|
||||
|
||||
mem = EREALLOC_IMPL(ptr, allocsz, file, line);
|
||||
if (NULL == mem) {
|
||||
msyslog_term = TRUE;
|
||||
#ifndef EREALLOC_CALLSITE
|
||||
msyslog(LOG_ERR, "fatal out of memory (%lu bytes)",
|
||||
(u_long)newsz);
|
||||
#else
|
||||
msyslog(LOG_ERR,
|
||||
"fatal out of memory %s line %d (%lu bytes)",
|
||||
file, line, (u_long)newsz);
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (zero_init && newsz > priorsz)
|
||||
zero_mem(mem + priorsz, newsz - priorsz);
|
||||
|
||||
return mem;
|
||||
}
|
||||
#endif
|
||||
/* oreallocarray.c is licensed under the following:
|
||||
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
|
||||
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
|
||||
*/
|
||||
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
|
||||
|
||||
void *
|
||||
oreallocarrayxz(
|
||||
void *optr,
|
||||
size_t nmemb,
|
||||
size_t size,
|
||||
size_t extra
|
||||
#ifdef EREALLOC_CALLSITE /* ntp_malloc.h */
|
||||
,
|
||||
const char * file,
|
||||
int line
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
|
||||
nmemb > 0 && SIZE_MAX / nmemb < size) {
|
||||
#ifndef EREALLOC_CALLSITE
|
||||
msyslog(LOG_ERR, "fatal allocation size overflow");
|
||||
#else
|
||||
msyslog(LOG_ERR,
|
||||
"fatal allocation size overflow %s line %d",
|
||||
file, line);
|
||||
#endif
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
#ifndef EREALLOC_CALLSITE
|
||||
return ereallocz(optr, extra + (size * nmemb), 0, TRUE);
|
||||
#else
|
||||
return ereallocz(optr, extra + (size * nmemb), 0, TRUE, file, line);
|
||||
#endif
|
||||
}
|
||||
|
||||
char *
|
||||
estrdup_impl(
|
||||
const char * str
|
||||
#ifdef EREALLOC_CALLSITE
|
||||
,
|
||||
const char * file,
|
||||
int line
|
||||
#endif
|
||||
)
|
||||
{
|
||||
char * copy;
|
||||
size_t bytes;
|
||||
|
||||
bytes = strlen(str) + 1;
|
||||
copy = ereallocz(NULL, bytes, 0, FALSE
|
||||
#ifdef EREALLOC_CALLSITE
|
||||
, file, line
|
||||
#endif
|
||||
);
|
||||
memcpy(copy, str, bytes);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
#ifndef EREALLOC_CALLSITE
|
||||
void *
|
||||
emalloc(size_t newsz)
|
||||
{
|
||||
return ereallocz(NULL, newsz, 0, FALSE);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#ifdef NEED_HPUX_FINDCONFIG
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const char *
|
||||
FindConfig(
|
||||
const char *base
|
||||
)
|
||||
{
|
||||
static char result[BUFSIZ];
|
||||
char hostname[BUFSIZ], *cp;
|
||||
struct stat sbuf;
|
||||
struct utsname unamebuf;
|
||||
|
||||
/* All keyed by initial target being a directory */
|
||||
strlcpy(result, base, sizeof(result));
|
||||
if (stat(result, &sbuf) == 0) {
|
||||
if (S_ISDIR(sbuf.st_mode)) {
|
||||
|
||||
/* First choice is my hostname */
|
||||
if (gethostname(hostname, BUFSIZ) >= 0) {
|
||||
snprintf(result, sizeof(result), "%s/%s", base, hostname);
|
||||
if (stat(result, &sbuf) == 0) {
|
||||
goto outahere;
|
||||
} else {
|
||||
|
||||
/* Second choice is of form default.835 */
|
||||
(void) uname(&unamebuf);
|
||||
if (strncmp(unamebuf.machine, "9000/", 5) == 0)
|
||||
cp = unamebuf.machine + 5;
|
||||
else
|
||||
cp = unamebuf.machine;
|
||||
snprintf(result, sizeof(result), "%s/default.%s", base, cp);
|
||||
if (stat(result, &sbuf) == 0) {
|
||||
goto outahere;
|
||||
} else {
|
||||
|
||||
/* Last choice is just default */
|
||||
snprintf(result, sizeof(result), "%s/default", base);
|
||||
if (stat(result, &sbuf) == 0) {
|
||||
goto outahere;
|
||||
} else {
|
||||
strlcpy(result,
|
||||
"/not/found",
|
||||
sizeof(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
outahere:
|
||||
return(result);
|
||||
}
|
||||
#else
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
const char *
|
||||
FindConfig(
|
||||
const char *base
|
||||
)
|
||||
{
|
||||
return base;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* hextoint - convert an ascii string in hex to an unsigned
|
||||
* long, with error checking
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
int
|
||||
hextoint(
|
||||
const char *str,
|
||||
u_long *pu
|
||||
)
|
||||
{
|
||||
register u_long u;
|
||||
register const char *cp;
|
||||
|
||||
cp = str;
|
||||
|
||||
if (*cp == '\0')
|
||||
return 0;
|
||||
|
||||
u = 0;
|
||||
while (*cp != '\0') {
|
||||
if (!isxdigit((unsigned char)*cp))
|
||||
return 0;
|
||||
if (u & 0xF0000000)
|
||||
return 0; /* overflow */
|
||||
u <<= 4;
|
||||
if ('0' <= *cp && *cp <= '9')
|
||||
u += *cp++ - '0';
|
||||
else if ('a' <= *cp && *cp <= 'f')
|
||||
u += *cp++ - 'a' + 10;
|
||||
else if ('A' <= *cp && *cp <= 'F')
|
||||
u += *cp++ - 'A' + 10;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
*pu = u;
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* hextolfp - convert an ascii hex string to an l_fp number
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "ntp_string.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
int
|
||||
hextolfp(
|
||||
const char *str,
|
||||
l_fp *lfp
|
||||
)
|
||||
{
|
||||
register const char *cp;
|
||||
register const char *cpstart;
|
||||
register u_long dec_i;
|
||||
register u_long dec_f;
|
||||
char *ind = NULL;
|
||||
static const char *digits = "0123456789abcdefABCDEF";
|
||||
|
||||
dec_i = dec_f = 0;
|
||||
cp = str;
|
||||
|
||||
/*
|
||||
* We understand numbers of the form:
|
||||
*
|
||||
* [spaces]8_hex_digits[.]8_hex_digits[spaces|\n|\0]
|
||||
*/
|
||||
while (isspace((unsigned char)*cp))
|
||||
cp++;
|
||||
|
||||
cpstart = cp;
|
||||
while (*cp != '\0' && (cp - cpstart) < 8 &&
|
||||
(ind = strchr(digits, *cp)) != NULL) {
|
||||
dec_i = dec_i << 4; /* multiply by 16 */
|
||||
dec_i += ((ind - digits) > 15)
|
||||
? (u_long)(ind - digits - 6)
|
||||
: (u_long)(ind - digits);
|
||||
cp++;
|
||||
}
|
||||
|
||||
if ((cp - cpstart) < 8 || ind == NULL)
|
||||
return 0;
|
||||
if (*cp == '.')
|
||||
cp++;
|
||||
|
||||
cpstart = cp;
|
||||
while (*cp != '\0' && (cp - cpstart) < 8 &&
|
||||
(ind = strchr(digits, *cp)) != NULL) {
|
||||
dec_f = dec_f << 4; /* multiply by 16 */
|
||||
dec_f += ((ind - digits) > 15)
|
||||
? (u_long)(ind - digits - 6)
|
||||
: (u_long)(ind - digits);
|
||||
cp++;
|
||||
}
|
||||
|
||||
if ((cp - cpstart) < 8 || ind == NULL)
|
||||
return 0;
|
||||
|
||||
if (*cp != '\0' && !isspace((unsigned char)*cp))
|
||||
return 0;
|
||||
|
||||
lfp->l_ui = dec_i;
|
||||
lfp->l_uf = dec_f;
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* humandate.c - convert an NTP (or the current) time to something readable
|
||||
*/
|
||||
#include <ntp_config.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "ntp_unixtime.h" /* includes <sys/time.h> and <time.h> */
|
||||
#include "lib_strbuf.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
|
||||
/* This is used in msyslog.c; we don't want to clutter up the log with
|
||||
the year and day of the week, etc.; just the minimal date and time. */
|
||||
|
||||
const char *
|
||||
humanlogtime(void)
|
||||
{
|
||||
char * bp;
|
||||
time_t cursec;
|
||||
struct tm * tm;
|
||||
|
||||
cursec = time(NULL);
|
||||
tm = localtime(&cursec);
|
||||
if (!tm)
|
||||
return "-- --- --:--:--";
|
||||
|
||||
LIB_GETBUF(bp);
|
||||
|
||||
snprintf(bp, LIB_BUFLENGTH, "%2d %s %02d:%02d:%02d",
|
||||
tm->tm_mday, months[tm->tm_mon],
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
|
||||
return bp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* humantime() -- like humanlogtime() but without date, and with the
|
||||
* time to display given as an argument.
|
||||
*/
|
||||
const char *
|
||||
humantime(
|
||||
time_t cursec
|
||||
)
|
||||
{
|
||||
char * bp;
|
||||
struct tm * tm;
|
||||
|
||||
tm = localtime(&cursec);
|
||||
if (!tm)
|
||||
return "--:--:--";
|
||||
|
||||
LIB_GETBUF(bp);
|
||||
|
||||
snprintf(bp, LIB_BUFLENGTH, "%02d:%02d:%02d",
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
|
||||
return bp;
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Program to control ICOM radios
|
||||
*
|
||||
* This is a ripoff of the utility routines in the ICOM software
|
||||
* distribution. The only function provided is to load the radio
|
||||
* frequency. All other parameters must be manually set before use.
|
||||
*/
|
||||
#include <config.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>
|
||||
|
||||
|
||||
#ifdef SYS_WINNT
|
||||
#undef write /* ports/winnt/include/config.h: #define write _write */
|
||||
extern int async_write(int, const void *, unsigned int);
|
||||
#define write(fd, data, octets) async_write(fd, data, octets)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Packet routines
|
||||
*
|
||||
* These routines send a packet and receive the response. If an error
|
||||
* (collision) occurs on transmit, the packet is resent. If an error
|
||||
* occurs on receive (timeout), all input to the terminating FI is
|
||||
* discarded and the packet is resent. If the maximum number of retries
|
||||
* is not exceeded, the program returns the number of octets in the user
|
||||
* buffer; otherwise, it returns zero.
|
||||
*
|
||||
* ICOM frame format
|
||||
*
|
||||
* Frames begin with a two-octet preamble PR-PR followyd by the
|
||||
* transceiver address RE, controller address TX, control code CN, zero
|
||||
* or more data octets DA (depending on command), and terminator FI.
|
||||
* Since the bus is bidirectional, every octet output is echoed on
|
||||
* input. Every valid frame sent is answered with a frame in the same
|
||||
* format, but with the RE and TX fields interchanged. The CN field is
|
||||
* set to NAK if an error has occurred. Otherwise, the data are returned
|
||||
* in this and following DA octets. If no data are returned, the CN
|
||||
* octet is set to ACK.
|
||||
*
|
||||
* +------+------+------+------+------+--//--+------+
|
||||
* | PR | PR | RE | TX | CN | DA | FI |
|
||||
* +------+------+------+------+------+--//--+------+
|
||||
*/
|
||||
/*
|
||||
* Scraps
|
||||
*/
|
||||
#define DICOM /dev/icom/ /* ICOM port link */
|
||||
|
||||
/*
|
||||
* Local function prototypes
|
||||
*/
|
||||
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(
|
||||
int fd, /* file descriptor */
|
||||
int ident, /* ICOM radio identifier */
|
||||
double freq /* frequency (MHz) */
|
||||
)
|
||||
{
|
||||
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)
|
||||
temp = 4;
|
||||
else
|
||||
temp = 5;
|
||||
doublefreq(freq * 1e6, &cmd[6], temp);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* doublefreq(freq, y, len) - double to ICOM frequency with padding
|
||||
*/
|
||||
static void
|
||||
doublefreq( /* returns void */
|
||||
double freq, /* frequency */
|
||||
u_char *x, /* radio frequency */
|
||||
int len /* length (octets) */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
char s1[16];
|
||||
char *y;
|
||||
|
||||
snprintf(s1, sizeof(s1), " %10.0f", freq);
|
||||
y = s1 + 10;
|
||||
i = 0;
|
||||
while (*y != ' ') {
|
||||
x[i] = *y-- & 0x0f;
|
||||
x[i] = x[i] | ((*y-- & 0x0f) << 4);
|
||||
i++;
|
||||
}
|
||||
for ( ; i < len; i++)
|
||||
x[i] = 0;
|
||||
x[i] = FI;
|
||||
}
|
||||
|
||||
/*
|
||||
* icom_init() - open and initialize serial interface
|
||||
*
|
||||
* This routine opens the serial interface for raw transmission; that
|
||||
* is, character-at-a-time, no stripping, checking or monkeying with the
|
||||
* bits. For Unix, an input operation ends either with the receipt of a
|
||||
* character or a 0.5-s timeout.
|
||||
*/
|
||||
int
|
||||
icom_init(
|
||||
const char *device, /* device name/link */
|
||||
int speed, /* line speed */
|
||||
int trace /* trace flags */ )
|
||||
{
|
||||
TTY ttyb;
|
||||
int fd;
|
||||
int rc;
|
||||
int saved_errno;
|
||||
|
||||
fd = tty_open(device, O_RDWR, 0777);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
rc = tcgetattr(fd, &ttyb);
|
||||
if (rc < 0) {
|
||||
saved_errno = errno;
|
||||
close(fd);
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
ttyb.c_iflag = 0; /* input modes */
|
||||
ttyb.c_oflag = 0; /* output modes */
|
||||
ttyb.c_cflag = IBAUD|CS8|CLOCAL; /* control modes (no read) */
|
||||
ttyb.c_lflag = 0; /* local modes */
|
||||
ttyb.c_cc[VMIN] = 0; /* min chars */
|
||||
ttyb.c_cc[VTIME] = 5; /* receive timeout */
|
||||
cfsetispeed(&ttyb, (u_int)speed);
|
||||
cfsetospeed(&ttyb, (u_int)speed);
|
||||
rc = tcsetattr(fd, TCSANOW, &ttyb);
|
||||
if (rc < 0) {
|
||||
saved_errno = errno;
|
||||
close(fd);
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
return (fd);
|
||||
}
|
||||
|
||||
/* end program */
|
||||
@@ -0,0 +1,551 @@
|
||||
/*
|
||||
* iosignal.c - input/output routines for ntpd. The socket-opening code
|
||||
* was shamelessly stolen from ntpd.
|
||||
*/
|
||||
|
||||
/*
|
||||
* [Bug 158]
|
||||
* Do the #includes differently, as under some versions of Linux
|
||||
* sys/param.h has a #undef CONFIG_PHONE line in it.
|
||||
*
|
||||
* As we have ~40 CONFIG_ variables, I don't feel like renaming them
|
||||
* every time somebody adds a new macro to some system header.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
# include <sys/param.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#if _BSDI_VERSION >= 199510
|
||||
# include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
# ifdef __QNXNTO__
|
||||
# include <fcntl.h>
|
||||
# include <unix.h>
|
||||
# define FNDELAY O_NDELAY
|
||||
# endif
|
||||
|
||||
#include "ntp_machine.h"
|
||||
#include "ntpd.h"
|
||||
#include "ntp_io.h"
|
||||
#include "ntp_if.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "iosignal.h"
|
||||
|
||||
#include <ipcom_type.h>
|
||||
#include <ipcom_os.h>
|
||||
#include <ipntp.h>
|
||||
|
||||
|
||||
#if defined(HAVE_SIGNALED_IO)
|
||||
static RETSIGTYPE sigio_handler (int);
|
||||
|
||||
/* consistency safegurad to catch BLOCK/UNBLOCK oversights */
|
||||
static int sigio_block_count = 0;
|
||||
|
||||
/* main inputhandler to be called on SIGIO */
|
||||
static input_handler_t *input_handler_callback = NULL;
|
||||
|
||||
# if defined(HAVE_SIGACTION)
|
||||
/*
|
||||
* If sigaction() is used for signal handling and a signal is
|
||||
* pending then the kernel blocks the signal before it calls
|
||||
* the signal handler.
|
||||
*
|
||||
* The variable below is used to take care that the SIGIO signal
|
||||
* is not unintentionally unblocked inside the sigio_handler()
|
||||
* if the handler executes a piece of code that is normally
|
||||
* bracketed by BLOCKIO()/UNBLOCKIO() calls.
|
||||
*/
|
||||
static int sigio_handler_active = 0;
|
||||
# endif
|
||||
|
||||
/*
|
||||
* SIGPOLL and SIGIO ROUTINES.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* TTY initialization routines.
|
||||
*/
|
||||
int
|
||||
init_clock_sig(
|
||||
struct refclockio *rio
|
||||
)
|
||||
{
|
||||
# ifdef USE_TTY_SIGPOLL
|
||||
{
|
||||
/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
|
||||
if (ioctl(rio->fd, I_SETSIG, S_INPUT) < 0)
|
||||
{
|
||||
msyslog(LOG_ERR,
|
||||
"init_clock_sig: ioctl(I_SETSIG, S_INPUT) failed: %m");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
# else
|
||||
/*
|
||||
* Special cases first!
|
||||
*/
|
||||
/* Was: defined(SYS_HPUX) */
|
||||
# if defined(FIOSSAIOOWN) && defined(FIOSNBIO) && defined(FIOSSAIOSTAT)
|
||||
#define CLOCK_DONE
|
||||
{
|
||||
int pgrp, on = 1;
|
||||
|
||||
/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
|
||||
pgrp = (int)ipcom_getpid();
|
||||
if (ioctl(rio->fd, FIOSSAIOOWN, (char *)&pgrp) == -1)
|
||||
{
|
||||
msyslog(LOG_ERR, "ioctl(FIOSSAIOOWN) fails for clock I/O: %m - EXITING");
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/*
|
||||
* set non-blocking, async I/O on the descriptor
|
||||
*/
|
||||
if (ioctl(rio->fd, FIOSNBIO, (char *)&on) == -1)
|
||||
{
|
||||
msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails for clock I/O: %m - EXITING");
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
if (ioctl(rio->fd, FIOSSAIOSTAT, (char *)&on) == -1)
|
||||
{
|
||||
msyslog(LOG_ERR, "ioctl(FIOSSAIOSTAT) fails for clock I/O: %m - EXITING");
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
# endif /* SYS_HPUX: FIOSSAIOOWN && FIOSNBIO && FIOSSAIOSTAT */
|
||||
/* Was: defined(SYS_AIX) && !defined(_BSD) */
|
||||
# if !defined(_BSD) && defined(_AIX) && defined(FIOASYNC) && defined(FIOSETOWN)
|
||||
/*
|
||||
* SYSV compatibility mode under AIX.
|
||||
*/
|
||||
#define CLOCK_DONE
|
||||
{
|
||||
int pgrp, on = 1;
|
||||
|
||||
/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
|
||||
if (ioctl(rio->fd, FIOASYNC, (char *)&on) == -1)
|
||||
{
|
||||
msyslog(LOG_ERR, "ioctl(FIOASYNC) fails for clock I/O: %m");
|
||||
return 1;
|
||||
}
|
||||
pgrp = -getpid();
|
||||
if (ioctl(rio->fd, FIOSETOWN, (char*)&pgrp) == -1)
|
||||
{
|
||||
msyslog(LOG_ERR, "ioctl(FIOSETOWN) fails for clock I/O: %m");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0)
|
||||
{
|
||||
msyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails for clock I/O: %m");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
# endif /* AIX && !BSD: !_BSD && FIOASYNC && FIOSETOWN */
|
||||
# ifndef CLOCK_DONE
|
||||
{
|
||||
/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
|
||||
# if defined(TIOCSCTTY) && defined(USE_FSETOWNCTTY)
|
||||
/*
|
||||
* there are, however, always exceptions to the rules
|
||||
* one is, that OSF accepts SETOWN on TTY fd's only, iff they are
|
||||
* CTTYs. SunOS and HPUX do not semm to have this restriction.
|
||||
* another question is: how can you do multiple SIGIO from several
|
||||
* ttys (as they all should be CTTYs), wondering...
|
||||
*
|
||||
* kd 95-07-16
|
||||
*/
|
||||
if (ioctl(rio->fd, TIOCSCTTY, 0) == -1)
|
||||
{
|
||||
msyslog(LOG_ERR, "ioctl(TIOCSCTTY, 0) fails for clock I/O: %m");
|
||||
return 1;
|
||||
}
|
||||
# endif /* TIOCSCTTY && USE_FSETOWNCTTY */
|
||||
|
||||
if (fcntl(rio->fd, F_SETOWN, getpid()) == -1)
|
||||
{
|
||||
msyslog(LOG_ERR, "fcntl(F_SETOWN) fails for clock I/O: %m");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0)
|
||||
{
|
||||
msyslog(LOG_ERR,
|
||||
"fcntl(FNDELAY|FASYNC) fails for clock I/O: %m");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
# endif /* CLOCK_DONE */
|
||||
# endif /* !USE_TTY_SIGPOLL */
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
init_socket_sig(
|
||||
int fd
|
||||
)
|
||||
{
|
||||
# ifdef USE_UDP_SIGPOLL
|
||||
{
|
||||
if (ioctl(fd, I_SETSIG, S_INPUT) < 0)
|
||||
{
|
||||
msyslog(LOG_ERR,
|
||||
"init_socket_sig: ioctl(I_SETSIG, S_INPUT) failed: %m - EXITING");
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
}
|
||||
# else /* USE_UDP_SIGPOLL */
|
||||
{
|
||||
int pgrp;
|
||||
# ifdef FIOASYNC
|
||||
int on = 1;
|
||||
# endif
|
||||
|
||||
# if defined(FIOASYNC)
|
||||
if (ioctl(fd, FIOASYNC, (char *)&on) == -1)
|
||||
{
|
||||
msyslog(LOG_ERR, "ioctl(FIOASYNC) fails: %m - EXITING");
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
# elif defined(FASYNC)
|
||||
{
|
||||
int flags;
|
||||
|
||||
if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
|
||||
{
|
||||
msyslog(LOG_ERR, "fcntl(F_GETFL) fails: %m - EXITING");
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
if (fcntl(fd, F_SETFL, flags|FASYNC) < 0)
|
||||
{
|
||||
msyslog(LOG_ERR, "fcntl(...|FASYNC) fails: %m - EXITING");
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
# else
|
||||
# include "Bletch: Need asynchronous I/O!"
|
||||
# endif
|
||||
|
||||
# ifdef UDP_BACKWARDS_SETOWN
|
||||
pgrp = -getpid();
|
||||
# else
|
||||
pgrp = getpid();
|
||||
# endif
|
||||
|
||||
# if defined(SIOCSPGRP)
|
||||
if (ioctl(fd, SIOCSPGRP, (char *)&pgrp) == -1)
|
||||
{
|
||||
msyslog(LOG_ERR, "ioctl(SIOCSPGRP) fails: %m - EXITING");
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
# elif defined(FIOSETOWN)
|
||||
if (ioctl(fd, FIOSETOWN, (char*)&pgrp) == -1)
|
||||
{
|
||||
msyslog(LOG_ERR, "ioctl(FIOSETOWN) fails: %m - EXITING");
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
# elif defined(F_SETOWN)
|
||||
if (fcntl(fd, F_SETOWN, pgrp) == -1)
|
||||
{
|
||||
msyslog(LOG_ERR, "fcntl(F_SETOWN) fails: %m - EXITING");
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
# else
|
||||
# include "Bletch: Need to set process(group) to receive SIG(IO|POLL)"
|
||||
# endif
|
||||
}
|
||||
# endif /* USE_UDP_SIGPOLL */
|
||||
}
|
||||
|
||||
static RETSIGTYPE
|
||||
sigio_handler(
|
||||
int sig
|
||||
)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
l_fp ts;
|
||||
|
||||
get_systime(&ts);
|
||||
|
||||
# if defined(HAVE_SIGACTION)
|
||||
sigio_handler_active++;
|
||||
if (sigio_handler_active != 1) /* This should never happen! */
|
||||
msyslog(LOG_ERR, "sigio_handler: sigio_handler_active != 1");
|
||||
# endif
|
||||
|
||||
INSIST(input_handler_callback != NULL);
|
||||
(*input_handler_callback)(&ts);
|
||||
|
||||
# if defined(HAVE_SIGACTION)
|
||||
sigio_handler_active--;
|
||||
if (sigio_handler_active != 0) /* This should never happen! */
|
||||
msyslog(LOG_ERR, "sigio_handler: sigio_handler_active != 0");
|
||||
# endif
|
||||
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal support routines.
|
||||
*/
|
||||
# ifdef HAVE_SIGACTION
|
||||
void
|
||||
set_signal(input_handler_t *input)
|
||||
{
|
||||
INSIST(input != NULL);
|
||||
|
||||
input_handler_callback = input;
|
||||
|
||||
using_sigio = TRUE;
|
||||
# ifdef USE_SIGIO
|
||||
(void) signal_no_reset(SIGIO, sigio_handler);
|
||||
# endif
|
||||
# ifdef USE_SIGPOLL
|
||||
(void) signal_no_reset(SIGPOLL, sigio_handler);
|
||||
# endif
|
||||
}
|
||||
|
||||
void
|
||||
block_io_and_alarm(void)
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
if (sigemptyset(&set))
|
||||
msyslog(LOG_ERR, "block_io_and_alarm: sigemptyset() failed: %m");
|
||||
# if defined(USE_SIGIO)
|
||||
if (sigaddset(&set, SIGIO))
|
||||
msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGIO) failed: %m");
|
||||
# endif
|
||||
# if defined(USE_SIGPOLL)
|
||||
if (sigaddset(&set, SIGPOLL))
|
||||
msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGPOLL) failed: %m");
|
||||
# endif
|
||||
if (sigaddset(&set, SIGALRM))
|
||||
msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGALRM) failed: %m");
|
||||
|
||||
if (sigprocmask(SIG_BLOCK, &set, NULL))
|
||||
msyslog(LOG_ERR, "block_io_and_alarm: sigprocmask() failed: %m");
|
||||
}
|
||||
|
||||
void
|
||||
block_sigio(void)
|
||||
{
|
||||
if ( sigio_handler_active == 0 ) /* not called from within signal handler */
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
++sigio_block_count;
|
||||
if (sigio_block_count > 1)
|
||||
msyslog(LOG_INFO, "block_sigio: sigio_block_count > 1");
|
||||
if (sigio_block_count < 1)
|
||||
msyslog(LOG_INFO, "block_sigio: sigio_block_count < 1");
|
||||
|
||||
if (sigemptyset(&set))
|
||||
msyslog(LOG_ERR, "block_sigio: sigemptyset() failed: %m");
|
||||
# if defined(USE_SIGIO)
|
||||
if (sigaddset(&set, SIGIO))
|
||||
msyslog(LOG_ERR, "block_sigio: sigaddset(SIGIO) failed: %m");
|
||||
# endif
|
||||
# if defined(USE_SIGPOLL)
|
||||
if (sigaddset(&set, SIGPOLL))
|
||||
msyslog(LOG_ERR, "block_sigio: sigaddset(SIGPOLL) failed: %m");
|
||||
# endif
|
||||
|
||||
if (sigprocmask(SIG_BLOCK, &set, NULL))
|
||||
msyslog(LOG_ERR, "block_sigio: sigprocmask() failed: %m");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
unblock_io_and_alarm(void)
|
||||
{
|
||||
sigset_t unset;
|
||||
|
||||
if (sigemptyset(&unset))
|
||||
msyslog(LOG_ERR, "unblock_io_and_alarm: sigemptyset() failed: %m");
|
||||
|
||||
# if defined(USE_SIGIO)
|
||||
if (sigaddset(&unset, SIGIO))
|
||||
msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGIO) failed: %m");
|
||||
# endif
|
||||
# if defined(USE_SIGPOLL)
|
||||
if (sigaddset(&unset, SIGPOLL))
|
||||
msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGPOLL) failed: %m");
|
||||
# endif
|
||||
if (sigaddset(&unset, SIGALRM))
|
||||
msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGALRM) failed: %m");
|
||||
|
||||
if (sigprocmask(SIG_UNBLOCK, &unset, NULL))
|
||||
msyslog(LOG_ERR, "unblock_io_and_alarm: sigprocmask() failed: %m");
|
||||
}
|
||||
|
||||
void
|
||||
unblock_sigio(void)
|
||||
{
|
||||
if ( sigio_handler_active == 0 ) /* not called from within signal handler */
|
||||
{
|
||||
sigset_t unset;
|
||||
|
||||
--sigio_block_count;
|
||||
if (sigio_block_count > 0)
|
||||
msyslog(LOG_INFO, "unblock_sigio: sigio_block_count > 0");
|
||||
if (sigio_block_count < 0)
|
||||
msyslog(LOG_INFO, "unblock_sigio: sigio_block_count < 0");
|
||||
|
||||
if (sigemptyset(&unset))
|
||||
msyslog(LOG_ERR, "unblock_sigio: sigemptyset() failed: %m");
|
||||
|
||||
# if defined(USE_SIGIO)
|
||||
if (sigaddset(&unset, SIGIO))
|
||||
msyslog(LOG_ERR, "unblock_sigio: sigaddset(SIGIO) failed: %m");
|
||||
# endif
|
||||
# if defined(USE_SIGPOLL)
|
||||
if (sigaddset(&unset, SIGPOLL))
|
||||
msyslog(LOG_ERR, "unblock_sigio: sigaddset(SIGPOLL) failed: %m");
|
||||
# endif
|
||||
|
||||
if (sigprocmask(SIG_UNBLOCK, &unset, NULL))
|
||||
msyslog(LOG_ERR, "unblock_sigio: sigprocmask() failed: %m");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wait_for_signal(void)
|
||||
{
|
||||
sigset_t old;
|
||||
|
||||
if (sigprocmask(SIG_UNBLOCK, NULL, &old))
|
||||
msyslog(LOG_ERR, "wait_for_signal: sigprocmask() failed: %m");
|
||||
|
||||
# if defined(USE_SIGIO)
|
||||
if (sigdelset(&old, SIGIO))
|
||||
msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGIO) failed: %m");
|
||||
# endif
|
||||
# if defined(USE_SIGPOLL)
|
||||
if (sigdelset(&old, SIGPOLL))
|
||||
msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGPOLL) failed: %m");
|
||||
# endif
|
||||
if (sigdelset(&old, SIGALRM))
|
||||
msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGALRM) failed: %m");
|
||||
|
||||
if (sigsuspend(&old) && (errno != EINTR))
|
||||
msyslog(LOG_ERR, "wait_for_signal: sigsuspend() failed: %m");
|
||||
}
|
||||
|
||||
# else /* !HAVE_SIGACTION */
|
||||
/*
|
||||
* Must be an old bsd system.
|
||||
* We assume there is no SIGPOLL.
|
||||
*/
|
||||
|
||||
void
|
||||
block_io_and_alarm(void)
|
||||
{
|
||||
int mask;
|
||||
|
||||
mask = sigmask(SIGIO) | sigmask(SIGALRM);
|
||||
if (sigblock(mask))
|
||||
msyslog(LOG_ERR, "block_io_and_alarm: sigblock() failed: %m");
|
||||
}
|
||||
|
||||
void
|
||||
block_sigio(void)
|
||||
{
|
||||
int mask;
|
||||
|
||||
++sigio_block_count;
|
||||
if (sigio_block_count > 1)
|
||||
msyslog(LOG_INFO, "block_sigio: sigio_block_count > 1");
|
||||
if (sigio_block_count < 1)
|
||||
msyslog(LOG_INFO, "block_sigio: sigio_block_count < 1");
|
||||
|
||||
mask = sigmask(SIGIO);
|
||||
if (sigblock(mask))
|
||||
msyslog(LOG_ERR, "block_sigio: sigblock() failed: %m");
|
||||
}
|
||||
|
||||
void
|
||||
set_signal(input_handler_t *input)
|
||||
{
|
||||
INSIST(input != NULL);
|
||||
|
||||
input_handler_callback = input;
|
||||
|
||||
using_sigio = TRUE;
|
||||
(void) signal_no_reset(SIGIO, sigio_handler);
|
||||
}
|
||||
|
||||
void
|
||||
unblock_io_and_alarm(void)
|
||||
{
|
||||
int mask, omask;
|
||||
|
||||
mask = sigmask(SIGIO) | sigmask(SIGALRM);
|
||||
omask = sigblock(0);
|
||||
omask &= ~mask;
|
||||
(void) sigsetmask(omask);
|
||||
}
|
||||
|
||||
void
|
||||
unblock_sigio(void)
|
||||
{
|
||||
int mask, omask;
|
||||
|
||||
--sigio_block_count;
|
||||
if (sigio_block_count > 0)
|
||||
msyslog(LOG_INFO, "unblock_sigio: sigio_block_count > 0");
|
||||
if (sigio_block_count < 0)
|
||||
msyslog(LOG_INFO, "unblock_sigio: sigio_block_count < 0");
|
||||
mask = sigmask(SIGIO);
|
||||
omask = sigblock(0);
|
||||
omask &= ~mask;
|
||||
(void) sigsetmask(omask);
|
||||
}
|
||||
|
||||
void
|
||||
wait_for_signal(void)
|
||||
{
|
||||
int mask, omask;
|
||||
|
||||
mask = sigmask(SIGIO) | sigmask(SIGALRM);
|
||||
omask = sigblock(0);
|
||||
omask &= ~mask;
|
||||
if (sigpause(omask) && (errno != EINTR))
|
||||
msyslog(LOG_ERR, "wait_for_signal: sigspause() failed: %m");
|
||||
}
|
||||
|
||||
# endif /* HAVE_SIGACTION */
|
||||
#else
|
||||
int NotAnEmptyCompilationUnit;
|
||||
#endif
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* is_ip_address
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#include "ntp_assert.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "safecast.h"
|
||||
|
||||
/* Don't include ISC's version of IPv6 variables and structures */
|
||||
#define ISC_IPV6_H 1
|
||||
#include <isc/netaddr.h>
|
||||
#include <isc/sockaddr.h>
|
||||
|
||||
|
||||
/*
|
||||
* Code to tell if we have an IP address
|
||||
* If we have then return the sockaddr structure
|
||||
* and set the return value
|
||||
* see the bind9/getaddresses.c for details
|
||||
*/
|
||||
int
|
||||
is_ip_address(
|
||||
const char * host,
|
||||
u_short af,
|
||||
sockaddr_u * addr
|
||||
)
|
||||
{
|
||||
struct in_addr in4;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *result;
|
||||
struct sockaddr_in6 *resaddr6;
|
||||
char tmpbuf[128];
|
||||
char *pch;
|
||||
|
||||
REQUIRE(host != NULL);
|
||||
REQUIRE(addr != NULL);
|
||||
|
||||
ZERO_SOCK(addr);
|
||||
|
||||
/*
|
||||
* Try IPv4, then IPv6. In order to handle the extended format
|
||||
* for IPv6 scoped addresses (address%scope_ID), we'll use a local
|
||||
* working buffer of 128 bytes. The length is an ad-hoc value, but
|
||||
* should be enough for this purpose; the buffer can contain a string
|
||||
* of at least 80 bytes for scope_ID in addition to any IPv6 numeric
|
||||
* addresses (up to 46 bytes), the delimiter character and the
|
||||
* terminating NULL character.
|
||||
*/
|
||||
if (AF_UNSPEC == af || AF_INET == af)
|
||||
if (inet_pton(AF_INET, host, &in4) == 1) {
|
||||
AF(addr) = AF_INET;
|
||||
SET_ADDR4N(addr, in4.s_addr);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (AF_UNSPEC == af || AF_INET6 == af)
|
||||
if (sizeof(tmpbuf) > strlen(host)) {
|
||||
if ('[' == host[0]) {
|
||||
strlcpy(tmpbuf, &host[1], sizeof(tmpbuf));
|
||||
pch = strchr(tmpbuf, ']');
|
||||
if (pch != NULL)
|
||||
*pch = '\0';
|
||||
} else {
|
||||
strlcpy(tmpbuf, host, sizeof(tmpbuf));
|
||||
}
|
||||
ZERO(hints);
|
||||
hints.ai_family = AF_INET6;
|
||||
hints.ai_flags |= AI_NUMERICHOST;
|
||||
if (getaddrinfo(tmpbuf, NULL, &hints, &result) == 0) {
|
||||
AF(addr) = AF_INET6;
|
||||
resaddr6 = UA_PTR(struct sockaddr_in6, result->ai_addr);
|
||||
SET_ADDR6N(addr, resaddr6->sin6_addr);
|
||||
SET_SCOPE(addr, resaddr6->sin6_scope_id);
|
||||
|
||||
freeaddrinfo(result);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If we got here it was not an IP address
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* lib_strbuf - library string storage
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#include <isc/net.h>
|
||||
#include <isc/result.h>
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "lib_strbuf.h"
|
||||
|
||||
|
||||
/*
|
||||
* Storage declarations
|
||||
*/
|
||||
int debug;
|
||||
libbufstr lib_stringbuf[LIB_NUMBUF];
|
||||
int lib_nextbuf;
|
||||
int ipv4_works;
|
||||
int ipv6_works;
|
||||
int lib_inited;
|
||||
|
||||
|
||||
/*
|
||||
* initialization routine. Might be needed if the code is ROMized.
|
||||
*/
|
||||
void
|
||||
init_lib(void)
|
||||
{
|
||||
if (lib_inited)
|
||||
return;
|
||||
ipv4_works = (ISC_R_SUCCESS == isc_net_probeipv4());
|
||||
ipv6_works = (ISC_R_SUCCESS == isc_net_probeipv6());
|
||||
init_systime();
|
||||
debug = 0;
|
||||
lib_nextbuf = 0;
|
||||
memset(lib_stringbuf, 0, sizeof(libbufstr)*LIB_NUMBUF);
|
||||
lib_inited = TRUE;
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* libssl_compat.c -- OpenSSL v1.1 compatibility functions
|
||||
*
|
||||
* ---------------------------------------------------------------------
|
||||
* Written by Juergen Perlinger <perlinger@ntp.org> for the NTP project
|
||||
*
|
||||
* Based on an idea by Kurt Roeckx <kurt@roeckx.be>
|
||||
*
|
||||
* ---------------------------------------------------------------------
|
||||
* This is a clean room implementation of shim functions that have
|
||||
* counterparts in the OpenSSL v1.1 API but not in earlier versions. So
|
||||
* while OpenSSL broke binary compatibility with v1.1, this shim module
|
||||
* should provide the necessary source code compatibility with older
|
||||
* versions of OpenSSL.
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
#include "ipntp_config.h"
|
||||
#include "ntp_types.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_types.h"
|
||||
#include "ntp_mem.h"
|
||||
|
||||
#include "libssl_compat.h"
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
#ifdef OPENSSL
|
||||
# include <string.h>
|
||||
# include <openssl/bn.h>
|
||||
# include <openssl/evp.h>
|
||||
#endif
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
#if defined(OPENSSL) && OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "ntp_assert.h"
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* replace a BIGNUM owned by the caller with another one if it's not
|
||||
* NULL, taking over the ownership of the new value. This clears & frees
|
||||
* the old value -- the clear might be overkill, but it's better to err
|
||||
* on the side of paranoia here.
|
||||
*/
|
||||
static void
|
||||
replace_bn_nn(
|
||||
BIGNUM ** ps,
|
||||
BIGNUM * n
|
||||
)
|
||||
{
|
||||
if (n) {
|
||||
REQUIRE(*ps != n);
|
||||
BN_clear_free(*ps);
|
||||
*ps = n;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* allocation and deallocation of prime number callbacks
|
||||
*/
|
||||
BN_GENCB*
|
||||
sslshimBN_GENCB_new(void)
|
||||
{
|
||||
return emalloc(sizeof(BN_GENCB));
|
||||
}
|
||||
|
||||
void
|
||||
sslshimBN_GENCB_free(
|
||||
BN_GENCB *cb
|
||||
)
|
||||
{
|
||||
efree(cb);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* allocation and deallocation of message digests
|
||||
*/
|
||||
EVP_MD_CTX*
|
||||
sslshim_EVP_MD_CTX_new(void)
|
||||
{
|
||||
EVP_MD_CTX * ctx;
|
||||
if (NULL != (ctx = emalloc(sizeof(EVP_MD_CTX))))
|
||||
EVP_MD_CTX_init(ctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void
|
||||
sslshim_EVP_MD_CTX_free(
|
||||
EVP_MD_CTX * pctx
|
||||
)
|
||||
{
|
||||
efree(pctx);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* get EVP keys and key type
|
||||
*/
|
||||
int
|
||||
sslshim_EVP_PKEY_id(
|
||||
const EVP_PKEY *pkey
|
||||
)
|
||||
{
|
||||
return (pkey) ? pkey->type : EVP_PKEY_NONE;
|
||||
}
|
||||
|
||||
int
|
||||
sslshim_EVP_PKEY_base_id(
|
||||
const EVP_PKEY *pkey
|
||||
)
|
||||
{
|
||||
return (pkey) ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE;
|
||||
}
|
||||
|
||||
RSA*
|
||||
sslshim_EVP_PKEY_get0_RSA(
|
||||
EVP_PKEY * pkey
|
||||
)
|
||||
{
|
||||
return (pkey) ? pkey->pkey.rsa : NULL;
|
||||
}
|
||||
|
||||
DSA*
|
||||
sslshim_EVP_PKEY_get0_DSA(
|
||||
EVP_PKEY * pkey
|
||||
)
|
||||
{
|
||||
return (pkey) ? pkey->pkey.dsa : NULL;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* set/get RSA params
|
||||
*/
|
||||
void
|
||||
sslshim_RSA_get0_key(
|
||||
const RSA * prsa,
|
||||
const BIGNUM ** pn,
|
||||
const BIGNUM ** pe,
|
||||
const BIGNUM ** pd
|
||||
)
|
||||
{
|
||||
REQUIRE(prsa != NULL);
|
||||
|
||||
if (pn)
|
||||
*pn = prsa->n;
|
||||
if (pe)
|
||||
*pe = prsa->e;
|
||||
if (pd)
|
||||
*pd = prsa->d;
|
||||
}
|
||||
|
||||
int
|
||||
sslshim_RSA_set0_key(
|
||||
RSA * prsa,
|
||||
BIGNUM * n,
|
||||
BIGNUM * e,
|
||||
BIGNUM * d
|
||||
)
|
||||
{
|
||||
REQUIRE(prsa != NULL);
|
||||
if (!((prsa->n || n) && (prsa->e || e)))
|
||||
return 0;
|
||||
|
||||
replace_bn_nn(&prsa->n, n);
|
||||
replace_bn_nn(&prsa->e, e);
|
||||
replace_bn_nn(&prsa->d, d);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
sslshim_RSA_get0_factors(
|
||||
const RSA * prsa,
|
||||
const BIGNUM ** pp,
|
||||
const BIGNUM ** pq
|
||||
)
|
||||
{
|
||||
REQUIRE(prsa != NULL);
|
||||
|
||||
if (pp)
|
||||
*pp = prsa->p;
|
||||
if (pq)
|
||||
*pq = prsa->q;
|
||||
}
|
||||
|
||||
int
|
||||
sslshim_RSA_set0_factors(
|
||||
RSA * prsa,
|
||||
BIGNUM * p,
|
||||
BIGNUM * q
|
||||
)
|
||||
{
|
||||
REQUIRE(prsa != NULL);
|
||||
if (!((prsa->p || p) && (prsa->q || q)))
|
||||
return 0;
|
||||
|
||||
replace_bn_nn(&prsa->p, p);
|
||||
replace_bn_nn(&prsa->q, q);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
sslshim_RSA_set0_crt_params(
|
||||
RSA * prsa,
|
||||
BIGNUM * dmp1,
|
||||
BIGNUM * dmq1,
|
||||
BIGNUM * iqmp
|
||||
)
|
||||
{
|
||||
REQUIRE(prsa != NULL);
|
||||
if (!((prsa->dmp1 || dmp1) &&
|
||||
(prsa->dmq1 || dmq1) &&
|
||||
(prsa->iqmp || iqmp) ))
|
||||
return 0;
|
||||
|
||||
replace_bn_nn(&prsa->dmp1, dmp1);
|
||||
replace_bn_nn(&prsa->dmq1, dmq1);
|
||||
replace_bn_nn(&prsa->iqmp, iqmp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* set/get DSA signature parameters
|
||||
*/
|
||||
void
|
||||
sslshim_DSA_SIG_get0(
|
||||
const DSA_SIG * psig,
|
||||
const BIGNUM ** pr,
|
||||
const BIGNUM ** ps
|
||||
)
|
||||
{
|
||||
REQUIRE(psig != NULL);
|
||||
|
||||
if (pr != NULL)
|
||||
*pr = psig->r;
|
||||
if (ps != NULL)
|
||||
*ps = psig->s;
|
||||
}
|
||||
|
||||
int
|
||||
sslshim_DSA_SIG_set0(
|
||||
DSA_SIG * psig,
|
||||
BIGNUM * r,
|
||||
BIGNUM * s
|
||||
)
|
||||
{
|
||||
REQUIRE(psig != NULL);
|
||||
if (!(r && s))
|
||||
return 0;
|
||||
|
||||
replace_bn_nn(&psig->r, r);
|
||||
replace_bn_nn(&psig->s, s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* get/set DSA parameters
|
||||
*/
|
||||
void
|
||||
sslshim_DSA_get0_pqg(
|
||||
const DSA * pdsa,
|
||||
const BIGNUM ** pp,
|
||||
const BIGNUM ** pq,
|
||||
const BIGNUM ** pg
|
||||
)
|
||||
{
|
||||
REQUIRE(pdsa != NULL);
|
||||
|
||||
if (pp != NULL)
|
||||
*pp = pdsa->p;
|
||||
if (pq != NULL)
|
||||
*pq = pdsa->q;
|
||||
if (pg != NULL)
|
||||
*pg = pdsa->g;
|
||||
}
|
||||
|
||||
int
|
||||
sslshim_DSA_set0_pqg(
|
||||
DSA * pdsa,
|
||||
BIGNUM * p,
|
||||
BIGNUM * q,
|
||||
BIGNUM * g
|
||||
)
|
||||
{
|
||||
if (!((pdsa->p || p) && (pdsa->q || q) && (pdsa->g || g)))
|
||||
return 0;
|
||||
|
||||
replace_bn_nn(&pdsa->p, p);
|
||||
replace_bn_nn(&pdsa->q, q);
|
||||
replace_bn_nn(&pdsa->g, g);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
sslshim_DSA_get0_key(
|
||||
const DSA * pdsa,
|
||||
const BIGNUM ** ppub_key,
|
||||
const BIGNUM ** ppriv_key
|
||||
)
|
||||
{
|
||||
REQUIRE(pdsa != NULL);
|
||||
|
||||
if (ppub_key != NULL)
|
||||
*ppub_key = pdsa->pub_key;
|
||||
if (ppriv_key != NULL)
|
||||
*ppriv_key = pdsa->priv_key;
|
||||
}
|
||||
|
||||
int
|
||||
sslshim_DSA_set0_key(
|
||||
DSA * pdsa,
|
||||
BIGNUM * pub_key,
|
||||
BIGNUM * priv_key
|
||||
)
|
||||
{
|
||||
REQUIRE(pdsa != NULL);
|
||||
if (!(pdsa->pub_key || pub_key))
|
||||
return 0;
|
||||
|
||||
replace_bn_nn(&pdsa->pub_key, pub_key);
|
||||
replace_bn_nn(&pdsa->priv_key, priv_key);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
sslshim_X509_get_signature_nid(
|
||||
const X509 *x
|
||||
)
|
||||
{
|
||||
return OBJ_obj2nid(x->sig_alg->algorithm);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
#else /* OPENSSL && OPENSSL_VERSION_NUMBER >= v1.1.0 */
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
NONEMPTY_TRANSLATION_UNIT
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
#endif
|
||||
/* ----------------------------------------------------------------- */
|
||||
@@ -0,0 +1,546 @@
|
||||
/* machines.c - provide special support for peculiar architectures
|
||||
*
|
||||
* Real bummers unite !
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "ipntp_config.h"
|
||||
#endif
|
||||
|
||||
#include "ntp.h"
|
||||
#include "ntp_machine.h"
|
||||
#include "ntp_syslog.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_unixtime.h"
|
||||
#include "lib_strbuf.h"
|
||||
#include "ntp_debug.h"
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef SYS_WINNT
|
||||
int _getch(void); /* Declare the one function rather than include conio.h */
|
||||
#else
|
||||
|
||||
#ifdef SYS_VXWORKS
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
#ifdef NTP_VXWORKS_6
|
||||
#include <time.h>
|
||||
#include "ntp_syslog.h"
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#include "taskLib.h"
|
||||
#include "sysLib.h"
|
||||
#include "time.h"
|
||||
#include "ntp_syslog.h"
|
||||
|
||||
#include "ntp_vxworks.h"
|
||||
|
||||
/* some translations to the world of vxWorkings -casey */
|
||||
/* first some netdb type things */
|
||||
#include "ioLib.h"
|
||||
#include <socket.h>
|
||||
int h_errno;
|
||||
|
||||
struct hostent *gethostbyname(char *name)
|
||||
{
|
||||
struct hostent *host1;
|
||||
h_errno = 0; /* we are always successful!!! */
|
||||
host1 = (struct hostent *) emalloc (sizeof(struct hostent));
|
||||
host1->h_name = name;
|
||||
host1->h_addrtype = AF_INET;
|
||||
host1->h_aliases = name;
|
||||
host1->h_length = 4;
|
||||
host1->h_addr_list[0] = (char *)hostGetByName (name);
|
||||
host1->h_addr_list[1] = NULL;
|
||||
return host1;
|
||||
}
|
||||
|
||||
struct hostent *gethostbyaddr(char *name, int size, int addr_type)
|
||||
{
|
||||
struct hostent *host1;
|
||||
h_errno = 0; /* we are always successful!!! */
|
||||
host1 = (struct hostent *) emalloc (sizeof(struct hostent));
|
||||
host1->h_name = name;
|
||||
host1->h_addrtype = AF_INET;
|
||||
host1->h_aliases = name;
|
||||
host1->h_length = 4;
|
||||
host1->h_addr_list = NULL;
|
||||
return host1;
|
||||
}
|
||||
|
||||
struct servent *getservbyname (char *name, char *type)
|
||||
{
|
||||
struct servent *serv1;
|
||||
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 # */
|
||||
serv1->s_proto = "udp"; /* protocol to use */
|
||||
return serv1;
|
||||
}
|
||||
#endif
|
||||
/* second
|
||||
* vxworks thinks it has insomnia
|
||||
* we have to sleep for number of seconds
|
||||
*/
|
||||
|
||||
/* I am not sure how valid the granularity is - it is from G. Eger's port */
|
||||
#define CLK_GRANULARITY 1 /* Granularity of system clock in usec */
|
||||
/* Used to round down # usecs/tick */
|
||||
/* On a VCOM-100, PIT gets 8 MHz clk, */
|
||||
/* & it prescales by 32, thus 4 usec */
|
||||
/* on mv167, granularity is 1usec anyway*/
|
||||
/* To defeat rounding, set to 1 */
|
||||
#define USECS_PER_SEC MILLION /* Microseconds per second */
|
||||
#define TICK (((USECS_PER_SEC / NTP_SYSCLKRATEGET) / CLK_GRANULARITY) * CLK_GRANULARITY)
|
||||
|
||||
/*#define KEY_TYPE_MD5 4*/
|
||||
/*#define MINDISPERSE .005 min dispersion increment */
|
||||
/*#define MAXDISTANCE 1. max root distance (select threshold) */
|
||||
#define MAXHOP 2 /* anti-clockhop threshold */
|
||||
|
||||
#ifndef NTP_VXWORKS_6
|
||||
|
||||
/* emulate unix sleep
|
||||
* casey
|
||||
*/
|
||||
void sleep(int seconds)
|
||||
{
|
||||
taskDelay(seconds*TICK);
|
||||
}
|
||||
/* emulate unix alarm
|
||||
* that pauses and calls SIGALRM after the seconds are up...
|
||||
* so ... taskDelay() fudged for seconds should amount to the same thing.
|
||||
* casey
|
||||
*/
|
||||
void alarm (int seconds)
|
||||
{
|
||||
sleep(seconds);
|
||||
}
|
||||
|
||||
#endif /* NTP_VXWORKS_6 */
|
||||
#endif /* SYS_VXWORKS */
|
||||
|
||||
#ifdef SYS_PTX /* Does PTX still need this? */
|
||||
/*#include <sys/types.h> */
|
||||
#include <sys/procstats.h>
|
||||
|
||||
int
|
||||
gettimeofday(
|
||||
struct timeval *tvp
|
||||
)
|
||||
{
|
||||
/*
|
||||
* hi, this is Sequents sneak path to get to a clock
|
||||
* this is also the most logical syscall for such a function
|
||||
*/
|
||||
return (get_process_stats(tvp, PS_SELF, (struct procstats *) 0,
|
||||
(struct procstats *) 0));
|
||||
}
|
||||
#endif /* SYS_PTX */
|
||||
|
||||
#ifdef MPE
|
||||
/* This is a substitute for bind() that if called for an AF_INET socket
|
||||
port less than 1024, GETPRIVMODE() and GETUSERMODE() calls will be done. */
|
||||
|
||||
#undef bind
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
extern void GETPRIVMODE(void);
|
||||
extern void GETUSERMODE(void);
|
||||
|
||||
int __ntp_mpe_bind(int s, void *addr, int addrlen);
|
||||
|
||||
int __ntp_mpe_bind(int s, void *addr, int addrlen) {
|
||||
int priv = 0;
|
||||
int result;
|
||||
|
||||
if (addrlen == sizeof(struct sockaddr_in)) { /* AF_INET */
|
||||
if (((struct sockaddr_in *)addr)->sin_port > 0 &&
|
||||
((struct sockaddr_in *)addr)->sin_port < 1024) {
|
||||
priv = 1;
|
||||
GETPRIVMODE();
|
||||
}
|
||||
/* ((struct sockaddr_in *)addr)->sin_addr.s_addr = 0; */
|
||||
result = bind(s,addr,addrlen);
|
||||
if (priv == 1) GETUSERMODE();
|
||||
} else /* AF_UNIX */
|
||||
result = bind(s,addr,addrlen);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* MPE stupidly requires sfcntl() to be used on sockets instead of fcntl(),
|
||||
* so we define a wrapper to analyze the file descriptor and call the correct
|
||||
* function.
|
||||
*/
|
||||
|
||||
#undef fcntl
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
int __ntp_mpe_fcntl(int fd, int cmd, int arg);
|
||||
|
||||
int __ntp_mpe_fcntl(int fd, int cmd, int arg) {
|
||||
int len;
|
||||
struct sockaddr sa;
|
||||
|
||||
extern int sfcntl(int, int, int);
|
||||
|
||||
len = sizeof sa;
|
||||
if (getsockname(fd, &sa, &len) == -1) {
|
||||
if (errno == EAFNOSUPPORT) /* AF_UNIX socket */
|
||||
return sfcntl(fd, cmd, arg);
|
||||
if (errno == ENOTSOCK) /* file or pipe */
|
||||
return fcntl(fd, cmd, arg);
|
||||
return (-1); /* unknown getsockname() failure */
|
||||
} else /* AF_INET socket */
|
||||
return sfcntl(fd, cmd, arg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setitimer emulation support. Note that we implement this using alarm(),
|
||||
* and since alarm() only delivers one signal, we must re-enable the alarm
|
||||
* by enabling our own SIGALRM setitimer_mpe_handler routine to be called
|
||||
* before the real handler routine and re-enable the alarm at that time.
|
||||
*
|
||||
* Note that this solution assumes that sigaction(SIGALRM) is called before
|
||||
* calling setitimer(). If it should ever to become necessary to support
|
||||
* sigaction(SIGALRM) after calling setitimer(), it will be necessary to trap
|
||||
* those sigaction() calls.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
|
||||
/*
|
||||
* Some global data that needs to be shared between setitimer() and
|
||||
* setitimer_mpe_handler().
|
||||
*/
|
||||
|
||||
struct {
|
||||
unsigned long current_msec; /* current alarm() value in effect */
|
||||
unsigned long interval_msec; /* next alarm() value from setitimer */
|
||||
unsigned long value_msec; /* first alarm() value from setitimer */
|
||||
struct itimerval current_itimerval; /* current itimerval in effect */
|
||||
struct sigaction oldact; /* SIGALRM state saved by setitimer */
|
||||
} setitimer_mpe_ctx = { 0, 0, 0 };
|
||||
|
||||
/*
|
||||
* Undocumented, unsupported function to do alarm() in milliseconds.
|
||||
*/
|
||||
|
||||
extern unsigned int px_alarm(unsigned long, int *);
|
||||
|
||||
/*
|
||||
* The SIGALRM handler routine enabled by setitimer(). Re-enable the alarm or
|
||||
* restore the original SIGALRM setting if no more alarms are needed. Then
|
||||
* call the original SIGALRM handler (if any).
|
||||
*/
|
||||
|
||||
static RETSIGTYPE setitimer_mpe_handler(int sig)
|
||||
{
|
||||
int alarm_hpe_status;
|
||||
|
||||
/* Update the new current alarm value */
|
||||
|
||||
setitimer_mpe_ctx.current_msec = setitimer_mpe_ctx.interval_msec;
|
||||
|
||||
if (setitimer_mpe_ctx.interval_msec > 0) {
|
||||
/* Additional intervals needed; re-arm the alarm timer */
|
||||
px_alarm(setitimer_mpe_ctx.interval_msec,&alarm_hpe_status);
|
||||
} else {
|
||||
/* No more intervals, so restore previous original SIGALRM handler */
|
||||
sigaction(SIGALRM, &setitimer_mpe_ctx.oldact, NULL);
|
||||
}
|
||||
|
||||
/* Call the original SIGALRM handler if it is a function and not just a flag */
|
||||
|
||||
if (setitimer_mpe_ctx.oldact.sa_handler != SIG_DFL &&
|
||||
setitimer_mpe_ctx.oldact.sa_handler != SIG_ERR &&
|
||||
setitimer_mpe_ctx.oldact.sa_handler != SIG_IGN)
|
||||
(*setitimer_mpe_ctx.oldact.sa_handler)(SIGALRM);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Our implementation of setitimer().
|
||||
*/
|
||||
|
||||
int
|
||||
setitimer(int which, struct itimerval *value,
|
||||
struct itimerval *ovalue)
|
||||
{
|
||||
|
||||
int alarm_hpe_status;
|
||||
unsigned long remaining_msec, value_msec, interval_msec;
|
||||
struct sigaction newact;
|
||||
|
||||
/*
|
||||
* Convert the initial interval to milliseconds
|
||||
*/
|
||||
|
||||
if (value->it_value.tv_sec > (UINT_MAX / 1000))
|
||||
value_msec = UINT_MAX;
|
||||
else
|
||||
value_msec = value->it_value.tv_sec * 1000;
|
||||
|
||||
value_msec += value->it_value.tv_usec / 1000;
|
||||
|
||||
/*
|
||||
* Convert the reset interval to milliseconds
|
||||
*/
|
||||
|
||||
if (value->it_interval.tv_sec > (UINT_MAX / 1000))
|
||||
interval_msec = UINT_MAX;
|
||||
else
|
||||
interval_msec = value->it_interval.tv_sec * 1000;
|
||||
|
||||
interval_msec += value->it_interval.tv_usec / 1000;
|
||||
|
||||
if (value_msec > 0 && interval_msec > 0) {
|
||||
/*
|
||||
* We'll be starting an interval timer that will be repeating, so we need to
|
||||
* insert our own SIGALRM signal handler to schedule the repeats.
|
||||
*/
|
||||
|
||||
/* Read the current SIGALRM action */
|
||||
|
||||
if (sigaction(SIGALRM, NULL, &setitimer_mpe_ctx.oldact) < 0) {
|
||||
fprintf(stderr,"MPE setitimer old handler failed, errno=%d\n",errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize the new action to call our SIGALRM handler instead */
|
||||
|
||||
newact.sa_handler = &setitimer_mpe_handler;
|
||||
newact.sa_mask = setitimer_mpe_ctx.oldact.sa_mask;
|
||||
newact.sa_flags = setitimer_mpe_ctx.oldact.sa_flags;
|
||||
|
||||
if (sigaction(SIGALRM, &newact, NULL) < 0) {
|
||||
fprintf(stderr,"MPE setitimer new handler failed, errno=%d\n",errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return previous itimerval if desired
|
||||
*/
|
||||
|
||||
if (ovalue != NULL) *ovalue = setitimer_mpe_ctx.current_itimerval;
|
||||
|
||||
/*
|
||||
* Save current parameters for later usage
|
||||
*/
|
||||
|
||||
setitimer_mpe_ctx.current_itimerval = *value;
|
||||
setitimer_mpe_ctx.current_msec = value_msec;
|
||||
setitimer_mpe_ctx.value_msec = value_msec;
|
||||
setitimer_mpe_ctx.interval_msec = interval_msec;
|
||||
|
||||
/*
|
||||
* Schedule the first alarm
|
||||
*/
|
||||
|
||||
remaining_msec = px_alarm(value_msec, &alarm_hpe_status);
|
||||
if (alarm_hpe_status == 0)
|
||||
return (0);
|
||||
else
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* MPE lacks gettimeofday(), so we define our own.
|
||||
*/
|
||||
|
||||
int gettimeofday(struct timeval *tvp)
|
||||
|
||||
{
|
||||
/* Documented, supported MPE functions. */
|
||||
extern void GETPRIVMODE(void);
|
||||
extern void GETUSERMODE(void);
|
||||
|
||||
/* Undocumented, unsupported MPE functions. */
|
||||
extern long long get_time(void);
|
||||
extern void get_time_change_info(long long *, char *, char *);
|
||||
extern long long ticks_to_micro(long long);
|
||||
|
||||
char pwf_since_boot, recover_pwf_time;
|
||||
long long mpetime, offset_ticks, offset_usec;
|
||||
|
||||
GETPRIVMODE();
|
||||
mpetime = get_time(); /* MPE local time usecs since Jan 1 1970 */
|
||||
get_time_change_info(&offset_ticks, &pwf_since_boot, &recover_pwf_time);
|
||||
offset_usec = ticks_to_micro(offset_ticks); /* UTC offset usecs */
|
||||
GETUSERMODE();
|
||||
|
||||
mpetime = mpetime - offset_usec; /* Convert from local time to UTC */
|
||||
tvp->tv_sec = mpetime / 1000000LL;
|
||||
tvp->tv_usec = mpetime % 1000000LL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* MPE lacks settimeofday(), so we define our own.
|
||||
*/
|
||||
|
||||
#define HAVE_SETTIMEOFDAY
|
||||
|
||||
int settimeofday(struct timeval *tvp)
|
||||
|
||||
{
|
||||
/* Documented, supported MPE functions. */
|
||||
extern void GETPRIVMODE(void);
|
||||
extern void GETUSERMODE(void);
|
||||
|
||||
/* Undocumented, unsupported MPE functions. */
|
||||
extern void get_time_change_info(long long *, char *, char *);
|
||||
extern void initialize_system_time(long long, int);
|
||||
extern void set_time_correction(long long, int, int);
|
||||
extern long long ticks_to_micro(long long);
|
||||
|
||||
char pwf_since_boot, recover_pwf_time;
|
||||
long long big_sec, big_usec, mpetime, offset_ticks, offset_usec;
|
||||
|
||||
big_sec = tvp->tv_sec;
|
||||
big_usec = tvp->tv_usec;
|
||||
mpetime = (big_sec * 1000000LL) + big_usec; /* Desired UTC microseconds */
|
||||
|
||||
GETPRIVMODE();
|
||||
set_time_correction(0LL,0,0); /* Cancel previous time correction, if any */
|
||||
get_time_change_info(&offset_ticks, &pwf_since_boot, &recover_pwf_time);
|
||||
offset_usec = ticks_to_micro(offset_ticks); /* UTC offset microseconds */
|
||||
mpetime = mpetime + offset_usec; /* Convert from UTC to local time */
|
||||
initialize_system_time(mpetime,1);
|
||||
GETUSERMODE();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* MPE */
|
||||
|
||||
#define SET_TOD_UNDETERMINED 0
|
||||
#define SET_TOD_CLOCK_SETTIME 1
|
||||
#define SET_TOD_SETTIMEOFDAY 2
|
||||
#define SET_TOD_STIME 3
|
||||
|
||||
const char * const set_tod_used[] = {
|
||||
"undetermined",
|
||||
"clock_settime",
|
||||
"settimeofday",
|
||||
"stime"
|
||||
};
|
||||
|
||||
pset_tod_using set_tod_using = NULL;
|
||||
|
||||
int
|
||||
ntp_set_tod(
|
||||
struct timeval *tvp,
|
||||
void *tzp
|
||||
)
|
||||
{
|
||||
static int tod;
|
||||
int rc;
|
||||
int saved_errno;
|
||||
|
||||
TRACE(1, ("In ntp_set_tod\n"));
|
||||
rc = -1;
|
||||
saved_errno = 0;
|
||||
|
||||
#ifdef HAVE_CLOCK_SETTIME
|
||||
if (rc && (SET_TOD_CLOCK_SETTIME == tod || !tod)) {
|
||||
errno = 0;
|
||||
rc = ipcom_settimeofday(tvp, IP_NULL);
|
||||
saved_errno = errno;
|
||||
TRACE(1, ("ntp_set_tod: clock_settime: %d %m\n", rc));
|
||||
if (!tod && !rc)
|
||||
tod = SET_TOD_CLOCK_SETTIME;
|
||||
|
||||
}
|
||||
#endif /* HAVE_CLOCK_SETTIME */
|
||||
#ifdef HAVE_SETTIMEOFDAY
|
||||
if (rc && (SET_TOD_SETTIMEOFDAY == tod || !tod)) {
|
||||
struct timeval adjtv;
|
||||
|
||||
/*
|
||||
* Some broken systems don't reset adjtime() when the
|
||||
* clock is stepped.
|
||||
*/
|
||||
adjtv.tv_sec = adjtv.tv_usec = 0;
|
||||
adjtime(&adjtv, NULL);
|
||||
errno = 0;
|
||||
rc = SETTIMEOFDAY(tvp, tzp);
|
||||
saved_errno = errno;
|
||||
TRACE(1, ("ntp_set_tod: settimeofday: %d %m\n", rc));
|
||||
if (!tod && !rc)
|
||||
tod = SET_TOD_SETTIMEOFDAY;
|
||||
}
|
||||
#endif /* HAVE_SETTIMEOFDAY */
|
||||
#ifdef HAVE_STIME
|
||||
if (rc && (SET_TOD_STIME == tod || !tod)) {
|
||||
long tp = tvp->tv_sec;
|
||||
|
||||
errno = 0;
|
||||
rc = stime(&tp); /* lie as bad as SysVR4 */
|
||||
saved_errno = errno;
|
||||
TRACE(1, ("ntp_set_tod: stime: %d %m\n", rc));
|
||||
if (!tod && !rc)
|
||||
tod = SET_TOD_STIME;
|
||||
}
|
||||
#endif /* HAVE_STIME */
|
||||
|
||||
errno = saved_errno; /* for %m below */
|
||||
TRACE(1, ("ntp_set_tod: Final result: %s: %d %m\n",
|
||||
set_tod_used[tod], rc));
|
||||
/*
|
||||
* Say how we're setting the time of day
|
||||
*/
|
||||
if (!rc && NULL != set_tod_using) {
|
||||
(*set_tod_using)(set_tod_used[tod]);
|
||||
set_tod_using = NULL;
|
||||
}
|
||||
|
||||
if (rc)
|
||||
errno = saved_errno;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* not SYS_WINNT */
|
||||
|
||||
#if defined (SYS_WINNT) || defined (SYS_VXWORKS) || defined(MPE)
|
||||
/* getpass is used in ntpq.c and ntpdc.c */
|
||||
static char ntp_password[32];
|
||||
|
||||
char *
|
||||
getpass(const char * prompt)
|
||||
{
|
||||
int c, i;
|
||||
FILE *fi = stdin;
|
||||
|
||||
fprintf(stderr, "%s", prompt);
|
||||
fflush(stderr);
|
||||
|
||||
for (i=0; i<sizeof(ntp_password)-1 && ((c=getc(fi))!=EOF && c!='\r'); i++) {
|
||||
ntp_password[i] = (char) c;
|
||||
}
|
||||
ntp_password[i] = '\0';
|
||||
|
||||
fputc('\n', stderr);
|
||||
fflush(stderr);
|
||||
|
||||
return ntp_password;
|
||||
}
|
||||
#endif /* SYS_WINNT */
|
||||
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (C) 2000, 2001 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: md5c.c,v 1.1.12.1 2015-03-31 09:17:02 lyang3 Exp $ */
|
||||
|
||||
/*! \file
|
||||
* This code implements the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||
* This code is in the public domain; do with it what you wish.
|
||||
*
|
||||
* Equivalent code is available from RSA Data Security, Inc.
|
||||
* This code has been tested against that, and is equivalent,
|
||||
* except that you don't need to include two pages of legalese
|
||||
* with every copy.
|
||||
*
|
||||
* To compute the message digest of a chunk of bytes, declare an
|
||||
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||
* needed on buffers full of bytes, and then call MD5Final, which
|
||||
* will fill a supplied 16-byte array with the digest.
|
||||
*/
|
||||
|
||||
#include "ipntp_config.h"
|
||||
|
||||
#include <isc/assertions.h>
|
||||
#include <isc/md5.h>
|
||||
#include <isc/platform.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/types.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#ifdef ISC_PLATFORM_OPENSSLHASH
|
||||
|
||||
void
|
||||
isc_md5_init(isc_md5_t *ctx) {
|
||||
EVP_DigestInit(ctx, EVP_md5());
|
||||
}
|
||||
|
||||
void
|
||||
isc_md5_invalidate(isc_md5_t *ctx) {
|
||||
EVP_MD_CTX_cleanup(ctx);
|
||||
}
|
||||
|
||||
void
|
||||
isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len) {
|
||||
EVP_DigestUpdate(ctx, (const void *) buf, (size_t) len);
|
||||
}
|
||||
|
||||
void
|
||||
isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
|
||||
EVP_DigestFinal(ctx, digest, NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void
|
||||
byteSwap(isc_uint32_t *buf, unsigned words)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)buf;
|
||||
|
||||
do {
|
||||
*buf++ = (isc_uint32_t)((unsigned)p[3] << 8 | p[2]) << 16 |
|
||||
((unsigned)p[1] << 8 | p[0]);
|
||||
p += 4;
|
||||
} while (--words);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
* initialization constants.
|
||||
*/
|
||||
void
|
||||
isc_md5_init(isc_md5_t *ctx) {
|
||||
ctx->buf[0] = 0x67452301;
|
||||
ctx->buf[1] = 0xefcdab89;
|
||||
ctx->buf[2] = 0x98badcfe;
|
||||
ctx->buf[3] = 0x10325476;
|
||||
|
||||
ctx->bytes[0] = 0;
|
||||
ctx->bytes[1] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
isc_md5_invalidate(isc_md5_t *ctx) {
|
||||
memset(ctx, 0, sizeof(isc_md5_t));
|
||||
}
|
||||
|
||||
/*@{*/
|
||||
/*! The four core functions - F1 is optimized somewhat */
|
||||
|
||||
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
/*@}*/
|
||||
|
||||
/*! This is the central step in the MD5 algorithm. */
|
||||
#define MD5STEP(f,w,x,y,z,in,s) \
|
||||
(w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
|
||||
|
||||
/*!
|
||||
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
static void
|
||||
transform(isc_uint32_t buf[4], isc_uint32_t const in[16]) {
|
||||
register isc_uint32_t a, b, c, d;
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Update context to reflect the concatenation of another buffer full
|
||||
* of bytes.
|
||||
*/
|
||||
void
|
||||
isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len) {
|
||||
isc_uint32_t t;
|
||||
|
||||
/* Update byte count */
|
||||
|
||||
t = ctx->bytes[0];
|
||||
if ((ctx->bytes[0] = t + len) < t)
|
||||
ctx->bytes[1]++; /* Carry from low to high */
|
||||
|
||||
t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
|
||||
if (t > len) {
|
||||
memcpy((unsigned char *)ctx->in + 64 - t, buf, len);
|
||||
return;
|
||||
}
|
||||
/* First chunk is an odd size */
|
||||
memcpy((unsigned char *)ctx->in + 64 - t, buf, t);
|
||||
byteSwap(ctx->in, 16);
|
||||
transform(ctx->buf, ctx->in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
|
||||
/* Process data in 64-byte chunks */
|
||||
while (len >= 64) {
|
||||
memcpy(ctx->in, buf, 64);
|
||||
byteSwap(ctx->in, 16);
|
||||
transform(ctx->buf, ctx->in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
memcpy(ctx->in, buf, len);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
* 1 0* (64-bit count of bits processed, MSB-first)
|
||||
*/
|
||||
void
|
||||
isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
|
||||
int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
|
||||
unsigned char *p = (unsigned char *)ctx->in + count;
|
||||
|
||||
/* Set the first char of padding to 0x80. There is always room. */
|
||||
*p++ = 0x80;
|
||||
|
||||
/* Bytes of padding needed to make 56 bytes (-8..55) */
|
||||
count = 56 - 1 - count;
|
||||
|
||||
if (count < 0) { /* Padding forces an extra block */
|
||||
memset(p, 0, count + 8);
|
||||
byteSwap(ctx->in, 16);
|
||||
transform(ctx->buf, ctx->in);
|
||||
p = (unsigned char *)ctx->in;
|
||||
count = 56;
|
||||
}
|
||||
memset(p, 0, count);
|
||||
byteSwap(ctx->in, 14);
|
||||
|
||||
/* Append length in bits and transform */
|
||||
ctx->in[14] = ctx->bytes[0] << 3;
|
||||
ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
|
||||
transform(ctx->buf, ctx->in);
|
||||
|
||||
byteSwap(ctx->buf, 4);
|
||||
memcpy(digest, ctx->buf, 16);
|
||||
memset(ctx, 0, sizeof(isc_md5_t)); /* In case it's sensitive */
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* modetoa - return an asciized mode
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lib_strbuf.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
const char *
|
||||
modetoa(
|
||||
size_t mode
|
||||
)
|
||||
{
|
||||
char *bp;
|
||||
static const char * const modestrings[] = {
|
||||
"unspec",
|
||||
"sym_active",
|
||||
"sym_passive",
|
||||
"client",
|
||||
"server",
|
||||
"broadcast",
|
||||
"control",
|
||||
"private",
|
||||
"bclient",
|
||||
};
|
||||
|
||||
if (mode >= COUNTOF(modestrings)) {
|
||||
LIB_GETBUF(bp);
|
||||
snprintf(bp, LIB_BUFLENGTH, "mode#%zu", mode);
|
||||
return bp;
|
||||
}
|
||||
|
||||
return modestrings[mode];
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* mstolfp - convert an ascii string in milliseconds to an l_fp number
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
int
|
||||
mstolfp(
|
||||
const char *str,
|
||||
l_fp *lfp
|
||||
)
|
||||
{
|
||||
register const char *cp;
|
||||
register char *bp;
|
||||
register const char *cpdec;
|
||||
char buf[100];
|
||||
|
||||
/*
|
||||
* We understand numbers of the form:
|
||||
*
|
||||
* [spaces][-|+][digits][.][digits][spaces|\n|\0]
|
||||
*
|
||||
* This is one enormous hack. Since I didn't feel like
|
||||
* rewriting the decoding routine for milliseconds, what
|
||||
* is essentially done here is to make a copy of the string
|
||||
* with the decimal moved over three places so the seconds
|
||||
* decoding routine can be used.
|
||||
*/
|
||||
bp = buf;
|
||||
cp = str;
|
||||
while (isspace((unsigned char)*cp))
|
||||
cp++;
|
||||
|
||||
if (*cp == '-' || *cp == '+') {
|
||||
*bp++ = *cp++;
|
||||
}
|
||||
|
||||
if (*cp != '.' && !isdigit((unsigned char)*cp))
|
||||
return 0;
|
||||
|
||||
|
||||
/*
|
||||
* Search forward for the decimal point or the end of the string.
|
||||
*/
|
||||
cpdec = cp;
|
||||
while (isdigit((unsigned char)*cpdec))
|
||||
cpdec++;
|
||||
|
||||
/*
|
||||
* Found something. If we have more than three digits copy the
|
||||
* excess over, else insert a leading 0.
|
||||
*/
|
||||
if ((cpdec - cp) > 3) {
|
||||
do {
|
||||
*bp++ = (char)*cp++;
|
||||
} while ((cpdec - cp) > 3);
|
||||
} else {
|
||||
*bp++ = '0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Stick the decimal in. If we've got less than three digits in
|
||||
* front of the millisecond decimal we insert the appropriate number
|
||||
* of zeros.
|
||||
*/
|
||||
*bp++ = '.';
|
||||
if ((cpdec - cp) < 3) {
|
||||
size_t i = 3 - (cpdec - cp);
|
||||
do {
|
||||
*bp++ = '0';
|
||||
} while (--i > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the remainder up to the millisecond decimal. If cpdec
|
||||
* is pointing at a decimal point, copy in the trailing number too.
|
||||
*/
|
||||
while (cp < cpdec)
|
||||
*bp++ = (char)*cp++;
|
||||
|
||||
if (*cp == '.') {
|
||||
cp++;
|
||||
while (isdigit((unsigned char)*cp))
|
||||
*bp++ = (char)*cp++;
|
||||
}
|
||||
*bp = '\0';
|
||||
|
||||
/*
|
||||
* Check to make sure the string is properly terminated. If
|
||||
* so, give the buffer to the decoding routine.
|
||||
*/
|
||||
if (*cp != '\0' && !isspace((unsigned char)*cp))
|
||||
return 0;
|
||||
return atolfp(buf, lfp);
|
||||
}
|
||||
@@ -0,0 +1,670 @@
|
||||
/*
|
||||
* msyslog - either send a message to the terminal or print it on
|
||||
* the standard output.
|
||||
*
|
||||
* Converted to use varargs, much better ... jks
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntp_string.h"
|
||||
#include "ntp.h"
|
||||
#include "ntp_debug.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_mem.h"
|
||||
#ifdef NTP_VXWORKS_7
|
||||
#include "applUtilLib.h"
|
||||
#endif
|
||||
#include <ipcom_syslog.h>
|
||||
|
||||
|
||||
#ifdef SYS_WINNT
|
||||
# include <stdarg.h>
|
||||
# include "..\ports\winnt\libntp\messages.h"
|
||||
#endif
|
||||
|
||||
#if defined(SYS_VXWORKS)
|
||||
#ifdef IPCOM_SYSLOG_FACILITY
|
||||
#undef IPCOM_SYSLOG_FACILITY
|
||||
#endif
|
||||
#define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPNTP
|
||||
|
||||
#ifdef IPCOM_SYSLOG_PRIORITY
|
||||
#undef IPCOM_SYSLOG_PRIORITY
|
||||
#endif
|
||||
#if defined(_WRS_CONFIG_IPNTP_SYSLOG_PRIORITY)
|
||||
#define IPCOM_SYSLOG_PRIORITY _WRS_CONFIG_IPNTP_SYSLOG_PRIORITY
|
||||
#else
|
||||
#define IPCOM_SYSLOG_PRIORITY _WRS_CONFIG_IPCOM_DEFAULT_SYSLOG_PRIORITY
|
||||
#endif
|
||||
|
||||
#define IPCOM_NTP_LOG(x,fm,a) \
|
||||
do { if ((IPCOM_SYSLOG_PRIORITY >= x) && IPCOM_SYSLOG_ENABLE(x)) \
|
||||
ipcom_syslog(IPCOM_SYSLOG_FACILITY | x, IPCOM_SYSLOG_BODY(fm),a); } while((0))
|
||||
#endif
|
||||
|
||||
int syslogit = TRUE;
|
||||
int msyslog_term = FALSE; /* duplicate to stdout/err */
|
||||
int msyslog_term_pid = TRUE;
|
||||
int msyslog_include_timestamp = TRUE;
|
||||
FILE * syslog_file;
|
||||
char * syslog_fname;
|
||||
char * syslog_abs_fname;
|
||||
|
||||
/* libntp default ntp_syslogmask is all bits lit */
|
||||
#define INIT_NTP_SYSLOGMASK ~(u_int32)0
|
||||
u_int32 ntp_syslogmask = INIT_NTP_SYSLOGMASK;
|
||||
|
||||
extern char const * progname;
|
||||
|
||||
/* Declare the local functions */
|
||||
void addto_syslog (int, const char *);
|
||||
#ifndef VSNPRINTF_PERCENT_M
|
||||
void format_errmsg (char *, size_t, const char *, int);
|
||||
|
||||
/* format_errmsg() is under #ifndef VSNPRINTF_PERCENT_M above */
|
||||
void
|
||||
format_errmsg(
|
||||
char * nfmt,
|
||||
size_t lennfmt,
|
||||
const char * fmt,
|
||||
int errval
|
||||
)
|
||||
{
|
||||
char errmsg[256];
|
||||
char c;
|
||||
char *n;
|
||||
const char *f;
|
||||
size_t len;
|
||||
|
||||
n = nfmt;
|
||||
f = fmt;
|
||||
while ((c = *f++) != '\0' && n < (nfmt + lennfmt - 1)) {
|
||||
if (c != '%') {
|
||||
*n++ = c;
|
||||
continue;
|
||||
}
|
||||
if ((c = *f++) != 'm') {
|
||||
*n++ = '%';
|
||||
if ('\0' == c)
|
||||
break;
|
||||
*n++ = c;
|
||||
continue;
|
||||
}
|
||||
errno_to_str(errval, errmsg, sizeof(errmsg));
|
||||
len = strlen(errmsg);
|
||||
|
||||
/* Make sure we have enough space for the error message */
|
||||
if ((n + len) < (nfmt + lennfmt - 1)) {
|
||||
memcpy(n, errmsg, len);
|
||||
n += len;
|
||||
}
|
||||
}
|
||||
*n = '\0';
|
||||
}
|
||||
#endif /* VSNPRINTF_PERCENT_M */
|
||||
|
||||
|
||||
/*
|
||||
* errno_to_str() - a thread-safe strerror() replacement.
|
||||
* Hides the varied signatures of strerror_r().
|
||||
* For Windows, we have:
|
||||
* #define errno_to_str isc_strerror
|
||||
*/
|
||||
#ifndef errno_to_str
|
||||
void
|
||||
errno_to_str(
|
||||
int err,
|
||||
char * buf,
|
||||
size_t bufsiz
|
||||
)
|
||||
{
|
||||
# if defined(STRERROR_R_CHAR_P) || !HAVE_DECL_STRERROR_R
|
||||
char * pstatic;
|
||||
|
||||
buf[0] = '\0';
|
||||
# ifdef STRERROR_R_CHAR_P
|
||||
pstatic = strerror_r(err, buf, bufsiz);
|
||||
# else
|
||||
pstatic = strerror(err);
|
||||
# endif
|
||||
if (NULL == pstatic && '\0' == buf[0])
|
||||
snprintf(buf, bufsiz, "%s(%d): errno %d",
|
||||
# ifdef STRERROR_R_CHAR_P
|
||||
"strerror_r",
|
||||
# else
|
||||
"strerror",
|
||||
# endif
|
||||
err, errno);
|
||||
/* protect against believing an int return is a pointer */
|
||||
else if (pstatic != buf && pstatic > (char *)bufsiz)
|
||||
strlcpy(buf, pstatic, bufsiz);
|
||||
# else
|
||||
int rc;
|
||||
|
||||
rc = strerror_r(err, buf, bufsiz);
|
||||
if (rc < 0)
|
||||
snprintf(buf, bufsiz, "strerror_r(%d): errno %d",
|
||||
err, errno);
|
||||
# endif
|
||||
}
|
||||
#endif /* errno_to_str */
|
||||
|
||||
|
||||
/*
|
||||
* addto_syslog()
|
||||
* This routine adds the contents of a buffer to the syslog or an
|
||||
* application-specific logfile.
|
||||
*/
|
||||
void
|
||||
addto_syslog(
|
||||
int level,
|
||||
const char * msg
|
||||
)
|
||||
{
|
||||
static char const * prevcall_progname;
|
||||
static char const * prog;
|
||||
const char nl[] = "\n";
|
||||
const char empty[] = "";
|
||||
FILE * term_file;
|
||||
int log_to_term;
|
||||
int log_to_file;
|
||||
int pid;
|
||||
const char * nl_or_empty;
|
||||
const char * human_time;
|
||||
|
||||
/* setup program basename static var prog if needed */
|
||||
if (progname != prevcall_progname) {
|
||||
prevcall_progname = progname;
|
||||
prog = strrchr(progname, DIR_SEP);
|
||||
if (prog != NULL)
|
||||
prog++;
|
||||
else
|
||||
prog = progname;
|
||||
}
|
||||
|
||||
log_to_term = msyslog_term;
|
||||
log_to_file = FALSE;
|
||||
#if !defined(VMS) && defined(SYS_VXWORKS)
|
||||
if (syslogit)
|
||||
IPCOM_NTP_LOG(level, "%s", msg);
|
||||
else
|
||||
#endif
|
||||
if (syslog_file != NULL)
|
||||
log_to_file = TRUE;
|
||||
else
|
||||
log_to_term = TRUE;
|
||||
#ifdef NTP_DEBUG
|
||||
if (debug > 0)
|
||||
log_to_term = TRUE;
|
||||
#endif
|
||||
if (!(log_to_file || log_to_term))
|
||||
return;
|
||||
|
||||
/* syslog() adds the timestamp, name, and pid */
|
||||
if (msyslog_include_timestamp)
|
||||
human_time = humanlogtime();
|
||||
else /* suppress gcc pot. uninit. warning */
|
||||
human_time = NULL;
|
||||
if (msyslog_term_pid || log_to_file)
|
||||
pid = getpid();
|
||||
else /* suppress gcc pot. uninit. warning */
|
||||
pid = -1;
|
||||
|
||||
/* syslog() adds trailing \n if not present */
|
||||
if ('\n' != msg[strlen(msg) - 1])
|
||||
nl_or_empty = nl;
|
||||
else
|
||||
nl_or_empty = empty;
|
||||
|
||||
if (log_to_term) {
|
||||
term_file = (level <= LOG_ERR)
|
||||
? stderr
|
||||
: stdout;
|
||||
if (term_file)
|
||||
{
|
||||
if (msyslog_include_timestamp)
|
||||
fprintf(term_file, "%s ", human_time);
|
||||
if (msyslog_term_pid)
|
||||
fprintf(term_file, "%s[%d]: ", prog, pid);
|
||||
fprintf(term_file, "%s%s", msg, nl_or_empty);
|
||||
#ifdef SYS_VXWORKS
|
||||
(void) fprintf(term_file, "\n");
|
||||
#endif
|
||||
fflush(term_file);
|
||||
}
|
||||
}
|
||||
|
||||
if (log_to_file) {
|
||||
if (msyslog_include_timestamp)
|
||||
fprintf(syslog_file, "%s ", human_time);
|
||||
fprintf(syslog_file, "%s[%d]: %s%s", prog, pid, msg,
|
||||
nl_or_empty);
|
||||
#ifdef SYS_VXWORKS
|
||||
(void) fprintf(syslog_file, "\n");
|
||||
#endif
|
||||
fflush(syslog_file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mvsnprintf(
|
||||
char * buf,
|
||||
size_t bufsiz,
|
||||
const char * fmt,
|
||||
va_list ap
|
||||
)
|
||||
{
|
||||
#ifndef VSNPRINTF_PERCENT_M
|
||||
char nfmt[256];
|
||||
#else
|
||||
const char * nfmt = fmt;
|
||||
#endif
|
||||
int errval;
|
||||
|
||||
/*
|
||||
* Save the error value as soon as possible
|
||||
*/
|
||||
#ifdef SYS_WINNT
|
||||
errval = GetLastError();
|
||||
if (NO_ERROR == errval)
|
||||
#endif /* SYS_WINNT */
|
||||
errval = errno;
|
||||
|
||||
#ifndef VSNPRINTF_PERCENT_M
|
||||
format_errmsg(nfmt, sizeof(nfmt), fmt, errval);
|
||||
#else
|
||||
errno = errval;
|
||||
#endif
|
||||
return vsnprintf(buf, bufsiz, nfmt, ap);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mvfprintf(
|
||||
FILE * fp,
|
||||
const char * fmt,
|
||||
va_list ap
|
||||
)
|
||||
{
|
||||
#ifndef VSNPRINTF_PERCENT_M
|
||||
char nfmt[256];
|
||||
#else
|
||||
const char * nfmt = fmt;
|
||||
#endif
|
||||
int errval;
|
||||
|
||||
/*
|
||||
* Save the error value as soon as possible
|
||||
*/
|
||||
#ifdef SYS_WINNT
|
||||
errval = GetLastError();
|
||||
if (NO_ERROR == errval)
|
||||
#endif /* SYS_WINNT */
|
||||
errval = errno;
|
||||
|
||||
#ifndef VSNPRINTF_PERCENT_M
|
||||
format_errmsg(nfmt, sizeof(nfmt), fmt, errval);
|
||||
#else
|
||||
errno = errval;
|
||||
#endif
|
||||
if (fp)
|
||||
return vfprintf(fp, nfmt, ap);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mfprintf(
|
||||
FILE * fp,
|
||||
const char * fmt,
|
||||
...
|
||||
)
|
||||
{
|
||||
va_list ap;
|
||||
int rc;
|
||||
|
||||
va_start(ap, fmt);
|
||||
rc = mvfprintf(fp, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mprintf(
|
||||
const char * fmt,
|
||||
...
|
||||
)
|
||||
{
|
||||
va_list ap;
|
||||
int rc;
|
||||
|
||||
va_start(ap, fmt);
|
||||
rc = mvfprintf(stdout, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
msnprintf(
|
||||
char * buf,
|
||||
size_t bufsiz,
|
||||
const char * fmt,
|
||||
...
|
||||
)
|
||||
{
|
||||
va_list ap;
|
||||
int rc;
|
||||
|
||||
va_start(ap, fmt);
|
||||
rc = mvsnprintf(buf, bufsiz, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
msyslog(
|
||||
int level,
|
||||
const char * fmt,
|
||||
...
|
||||
)
|
||||
{
|
||||
char buf[1024];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
mvsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
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
|
||||
*
|
||||
* Called once per process, including forked children.
|
||||
*/
|
||||
void
|
||||
init_logging(
|
||||
const char * name,
|
||||
u_int32 def_syslogmask,
|
||||
int is_daemon
|
||||
)
|
||||
{
|
||||
static int was_daemon;
|
||||
char * cp;
|
||||
const char * pname;
|
||||
|
||||
|
||||
syslogit = TRUE;
|
||||
msyslog_term = FALSE;
|
||||
msyslog_term_pid = TRUE;
|
||||
msyslog_include_timestamp = TRUE;
|
||||
syslog_file = NULL;
|
||||
syslog_fname = NULL;
|
||||
syslog_abs_fname = NULL;
|
||||
ntp_syslogmask = INIT_NTP_SYSLOGMASK;
|
||||
|
||||
/*
|
||||
* ntpd defaults to only logging sync-category events, when
|
||||
* NLOG() is used to conditionalize. Other libntp clients
|
||||
* leave it alone so that all NLOG() conditionals will fire.
|
||||
* This presumes all bits lit in ntp_syslogmask can't be
|
||||
* configured via logconfig and all lit is thereby a sentinel
|
||||
* that ntp_syslogmask is still at its default from libntp,
|
||||
* keeping in mind this function is called in forked children
|
||||
* where it has already been called in the parent earlier.
|
||||
* Forked children pass 0 for def_syslogmask.
|
||||
*/
|
||||
if (INIT_NTP_SYSLOGMASK == ntp_syslogmask &&
|
||||
0 != def_syslogmask)
|
||||
ntp_syslogmask = def_syslogmask; /* set more via logconfig */
|
||||
|
||||
/*
|
||||
* Logging. This may actually work on the gizmo board. Find a name
|
||||
* to log with by using the basename
|
||||
*/
|
||||
cp = strrchr(name, DIR_SEP);
|
||||
if (NULL == cp)
|
||||
pname = name;
|
||||
else
|
||||
pname = 1 + cp; /* skip DIR_SEP */
|
||||
progname = estrdup(pname);
|
||||
#ifdef SYS_WINNT /* strip ".exe" */
|
||||
cp = strrchr(progname, '.');
|
||||
if (NULL != cp && !strcasecmp(cp, ".exe"))
|
||||
*cp = '\0';
|
||||
#endif
|
||||
|
||||
#if !defined(VMS)
|
||||
|
||||
if (is_daemon)
|
||||
was_daemon = TRUE;
|
||||
# ifndef LOG_DAEMON
|
||||
#ifndef SYS_VXWORKS
|
||||
openlog(progname, LOG_PID);
|
||||
#endif
|
||||
# else /* LOG_DAEMON */
|
||||
|
||||
# ifndef LOG_NTP
|
||||
# define LOG_NTP IPCOM_LOG_IPNTP
|
||||
# endif
|
||||
openlog(progname, LOG_PID | LOG_NDELAY, (was_daemon)
|
||||
? LOG_NTP
|
||||
: 0);
|
||||
# ifdef NTP_DEBUG
|
||||
if (debug)
|
||||
ipcom_setlogmask_on(LOG_UPTO(LOG_DEBUG), IPCOM_LOG_IPNTP);
|
||||
# endif /* NTP_DEBUG */
|
||||
|
||||
# endif /* LOG_DAEMON */
|
||||
#endif /* !VMS */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* change_logfile()
|
||||
*
|
||||
* Used to change from syslog to a logfile, or from one logfile to
|
||||
* another, and to reopen logfiles after forking. On systems where
|
||||
* ntpd forks, deals with converting relative logfile paths to
|
||||
* absolute (root-based) because we reopen logfiles after the current
|
||||
* directory has changed.
|
||||
*/
|
||||
int
|
||||
change_logfile(
|
||||
const char * fname,
|
||||
int leave_crumbs
|
||||
)
|
||||
{
|
||||
FILE * new_file;
|
||||
const char * log_fname;
|
||||
char * abs_fname;
|
||||
#if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS)
|
||||
char curdir[512];
|
||||
size_t cd_octets;
|
||||
size_t octets;
|
||||
#endif /* POSIX */
|
||||
|
||||
REQUIRE(fname != NULL);
|
||||
log_fname = fname;
|
||||
|
||||
/*
|
||||
* In a forked child of a parent which is logging to a file
|
||||
* instead of syslog, syslog_file will be NULL and both
|
||||
* syslog_fname and syslog_abs_fname will be non-NULL.
|
||||
* If we are given the same filename previously opened
|
||||
* and it's still open, there's nothing to do here.
|
||||
*/
|
||||
if (syslog_file != NULL && syslog_fname != NULL &&
|
||||
0 == strcmp(syslog_fname, log_fname))
|
||||
return 0;
|
||||
|
||||
if (0 == strcmp(log_fname, "stderr")) {
|
||||
new_file = stderr;
|
||||
abs_fname = estrdup(log_fname);
|
||||
} else if (0 == strcmp(log_fname, "stdout")) {
|
||||
new_file = stdout;
|
||||
abs_fname = estrdup(log_fname);
|
||||
} else {
|
||||
if (syslog_fname != NULL &&
|
||||
0 == strcmp(log_fname, syslog_fname))
|
||||
log_fname = syslog_abs_fname;
|
||||
#if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS)
|
||||
if (log_fname != syslog_abs_fname &&
|
||||
DIR_SEP != log_fname[0] &&
|
||||
0 != strcmp(log_fname, "stderr") &&
|
||||
0 != strcmp(log_fname, "stdout") &&
|
||||
NULL != getcwd(curdir, sizeof(curdir))) {
|
||||
cd_octets = strlen(curdir);
|
||||
/* trim any trailing '/' */
|
||||
if (cd_octets > 1 &&
|
||||
DIR_SEP == curdir[cd_octets - 1])
|
||||
cd_octets--;
|
||||
octets = cd_octets;
|
||||
octets += 1; /* separator '/' */
|
||||
octets += strlen(log_fname);
|
||||
octets += 1; /* NUL terminator */
|
||||
abs_fname = emalloc(octets);
|
||||
snprintf(abs_fname, octets, "%.*s%c%s",
|
||||
(int)cd_octets, curdir, DIR_SEP,
|
||||
log_fname);
|
||||
} else
|
||||
#endif
|
||||
abs_fname = estrdup(log_fname);
|
||||
TRACE(1, ("attempting to open log %s\n", abs_fname));
|
||||
new_file = fopen(abs_fname, "a");
|
||||
}
|
||||
|
||||
if (NULL == new_file) {
|
||||
efree(abs_fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* leave a pointer in the old log */
|
||||
if (leave_crumbs && (syslogit || log_fname != syslog_abs_fname))
|
||||
msyslog(LOG_NOTICE, "switching logging to file %s",
|
||||
abs_fname);
|
||||
|
||||
if (syslog_file != NULL &&
|
||||
syslog_file != stderr && syslog_file != stdout &&
|
||||
fileno(syslog_file) != fileno(new_file))
|
||||
fclose(syslog_file);
|
||||
syslog_file = new_file;
|
||||
if (log_fname == syslog_abs_fname) {
|
||||
efree(abs_fname);
|
||||
} else {
|
||||
if (syslog_abs_fname != NULL &&
|
||||
syslog_abs_fname != syslog_fname)
|
||||
efree(syslog_abs_fname);
|
||||
if (syslog_fname != NULL)
|
||||
efree(syslog_fname);
|
||||
syslog_fname = estrdup(log_fname);
|
||||
syslog_abs_fname = abs_fname;
|
||||
}
|
||||
syslogit = FALSE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* setup_logfile()
|
||||
*
|
||||
* Redirect logging to a file if requested with -l/--logfile or via
|
||||
* ntp.conf logfile directive.
|
||||
*
|
||||
* This routine is invoked three different times in the sequence of a
|
||||
* typical daemon ntpd with DNS lookups to do. First it is invoked in
|
||||
* the original ntpd process, then again in the daemon after closing
|
||||
* all descriptors. In both of those cases, ntp.conf has not been
|
||||
* processed, so only -l/--logfile will trigger logfile redirection in
|
||||
* those invocations. Finally, if DNS names are resolved, the worker
|
||||
* child invokes this routine after its fork and close of all
|
||||
* descriptors. In this case, ntp.conf has been processed and any
|
||||
* "logfile" directive needs to be honored in the child as well.
|
||||
*/
|
||||
void
|
||||
setup_logfile(
|
||||
const char * name
|
||||
)
|
||||
{
|
||||
if (NULL == syslog_fname && NULL != name) {
|
||||
if (-1 == change_logfile(name, TRUE))
|
||||
msyslog(LOG_ERR, "Cannot open log file %s, %m",
|
||||
name);
|
||||
return ;
|
||||
}
|
||||
if (NULL == syslog_fname)
|
||||
return;
|
||||
|
||||
if (-1 == change_logfile(syslog_fname, FALSE))
|
||||
msyslog(LOG_ERR, "Cannot reopen log file %s, %m",
|
||||
syslog_fname);
|
||||
}
|
||||
|
||||
/* Helper for unit tests, where stdout + stderr are piped to the same
|
||||
* stream. This works moderately reliable only if both streams are
|
||||
* unbuffered or line buffered. Unfortunately stdout can be fully
|
||||
* buffered on pipes or files...
|
||||
*/
|
||||
int
|
||||
change_iobufs(
|
||||
int how
|
||||
)
|
||||
{
|
||||
int retv = 0;
|
||||
|
||||
# ifdef HAVE_SETVBUF
|
||||
|
||||
int mode;
|
||||
|
||||
switch (how) {
|
||||
case 0 : mode = _IONBF; break; /* no buffering */
|
||||
case 1 : mode = _IOLBF; break; /* line buffering */
|
||||
case 2 : mode = _IOFBF; break; /* full buffering */
|
||||
default: mode = _IOLBF; break; /* line buffering */
|
||||
}
|
||||
|
||||
retv = 1;
|
||||
if (setvbuf(stdout, NULL, mode, BUFSIZ) != 0)
|
||||
retv = -1;
|
||||
if (setvbuf(stderr, NULL, mode, BUFSIZ) != 0)
|
||||
retv = -1;
|
||||
|
||||
# else
|
||||
|
||||
UNUSED_ARG(how);
|
||||
|
||||
# endif
|
||||
|
||||
return retv;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* netof - return the net address part of an ip address in a sockaddr_storage structure
|
||||
* (zero out host part)
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include "ipntp.h"
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "ntp_net.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp.h"
|
||||
|
||||
sockaddr_u *
|
||||
netof(
|
||||
sockaddr_u *hostaddr
|
||||
)
|
||||
{
|
||||
static sockaddr_u netofbuf[8];
|
||||
static int next_netofbuf;
|
||||
u_int32 netnum;
|
||||
sockaddr_u * netaddr;
|
||||
|
||||
netaddr = &netofbuf[next_netofbuf];
|
||||
next_netofbuf = (next_netofbuf + 1) % COUNTOF(netofbuf);
|
||||
|
||||
memcpy(netaddr, hostaddr, sizeof(*netaddr));
|
||||
|
||||
if (IS_IPV4(netaddr)) {
|
||||
netnum = SRCADR(netaddr);
|
||||
|
||||
/*
|
||||
* We live in a modern CIDR world where the basement nets, which
|
||||
* used to be class A, are now probably associated with each
|
||||
* host address. So, for class-A nets, all bits are significant.
|
||||
*/
|
||||
if (IN_CLASSC(netnum))
|
||||
netnum &= 0xffffff00;
|
||||
else if (IN_CLASSB(netnum))
|
||||
netnum &= 0xffff0000;
|
||||
|
||||
SET_ADDR4(netaddr, netnum);
|
||||
|
||||
} else if (IS_IPV6(netaddr))
|
||||
/* assume the typical /64 subnet size */
|
||||
zero_mem(&NSRCADR6(netaddr)[8], 8);
|
||||
#ifdef NTP_DEBUG
|
||||
else {
|
||||
msyslog(LOG_ERR, "netof unknown AF %d", AF(netaddr));
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
#endif
|
||||
|
||||
return netaddr;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,634 @@
|
||||
/*
|
||||
* ntp_calgps.c - calendar for GPS/GNSS based clocks
|
||||
*
|
||||
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
|
||||
* The contents of 'html/copyright.html' apply.
|
||||
*
|
||||
* --------------------------------------------------------------------
|
||||
*
|
||||
* This module implements stuff often used with GPS/GNSS receivers
|
||||
*/
|
||||
|
||||
#include <ipntp_config.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "ntp_types.h"
|
||||
#include "ntp_calendar.h"
|
||||
#include "ntp_calgps.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_unixtime.h"
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "ntpd.h"
|
||||
#include "vint64ops.h"
|
||||
|
||||
/* ====================================================================
|
||||
* misc. helpers -- might go elsewhere sometime?
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
l_fp
|
||||
ntpfp_with_fudge(
|
||||
l_fp lfp,
|
||||
double ofs
|
||||
)
|
||||
{
|
||||
l_fp fpo;
|
||||
/* calculate 'lfp - ofs' as '(l_fp)(-ofs) + lfp': negating a
|
||||
* double is cheap, as it only flips one bit...
|
||||
*/
|
||||
ofs = -ofs;
|
||||
DTOLFP(ofs, &fpo);
|
||||
L_ADD(&fpo, &lfp);
|
||||
return fpo;
|
||||
}
|
||||
|
||||
|
||||
/* ====================================================================
|
||||
* GPS calendar functions
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* normalization functions for day/time and week/time representations.
|
||||
* Since we only use moderate offsets (leap second corrections and
|
||||
* alike) it does not really pay off to do a floor-corrected division
|
||||
* here. We use compare/decrement/increment loops instead.
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
_norm_ntp_datum(
|
||||
TNtpDatum * datum
|
||||
)
|
||||
{
|
||||
static const int32_t limit = SECSPERDAY;
|
||||
|
||||
if (datum->secs >= limit) {
|
||||
do
|
||||
++datum->days;
|
||||
while ((datum->secs -= limit) >= limit);
|
||||
} else if (datum->secs < 0) {
|
||||
do
|
||||
--datum->days;
|
||||
while ((datum->secs += limit) < 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_norm_gps_datum(
|
||||
TGpsDatum * datum
|
||||
)
|
||||
{
|
||||
static const int32_t limit = 7 * SECSPERDAY;
|
||||
|
||||
if (datum->wsecs >= limit) {
|
||||
do
|
||||
++datum->weeks;
|
||||
while ((datum->wsecs -= limit) >= limit);
|
||||
} else if (datum->wsecs < 0) {
|
||||
do
|
||||
--datum->weeks;
|
||||
while ((datum->wsecs += limit) < 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Add an offset to a day/time and week/time representation.
|
||||
*
|
||||
* !!Attention!! the offset should be small, compared to the time period
|
||||
* (either a day or a week).
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
gpsntp_add_offset(
|
||||
TNtpDatum * datum,
|
||||
l_fp offset
|
||||
)
|
||||
{
|
||||
/* fraction can be added easily */
|
||||
datum->frac += offset.l_uf;
|
||||
datum->secs += (datum->frac < offset.l_uf);
|
||||
|
||||
/* avoid integer overflow on the seconds */
|
||||
if (offset.l_ui >= INT32_MAX)
|
||||
datum->secs -= (int32_t)~offset.l_ui + 1;
|
||||
else
|
||||
datum->secs += (int32_t)offset.l_ui;
|
||||
_norm_ntp_datum(datum);
|
||||
}
|
||||
|
||||
void
|
||||
gpscal_add_offset(
|
||||
TGpsDatum * datum,
|
||||
l_fp offset
|
||||
)
|
||||
{
|
||||
/* fraction can be added easily */
|
||||
datum->frac += offset.l_uf;
|
||||
datum->wsecs += (datum->frac < offset.l_uf);
|
||||
|
||||
|
||||
/* avoid integer overflow on the seconds */
|
||||
if (offset.l_ui >= INT32_MAX)
|
||||
datum->wsecs -= (int32_t)~offset.l_ui + 1;
|
||||
else
|
||||
datum->wsecs += (int32_t)offset.l_ui;
|
||||
_norm_gps_datum(datum);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------
|
||||
* API functions civil calendar and NTP datum
|
||||
* -------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static TNtpDatum
|
||||
_gpsntp_fix_gps_era(
|
||||
TcNtpDatum * in
|
||||
)
|
||||
{
|
||||
/* force result in basedate era
|
||||
*
|
||||
* When calculating this directly in days, we have to execute a
|
||||
* real modulus calculation, since we're obviously not doing a
|
||||
* modulus by a power of 2. Executing this as true floor mod
|
||||
* needs some care and is done under explicit usage of one's
|
||||
* complement and masking to get mostly branchless code.
|
||||
*/
|
||||
static uint32_t const clen = 7*1024;
|
||||
|
||||
uint32_t base, days, sign;
|
||||
TNtpDatum out = *in;
|
||||
|
||||
/* Get base in NTP day scale. No overflows here. */
|
||||
base = (basedate_get_gpsweek() + GPSNTP_WSHIFT) * 7
|
||||
- GPSNTP_DSHIFT;
|
||||
days = out.days;
|
||||
|
||||
sign = (uint32_t)-(days < base);
|
||||
days = sign ^ (days - base);
|
||||
days %= clen;
|
||||
days = base + (sign & clen) + (sign ^ days);
|
||||
|
||||
out.days = days;
|
||||
return out;
|
||||
}
|
||||
|
||||
TNtpDatum
|
||||
gpsntp_fix_gps_era(
|
||||
TcNtpDatum * in
|
||||
)
|
||||
{
|
||||
TNtpDatum out = *in;
|
||||
_norm_ntp_datum(&out);
|
||||
return _gpsntp_fix_gps_era(&out);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
static TNtpDatum
|
||||
_gpsntp_from_daytime(
|
||||
TcCivilDate * jd,
|
||||
l_fp fofs,
|
||||
TcNtpDatum * pivot,
|
||||
int warp
|
||||
)
|
||||
{
|
||||
static const int32_t shift = SECSPERDAY / 2;
|
||||
|
||||
TNtpDatum retv;
|
||||
|
||||
/* set result based on pivot -- ops order is important here */
|
||||
ZERO(retv);
|
||||
retv.secs = ntpcal_date_to_daysec(jd);
|
||||
gpsntp_add_offset(&retv, fofs); /* result is normalized */
|
||||
retv.days = pivot->days;
|
||||
|
||||
/* Manual periodic extension without division: */
|
||||
if (pivot->secs < shift) {
|
||||
int32_t lim = pivot->secs + shift;
|
||||
retv.days -= (retv.secs > lim ||
|
||||
(retv.secs == lim && retv.frac >= pivot->frac));
|
||||
} else {
|
||||
int32_t lim = pivot->secs - shift;
|
||||
retv.days += (retv.secs < lim ||
|
||||
(retv.secs == lim && retv.frac < pivot->frac));
|
||||
}
|
||||
return warp ? _gpsntp_fix_gps_era(&retv) : retv;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* Given the time-of-day part of a civil datum and an additional
|
||||
* (fractional) offset, calculate a full time stamp around a given pivot
|
||||
* time so that the difference between the pivot and the resulting time
|
||||
* stamp is less or equal to 12 hours absolute.
|
||||
*/
|
||||
TNtpDatum
|
||||
gpsntp_from_daytime2_ex(
|
||||
TcCivilDate * jd,
|
||||
l_fp fofs,
|
||||
TcNtpDatum * pivot,
|
||||
int/*BOOL*/ warp
|
||||
)
|
||||
{
|
||||
TNtpDatum dpiv = *pivot;
|
||||
_norm_ntp_datum(&dpiv);
|
||||
return _gpsntp_from_daytime(jd, fofs, &dpiv, warp);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* This works similar to 'gpsntp_from_daytime1()' and actually even uses
|
||||
* it, but the pivot is calculated from the pivot given as 'l_fp' in NTP
|
||||
* time scale. This is in turn expanded around the current system time,
|
||||
* and the resulting absolute pivot is then used to calculate the full
|
||||
* NTP time stamp.
|
||||
*/
|
||||
TNtpDatum
|
||||
gpsntp_from_daytime1_ex(
|
||||
TcCivilDate * jd,
|
||||
l_fp fofs,
|
||||
l_fp pivot,
|
||||
int/*BOOL*/ warp
|
||||
)
|
||||
{
|
||||
vint64 pvi64;
|
||||
TNtpDatum dpiv;
|
||||
ntpcal_split split;
|
||||
|
||||
pvi64 = ntpcal_ntp_to_ntp(pivot.l_ui, NULL);
|
||||
split = ntpcal_daysplit(&pvi64);
|
||||
dpiv.days = split.hi;
|
||||
dpiv.secs = split.lo;
|
||||
dpiv.frac = pivot.l_uf;
|
||||
return _gpsntp_from_daytime(jd, fofs, &dpiv, warp);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* Given a calendar date, zap it into a GPS time format and then convert
|
||||
* that one into the NTP time scale.
|
||||
*/
|
||||
TNtpDatum
|
||||
gpsntp_from_calendar_ex(
|
||||
TcCivilDate * jd,
|
||||
l_fp fofs,
|
||||
int/*BOOL*/ warp
|
||||
)
|
||||
{
|
||||
TGpsDatum gps;
|
||||
gps = gpscal_from_calendar_ex(jd, fofs, warp);
|
||||
return gpsntp_from_gpscal_ex(&gps, FALSE);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* create a civil calendar datum from a NTP date representation
|
||||
*/
|
||||
void
|
||||
gpsntp_to_calendar(
|
||||
TCivilDate * cd,
|
||||
TcNtpDatum * nd
|
||||
)
|
||||
{
|
||||
memset(cd, 0, sizeof(*cd));
|
||||
ntpcal_rd_to_date(
|
||||
cd,
|
||||
nd->days + DAY_NTP_STARTS + ntpcal_daysec_to_date(
|
||||
cd, nd->secs));
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* get day/tod representation from week/tow datum
|
||||
*/
|
||||
TNtpDatum
|
||||
gpsntp_from_gpscal_ex(
|
||||
TcGpsDatum * gd,
|
||||
int/*BOOL*/ warp
|
||||
)
|
||||
{
|
||||
TNtpDatum retv;
|
||||
vint64 ts64;
|
||||
ntpcal_split split;
|
||||
TGpsDatum date = *gd;
|
||||
|
||||
if (warp) {
|
||||
uint32_t base = basedate_get_gpsweek() + GPSNTP_WSHIFT;
|
||||
_norm_gps_datum(&date);
|
||||
date.weeks = ((date.weeks - base) & 1023u) + base;
|
||||
}
|
||||
|
||||
ts64 = ntpcal_weekjoin(date.weeks, date.wsecs);
|
||||
ts64 = subv64u32(&ts64, (GPSNTP_DSHIFT * SECSPERDAY));
|
||||
split = ntpcal_daysplit(&ts64);
|
||||
|
||||
retv.frac = gd->frac;
|
||||
retv.secs = split.lo;
|
||||
retv.days = split.hi;
|
||||
return retv;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* get LFP from ntp datum
|
||||
*/
|
||||
l_fp
|
||||
ntpfp_from_ntpdatum(
|
||||
TcNtpDatum * nd
|
||||
)
|
||||
{
|
||||
l_fp retv;
|
||||
|
||||
retv.l_uf = nd->frac;
|
||||
retv.l_ui = nd->days * (uint32_t)SECSPERDAY
|
||||
+ nd->secs;
|
||||
return retv;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------
|
||||
* API functions GPS week calendar
|
||||
*
|
||||
* Here we use a calendar base of 1899-12-31, so the NTP epoch has
|
||||
* { 0, 86400.0 } in this representation.
|
||||
* -------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static TGpsDatum
|
||||
_gpscal_fix_gps_era(
|
||||
TcGpsDatum * in
|
||||
)
|
||||
{
|
||||
/* force result in basedate era
|
||||
*
|
||||
* This is based on calculating the modulus to a power of two,
|
||||
* so signed integer overflow does not affect the result. Which
|
||||
* in turn makes for a very compact calculation...
|
||||
*/
|
||||
uint32_t base, week;
|
||||
TGpsDatum out = *in;
|
||||
|
||||
week = out.weeks;
|
||||
base = basedate_get_gpsweek() + GPSNTP_WSHIFT;
|
||||
week = base + ((week - base) & (GPSWEEKS - 1));
|
||||
out.weeks = week;
|
||||
return out;
|
||||
}
|
||||
|
||||
TGpsDatum
|
||||
gpscal_fix_gps_era(
|
||||
TcGpsDatum * in
|
||||
)
|
||||
{
|
||||
TGpsDatum out = *in;
|
||||
_norm_gps_datum(&out);
|
||||
return _gpscal_fix_gps_era(&out);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* Given a calendar date, zap it into a GPS time format and the do a
|
||||
* proper era mapping in the GPS time scale, based on the GPS base date,
|
||||
* if so requested.
|
||||
*
|
||||
* This function also augments the century if just a 2-digit year
|
||||
* (0..99) is provided on input.
|
||||
*
|
||||
* This is a fail-safe against GPS receivers with an unknown starting
|
||||
* point for their internal calendar calculation and therefore
|
||||
* unpredictable (but reproducible!) rollover behavior. While there
|
||||
* *are* receivers that create a full date in the proper way, many
|
||||
* others just don't. The overall damage is minimized by simply not
|
||||
* trusting the era mapping of the receiver and doing the era assignment
|
||||
* with a configurable base date *inside* ntpd.
|
||||
*/
|
||||
TGpsDatum
|
||||
gpscal_from_calendar_ex(
|
||||
TcCivilDate * jd,
|
||||
l_fp fofs,
|
||||
int/*BOOL*/ warp
|
||||
)
|
||||
{
|
||||
/* (-DAY_GPS_STARTS) (mod 7*1024) -- complement of cycle shift */
|
||||
static const uint32_t s_compl_shift =
|
||||
(7 * 1024) - DAY_GPS_STARTS % (7 * 1024);
|
||||
|
||||
TGpsDatum gps;
|
||||
TCivilDate cal;
|
||||
int32_t days, week;
|
||||
|
||||
/* if needed, convert from 2-digit year to full year
|
||||
* !!NOTE!! works only between 1980 and 2079!
|
||||
*/
|
||||
cal = *jd;
|
||||
if (cal.year < 80)
|
||||
cal.year += 2000;
|
||||
else if (cal.year < 100)
|
||||
cal.year += 1900;
|
||||
|
||||
/* get RDN from date, possibly adjusting the century */
|
||||
again: if (cal.month && cal.monthday) { /* use Y/M/D civil date */
|
||||
days = ntpcal_date_to_rd(&cal);
|
||||
} else { /* using Y/DoY date */
|
||||
days = ntpcal_year_to_ystart(cal.year)
|
||||
+ (int32_t)cal.yearday
|
||||
- 1; /* both RDN and yearday start with '1'. */
|
||||
}
|
||||
|
||||
/* Rebase to days after the GPS epoch. 'days' is positive here,
|
||||
* but it might be less than the GPS epoch start. Depending on
|
||||
* the input, we have to do different things to get the desired
|
||||
* result. (Since we want to remap the era anyway, we only have
|
||||
* to retain congruential identities....)
|
||||
*/
|
||||
|
||||
if (days >= DAY_GPS_STARTS) {
|
||||
/* simply shift to days since GPS epoch */
|
||||
days -= DAY_GPS_STARTS;
|
||||
} else if (jd->year < 100) {
|
||||
/* Two-digit year on input: add another century and
|
||||
* retry. This can happen only if the century expansion
|
||||
* yielded a date between 1980-01-01 and 1980-01-05,
|
||||
* both inclusive. We have at most one retry here.
|
||||
*/
|
||||
cal.year += 100;
|
||||
goto again;
|
||||
} else {
|
||||
/* A very bad date before the GPS epoch. There's not
|
||||
* much we can do, except to add the complement of
|
||||
* DAY_GPS_STARTS % (7 * 1024) here, that is, use a
|
||||
* congruential identity: Add the complement instead of
|
||||
* subtracting the value gives a value with the same
|
||||
* modulus. But of course, now we MUST to go through a
|
||||
* cycle fix... because the date was obviously wrong!
|
||||
*/
|
||||
warp = TRUE;
|
||||
days += s_compl_shift;
|
||||
}
|
||||
|
||||
/* Splitting to weeks is simple now: */
|
||||
week = days / 7;
|
||||
days -= week * 7;
|
||||
|
||||
/* re-base on start of NTP with weeks mapped to 1024 weeks
|
||||
* starting with the GPS base day set in the calendar.
|
||||
*/
|
||||
gps.weeks = week + GPSNTP_WSHIFT;
|
||||
gps.wsecs = days * SECSPERDAY + ntpcal_date_to_daysec(&cal);
|
||||
gps.frac = 0;
|
||||
gpscal_add_offset(&gps, fofs);
|
||||
return warp ? _gpscal_fix_gps_era(&gps) : gps;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* get civil date from week/tow representation
|
||||
*/
|
||||
void
|
||||
gpscal_to_calendar(
|
||||
TCivilDate * cd,
|
||||
TcGpsDatum * wd
|
||||
)
|
||||
{
|
||||
TNtpDatum nd;
|
||||
|
||||
memset(cd, 0, sizeof(*cd));
|
||||
nd = gpsntp_from_gpscal_ex(wd, FALSE);
|
||||
gpsntp_to_calendar(cd, &nd);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* Given the week and seconds in week, as well as the fraction/offset
|
||||
* (which should/could include the leap seconds offset), unfold the
|
||||
* weeks (which are assumed to have just 10 bits) into expanded weeks
|
||||
* based on the GPS base date derived from the build date (default) or
|
||||
* set by the configuration.
|
||||
*
|
||||
* !NOTE! This function takes RAW GPS weeks, aligned to the GPS start
|
||||
* (1980-01-06) on input. The output weeks will be aligned to NTPD's
|
||||
* week calendar start (1899-12-31)!
|
||||
*/
|
||||
TGpsDatum
|
||||
gpscal_from_gpsweek(
|
||||
uint16_t week,
|
||||
int32_t secs,
|
||||
l_fp fofs
|
||||
)
|
||||
{
|
||||
TGpsDatum retv;
|
||||
|
||||
retv.frac = 0;
|
||||
retv.wsecs = secs;
|
||||
retv.weeks = week + GPSNTP_WSHIFT;
|
||||
gpscal_add_offset(&retv, fofs);
|
||||
return _gpscal_fix_gps_era(&retv);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* internal work horse for time-of-week expansion
|
||||
*/
|
||||
static TGpsDatum
|
||||
_gpscal_from_weektime(
|
||||
int32_t wsecs,
|
||||
l_fp fofs,
|
||||
TcGpsDatum * pivot
|
||||
)
|
||||
{
|
||||
static const int32_t shift = SECSPERWEEK / 2;
|
||||
|
||||
TGpsDatum retv;
|
||||
|
||||
/* set result based on pivot -- ops order is important here */
|
||||
ZERO(retv);
|
||||
retv.wsecs = wsecs;
|
||||
gpscal_add_offset(&retv, fofs); /* result is normalized */
|
||||
retv.weeks = pivot->weeks;
|
||||
|
||||
/* Manual periodic extension without division: */
|
||||
if (pivot->wsecs < shift) {
|
||||
int32_t lim = pivot->wsecs + shift;
|
||||
retv.weeks -= (retv.wsecs > lim ||
|
||||
(retv.wsecs == lim && retv.frac >= pivot->frac));
|
||||
} else {
|
||||
int32_t lim = pivot->wsecs - shift;
|
||||
retv.weeks += (retv.wsecs < lim ||
|
||||
(retv.wsecs == lim && retv.frac < pivot->frac));
|
||||
}
|
||||
return _gpscal_fix_gps_era(&retv);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* expand a time-of-week around a pivot given as week datum
|
||||
*/
|
||||
TGpsDatum
|
||||
gpscal_from_weektime2(
|
||||
int32_t wsecs,
|
||||
l_fp fofs,
|
||||
TcGpsDatum * pivot
|
||||
)
|
||||
{
|
||||
TGpsDatum wpiv = * pivot;
|
||||
_norm_gps_datum(&wpiv);
|
||||
return _gpscal_from_weektime(wsecs, fofs, &wpiv);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* epand a time-of-week around an pivot given as LFP, which in turn
|
||||
* is expanded around the current system time and then converted
|
||||
* into a week datum.
|
||||
*/
|
||||
TGpsDatum
|
||||
gpscal_from_weektime1(
|
||||
int32_t wsecs,
|
||||
l_fp fofs,
|
||||
l_fp pivot
|
||||
)
|
||||
{
|
||||
vint64 pvi64;
|
||||
TGpsDatum wpiv;
|
||||
ntpcal_split split;
|
||||
|
||||
/* get 64-bit pivot in NTP epoch */
|
||||
pvi64 = ntpcal_ntp_to_ntp(pivot.l_ui, NULL);
|
||||
|
||||
/* convert to weeks since 1899-12-31 and seconds in week */
|
||||
pvi64 = addv64u32(&pvi64, (GPSNTP_DSHIFT * SECSPERDAY));
|
||||
split = ntpcal_weeksplit(&pvi64);
|
||||
|
||||
wpiv.weeks = split.hi;
|
||||
wpiv.wsecs = split.lo;
|
||||
wpiv.frac = pivot.l_uf;
|
||||
return _gpscal_from_weektime(wsecs, fofs, &wpiv);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* get week/tow representation from day/tod datum
|
||||
*/
|
||||
TGpsDatum
|
||||
gpscal_from_gpsntp(
|
||||
TcNtpDatum * gd
|
||||
)
|
||||
{
|
||||
TGpsDatum retv;
|
||||
vint64 ts64;
|
||||
ntpcal_split split;
|
||||
|
||||
ts64 = ntpcal_dayjoin(gd->days, gd->secs);
|
||||
ts64 = addv64u32(&ts64, (GPSNTP_DSHIFT * SECSPERDAY));
|
||||
split = ntpcal_weeksplit(&ts64);
|
||||
|
||||
retv.frac = gd->frac;
|
||||
retv.wsecs = split.lo;
|
||||
retv.weeks = split.hi;
|
||||
return retv;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* convert week/tow to LFP stamp
|
||||
*/
|
||||
l_fp
|
||||
ntpfp_from_gpsdatum(
|
||||
TcGpsDatum * gd
|
||||
)
|
||||
{
|
||||
l_fp retv;
|
||||
|
||||
retv.l_uf = gd->frac;
|
||||
retv.l_ui = gd->weeks * (uint32_t)SECSPERWEEK
|
||||
+ (uint32_t)gd->wsecs
|
||||
- (uint32_t)SECSPERDAY * GPSNTP_DSHIFT;
|
||||
return retv;
|
||||
}
|
||||
|
||||
/* -*-EOF-*- */
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Crypto-quality random number functions
|
||||
*
|
||||
* Author: Harlan Stenn, 2014
|
||||
*
|
||||
* This file is Copyright (c) 2014 by Network Time Foundation.
|
||||
* BSD terms apply: see the file COPYRIGHT in the distribution root for details.
|
||||
*/
|
||||
|
||||
#include "ipntp_config.h"
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#include <l_stdlib.h>
|
||||
#include <ntp_random.h>
|
||||
#include "safecast.h"
|
||||
|
||||
#ifdef USE_OPENSSL_CRYPTO_RAND
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
int crypto_rand_init = 0;
|
||||
#else
|
||||
|
||||
# ifndef HAVE_ARC4RANDOM_BUF
|
||||
void
|
||||
evutil_secure_rng_get_bytes(void *buf, size_t nbytes);
|
||||
|
||||
#ifndef SYS_VXWORKS
|
||||
static void
|
||||
arc4random_buf(void *buf, size_t nbytes);
|
||||
|
||||
static void
|
||||
arc4random_buf(void *buf, size_t nbytes)
|
||||
{
|
||||
evutil_secure_rng_get_bytes(buf, nbytes);
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* As of late 2014, here's how we plan to provide cryptographic-quality
|
||||
* random numbers:
|
||||
*
|
||||
* - If we are building with OpenSSL, use RAND_poll() and RAND_bytes().
|
||||
* - Otherwise, use arc4random().
|
||||
*
|
||||
* Use of arc4random() can be forced using configure --disable-openssl-random
|
||||
*
|
||||
* We can count on arc4random existing, thru the OS or thru libevent.
|
||||
* The quality of arc4random depends on the implementor.
|
||||
*
|
||||
* RAND_poll() doesn't show up until XXX. If it's not present, we
|
||||
* need to either provide our own or use arc4random().
|
||||
*/
|
||||
|
||||
/*
|
||||
* ntp_crypto_srandom:
|
||||
*
|
||||
* Initialize the random number generator, if needed by the underlying
|
||||
* crypto random number generation mechanism.
|
||||
*/
|
||||
|
||||
void
|
||||
ntp_crypto_srandom(
|
||||
void
|
||||
)
|
||||
{
|
||||
#ifdef USE_OPENSSL_CRYPTO_RAND
|
||||
if (!crypto_rand_init) {
|
||||
RAND_poll();
|
||||
crypto_rand_init = 1;
|
||||
}
|
||||
#else
|
||||
/* No initialization needed for arc4random() */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ntp_crypto_random_buf:
|
||||
*
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
ntp_crypto_random_buf(
|
||||
void *buf,
|
||||
size_t nbytes
|
||||
)
|
||||
{
|
||||
#ifdef USE_OPENSSL_CRYPTO_RAND
|
||||
int rc;
|
||||
|
||||
rc = RAND_bytes(buf, size2int_chk(nbytes));
|
||||
if (1 != rc) {
|
||||
unsigned long err;
|
||||
char *err_str;
|
||||
|
||||
err = ERR_get_error();
|
||||
err_str = ERR_error_string(err, NULL);
|
||||
/* XXX: Log the error */
|
||||
(void)&err_str;
|
||||
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
#ifndef SYS_VXWORKS
|
||||
|
||||
arc4random_buf(buf, nbytes);
|
||||
#endif
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* getopt - get option letter from argv
|
||||
*
|
||||
* This is a version of the public domain getopt() implementation by
|
||||
* Henry Spencer, changed for 4.3BSD compatibility (in addition to System V).
|
||||
* It allows rescanning of an option list by setting optind to 0 before
|
||||
* calling, which is why we use it even if the system has its own (in fact,
|
||||
* this one has a unique name so as not to conflict with the system's).
|
||||
* Thanks to Dennis Ferguson for the appropriate modifications.
|
||||
*
|
||||
* This file is in the Public Domain.
|
||||
*/
|
||||
|
||||
/*LINTLIBRARY*/
|
||||
|
||||
#include <ipntp_config.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
#ifdef lint
|
||||
#undef putc
|
||||
#define putc fputc
|
||||
#endif /* lint */
|
||||
|
||||
char *ntp_optarg; /* Global argument pointer. */
|
||||
int ntp_optind = 0; /* Global argv index. */
|
||||
int ntp_opterr = 1; /* for compatibility, should error be printed? */
|
||||
int ntp_optopt; /* for compatibility, option character checked */
|
||||
|
||||
static char *scan = NULL; /* Private scan pointer. */
|
||||
static const char *prog = "amnesia";
|
||||
|
||||
|
||||
void clear_opt(void)
|
||||
{
|
||||
ntp_optarg = NULL;
|
||||
ntp_optind = 0;
|
||||
ntp_opterr = 1;
|
||||
ntp_optopt = 0;
|
||||
|
||||
scan = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print message about a bad option.
|
||||
*/
|
||||
static int
|
||||
badopt(
|
||||
const char *mess,
|
||||
int ch
|
||||
)
|
||||
{
|
||||
if (ntp_opterr) {
|
||||
fputs(prog, stderr);
|
||||
fputs(mess, stderr);
|
||||
(void) putc(ch, stderr);
|
||||
(void) putc('\n', stderr);
|
||||
}
|
||||
return ('?');
|
||||
}
|
||||
|
||||
int
|
||||
ntp_getopt(
|
||||
int argc,
|
||||
char *argv[],
|
||||
const char *optstring
|
||||
)
|
||||
{
|
||||
register char c;
|
||||
register const char *place;
|
||||
|
||||
prog = argv[0];
|
||||
ntp_optarg = NULL;
|
||||
|
||||
if (ntp_optind == 0) {
|
||||
scan = NULL;
|
||||
ntp_optind++;
|
||||
}
|
||||
|
||||
if (scan == NULL || *scan == '\0') {
|
||||
if (ntp_optind >= argc
|
||||
|| argv[ntp_optind][0] != '-'
|
||||
|| argv[ntp_optind][1] == '\0') {
|
||||
return (EOF);
|
||||
}
|
||||
if (argv[ntp_optind][1] == '-'
|
||||
&& argv[ntp_optind][2] == '\0') {
|
||||
ntp_optind++;
|
||||
return (EOF);
|
||||
}
|
||||
|
||||
scan = argv[ntp_optind++]+1;
|
||||
}
|
||||
|
||||
c = *scan++;
|
||||
ntp_optopt = c & 0377;
|
||||
for (place = optstring; place != NULL && *place != '\0'; ++place)
|
||||
if (*place == c)
|
||||
break;
|
||||
|
||||
if (place == NULL || *place == '\0' || c == ':' || c == '?') {
|
||||
return (badopt(": unknown option -", c));
|
||||
}
|
||||
|
||||
place++;
|
||||
if (*place == ':') {
|
||||
if (*scan != '\0') {
|
||||
ntp_optarg = scan;
|
||||
scan = NULL;
|
||||
} else if (ntp_optind >= argc) {
|
||||
return (badopt(": option requires argument -", c));
|
||||
} else {
|
||||
ntp_optarg = argv[ntp_optind++];
|
||||
}
|
||||
}
|
||||
|
||||
return (c & 0377);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* ntp_libopts.c
|
||||
*
|
||||
* Common code interfacing with Autogen's libopts command-line option
|
||||
* processing.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include "ntp_libopts.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
extern const char *Version; /* version.c for each program */
|
||||
|
||||
|
||||
/*
|
||||
* ntpOptionProcess() was a clone of libopts' optionProcess which
|
||||
* overrode the --version output, appending detail from version.c
|
||||
* which was not available at Autogen time. This is now done via
|
||||
* AutoOpts' version-proc = override in copyright.def, so this
|
||||
* routine is a straightforward wrapper of optionProcess().
|
||||
*/
|
||||
int
|
||||
ntpOptionProcess(
|
||||
tOptions * pOpts,
|
||||
int argc,
|
||||
char ** argv
|
||||
)
|
||||
{
|
||||
return optionProcess(pOpts, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ntpOptionPrintVersion() replaces the stock optionPrintVersion() via
|
||||
* version-proc = ntpOptionPrintVersion; in copyright.def. It differs
|
||||
* from the stock function by displaying the complete version string,
|
||||
* including compile time which was unknown when Autogen ran.
|
||||
*
|
||||
* Like optionPrintVersion() this function must exit(0) rather than
|
||||
* return.
|
||||
*/
|
||||
void
|
||||
ntpOptionPrintVersion(
|
||||
tOptions * pOpts,
|
||||
tOptDesc * pOD
|
||||
)
|
||||
{
|
||||
UNUSED_ARG(pOpts);
|
||||
UNUSED_ARG(pOD);
|
||||
|
||||
printf("%s\n", Version);
|
||||
fflush(stdout);
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* ntp_lineedit.c - generic interface to various line editing libs
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "ntp_mem.h"
|
||||
|
||||
#if defined(HAVE_READLINE_HISTORY) && \
|
||||
(!defined(HAVE_READLINE_HISTORY_H) || \
|
||||
!defined(HAVE_READLINE_READLINE_H))
|
||||
# undef HAVE_READLINE_HISTORY
|
||||
#endif
|
||||
#if defined(HAVE_READLINE_HISTORY)
|
||||
# include <readline/readline.h>
|
||||
# include <readline/history.h>
|
||||
# define LE_READLINE
|
||||
#elif defined(HAVE_HISTEDIT_H)
|
||||
# include <histedit.h>
|
||||
# define LE_EDITLINE
|
||||
#else
|
||||
# define LE_NONE
|
||||
#endif
|
||||
|
||||
#include "ntp.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_lineedit.h"
|
||||
#include "safecast.h"
|
||||
|
||||
#define MAXEDITLINE 512
|
||||
|
||||
/*
|
||||
* external references
|
||||
*/
|
||||
|
||||
extern char const * progname;
|
||||
|
||||
/*
|
||||
* globals, private prototypes
|
||||
*/
|
||||
|
||||
static int ntp_readline_initted;
|
||||
static char * lineedit_prompt;
|
||||
|
||||
|
||||
#ifdef LE_EDITLINE
|
||||
# ifndef H_SETSIZE
|
||||
# define H_SETSIZE H_EVENT
|
||||
# endif
|
||||
static EditLine * ntp_el;
|
||||
static History * ntp_hist;
|
||||
static HistEvent hev;
|
||||
|
||||
char * ntp_prompt_callback(EditLine *);
|
||||
#endif /* LE_EDITLINE */
|
||||
|
||||
|
||||
/*
|
||||
* ntp_readline_init - setup, set or reset prompt string
|
||||
*/
|
||||
int
|
||||
ntp_readline_init(
|
||||
const char * prompt
|
||||
)
|
||||
{
|
||||
int success;
|
||||
|
||||
success = 1;
|
||||
|
||||
if (prompt) {
|
||||
if (lineedit_prompt)
|
||||
efree((void *)lineedit_prompt);
|
||||
lineedit_prompt = estrdup(prompt);
|
||||
}
|
||||
|
||||
#ifdef LE_EDITLINE
|
||||
if (NULL == ntp_el) {
|
||||
|
||||
# if 4 == EL_INIT_ARGS
|
||||
ntp_el = el_init(progname, stdin, stdout, stderr);
|
||||
# else
|
||||
ntp_el = el_init(progname, stdin, stdout);
|
||||
# endif
|
||||
if (ntp_el) {
|
||||
|
||||
el_set(ntp_el, EL_PROMPT, ntp_prompt_callback);
|
||||
el_set(ntp_el, EL_EDITOR, "emacs");
|
||||
|
||||
ntp_hist = history_init();
|
||||
|
||||
if (NULL == ntp_hist) {
|
||||
|
||||
mfprintf(stderr, "history_init(): %m\n");
|
||||
fflush(stderr);
|
||||
|
||||
el_end(ntp_el);
|
||||
ntp_el = NULL;
|
||||
|
||||
success = 0;
|
||||
|
||||
} else {
|
||||
ZERO(hev);
|
||||
#ifdef H_SETSIZE
|
||||
history(ntp_hist, &hev, H_SETSIZE, 128);
|
||||
#endif
|
||||
el_set(ntp_el, EL_HIST, history,
|
||||
ntp_hist);
|
||||
/* use any .editrc */
|
||||
el_source(ntp_el, NULL);
|
||||
}
|
||||
} else
|
||||
success = 0;
|
||||
}
|
||||
#endif /* LE_EDITLINE */
|
||||
|
||||
ntp_readline_initted = success;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ntp_readline_uninit - release resources
|
||||
*/
|
||||
void
|
||||
ntp_readline_uninit(
|
||||
void
|
||||
)
|
||||
{
|
||||
#ifdef LE_EDITLINE
|
||||
if (ntp_el) {
|
||||
el_end(ntp_el);
|
||||
ntp_el = NULL;
|
||||
|
||||
history_end(ntp_hist);
|
||||
ntp_hist = NULL;
|
||||
}
|
||||
#endif /* LE_EDITLINE */
|
||||
|
||||
if (lineedit_prompt) {
|
||||
efree(lineedit_prompt);
|
||||
lineedit_prompt = NULL;
|
||||
}
|
||||
|
||||
ntp_readline_initted = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ntp_readline - read a line with the line editor available
|
||||
*
|
||||
* The string returned must be released with free()
|
||||
*/
|
||||
|
||||
char *
|
||||
ntp_readline(
|
||||
int * pcount
|
||||
)
|
||||
{
|
||||
char * line;
|
||||
#ifdef LE_NONE
|
||||
char line_buf[MAXEDITLINE];
|
||||
#endif
|
||||
#ifdef LE_EDITLINE
|
||||
const char * cline;
|
||||
#endif
|
||||
|
||||
if (!ntp_readline_initted)
|
||||
return NULL;
|
||||
|
||||
*pcount = 0;
|
||||
|
||||
#ifdef LE_READLINE
|
||||
line = readline(lineedit_prompt ? lineedit_prompt : "");
|
||||
if (NULL != line) {
|
||||
if (*line) {
|
||||
add_history(line);
|
||||
}
|
||||
*pcount = strlen(line);
|
||||
}
|
||||
#endif /* LE_READLINE */
|
||||
|
||||
#ifdef LE_EDITLINE
|
||||
cline = el_gets(ntp_el, pcount);
|
||||
|
||||
if (NULL != cline && *cline) {
|
||||
history(ntp_hist, &hev, H_ENTER, cline);
|
||||
*pcount = strlen(cline);
|
||||
line = estrdup(cline);
|
||||
} else if (*pcount == -1) {
|
||||
line = NULL;
|
||||
} else {
|
||||
line = estrdup("");
|
||||
}
|
||||
#endif /* LE_EDITLINE */
|
||||
|
||||
#ifdef LE_NONE
|
||||
/* stone hammers */
|
||||
if (lineedit_prompt) {
|
||||
# ifdef VMS
|
||||
/*
|
||||
* work around problem mixing
|
||||
* stdout & stderr
|
||||
*/
|
||||
fputs("", stdout);
|
||||
# endif /* VMS */
|
||||
|
||||
fputs(lineedit_prompt, stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
line = fgets(line_buf, sizeof(line_buf), stdin);
|
||||
if (NULL != line && *line) {
|
||||
*pcount = (int)strlen(line); /* cannot overflow here */
|
||||
line = estrdup(line);
|
||||
} else
|
||||
line = NULL;
|
||||
|
||||
#endif /* LE_NONE */
|
||||
|
||||
|
||||
if (!line) /* EOF */
|
||||
fputs("\n", stderr);
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
#ifdef LE_EDITLINE
|
||||
/*
|
||||
* ntp_prompt_callback - return prompt string to el_gets()
|
||||
*/
|
||||
char *
|
||||
ntp_prompt_callback(
|
||||
EditLine *el
|
||||
)
|
||||
{
|
||||
UNUSED_ARG(el);
|
||||
|
||||
return lineedit_prompt;
|
||||
}
|
||||
#endif /* LE_EDITLINE */
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (c) 1987, 1989 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Arthur David Olson of the National Cancer Institute.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE. */
|
||||
|
||||
/*static char *sccsid = "from: @(#)ctime.c 5.26 (Berkeley) 2/23/91";*/
|
||||
|
||||
/*
|
||||
* This implementation of mktime is lifted straight from the NetBSD (BSD 4.4)
|
||||
* version. I modified it slightly to divorce it from the internals of the
|
||||
* ctime library. Thus this version can't use details of the internal
|
||||
* timezone state file to figure out strange unnormalized struct tm values,
|
||||
* as might result from someone doing date math on the tm struct then passing
|
||||
* it to mktime.
|
||||
*
|
||||
* It just does as well as it can at normalizing the tm input, then does a
|
||||
* binary search of the time space using the system's localtime() function.
|
||||
*
|
||||
* The original binary search was defective in that it didn't consider the
|
||||
* setting of tm_isdst when comparing tm values, causing the search to be
|
||||
* flubbed for times near the dst/standard time changeover. The original
|
||||
* code seems to make up for this by grubbing through the timezone info
|
||||
* whenever the binary search barfed. Since I don't have that luxury in
|
||||
* portable code, I have to take care of tm_isdst in the comparison routine.
|
||||
* This requires knowing how many minutes offset dst is from standard time.
|
||||
*
|
||||
* So, if you live somewhere in the world where dst is not 60 minutes offset,
|
||||
* and your vendor doesn't supply mktime(), you'll have to edit this variable
|
||||
* by hand. Sorry about that.
|
||||
*/
|
||||
|
||||
#include <ipntp_config.h>
|
||||
#include "ntp_machine.h"
|
||||
|
||||
#if !defined(HAVE_MKTIME) || ( !defined(HAVE_TIMEGM) && defined(WANT_TIMEGM) )
|
||||
|
||||
#if SIZEOF_TIME_T >= 8
|
||||
#error libntp supplied mktime()/timegm() do not support 64-bit time_t
|
||||
#endif
|
||||
|
||||
#ifndef DSTMINUTES
|
||||
#define DSTMINUTES 60
|
||||
#endif
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
/* some constants from tzfile.h */
|
||||
#define SECSPERMIN 60
|
||||
#define MINSPERHOUR 60
|
||||
#define HOURSPERDAY 24
|
||||
#define DAYSPERWEEK 7
|
||||
#define DAYSPERNYEAR 365
|
||||
#define DAYSPERLYEAR 366
|
||||
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
|
||||
#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
|
||||
#define MONSPERYEAR 12
|
||||
#define TM_YEAR_BASE 1900
|
||||
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
|
||||
|
||||
static int mon_lengths[2][MONSPERYEAR] = {
|
||||
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
|
||||
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
||||
};
|
||||
|
||||
static int year_lengths[2] = {
|
||||
DAYSPERNYEAR, DAYSPERLYEAR
|
||||
};
|
||||
|
||||
/*
|
||||
** Adapted from code provided by Robert Elz, who writes:
|
||||
** The "best" way to do mktime I think is based on an idea of Bob
|
||||
** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
|
||||
** It does a binary search of the time_t space. Since time_t's are
|
||||
** just 32 bits, its a max of 32 iterations (even at 64 bits it
|
||||
** would still be very reasonable).
|
||||
*/
|
||||
|
||||
#ifndef WRONG
|
||||
#define WRONG (-1)
|
||||
#endif /* !defined WRONG */
|
||||
|
||||
static void
|
||||
normalize(
|
||||
int * tensptr,
|
||||
int * unitsptr,
|
||||
int base
|
||||
)
|
||||
{
|
||||
if (*unitsptr >= base) {
|
||||
*tensptr += *unitsptr / base;
|
||||
*unitsptr %= base;
|
||||
} else if (*unitsptr < 0) {
|
||||
--*tensptr;
|
||||
*unitsptr += base;
|
||||
if (*unitsptr < 0) {
|
||||
*tensptr -= 1 + (-*unitsptr) / base;
|
||||
*unitsptr = base - (-*unitsptr) % base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct tm *
|
||||
mkdst(
|
||||
struct tm * tmp
|
||||
)
|
||||
{
|
||||
/* jds */
|
||||
static struct tm tmbuf;
|
||||
|
||||
tmbuf = *tmp;
|
||||
tmbuf.tm_isdst = 1;
|
||||
tmbuf.tm_min += DSTMINUTES;
|
||||
normalize(&tmbuf.tm_hour, &tmbuf.tm_min, MINSPERHOUR);
|
||||
return &tmbuf;
|
||||
}
|
||||
|
||||
static int
|
||||
tmcomp(
|
||||
register struct tm * atmp,
|
||||
register struct tm * btmp
|
||||
)
|
||||
{
|
||||
register int result;
|
||||
|
||||
/* compare down to the same day */
|
||||
|
||||
if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
|
||||
(result = (atmp->tm_mon - btmp->tm_mon)) == 0)
|
||||
result = (atmp->tm_mday - btmp->tm_mday);
|
||||
|
||||
if(result != 0)
|
||||
return result;
|
||||
|
||||
/* get rid of one-sided dst bias */
|
||||
|
||||
if(atmp->tm_isdst == 1 && !btmp->tm_isdst)
|
||||
btmp = mkdst(btmp);
|
||||
else if(btmp->tm_isdst == 1 && !atmp->tm_isdst)
|
||||
atmp = mkdst(atmp);
|
||||
|
||||
/* compare the rest of the way */
|
||||
|
||||
if ((result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
|
||||
(result = (atmp->tm_min - btmp->tm_min)) == 0)
|
||||
result = atmp->tm_sec - btmp->tm_sec;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static time_t
|
||||
time2(
|
||||
struct tm * tmp,
|
||||
int * okayp,
|
||||
int usezn
|
||||
)
|
||||
{
|
||||
register int dir;
|
||||
register int bits;
|
||||
register int i;
|
||||
register int saved_seconds;
|
||||
time_t t;
|
||||
struct tm yourtm, mytm;
|
||||
|
||||
*okayp = FALSE;
|
||||
yourtm = *tmp;
|
||||
if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0)
|
||||
normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN);
|
||||
normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR);
|
||||
normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY);
|
||||
normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR);
|
||||
while (yourtm.tm_mday <= 0) {
|
||||
--yourtm.tm_year;
|
||||
yourtm.tm_mday +=
|
||||
year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
|
||||
}
|
||||
for ( ; ; ) {
|
||||
i = mon_lengths[isleap(yourtm.tm_year +
|
||||
TM_YEAR_BASE)][yourtm.tm_mon];
|
||||
if (yourtm.tm_mday <= i)
|
||||
break;
|
||||
yourtm.tm_mday -= i;
|
||||
if (++yourtm.tm_mon >= MONSPERYEAR) {
|
||||
yourtm.tm_mon = 0;
|
||||
++yourtm.tm_year;
|
||||
}
|
||||
}
|
||||
saved_seconds = yourtm.tm_sec;
|
||||
yourtm.tm_sec = 0;
|
||||
/*
|
||||
** Calculate the number of magnitude bits in a time_t
|
||||
** (this works regardless of whether time_t is
|
||||
** signed or unsigned, though lint complains if unsigned).
|
||||
*/
|
||||
for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
|
||||
;
|
||||
/*
|
||||
** If time_t is signed, then 0 is the median value,
|
||||
** if time_t is unsigned, then 1 << bits is median.
|
||||
*/
|
||||
t = (t < 0) ? 0 : ((time_t) 1 << bits);
|
||||
for ( ; ; ) {
|
||||
if (usezn)
|
||||
mytm = *localtime(&t);
|
||||
else
|
||||
mytm = *gmtime(&t);
|
||||
dir = tmcomp(&mytm, &yourtm);
|
||||
if (dir != 0) {
|
||||
if (bits-- < 0)
|
||||
return WRONG;
|
||||
if (bits < 0)
|
||||
--t;
|
||||
else if (dir > 0)
|
||||
t -= (time_t) 1 << bits;
|
||||
else t += (time_t) 1 << bits;
|
||||
continue;
|
||||
}
|
||||
if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
|
||||
break;
|
||||
|
||||
return WRONG;
|
||||
}
|
||||
t += saved_seconds;
|
||||
if (usezn)
|
||||
*tmp = *localtime(&t);
|
||||
else
|
||||
*tmp = *gmtime(&t);
|
||||
*okayp = TRUE;
|
||||
return t;
|
||||
}
|
||||
#else
|
||||
int mktime_bs;
|
||||
#endif /* !HAVE_MKTIME || !HAVE_TIMEGM */
|
||||
|
||||
#ifndef HAVE_MKTIME
|
||||
static time_t
|
||||
time1(
|
||||
struct tm * tmp
|
||||
)
|
||||
{
|
||||
register time_t t;
|
||||
int okay;
|
||||
|
||||
if (tmp->tm_isdst > 1)
|
||||
tmp->tm_isdst = 1;
|
||||
t = time2(tmp, &okay, 1);
|
||||
if (okay || tmp->tm_isdst < 0)
|
||||
return t;
|
||||
|
||||
return WRONG;
|
||||
}
|
||||
|
||||
time_t
|
||||
mktime(
|
||||
struct tm * tmp
|
||||
)
|
||||
{
|
||||
return time1(tmp);
|
||||
}
|
||||
#endif /* !HAVE_MKTIME */
|
||||
|
||||
#ifdef WANT_TIMEGM
|
||||
#ifndef HAVE_TIMEGM
|
||||
time_t
|
||||
timegm(
|
||||
struct tm * tmp
|
||||
)
|
||||
{
|
||||
register time_t t;
|
||||
int okay;
|
||||
|
||||
tmp->tm_isdst = 0;
|
||||
t = time2(tmp, &okay, 0);
|
||||
if (okay || tmp->tm_isdst < 0)
|
||||
return t;
|
||||
|
||||
return WRONG;
|
||||
}
|
||||
#endif /* !HAVE_TIMEGM */
|
||||
#endif /* WANT_TIMEGM */
|
||||
@@ -0,0 +1,517 @@
|
||||
/*
|
||||
* Copyright (c) 1983, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD: src/lib/libc/stdlib/random.c,v 1.4.2.2 1999/09/05 11:16:45 peter Exp $
|
||||
*
|
||||
*/
|
||||
#include "ipntp_config.h"
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)random.c 8.2 (Berkeley) 5/19/95";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <l_stdlib.h>
|
||||
#include <ntp_random.h>
|
||||
#include <ntp_unixtime.h>
|
||||
|
||||
/*
|
||||
* random.c:
|
||||
*
|
||||
* An improved random number generation package. In addition to the standard
|
||||
* rand()/srand() like interface, this package also has a special state info
|
||||
* interface. The initstate() routine is called with a seed, an array of
|
||||
* bytes, and a count of how many bytes are being passed in; this array is
|
||||
* then initialized to contain information for random number generation with
|
||||
* that much state information. Good sizes for the amount of state
|
||||
* information are 32, 64, 128, and 256 bytes. The state can be switched by
|
||||
* calling the setstate() routine with the same array as was initiallized
|
||||
* with initstate(). By default, the package runs with 128 bytes of state
|
||||
* information and generates far better random numbers than a linear
|
||||
* congruential generator. If the amount of state information is less than
|
||||
* 32 bytes, a simple linear congruential R.N.G. is used.
|
||||
*
|
||||
* Internally, the state information is treated as an array of longs; the
|
||||
* zeroeth element of the array is the type of R.N.G. being used (small
|
||||
* integer); the remainder of the array is the state information for the
|
||||
* R.N.G. Thus, 32 bytes of state information will give 7 longs worth of
|
||||
* state information, which will allow a degree seven polynomial. (Note:
|
||||
* the zeroeth word of state information also has some other information
|
||||
* stored in it -- see setstate() for details).
|
||||
*
|
||||
* The random number generation technique is a linear feedback shift register
|
||||
* approach, employing trinomials (since there are fewer terms to sum up that
|
||||
* way). In this approach, the least significant bit of all the numbers in
|
||||
* the state table will act as a linear feedback shift register, and will
|
||||
* have period 2^deg - 1 (where deg is the degree of the polynomial being
|
||||
* used, assuming that the polynomial is irreducible and primitive). The
|
||||
* higher order bits will have longer periods, since their values are also
|
||||
* influenced by pseudo-random carries out of the lower bits. The total
|
||||
* period of the generator is approximately deg*(2**deg - 1); thus doubling
|
||||
* the amount of state information has a vast influence on the period of the
|
||||
* generator. Note: the deg*(2**deg - 1) is an approximation only good for
|
||||
* large deg, when the period of the shift register is the dominant factor.
|
||||
* With deg equal to seven, the period is actually much longer than the
|
||||
* 7*(2**7 - 1) predicted by this formula.
|
||||
*
|
||||
* Modified 28 December 1994 by Jacob S. Rosenberg.
|
||||
* The following changes have been made:
|
||||
* All references to the type u_int have been changed to unsigned long.
|
||||
* All references to type int have been changed to type long. Other
|
||||
* cleanups have been made as well. A warning for both initstate and
|
||||
* setstate has been inserted to the effect that on Sparc platforms
|
||||
* the 'arg_state' variable must be forced to begin on word boundaries.
|
||||
* This can be easily done by casting a long integer array to char *.
|
||||
* The overall logic has been left STRICTLY alone. This software was
|
||||
* tested on both a VAX and Sun SpacsStation with exactly the same
|
||||
* results. The new version and the original give IDENTICAL results.
|
||||
* The new version is somewhat faster than the original. As the
|
||||
* documentation says: "By default, the package runs with 128 bytes of
|
||||
* state information and generates far better random numbers than a linear
|
||||
* congruential generator. If the amount of state information is less than
|
||||
* 32 bytes, a simple linear congruential R.N.G. is used." For a buffer of
|
||||
* 128 bytes, this new version runs about 19 percent faster and for a 16
|
||||
* byte buffer it is about 5 percent faster.
|
||||
*/
|
||||
|
||||
/*
|
||||
* For each of the currently supported random number generators, we have a
|
||||
* break value on the amount of state information (you need at least this
|
||||
* many bytes of state info to support this random number generator), a degree
|
||||
* for the polynomial (actually a trinomial) that the R.N.G. is based on, and
|
||||
* the separation between the two lower order coefficients of the trinomial.
|
||||
*/
|
||||
#define TYPE_0 0 /* linear congruential */
|
||||
#define BREAK_0 8
|
||||
#define DEG_0 0
|
||||
#define SEP_0 0
|
||||
|
||||
#define TYPE_1 1 /* x**7 + x**3 + 1 */
|
||||
#define BREAK_1 32
|
||||
#define DEG_1 7
|
||||
#define SEP_1 3
|
||||
|
||||
#define TYPE_2 2 /* x**15 + x + 1 */
|
||||
#define BREAK_2 64
|
||||
#define DEG_2 15
|
||||
#define SEP_2 1
|
||||
|
||||
#define TYPE_3 3 /* x**31 + x**3 + 1 */
|
||||
#define BREAK_3 128
|
||||
#define DEG_3 31
|
||||
#define SEP_3 3
|
||||
|
||||
#define TYPE_4 4 /* x**63 + x + 1 */
|
||||
#define BREAK_4 256
|
||||
#define DEG_4 63
|
||||
#define SEP_4 1
|
||||
|
||||
#define MAX_TYPES 5 /* max number of types above */
|
||||
|
||||
/*
|
||||
* Initially, everything is set up as if from:
|
||||
*
|
||||
* initstate(1, randtbl, 128);
|
||||
*
|
||||
* Note that this initialization takes advantage of the fact that srandom()
|
||||
* advances the front and rear pointers 10*rand_deg times, and hence the
|
||||
* rear pointer which starts at 0 will also end up at zero; thus the zeroeth
|
||||
* element of the state information, which contains info about the current
|
||||
* position of the rear pointer is just
|
||||
*
|
||||
* MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3.
|
||||
*/
|
||||
|
||||
static unsigned long randtbl[DEG_3 + 1] = {
|
||||
TYPE_3,
|
||||
#ifdef USE_WEAK_SEEDING
|
||||
/* Historic implementation compatibility */
|
||||
/* The random sequences do not vary much with the seed */
|
||||
0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 0xde3b81e0, 0xdf0a6fb5,
|
||||
0xf103bc02, 0x48f340fb, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd,
|
||||
0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88,
|
||||
0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc,
|
||||
0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b,
|
||||
0x27fb47b9,
|
||||
#else /* !USE_WEAK_SEEDING */
|
||||
0x991539b1, 0x16a5bce3, 0x6774a4cd, 0x3e01511e, 0x4e508aaa, 0x61048c05,
|
||||
0xf5500617, 0x846b7115, 0x6a19892c, 0x896a97af, 0xdb48f936, 0x14898454,
|
||||
0x37ffd106, 0xb58bff9c, 0x59e17104, 0xcf918a49, 0x09378c83, 0x52c7a471,
|
||||
0x8d293ea9, 0x1f4fc301, 0xc3db71be, 0x39b44e1c, 0xf8a44ef9, 0x4c8b80b1,
|
||||
0x19edc328, 0x87bf4bdd, 0xc9b240e5, 0xe9ee4b1b, 0x4382aee7, 0x535b6b41,
|
||||
0xf3bec5da
|
||||
#endif /* !USE_WEAK_SEEDING */
|
||||
};
|
||||
|
||||
/*
|
||||
* fptr and rptr are two pointers into the state info, a front and a rear
|
||||
* pointer. These two pointers are always rand_sep places aparts, as they
|
||||
* cycle cyclically through the state information. (Yes, this does mean we
|
||||
* could get away with just one pointer, but the code for random() is more
|
||||
* efficient this way). The pointers are left positioned as they would be
|
||||
* from the call
|
||||
*
|
||||
* initstate(1, randtbl, 128);
|
||||
*
|
||||
* (The position of the rear pointer, rptr, is really 0 (as explained above
|
||||
* in the initialization of randtbl) because the state table pointer is set
|
||||
* to point to randtbl[1] (as explained below).
|
||||
*/
|
||||
static unsigned long *fptr = &randtbl[SEP_3 + 1];
|
||||
static unsigned long *rptr = &randtbl[1];
|
||||
|
||||
/*
|
||||
* The following things are the pointer to the state information table, the
|
||||
* type of the current generator, the degree of the current polynomial being
|
||||
* used, and the separation between the two pointers. Note that for efficiency
|
||||
* of random(), we remember the first location of the state information, not
|
||||
* the zeroeth. Hence it is valid to access state[-1], which is used to
|
||||
* store the type of the R.N.G. Also, we remember the last location, since
|
||||
* this is more efficient than indexing every time to find the address of
|
||||
* the last element to see if the front and rear pointers have wrapped.
|
||||
*/
|
||||
static unsigned long *state = &randtbl[1];
|
||||
static long rand_type = TYPE_3;
|
||||
static long rand_deg = DEG_3;
|
||||
static long rand_sep = SEP_3;
|
||||
static unsigned long *end_ptr = &randtbl[DEG_3 + 1];
|
||||
|
||||
|
||||
void clear_ramdom(void)
|
||||
{
|
||||
fptr = &randtbl[SEP_3 + 1];
|
||||
rptr = &randtbl[1];
|
||||
|
||||
state = &randtbl[1];
|
||||
rand_type = TYPE_3;
|
||||
rand_deg = DEG_3;
|
||||
rand_sep = SEP_3;
|
||||
end_ptr = &randtbl[DEG_3 + 1];
|
||||
}
|
||||
|
||||
static inline long good_rand (long);
|
||||
|
||||
static inline long
|
||||
good_rand (
|
||||
register long x
|
||||
)
|
||||
{
|
||||
#ifdef USE_WEAK_SEEDING
|
||||
/*
|
||||
* Historic implementation compatibility.
|
||||
* The random sequences do not vary much with the seed,
|
||||
* even with overflowing.
|
||||
*/
|
||||
return (1103515245 * x + 12345);
|
||||
#else /* !USE_WEAK_SEEDING */
|
||||
/*
|
||||
* Compute x = (7^5 * x) mod (2^31 - 1)
|
||||
* wihout overflowing 31 bits:
|
||||
* (2^31 - 1) = 127773 * (7^5) + 2836
|
||||
* From "Random number generators: good ones are hard to find",
|
||||
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
|
||||
* October 1988, p. 1195.
|
||||
*/
|
||||
register long hi, lo;
|
||||
|
||||
hi = x / 127773;
|
||||
lo = x % 127773;
|
||||
x = 16807 * lo - 2836 * hi;
|
||||
if (x <= 0)
|
||||
x += 0x7fffffff;
|
||||
return (x);
|
||||
#endif /* !USE_WEAK_SEEDING */
|
||||
}
|
||||
|
||||
/*
|
||||
* srandom:
|
||||
*
|
||||
* Initialize the random number generator based on the given seed. If the
|
||||
* type is the trivial no-state-information type, just remember the seed.
|
||||
* Otherwise, initializes state[] based on the given "seed" via a linear
|
||||
* congruential generator. Then, the pointers are set to known locations
|
||||
* that are exactly rand_sep places apart. Lastly, it cycles the state
|
||||
* information a given number of times to get rid of any initial dependencies
|
||||
* introduced by the L.C.R.N.G. Note that the initialization of randtbl[]
|
||||
* for default usage relies on values produced by this routine.
|
||||
*/
|
||||
void
|
||||
ntp_srandom(
|
||||
unsigned long x
|
||||
)
|
||||
{
|
||||
long i;
|
||||
|
||||
if (rand_type == TYPE_0) {
|
||||
state[0] = x;
|
||||
} else {
|
||||
state[0] = x;
|
||||
for (i = 1; i < rand_deg; i++)
|
||||
state[i] = good_rand(state[i - 1]);
|
||||
fptr = &state[rand_sep];
|
||||
rptr = &state[0];
|
||||
for (i = 0; i < 10 * rand_deg; i++)
|
||||
x = ntp_random();
|
||||
}
|
||||
|
||||
/* seed the likely faster (and poorer) rand() as well */
|
||||
srand((u_int)x);
|
||||
}
|
||||
|
||||
/*
|
||||
* srandomdev:
|
||||
*
|
||||
* Many programs choose the seed value in a totally predictable manner.
|
||||
* This often causes problems. We seed the generator using the much more
|
||||
* secure urandom(4) interface. Note that this particular seeding
|
||||
* procedure can generate states which are impossible to reproduce by
|
||||
* calling srandom() with any value, since the succeeding terms in the
|
||||
* state buffer are no longer derived from the LC algorithm applied to
|
||||
* a fixed seed.
|
||||
*/
|
||||
#ifdef NEED_SRANDOMDEV
|
||||
void
|
||||
ntp_srandomdev( void )
|
||||
{
|
||||
struct timeval tv;
|
||||
unsigned long junk; /* Purposely used uninitialized */
|
||||
#ifndef SYS_VXWORKS
|
||||
GETTIMEOFDAY(&tv, NULL);
|
||||
#else
|
||||
(void)ipcom_gettimeofday(&tv, IP_NULL);
|
||||
#endif
|
||||
|
||||
ntp_srandom(getpid() ^ tv.tv_sec ^ tv.tv_usec ^ junk);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* ntp_initstate() and ntp_setstate() are unused in our codebase and
|
||||
* trigger warnings due to casting to a more-strictly-aligned pointer
|
||||
* on alignment-sensitive platforms. #ifdef them away to save noise,
|
||||
* build time, and binary space, but retain the code in case we find a
|
||||
* use.
|
||||
*/
|
||||
#ifdef COMPILE_UNUSED_FUNCTIONS
|
||||
/*
|
||||
* Array versions of the above information to make code run faster --
|
||||
* relies on fact that TYPE_i == i.
|
||||
*/
|
||||
#define MAX_TYPES 5 /* max number of types above */
|
||||
|
||||
static long degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 };
|
||||
static long seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };
|
||||
|
||||
/*
|
||||
* initstate:
|
||||
*
|
||||
* Initialize the state information in the given array of n bytes for future
|
||||
* random number generation. Based on the number of bytes we are given, and
|
||||
* the break values for the different R.N.G.'s, we choose the best (largest)
|
||||
* one we can and set things up for it. srandom() is then called to
|
||||
* initialize the state information.
|
||||
*
|
||||
* Note that on return from srandom(), we set state[-1] to be the type
|
||||
* multiplexed with the current value of the rear pointer; this is so
|
||||
* successive calls to initstate() won't lose this information and will be
|
||||
* able to restart with setstate().
|
||||
*
|
||||
* Note: the first thing we do is save the current state, if any, just like
|
||||
* setstate() so that it doesn't matter when initstate is called.
|
||||
*
|
||||
* Returns a pointer to the old state.
|
||||
*
|
||||
* Note: The Sparc platform requires that arg_state begin on a long
|
||||
* word boundary; otherwise a bus error will occur. Even so, lint will
|
||||
* complain about mis-alignment, but you should disregard these messages.
|
||||
*/
|
||||
char *
|
||||
ntp_initstate(
|
||||
unsigned long seed, /* seed for R.N.G. */
|
||||
char *arg_state, /* pointer to state array */
|
||||
long n /* # bytes of state info */
|
||||
)
|
||||
{
|
||||
register char *ostate = (char *)(&state[-1]);
|
||||
register long *long_arg_state = (long *) arg_state;
|
||||
|
||||
if (rand_type == TYPE_0)
|
||||
state[-1] = rand_type;
|
||||
else
|
||||
state[-1] = MAX_TYPES * (rptr - state) + rand_type;
|
||||
if (n < BREAK_0) {
|
||||
(void)fprintf(stderr,
|
||||
"random: not enough state (%ld bytes); ignored.\n", n);
|
||||
return(0);
|
||||
}
|
||||
if (n < BREAK_1) {
|
||||
rand_type = TYPE_0;
|
||||
rand_deg = DEG_0;
|
||||
rand_sep = SEP_0;
|
||||
} else if (n < BREAK_2) {
|
||||
rand_type = TYPE_1;
|
||||
rand_deg = DEG_1;
|
||||
rand_sep = SEP_1;
|
||||
} else if (n < BREAK_3) {
|
||||
rand_type = TYPE_2;
|
||||
rand_deg = DEG_2;
|
||||
rand_sep = SEP_2;
|
||||
} else if (n < BREAK_4) {
|
||||
rand_type = TYPE_3;
|
||||
rand_deg = DEG_3;
|
||||
rand_sep = SEP_3;
|
||||
} else {
|
||||
rand_type = TYPE_4;
|
||||
rand_deg = DEG_4;
|
||||
rand_sep = SEP_4;
|
||||
}
|
||||
state = (unsigned long *) (long_arg_state + 1); /* first location */
|
||||
end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */
|
||||
ntp_srandom(seed);
|
||||
if (rand_type == TYPE_0)
|
||||
long_arg_state[0] = rand_type;
|
||||
else
|
||||
long_arg_state[0] = MAX_TYPES * (rptr - state) + rand_type;
|
||||
return(ostate);
|
||||
}
|
||||
|
||||
/*
|
||||
* setstate:
|
||||
*
|
||||
* Restore the state from the given state array.
|
||||
*
|
||||
* Note: it is important that we also remember the locations of the pointers
|
||||
* in the current state information, and restore the locations of the pointers
|
||||
* from the old state information. This is done by multiplexing the pointer
|
||||
* location into the zeroeth word of the state information.
|
||||
*
|
||||
* Note that due to the order in which things are done, it is OK to call
|
||||
* setstate() with the same state as the current state.
|
||||
*
|
||||
* Returns a pointer to the old state information.
|
||||
*
|
||||
* Note: The Sparc platform requires that arg_state begin on a long
|
||||
* word boundary; otherwise a bus error will occur. Even so, lint will
|
||||
* complain about mis-alignment, but you should disregard these messages.
|
||||
*/
|
||||
char *
|
||||
ntp_setstate(
|
||||
char *arg_state /* pointer to state array */
|
||||
)
|
||||
{
|
||||
register unsigned long *new_state = (unsigned long *) arg_state;
|
||||
register long type = new_state[0] % MAX_TYPES;
|
||||
register long rear = new_state[0] / MAX_TYPES;
|
||||
char *ostate = (char *)(&state[-1]);
|
||||
|
||||
if (rand_type == TYPE_0)
|
||||
state[-1] = rand_type;
|
||||
else
|
||||
state[-1] = MAX_TYPES * (rptr - state) + rand_type;
|
||||
switch(type) {
|
||||
case TYPE_0:
|
||||
case TYPE_1:
|
||||
case TYPE_2:
|
||||
case TYPE_3:
|
||||
case TYPE_4:
|
||||
rand_type = type;
|
||||
rand_deg = degrees[type];
|
||||
rand_sep = seps[type];
|
||||
break;
|
||||
default:
|
||||
(void)fprintf(stderr,
|
||||
"random: state info corrupted; not changed.\n");
|
||||
}
|
||||
state = (new_state + 1);
|
||||
if (rand_type != TYPE_0) {
|
||||
rptr = &state[rear];
|
||||
fptr = &state[(rear + rand_sep) % rand_deg];
|
||||
}
|
||||
end_ptr = &state[rand_deg]; /* set end_ptr too */
|
||||
return(ostate);
|
||||
}
|
||||
#endif /* COMPILE_UNUSED_FUNCTIONS */
|
||||
|
||||
|
||||
/*
|
||||
* random:
|
||||
*
|
||||
* If we are using the trivial TYPE_0 R.N.G., just do the old linear
|
||||
* congruential bit. Otherwise, we do our fancy trinomial stuff, which is
|
||||
* the same in all the other cases due to all the global variables that have
|
||||
* been set up. The basic operation is to add the number at the rear pointer
|
||||
* into the one at the front pointer. Then both pointers are advanced to
|
||||
* the next location cyclically in the table. The value returned is the sum
|
||||
* generated, reduced to 31 bits by throwing away the "least random" low bit.
|
||||
*
|
||||
* Note: the code takes advantage of the fact that both the front and
|
||||
* rear pointers can't wrap on the same call by not testing the rear
|
||||
* pointer if the front one has wrapped.
|
||||
*
|
||||
* Returns a 31-bit random number.
|
||||
*/
|
||||
long
|
||||
ntp_random( void )
|
||||
{
|
||||
register long i;
|
||||
register unsigned long *f, *r;
|
||||
|
||||
if (rand_type == TYPE_0) {
|
||||
i = state[0];
|
||||
state[0] = i = (good_rand(i)) & 0x7fffffff;
|
||||
} else {
|
||||
/*
|
||||
* Use local variables rather than static variables for speed.
|
||||
*/
|
||||
f = fptr; r = rptr;
|
||||
*f += *r;
|
||||
i = (*f >> 1) & 0x7fffffff; /* chucking least random bit */
|
||||
if (++f >= end_ptr) {
|
||||
f = state;
|
||||
++r;
|
||||
}
|
||||
else if (++r >= end_ptr) {
|
||||
r = state;
|
||||
}
|
||||
|
||||
fptr = f; rptr = r;
|
||||
}
|
||||
return(i);
|
||||
}
|
||||
@@ -0,0 +1,589 @@
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1986, 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Compatability shims with the rfc2553 API to simplify ntp.
|
||||
*/
|
||||
|
||||
#include <ipntp_config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <isc/net.h>
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#include "ntp_rfc2553.h"
|
||||
|
||||
#include "ntpd.h"
|
||||
#include "ntp_malloc.h"
|
||||
#include "ntp_string.h"
|
||||
#include "ntp_debug.h"
|
||||
|
||||
|
||||
/*
|
||||
* copy_addrinfo() - copy a single addrinfo to malloc()'d block.
|
||||
* copy_addrinfo_list() - copy an addrinfo list to malloc()'d block.
|
||||
*
|
||||
* Copies an addrinfo list and its associated data to a contiguous block
|
||||
* of storage from emalloc(). Callback routines invoked via
|
||||
* getaddrinfo_sometime() have access to the resulting addrinfo list
|
||||
* only until they return. This routine provides an easy way to make a
|
||||
* persistent copy. Although the list provided to gai_sometime_callback
|
||||
* routines is similarly contiguous, to keep this code usable in any
|
||||
* context where we might want to duplicate an addrinfo list, it does
|
||||
* not require the input list be contiguous.
|
||||
*
|
||||
* The returned list head pointer is passed to free() to release the
|
||||
* entire list.
|
||||
*
|
||||
* In keeping with the rest of the NTP distribution, sockaddr_u is used
|
||||
* in preference to struct sockaddr_storage, which is a member of the
|
||||
* former union and so compatible.
|
||||
*
|
||||
* The rest of ntp_rfc2553.c is conditioned on ISC_PLATFORM_HAVEIPV6
|
||||
* not being defined, copy_addrinfo_*() are exceptions.
|
||||
*/
|
||||
struct addrinfo * copy_addrinfo_common(const struct addrinfo *, int
|
||||
#ifdef EREALLOC_CALLSITE
|
||||
,
|
||||
const char *, int
|
||||
#endif
|
||||
);
|
||||
|
||||
|
||||
struct addrinfo *
|
||||
copy_addrinfo_impl(
|
||||
const struct addrinfo * src
|
||||
#ifdef EREALLOC_CALLSITE
|
||||
,
|
||||
const char * caller_file,
|
||||
int caller_line
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return copy_addrinfo_common(src, TRUE
|
||||
#ifdef EREALLOC_CALLSITE
|
||||
,
|
||||
caller_file, caller_line
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
struct addrinfo *
|
||||
copy_addrinfo_list_impl(
|
||||
const struct addrinfo * src
|
||||
#ifdef EREALLOC_CALLSITE
|
||||
,
|
||||
const char * caller_file,
|
||||
int caller_line
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return copy_addrinfo_common(src, FALSE
|
||||
#ifdef EREALLOC_CALLSITE
|
||||
,
|
||||
caller_file, caller_line
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
struct addrinfo *
|
||||
copy_addrinfo_common(
|
||||
const struct addrinfo * src,
|
||||
int just_one
|
||||
#ifdef EREALLOC_CALLSITE
|
||||
,
|
||||
const char * caller_file,
|
||||
int caller_line
|
||||
#endif
|
||||
)
|
||||
{
|
||||
const struct addrinfo * ai_src;
|
||||
const struct addrinfo * ai_nxt;
|
||||
struct addrinfo * ai_cpy;
|
||||
struct addrinfo * dst;
|
||||
sockaddr_u * psau;
|
||||
char * pcanon;
|
||||
u_int elements;
|
||||
size_t octets;
|
||||
size_t canons_octets;
|
||||
size_t str_octets;
|
||||
|
||||
elements = 0;
|
||||
canons_octets = 0;
|
||||
|
||||
for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
|
||||
if (just_one)
|
||||
ai_nxt = NULL;
|
||||
else
|
||||
ai_nxt = ai_src->ai_next;
|
||||
++elements;
|
||||
if (NULL != ai_src->ai_canonname)
|
||||
canons_octets += 1 + strlen(ai_src->ai_canonname);
|
||||
}
|
||||
|
||||
octets = elements * (sizeof(*ai_cpy) + sizeof(*psau));
|
||||
octets += canons_octets;
|
||||
|
||||
dst = erealloczsite(NULL, octets, 0, TRUE, caller_file,
|
||||
caller_line);
|
||||
ai_cpy = dst;
|
||||
psau = (void *)(ai_cpy + elements);
|
||||
pcanon = (void *)(psau + elements);
|
||||
|
||||
for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
|
||||
if (just_one)
|
||||
ai_nxt = NULL;
|
||||
else
|
||||
ai_nxt = ai_src->ai_next;
|
||||
*ai_cpy = *ai_src;
|
||||
DEBUG_INSIST(ai_cpy->ai_canonname == ai_src->ai_canonname);
|
||||
INSIST(ai_src->ai_addrlen <= sizeof(sockaddr_u));
|
||||
memcpy(psau, ai_src->ai_addr, ai_src->ai_addrlen);
|
||||
ai_cpy->ai_addr = &psau->sa;
|
||||
++psau;
|
||||
if (NULL != ai_src->ai_canonname) {
|
||||
ai_cpy->ai_canonname = pcanon;
|
||||
str_octets = 1 + strlen(ai_src->ai_canonname);
|
||||
memcpy(pcanon, ai_src->ai_canonname, str_octets);
|
||||
pcanon += str_octets;
|
||||
}
|
||||
if (NULL != ai_cpy->ai_next) {
|
||||
if (just_one)
|
||||
ai_cpy->ai_next = NULL;
|
||||
else
|
||||
ai_cpy->ai_next = ai_cpy + 1;
|
||||
}
|
||||
++ai_cpy;
|
||||
}
|
||||
ENSURE(pcanon == ((char *)dst + octets));
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
#ifndef ISC_PLATFORM_HAVEIPV6
|
||||
|
||||
static char *ai_errlist[] = {
|
||||
"Success",
|
||||
"Address family for hostname not supported", /* EAI_ADDRFAMILY */
|
||||
"Temporary failure in name resolution", /* EAI_AGAIN */
|
||||
"Invalid value for ai_flags", /* EAI_BADFLAGS */
|
||||
"Non-recoverable failure in name resolution", /* EAI_FAIL */
|
||||
"ai_family not supported", /* EAI_FAMILY */
|
||||
"Memory allocation failure", /* EAI_MEMORY */
|
||||
"No address associated with hostname", /* EAI_NODATA */
|
||||
"hostname nor servname provided, or not known", /* EAI_NONAME */
|
||||
"servname not supported for ai_socktype", /* EAI_SERVICE */
|
||||
"ai_socktype not supported", /* EAI_SOCKTYPE */
|
||||
"System error returned in errno", /* EAI_SYSTEM */
|
||||
"Invalid value for hints", /* EAI_BADHINTS */
|
||||
"Resolved protocol is unknown", /* EAI_PROTOCOL */
|
||||
"Unknown error", /* EAI_MAX */
|
||||
};
|
||||
|
||||
/*
|
||||
* Local declaration
|
||||
*/
|
||||
int
|
||||
DNSlookup_name(
|
||||
const char *name,
|
||||
int ai_family,
|
||||
struct hostent **Addresses
|
||||
);
|
||||
|
||||
#ifndef SYS_WINNT
|
||||
/*
|
||||
* Encapsulate gethostbyname to control the error code
|
||||
*/
|
||||
int
|
||||
DNSlookup_name(
|
||||
const char *name,
|
||||
int ai_family,
|
||||
struct hostent **Addresses
|
||||
)
|
||||
{
|
||||
*Addresses = gethostbyname(name);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ADDRINFO
|
||||
|
||||
static int do_nodename (const char *nodename, struct addrinfo *ai,
|
||||
const struct addrinfo *hints);
|
||||
|
||||
int
|
||||
getaddrinfo (const char *nodename, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
{
|
||||
int rval;
|
||||
struct servent *sp;
|
||||
struct addrinfo *ai = NULL;
|
||||
int port;
|
||||
const char *proto = NULL;
|
||||
int family, socktype, flags, protocol;
|
||||
|
||||
|
||||
/*
|
||||
* If no name is provide just return an error
|
||||
*/
|
||||
if (nodename == NULL && servname == NULL)
|
||||
return (EAI_NONAME);
|
||||
|
||||
ai = emalloc(sizeof(struct addrinfo));
|
||||
if (ai == NULL)
|
||||
return (EAI_MEMORY);
|
||||
|
||||
/*
|
||||
* Copy default values from hints, if available
|
||||
*/
|
||||
if (hints != NULL) {
|
||||
ai->ai_flags = hints->ai_flags;
|
||||
ai->ai_family = hints->ai_family;
|
||||
ai->ai_socktype = hints->ai_socktype;
|
||||
ai->ai_protocol = hints->ai_protocol;
|
||||
|
||||
family = hints->ai_family;
|
||||
socktype = hints->ai_socktype;
|
||||
protocol = hints->ai_protocol;
|
||||
flags = hints->ai_flags;
|
||||
|
||||
switch (family) {
|
||||
case AF_UNSPEC:
|
||||
switch (hints->ai_socktype) {
|
||||
case SOCK_STREAM:
|
||||
proto = "tcp";
|
||||
break;
|
||||
case SOCK_DGRAM:
|
||||
proto = "udp";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
switch (hints->ai_socktype) {
|
||||
case 0:
|
||||
break;
|
||||
case SOCK_STREAM:
|
||||
proto = "tcp";
|
||||
break;
|
||||
case SOCK_DGRAM:
|
||||
proto = "udp";
|
||||
break;
|
||||
case SOCK_RAW:
|
||||
break;
|
||||
default:
|
||||
return (EAI_SOCKTYPE);
|
||||
}
|
||||
break;
|
||||
#ifdef AF_LOCAL
|
||||
case AF_LOCAL:
|
||||
switch (hints->ai_socktype) {
|
||||
case 0:
|
||||
break;
|
||||
case SOCK_STREAM:
|
||||
break;
|
||||
case SOCK_DGRAM:
|
||||
break;
|
||||
default:
|
||||
return (EAI_SOCKTYPE);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return (EAI_FAMILY);
|
||||
}
|
||||
} else {
|
||||
protocol = 0;
|
||||
family = 0;
|
||||
socktype = 0;
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
rval = do_nodename(nodename, ai, hints);
|
||||
if (rval != 0) {
|
||||
freeaddrinfo(ai);
|
||||
return (rval);
|
||||
}
|
||||
|
||||
/*
|
||||
* First, look up the service name (port) if it was
|
||||
* requested. If the socket type wasn't specified, then
|
||||
* try and figure it out.
|
||||
*/
|
||||
if (servname != NULL) {
|
||||
char *e;
|
||||
|
||||
port = strtol(servname, &e, 10);
|
||||
if (*e == '\0') {
|
||||
if (socktype == 0)
|
||||
return (EAI_SOCKTYPE);
|
||||
if (port < 0 || port > 65535)
|
||||
return (EAI_SERVICE);
|
||||
port = htons((unsigned short) port);
|
||||
} else {
|
||||
sp = getservbyname(servname, proto);
|
||||
if (sp == NULL)
|
||||
return (EAI_SERVICE);
|
||||
port = sp->s_port;
|
||||
if (socktype == 0) {
|
||||
if (strcmp(sp->s_proto, "tcp") == 0)
|
||||
socktype = SOCK_STREAM;
|
||||
else if (strcmp(sp->s_proto, "udp") == 0)
|
||||
socktype = SOCK_DGRAM;
|
||||
}
|
||||
}
|
||||
} else
|
||||
port = 0;
|
||||
|
||||
/*
|
||||
*
|
||||
* Set up the port number
|
||||
*/
|
||||
if (ai->ai_family == AF_INET)
|
||||
((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port;
|
||||
else if (ai->ai_family == AF_INET6)
|
||||
((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port;
|
||||
*res = ai;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
freeaddrinfo(struct addrinfo *ai)
|
||||
{
|
||||
if (ai->ai_canonname != NULL)
|
||||
{
|
||||
efree(ai->ai_canonname);
|
||||
ai->ai_canonname = NULL;
|
||||
}
|
||||
if (ai->ai_addr != NULL)
|
||||
{
|
||||
efree(ai->ai_addr);
|
||||
ai->ai_addr = NULL;
|
||||
}
|
||||
efree(ai);
|
||||
ai = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
|
||||
size_t hostlen, char *serv, size_t servlen, int flags)
|
||||
{
|
||||
struct hostent *hp;
|
||||
|
||||
if (sa->sa_family != AF_INET)
|
||||
return (EAI_FAMILY);
|
||||
hp = gethostbyaddr(
|
||||
(const char *)&((const struct sockaddr_in *)sa)->sin_addr,
|
||||
4, AF_INET);
|
||||
if (hp == NULL) {
|
||||
if (h_errno == TRY_AGAIN)
|
||||
return (EAI_AGAIN);
|
||||
else
|
||||
return (EAI_FAIL);
|
||||
}
|
||||
if (host != NULL && hostlen > 0)
|
||||
strlcpy(host, hp->h_name, hostlen);
|
||||
return (0);
|
||||
}
|
||||
|
||||
char *
|
||||
gai_strerror(int ecode)
|
||||
{
|
||||
if (ecode < 0 || ecode > EAI_MAX)
|
||||
ecode = EAI_MAX;
|
||||
return ai_errlist[ecode];
|
||||
}
|
||||
|
||||
static int
|
||||
do_nodename(
|
||||
const char *nodename,
|
||||
struct addrinfo *ai,
|
||||
const struct addrinfo *hints)
|
||||
{
|
||||
struct hostent *hp = NULL;
|
||||
struct sockaddr_in *sockin;
|
||||
struct sockaddr_in6 *sockin6;
|
||||
int errval;
|
||||
|
||||
ai->ai_addr = emalloc(sizeof(struct sockaddr_storage));
|
||||
if (ai->ai_addr == NULL)
|
||||
return (IP_EAI_MEMORY);
|
||||
|
||||
/*
|
||||
* For an empty node name just use the wildcard.
|
||||
* NOTE: We need to assume that the address family is
|
||||
* set elsewhere so that we can set the appropriate wildcard
|
||||
*/
|
||||
if (nodename == NULL) {
|
||||
if (ai->ai_family == AF_INET)
|
||||
{
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
sockin = (struct sockaddr_in *)ai->ai_addr;
|
||||
sockin->sin_family = (short) ai->ai_family;
|
||||
sockin->sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
else
|
||||
{
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in6);
|
||||
sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
|
||||
sockin6->sin6_family = (short) ai->ai_family;
|
||||
/*
|
||||
* we have already zeroed out the address
|
||||
* so we don't actually need to do this
|
||||
* This assignment is causing problems so
|
||||
* we don't do what this would do.
|
||||
sockin6->sin6_addr = in6addr_any;
|
||||
*/
|
||||
}
|
||||
#ifdef ISC_PLATFORM_HAVESALEN
|
||||
ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* See if we have an IPv6 address
|
||||
*/
|
||||
if(strchr(nodename, ':') != NULL) {
|
||||
if (inet_pton(AF_INET6, nodename,
|
||||
&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) {
|
||||
((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6;
|
||||
ai->ai_family = AF_INET6;
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in6);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* See if we have an IPv4 address
|
||||
*/
|
||||
if (inet_pton(AF_INET, nodename,
|
||||
&((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
|
||||
((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
|
||||
ai->ai_family = AF_INET;
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the numeric host flag is set, don't attempt resolution
|
||||
*/
|
||||
if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
|
||||
return (IP_EAI_NONAME);
|
||||
|
||||
/*
|
||||
* Look for a name
|
||||
*/
|
||||
|
||||
errval = DNSlookup_name(nodename, AF_INET, &hp);
|
||||
|
||||
if (hp == NULL) {
|
||||
if (errval == IP_TRY_AGAIN || errval == IP_TRY_AGAIN)
|
||||
return (IP_TRY_AGAIN);
|
||||
else if (errval == IP_EAI_NONAME) {
|
||||
if (inet_pton(AF_INET, nodename,
|
||||
&((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
|
||||
((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
|
||||
ai->ai_family = AF_INET;
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
return (0);
|
||||
}
|
||||
return (errval);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (errval);
|
||||
}
|
||||
}
|
||||
ai->ai_family = hp->h_addrtype;
|
||||
ai->ai_addrlen = sizeof(struct sockaddr);
|
||||
sockin = (struct sockaddr_in *)ai->ai_addr;
|
||||
memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
|
||||
ai->ai_addr->sa_family = hp->h_addrtype;
|
||||
#ifdef ISC_PLATFORM_HAVESALEN
|
||||
ai->ai_addr->sa_len = sizeof(struct sockaddr);
|
||||
#endif
|
||||
if (hints != NULL && (hints->ai_flags & AI_CANONNAME))
|
||||
ai->ai_canonname = estrdup(hp->h_name);
|
||||
return (0);
|
||||
}
|
||||
#endif /* HAVE_ADDRINFO */
|
||||
|
||||
char *
|
||||
ntp_gai_strerror(int ecode)
|
||||
{
|
||||
if (ecode < 0 || ecode > EAI_MAX)
|
||||
ecode = EAI_MAX;
|
||||
return ai_errlist[ecode];
|
||||
}
|
||||
|
||||
#endif /* !ISC_PLATFORM_HAVEIPV6 */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,55 @@
|
||||
#include <ipntp_config.h>
|
||||
|
||||
#include <ntp_assert.h>
|
||||
#include <string.h>
|
||||
#include "ntp_malloc.h"
|
||||
#include "l_stdlib.h"
|
||||
|
||||
#define STRDUP_EMPTY_UNIT
|
||||
|
||||
#ifndef HAVE_STRDUP
|
||||
# undef STRDUP_EMPTY_UNIT
|
||||
char *strdup(const char *s);
|
||||
char *
|
||||
strdup(
|
||||
const char *s
|
||||
)
|
||||
{
|
||||
size_t octets;
|
||||
char * cp;
|
||||
|
||||
REQUIRE(s);
|
||||
octets = strlen(s) + 1;
|
||||
if ((cp = emalloc(octets)) == NULL)
|
||||
return NULL;
|
||||
memcpy(cp, s, octets);
|
||||
|
||||
return cp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_MEMCHR
|
||||
# undef STRDUP_EMPTY_UNIT
|
||||
void *memchr(const void *s, int c, size_t n)
|
||||
{
|
||||
const unsigned char *p = s;
|
||||
while (n && *p != c) {
|
||||
--n;
|
||||
++p;
|
||||
}
|
||||
return n ? (char*)p : NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRNLEN
|
||||
# undef STRDUP_EMPTY_UNIT
|
||||
size_t strnlen(const char *s, size_t n)
|
||||
{
|
||||
const char *e = memchr(s, 0, n);
|
||||
return e ? (size_t)(e - s) : n;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef STRDUP_EMPTY_UNIT
|
||||
int strdup_c_nonempty_compilation_unit;
|
||||
#endif
|
||||
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* ntp_worker.c
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include "ntp_workimpl.h"
|
||||
|
||||
#ifdef WORKER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "iosignal.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_malloc.h"
|
||||
#include "ntp_syslog.h"
|
||||
#include "ntpd.h"
|
||||
#include "ntp_io.h"
|
||||
#include "ntp_assert.h"
|
||||
#include "ntp_unixtime.h"
|
||||
#include "intreswork.h"
|
||||
|
||||
|
||||
#define CHILD_MAX_IDLE (3 * 60) /* seconds, idle worker limit */
|
||||
|
||||
blocking_child ** blocking_children;
|
||||
size_t blocking_children_alloc;
|
||||
int worker_per_query; /* boolean */
|
||||
int intres_req_pending;
|
||||
volatile u_int blocking_child_ready_seen;
|
||||
volatile u_int blocking_child_ready_done;
|
||||
|
||||
void clear_worker(void)
|
||||
{
|
||||
blocking_children = NULL;
|
||||
blocking_children_alloc = 0;
|
||||
worker_per_query = 0;
|
||||
intres_req_pending = 0;
|
||||
|
||||
}
|
||||
|
||||
#ifndef HAVE_IO_COMPLETION_PORT
|
||||
/*
|
||||
* pipe_socketpair()
|
||||
*
|
||||
* Provides an AF_UNIX socketpair on systems which have them, otherwise
|
||||
* pair of unidirectional pipes.
|
||||
*/
|
||||
int
|
||||
pipe_socketpair(
|
||||
int caller_fds[2],
|
||||
int * is_pipe
|
||||
)
|
||||
{
|
||||
int rc;
|
||||
int fds[2];
|
||||
int called_pipe;
|
||||
|
||||
#ifdef HAVE_SOCKETPAIR
|
||||
rc = socketpair(AF_UNIX, SOCK_STREAM, 0, &fds[0]);
|
||||
#else
|
||||
rc = -1;
|
||||
#endif
|
||||
|
||||
if (-1 == rc) {
|
||||
rc = pipe(&fds[0]);
|
||||
called_pipe = TRUE;
|
||||
} else {
|
||||
called_pipe = FALSE;
|
||||
}
|
||||
|
||||
if (-1 == rc)
|
||||
return rc;
|
||||
|
||||
caller_fds[0] = fds[0];
|
||||
caller_fds[1] = fds[1];
|
||||
if (is_pipe != NULL)
|
||||
*is_pipe = called_pipe;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* close_all_except()
|
||||
*
|
||||
* Close all file descriptors except the given keep_fd.
|
||||
*/
|
||||
void
|
||||
close_all_except(
|
||||
int keep_fd
|
||||
)
|
||||
{
|
||||
int fd;
|
||||
|
||||
for (fd = 0; fd < keep_fd; fd++)
|
||||
close(fd);
|
||||
|
||||
close_all_beyond(keep_fd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* close_all_beyond()
|
||||
*
|
||||
* Close all file descriptors after the given keep_fd, which is the
|
||||
* highest fd to keep open.
|
||||
*/
|
||||
void
|
||||
close_all_beyond(
|
||||
int keep_fd
|
||||
)
|
||||
{
|
||||
# ifdef HAVE_CLOSEFROM
|
||||
closefrom(keep_fd + 1);
|
||||
# elif defined(F_CLOSEM)
|
||||
/*
|
||||
* From 'Writing Reliable AIX Daemons,' SG24-4946-00,
|
||||
* by Eric Agar (saves us from doing 32767 system
|
||||
* calls)
|
||||
*/
|
||||
if (fcntl(keep_fd + 1, F_CLOSEM, 0) == -1)
|
||||
msyslog(LOG_ERR, "F_CLOSEM(%d): %m", keep_fd + 1);
|
||||
# else /* !HAVE_CLOSEFROM && !F_CLOSEM follows */
|
||||
int fd;
|
||||
int max_fd;
|
||||
|
||||
max_fd = GETDTABLESIZE();
|
||||
for (fd = keep_fd + 1; fd < max_fd; fd++)
|
||||
close(fd);
|
||||
# endif /* !HAVE_CLOSEFROM && !F_CLOSEM */
|
||||
}
|
||||
#endif /* HAVE_IO_COMPLETION_PORT */
|
||||
|
||||
|
||||
u_int
|
||||
available_blocking_child_slot(void)
|
||||
{
|
||||
const size_t each = sizeof(blocking_children[0]);
|
||||
u_int slot;
|
||||
size_t prev_alloc;
|
||||
size_t new_alloc;
|
||||
size_t prev_octets;
|
||||
size_t octets;
|
||||
|
||||
for (slot = 0; slot < blocking_children_alloc; slot++) {
|
||||
if (NULL == blocking_children[slot])
|
||||
return slot;
|
||||
if (blocking_children[slot]->reusable) {
|
||||
blocking_children[slot]->reusable = FALSE;
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
prev_alloc = blocking_children_alloc;
|
||||
prev_octets = prev_alloc * each;
|
||||
new_alloc = blocking_children_alloc + 4;
|
||||
octets = new_alloc * each;
|
||||
blocking_children = erealloc_zero(blocking_children, octets,
|
||||
prev_octets);
|
||||
blocking_children_alloc = new_alloc;
|
||||
|
||||
/* assume we'll never have enough workers to overflow u_int */
|
||||
return (u_int)prev_alloc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
queue_blocking_request(
|
||||
blocking_work_req rtype,
|
||||
void * req,
|
||||
size_t reqsize,
|
||||
blocking_work_callback done_func,
|
||||
void * context
|
||||
)
|
||||
{
|
||||
static u_int intres_slot = UINT_MAX;
|
||||
u_int child_slot;
|
||||
blocking_child * c;
|
||||
blocking_pipe_header req_hdr;
|
||||
|
||||
req_hdr.octets = sizeof(req_hdr) + reqsize;
|
||||
req_hdr.magic_sig = BLOCKING_REQ_MAGIC;
|
||||
req_hdr.rtype = rtype;
|
||||
req_hdr.done_func = done_func;
|
||||
req_hdr.context = context;
|
||||
|
||||
child_slot = UINT_MAX;
|
||||
if (worker_per_query || UINT_MAX == intres_slot ||
|
||||
blocking_children[intres_slot]->reusable)
|
||||
child_slot = available_blocking_child_slot();
|
||||
if (!worker_per_query) {
|
||||
if (UINT_MAX == intres_slot)
|
||||
intres_slot = child_slot;
|
||||
else
|
||||
child_slot = intres_slot;
|
||||
if (0 == intres_req_pending)
|
||||
intres_timeout_req(0);
|
||||
}
|
||||
intres_req_pending++;
|
||||
INSIST(UINT_MAX != child_slot);
|
||||
c = blocking_children[child_slot];
|
||||
if (NULL == c) {
|
||||
c = emalloc_zero(sizeof(*c));
|
||||
#ifdef WORK_FORK
|
||||
c->req_read_pipe = -1;
|
||||
c->req_write_pipe = -1;
|
||||
#endif
|
||||
#ifdef WORK_PIPE
|
||||
c->resp_read_pipe = -1;
|
||||
c->resp_write_pipe = -1;
|
||||
#endif
|
||||
blocking_children[child_slot] = c;
|
||||
}
|
||||
req_hdr.child_idx = child_slot;
|
||||
|
||||
return send_blocking_req_internal(c, &req_hdr, req);
|
||||
}
|
||||
|
||||
|
||||
int queue_blocking_response(
|
||||
blocking_child * c,
|
||||
blocking_pipe_header * resp,
|
||||
size_t respsize,
|
||||
const blocking_pipe_header * req
|
||||
)
|
||||
{
|
||||
resp->octets = respsize;
|
||||
resp->magic_sig = BLOCKING_RESP_MAGIC;
|
||||
resp->rtype = req->rtype;
|
||||
resp->context = req->context;
|
||||
resp->done_func = req->done_func;
|
||||
|
||||
return send_blocking_resp_internal(c, resp);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
process_blocking_resp(
|
||||
blocking_child * c
|
||||
)
|
||||
{
|
||||
blocking_pipe_header * resp;
|
||||
void * data;
|
||||
|
||||
/*
|
||||
* On Windows send_blocking_resp_internal() may signal the
|
||||
* blocking_response_ready event multiple times while we're
|
||||
* processing a response, so always consume all available
|
||||
* responses before returning to test the event again.
|
||||
*/
|
||||
#ifdef WORK_THREAD
|
||||
do {
|
||||
#endif
|
||||
resp = receive_blocking_resp_internal(c);
|
||||
if (NULL != resp) {
|
||||
DEBUG_REQUIRE(BLOCKING_RESP_MAGIC ==
|
||||
resp->magic_sig);
|
||||
data = (char *)resp + sizeof(*resp);
|
||||
intres_req_pending--;
|
||||
(*resp->done_func)(resp->rtype, resp->context,
|
||||
resp->octets - sizeof(*resp),
|
||||
data);
|
||||
efree(resp);
|
||||
}
|
||||
#ifdef WORK_THREAD
|
||||
} while (NULL != resp);
|
||||
#endif
|
||||
if (!worker_per_query && 0 == intres_req_pending)
|
||||
intres_timeout_req(CHILD_MAX_IDLE);
|
||||
else if (worker_per_query)
|
||||
req_child_exit(c);
|
||||
}
|
||||
|
||||
void
|
||||
harvest_blocking_responses(void)
|
||||
{
|
||||
size_t idx;
|
||||
blocking_child* cp;
|
||||
u_int scseen, scdone;
|
||||
|
||||
scseen = blocking_child_ready_seen;
|
||||
scdone = blocking_child_ready_done;
|
||||
if (scdone != scseen) {
|
||||
blocking_child_ready_done = scseen;
|
||||
for (idx = 0; idx < blocking_children_alloc; idx++) {
|
||||
cp = blocking_children[idx];
|
||||
if (NULL == cp)
|
||||
continue;
|
||||
scseen = cp->resp_ready_seen;
|
||||
scdone = cp->resp_ready_done;
|
||||
if (scdone != scseen) {
|
||||
cp->resp_ready_done = scseen;
|
||||
process_blocking_resp(cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* blocking_child_common runs as a forked child or a thread
|
||||
*/
|
||||
int
|
||||
blocking_child_common(
|
||||
blocking_child *c
|
||||
)
|
||||
{
|
||||
int say_bye;
|
||||
blocking_pipe_header *req;
|
||||
|
||||
say_bye = FALSE;
|
||||
while (!say_bye) {
|
||||
req = receive_blocking_req_internal(c);
|
||||
if (NULL == req) {
|
||||
say_bye = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_REQUIRE(BLOCKING_REQ_MAGIC == req->magic_sig);
|
||||
|
||||
switch (req->rtype) {
|
||||
case BLOCKING_GETADDRINFO:
|
||||
if (blocking_getaddrinfo(c, req))
|
||||
say_bye = TRUE;
|
||||
break;
|
||||
|
||||
case BLOCKING_GETNAMEINFO:
|
||||
if (blocking_getnameinfo(c, req))
|
||||
say_bye = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
msyslog(LOG_ERR, "unknown req %d to blocking worker", req->rtype);
|
||||
say_bye = TRUE;
|
||||
}
|
||||
|
||||
efree(req);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* worker_idle_timer_fired()
|
||||
*
|
||||
* The parent starts this timer when the last pending response has been
|
||||
* received from the child, making it idle, and clears the timer when a
|
||||
* request is dispatched to the child. Once the timer expires, the
|
||||
* child is sent packing.
|
||||
*
|
||||
* This is called when worker_idle_timer is nonzero and less than or
|
||||
* equal to current_time.
|
||||
*/
|
||||
void
|
||||
worker_idle_timer_fired(void)
|
||||
{
|
||||
u_int idx;
|
||||
blocking_child * c;
|
||||
|
||||
DEBUG_REQUIRE(0 == intres_req_pending);
|
||||
|
||||
intres_timeout_req(0);
|
||||
for (idx = 0; idx < blocking_children_alloc; idx++) {
|
||||
c = blocking_children[idx];
|
||||
if (NULL == c)
|
||||
continue;
|
||||
req_child_exit(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#else /* !WORKER follows */
|
||||
int ntp_worker_nonempty_compilation_unit;
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* numtoa - return asciized network numbers store in local array space
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h> /* ntohl */
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "lib_strbuf.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
char *
|
||||
numtoa(
|
||||
u_int32 num
|
||||
)
|
||||
{
|
||||
register u_int32 netnum;
|
||||
register char *buf;
|
||||
|
||||
netnum = ntohl(num);
|
||||
LIB_GETBUF(buf);
|
||||
snprintf(buf, LIB_BUFLENGTH, "%lu.%lu.%lu.%lu",
|
||||
((u_long)netnum >> 24) & 0xff,
|
||||
((u_long)netnum >> 16) & 0xff,
|
||||
((u_long)netnum >> 8) & 0xff,
|
||||
(u_long)netnum & 0xff);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/* Convert a refid & stratum to a string */
|
||||
const char *
|
||||
refid_str(
|
||||
u_int32 refid,
|
||||
int stratum
|
||||
)
|
||||
{
|
||||
char * text;
|
||||
size_t tlen;
|
||||
|
||||
if (stratum > 1)
|
||||
return numtoa(refid);
|
||||
|
||||
LIB_GETBUF(text);
|
||||
text[0] = '.';
|
||||
memcpy(&text[1], &refid, sizeof(refid));
|
||||
text[1 + sizeof(refid)] = '\0';
|
||||
tlen = strlen(text);
|
||||
text[tlen] = '.';
|
||||
text[tlen + 1] = '\0';
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* numtohost - convert network number to host name.
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h> /* ntohl */
|
||||
#endif
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "lib_strbuf.h"
|
||||
|
||||
#define LOOPBACKNET 0x7f000000
|
||||
#define LOOPBACKHOST 0x7f000001
|
||||
#define LOOPBACKNETMASK 0xff000000
|
||||
|
||||
char *
|
||||
numtohost(
|
||||
u_int32 netnum
|
||||
)
|
||||
{
|
||||
char *bp;
|
||||
struct hostent *hp;
|
||||
|
||||
/*
|
||||
* This is really gross, but saves lots of hanging looking for
|
||||
* hostnames for the radio clocks. Don't bother looking up
|
||||
* addresses on the loopback network except for the loopback
|
||||
* host itself.
|
||||
*/
|
||||
if ((((ntohl(netnum) & LOOPBACKNETMASK) == LOOPBACKNET)
|
||||
&& (ntohl(netnum) != LOOPBACKHOST))
|
||||
|| ((hp = gethostbyaddr((char *)&netnum, sizeof netnum, AF_INET))
|
||||
== 0))
|
||||
return numtoa(netnum);
|
||||
|
||||
LIB_GETBUF(bp);
|
||||
strlcpy(bp, hp->h_name, LIB_BUFLENGTH);
|
||||
|
||||
return bp;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* octtoint - convert an ascii string in octal to an unsigned
|
||||
* long, with error checking
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
int
|
||||
octtoint(
|
||||
const char *str,
|
||||
u_long *ival
|
||||
)
|
||||
{
|
||||
register u_long u;
|
||||
register const char *cp;
|
||||
|
||||
cp = str;
|
||||
|
||||
if (*cp == '\0')
|
||||
return 0;
|
||||
|
||||
u = 0;
|
||||
while (*cp != '\0') {
|
||||
if (!isdigit((unsigned char)*cp) || *cp == '8' || *cp == '9')
|
||||
return 0;
|
||||
if (u >= 0x20000000)
|
||||
return 0; /* overflow */
|
||||
u <<= 3;
|
||||
u += *cp++ - '0'; /* ascii dependent */
|
||||
}
|
||||
*ival = u;
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* prettydate - convert a time stamp to something readable
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "ntp_unixtime.h" /* includes <sys/time.h> */
|
||||
#include "lib_strbuf.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_assert.h"
|
||||
#include "ntp_calendar.h"
|
||||
|
||||
#if SIZEOF_TIME_T < 4
|
||||
# error sizeof(time_t) < 4 -- this will not work!
|
||||
#endif
|
||||
|
||||
static char *common_prettydate(l_fp *, int);
|
||||
|
||||
const char * const months[12] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
const char * const daynames[7] = {
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||
};
|
||||
|
||||
/* Helper function to handle possible wraparound of the ntp epoch.
|
||||
*
|
||||
* Works by periodic extension of the ntp time stamp in the UN*X epoch.
|
||||
* If the 'time_t' is 32 bit, use solar cycle warping to get the value
|
||||
* in a suitable range. Also uses solar cycle warping to work around
|
||||
* really buggy implementations of 'gmtime()' / 'localtime()' that
|
||||
* cannot work with a negative time value, that is, times before
|
||||
* 1970-01-01. (MSVCRT...)
|
||||
*
|
||||
* Apart from that we're assuming that the localtime/gmtime library
|
||||
* functions have been updated so that they work...
|
||||
*
|
||||
* An explanation: The julian calendar repeats ever 28 years, because
|
||||
* it's the LCM of 7 and 1461, the week and leap year cycles. This is
|
||||
* called a 'solar cycle'. The gregorian calendar does the same as
|
||||
* long as no centennial year (divisible by 100, but not 400) goes in
|
||||
* the way. So between 1901 and 2099 (inclusive) we can warp time
|
||||
* stamps by 28 years to make them suitable for localtime() and
|
||||
* gmtime() if we have trouble. Of course this will play hubbubb with
|
||||
* the DST zone switches, so we should do it only if necessary; but as
|
||||
* we NEED a proper conversion to dates via gmtime() we should try to
|
||||
* cope with as many idiosyncrasies as possible.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* solar cycle in unsigned secs and years, and the cycle limits.
|
||||
*/
|
||||
#define SOLAR_CYCLE_SECS 0x34AADC80UL /* 7*1461*86400*/
|
||||
#define SOLAR_CYCLE_YEARS 28
|
||||
#define MINFOLD -3
|
||||
#define MAXFOLD 3
|
||||
|
||||
static struct tm *
|
||||
get_struct_tm(
|
||||
const vint64 *stamp,
|
||||
int local)
|
||||
{
|
||||
struct tm *tm = NULL;
|
||||
int32 folds = 0;
|
||||
time_t ts;
|
||||
|
||||
#ifdef HAVE_INT64
|
||||
|
||||
int64 tl;
|
||||
|
||||
tl = stamp->q_s;
|
||||
ts = (time_t)tl;
|
||||
|
||||
/*
|
||||
* If there is chance of truncation, try to fix it. Let the
|
||||
* compiler find out if this can happen at all.
|
||||
*/
|
||||
while (ts != tl) { /* truncation? */
|
||||
if (tl < 0) {
|
||||
if (--folds < MINFOLD)
|
||||
return NULL;
|
||||
tl += SOLAR_CYCLE_SECS;
|
||||
} else {
|
||||
if (++folds > MAXFOLD)
|
||||
return NULL;
|
||||
tl -= SOLAR_CYCLE_SECS;
|
||||
}
|
||||
ts = (time_t)tl; /* next try... */
|
||||
}
|
||||
#else
|
||||
|
||||
/*
|
||||
* since we do not have 64-bit scalars, it's not likely we have
|
||||
* 64-bit time_t. Assume 32 bits and properly reduce the value.
|
||||
*/
|
||||
u_int32 hi, lo;
|
||||
|
||||
hi = stamp->D_s.hi;
|
||||
lo = stamp->D_s.lo;
|
||||
|
||||
while ((hi && ~hi) || ((hi ^ lo) & 0x80000000u)) {
|
||||
if ((((hi) & 0x80000000) != 0)) {
|
||||
if (--folds < MINFOLD)
|
||||
return NULL;
|
||||
M_ADD(hi, lo, 0, SOLAR_CYCLE_SECS);
|
||||
} else {
|
||||
if (++folds > MAXFOLD)
|
||||
return NULL;
|
||||
M_SUB(hi, lo, 0, SOLAR_CYCLE_SECS);
|
||||
}
|
||||
}
|
||||
ts = (int32)lo;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 'ts' should be a suitable value by now. Just go ahead, but
|
||||
* with care:
|
||||
*
|
||||
* There are some pathological implementations of 'gmtime()'
|
||||
* and 'localtime()' out there. No matter if we have 32-bit or
|
||||
* 64-bit 'time_t', try to fix this by solar cycle warping
|
||||
* again...
|
||||
*
|
||||
* At least the MSDN says that the (Microsoft) Windoze
|
||||
* versions of 'gmtime()' and 'localtime()' will bark on time
|
||||
* stamps < 0.
|
||||
*/
|
||||
while ((tm = (*(local ? localtime : gmtime))(&ts)) == NULL)
|
||||
if (ts < 0) {
|
||||
if (--folds < MINFOLD)
|
||||
return NULL;
|
||||
ts += SOLAR_CYCLE_SECS;
|
||||
} else if (ts >= (time_t)SOLAR_CYCLE_SECS) {
|
||||
if (++folds > MAXFOLD)
|
||||
return NULL;
|
||||
ts -= SOLAR_CYCLE_SECS;
|
||||
} else
|
||||
return NULL; /* That's truly pathological! */
|
||||
|
||||
/* 'tm' surely not NULL here! */
|
||||
INSIST(tm != NULL);
|
||||
if (folds != 0) {
|
||||
tm->tm_year += folds * SOLAR_CYCLE_YEARS;
|
||||
if (tm->tm_year <= 0 || tm->tm_year >= 200)
|
||||
return NULL; /* left warp range... can't help here! */
|
||||
}
|
||||
|
||||
return tm;
|
||||
}
|
||||
|
||||
static char *
|
||||
common_prettydate(
|
||||
l_fp *ts,
|
||||
int local
|
||||
)
|
||||
{
|
||||
static const char pfmt0[] =
|
||||
"%08lx.%08lx %s, %s %2d %4d %2d:%02d:%02d.%03u";
|
||||
static const char pfmt1[] =
|
||||
"%08lx.%08lx [%s, %s %2d %4d %2d:%02d:%02d.%03u UTC]";
|
||||
|
||||
char *bp;
|
||||
struct tm *tm;
|
||||
u_int msec;
|
||||
u_int32 ntps;
|
||||
vint64 sec;
|
||||
|
||||
LIB_GETBUF(bp);
|
||||
|
||||
if (ts->l_ui == 0 && ts->l_uf == 0) {
|
||||
strlcpy (bp, "(no time)", LIB_BUFLENGTH);
|
||||
return (bp);
|
||||
}
|
||||
|
||||
/* get & fix milliseconds */
|
||||
ntps = ts->l_ui;
|
||||
msec = ts->l_uf / 4294967; /* fract / (2 ** 32 / 1000) */
|
||||
if (msec >= 1000u) {
|
||||
msec -= 1000u;
|
||||
ntps++;
|
||||
}
|
||||
sec = ntpcal_ntp_to_time(ntps, NULL);
|
||||
tm = get_struct_tm(&sec, local);
|
||||
if (!tm) {
|
||||
/*
|
||||
* get a replacement, but always in UTC, using
|
||||
* ntpcal_time_to_date()
|
||||
*/
|
||||
struct calendar jd;
|
||||
ntpcal_time_to_date(&jd, &sec);
|
||||
snprintf(bp, LIB_BUFLENGTH, local ? pfmt1 : pfmt0,
|
||||
(u_long)ts->l_ui, (u_long)ts->l_uf,
|
||||
daynames[jd.weekday], months[jd.month-1],
|
||||
jd.monthday, jd.year, jd.hour,
|
||||
jd.minute, jd.second, msec);
|
||||
} else
|
||||
snprintf(bp, LIB_BUFLENGTH, pfmt0,
|
||||
(u_long)ts->l_ui, (u_long)ts->l_uf,
|
||||
daynames[tm->tm_wday], months[tm->tm_mon],
|
||||
tm->tm_mday, 1900 + tm->tm_year, tm->tm_hour,
|
||||
tm->tm_min, tm->tm_sec, msec);
|
||||
return bp;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
prettydate(
|
||||
l_fp *ts
|
||||
)
|
||||
{
|
||||
return common_prettydate(ts, 1);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
gmprettydate(
|
||||
l_fp *ts
|
||||
)
|
||||
{
|
||||
return common_prettydate(ts, 0);
|
||||
}
|
||||
|
||||
|
||||
struct tm *
|
||||
ntp2unix_tm(
|
||||
u_int32 ntp, int local
|
||||
)
|
||||
{
|
||||
vint64 vl;
|
||||
vl = ntpcal_ntp_to_time(ntp, NULL);
|
||||
return get_struct_tm(&vl, local);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,419 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntp_assert.h"
|
||||
#include "ntp_syslog.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_lists.h"
|
||||
#include "recvbuff.h"
|
||||
#include "iosignal.h"
|
||||
|
||||
#include <isc/isc_list.h>
|
||||
#include "ntp_mem.h"
|
||||
|
||||
#if (RECV_INC & (RECV_INC-1))
|
||||
# error RECV_INC not a power of 2!
|
||||
#endif
|
||||
#if (RECV_BATCH & (RECV_BATCH - 1))
|
||||
#error RECV_BATCH not a power of 2!
|
||||
#endif
|
||||
#if (RECV_BATCH < RECV_INC)
|
||||
#error RECV_BATCH must be >= RECV_INC!
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Memory allocation
|
||||
*/
|
||||
static u_long volatile full_recvbufs; /* recvbufs on full_recv_fifo */
|
||||
static u_long volatile free_recvbufs; /* recvbufs on free_recv_list */
|
||||
static u_long volatile total_recvbufs; /* total recvbufs currently in use */
|
||||
static u_long volatile lowater_adds; /* number of times we have added memory */
|
||||
static u_long volatile buffer_shortfall;/* number of missed free receive buffers
|
||||
between replenishments */
|
||||
static u_long limit_recvbufs; /* maximum total of receive buffers */
|
||||
static u_long emerg_recvbufs; /* emergency/urgent buffers to keep */
|
||||
|
||||
static void *total_recv_bufp = NULL;
|
||||
|
||||
static DECL_FIFO_ANCHOR(recvbuf_t) full_recv_fifo;
|
||||
static recvbuf_t * free_recv_list;
|
||||
|
||||
#if defined(SYS_WINNT)
|
||||
|
||||
/*
|
||||
* For Windows we need to set up a lock to manipulate the
|
||||
* recv buffers to prevent corruption. We keep it lock for as
|
||||
* short a time as possible
|
||||
*/
|
||||
static CRITICAL_SECTION RecvLock;
|
||||
static CRITICAL_SECTION FreeLock;
|
||||
# define LOCK_R() EnterCriticalSection(&RecvLock)
|
||||
# define UNLOCK_R() LeaveCriticalSection(&RecvLock)
|
||||
# define LOCK_F() EnterCriticalSection(&FreeLock)
|
||||
# define UNLOCK_F() LeaveCriticalSection(&FreeLock)
|
||||
#else
|
||||
# define LOCK_R() do {} while (FALSE)
|
||||
# define UNLOCK_R() do {} while (FALSE)
|
||||
# define LOCK_F() do {} while (FALSE)
|
||||
# define UNLOCK_F() do {} while (FALSE)
|
||||
#endif
|
||||
|
||||
#ifdef NTP_DEBUG
|
||||
static void uninit_recvbuff(void);
|
||||
#endif
|
||||
|
||||
|
||||
u_long
|
||||
free_recvbuffs (void)
|
||||
{
|
||||
return free_recvbufs;
|
||||
}
|
||||
|
||||
u_long
|
||||
full_recvbuffs (void)
|
||||
{
|
||||
return full_recvbufs;
|
||||
}
|
||||
|
||||
u_long
|
||||
total_recvbuffs (void)
|
||||
{
|
||||
return total_recvbufs;
|
||||
}
|
||||
|
||||
u_long
|
||||
lowater_additions(void)
|
||||
{
|
||||
return lowater_adds;
|
||||
}
|
||||
|
||||
static inline void
|
||||
initialise_buffer(recvbuf_t *buff)
|
||||
{
|
||||
ZERO(*buff);
|
||||
}
|
||||
|
||||
static void
|
||||
create_buffers(
|
||||
size_t nbufs)
|
||||
{
|
||||
# ifndef NTP_DEBUG
|
||||
static const u_int chunk = RECV_INC;
|
||||
# else
|
||||
/* Allocate each buffer individually so they can be free()d
|
||||
* during ntpd shutdown on DEBUG builds to keep them out of heap
|
||||
* leak reports.
|
||||
*/
|
||||
static const u_int chunk = 1;
|
||||
# endif
|
||||
|
||||
register recvbuf_t *bufp;
|
||||
recvbuf_t *head;
|
||||
u_int i;
|
||||
size_t abuf;
|
||||
|
||||
if (limit_recvbufs <= total_recvbufs)
|
||||
return;
|
||||
|
||||
abuf = nbufs + buffer_shortfall;
|
||||
buffer_shortfall = 0;
|
||||
|
||||
if (abuf < nbufs || abuf > RECV_BATCH)
|
||||
abuf = RECV_BATCH; /* clamp on overflow */
|
||||
else
|
||||
abuf += (~abuf + 1) & (RECV_INC - 1); /* round up */
|
||||
|
||||
if (abuf > (limit_recvbufs - total_recvbufs))
|
||||
abuf = limit_recvbufs - total_recvbufs;
|
||||
abuf += (~abuf + 1) & (chunk - 1); /* round up */
|
||||
|
||||
while (abuf) {
|
||||
bufp = emalloc(chunk*sizeof(*bufp));
|
||||
if (!bufp) {
|
||||
limit_recvbufs = total_recvbufs;
|
||||
break;
|
||||
}
|
||||
head = bufp;
|
||||
for (i = chunk; i; --i,++bufp) {
|
||||
bufp->mem_head = FALSE;
|
||||
LINK_SLIST(free_recv_list, bufp, link);
|
||||
}
|
||||
head->mem_head = TRUE;
|
||||
free_recvbufs += chunk;
|
||||
total_recvbufs += chunk;
|
||||
abuf -= chunk;
|
||||
}
|
||||
++lowater_adds;
|
||||
}
|
||||
|
||||
void
|
||||
init_recvbuff(int nbufs)
|
||||
{
|
||||
|
||||
buffer_shortfall = 0;
|
||||
|
||||
total_recv_bufp = NULL;
|
||||
free_recv_list = NULL;
|
||||
memset(&full_recv_fifo, 0, sizeof(full_recv_fifo));
|
||||
|
||||
|
||||
/*
|
||||
* Init buffer free list and stat counters
|
||||
*/
|
||||
free_recvbufs = total_recvbufs = 0;
|
||||
full_recvbufs = lowater_adds = 0;
|
||||
|
||||
limit_recvbufs = RECV_TOOMANY;
|
||||
emerg_recvbufs = RECV_CLOCK;
|
||||
|
||||
create_buffers(nbufs);
|
||||
|
||||
# if defined(SYS_WINNT)
|
||||
InitializeCriticalSection(&RecvLock);
|
||||
InitializeCriticalSection(&FreeLock);
|
||||
# endif
|
||||
|
||||
# ifdef NTP_DEBUG
|
||||
atexit(&uninit_recvbuff);
|
||||
# endif
|
||||
}
|
||||
|
||||
void
|
||||
clean_all_recvbuff()
|
||||
{
|
||||
recvbuf_t *rbunlinked;
|
||||
LOCK_R();
|
||||
efree(total_recv_bufp);
|
||||
UNLOCK_R();
|
||||
for (;;) {
|
||||
UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link);
|
||||
if (rbunlinked == NULL)
|
||||
break;
|
||||
if (rbunlinked->mem_head)
|
||||
efree(rbunlinked);
|
||||
}
|
||||
free_recv_list = NULL;
|
||||
free_recvbufs = total_recvbufs = 0;
|
||||
full_recvbufs = lowater_adds = 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef NTP_DEBUG
|
||||
static void
|
||||
uninit_recvbuff(void)
|
||||
{
|
||||
recvbuf_t *rbunlinked;
|
||||
|
||||
for (;;) {
|
||||
UNLINK_FIFO(rbunlinked, full_recv_fifo, link);
|
||||
if (rbunlinked == NULL)
|
||||
break;
|
||||
efree(rbunlinked);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link);
|
||||
if (rbunlinked == NULL)
|
||||
break;
|
||||
efree(rbunlinked);
|
||||
}
|
||||
# if defined(SYS_WINNT)
|
||||
DeleteCriticalSection(&FreeLock);
|
||||
DeleteCriticalSection(&RecvLock);
|
||||
# endif
|
||||
}
|
||||
#endif /* NTP_DEBUG */
|
||||
|
||||
|
||||
/*
|
||||
* freerecvbuf - make a single recvbuf available for reuse
|
||||
*/
|
||||
void
|
||||
freerecvbuf(recvbuf_t *rb)
|
||||
{
|
||||
if (rb) {
|
||||
if (--rb->used != 0) {
|
||||
msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used);
|
||||
rb->used = 0;
|
||||
}
|
||||
LOCK_F();
|
||||
LINK_SLIST(free_recv_list, rb, link);
|
||||
++free_recvbufs;
|
||||
UNLOCK_F();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
add_full_recv_buffer(recvbuf_t *rb)
|
||||
{
|
||||
if (rb == NULL) {
|
||||
msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer");
|
||||
return;
|
||||
}
|
||||
LOCK_R();
|
||||
LINK_FIFO(full_recv_fifo, rb, link);
|
||||
++full_recvbufs;
|
||||
UNLOCK_R();
|
||||
}
|
||||
|
||||
|
||||
recvbuf_t *
|
||||
get_free_recv_buffer(
|
||||
int /*BOOL*/ urgent
|
||||
)
|
||||
{
|
||||
recvbuf_t *buffer = NULL;
|
||||
|
||||
LOCK_F();
|
||||
if (free_recvbufs > (urgent ? emerg_recvbufs : 0)) {
|
||||
UNLINK_HEAD_SLIST(buffer, free_recv_list, link);
|
||||
}
|
||||
|
||||
if (buffer != NULL) {
|
||||
if (free_recvbufs)
|
||||
--free_recvbufs;
|
||||
initialise_buffer(buffer);
|
||||
++buffer->used;
|
||||
} else {
|
||||
++buffer_shortfall;
|
||||
}
|
||||
UNLOCK_F();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_IO_COMPLETION_PORT
|
||||
recvbuf_t *
|
||||
get_free_recv_buffer_alloc(
|
||||
int /*BOOL*/ urgent
|
||||
)
|
||||
{
|
||||
LOCK_F();
|
||||
if (free_recvbufs <= emerg_recvbufs || buffer_shortfall > 0)
|
||||
create_buffers(RECV_INC);
|
||||
UNLOCK_F();
|
||||
return get_free_recv_buffer(urgent);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
recvbuf_t *
|
||||
get_full_recv_buffer(void)
|
||||
{
|
||||
recvbuf_t * rbuf;
|
||||
|
||||
/*
|
||||
* make sure there are free buffers when we wander off to do
|
||||
* lengthy packet processing with any buffer we grab from the
|
||||
* full list.
|
||||
*
|
||||
* fixes malloc() interrupted by SIGIO risk (Bug 889)
|
||||
*/
|
||||
LOCK_F();
|
||||
if (free_recvbufs <= emerg_recvbufs || buffer_shortfall > 0)
|
||||
create_buffers(RECV_INC);
|
||||
UNLOCK_F();
|
||||
|
||||
/*
|
||||
* try to grab a full buffer
|
||||
*/
|
||||
LOCK_R();
|
||||
UNLINK_FIFO(rbuf, full_recv_fifo, link);
|
||||
if (rbuf != NULL && full_recvbufs)
|
||||
--full_recvbufs;
|
||||
UNLOCK_R();
|
||||
|
||||
return rbuf;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* purge_recv_buffers_for_fd() - purges any previously-received input
|
||||
* from a given file descriptor.
|
||||
*/
|
||||
void
|
||||
purge_recv_buffers_for_fd(
|
||||
int fd
|
||||
)
|
||||
{
|
||||
recvbuf_t *rbufp;
|
||||
recvbuf_t *next;
|
||||
recvbuf_t *punlinked;
|
||||
recvbuf_t *freelist = NULL;
|
||||
|
||||
/* We want to hold only one lock at a time. So we do a scan on
|
||||
* the full buffer queue, collecting items as we go, and when
|
||||
* done we spool the the collected items to 'freerecvbuf()'.
|
||||
*/
|
||||
LOCK_R();
|
||||
|
||||
for (rbufp = HEAD_FIFO(full_recv_fifo);
|
||||
rbufp != NULL;
|
||||
rbufp = next)
|
||||
{
|
||||
next = rbufp->link;
|
||||
# ifdef HAVE_IO_COMPLETION_PORT
|
||||
if (rbufp->dstadr == NULL && rbufp->fd == fd)
|
||||
# else
|
||||
if (rbufp->fd == fd)
|
||||
# endif
|
||||
{
|
||||
UNLINK_MID_FIFO(punlinked, full_recv_fifo,
|
||||
rbufp, link, recvbuf_t);
|
||||
INSIST(punlinked == rbufp);
|
||||
if (full_recvbufs)
|
||||
--full_recvbufs;
|
||||
rbufp->link = freelist;
|
||||
freelist = rbufp;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK_R();
|
||||
|
||||
while (freelist) {
|
||||
next = freelist->link;
|
||||
freerecvbuf(freelist);
|
||||
freelist = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Checks to see if there are buffers to process
|
||||
*/
|
||||
isc_boolean_t has_full_recv_buffer(void)
|
||||
{
|
||||
if (HEAD_FIFO(full_recv_fifo) != NULL)
|
||||
return (ISC_TRUE);
|
||||
else
|
||||
return (ISC_FALSE);
|
||||
}
|
||||
|
||||
|
||||
#ifdef NTP_DEBUG_LISTS_H
|
||||
void
|
||||
check_gen_fifo_consistency(void *fifo)
|
||||
{
|
||||
gen_fifo *pf;
|
||||
gen_node *pthis;
|
||||
gen_node **pptail;
|
||||
|
||||
pf = fifo;
|
||||
REQUIRE((NULL == pf->phead && NULL == pf->pptail) ||
|
||||
(NULL != pf->phead && NULL != pf->pptail));
|
||||
|
||||
pptail = &pf->phead;
|
||||
for (pthis = pf->phead;
|
||||
pthis != NULL;
|
||||
pthis = pthis->link)
|
||||
if (NULL != pthis->link)
|
||||
pptail = &pthis->link;
|
||||
|
||||
REQUIRE(NULL == pf->pptail || pptail == pf->pptail);
|
||||
}
|
||||
#endif /* NTP_DEBUG_LISTS_H */
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* refnumtoa - return asciized refclock addresses stored in local array space
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntp_net.h"
|
||||
#include "lib_strbuf.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
const char *
|
||||
refnumtoa(
|
||||
sockaddr_u *num
|
||||
)
|
||||
{
|
||||
u_int32 netnum;
|
||||
char *buf;
|
||||
const char *rclock;
|
||||
|
||||
if (!ISREFCLOCKADR(num))
|
||||
return socktoa(num);
|
||||
|
||||
LIB_GETBUF(buf);
|
||||
netnum = SRCADR(num);
|
||||
rclock = clockname((int)((u_long)netnum >> 8) & 0xff);
|
||||
|
||||
if (rclock != NULL)
|
||||
snprintf(buf, LIB_BUFLENGTH, "%s(%lu)",
|
||||
rclock, (u_long)netnum & 0xff);
|
||||
else
|
||||
snprintf(buf, LIB_BUFLENGTH, "REFCLK(%lu,%lu)",
|
||||
((u_long)netnum >> 8) & 0xff,
|
||||
(u_long)netnum & 0xff);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* socket.c - low-level socket operations
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntp.h"
|
||||
#include "ntp_io.h"
|
||||
#include "ntp_net.h"
|
||||
#include "ntp_debug.h"
|
||||
#include "ipcom_sock.h"
|
||||
#include "ipntp.h"
|
||||
|
||||
/*
|
||||
* Windows C runtime ioctl() can't deal properly with sockets,
|
||||
* map to ioctlsocket for this source file.
|
||||
*/
|
||||
#ifdef SYS_WINNT
|
||||
#define ioctl(fd, opt, val) ioctlsocket(fd, opt, (u_long *)(val))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* on Unix systems the stdio library typically
|
||||
* makes use of file descriptors in the lower
|
||||
* integer range. stdio usually will make use
|
||||
* of the file descriptors in the range of
|
||||
* [0..FOPEN_MAX)
|
||||
* in order to keep this range clean, for socket
|
||||
* file descriptors we attempt to move them above
|
||||
* FOPEN_MAX. This is not as easy as it sounds as
|
||||
* FOPEN_MAX changes from implementation to implementation
|
||||
* and may exceed to current file decriptor limits.
|
||||
* We are using following strategy:
|
||||
* - keep a current socket fd boundary initialized with
|
||||
* max(0, min(GETDTABLESIZE() - FD_CHUNK, FOPEN_MAX))
|
||||
* - attempt to move the descriptor to the boundary or
|
||||
* above.
|
||||
* - if that fails and boundary > 0 set boundary
|
||||
* to min(0, socket_fd_boundary - FD_CHUNK)
|
||||
* -> retry
|
||||
* if failure and boundary == 0 return old fd
|
||||
* - on success close old fd return new fd
|
||||
*
|
||||
* effects:
|
||||
* - fds will be moved above the socket fd boundary
|
||||
* if at all possible.
|
||||
* - the socket boundary will be reduced until
|
||||
* allocation is possible or 0 is reached - at this
|
||||
* point the algrithm will be disabled
|
||||
*/
|
||||
SOCKET
|
||||
move_fd(
|
||||
SOCKET fd
|
||||
)
|
||||
{
|
||||
#if !defined(SYS_WINNT) && defined(F_DUPFD)
|
||||
#ifndef FD_CHUNK
|
||||
#define FD_CHUNK 10
|
||||
#endif
|
||||
#ifndef FOPEN_MAX
|
||||
#define FOPEN_MAX 20
|
||||
#endif
|
||||
/*
|
||||
* number of fds we would like to have for
|
||||
* stdio FILE* available.
|
||||
* we can pick a "low" number as our use of
|
||||
* FILE* is limited to log files and temporarily
|
||||
* to data and config files. Except for log files
|
||||
* we don't keep the other FILE* open beyond the
|
||||
* scope of the function that opened it.
|
||||
*/
|
||||
#ifndef FD_PREFERRED_SOCKBOUNDARY
|
||||
#define FD_PREFERRED_SOCKBOUNDARY 48
|
||||
#endif
|
||||
|
||||
static SOCKET socket_boundary = -1;
|
||||
SOCKET newfd;
|
||||
|
||||
REQUIRE((int)fd >= 0);
|
||||
|
||||
/*
|
||||
* check whether boundary has be set up
|
||||
* already
|
||||
*/
|
||||
if (socket_boundary == -1) {
|
||||
socket_boundary = max(0, min(GETDTABLESIZE() - FD_CHUNK,
|
||||
min(FOPEN_MAX, FD_PREFERRED_SOCKBOUNDARY)));
|
||||
TRACE(1, ("move_fd: estimated max descriptors: %d, "
|
||||
"initial socket boundary: %d\n",
|
||||
GETDTABLESIZE(), socket_boundary));
|
||||
}
|
||||
|
||||
/*
|
||||
* Leave a space for stdio to work in. potentially moving the
|
||||
* socket_boundary lower until allocation succeeds.
|
||||
*/
|
||||
do {
|
||||
if (fd >= 0 && fd < socket_boundary) {
|
||||
/* inside reserved range: attempt to move fd */
|
||||
newfd = fcntl(fd, F_DUPFD, socket_boundary);
|
||||
|
||||
if (newfd != -1) {
|
||||
/* success: drop the old one - return the new one */
|
||||
close(fd);
|
||||
return newfd;
|
||||
}
|
||||
} else {
|
||||
/* outside reserved range: no work - return the original one */
|
||||
return fd;
|
||||
}
|
||||
socket_boundary = max(0, socket_boundary - FD_CHUNK);
|
||||
TRACE(1, ("move_fd: selecting new socket boundary: %d\n",
|
||||
socket_boundary));
|
||||
} while (socket_boundary > 0);
|
||||
#else
|
||||
REQUIRE((int)fd >= 0);
|
||||
#endif /* !defined(SYS_WINNT) && defined(F_DUPFD) */
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* make_socket_nonblocking() - set up descriptor to be non blocking
|
||||
*/
|
||||
void
|
||||
make_socket_nonblocking(
|
||||
SOCKET fd
|
||||
)
|
||||
{
|
||||
/*
|
||||
* set non-blocking,
|
||||
*/
|
||||
|
||||
#ifdef USE_FIONBIO
|
||||
/* in vxWorks we use FIONBIO, but the others are defined for old
|
||||
* systems, so all hell breaks loose if we leave them defined
|
||||
*/
|
||||
#undef O_NONBLOCK
|
||||
#undef FNDELAY
|
||||
#undef O_NDELAY
|
||||
#endif
|
||||
|
||||
#ifndef NTP_VXWORKS_7
|
||||
#if defined(O_NONBLOCK) /* POSIX */
|
||||
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
|
||||
msyslog(LOG_ERR,
|
||||
"fcntl(O_NONBLOCK) fails on fd #%d: %m", fd);
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
#elif defined(FNDELAY)
|
||||
if (fcntl(fd, F_SETFL, FNDELAY) < 0) {
|
||||
msyslog(LOG_ERR, "fcntl(FNDELAY) fails on fd #%d: %m",
|
||||
fd);
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
#elif defined(O_NDELAY) /* generally the same as FNDELAY */
|
||||
if (fcntl(fd, F_SETFL, O_NDELAY) < 0) {
|
||||
msyslog(LOG_ERR, "fcntl(O_NDELAY) fails on fd #%d: %m",
|
||||
fd);
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
#elif defined(FIONBIO)
|
||||
{
|
||||
int on = 1;
|
||||
|
||||
if (ioctl(fd, FIONBIO, &on) < 0) {
|
||||
msyslog(LOG_ERR,
|
||||
"ioctl(FIONBIO) fails on fd #%d: %m",
|
||||
fd);
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
}
|
||||
#elif defined(FIOSNBIO)
|
||||
if (ioctl(fd, FIOSNBIO, &on) < 0) {
|
||||
msyslog(LOG_ERR,
|
||||
"ioctl(FIOSNBIO) fails on fd #%d: %m", fd);
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
#else
|
||||
# include "Bletch: Need non-blocking I/O!"
|
||||
#endif
|
||||
#endif
|
||||
int on = 1;
|
||||
|
||||
if (ipcom_socketioctl(fd, IP_FIONBIO, &on) < 0) {
|
||||
msyslog(LOG_ERR,
|
||||
"ioctl(FIONBIO) fails on fd #%d: %m",
|
||||
fd);
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/* The following subroutines should probably be moved here */
|
||||
|
||||
static SOCKET
|
||||
open_socket(
|
||||
sockaddr_u * addr,
|
||||
int bcast,
|
||||
int turn_off_reuse,
|
||||
endpt * interf
|
||||
)
|
||||
void
|
||||
sendpkt(
|
||||
sockaddr_u * dest,
|
||||
struct interface * ep,
|
||||
int ttl,
|
||||
struct pkt * pkt,
|
||||
int len
|
||||
)
|
||||
|
||||
static inline int
|
||||
read_refclock_packet(SOCKET fd, struct refclockio *rp, l_fp ts)
|
||||
|
||||
static inline int
|
||||
read_network_packet(
|
||||
SOCKET fd,
|
||||
struct interface * itf,
|
||||
l_fp ts
|
||||
)
|
||||
|
||||
void
|
||||
kill_asyncio(int startfd)
|
||||
|
||||
#endif /* 0 */
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* socktoa.c socktoa(), sockporttoa(), and sock_hash()
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/netaddr.h>
|
||||
#include <isc/sockaddr.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "lib_strbuf.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp.h"
|
||||
|
||||
|
||||
/*
|
||||
* socktoa - return a numeric host name from a sockaddr_storage structure
|
||||
*/
|
||||
const char *
|
||||
socktoa(
|
||||
const sockaddr_u *sock
|
||||
)
|
||||
{
|
||||
int saved_errno;
|
||||
char * res;
|
||||
char * addr;
|
||||
u_long scope;
|
||||
|
||||
saved_errno = socket_errno();
|
||||
LIB_GETBUF(res);
|
||||
|
||||
if (NULL == sock) {
|
||||
strlcpy(res, "(null)", LIB_BUFLENGTH);
|
||||
} else {
|
||||
switch(AF(sock)) {
|
||||
|
||||
case AF_INET:
|
||||
case AF_UNSPEC:
|
||||
inet_ntop(AF_INET, PSOCK_ADDR4(sock), res,
|
||||
LIB_BUFLENGTH);
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
inet_ntop(AF_INET6, PSOCK_ADDR6(sock), res,
|
||||
LIB_BUFLENGTH);
|
||||
scope = SCOPE_VAR(sock);
|
||||
if (0 != scope && !strchr(res, '%')) {
|
||||
addr = res;
|
||||
LIB_GETBUF(res);
|
||||
snprintf(res, LIB_BUFLENGTH, "%s%%%lu",
|
||||
addr, scope);
|
||||
res[LIB_BUFLENGTH - 1] = '\0';
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
snprintf(res, LIB_BUFLENGTH,
|
||||
"(socktoa unknown family %d)",
|
||||
AF(sock));
|
||||
}
|
||||
}
|
||||
errno = saved_errno;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
sockporttoa(
|
||||
const sockaddr_u *sock
|
||||
)
|
||||
{
|
||||
int saved_errno;
|
||||
const char * atext;
|
||||
char * buf;
|
||||
|
||||
saved_errno = socket_errno();
|
||||
atext = socktoa(sock);
|
||||
LIB_GETBUF(buf);
|
||||
snprintf(buf, LIB_BUFLENGTH,
|
||||
(IS_IPV6(sock))
|
||||
? "[%s]:%hu"
|
||||
: "%s:%hu",
|
||||
atext, SRCPORT(sock));
|
||||
errno = saved_errno;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* sock_hash - hash a sockaddr_u structure
|
||||
*/
|
||||
u_short
|
||||
sock_hash(
|
||||
const sockaddr_u *addr
|
||||
)
|
||||
{
|
||||
u_int hashVal;
|
||||
u_int j;
|
||||
size_t len;
|
||||
const u_char *pch;
|
||||
|
||||
hashVal = 0;
|
||||
len = 0;
|
||||
|
||||
/*
|
||||
* We can't just hash the whole thing because there are hidden
|
||||
* fields in sockaddr_in6 that might be filled in by recvfrom(),
|
||||
* so just use the family, port and address.
|
||||
*/
|
||||
pch = (const void *)&AF(addr);
|
||||
hashVal = 37 * hashVal + *pch;
|
||||
if (sizeof(AF(addr)) > 1) {
|
||||
pch++;
|
||||
hashVal = 37 * hashVal + *pch;
|
||||
}
|
||||
switch(AF(addr)) {
|
||||
case AF_INET:
|
||||
pch = (const void *)&SOCK_ADDR4(addr);
|
||||
len = sizeof(SOCK_ADDR4(addr));
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
pch = (const void *)&SOCK_ADDR6(addr);
|
||||
len = sizeof(SOCK_ADDR6(addr));
|
||||
break;
|
||||
}
|
||||
|
||||
for (j = 0; j < len ; j++)
|
||||
hashVal = 37 * hashVal + pch[j];
|
||||
|
||||
return (u_short)(hashVal & USHRT_MAX);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sockaddr_masktoprefixlen(
|
||||
const sockaddr_u * psa
|
||||
)
|
||||
{
|
||||
isc_netaddr_t isc_na;
|
||||
isc_sockaddr_t isc_sa;
|
||||
u_int pfxlen;
|
||||
isc_result_t result;
|
||||
int rc;
|
||||
|
||||
ZERO(isc_sa);
|
||||
memcpy(&isc_sa.type, psa,
|
||||
min(sizeof(isc_sa.type), sizeof(*psa)));
|
||||
isc_netaddr_fromsockaddr(&isc_na, &isc_sa);
|
||||
result = isc_netaddr_masktoprefixlen(&isc_na, &pfxlen);
|
||||
rc = (ISC_R_SUCCESS == result)
|
||||
? (int)pfxlen
|
||||
: -1;
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* socktoa - return a numeric host name from a sockaddr_storage structure
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "lib_strbuf.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp.h"
|
||||
#include "ntp_debug.h"
|
||||
#include "ntp_rfc2553.h"
|
||||
|
||||
extern char *gai_strerror(int ecode);
|
||||
|
||||
const char *
|
||||
socktohost(
|
||||
const sockaddr_u *sock
|
||||
)
|
||||
{
|
||||
const char svc[] = "ntp";
|
||||
char * pbuf;
|
||||
char * pliar;
|
||||
int gni_flags;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo * alist;
|
||||
struct addrinfo * ai;
|
||||
sockaddr_u addr;
|
||||
size_t octets;
|
||||
int a_info;
|
||||
int saved_errno;
|
||||
|
||||
saved_errno = socket_errno();
|
||||
|
||||
/* reverse the address to purported DNS name */
|
||||
LIB_GETBUF(pbuf);
|
||||
gni_flags = IP_NI_DGRAM | IP_NI_NAMEREQD;
|
||||
if (getnameinfo(&sock->sa, (Ip_socklen_t)SOCKLEN(sock), pbuf, LIB_BUFLENGTH,
|
||||
NULL, 0, gni_flags)) {
|
||||
errno = saved_errno;
|
||||
return stoa(sock); /* use address */
|
||||
}
|
||||
|
||||
TRACE(1, ("%s reversed to %s\n", stoa(sock), pbuf));
|
||||
|
||||
/*
|
||||
* Resolve the reversed name and make sure the reversed address
|
||||
* is among the results.
|
||||
*/
|
||||
ZERO(hints);
|
||||
hints.ai_family = AF(sock);
|
||||
hints.ai_protocol = IPPROTO_UDP;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_flags = 0;
|
||||
alist = NULL;
|
||||
|
||||
a_info = getaddrinfo(pbuf, svc, &hints, &alist);
|
||||
if (a_info == EAI_NONAME
|
||||
#ifdef EAI_NODATA
|
||||
|| a_info == EAI_NODATA
|
||||
#endif
|
||||
) {
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
#ifdef AI_ADDRCONFIG
|
||||
hints.ai_flags |= AI_ADDRCONFIG;
|
||||
#endif
|
||||
a_info = getaddrinfo(pbuf, svc, &hints, &alist);
|
||||
}
|
||||
#ifdef AI_ADDRCONFIG
|
||||
/* Some older implementations don't like AI_ADDRCONFIG. */
|
||||
if (a_info == EAI_BADFLAGS) {
|
||||
hints.ai_flags &= ~AI_ADDRCONFIG;
|
||||
a_info = getaddrinfo(pbuf, svc, &hints, &alist);
|
||||
}
|
||||
#endif
|
||||
if (a_info)
|
||||
goto forward_fail;
|
||||
|
||||
INSIST(alist != NULL);
|
||||
|
||||
for (ai = alist; ai != NULL; ai = ai->ai_next) {
|
||||
/*
|
||||
* Make a convenience sockaddr_u copy from ai->ai_addr
|
||||
* because casting from sockaddr * to sockaddr_u * is
|
||||
* risking alignment problems on platforms where
|
||||
* sockaddr_u has stricter alignment than sockaddr,
|
||||
* such as sparc.
|
||||
*/
|
||||
ZERO_SOCK(&addr);
|
||||
octets = min(sizeof(addr), ai->ai_addrlen);
|
||||
memcpy(&addr, ai->ai_addr, octets);
|
||||
if (SOCK_EQ(sock, &addr))
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(alist);
|
||||
|
||||
if (ai != NULL) {
|
||||
errno = saved_errno;
|
||||
return pbuf; /* forward check passed */
|
||||
}
|
||||
|
||||
forward_fail:
|
||||
TRACE(1, ("%s forward check lookup fail: %s\n", pbuf,
|
||||
(char *)gai_strerror(a_info)));
|
||||
LIB_GETBUF(pliar);
|
||||
snprintf(pliar, LIB_BUFLENGTH, "%s (%s)", stoa(sock), pbuf);
|
||||
|
||||
errno = saved_errno;
|
||||
return pliar;
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* ssl_init.c Common OpenSSL initialization code for the various
|
||||
* programs which use it.
|
||||
*
|
||||
* Moved from ntpd/ntp_crypto.c crypto_setup()
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <ipntp_config.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#include <ntp.h>
|
||||
#include <ntp_debug.h>
|
||||
#include <lib_strbuf.h>
|
||||
|
||||
#ifdef OPENSSL
|
||||
# include <openssl/crypto.h>
|
||||
# include <openssl/err.h>
|
||||
# include <openssl/evp.h>
|
||||
#include "stdlib.h"
|
||||
# include <openssl/opensslv.h>
|
||||
# include "libssl_compat.h"
|
||||
# ifdef HAVE_OPENSSL_CMAC_H
|
||||
# include <openssl/cmac.h>
|
||||
# define CMAC_LENGTH 16
|
||||
# define CMAC "AES128CMAC"
|
||||
# endif /*HAVE_OPENSSL_CMAC_H*/
|
||||
extern int atexit (void (*__func)(void));
|
||||
int ssl_init_done;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
|
||||
static void
|
||||
atexit_ssl_cleanup(void)
|
||||
{
|
||||
if (!ssl_init_done) {
|
||||
return;
|
||||
}
|
||||
|
||||
ssl_init_done = FALSE;
|
||||
EVP_cleanup();
|
||||
ERR_free_strings();
|
||||
}
|
||||
|
||||
void
|
||||
ssl_init(void)
|
||||
{
|
||||
init_lib();
|
||||
|
||||
if ( ! ssl_init_done) {
|
||||
ERR_load_crypto_strings();
|
||||
OpenSSL_add_all_algorithms();
|
||||
atexit(&atexit_ssl_cleanup);
|
||||
ssl_init_done = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
|
||||
|
||||
void
|
||||
ssl_init(void)
|
||||
{
|
||||
init_lib();
|
||||
ssl_init_done = TRUE;
|
||||
}
|
||||
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
|
||||
void
|
||||
ssl_check_version(void)
|
||||
{
|
||||
u_long v;
|
||||
|
||||
v = OpenSSL_version_num();
|
||||
if ((v ^ OPENSSL_VERSION_NUMBER) & ~0xff0L) {
|
||||
msyslog(LOG_WARNING,
|
||||
"OpenSSL version mismatch. Built against %lx, you have %lx",
|
||||
(u_long)OPENSSL_VERSION_NUMBER, v);
|
||||
fprintf(stderr,
|
||||
"OpenSSL version mismatch. Built against %lx, you have %lx\n",
|
||||
(u_long)OPENSSL_VERSION_NUMBER, v);
|
||||
}
|
||||
|
||||
INIT_SSL();
|
||||
}
|
||||
|
||||
#else /* !OPENSSL */
|
||||
# define MD5_LENGTH 16
|
||||
#endif /* OPENSSL */
|
||||
|
||||
|
||||
/*
|
||||
* keytype_from_text returns OpenSSL NID for digest by name, and
|
||||
* optionally the associated digest length.
|
||||
*
|
||||
* Used by ntpd authreadkeys(), ntpq and ntpdc keytype()
|
||||
*/
|
||||
int
|
||||
keytype_from_text(
|
||||
const char * text,
|
||||
size_t * pdigest_len
|
||||
)
|
||||
{
|
||||
int key_type;
|
||||
u_int digest_len;
|
||||
#ifdef OPENSSL /* --*-- OpenSSL code --*-- */
|
||||
const u_long max_digest_len = MAX_MAC_LEN - sizeof(keyid_t);
|
||||
char * upcased;
|
||||
char * pch;
|
||||
EVP_MD const * md;
|
||||
|
||||
/*
|
||||
* OpenSSL digest short names are capitalized, so uppercase the
|
||||
* digest name before passing to OBJ_sn2nid(). If it is not
|
||||
* recognized but matches our CMAC string use NID_cmac, or if
|
||||
* it begins with 'M' or 'm' use NID_md5 to be consistent with
|
||||
* past behavior.
|
||||
*/
|
||||
INIT_SSL();
|
||||
|
||||
/* get name in uppercase */
|
||||
LIB_GETBUF(upcased);
|
||||
strlcpy(upcased, text, LIB_BUFLENGTH);
|
||||
|
||||
for (pch = upcased; '\0' != *pch; pch++) {
|
||||
*pch = (char)toupper((unsigned char)*pch);
|
||||
}
|
||||
|
||||
key_type = OBJ_sn2nid(upcased);
|
||||
|
||||
# ifdef ENABLE_CMAC
|
||||
if (!key_type && !strncmp(CMAC, upcased, strlen(CMAC) + 1)) {
|
||||
key_type = NID_cmac;
|
||||
|
||||
if (debug) {
|
||||
fprintf(stderr, "%s:%d:%s():%s:key\n",
|
||||
__FILE__, __LINE__, __func__, CMAC);
|
||||
}
|
||||
}
|
||||
# endif /*ENABLE_CMAC*/
|
||||
#else
|
||||
|
||||
key_type = 0;
|
||||
#endif
|
||||
|
||||
if (!key_type && 'm' == tolower((unsigned char)text[0])) {
|
||||
key_type = NID_md5;
|
||||
}
|
||||
|
||||
if (!key_type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (NULL != pdigest_len) {
|
||||
#ifdef OPENSSL
|
||||
md = EVP_get_digestbynid(key_type);
|
||||
digest_len = (md) ? EVP_MD_size(md) : 0;
|
||||
|
||||
if (!md || digest_len <= 0) {
|
||||
# ifdef ENABLE_CMAC
|
||||
if (key_type == NID_cmac) {
|
||||
digest_len = CMAC_LENGTH;
|
||||
|
||||
if (debug) {
|
||||
fprintf(stderr, "%s:%d:%s():%s:len\n",
|
||||
__FILE__, __LINE__, __func__, CMAC);
|
||||
}
|
||||
} else
|
||||
# endif /*ENABLE_CMAC*/
|
||||
{
|
||||
fprintf(stderr,
|
||||
"key type %s is not supported by OpenSSL\n",
|
||||
keytype_name(key_type));
|
||||
msyslog(LOG_ERR,
|
||||
"key type %s is not supported by OpenSSL\n",
|
||||
keytype_name(key_type));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (digest_len > max_digest_len) {
|
||||
fprintf(stderr,
|
||||
"key type %s %u octet digests are too big, max %lu\n",
|
||||
keytype_name(key_type), digest_len,
|
||||
max_digest_len);
|
||||
msyslog(LOG_ERR,
|
||||
"key type %s %u octet digests are too big, max %lu",
|
||||
keytype_name(key_type), digest_len,
|
||||
max_digest_len);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
digest_len = MD5_LENGTH;
|
||||
#endif
|
||||
*pdigest_len = digest_len;
|
||||
}
|
||||
|
||||
return key_type;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* keytype_name returns OpenSSL short name for digest by NID.
|
||||
*
|
||||
* Used by ntpq and ntpdc keytype()
|
||||
*/
|
||||
const char *
|
||||
keytype_name(
|
||||
int nid
|
||||
)
|
||||
{
|
||||
static const char unknown_type[] = "(unknown key type)";
|
||||
const char *name;
|
||||
|
||||
#ifdef OPENSSL
|
||||
INIT_SSL();
|
||||
name = OBJ_nid2sn(nid);
|
||||
|
||||
# ifdef ENABLE_CMAC
|
||||
if (NID_cmac == nid) {
|
||||
name = CMAC;
|
||||
|
||||
if (debug) {
|
||||
fprintf(stderr, "%s:%d:%s():%s:nid\n",
|
||||
__FILE__, __LINE__, __func__, CMAC);
|
||||
}
|
||||
} else
|
||||
# endif /*ENABLE_CMAC*/
|
||||
if (NULL == name) {
|
||||
name = unknown_type;
|
||||
}
|
||||
#else /* !OPENSSL follows */
|
||||
if (NID_md5 == nid)
|
||||
name = "MD5";
|
||||
else
|
||||
name = unknown_type;
|
||||
#endif
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Use getpassphrase() if configure.ac detected it, as Suns that
|
||||
* have it truncate the password in getpass() to 8 characters.
|
||||
*/
|
||||
#ifdef HAVE_GETPASSPHRASE
|
||||
# define getpass(str) getpassphrase(str)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* getpass_keytype() -- shared between ntpq and ntpdc, only vaguely
|
||||
* related to the rest of ssl_init.c.
|
||||
*/
|
||||
char *
|
||||
getpass_keytype(
|
||||
int keytype
|
||||
)
|
||||
{
|
||||
char pass_prompt[64 + 11 + 1]; /* 11 for " Password: " */
|
||||
|
||||
snprintf(pass_prompt, sizeof(pass_prompt),
|
||||
"%.64s Password: ", keytype_name(keytype));
|
||||
|
||||
return getpass(pass_prompt);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,517 @@
|
||||
/*
|
||||
* pretty printing of status information
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <ipntp_config.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_fp.h"
|
||||
#include "ntp.h"
|
||||
#include "lib_strbuf.h"
|
||||
#include "ntp_refclock.h"
|
||||
#include "ntp_control.h"
|
||||
#include "ntp_string.h"
|
||||
#ifdef KERNEL_PLL
|
||||
# include "ntp_syscall.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Structure for turning various constants into a readable string.
|
||||
*/
|
||||
struct codestring {
|
||||
int code;
|
||||
const char * const string1;
|
||||
const char * const string0;
|
||||
};
|
||||
|
||||
/*
|
||||
* Leap status (leap)
|
||||
*/
|
||||
static const struct codestring leap_codes[] = {
|
||||
{ LEAP_NOWARNING, "leap_none", 0 },
|
||||
{ LEAP_ADDSECOND, "leap_add_sec", 0 },
|
||||
{ LEAP_DELSECOND, "leap_del_sec", 0 },
|
||||
{ LEAP_NOTINSYNC, "leap_alarm", 0 },
|
||||
{ -1, "leap", 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Clock source status (sync)
|
||||
*/
|
||||
static const struct codestring sync_codes[] = {
|
||||
{ CTL_SST_TS_UNSPEC, "sync_unspec", 0 },
|
||||
{ CTL_SST_TS_ATOM, "sync_pps", 0 },
|
||||
{ CTL_SST_TS_LF, "sync_lf_radio", 0 },
|
||||
{ CTL_SST_TS_HF, "sync_hf_radio", 0 },
|
||||
{ CTL_SST_TS_UHF, "sync_uhf_radio", 0 },
|
||||
{ CTL_SST_TS_LOCAL, "sync_local", 0 },
|
||||
{ CTL_SST_TS_NTP, "sync_ntp", 0 },
|
||||
{ CTL_SST_TS_UDPTIME, "sync_other", 0 },
|
||||
{ CTL_SST_TS_WRSTWTCH, "sync_wristwatch", 0 },
|
||||
{ CTL_SST_TS_TELEPHONE, "sync_telephone", 0 },
|
||||
{ -1, "sync", 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Peer selection status (sel)
|
||||
*/
|
||||
static const struct codestring select_codes[] = {
|
||||
{ CTL_PST_SEL_REJECT, "sel_reject", 0 },
|
||||
{ CTL_PST_SEL_SANE, "sel_falsetick", 0 },
|
||||
{ CTL_PST_SEL_CORRECT, "sel_excess", 0 },
|
||||
{ CTL_PST_SEL_SELCAND, "sel_outlyer", 0 },
|
||||
{ CTL_PST_SEL_SYNCCAND, "sel_candidate", 0 },
|
||||
{ CTL_PST_SEL_EXCESS, "sel_backup", 0 },
|
||||
{ CTL_PST_SEL_SYSPEER, "sel_sys.peer", 0 },
|
||||
{ CTL_PST_SEL_PPS, "sel_pps.peer", 0 },
|
||||
{ -1, "sel", 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Clock status (clk)
|
||||
*/
|
||||
static const struct codestring clock_codes[] = {
|
||||
{ CTL_CLK_OKAY, "clk_unspec", 0 },
|
||||
{ CTL_CLK_NOREPLY, "clk_no_reply", 0 },
|
||||
{ CTL_CLK_BADFORMAT, "clk_bad_format", 0 },
|
||||
{ CTL_CLK_FAULT, "clk_fault", 0 },
|
||||
{ CTL_CLK_PROPAGATION, "clk_bad_signal", 0 },
|
||||
{ CTL_CLK_BADDATE, "clk_bad_date", 0 },
|
||||
{ CTL_CLK_BADTIME, "clk_bad_time", 0 },
|
||||
{ -1, "clk", 0 }
|
||||
};
|
||||
|
||||
|
||||
#ifdef FLASH_CODES_UNUSED
|
||||
/*
|
||||
* Flash bits -- see ntpq.c tstflags & tstflagnames
|
||||
*/
|
||||
static const struct codestring flash_codes[] = {
|
||||
{ TEST1, "pkt_dup", 0 },
|
||||
{ TEST2, "pkt_bogus", 0 },
|
||||
{ TEST3, "pkt_unsync", 0 },
|
||||
{ TEST4, "pkt_denied", 0 },
|
||||
{ TEST5, "pkt_auth", 0 },
|
||||
{ TEST6, "pkt_stratum", 0 },
|
||||
{ TEST7, "pkt_header", 0 },
|
||||
{ TEST8, "pkt_autokey", 0 },
|
||||
{ TEST9, "pkt_crypto", 0 },
|
||||
{ TEST10, "peer_stratum", 0 },
|
||||
{ TEST11, "peer_dist", 0 },
|
||||
{ TEST12, "peer_loop", 0 },
|
||||
{ TEST13, "peer_unreach", 0 },
|
||||
{ -1, "flash", 0 }
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* System events (sys)
|
||||
*/
|
||||
static const struct codestring sys_codes[] = {
|
||||
{ EVNT_UNSPEC, "unspecified", 0 },
|
||||
{ EVNT_NSET, "freq_not_set", 0 },
|
||||
{ EVNT_FSET, "freq_set", 0 },
|
||||
{ EVNT_SPIK, "spike_detect", 0 },
|
||||
{ EVNT_FREQ, "freq_mode", 0 },
|
||||
{ EVNT_SYNC, "clock_sync", 0 },
|
||||
{ EVNT_SYSRESTART, "restart", 0 },
|
||||
{ EVNT_SYSFAULT, "panic_stop", 0 },
|
||||
{ EVNT_NOPEER, "no_sys_peer", 0 },
|
||||
{ EVNT_ARMED, "leap_armed", 0 },
|
||||
{ EVNT_DISARMED, "leap_disarmed", 0 },
|
||||
{ EVNT_LEAP, "leap_event", 0 },
|
||||
{ EVNT_CLOCKRESET, "clock_step", 0 },
|
||||
{ EVNT_KERN, "kern", 0 },
|
||||
{ EVNT_TAI, "TAI", 0 },
|
||||
{ EVNT_LEAPVAL, "stale_leapsecond_values", 0 },
|
||||
{ -1, "", 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Peer events (peer)
|
||||
*/
|
||||
static const struct codestring peer_codes[] = {
|
||||
{ PEVNT_MOBIL & ~PEER_EVENT, "mobilize", 0 },
|
||||
{ PEVNT_DEMOBIL & ~PEER_EVENT, "demobilize", 0 },
|
||||
{ PEVNT_UNREACH & ~PEER_EVENT, "unreachable", 0 },
|
||||
{ PEVNT_REACH & ~PEER_EVENT, "reachable", 0 },
|
||||
{ PEVNT_RESTART & ~PEER_EVENT, "restart", 0 },
|
||||
{ PEVNT_REPLY & ~PEER_EVENT, "no_reply", 0 },
|
||||
{ PEVNT_RATE & ~PEER_EVENT, "rate_exceeded", 0 },
|
||||
{ PEVNT_DENY & ~PEER_EVENT, "access_denied", 0 },
|
||||
{ PEVNT_ARMED & ~PEER_EVENT, "leap_armed", 0 },
|
||||
{ PEVNT_NEWPEER & ~PEER_EVENT, "sys_peer", 0 },
|
||||
{ PEVNT_CLOCK & ~PEER_EVENT, "clock_event", 0 },
|
||||
{ PEVNT_AUTH & ~PEER_EVENT, "bad_auth", 0 },
|
||||
{ PEVNT_POPCORN & ~PEER_EVENT, "popcorn", 0 },
|
||||
{ PEVNT_XLEAVE & ~PEER_EVENT, "interleave_mode", 0 },
|
||||
{ PEVNT_XERR & ~PEER_EVENT, "interleave_error", 0 },
|
||||
{ -1, "", 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Peer status bits
|
||||
*/
|
||||
static const struct codestring peer_st_bits[] = {
|
||||
{ CTL_PST_CONFIG, "conf", 0 },
|
||||
{ CTL_PST_AUTHENABLE, "authenb", 0 },
|
||||
{ CTL_PST_AUTHENTIC, "auth", 0 },
|
||||
{ CTL_PST_REACH, "reach", 0 },
|
||||
{ CTL_PST_BCAST, "bcast", 0 },
|
||||
/* not used with getcode(), no terminating entry needed */
|
||||
};
|
||||
|
||||
/*
|
||||
* Restriction match bits
|
||||
*/
|
||||
static const struct codestring res_match_bits[] = {
|
||||
{ RESM_NTPONLY, "ntpport", 0 },
|
||||
{ RESM_INTERFACE, "interface", 0 },
|
||||
{ RESM_SOURCE, "source", 0 },
|
||||
/* not used with getcode(), no terminating entry needed */
|
||||
};
|
||||
|
||||
/*
|
||||
* Restriction access bits
|
||||
*/
|
||||
static const struct codestring res_access_bits[] = {
|
||||
{ RES_IGNORE, "ignore", 0 },
|
||||
{ RES_DONTSERVE, "noserve", "serve" },
|
||||
{ RES_DONTTRUST, "notrust", "trust" },
|
||||
{ RES_VERSION, "version", 0 },
|
||||
{ RES_NOPEER, "nopeer", "peer" },
|
||||
{ RES_NOEPEER, "noepeer", "epeer" },
|
||||
{ RES_LIMITED, "limited", 0 },
|
||||
|
||||
{ RES_NOQUERY, "noquery", "query" },
|
||||
{ RES_NOMODIFY, "nomodify", 0 },
|
||||
{ RES_NOTRAP, "notrap", "trap" },
|
||||
{ RES_LPTRAP, "lptrap", 0 },
|
||||
|
||||
{ RES_KOD, "kod", 0 },
|
||||
{ RES_MSSNTP, "mssntp", 0 },
|
||||
{ RES_FLAKE, "flake", 0 },
|
||||
{ RES_NOMRULIST, "nomrulist", 0 },
|
||||
|
||||
{ RES_SRVRSPFUZ, "serverresponse fuzz", 0 },
|
||||
|
||||
/* not used with getcode(), no terminating entry needed */
|
||||
};
|
||||
|
||||
#ifdef AUTOKEY
|
||||
/*
|
||||
* Crypto events (cryp)
|
||||
*/
|
||||
static const struct codestring crypto_codes[] = {
|
||||
{ XEVNT_OK & ~CRPT_EVENT, "success", 0 },
|
||||
{ XEVNT_LEN & ~CRPT_EVENT, "bad_field_format_or_length", 0 },
|
||||
{ XEVNT_TSP & ~CRPT_EVENT, "bad_timestamp", 0 },
|
||||
{ XEVNT_FSP & ~CRPT_EVENT, "bad_filestamp", 0 },
|
||||
{ XEVNT_PUB & ~CRPT_EVENT, "bad_or_missing_public_key", 0 },
|
||||
{ XEVNT_MD & ~CRPT_EVENT, "unsupported_digest_type", 0 },
|
||||
{ XEVNT_KEY & ~CRPT_EVENT, "unsupported_identity_type", 0 },
|
||||
{ XEVNT_SGL & ~CRPT_EVENT, "bad_signature_length", 0 },
|
||||
{ XEVNT_SIG & ~CRPT_EVENT, "signature_not_verified", 0 },
|
||||
{ XEVNT_VFY & ~CRPT_EVENT, "certificate_not_verified", 0 },
|
||||
{ XEVNT_PER & ~CRPT_EVENT, "host_certificate_expired", 0 },
|
||||
{ XEVNT_CKY & ~CRPT_EVENT, "bad_or_missing_cookie", 0 },
|
||||
{ XEVNT_DAT & ~CRPT_EVENT, "bad_or_missing_leapseconds", 0 },
|
||||
{ XEVNT_CRT & ~CRPT_EVENT, "bad_or_missing_certificate", 0 },
|
||||
{ XEVNT_ID & ~CRPT_EVENT, "bad_or_missing_group key", 0 },
|
||||
{ XEVNT_ERR & ~CRPT_EVENT, "protocol_error", 0 },
|
||||
{ -1, "", 0 }
|
||||
};
|
||||
#endif /* AUTOKEY */
|
||||
|
||||
#ifdef KERNEL_PLL
|
||||
/*
|
||||
* kernel discipline status bits
|
||||
*/
|
||||
static const struct codestring k_st_bits[] = {
|
||||
# ifdef STA_PLL
|
||||
{ STA_PLL, "pll", 0 },
|
||||
# endif
|
||||
# ifdef STA_PPSFREQ
|
||||
{ STA_PPSFREQ, "ppsfreq", 0 },
|
||||
# endif
|
||||
# ifdef STA_PPSTIME
|
||||
{ STA_PPSTIME, "ppstime", 0 },
|
||||
# endif
|
||||
# ifdef STA_FLL
|
||||
{ STA_FLL, "fll", 0 },
|
||||
# endif
|
||||
# ifdef STA_INS
|
||||
{ STA_INS, "ins", 0 },
|
||||
# endif
|
||||
# ifdef STA_DEL
|
||||
{ STA_DEL, "del", 0 },
|
||||
# endif
|
||||
# ifdef STA_UNSYNC
|
||||
{ STA_UNSYNC, "unsync", 0 },
|
||||
# endif
|
||||
# ifdef STA_FREQHOLD
|
||||
{ STA_FREQHOLD, "freqhold", 0 },
|
||||
# endif
|
||||
# ifdef STA_PPSSIGNAL
|
||||
{ STA_PPSSIGNAL, "ppssignal", 0 },
|
||||
# endif
|
||||
# ifdef STA_PPSJITTER
|
||||
{ STA_PPSJITTER, "ppsjitter", 0 },
|
||||
# endif
|
||||
# ifdef STA_PPSWANDER
|
||||
{ STA_PPSWANDER, "ppswander", 0 },
|
||||
# endif
|
||||
# ifdef STA_PPSERROR
|
||||
{ STA_PPSERROR, "ppserror", 0 },
|
||||
# endif
|
||||
# ifdef STA_CLOCKERR
|
||||
{ STA_CLOCKERR, "clockerr", 0 },
|
||||
# endif
|
||||
# ifdef STA_NANO
|
||||
{ STA_NANO, "nano", 0 },
|
||||
# endif
|
||||
# ifdef STA_MODE
|
||||
{ STA_MODE, "mode=fll", 0 },
|
||||
# endif
|
||||
# ifdef STA_CLK
|
||||
{ STA_CLK, "src=B", 0 },
|
||||
# endif
|
||||
/* not used with getcode(), no terminating entry needed */
|
||||
};
|
||||
#endif /* KERNEL_PLL */
|
||||
|
||||
/* Forwards */
|
||||
static const char * getcode(int, const struct codestring *);
|
||||
static const char * getevents(int);
|
||||
static const char * peer_st_flags(u_char pst);
|
||||
|
||||
/*
|
||||
* getcode - return string corresponding to code
|
||||
*/
|
||||
static const char *
|
||||
getcode(
|
||||
int code,
|
||||
const struct codestring * codetab
|
||||
)
|
||||
{
|
||||
char * buf;
|
||||
|
||||
while (codetab->code != -1) {
|
||||
if (codetab->code == code)
|
||||
return codetab->string1;
|
||||
codetab++;
|
||||
}
|
||||
|
||||
LIB_GETBUF(buf);
|
||||
snprintf(buf, LIB_BUFLENGTH, "%s_%d", codetab->string1, code);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* getevents - return a descriptive string for the event count
|
||||
*/
|
||||
static const char *
|
||||
getevents(
|
||||
int cnt
|
||||
)
|
||||
{
|
||||
char * buf;
|
||||
|
||||
if (cnt == 0)
|
||||
return "no events";
|
||||
|
||||
LIB_GETBUF(buf);
|
||||
snprintf(buf, LIB_BUFLENGTH, "%d event%s", cnt,
|
||||
(1 == cnt)
|
||||
? ""
|
||||
: "s");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* decode_bitflags()
|
||||
*
|
||||
* returns a human-readable string with a keyword from tab for each bit
|
||||
* set in bits, separating multiple entries with text of sep2.
|
||||
*/
|
||||
static const char *
|
||||
decode_bitflags(
|
||||
int bits,
|
||||
const char * sep2,
|
||||
const struct codestring * tab,
|
||||
size_t tab_ct
|
||||
)
|
||||
{
|
||||
const char * sep;
|
||||
char * buf;
|
||||
char * pch;
|
||||
char * lim;
|
||||
size_t b;
|
||||
int rc;
|
||||
int saved_errno; /* for use in DPRINTF with %m */
|
||||
|
||||
saved_errno = errno;
|
||||
LIB_GETBUF(buf);
|
||||
pch = buf;
|
||||
lim = buf + LIB_BUFLENGTH;
|
||||
sep = "";
|
||||
|
||||
for (b = 0; b < tab_ct; b++) {
|
||||
const char * flagstr;
|
||||
|
||||
if (tab[b].code & bits) {
|
||||
flagstr = tab[b].string1;
|
||||
} else {
|
||||
flagstr = tab[b].string0;
|
||||
}
|
||||
|
||||
if (flagstr) {
|
||||
size_t avail = lim - pch;
|
||||
rc = snprintf(pch, avail, "%s%s", sep,
|
||||
flagstr);
|
||||
if ((size_t)rc >= avail)
|
||||
goto toosmall;
|
||||
pch += rc;
|
||||
sep = sep2;
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
|
||||
toosmall:
|
||||
snprintf(buf, LIB_BUFLENGTH,
|
||||
"decode_bitflags(%s) can't decode 0x%x in %d bytes",
|
||||
(tab == peer_st_bits)
|
||||
? "peer_st"
|
||||
:
|
||||
#ifdef KERNEL_PLL
|
||||
(tab == k_st_bits)
|
||||
? "kern_st"
|
||||
:
|
||||
#endif
|
||||
"",
|
||||
bits, (int)LIB_BUFLENGTH);
|
||||
errno = saved_errno;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
peer_st_flags(
|
||||
u_char pst
|
||||
)
|
||||
{
|
||||
return decode_bitflags(pst, ", ", peer_st_bits,
|
||||
COUNTOF(peer_st_bits));
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
res_match_flags(
|
||||
u_short mf
|
||||
)
|
||||
{
|
||||
return decode_bitflags(mf, " ", res_match_bits,
|
||||
COUNTOF(res_match_bits));
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
res_access_flags(
|
||||
u_int32 af
|
||||
)
|
||||
{
|
||||
return decode_bitflags(af, " ", res_access_bits,
|
||||
COUNTOF(res_access_bits));
|
||||
}
|
||||
|
||||
|
||||
#ifdef KERNEL_PLL
|
||||
const char *
|
||||
k_st_flags(
|
||||
unsigned int st
|
||||
)
|
||||
{
|
||||
return decode_bitflags(st, " ", k_st_bits, COUNTOF(k_st_bits));
|
||||
}
|
||||
#endif /* KERNEL_PLL */
|
||||
|
||||
|
||||
/*
|
||||
* statustoa - return a descriptive string for a peer status
|
||||
*/
|
||||
char *
|
||||
statustoa(
|
||||
int type,
|
||||
int st
|
||||
)
|
||||
{
|
||||
char * cb;
|
||||
char * cc;
|
||||
u_char pst;
|
||||
|
||||
LIB_GETBUF(cb);
|
||||
|
||||
switch (type) {
|
||||
|
||||
case TYPE_SYS:
|
||||
snprintf(cb, LIB_BUFLENGTH, "%s, %s, %s, %s",
|
||||
getcode(CTL_SYS_LI(st), leap_codes),
|
||||
getcode(CTL_SYS_SOURCE(st), sync_codes),
|
||||
getevents(CTL_SYS_NEVNT(st)),
|
||||
getcode(CTL_SYS_EVENT(st), sys_codes));
|
||||
break;
|
||||
|
||||
case TYPE_PEER:
|
||||
pst = (u_char)CTL_PEER_STATVAL(st);
|
||||
snprintf(cb, LIB_BUFLENGTH, "%s, %s, %s",
|
||||
peer_st_flags(pst),
|
||||
getcode(pst & 0x7, select_codes),
|
||||
getevents(CTL_PEER_NEVNT(st)));
|
||||
if (CTL_PEER_EVENT(st) != EVNT_UNSPEC) {
|
||||
cc = cb + strlen(cb);
|
||||
snprintf(cc, LIB_BUFLENGTH - (cc - cb), ", %s",
|
||||
getcode(CTL_PEER_EVENT(st),
|
||||
peer_codes));
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_CLOCK:
|
||||
snprintf(cb, LIB_BUFLENGTH, "%s, %s",
|
||||
getevents(CTL_SYS_NEVNT(st)),
|
||||
getcode((st) & 0xf, clock_codes));
|
||||
break;
|
||||
}
|
||||
|
||||
return cb;
|
||||
}
|
||||
|
||||
const char *
|
||||
eventstr(
|
||||
int num
|
||||
)
|
||||
{
|
||||
if (num & PEER_EVENT)
|
||||
return (getcode(num & ~PEER_EVENT, peer_codes));
|
||||
#ifdef AUTOKEY
|
||||
else if (num & CRPT_EVENT)
|
||||
return (getcode(num & ~CRPT_EVENT, crypto_codes));
|
||||
#endif /* AUTOKEY */
|
||||
else
|
||||
return (getcode(num, sys_codes));
|
||||
}
|
||||
|
||||
const char *
|
||||
ceventstr(
|
||||
int num
|
||||
)
|
||||
{
|
||||
return getcode(num, clock_codes);
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <ipntp_config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <ipcom_type.h>
|
||||
#include <ipcom_os.h>
|
||||
#include <ipntp.h>
|
||||
|
||||
#include "ntp_syslog.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
static ctrl_c_fn ctrl_c_hook;
|
||||
#ifndef SYS_WINNT
|
||||
RETSIGTYPE sigint_handler(int);
|
||||
#else
|
||||
BOOL WINAPI console_event_handler(DWORD);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_SIGACTION
|
||||
|
||||
# ifdef SA_RESTART
|
||||
# define Z_SA_RESTART SA_RESTART
|
||||
# else
|
||||
# define Z_SA_RESTART 0
|
||||
# endif
|
||||
|
||||
void
|
||||
signal_no_reset(
|
||||
int sig,
|
||||
void (*func)(int)
|
||||
)
|
||||
{
|
||||
int n;
|
||||
struct sigaction vec;
|
||||
struct sigaction ovec;
|
||||
|
||||
ZERO(vec);
|
||||
sigemptyset(&vec.sa_mask);
|
||||
vec.sa_handler = func;
|
||||
|
||||
/* Added for PPS clocks on Solaris 7 which get EINTR errors */
|
||||
# ifdef SIGPOLL
|
||||
if (SIGPOLL == sig)
|
||||
vec.sa_flags = Z_SA_RESTART;
|
||||
# endif
|
||||
# ifdef SIGIO
|
||||
if (SIGIO == sig)
|
||||
vec.sa_flags = Z_SA_RESTART;
|
||||
# endif
|
||||
|
||||
do
|
||||
n = sigaction(sig, &vec, &ovec);
|
||||
while (-1 == n && EINTR == errno);
|
||||
if (-1 == n) {
|
||||
perror("sigaction");
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
}
|
||||
|
||||
#elif HAVE_SIGVEC
|
||||
|
||||
void
|
||||
signal_no_reset(
|
||||
int sig,
|
||||
RETSIGTYPE (*func)(int)
|
||||
)
|
||||
{
|
||||
struct sigvec sv;
|
||||
int n;
|
||||
|
||||
ZERO(sv);
|
||||
sv.sv_handler = func;
|
||||
n = sigvec(sig, &sv, (struct sigvec *)NULL);
|
||||
if (-1 == n) {
|
||||
perror("sigvec");
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
}
|
||||
|
||||
#elif HAVE_SIGSET
|
||||
|
||||
void
|
||||
signal_no_reset(
|
||||
int sig,
|
||||
RETSIGTYPE (*func)(int)
|
||||
)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = sigset(sig, func);
|
||||
if (-1 == n) {
|
||||
perror("sigset");
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Beware! This implementation resets the signal to SIG_DFL */
|
||||
void
|
||||
signal_no_reset(
|
||||
int sig,
|
||||
RETSIGTYPE (*func)(int)
|
||||
)
|
||||
{
|
||||
#ifndef SIG_ERR
|
||||
# define SIG_ERR (-1)
|
||||
#endif
|
||||
if (SIG_ERR == signal(sig, func)) {
|
||||
perror("signal");
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef SYS_WINNT
|
||||
/*
|
||||
* POSIX implementation of set_ctrl_c_hook()
|
||||
*/
|
||||
RETSIGTYPE
|
||||
sigint_handler(
|
||||
int signum
|
||||
)
|
||||
{
|
||||
UNUSED_ARG(signum);
|
||||
if (ctrl_c_hook != NULL)
|
||||
(*ctrl_c_hook)();
|
||||
}
|
||||
|
||||
void
|
||||
set_ctrl_c_hook(
|
||||
ctrl_c_fn c_hook
|
||||
)
|
||||
{
|
||||
RETSIGTYPE (*handler)(int);
|
||||
|
||||
if (NULL == c_hook) {
|
||||
handler = SIG_DFL;
|
||||
signal_no_reset(SIGINT, handler);
|
||||
ctrl_c_hook = c_hook;
|
||||
} else {
|
||||
ctrl_c_hook = c_hook;
|
||||
handler = &sigint_handler;
|
||||
signal_no_reset(SIGINT, handler);
|
||||
}
|
||||
}
|
||||
#else /* SYS_WINNT follows */
|
||||
/*
|
||||
* Windows implementation of set_ctrl_c_hook()
|
||||
*/
|
||||
BOOL WINAPI
|
||||
console_event_handler(
|
||||
DWORD dwCtrlType
|
||||
)
|
||||
{
|
||||
BOOL handled;
|
||||
|
||||
if (CTRL_C_EVENT == dwCtrlType && ctrl_c_hook != NULL) {
|
||||
(*ctrl_c_hook)();
|
||||
handled = TRUE;
|
||||
} else {
|
||||
handled = FALSE;
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
void
|
||||
set_ctrl_c_hook(
|
||||
ctrl_c_fn c_hook
|
||||
)
|
||||
{
|
||||
BOOL install;
|
||||
|
||||
if (NULL == c_hook) {
|
||||
ctrl_c_hook = NULL;
|
||||
install = FALSE;
|
||||
} else {
|
||||
ctrl_c_hook = c_hook;
|
||||
install = TRUE;
|
||||
}
|
||||
if (!SetConsoleCtrlHandler(&console_event_handler, install))
|
||||
msyslog(LOG_ERR, "Can't %s console control handler: %m",
|
||||
(install)
|
||||
? "add"
|
||||
: "remove");
|
||||
}
|
||||
#endif /* SYS_WINNT */
|
||||
@@ -0,0 +1,711 @@
|
||||
/*
|
||||
* systime -- routines to fiddle a UNIX clock.
|
||||
*
|
||||
* ATTENTION: Get approval from Dave Mills on all changes to this file!
|
||||
*
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <ipcom_clib.h>
|
||||
#include <ipcom_time.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "ntp.h"
|
||||
#include "ntpd.h"
|
||||
#include "ntp_syslog.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_random.h"
|
||||
#include "iosignal.h"
|
||||
#include "timevalops.h"
|
||||
#include "timespecops.h"
|
||||
#include "ntp_calendar.h"
|
||||
#include "lib_strbuf.h"
|
||||
#include "ipntp.h"
|
||||
|
||||
extern Ip_u32 ipsntp_server_nsec_to_fraction(Ip_u32 nsecs);
|
||||
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
#ifdef HAVE_UTMP_H
|
||||
# include <utmp.h>
|
||||
#endif /* HAVE_UTMP_H */
|
||||
#ifdef HAVE_UTMPX_H
|
||||
# include <utmpx.h>
|
||||
#endif /* HAVE_UTMPX_H */
|
||||
|
||||
int allow_panic = FALSE; /* allow panic correction (-g) */
|
||||
int enable_panic_check = TRUE; /* Can we check allow_panic's state? */
|
||||
|
||||
u_long sys_lamport; /* Lamport violation */
|
||||
u_long sys_tsrounding; /* timestamp rounding errors */
|
||||
|
||||
#ifndef USE_COMPILETIME_PIVOT
|
||||
# define USE_COMPILETIME_PIVOT 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These routines (get_systime, step_systime, adj_systime) implement an
|
||||
* interface between the system independent NTP clock and the Unix
|
||||
* system clock in various architectures and operating systems. Time is
|
||||
* a precious quantity in these routines and every effort is made to
|
||||
* minimize errors by unbiased rounding and amortizing adjustment
|
||||
* residues.
|
||||
*
|
||||
* In order to improve the apparent resolution, provide unbiased
|
||||
* rounding and most importantly ensure that the readings cannot be
|
||||
* predicted, the low-order unused portion of the time below the minimum
|
||||
* time to read the clock is filled with an unbiased random fuzz.
|
||||
*
|
||||
* The sys_tick variable specifies the system clock tick interval in
|
||||
* seconds, for stepping clocks, defined as those which return times
|
||||
* less than MINSTEP greater than the previous reading. For systems that
|
||||
* use a high-resolution counter such that each clock reading is always
|
||||
* at least MINSTEP greater than the prior, sys_tick is the time to read
|
||||
* the system clock.
|
||||
*
|
||||
* The sys_fuzz variable measures the minimum time to read the system
|
||||
* clock, regardless of its precision. When reading the system clock
|
||||
* using get_systime() after sys_tick and sys_fuzz have been determined,
|
||||
* ntpd ensures each unprocessed clock reading is no less than sys_fuzz
|
||||
* later than the prior unprocessed reading, and then fuzzes the bits
|
||||
* below sys_fuzz in the timestamp returned, ensuring each of its
|
||||
* resulting readings is strictly later than the previous.
|
||||
*
|
||||
* When slewing the system clock using adj_systime() (with the kernel
|
||||
* loop discipline unavailable or disabled), adjtime() offsets are
|
||||
* quantized to sys_tick, if sys_tick is greater than sys_fuzz, which
|
||||
* is to say if the OS presents a stepping clock. Otherwise, offsets
|
||||
* are quantized to the microsecond resolution of adjtime()'s timeval
|
||||
* input. The remaining correction sys_residual is carried into the
|
||||
* next adjtime() and meanwhile is also factored into get_systime()
|
||||
* readings.
|
||||
*/
|
||||
double sys_tick = 1e-6; /* 1 us tickadj() , tick size or time to read (s) */
|
||||
double sys_fuzz = 0; /* min. time to read the clock (s) */
|
||||
long sys_fuzz_nsec = 0; /* min. time to read the clock (ns) */
|
||||
double measured_tick; /* non-overridable sys_tick (s) */
|
||||
double sys_residual = 0; /* adjustment residue (s) */
|
||||
int trunc_os_clock; /* sys_tick > measured_tick */
|
||||
time_stepped_callback step_callback;
|
||||
|
||||
#ifndef SIM
|
||||
/* perlinger@ntp.org: As 'get_sysime()' does it's own check for clock
|
||||
* backstepping, this could probably become a local variable in
|
||||
* 'get_systime()' and the cruft associated with communicating via a
|
||||
* static value could be removed after the v4.2.8 release.
|
||||
*/
|
||||
static int lamport_violated = FALSE; /* clock was stepped back */
|
||||
#endif /* !SIM */
|
||||
|
||||
#ifdef NTP_DEBUG
|
||||
static int systime_init_done;
|
||||
# define DONE_SYSTIME_INIT() systime_init_done = TRUE
|
||||
#else
|
||||
# define DONE_SYSTIME_INIT() do {} while (FALSE)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SIGNALED_IO
|
||||
int using_sigio;
|
||||
#endif
|
||||
|
||||
#ifdef SYS_WINNT
|
||||
CRITICAL_SECTION get_systime_cs;
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
set_sys_fuzz(
|
||||
double fuzz_val
|
||||
)
|
||||
{
|
||||
sys_fuzz = fuzz_val;
|
||||
INSIST(sys_fuzz >= 0);
|
||||
INSIST(sys_fuzz <= 1.0);
|
||||
#ifdef NTP_VXWORKS_6
|
||||
sys_fuzz_nsec = (long)(sys_fuzz * 1e9 + 0.5);
|
||||
#else
|
||||
/* [Bug 3450] ensure nsec fuzz >= sys_fuzz to reduce chance of
|
||||
* short-falling fuzz advance
|
||||
*/
|
||||
sys_fuzz_nsec = (long)ceil(sys_fuzz * 1e9);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
init_systime(void)
|
||||
{
|
||||
sys_tick = 1e-6;
|
||||
sys_fuzz = 0;
|
||||
sys_fuzz_nsec = 0;
|
||||
measured_tick = 0;
|
||||
sys_residual = 0;
|
||||
trunc_os_clock = 0;
|
||||
|
||||
INIT_GET_SYSTIME_CRITSEC();
|
||||
INIT_WIN_PRECISE_TIME();
|
||||
DONE_SYSTIME_INIT();
|
||||
}
|
||||
|
||||
|
||||
#ifndef SIM /* ntpsim.c has get_systime() and friends for sim */
|
||||
|
||||
static inline void
|
||||
get_ostime(
|
||||
struct timespec * tsp
|
||||
)
|
||||
{
|
||||
int rc;
|
||||
long ticks;
|
||||
|
||||
struct timeval tv;
|
||||
|
||||
rc = ipcom_gettimeofday(&tv, IP_NULL);
|
||||
tsp->tv_sec = tv.tv_sec;
|
||||
tsp->tv_nsec = tv.tv_usec * 1000;
|
||||
|
||||
if (rc < 0) {
|
||||
msyslog(LOG_ERR, "read system clock failed: %m (%d)",
|
||||
errno);
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
|
||||
if (trunc_os_clock) {
|
||||
ticks = (long)((tsp->tv_nsec * 1e-9) / sys_tick);
|
||||
tsp->tv_nsec = (long)(ticks * 1e9 * sys_tick);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_systime - return system time in NTP timestamp format.
|
||||
*/
|
||||
void
|
||||
get_systime(
|
||||
l_fp *now /* system time */
|
||||
)
|
||||
{
|
||||
static struct timespec ts_last; /* last sampled os time */
|
||||
static struct timespec ts_prev; /* prior os time */
|
||||
static l_fp lfp_prev; /* prior result */
|
||||
struct timespec ts; /* seconds and nanoseconds */
|
||||
struct timespec ts_min; /* earliest permissible */
|
||||
struct timespec ts_lam; /* lamport fictional increment */
|
||||
double dfuzz;
|
||||
l_fp result;
|
||||
l_fp lfpfuzz;
|
||||
l_fp lfpdelta;
|
||||
|
||||
get_ostime(&ts);
|
||||
DEBUG_REQUIRE(systime_init_done);
|
||||
ENTER_GET_SYSTIME_CRITSEC();
|
||||
|
||||
/* First check if here was a Lamport violation, that is, two
|
||||
* successive calls to 'get_ostime()' resulted in negative
|
||||
* time difference. Use a few milliseconds of permissible
|
||||
* tolerance -- being too sharp can hurt here. (This is intented
|
||||
* for the Win32 target, where the HPC interpolation might
|
||||
* introduce small steps backward. It should not be an issue on
|
||||
* systems where get_ostime() results in a true syscall.)
|
||||
*/
|
||||
if (cmp_tspec(add_tspec_ns(ts, 50000000), ts_last) < 0) {
|
||||
lamport_violated = 1;
|
||||
sys_lamport++;
|
||||
}
|
||||
ts_last = ts;
|
||||
|
||||
/*
|
||||
* After default_get_precision() has set a nonzero sys_fuzz,
|
||||
* ensure every reading of the OS clock advances by at least
|
||||
* sys_fuzz over the prior reading, thereby assuring each
|
||||
* fuzzed result is strictly later than the prior. Limit the
|
||||
* necessary fiction to 1 second.
|
||||
*/
|
||||
if (!USING_SIGIO()) {
|
||||
ts_min = add_tspec_ns(ts_prev, sys_fuzz_nsec);
|
||||
if (cmp_tspec(ts, ts_min) < 0) {
|
||||
ts_lam = sub_tspec(ts_min, ts);
|
||||
if (ts_lam.tv_sec > 0 && !lamport_violated) {
|
||||
msyslog(LOG_ERR,
|
||||
"get_systime Lamport advance exceeds one second (%.9f)",
|
||||
ts_lam.tv_sec +
|
||||
1e-9 * ts_lam.tv_nsec);
|
||||
ipntp_exit_callback(ipcom_getpid());
|
||||
}
|
||||
if (!lamport_violated)
|
||||
ts = ts_min;
|
||||
}
|
||||
ts_prev = ts;
|
||||
}
|
||||
|
||||
/* convert from timespec to l_fp fixed-point */
|
||||
result = tspec_stamp_to_lfp(ts);
|
||||
|
||||
/*
|
||||
* Add in the fuzz. 'ntp_random()' returns [0..2**31-1] so we
|
||||
* must scale up the result by 2.0 to cover the full fractional
|
||||
* range.
|
||||
*/
|
||||
dfuzz = ntp_random() * 2. / FRAC * sys_fuzz;
|
||||
DTOLFP(dfuzz, &lfpfuzz);
|
||||
L_ADD(&result, &lfpfuzz);
|
||||
|
||||
/*
|
||||
* Ensure result is strictly greater than prior result (ignoring
|
||||
* sys_residual's effect for now) once sys_fuzz has been
|
||||
* determined.
|
||||
*
|
||||
* [Bug 3450] Rounding errors and time slew can lead to a
|
||||
* violation of the expected postcondition. This is bound to
|
||||
* happen from time to time (depending on state of the random
|
||||
* generator, the current slew and the closeness of system time
|
||||
* stamps drawn) and does not warrant a syslog entry. Instead it
|
||||
* makes much more sense to ensure the postcondition and hop
|
||||
* along silently.
|
||||
*/
|
||||
if (!USING_SIGIO()) {
|
||||
if ( !L_ISZERO(&lfp_prev)
|
||||
&& !lamport_violated
|
||||
&& (sys_fuzz > 0.0)
|
||||
) {
|
||||
lfpdelta = result;
|
||||
L_SUB(&lfpdelta, &lfp_prev);
|
||||
L_SUBUF(&lfpdelta, 1);
|
||||
if (lfpdelta.l_i < 0)
|
||||
{
|
||||
L_NEG(&lfpdelta);
|
||||
DPRINTF(1, ("get_systime: postcond failed by %s secs, fixed\n",
|
||||
lfptoa(&lfpdelta, 9)));
|
||||
result = lfp_prev;
|
||||
L_ADDUF(&result, 1);
|
||||
sys_tsrounding++;
|
||||
}
|
||||
}
|
||||
lfp_prev = result;
|
||||
if (lamport_violated)
|
||||
lamport_violated = FALSE;
|
||||
}
|
||||
LEAVE_GET_SYSTIME_CRITSEC();
|
||||
*now = result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* adj_systime - adjust system time by the argument.
|
||||
*/
|
||||
#if !defined SYS_WINNT
|
||||
int /* 0 okay, 1 error */
|
||||
adj_systime(
|
||||
double now /* adjustment (s) */
|
||||
)
|
||||
{
|
||||
struct timeval adjtv; /* new adjustment */
|
||||
struct timeval oadjtv; /* residual adjustment */
|
||||
double quant; /* quantize to multiples of */
|
||||
double dtemp;
|
||||
long ticks;
|
||||
int isneg = 0;
|
||||
|
||||
/*
|
||||
* The Windows port adj_systime() depends on being called each
|
||||
* second even when there's no additional correction, to allow
|
||||
* emulation of adjtime() behavior on top of an API that simply
|
||||
* sets the current rate. This POSIX implementation needs to
|
||||
* ignore invocations with zero correction, otherwise ongoing
|
||||
* EVNT_NSET adjtime() can be aborted by a tiny adjtime()
|
||||
* triggered by sys_residual.
|
||||
*/
|
||||
if (0. == now) {
|
||||
if (enable_panic_check && allow_panic) {
|
||||
msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!");
|
||||
INSIST(!allow_panic);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Most Unix adjtime() implementations adjust the system clock
|
||||
* in microsecond quanta, but some adjust in 10-ms quanta. We
|
||||
* carefully round the adjustment to the nearest quantum, then
|
||||
* adjust in quanta and keep the residue for later.
|
||||
*/
|
||||
dtemp = now + sys_residual;
|
||||
if (dtemp < 0) {
|
||||
isneg = 1;
|
||||
dtemp = -dtemp;
|
||||
}
|
||||
adjtv.tv_sec = (time_t)dtemp;
|
||||
dtemp -= (double)adjtv.tv_sec;
|
||||
if (sys_tick > sys_fuzz)
|
||||
quant = sys_tick;
|
||||
else
|
||||
quant = 1e-6;
|
||||
ticks = (long)(dtemp / quant + .5);
|
||||
adjtv.tv_usec = (long)(ticks * quant * 1.e6 + .5);
|
||||
/* The rounding in the conversions could us push over the
|
||||
* limits: make sure the result is properly normalised!
|
||||
* note: sign comes later, all numbers non-negative here.
|
||||
*/
|
||||
if (adjtv.tv_usec >= 1000000) {
|
||||
adjtv.tv_sec += 1;
|
||||
adjtv.tv_usec -= 1000000;
|
||||
dtemp -= 1.;
|
||||
}
|
||||
/* set the new residual with leftover from correction */
|
||||
sys_residual = dtemp - adjtv.tv_usec * 1.e-6;
|
||||
|
||||
/*
|
||||
* Convert to signed seconds and microseconds for the Unix
|
||||
* adjtime() system call. Note we purposely lose the adjtime()
|
||||
* leftover.
|
||||
*/
|
||||
if (isneg) {
|
||||
adjtv.tv_sec = -adjtv.tv_sec;
|
||||
adjtv.tv_usec = -adjtv.tv_usec;
|
||||
sys_residual = -sys_residual;
|
||||
}
|
||||
if (adjtv.tv_sec != 0 || adjtv.tv_usec != 0) {
|
||||
if (adjtime(&adjtv, &oadjtv) < 0) {
|
||||
msyslog(LOG_ERR, "adj_systime: %m");
|
||||
if (enable_panic_check && allow_panic) {
|
||||
msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (enable_panic_check && allow_panic) {
|
||||
msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!");
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* helper to keep utmp/wtmp up to date
|
||||
*/
|
||||
static void
|
||||
update_uwtmp(
|
||||
struct timeval timetv,
|
||||
struct timeval tvlast
|
||||
)
|
||||
{
|
||||
struct timeval tvdiff;
|
||||
#ifdef NTP_VXWORKS_7
|
||||
struct timeval tmpval, tmpvallast;
|
||||
#endif
|
||||
/*
|
||||
* FreeBSD, for example, has:
|
||||
* struct utmp {
|
||||
* char ut_line[UT_LINESIZE];
|
||||
* char ut_name[UT_NAMESIZE];
|
||||
* char ut_host[UT_HOSTSIZE];
|
||||
* long ut_time;
|
||||
* };
|
||||
* and appends line="|", name="date", host="", time for the OLD
|
||||
* and appends line="{", name="date", host="", time for the NEW
|
||||
* to _PATH_WTMP .
|
||||
*
|
||||
* Some OSes have utmp, some have utmpx.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Write old and new time entries in utmp and wtmp if step
|
||||
* adjustment is greater than one second.
|
||||
*
|
||||
* This might become even Uglier...
|
||||
*/
|
||||
#ifdef NTP_VXWORKS_7
|
||||
tmpval.tv_sec = timetv.tv_sec;
|
||||
tmpval.tv_usec = timetv.tv_usec;
|
||||
tmpvallast.tv_sec = tvlast.tv_sec;
|
||||
tmpvallast.tv_usec = tvlast.tv_usec;
|
||||
tmpval = abs_tval(sub_tval(tmpval, tmpvallast));
|
||||
tvdiff.tv_sec = tmpval.tv_sec;
|
||||
tvdiff.tv_usec = tmpval.tv_usec;
|
||||
#else
|
||||
tvdiff = abs_tval(sub_tval(timetv, tvlast));
|
||||
#endif
|
||||
if (tvdiff.tv_sec > 0) {
|
||||
#ifdef HAVE_UTMP_H
|
||||
struct utmp ut;
|
||||
#endif
|
||||
#ifdef HAVE_UTMPX_H
|
||||
struct utmpx utx;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UTMP_H
|
||||
ZERO(ut);
|
||||
#endif
|
||||
#ifdef HAVE_UTMPX_H
|
||||
ZERO(utx);
|
||||
#endif
|
||||
|
||||
/* UTMP */
|
||||
|
||||
#ifdef UPDATE_UTMP
|
||||
# ifdef HAVE_PUTUTLINE
|
||||
# ifndef _PATH_UTMP
|
||||
# define _PATH_UTMP UTMP_FILE
|
||||
# endif
|
||||
utmpname(_PATH_UTMP);
|
||||
ut.ut_type = OLD_TIME;
|
||||
strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line));
|
||||
ut.ut_time = tvlast.tv_sec;
|
||||
setutent();
|
||||
pututline(&ut);
|
||||
ut.ut_type = NEW_TIME;
|
||||
strlcpy(ut.ut_line, NTIME_MSG, sizeof(ut.ut_line));
|
||||
ut.ut_time = timetv.tv_sec;
|
||||
setutent();
|
||||
pututline(&ut);
|
||||
endutent();
|
||||
# else /* not HAVE_PUTUTLINE */
|
||||
# endif /* not HAVE_PUTUTLINE */
|
||||
#endif /* UPDATE_UTMP */
|
||||
|
||||
/* UTMPX */
|
||||
|
||||
#ifdef UPDATE_UTMPX
|
||||
# ifdef HAVE_PUTUTXLINE
|
||||
utx.ut_type = OLD_TIME;
|
||||
strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line));
|
||||
utx.ut_tv = tvlast;
|
||||
setutxent();
|
||||
pututxline(&utx);
|
||||
utx.ut_type = NEW_TIME;
|
||||
strlcpy(utx.ut_line, NTIME_MSG, sizeof(utx.ut_line));
|
||||
utx.ut_tv = timetv;
|
||||
setutxent();
|
||||
pututxline(&utx);
|
||||
endutxent();
|
||||
# else /* not HAVE_PUTUTXLINE */
|
||||
# endif /* not HAVE_PUTUTXLINE */
|
||||
#endif /* UPDATE_UTMPX */
|
||||
|
||||
/* WTMP */
|
||||
|
||||
#ifdef UPDATE_WTMP
|
||||
# ifdef HAVE_PUTUTLINE
|
||||
# ifndef _PATH_WTMP
|
||||
# define _PATH_WTMP WTMP_FILE
|
||||
# endif
|
||||
utmpname(_PATH_WTMP);
|
||||
ut.ut_type = OLD_TIME;
|
||||
strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line));
|
||||
ut.ut_time = tvlast.tv_sec;
|
||||
setutent();
|
||||
pututline(&ut);
|
||||
ut.ut_type = NEW_TIME;
|
||||
strlcpy(ut.ut_line, NTIME_MSG, sizeof(ut.ut_line));
|
||||
ut.ut_time = timetv.tv_sec;
|
||||
setutent();
|
||||
pututline(&ut);
|
||||
endutent();
|
||||
# else /* not HAVE_PUTUTLINE */
|
||||
# endif /* not HAVE_PUTUTLINE */
|
||||
#endif /* UPDATE_WTMP */
|
||||
|
||||
/* WTMPX */
|
||||
|
||||
#ifdef UPDATE_WTMPX
|
||||
# ifdef HAVE_PUTUTXLINE
|
||||
utx.ut_type = OLD_TIME;
|
||||
utx.ut_tv = tvlast;
|
||||
strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line));
|
||||
# ifdef HAVE_UPDWTMPX
|
||||
updwtmpx(WTMPX_FILE, &utx);
|
||||
# else /* not HAVE_UPDWTMPX */
|
||||
# endif /* not HAVE_UPDWTMPX */
|
||||
# else /* not HAVE_PUTUTXLINE */
|
||||
# endif /* not HAVE_PUTUTXLINE */
|
||||
# ifdef HAVE_PUTUTXLINE
|
||||
utx.ut_type = NEW_TIME;
|
||||
utx.ut_tv = timetv;
|
||||
strlcpy(utx.ut_line, NTIME_MSG, sizeof(utx.ut_line));
|
||||
# ifdef HAVE_UPDWTMPX
|
||||
updwtmpx(WTMPX_FILE, &utx);
|
||||
# else /* not HAVE_UPDWTMPX */
|
||||
# endif /* not HAVE_UPDWTMPX */
|
||||
# else /* not HAVE_PUTUTXLINE */
|
||||
# endif /* not HAVE_PUTUTXLINE */
|
||||
#endif /* UPDATE_WTMPX */
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* step_systime - step the system clock.
|
||||
*/
|
||||
|
||||
int
|
||||
step_systime(
|
||||
double step
|
||||
)
|
||||
{
|
||||
time_t pivot; /* for ntp era unfolding */
|
||||
struct timeval timetv, tvlast;
|
||||
#ifdef NTP_VXWORKS_7
|
||||
struct timeval tmpval;
|
||||
#endif
|
||||
l_fp fp_ofs, fp_sys; /* offset and target system time in FP */
|
||||
|
||||
/*
|
||||
* Get pivot time for NTP era unfolding. Since we don't step
|
||||
* very often, we can afford to do the whole calculation from
|
||||
* scratch. And we're not in the time-critical path yet.
|
||||
*/
|
||||
#if SIZEOF_TIME_T > 4
|
||||
pivot = basedate_get_eracenter();
|
||||
#else
|
||||
/* This makes sure the resulting time stamp is on or after
|
||||
* 1969-12-31/23:59:59 UTC and gives us additional two years,
|
||||
* from the change of NTP era in 2036 to the UNIX rollover in
|
||||
* 2038. (Minus one second, but that won't hurt.) We *really*
|
||||
* need a longer 'time_t' after that! Or a different baseline,
|
||||
* but that would cause other serious trouble, too.
|
||||
*/
|
||||
pivot = 0x7FFFFFFF;
|
||||
#endif
|
||||
|
||||
/* get the complete jump distance as l_fp */
|
||||
DTOLFP(sys_residual, &fp_sys);
|
||||
DTOLFP(step, &fp_ofs);
|
||||
L_ADD(&fp_ofs, &fp_sys);
|
||||
|
||||
/* ---> time-critical path starts ---> */
|
||||
|
||||
(void)ipcom_gettimeofday(&tvlast, IP_NULL);
|
||||
|
||||
fp_sys.l_i = (int)tvlast.tv_sec + JAN_1970;
|
||||
fp_sys.l_uf = (unsigned int)ipsntp_server_nsec_to_fraction(tvlast.tv_usec * 1000);
|
||||
|
||||
/* get the target time as l_fp */
|
||||
L_ADD(&fp_sys, &fp_ofs);
|
||||
|
||||
/* unfold the new system time */
|
||||
#ifdef NTP_VXWORKS_7
|
||||
tmpval = lfp_stamp_to_tval(fp_sys, &pivot);
|
||||
timetv.tv_sec = tmpval.tv_sec;
|
||||
timetv.tv_usec = tmpval.tv_usec;
|
||||
#else
|
||||
timetv = lfp_stamp_to_tval(fp_sys, &pivot);
|
||||
#endif
|
||||
|
||||
/* now set new system time */
|
||||
if (ntp_set_tod(&timetv, NULL) != 0) {
|
||||
msyslog(LOG_ERR, "step-systime: %m");
|
||||
if (enable_panic_check && allow_panic) {
|
||||
msyslog(LOG_ERR, "step_systime: allow_panic is TRUE!");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* <--- time-critical path ended with 'ntp_set_tod()' <--- */
|
||||
|
||||
sys_residual = 0;
|
||||
lamport_violated = (step < 0);
|
||||
if (step_callback)
|
||||
(*step_callback)();
|
||||
|
||||
#ifdef NEED_HPUX_ADJTIME
|
||||
/*
|
||||
* CHECKME: is this correct when called by ntpdate?????
|
||||
*/
|
||||
_clear_adjtime();
|
||||
#endif
|
||||
|
||||
update_uwtmp(timetv, tvlast);
|
||||
if (enable_panic_check && allow_panic) {
|
||||
msyslog(LOG_ERR, "step_systime: allow_panic is TRUE!");
|
||||
INSIST(!allow_panic);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
tv_fmt_libbuf(
|
||||
const struct timeval * ptv
|
||||
)
|
||||
{
|
||||
char * retv;
|
||||
vint64 secs;
|
||||
ntpcal_split dds;
|
||||
struct calendar jd;
|
||||
|
||||
secs = time_to_vint64(&ptv->tv_sec);
|
||||
dds = ntpcal_daysplit(&secs);
|
||||
ntpcal_daysplit_to_date(&jd, &dds, DAY_UNIX_STARTS);
|
||||
LIB_GETBUF(retv);
|
||||
snprintf(retv, LIB_BUFLENGTH,
|
||||
"%04hu-%02hu-%02hu/%02hu:%02hu:%02hu.%06u",
|
||||
jd.year, (u_short)jd.month, (u_short)jd.monthday,
|
||||
(u_short)jd.hour, (u_short)jd.minute, (u_short)jd.second,
|
||||
(u_int)ptv->tv_usec);
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
||||
int /*BOOL*/
|
||||
clamp_systime(void)
|
||||
{
|
||||
#if SIZEOF_TIME_T > 4
|
||||
|
||||
struct timeval tvbase, tvlast;
|
||||
struct timespec timets;
|
||||
|
||||
tvbase.tv_sec = basedate_get_erabase();
|
||||
tvbase.tv_usec = 0;
|
||||
|
||||
/* ---> time-critical path starts ---> */
|
||||
|
||||
/* get the current time as l_fp (without fuzz) and as struct timeval */
|
||||
get_ostime(&timets);
|
||||
tvlast.tv_sec = timets.tv_sec;
|
||||
tvlast.tv_usec = (timets.tv_nsec + 500) / 1000;
|
||||
if (tvlast.tv_usec >= 1000000) {
|
||||
tvlast.tv_usec -= 1000000;
|
||||
tvlast.tv_sec += 1;
|
||||
}
|
||||
|
||||
if (tvbase.tv_sec > tvlast.tv_sec) {
|
||||
/* now set new system time */
|
||||
if (ntp_set_tod(&tvbase, NULL) != 0) {
|
||||
msyslog(LOG_ERR, "clamp-systime: %m");
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
msyslog(LOG_INFO,
|
||||
"clamp-systime: clock (%s) in allowed range",
|
||||
tv_fmt_libbuf(&tvlast));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* <--- time-critical path ended with 'ntp_set_tod()' <--- */
|
||||
|
||||
sys_residual = 0;
|
||||
lamport_violated = (tvbase.tv_sec < tvlast.tv_sec);
|
||||
if (step_callback)
|
||||
(*step_callback)();
|
||||
|
||||
# ifdef NEED_HPUX_ADJTIME
|
||||
/*
|
||||
* CHECKME: is this correct when called by ntpdate?????
|
||||
*/
|
||||
_clear_adjtime();
|
||||
# endif
|
||||
|
||||
update_uwtmp(tvbase, tvlast);
|
||||
msyslog(LOG_WARNING,
|
||||
"clamp-systime: clock stepped from %s to %s!",
|
||||
tv_fmt_libbuf(&tvlast), tv_fmt_libbuf(&tvbase));
|
||||
return TRUE;
|
||||
|
||||
#else
|
||||
|
||||
return FALSE;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* !SIM */
|
||||
@@ -0,0 +1,2 @@
|
||||
#define SIM
|
||||
#include "systime.c"
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* timespecops.c -- calculations on 'struct timespec' values
|
||||
*
|
||||
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
|
||||
* The contents of 'html/copyright.html' apply.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ipntp_config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "ntp.h"
|
||||
#include "timetoa.h"
|
||||
#include "timespecops.h"
|
||||
|
||||
|
||||
/* nanoseconds per second */
|
||||
#define NANOSECONDS 1000000000
|
||||
|
||||
/* conversion between l_fp fractions and nanoseconds */
|
||||
#ifdef HAVE_U_INT64
|
||||
# define FTOTVN(tsf) \
|
||||
((int32) \
|
||||
(((u_int64)(tsf) * NANOSECONDS + 0x80000000) >> 32))
|
||||
# define TVNTOF(tvu) \
|
||||
((u_int32) \
|
||||
((((u_int64)(tvu) << 32) + NANOSECONDS / 2) / \
|
||||
NANOSECONDS))
|
||||
#else
|
||||
# define NSECFRAC (FRAC / NANOSECONDS)
|
||||
# define FTOTVN(tsf) \
|
||||
((int32)((tsf) / NSECFRAC + 0.5))
|
||||
# define TVNTOF(tvu) \
|
||||
((u_int32)((tvu) * NSECFRAC + 0.5))
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* make sure nanoseconds are in nominal range */
|
||||
struct timespec
|
||||
normalize_tspec(
|
||||
struct timespec x
|
||||
)
|
||||
{
|
||||
#if SIZEOF_LONG > 4
|
||||
long z;
|
||||
|
||||
/*
|
||||
* tv_nsec is of type 'long', and on a 64-bit machine using only
|
||||
* loops becomes prohibitive once the upper 32 bits get
|
||||
* involved. On the other hand, division by constant should be
|
||||
* fast enough; so we do a division of the nanoseconds in that
|
||||
* case. The floor adjustment step follows with the standard
|
||||
* normalisation loops. And labs() is intentionally not used
|
||||
* here: it has implementation-defined behaviour when applied
|
||||
* to LONG_MIN.
|
||||
*/
|
||||
if (x.tv_nsec < -3l * NANOSECONDS ||
|
||||
x.tv_nsec > 3l * NANOSECONDS) {
|
||||
z = x.tv_nsec / NANOSECONDS;
|
||||
x.tv_nsec -= z * NANOSECONDS;
|
||||
x.tv_sec += z;
|
||||
}
|
||||
#endif
|
||||
/* since 10**9 is close to 2**32, we don't divide but do a
|
||||
* normalisation in a loop; this takes 3 steps max, and should
|
||||
* outperform a division even if the mul-by-inverse trick is
|
||||
* employed. */
|
||||
if (x.tv_nsec < 0)
|
||||
do {
|
||||
x.tv_nsec += NANOSECONDS;
|
||||
x.tv_sec--;
|
||||
} while (x.tv_nsec < 0);
|
||||
else if (x.tv_nsec >= NANOSECONDS)
|
||||
do {
|
||||
x.tv_nsec -= NANOSECONDS;
|
||||
x.tv_sec++;
|
||||
} while (x.tv_nsec >= NANOSECONDS);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/* x = abs(a) */
|
||||
struct timespec
|
||||
abs_tspec(
|
||||
struct timespec a
|
||||
)
|
||||
{
|
||||
struct timespec c;
|
||||
|
||||
c = normalize_tspec(a);
|
||||
if (c.tv_sec < 0) {
|
||||
if (c.tv_nsec != 0) {
|
||||
c.tv_sec = -c.tv_sec - 1;
|
||||
c.tv_nsec = NANOSECONDS - c.tv_nsec;
|
||||
} else {
|
||||
c.tv_sec = -c.tv_sec;
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* compare previously-normalised a and b
|
||||
* return 1 / 0 / -1 if a < / == / > b
|
||||
*/
|
||||
int
|
||||
cmp_tspec(
|
||||
struct timespec a,
|
||||
struct timespec b
|
||||
)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec);
|
||||
if (0 == r)
|
||||
r = (a.tv_nsec > b.tv_nsec) -
|
||||
(a.tv_nsec < b.tv_nsec);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* test previously-normalised a
|
||||
* return 1 / 0 / -1 if a < / == / > 0
|
||||
*/
|
||||
int
|
||||
test_tspec(
|
||||
struct timespec a
|
||||
)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = (a.tv_sec > 0) - (a.tv_sec < 0);
|
||||
if (r == 0)
|
||||
r = (a.tv_nsec > 0);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* convert to l_fp type, relative and absolute
|
||||
*/
|
||||
|
||||
/* convert from timespec duration to l_fp duration */
|
||||
l_fp
|
||||
tspec_intv_to_lfp(
|
||||
struct timespec x
|
||||
)
|
||||
{
|
||||
struct timespec v;
|
||||
l_fp y;
|
||||
|
||||
v = normalize_tspec(x);
|
||||
y.l_uf = TVNTOF(v.tv_nsec);
|
||||
y.l_i = (int32)v.tv_sec;
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
/* convert from l_fp type, relative signed/unsigned and absolute */
|
||||
struct timespec
|
||||
lfp_intv_to_tspec(
|
||||
l_fp x
|
||||
)
|
||||
{
|
||||
struct timespec out;
|
||||
l_fp absx;
|
||||
int neg;
|
||||
|
||||
neg = L_ISNEG(&x);
|
||||
absx = x;
|
||||
if (neg) {
|
||||
L_NEG(&absx);
|
||||
}
|
||||
out.tv_nsec = FTOTVN(absx.l_uf);
|
||||
out.tv_sec = absx.l_i;
|
||||
if (neg) {
|
||||
out.tv_sec = -out.tv_sec;
|
||||
out.tv_nsec = -out.tv_nsec;
|
||||
out = normalize_tspec(out);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
struct timespec
|
||||
lfp_uintv_to_tspec(
|
||||
l_fp x
|
||||
)
|
||||
{
|
||||
struct timespec out;
|
||||
|
||||
out.tv_nsec = FTOTVN(x.l_uf);
|
||||
out.tv_sec = x.l_ui;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* absolute (timestamp) conversion. Input is time in NTP epoch, output
|
||||
* is in UN*X epoch. The NTP time stamp will be expanded around the
|
||||
* pivot time *p or the current time, if p is NULL.
|
||||
*/
|
||||
struct timespec
|
||||
lfp_stamp_to_tspec(
|
||||
l_fp x,
|
||||
const time_t * p
|
||||
)
|
||||
{
|
||||
struct timespec out;
|
||||
vint64 sec;
|
||||
|
||||
sec = ntpcal_ntp_to_time(x.l_ui, p);
|
||||
out.tv_nsec = FTOTVN(x.l_uf);
|
||||
|
||||
/* copying a vint64 to a time_t needs some care... */
|
||||
#if SIZEOF_TIME_T <= 4
|
||||
out.tv_sec = (time_t)sec.d_s.lo;
|
||||
#elif defined(HAVE_INT64)
|
||||
out.tv_sec = (time_t)sec.q_s;
|
||||
#else
|
||||
out.tv_sec = ((time_t)sec.d_s.hi << 32) | sec.d_s.lo;
|
||||
#endif
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/* -*-EOF-*- */
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* timetoa.c -- time_t related string formatting
|
||||
*
|
||||
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
|
||||
* The contents of 'html/copyright.html' apply.
|
||||
*
|
||||
* Printing a 'time_t' has a lot of portability pitfalls, due to it's
|
||||
* opaque base type. The only requirement imposed by the standard is
|
||||
* that it must be a numeric type. For all practical purposes it's a
|
||||
* signed int, and 32 bits are common.
|
||||
*
|
||||
* Since the UN*X time epoch will cause a signed integer overflow for
|
||||
* 32-bit signed int in the year 2038, implementations slowly move to
|
||||
* 64bit base types for time_t, even in 32-bit environments.
|
||||
*
|
||||
* As the printf() family has no standardised type specifier for time_t,
|
||||
* guessing the right output format specifier is a bit troublesome and
|
||||
* best done with the help of the preprocessor and "config.h".
|
||||
*/
|
||||
|
||||
#include "ipntp_config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#include "timetoa.h"
|
||||
#include "ntp_assert.h"
|
||||
#include "lib_strbuf.h"
|
||||
|
||||
/*
|
||||
* Formatting to string needs at max 40 bytes (even with 64 bit time_t),
|
||||
* so we check LIB_BUFLENGTH is big enough for our purpose.
|
||||
*/
|
||||
#if LIB_BUFLENGTH < 40
|
||||
# include "GRONK: LIB_BUFLENGTH is not sufficient"
|
||||
#endif
|
||||
|
||||
#ifndef NTP_VXWORKS_7
|
||||
#ifdef SYS_VXWORKS
|
||||
typedef struct _ldiv_t {
|
||||
long quot;
|
||||
long rem;
|
||||
} ldiv_t;
|
||||
ldiv_t ldiv(long num, long denom);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* general fractional timestamp formatting
|
||||
*
|
||||
* Many pieces of ntpd require a machine with two's complement
|
||||
* representation of signed integers, so we don't go through the whole
|
||||
* rigamarole of creating fully portable code here. But we have to stay
|
||||
* away from signed integer overflow, as this might cause trouble even
|
||||
* with two's complement representation.
|
||||
*/
|
||||
const char *
|
||||
format_time_fraction(
|
||||
time_t secs,
|
||||
long frac,
|
||||
int prec
|
||||
)
|
||||
{
|
||||
char * cp;
|
||||
u_int prec_u;
|
||||
u_time secs_u;
|
||||
u_int u;
|
||||
long fraclimit;
|
||||
int notneg; /* flag for non-negative value */
|
||||
ldiv_t qr;
|
||||
|
||||
DEBUG_REQUIRE(prec != 0);
|
||||
|
||||
LIB_GETBUF(cp);
|
||||
secs_u = (u_time)secs;
|
||||
|
||||
/* check if we need signed or unsigned mode */
|
||||
notneg = (prec < 0);
|
||||
prec_u = ((prec) < 0 ? -(prec) : (prec));
|
||||
/* fraclimit = (long)pow(10, prec_u); */
|
||||
for (fraclimit = 10, u = 1; u < prec_u; u++) {
|
||||
DEBUG_INSIST(fraclimit < fraclimit * 10);
|
||||
fraclimit *= 10;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since conversion to string uses lots of divisions anyway,
|
||||
* there's no big extra penalty for normalisation. We do it for
|
||||
* consistency.
|
||||
*/
|
||||
if (frac < 0 || frac >= fraclimit) {
|
||||
qr = ldiv(frac, fraclimit);
|
||||
if (qr.rem < 0) {
|
||||
qr.quot--;
|
||||
qr.rem += fraclimit;
|
||||
}
|
||||
secs_u += (time_t)qr.quot;
|
||||
frac = qr.rem;
|
||||
}
|
||||
|
||||
/* Get the absolute value of the split representation time. */
|
||||
notneg = notneg || ((time_t)secs_u >= 0);
|
||||
if (!notneg) {
|
||||
secs_u = ~secs_u;
|
||||
if (0 == frac)
|
||||
secs_u++;
|
||||
else
|
||||
frac = fraclimit - frac;
|
||||
}
|
||||
|
||||
/* finally format the data and return the result */
|
||||
snprintf(cp, LIB_BUFLENGTH, "%s%" UTIME_FORMAT ".%0*ld",
|
||||
notneg? "" : "-", secs_u, prec_u, frac);
|
||||
|
||||
return cp;
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* timevalops.c -- calculations on 'struct timeval' values
|
||||
*
|
||||
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
|
||||
* The contents of 'html/copyright.html' apply.
|
||||
*/
|
||||
|
||||
#include <ipntp_config.h>
|
||||
|
||||
#include "timevalops.h"
|
||||
|
||||
#ifdef USE_TSF_USEC_TABLES
|
||||
/*
|
||||
* Tables to calculate time stamp fractions from usecs. The entries
|
||||
* in these tables are offset into using each of the two low order
|
||||
* bytes plus the next 4 bits in a usec value (from a struct timeval).
|
||||
* These are summed to produce the time stamp fraction.
|
||||
*
|
||||
* Note that these tables are rounded (not truncated) to the nearest
|
||||
* low order bit in the fraction. The timestamp computed should be
|
||||
* +- 1.5 low order bits.
|
||||
*/
|
||||
|
||||
const u_int32 ustotslo[256] = {
|
||||
0x00000000, 0x000010c7, 0x0000218e, 0x00003255,
|
||||
0x0000431c, 0x000053e3, 0x000064aa, 0x00007571,
|
||||
0x00008638, 0x000096ff, 0x0000a7c6, 0x0000b88d,
|
||||
0x0000c954, 0x0000da1b, 0x0000eae2, 0x0000fba9,
|
||||
0x00010c6f, 0x00011d36, 0x00012dfd, 0x00013ec4,
|
||||
0x00014f8b, 0x00016052, 0x00017119, 0x000181e0,
|
||||
0x000192a7, 0x0001a36e, 0x0001b435, 0x0001c4fc,
|
||||
0x0001d5c3, 0x0001e68a, 0x0001f751, 0x00020818,
|
||||
0x000218df, 0x000229a6, 0x00023a6d, 0x00024b34,
|
||||
0x00025bfb, 0x00026cc2, 0x00027d89, 0x00028e50,
|
||||
0x00029f17, 0x0002afde, 0x0002c0a5, 0x0002d16c,
|
||||
0x0002e233, 0x0002f2fa, 0x000303c0, 0x00031487,
|
||||
0x0003254e, 0x00033615, 0x000346dc, 0x000357a3,
|
||||
0x0003686a, 0x00037931, 0x000389f8, 0x00039abf,
|
||||
0x0003ab86, 0x0003bc4d, 0x0003cd14, 0x0003dddb,
|
||||
0x0003eea2, 0x0003ff69, 0x00041030, 0x000420f7,
|
||||
0x000431be, 0x00044285, 0x0004534c, 0x00046413,
|
||||
0x000474da, 0x000485a1, 0x00049668, 0x0004a72f,
|
||||
0x0004b7f6, 0x0004c8bd, 0x0004d984, 0x0004ea4b,
|
||||
0x0004fb12, 0x00050bd8, 0x00051c9f, 0x00052d66,
|
||||
0x00053e2d, 0x00054ef4, 0x00055fbb, 0x00057082,
|
||||
0x00058149, 0x00059210, 0x0005a2d7, 0x0005b39e,
|
||||
0x0005c465, 0x0005d52c, 0x0005e5f3, 0x0005f6ba,
|
||||
0x00060781, 0x00061848, 0x0006290f, 0x000639d6,
|
||||
0x00064a9d, 0x00065b64, 0x00066c2b, 0x00067cf2,
|
||||
0x00068db9, 0x00069e80, 0x0006af47, 0x0006c00e,
|
||||
0x0006d0d5, 0x0006e19c, 0x0006f263, 0x0007032a,
|
||||
0x000713f0, 0x000724b7, 0x0007357e, 0x00074645,
|
||||
0x0007570c, 0x000767d3, 0x0007789a, 0x00078961,
|
||||
0x00079a28, 0x0007aaef, 0x0007bbb6, 0x0007cc7d,
|
||||
0x0007dd44, 0x0007ee0b, 0x0007fed2, 0x00080f99,
|
||||
0x00082060, 0x00083127, 0x000841ee, 0x000852b5,
|
||||
0x0008637c, 0x00087443, 0x0008850a, 0x000895d1,
|
||||
0x0008a698, 0x0008b75f, 0x0008c826, 0x0008d8ed,
|
||||
0x0008e9b4, 0x0008fa7b, 0x00090b41, 0x00091c08,
|
||||
0x00092ccf, 0x00093d96, 0x00094e5d, 0x00095f24,
|
||||
0x00096feb, 0x000980b2, 0x00099179, 0x0009a240,
|
||||
0x0009b307, 0x0009c3ce, 0x0009d495, 0x0009e55c,
|
||||
0x0009f623, 0x000a06ea, 0x000a17b1, 0x000a2878,
|
||||
0x000a393f, 0x000a4a06, 0x000a5acd, 0x000a6b94,
|
||||
0x000a7c5b, 0x000a8d22, 0x000a9de9, 0x000aaeb0,
|
||||
0x000abf77, 0x000ad03e, 0x000ae105, 0x000af1cc,
|
||||
0x000b0293, 0x000b1359, 0x000b2420, 0x000b34e7,
|
||||
0x000b45ae, 0x000b5675, 0x000b673c, 0x000b7803,
|
||||
0x000b88ca, 0x000b9991, 0x000baa58, 0x000bbb1f,
|
||||
0x000bcbe6, 0x000bdcad, 0x000bed74, 0x000bfe3b,
|
||||
0x000c0f02, 0x000c1fc9, 0x000c3090, 0x000c4157,
|
||||
0x000c521e, 0x000c62e5, 0x000c73ac, 0x000c8473,
|
||||
0x000c953a, 0x000ca601, 0x000cb6c8, 0x000cc78f,
|
||||
0x000cd856, 0x000ce91d, 0x000cf9e4, 0x000d0aaa,
|
||||
0x000d1b71, 0x000d2c38, 0x000d3cff, 0x000d4dc6,
|
||||
0x000d5e8d, 0x000d6f54, 0x000d801b, 0x000d90e2,
|
||||
0x000da1a9, 0x000db270, 0x000dc337, 0x000dd3fe,
|
||||
0x000de4c5, 0x000df58c, 0x000e0653, 0x000e171a,
|
||||
0x000e27e1, 0x000e38a8, 0x000e496f, 0x000e5a36,
|
||||
0x000e6afd, 0x000e7bc4, 0x000e8c8b, 0x000e9d52,
|
||||
0x000eae19, 0x000ebee0, 0x000ecfa7, 0x000ee06e,
|
||||
0x000ef135, 0x000f01fc, 0x000f12c2, 0x000f2389,
|
||||
0x000f3450, 0x000f4517, 0x000f55de, 0x000f66a5,
|
||||
0x000f776c, 0x000f8833, 0x000f98fa, 0x000fa9c1,
|
||||
0x000fba88, 0x000fcb4f, 0x000fdc16, 0x000fecdd,
|
||||
0x000ffda4, 0x00100e6b, 0x00101f32, 0x00102ff9,
|
||||
0x001040c0, 0x00105187, 0x0010624e, 0x00107315,
|
||||
0x001083dc, 0x001094a3, 0x0010a56a, 0x0010b631
|
||||
};
|
||||
|
||||
const u_int32 ustotsmid[256] = {
|
||||
0x00000000, 0x0010c6f8, 0x00218def, 0x003254e7,
|
||||
0x00431bdf, 0x0053e2d6, 0x0064a9ce, 0x007570c5,
|
||||
0x008637bd, 0x0096feb5, 0x00a7c5ac, 0x00b88ca4,
|
||||
0x00c9539c, 0x00da1a93, 0x00eae18b, 0x00fba882,
|
||||
0x010c6f7a, 0x011d3672, 0x012dfd69, 0x013ec461,
|
||||
0x014f8b59, 0x01605250, 0x01711948, 0x0181e03f,
|
||||
0x0192a737, 0x01a36e2f, 0x01b43526, 0x01c4fc1e,
|
||||
0x01d5c316, 0x01e68a0d, 0x01f75105, 0x020817fc,
|
||||
0x0218def4, 0x0229a5ec, 0x023a6ce3, 0x024b33db,
|
||||
0x025bfad3, 0x026cc1ca, 0x027d88c2, 0x028e4fb9,
|
||||
0x029f16b1, 0x02afdda9, 0x02c0a4a0, 0x02d16b98,
|
||||
0x02e23290, 0x02f2f987, 0x0303c07f, 0x03148777,
|
||||
0x03254e6e, 0x03361566, 0x0346dc5d, 0x0357a355,
|
||||
0x03686a4d, 0x03793144, 0x0389f83c, 0x039abf34,
|
||||
0x03ab862b, 0x03bc4d23, 0x03cd141a, 0x03dddb12,
|
||||
0x03eea20a, 0x03ff6901, 0x04102ff9, 0x0420f6f1,
|
||||
0x0431bde8, 0x044284e0, 0x04534bd7, 0x046412cf,
|
||||
0x0474d9c7, 0x0485a0be, 0x049667b6, 0x04a72eae,
|
||||
0x04b7f5a5, 0x04c8bc9d, 0x04d98394, 0x04ea4a8c,
|
||||
0x04fb1184, 0x050bd87b, 0x051c9f73, 0x052d666b,
|
||||
0x053e2d62, 0x054ef45a, 0x055fbb51, 0x05708249,
|
||||
0x05814941, 0x05921038, 0x05a2d730, 0x05b39e28,
|
||||
0x05c4651f, 0x05d52c17, 0x05e5f30e, 0x05f6ba06,
|
||||
0x060780fe, 0x061847f5, 0x06290eed, 0x0639d5e5,
|
||||
0x064a9cdc, 0x065b63d4, 0x066c2acc, 0x067cf1c3,
|
||||
0x068db8bb, 0x069e7fb2, 0x06af46aa, 0x06c00da2,
|
||||
0x06d0d499, 0x06e19b91, 0x06f26289, 0x07032980,
|
||||
0x0713f078, 0x0724b76f, 0x07357e67, 0x0746455f,
|
||||
0x07570c56, 0x0767d34e, 0x07789a46, 0x0789613d,
|
||||
0x079a2835, 0x07aaef2c, 0x07bbb624, 0x07cc7d1c,
|
||||
0x07dd4413, 0x07ee0b0b, 0x07fed203, 0x080f98fa,
|
||||
0x08205ff2, 0x083126e9, 0x0841ede1, 0x0852b4d9,
|
||||
0x08637bd0, 0x087442c8, 0x088509c0, 0x0895d0b7,
|
||||
0x08a697af, 0x08b75ea6, 0x08c8259e, 0x08d8ec96,
|
||||
0x08e9b38d, 0x08fa7a85, 0x090b417d, 0x091c0874,
|
||||
0x092ccf6c, 0x093d9664, 0x094e5d5b, 0x095f2453,
|
||||
0x096feb4a, 0x0980b242, 0x0991793a, 0x09a24031,
|
||||
0x09b30729, 0x09c3ce21, 0x09d49518, 0x09e55c10,
|
||||
0x09f62307, 0x0a06e9ff, 0x0a17b0f7, 0x0a2877ee,
|
||||
0x0a393ee6, 0x0a4a05de, 0x0a5accd5, 0x0a6b93cd,
|
||||
0x0a7c5ac4, 0x0a8d21bc, 0x0a9de8b4, 0x0aaeafab,
|
||||
0x0abf76a3, 0x0ad03d9b, 0x0ae10492, 0x0af1cb8a,
|
||||
0x0b029281, 0x0b135979, 0x0b242071, 0x0b34e768,
|
||||
0x0b45ae60, 0x0b567558, 0x0b673c4f, 0x0b780347,
|
||||
0x0b88ca3e, 0x0b999136, 0x0baa582e, 0x0bbb1f25,
|
||||
0x0bcbe61d, 0x0bdcad15, 0x0bed740c, 0x0bfe3b04,
|
||||
0x0c0f01fc, 0x0c1fc8f3, 0x0c308feb, 0x0c4156e2,
|
||||
0x0c521dda, 0x0c62e4d2, 0x0c73abc9, 0x0c8472c1,
|
||||
0x0c9539b9, 0x0ca600b0, 0x0cb6c7a8, 0x0cc78e9f,
|
||||
0x0cd85597, 0x0ce91c8f, 0x0cf9e386, 0x0d0aaa7e,
|
||||
0x0d1b7176, 0x0d2c386d, 0x0d3cff65, 0x0d4dc65c,
|
||||
0x0d5e8d54, 0x0d6f544c, 0x0d801b43, 0x0d90e23b,
|
||||
0x0da1a933, 0x0db2702a, 0x0dc33722, 0x0dd3fe19,
|
||||
0x0de4c511, 0x0df58c09, 0x0e065300, 0x0e1719f8,
|
||||
0x0e27e0f0, 0x0e38a7e7, 0x0e496edf, 0x0e5a35d6,
|
||||
0x0e6afcce, 0x0e7bc3c6, 0x0e8c8abd, 0x0e9d51b5,
|
||||
0x0eae18ad, 0x0ebedfa4, 0x0ecfa69c, 0x0ee06d94,
|
||||
0x0ef1348b, 0x0f01fb83, 0x0f12c27a, 0x0f238972,
|
||||
0x0f34506a, 0x0f451761, 0x0f55de59, 0x0f66a551,
|
||||
0x0f776c48, 0x0f883340, 0x0f98fa37, 0x0fa9c12f,
|
||||
0x0fba8827, 0x0fcb4f1e, 0x0fdc1616, 0x0fecdd0e,
|
||||
0x0ffda405, 0x100e6afd, 0x101f31f4, 0x102ff8ec,
|
||||
0x1040bfe4, 0x105186db, 0x10624dd3, 0x107314cb,
|
||||
0x1083dbc2, 0x1094a2ba, 0x10a569b1, 0x10b630a9
|
||||
};
|
||||
|
||||
const u_int32 ustotshi[16] = {
|
||||
0x00000000, 0x10c6f7a1, 0x218def41, 0x3254e6e2,
|
||||
0x431bde83, 0x53e2d624, 0x64a9cdc4, 0x7570c565,
|
||||
0x8637bd06, 0x96feb4a6, 0xa7c5ac47, 0xb88ca3e8,
|
||||
0xc9539b89, 0xda1a9329, 0xeae18aca, 0xfba8826b
|
||||
};
|
||||
|
||||
/*
|
||||
* Tables to convert from a time stamp fraction to usecs. Note that
|
||||
* the units of these tables are actually (usec<<3). We carry three
|
||||
* guard bits so that the result can be properly truncated (or rounded)
|
||||
* to be correct to the least significant bit.
|
||||
*
|
||||
* These tables are rounded.
|
||||
*/
|
||||
|
||||
const u_int32 tstoushi[256] = {
|
||||
0x000000, 0x007a12, 0x00f424, 0x016e36,
|
||||
0x01e848, 0x02625a, 0x02dc6c, 0x03567e,
|
||||
0x03d090, 0x044aa2, 0x04c4b4, 0x053ec6,
|
||||
0x05b8d8, 0x0632ea, 0x06acfc, 0x07270e,
|
||||
0x07a120, 0x081b32, 0x089544, 0x090f56,
|
||||
0x098968, 0x0a037a, 0x0a7d8c, 0x0af79e,
|
||||
0x0b71b0, 0x0bebc2, 0x0c65d4, 0x0cdfe6,
|
||||
0x0d59f8, 0x0dd40a, 0x0e4e1c, 0x0ec82e,
|
||||
0x0f4240, 0x0fbc52, 0x103664, 0x10b076,
|
||||
0x112a88, 0x11a49a, 0x121eac, 0x1298be,
|
||||
0x1312d0, 0x138ce2, 0x1406f4, 0x148106,
|
||||
0x14fb18, 0x15752a, 0x15ef3c, 0x16694e,
|
||||
0x16e360, 0x175d72, 0x17d784, 0x185196,
|
||||
0x18cba8, 0x1945ba, 0x19bfcc, 0x1a39de,
|
||||
0x1ab3f0, 0x1b2e02, 0x1ba814, 0x1c2226,
|
||||
0x1c9c38, 0x1d164a, 0x1d905c, 0x1e0a6e,
|
||||
0x1e8480, 0x1efe92, 0x1f78a4, 0x1ff2b6,
|
||||
0x206cc8, 0x20e6da, 0x2160ec, 0x21dafe,
|
||||
0x225510, 0x22cf22, 0x234934, 0x23c346,
|
||||
0x243d58, 0x24b76a, 0x25317c, 0x25ab8e,
|
||||
0x2625a0, 0x269fb2, 0x2719c4, 0x2793d6,
|
||||
0x280de8, 0x2887fa, 0x29020c, 0x297c1e,
|
||||
0x29f630, 0x2a7042, 0x2aea54, 0x2b6466,
|
||||
0x2bde78, 0x2c588a, 0x2cd29c, 0x2d4cae,
|
||||
0x2dc6c0, 0x2e40d2, 0x2ebae4, 0x2f34f6,
|
||||
0x2faf08, 0x30291a, 0x30a32c, 0x311d3e,
|
||||
0x319750, 0x321162, 0x328b74, 0x330586,
|
||||
0x337f98, 0x33f9aa, 0x3473bc, 0x34edce,
|
||||
0x3567e0, 0x35e1f2, 0x365c04, 0x36d616,
|
||||
0x375028, 0x37ca3a, 0x38444c, 0x38be5e,
|
||||
0x393870, 0x39b282, 0x3a2c94, 0x3aa6a6,
|
||||
0x3b20b8, 0x3b9aca, 0x3c14dc, 0x3c8eee,
|
||||
0x3d0900, 0x3d8312, 0x3dfd24, 0x3e7736,
|
||||
0x3ef148, 0x3f6b5a, 0x3fe56c, 0x405f7e,
|
||||
0x40d990, 0x4153a2, 0x41cdb4, 0x4247c6,
|
||||
0x42c1d8, 0x433bea, 0x43b5fc, 0x44300e,
|
||||
0x44aa20, 0x452432, 0x459e44, 0x461856,
|
||||
0x469268, 0x470c7a, 0x47868c, 0x48009e,
|
||||
0x487ab0, 0x48f4c2, 0x496ed4, 0x49e8e6,
|
||||
0x4a62f8, 0x4add0a, 0x4b571c, 0x4bd12e,
|
||||
0x4c4b40, 0x4cc552, 0x4d3f64, 0x4db976,
|
||||
0x4e3388, 0x4ead9a, 0x4f27ac, 0x4fa1be,
|
||||
0x501bd0, 0x5095e2, 0x510ff4, 0x518a06,
|
||||
0x520418, 0x527e2a, 0x52f83c, 0x53724e,
|
||||
0x53ec60, 0x546672, 0x54e084, 0x555a96,
|
||||
0x55d4a8, 0x564eba, 0x56c8cc, 0x5742de,
|
||||
0x57bcf0, 0x583702, 0x58b114, 0x592b26,
|
||||
0x59a538, 0x5a1f4a, 0x5a995c, 0x5b136e,
|
||||
0x5b8d80, 0x5c0792, 0x5c81a4, 0x5cfbb6,
|
||||
0x5d75c8, 0x5defda, 0x5e69ec, 0x5ee3fe,
|
||||
0x5f5e10, 0x5fd822, 0x605234, 0x60cc46,
|
||||
0x614658, 0x61c06a, 0x623a7c, 0x62b48e,
|
||||
0x632ea0, 0x63a8b2, 0x6422c4, 0x649cd6,
|
||||
0x6516e8, 0x6590fa, 0x660b0c, 0x66851e,
|
||||
0x66ff30, 0x677942, 0x67f354, 0x686d66,
|
||||
0x68e778, 0x69618a, 0x69db9c, 0x6a55ae,
|
||||
0x6acfc0, 0x6b49d2, 0x6bc3e4, 0x6c3df6,
|
||||
0x6cb808, 0x6d321a, 0x6dac2c, 0x6e263e,
|
||||
0x6ea050, 0x6f1a62, 0x6f9474, 0x700e86,
|
||||
0x708898, 0x7102aa, 0x717cbc, 0x71f6ce,
|
||||
0x7270e0, 0x72eaf2, 0x736504, 0x73df16,
|
||||
0x745928, 0x74d33a, 0x754d4c, 0x75c75e,
|
||||
0x764170, 0x76bb82, 0x773594, 0x77afa6,
|
||||
0x7829b8, 0x78a3ca, 0x791ddc, 0x7997ee
|
||||
};
|
||||
|
||||
const u_int32 tstousmid[256] = {
|
||||
0x0000, 0x007a, 0x00f4, 0x016e, 0x01e8, 0x0262, 0x02dc, 0x0356,
|
||||
0x03d1, 0x044b, 0x04c5, 0x053f, 0x05b9, 0x0633, 0x06ad, 0x0727,
|
||||
0x07a1, 0x081b, 0x0895, 0x090f, 0x0989, 0x0a03, 0x0a7e, 0x0af8,
|
||||
0x0b72, 0x0bec, 0x0c66, 0x0ce0, 0x0d5a, 0x0dd4, 0x0e4e, 0x0ec8,
|
||||
0x0f42, 0x0fbc, 0x1036, 0x10b0, 0x112b, 0x11a5, 0x121f, 0x1299,
|
||||
0x1313, 0x138d, 0x1407, 0x1481, 0x14fb, 0x1575, 0x15ef, 0x1669,
|
||||
0x16e3, 0x175d, 0x17d8, 0x1852, 0x18cc, 0x1946, 0x19c0, 0x1a3a,
|
||||
0x1ab4, 0x1b2e, 0x1ba8, 0x1c22, 0x1c9c, 0x1d16, 0x1d90, 0x1e0a,
|
||||
0x1e84, 0x1eff, 0x1f79, 0x1ff3, 0x206d, 0x20e7, 0x2161, 0x21db,
|
||||
0x2255, 0x22cf, 0x2349, 0x23c3, 0x243d, 0x24b7, 0x2531, 0x25ac,
|
||||
0x2626, 0x26a0, 0x271a, 0x2794, 0x280e, 0x2888, 0x2902, 0x297c,
|
||||
0x29f6, 0x2a70, 0x2aea, 0x2b64, 0x2bde, 0x2c59, 0x2cd3, 0x2d4d,
|
||||
0x2dc7, 0x2e41, 0x2ebb, 0x2f35, 0x2faf, 0x3029, 0x30a3, 0x311d,
|
||||
0x3197, 0x3211, 0x328b, 0x3306, 0x3380, 0x33fa, 0x3474, 0x34ee,
|
||||
0x3568, 0x35e2, 0x365c, 0x36d6, 0x3750, 0x37ca, 0x3844, 0x38be,
|
||||
0x3938, 0x39b3, 0x3a2d, 0x3aa7, 0x3b21, 0x3b9b, 0x3c15, 0x3c8f,
|
||||
0x3d09, 0x3d83, 0x3dfd, 0x3e77, 0x3ef1, 0x3f6b, 0x3fe5, 0x405f,
|
||||
0x40da, 0x4154, 0x41ce, 0x4248, 0x42c2, 0x433c, 0x43b6, 0x4430,
|
||||
0x44aa, 0x4524, 0x459e, 0x4618, 0x4692, 0x470c, 0x4787, 0x4801,
|
||||
0x487b, 0x48f5, 0x496f, 0x49e9, 0x4a63, 0x4add, 0x4b57, 0x4bd1,
|
||||
0x4c4b, 0x4cc5, 0x4d3f, 0x4db9, 0x4e34, 0x4eae, 0x4f28, 0x4fa2,
|
||||
0x501c, 0x5096, 0x5110, 0x518a, 0x5204, 0x527e, 0x52f8, 0x5372,
|
||||
0x53ec, 0x5466, 0x54e1, 0x555b, 0x55d5, 0x564f, 0x56c9, 0x5743,
|
||||
0x57bd, 0x5837, 0x58b1, 0x592b, 0x59a5, 0x5a1f, 0x5a99, 0x5b13,
|
||||
0x5b8d, 0x5c08, 0x5c82, 0x5cfc, 0x5d76, 0x5df0, 0x5e6a, 0x5ee4,
|
||||
0x5f5e, 0x5fd8, 0x6052, 0x60cc, 0x6146, 0x61c0, 0x623a, 0x62b5,
|
||||
0x632f, 0x63a9, 0x6423, 0x649d, 0x6517, 0x6591, 0x660b, 0x6685,
|
||||
0x66ff, 0x6779, 0x67f3, 0x686d, 0x68e7, 0x6962, 0x69dc, 0x6a56,
|
||||
0x6ad0, 0x6b4a, 0x6bc4, 0x6c3e, 0x6cb8, 0x6d32, 0x6dac, 0x6e26,
|
||||
0x6ea0, 0x6f1a, 0x6f94, 0x700f, 0x7089, 0x7103, 0x717d, 0x71f7,
|
||||
0x7271, 0x72eb, 0x7365, 0x73df, 0x7459, 0x74d3, 0x754d, 0x75c7,
|
||||
0x7641, 0x76bc, 0x7736, 0x77b0, 0x782a, 0x78a4, 0x791e, 0x7998
|
||||
};
|
||||
|
||||
const u_int32 tstouslo[128] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
||||
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
|
||||
0x1f, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
|
||||
0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x33, 0x34,
|
||||
0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
|
||||
0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44,
|
||||
0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b,
|
||||
0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
|
||||
0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b,
|
||||
0x5c, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
|
||||
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
|
||||
0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x71,
|
||||
0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79
|
||||
};
|
||||
#else /* !USE_TSF_USEC_TABLES follows */
|
||||
NONEMPTY_TRANSLATION_UNIT
|
||||
#endif /* !USE_TSF_USEC_TABLES */
|
||||
/* -*- EOF -*- */
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* timexsup.c - 'struct timex' support functions
|
||||
*
|
||||
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
|
||||
* The contents of 'html/copyright.html' apply.
|
||||
*/
|
||||
|
||||
#include "ipntp_config.h"
|
||||
#include "timexsup.h"
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef HAVE_SYS_TIMEX_H
|
||||
# include <sys/timex.h>
|
||||
#endif
|
||||
|
||||
#if defined(MOD_NANO) != defined(STA_NANO)
|
||||
# warning inconsistent definitions of MOD_NANO vs STA_NANO
|
||||
#endif
|
||||
|
||||
static long
|
||||
clamp_rounded(
|
||||
double dval
|
||||
)
|
||||
{
|
||||
/* round */
|
||||
dval = floor(dval + 0.5);
|
||||
|
||||
/* clamp / saturate */
|
||||
if (dval >= (double)LONG_MAX)
|
||||
return LONG_MAX;
|
||||
if (dval <= (double)LONG_MIN)
|
||||
return LONG_MIN;
|
||||
return (long)dval;
|
||||
}
|
||||
|
||||
double
|
||||
dbl_from_var_long(
|
||||
long lval,
|
||||
int status
|
||||
)
|
||||
{
|
||||
#ifdef STA_NANO
|
||||
if (status & STA_NANO)
|
||||
return (double)lval * 1e-9;
|
||||
#else
|
||||
(void)status;
|
||||
#endif
|
||||
return (double)lval * 1e-6;
|
||||
}
|
||||
|
||||
double
|
||||
dbl_from_usec_long(
|
||||
long lval
|
||||
)
|
||||
{
|
||||
return (double)lval * 1e-6;
|
||||
}
|
||||
|
||||
long
|
||||
var_long_from_dbl(
|
||||
double dval,
|
||||
unsigned int * modes
|
||||
)
|
||||
{
|
||||
#ifdef MOD_NANO
|
||||
*modes |= MOD_NANO;
|
||||
dval *= 1e+9;
|
||||
#else
|
||||
(void)modes;
|
||||
dval *= 1e+6;
|
||||
#endif
|
||||
return clamp_rounded(dval);
|
||||
}
|
||||
|
||||
long
|
||||
usec_long_from_dbl(
|
||||
double dval
|
||||
)
|
||||
{
|
||||
return clamp_rounded(dval * 1e+6);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* uglydate - convert a time stamp to something barely readable
|
||||
* The string returned is 37 characters long.
|
||||
*/
|
||||
#include <ipntp_config.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntp_fp.h"
|
||||
#include "ntp_unixtime.h"
|
||||
#include "lib_strbuf.h"
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
|
||||
char *
|
||||
uglydate(
|
||||
l_fp *ts
|
||||
)
|
||||
{
|
||||
char *bp;
|
||||
char *timep;
|
||||
struct tm *tm;
|
||||
time_t sec;
|
||||
long msec;
|
||||
int year;
|
||||
|
||||
timep = ulfptoa(ts, 6); /* returns max 17 characters */
|
||||
LIB_GETBUF(bp);
|
||||
sec = ts->l_ui - JAN_1970;
|
||||
msec = ts->l_uf / 4294967; /* fract / (2**32/1000) */
|
||||
tm = gmtime(&sec);
|
||||
if (ts->l_ui == 0) {
|
||||
/*
|
||||
* Probably not a real good thing to do. Oh, well.
|
||||
*/
|
||||
year = 0;
|
||||
tm->tm_yday = 0;
|
||||
tm->tm_hour = 0;
|
||||
tm->tm_min = 0;
|
||||
tm->tm_sec = 0;
|
||||
} else {
|
||||
year = tm->tm_year;
|
||||
while (year >= 100)
|
||||
year -= 100;
|
||||
}
|
||||
snprintf(bp, LIB_BUFLENGTH,
|
||||
"%17s %02d:%03d:%02d:%02d:%02d.%03ld", timep, year,
|
||||
tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec,
|
||||
msec);
|
||||
|
||||
return bp;
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* vint64ops.c - operations on 'vint64' values
|
||||
*
|
||||
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
|
||||
* The contents of 'html/copyright.html' apply.
|
||||
* ----------------------------------------------------------------------
|
||||
* This is an attempt to get the vint64 calculations stuff centralised.
|
||||
*/
|
||||
|
||||
#include <ipntp_config.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "ntp_types.h"
|
||||
#include "ntp_fp.h"
|
||||
#include "vint64ops.h"
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* GCC is rather sticky with its 'const' attribute. We have to do it more
|
||||
* explicit than with a cast if we want to get rid of a CONST qualifier.
|
||||
* Greetings from the PASCAL world, where casting was only possible via
|
||||
* untagged unions...
|
||||
*/
|
||||
static inline void*
|
||||
noconst(
|
||||
const void* ptr
|
||||
)
|
||||
{
|
||||
union {
|
||||
const void * cp;
|
||||
void * vp;
|
||||
} tmp;
|
||||
tmp.cp = ptr;
|
||||
return tmp.vp;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------*/
|
||||
|
||||
vint64
|
||||
strtouv64(
|
||||
const char * begp,
|
||||
char ** endp,
|
||||
int base
|
||||
)
|
||||
{
|
||||
vint64 res;
|
||||
u_char digit;
|
||||
int sig, num;
|
||||
const u_char *src;
|
||||
|
||||
num = sig = 0;
|
||||
src = (const u_char*)begp;
|
||||
while (isspace(*src))
|
||||
src++;
|
||||
|
||||
if (*src == '-') {
|
||||
src++;
|
||||
sig = 1;
|
||||
} else if (*src == '+') {
|
||||
src++;
|
||||
}
|
||||
|
||||
if (base == 0) {
|
||||
base = 10;
|
||||
if (*src == '0') {
|
||||
base = 8;
|
||||
if (toupper(*++src) == 'X') {
|
||||
src++;
|
||||
base = 16;
|
||||
}
|
||||
}
|
||||
} else if (base == 16) { /* remove optional leading '0x' or '0X' */
|
||||
if (src[0] == '0' && toupper(src[1]) == 'X')
|
||||
src += 2;
|
||||
} else if (base <= 2 || base > 36) {
|
||||
memset(&res, 0xFF, sizeof(res));
|
||||
errno = ERANGE;
|
||||
return res;
|
||||
}
|
||||
|
||||
memset(&res, 0, sizeof(res));
|
||||
while (*src) {
|
||||
if (isdigit(*src))
|
||||
digit = *src - '0';
|
||||
else if (isupper(*src))
|
||||
digit = *src - 'A' + 10;
|
||||
else if (islower(*src))
|
||||
digit = *src - 'a' + 10;
|
||||
else
|
||||
break;
|
||||
if (digit >= base)
|
||||
break;
|
||||
num = 1;
|
||||
#if defined(HAVE_INT64)
|
||||
res.Q_s = res.Q_s * base + digit;
|
||||
#else
|
||||
/* res *= base, using 16x16->32 bit
|
||||
* multiplication. Slow but portable.
|
||||
*/
|
||||
{
|
||||
uint32_t accu;
|
||||
accu = (uint32_t)res.W_s.ll * base;
|
||||
res.W_s.ll = (uint16_t)accu;
|
||||
accu = (accu >> 16)
|
||||
+ (uint32_t)res.W_s.lh * base;
|
||||
res.W_s.lh = (uint16_t)accu;
|
||||
/* the upper bits can be done in one step: */
|
||||
res.D_s.hi = res.D_s.hi * base + (accu >> 16);
|
||||
}
|
||||
M_ADD(res.D_s.hi, res.D_s.lo, 0, digit);
|
||||
#endif
|
||||
src++;
|
||||
}
|
||||
if (!num)
|
||||
errno = EINVAL;
|
||||
if (endp)
|
||||
*endp = (char*)noconst(src);
|
||||
if (sig)
|
||||
M_NEG(res.D_s.hi, res.D_s.lo);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
icmpv64(
|
||||
const vint64 * lhs,
|
||||
const vint64 * rhs
|
||||
)
|
||||
{
|
||||
int res;
|
||||
|
||||
#if defined(HAVE_INT64)
|
||||
res = (lhs->q_s > rhs->q_s)
|
||||
- (lhs->q_s < rhs->q_s);
|
||||
#else
|
||||
res = (lhs->d_s.hi > rhs->d_s.hi)
|
||||
- (lhs->d_s.hi < rhs->d_s.hi);
|
||||
if ( ! res )
|
||||
res = (lhs->D_s.lo > rhs->D_s.lo)
|
||||
- (lhs->D_s.lo < rhs->D_s.lo);
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
ucmpv64(
|
||||
const vint64 * lhs,
|
||||
const vint64 * rhs
|
||||
)
|
||||
{
|
||||
int res;
|
||||
|
||||
#if defined(HAVE_INT64)
|
||||
res = (lhs->Q_s > rhs->Q_s)
|
||||
- (lhs->Q_s < rhs->Q_s);
|
||||
#else
|
||||
res = (lhs->D_s.hi > rhs->D_s.hi)
|
||||
- (lhs->D_s.hi < rhs->D_s.hi);
|
||||
if ( ! res )
|
||||
res = (lhs->D_s.lo > rhs->D_s.lo)
|
||||
- (lhs->D_s.lo < rhs->D_s.lo);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------*/
|
||||
|
||||
vint64
|
||||
addv64(
|
||||
const vint64 *lhs,
|
||||
const vint64 *rhs
|
||||
)
|
||||
{
|
||||
vint64 res;
|
||||
|
||||
#if defined(HAVE_INT64)
|
||||
res.Q_s = lhs->Q_s + rhs->Q_s;
|
||||
#else
|
||||
res = *lhs;
|
||||
M_ADD(res.D_s.hi, res.D_s.lo, rhs->D_s.hi, rhs->D_s.lo);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------*/
|
||||
|
||||
vint64
|
||||
subv64(
|
||||
const vint64 *lhs,
|
||||
const vint64 *rhs
|
||||
)
|
||||
{
|
||||
vint64 res;
|
||||
|
||||
#if defined(HAVE_INT64)
|
||||
res.Q_s = lhs->Q_s - rhs->Q_s;
|
||||
#else
|
||||
res = *lhs;
|
||||
M_SUB(res.D_s.hi, res.D_s.lo, rhs->D_s.hi, rhs->D_s.lo);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------*/
|
||||
|
||||
vint64
|
||||
addv64i32(
|
||||
const vint64 * lhs,
|
||||
int32_t rhs
|
||||
)
|
||||
{
|
||||
vint64 res;
|
||||
|
||||
res = *lhs;
|
||||
#if defined(HAVE_INT64)
|
||||
res.q_s += rhs;
|
||||
#else
|
||||
M_ADD(res.D_s.hi, res.D_s.lo, -(rhs < 0), rhs);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------*/
|
||||
|
||||
vint64
|
||||
subv64i32(
|
||||
const vint64 * lhs,
|
||||
int32_t rhs
|
||||
)
|
||||
{
|
||||
vint64 res;
|
||||
|
||||
res = *lhs;
|
||||
#if defined(HAVE_INT64)
|
||||
res.q_s -= rhs;
|
||||
#else
|
||||
M_SUB(res.D_s.hi, res.D_s.lo, -(rhs < 0), rhs);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------*/
|
||||
|
||||
vint64
|
||||
addv64u32(
|
||||
const vint64 * lhs,
|
||||
uint32_t rhs
|
||||
)
|
||||
{
|
||||
vint64 res;
|
||||
|
||||
res = *lhs;
|
||||
#if defined(HAVE_INT64)
|
||||
res.Q_s += rhs;
|
||||
#else
|
||||
M_ADD(res.D_s.hi, res.D_s.lo, 0, rhs);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------*/
|
||||
|
||||
vint64
|
||||
subv64u32(
|
||||
const vint64 * lhs,
|
||||
uint32_t rhs
|
||||
)
|
||||
{
|
||||
vint64 res;
|
||||
|
||||
res = *lhs;
|
||||
#if defined(HAVE_INT64)
|
||||
res.Q_s -= rhs;
|
||||
#else
|
||||
M_SUB(res.D_s.hi, res.D_s.lo, 0, rhs);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* xsbprintf.c - string buffer formatting helpers
|
||||
*
|
||||
* Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
|
||||
* The contents of 'html/copyright.html' apply.
|
||||
*/
|
||||
|
||||
#include <ipntp_config.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "ntp_stdlib.h"
|
||||
|
||||
/* eXtended Varlist String Buffer printf
|
||||
*
|
||||
* Formats via 'vsnprintf' into a string buffer, with some semantic
|
||||
* specialties:
|
||||
*
|
||||
* - The start of the buffer pointer is updated according to the number
|
||||
* of characters written.
|
||||
* - If the buffer is insufficient to format the number of charactes,
|
||||
* the partial result will be be discarded, and zero is returned to
|
||||
* indicate nothing was written to the buffer.
|
||||
* - On successful formatting, the return code is the return value of
|
||||
* the inner call to 'vsnprintf()'.
|
||||
* - If there is any error, the state of the buffer will not be
|
||||
* changed. (Bytes in the buffer might be smashed, but the buffer
|
||||
* position does not change, and the NUL marker stays in place at the
|
||||
* current buffer position.)
|
||||
* - If '(*ppbuf - pend) <= 0' (or ppbuf is NULL), fail with EINVAL.
|
||||
*/
|
||||
int
|
||||
xvsbprintf(
|
||||
char **ppbuf, /* pointer to buffer pointer (I/O) */
|
||||
char * const pend, /* buffer end (I) */
|
||||
char const *pfmt, /* printf-like format string */
|
||||
va_list va /* formatting args for above */
|
||||
)
|
||||
{
|
||||
char *pbuf = (ppbuf) ? *ppbuf : NULL;
|
||||
int rc = -1;
|
||||
if (pbuf && (pend - pbuf > 0)) {
|
||||
size_t blen = (size_t)(pend - pbuf);
|
||||
rc = vsnprintf(pbuf, blen, pfmt, va);
|
||||
if (rc > 0) {
|
||||
if ((size_t)rc >= blen)
|
||||
rc = 0;
|
||||
pbuf += rc;
|
||||
}
|
||||
*pbuf = '\0'; /* fear of bad vsnprintf */
|
||||
*ppbuf = pbuf;
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* variadic wrapper around the buffer string formatter */
|
||||
int
|
||||
xsbprintf(
|
||||
char **ppbuf, /* pointer to buffer pointer (I/O) */
|
||||
char * const pend, /* buffer end (I) */
|
||||
char const *pfmt, /* printf-like format string */
|
||||
... /* formatting args for above */
|
||||
)
|
||||
{
|
||||
va_list va;
|
||||
int rc;
|
||||
|
||||
va_start(va, pfmt);
|
||||
rc = xvsbprintf(ppbuf, pend, pfmt, va);
|
||||
va_end(va);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* that's all folks! */
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* ymd2yd - compute the date in the year from y/m/d
|
||||
*
|
||||
* A thin wrapper around a more general calendar function.
|
||||
*/
|
||||
|
||||
#include <ipntp_config.h>
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_calendar.h"
|
||||
|
||||
int
|
||||
ymd2yd(
|
||||
int y,
|
||||
int m,
|
||||
int d)
|
||||
{
|
||||
/*
|
||||
* convert y/m/d to elapsed calendar units, convert that to
|
||||
* elapsed days since the start of the given year and convert
|
||||
* back to unity-based day in year.
|
||||
*
|
||||
* This does no further error checking, since the underlying
|
||||
* function is assumed to work out how to handle the data.
|
||||
*/
|
||||
return ntpcal_edate_to_yeardays(y-1, m-1, d-1) + 1;
|
||||
}
|
||||
Reference in New Issue
Block a user