On Sat, May 16, 2009 at 20:41 +0000, Michael Shalayeff wrote:
> re
> suddenly bugs started to popup (:
looks like i hit this bug also.
ntpd[7676]: Lost child: child terminated; signal 8 (Floating point exception)
> there was a division by zero in poll scaling.
> i guess the offset never been small enough (:
> i would really appreciate if somebody actually
> read through the diff for possibly more tiny little
> stupid mistakes that might've crept in (:
> cu
>
> On Fri, May 15, 2009 at 04:13:29PM +0000, Michael Shalayeff wrote:
> > re
> > we've found a real bug behind the buffer sizes.
> > dns resolver was not limiting the response (ip list)
> > to any maximum number which is even defined already
> > as MAX_SERVERS_DNS. thus check that now.
> > now we can get away w/ much smaller buffers and
> > correct (non-overflowing) behaviour (;
> > cu
> >
> > On Fri, May 15, 2009 at 03:19:02PM +0000, Michael Shalayeff wrote:
> > > re
> > > first try out of the zoo shown that we need to keep MAX_IMSGSIZE
> > > at 8k for more dns addresses (:
> > > diff updated
> > > cu
> > >
> > > On Fri, May 15, 2009 at 02:58:36PM +0000, Michael Shalayeff wrote:
> > > > re
> > > > forgot to mention that while there touching structs
> > > > also rearrange fields for optimal alignment (save memory)
> > > > and shrink io buffers to a half K from 8k since we will
> > > > never have a valid packet larger than that.
> > > > cu
> > > >
> > > > On Fri, May 15, 2009 at 02:39:29PM +0000, Michael Shalayeff wrote:
> > > > > re
> > > > > using floating point for ntpd math is not a good idea.
> > > > > this comes from the fact that mixing small and large numbers
> > > > > in one fp expression leads to a huge loss of precision.
> > > > > besides the fact that there is no need to change representation
> > > > > from fixed point (ntp timestamps) to floating point and
> > > > > back all the time. plus to that using fpu in daemons is
> > > > > not polite and eats even more cpu time (:
> > > > >
> > > > > this diff converts internal math to fixed point (64bit)
> > > > > except for one place -- local clock frequency drift.
> > > > > this part is still broken as one can see by constantly
> > > > > flipping frequency adjucements in the logs since math
> > > > > currently used performs computation on very large
> > > > > numbers (products of time stamps) and very small
> > > > > ones (products of time offsets) and thus totally useless.
> > > > > i have figured a better way to follow frequency drift
> > > > > but that can be done in the next step.
> > > > >
> > > > > this has ran on both i386 and sparc64 for months now
> > > > > and only has shown massive improvement in precision
> > > > > (decrease of deviation). thus local clock offset still
> > > > > flips every few hours from positive to negative and back
> > > > > due to broken frequency adjucements.
> > > > >
> > > > > please read and try.
>
> Index: Makefile
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/Makefile,v
> retrieving revision 1.2
> diff -u -p -r1.2 Makefile
> --- Makefile 13 May 2009 18:10:04 -0000 1.2
> +++ Makefile 16 May 2009 19:04:47 -0000
> @@ -3,7 +3,7 @@
>
> PROG= ntpd
> SRCS= ntpd.c buffer.c log.c imsg.c ntp.c ntp_msg.c ntp_dns.c \
> - parse.y config.c server.c client.c sensors.c util.c
> + parse.y config.c server.c client.c sensors.c
> CFLAGS+= -Wall -I${.CURDIR}
> CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
> CFLAGS+= -Wmissing-declarations
> Index: client.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/client.c,v
> retrieving revision 1.4
> diff -u -p -r1.4 client.c
> --- client.c 15 May 2009 11:40:42 -0000 1.4
> +++ client.c 16 May 2009 19:04:47 -0000
> @@ -195,19 +195,21 @@ client_query(struct ntp_peer *p)
> int
> client_dispatch(struct ntp_peer *p, u_int8_t settime)
> {
> - struct ntp_msg msg;
> - struct msghdr somsg;
> - struct iovec iov[1];
> - struct timeval tv1;
> - char buf[NTP_MSGSIZE];
> + extern int debug; /* from log.c */
> + struct ntp_msg msg;
> + struct msghdr somsg;
> + struct iovec iov[1];
> + struct timeval tv1, tv2;
> + char buf[NTP_MSGSIZE];
> union {
> struct cmsghdr hdr;
> char buf[CMSG_SPACE(sizeof tv1)];
> } cmsgbuf;
> - struct cmsghdr *cmsg;
> - ssize_t size;
> - double T1, T2, T3, T4;
> - time_t interval;
> + int64_t T1, T2, T3, T4;
> + struct cmsghdr *cmsg;
> + struct ntp_offset *reply;
> + ssize_t size;
> + time_t interval;
>
> somsg.msg_name = NULL;
> somsg.msg_namelen = 0;
> @@ -219,7 +221,7 @@ client_dispatch(struct ntp_peer *p, u_in
> somsg.msg_controllen = sizeof cmsgbuf.buf;
> somsg.msg_flags = 0;
>
> - T4 = getoffset();
> + getoffset(&tv2);
> if ((size = recvmsg(p->query->fd, &somsg, 0)) < 0) {
> if (errno == EHOSTUNREACH || errno == EHOSTDOWN ||
> errno == ENETUNREACH || errno == ENETDOWN ||
> @@ -243,17 +245,20 @@ client_dispatch(struct ntp_peer *p, u_in
> return (0);
> }
>
> + T4 = 0;
> for (cmsg = CMSG_FIRSTHDR(&somsg); cmsg != NULL;
> cmsg = CMSG_NXTHDR(&somsg, cmsg)) {
> if (cmsg->cmsg_level == SOL_SOCKET &&
> cmsg->cmsg_type == SCM_TIMESTAMP) {
> memcpy(&tv1, CMSG_DATA(cmsg), sizeof tv1);
> - T4 += tv1.tv_sec + JAN_1970 + 1.0e-6 * tv1.tv_usec;
> + T4 = timeval2int64(&tv1);
> + T4 += (int64_t)JAN_1970 << 31;
> + T4 += timeval2int64(&tv2);
> break;
> }
> }
>
> - if (T4 < JAN_1970) {
> + if (T4 == 0) {
> client_log_error(p, "recvmsg control format", EBADF);
> set_next(p, error_interval());
> return (0);
> @@ -301,8 +306,8 @@ client_dispatch(struct ntp_peer *p, u_in
> */
>
> T1 = p->query->xmttime;
> - T2 = lfp_to_d(msg.rectime);
> - T3 = lfp_to_d(msg.xmttime);
> + T2 = lfxt2int64(&msg.rectime);
> + T3 = lfxt2int64(&msg.xmttime);
>
> /*
> * XXX workaround: time_t / tv_sec must never wrap.
> @@ -314,32 +319,51 @@ client_dispatch(struct ntp_peer *p, u_in
> return (0);
> }
>
> - p->reply[p->shift].offset = ((T2 - T1) + (T3 - T4)) / 2;
> - p->reply[p->shift].delay = (T4 - T1) - (T3 - T2);
> - if (p->reply[p->shift].delay < 0) {
> + if (T4 <= T1) {
> interval = error_interval();
> set_next(p, interval);
> - log_info("reply from %s: negative delay %fs, "
> + log_info("local clock is not monotonic");
> + return (0);
> + }
> +
> + reply = &p->reply[p->shift];
> +
> + reply->offset = ((T2 - T1) + (T3 - T4)) / 2;
> + reply->delay = (T4 - T1) - (T3 - T2);
> + if (reply->delay < 0) {
> + char *s = "";
> + int64_t val = reply->delay;
> + if (val < 0) {
> + s = "-";
> + val = -val;
> + }
> + int642timeval(val, &tv2);
> + interval = error_interval();
> + set_next(p, interval);
> + log_info("reply from %s: negative delay %s%ld.%06lus "
> "next query %ds",
> log_sockaddr((struct sockaddr *)&p->addr->ss),
> - p->reply[p->shift].delay, interval);
> + s, tv2.tv_sec, tv2.tv_usec, interval);
> return (0);
> }
> - p->reply[p->shift].error = (T2 - T1) - (T3 - T4);
> - p->reply[p->shift].rcvd = getmonotime();
> - p->reply[p->shift].good = 1;
> -
> - p->reply[p->shift].status.leap = (msg.status & LIMASK);
> - p->reply[p->shift].status.precision = msg.precision;
> - p->reply[p->shift].status.rootdelay = sfp_to_d(msg.rootdelay);
> - p->reply[p->shift].status.rootdispersion = sfp_to_d(msg.dispersion);
> - p->reply[p->shift].status.refid = msg.refid;
> - p->reply[p->shift].status.reftime = lfp_to_d(msg.reftime);
> - p->reply[p->shift].status.poll = msg.ppoll;
> - p->reply[p->shift].status.stratum = msg.stratum;
> +
> + p->shift = (p->shift + 1) % OFFSET_ARRAY_SIZE;
> +
> + reply->error = (T2 - T1) - (T3 - T4);
> + reply->rcvd = getmonotime();
> + reply->good = 1;
> +
> + reply->status.leap = msg.status & LIMASK;
> + reply->status.precision = msg.precision;
> + reply->status.refid = ntohl(msg.refid);
> + reply->status.poll = msg.ppoll;
> + reply->status.stratum = msg.stratum;
> + reply->status.rootdelay = sfxt2int64(&msg.rootdelay);
> + reply->status.rootdispersion = sfxt2int64(&msg.dispersion);
> + reply->status.reftime = lfxt2int64(&msg.reftime);
>
> if (p->addr->ss.ss_family == AF_INET) {
> - p->reply[p->shift].status.send_refid =
> + reply->status.send_refid =
> ((struct sockaddr_in *)&p->addr->ss)->sin_addr.s_addr;
> } else if (p->addr->ss.ss_family == AF_INET6) {
> MD5_CTX context;
> @@ -349,10 +373,10 @@ client_dispatch(struct ntp_peer *p, u_in
> MD5Update(&context, ((struct sockaddr_in6 *)&p->addr->ss)->
> sin6_addr.s6_addr, sizeof(struct in6_addr));
> MD5Final(digest, &context);
> - memcpy((char *)&p->reply[p->shift].status.send_refid, digest,
> + memcpy((char *)&reply->status.send_refid, digest,
> sizeof(u_int32_t));
> } else
> - p->reply[p->shift].status.send_refid = msg.xmttime.fractionl;
> + reply->status.send_refid = msg.xmttime.fractionl;
>
> if (p->trustlevel < TRUSTLEVEL_PATHETIC)
> interval = scale_interval(INTERVAL_QUERY_PATHETIC);
> @@ -373,16 +397,25 @@ client_dispatch(struct ntp_peer *p, u_in
> p->trustlevel++;
> }
>
> - log_debug("reply from %s: offset %f delay %f, "
> - "next query %ds", log_sockaddr((struct sockaddr *)&p->addr->ss),
> - p->reply[p->shift].offset, p->reply[p->shift].delay, interval);
> + if (debug) {
> + char *s = "";
> + int64_t val = reply->offset;
> + if (val < 0) {
> + s = "-";
> + val = -val;
> + }
> + int642timeval(val, &tv1);
> + int642timeval(reply->delay, &tv2);
> + log_debug("reply from %s: "
> + "offset %s%ld.%06lus delay %ld.%06lus, next query %ds",
> + log_sockaddr((struct sockaddr *)&p->addr->ss),
> + s, tv1.tv_sec, tv1.tv_usec, tv2.tv_sec, tv2.tv_usec,
> + interval);
> + }
>
> client_update(p);
> if (settime)
> - priv_settime(p->reply[p->shift].offset);
> -
> - if (++p->shift >= OFFSET_ARRAY_SIZE)
> - p->shift = 0;
> + priv_settime(reply->offset);
>
> return (0);
> }
> @@ -390,7 +423,8 @@ client_dispatch(struct ntp_peer *p, u_in
> int
> client_update(struct ntp_peer *p)
> {
> - int i, best = 0, good = 0;
> + struct ntp_offset *reply, *best, *last;
> + int good;
>
> /*
> * clock filter
> @@ -399,28 +433,26 @@ client_update(struct ntp_peer *p)
> * invalidate it and all older ones
> */
>
> - for (i = 0; good == 0 && i < OFFSET_ARRAY_SIZE; i++)
> - if (p->reply[i].good) {
> - good++;
> - best = i;
> - }
> -
> - for (; i < OFFSET_ARRAY_SIZE; i++)
> - if (p->reply[i].good) {
> - good++;
> - if (p->reply[i].delay < p->reply[best].delay)
> - best = i;
> - }
> + for (good = 0, best = NULL, reply = &p->reply[0],
> + last = &p->reply[OFFSET_ARRAY_SIZE]; reply < last; reply++) {
> + if (!reply->good)
> + continue;
> + good++;
> + if (!best)
> + best = reply;
> + if (reply->delay < best->delay)
> + best = reply;
> + }
>
> - if (good < 8)
> + if (good < OFFSET_ARRAY_SIZE)
> return (-1);
>
> - memcpy(&p->update, &p->reply[best], sizeof(p->update));
> - if (priv_adjtime() == 0) {
> - for (i = 0; i < OFFSET_ARRAY_SIZE; i++)
> - if (p->reply[i].rcvd <= p->reply[best].rcvd)
> - p->reply[i].good = 0;
> - }
> + memcpy(&p->update, best, sizeof(p->update));
> + if (priv_adjtime() == 0)
> + for (reply = &p->reply[0], last = &p->reply[OFFSET_ARRAY_SIZE];
> + reply < last; reply++)
> + if (reply->rcvd <= best->rcvd)
> + reply->good = 0;
> return (0);
> }
>
> Index: ntp.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/ntp.c,v
> retrieving revision 1.3
> diff -u -p -r1.3 ntp.c
> --- ntp.c 13 May 2009 18:10:04 -0000 1.3
> +++ ntp.c 16 May 2009 19:04:48 -0000
> @@ -1,4 +1,3 @@
> -
> /*
> * Copyright (c) 2003, 2004 Henning Brauer <[email protected]>
> * Copyright (c) 2004 Alexander Guy <[email protected]>
> @@ -168,7 +167,7 @@ ntp_main(int pipe_prnt[2], struct ntpd_c
> conf->freq.xx = 0.0;
> conf->freq.xy = 0.0;
> conf->freq.y = 0.0;
> - conf->freq.overall_offset = 0.0;
> + conf->freq.overall_offset = 0;
>
> conf->status.synced = 0;
> clock_getres(CLOCK_REALTIME, &tp);
> @@ -522,9 +521,10 @@ peer_remove(struct ntp_peer *p)
> }
>
> static void
> -priv_adjfreq(double offset)
> +priv_adjfreq(int64_t offset)
> {
> - double curtime, freq;
> + double curtime, freq, doff;
> + int64_t relfreq;
>
> if (!conf->status.synced)
> return;
> @@ -535,12 +535,12 @@ priv_adjfreq(double offset)
> return;
>
> conf->freq.overall_offset += offset;
> - offset = conf->freq.overall_offset;
>
> curtime = gettime_corrected();
> - conf->freq.xy += offset * curtime;
> + doff = conf->freq.overall_offset;
> + conf->freq.xy += doff * curtime;
> conf->freq.x += curtime;
> - conf->freq.y += offset;
> + conf->freq.y += doff;
> conf->freq.xx += curtime * curtime;
>
> if (conf->freq.samples % FREQUENCY_SAMPLES != 0)
> @@ -556,13 +556,14 @@ priv_adjfreq(double offset)
> else if (freq < -MAX_FREQUENCY_ADJUST)
> freq = -MAX_FREQUENCY_ADJUST;
>
> - imsg_compose(ibuf_main, IMSG_ADJFREQ, 0, 0, &freq, sizeof(freq));
> + relfreq = freq * 1e9 * (1LL << 32);
> + imsg_compose(ibuf_main, IMSG_ADJFREQ, 0, 0, &relfreq, sizeof(relfreq));
> conf->freq.xy = 0.0;
> conf->freq.x = 0.0;
> conf->freq.y = 0.0;
> conf->freq.xx = 0.0;
> conf->freq.samples = 0;
> - conf->freq.overall_offset = 0.0;
> + conf->freq.overall_offset = 0;
> conf->freq.num++;
> }
>
> @@ -573,7 +574,7 @@ priv_adjtime(void)
> struct ntp_sensor *s;
> int offset_cnt = 0, i = 0, j;
> struct ntp_offset **offsets;
> - double offset_median;
> + int64_t offset_median;
>
> TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
> if (p->trustlevel < TRUSTLEVEL_BADPEER)
> @@ -626,8 +627,8 @@ priv_adjtime(void)
> }
> conf->status.leap = offsets[i]->status.leap;
>
> - imsg_compose(ibuf_main, IMSG_ADJTIME, 0, 0,
> - &offset_median, sizeof(offset_median));
> + imsg_compose(ibuf_main, IMSG_ADJTIME, 0, 0, &offset_median,
> + sizeof(offset_median));
>
> priv_adjfreq(offset_median);
>
> @@ -671,9 +672,12 @@ offset_compare(const void *aa, const voi
> }
>
> void
> -priv_settime(double offset)
> +priv_settime(int64_t offset)
> {
> - imsg_compose(ibuf_main, IMSG_SETTIME, 0, 0, &offset, sizeof(offset));
> + struct timeval tv;
> +
> + int642timeval(offset, &tv);
> + imsg_compose(ibuf_main, IMSG_SETTIME, 0, 0, &tv, sizeof(tv));
> conf->settime = 0;
> }
>
> @@ -687,19 +691,24 @@ priv_host_dns(char *name, u_int32_t peer
> }
>
> void
> -update_scale(double offset)
> +update_scale(int64_t offset)
> {
> - offset += getoffset();
> + struct timeval tv;
> + int64_t qsmax, qsmin;
> +
> + getoffset(&tv);
> + offset += timeval2int64(&tv);
> if (offset < 0)
> - offset = -offset;
> + offset = (-offset);
>
> - if (offset > QSCALE_OFF_MAX || !conf->status.synced ||
> - conf->freq.num < 3)
> + qsmax = int64init(QSCALE_OFF_MAX / 1000000, QSCALE_OFF_MAX % 1000000);
> + qsmin = int64init(QSCALE_OFF_MIN / 1000000, QSCALE_OFF_MIN % 1000000);
> + if (offset > qsmax || !conf->status.synced || conf->freq.num < 3)
> conf->scale = 1;
> - else if (offset < QSCALE_OFF_MIN)
> - conf->scale = QSCALE_OFF_MAX / QSCALE_OFF_MIN;
> + else if (offset < qsmin)
> + conf->scale = qsmax / QSCALE_OFF_MIN;
> else
> - conf->scale = QSCALE_OFF_MAX / offset;
> + conf->scale = qsmax / offset;
> }
>
> time_t
> @@ -776,4 +785,41 @@ report_peers(int always)
> log_warnx("bad sensor %s", s->device);
> }
> }
> +}
> +
> +int64_t
> +gettime_corrected()
> +{
> + struct timeval tv;
> + getoffset(&tv);
> + return gettime() + timeval2int64(&tv);
> +}
> +
> +void
> +getoffset(struct timeval *tv)
> +{
> + if (adjtime(NULL, tv) == -1)
> + memset(tv, 0, sizeof(*tv));
> +}
> +
> +int64_t
> +gettime()
> +{
> + struct timeval tv;
> +
> + if (gettimeofday(&tv, NULL) == -1)
> + fatal("gettimeofday");
> +
> + return timeval2int64(&tv) + ((int64_t)JAN_1970 << 31);
> +}
> +
> +time_t
> +getmonotime(void)
> +{
> + struct timespec ts;
> +
> + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
> + fatal("clock_gettime");
> +
> + return (ts.tv_sec);
> }
> Index: ntp.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/ntp.h,v
> retrieving revision 1.2
> diff -u -p -r1.2 ntp.h
> --- ntp.h 13 May 2009 18:10:04 -0000 1.2
> +++ ntp.h 16 May 2009 19:04:48 -0000
> @@ -43,11 +43,41 @@ struct l_fixedpt {
> u_int32_t fractionl;
> };
>
> + /* 2147 = 2^31 / 1000000 */
> +#define timeval2int64(tv) \
> + (((int64_t)(tv)->tv_sec << 31) + (2147U * (tv)->tv_usec))
> +
> +#define int64init(s,u) (((int64_t)(s) << 31) + (2147U * (u)))
> +
> +#define int642timeval(i,tv) do { \
> + (tv)->tv_sec = (i) >> 31; \
> + (tv)->tv_usec = ((i) & 0x7fffffff) / 2148; \
> +} while (0)
> +
> +#define lfxt2int64(lf) \
> + (((int64_t)ntohl((lf)->int_partl) << 31) + (ntohl((lf)->fractionl) >> 1))
> +
> +#define int642lfxt(i,lf) do { \
> + (lf)->int_partl = htonl((i) >> 31); \
> + (lf)->fractionl = htonl((i) << 1); \
> +} while (0)
> +
> +#define us2int64(us) (2147ULL * (us))
> +
> struct s_fixedpt {
> u_int16_t int_parts;
> u_int16_t fractions;
> };
>
> +#define int642sfxt(i,lf) do { \
> + (lf)->int_parts = htons((i) >> 31); \
> + (lf)->fractions = htons((i & 0x7fffffff) >> 15); \
> +} while (0)
> +
> +#define sfxt2int64(lf) \
> + (((int64_t)ntohs((lf)->int_parts) << 31) + \
> + ((u_int)ntohs((lf)->fractions) << 15))
> +
> /* RFC Section 4
> *
> * 0 1 2 3
> @@ -107,9 +137,9 @@ struct ntp_msg {
> } __packed;
>
> struct ntp_query {
> - int fd;
> - struct ntp_msg msg;
> - double xmttime;
> + struct ntp_msg msg;
> + int64_t xmttime;
> + int fd;
> };
>
> /*
> @@ -139,8 +169,8 @@ struct ntp_query {
> #define MODE_RES1 6 /* reserved for NTP control message */
> #define MODE_RES2 7 /* reserved for private use */
>
> -#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
> -#define JAN_2030 1893456000UL + JAN_1970 /* 1. 1. 2030 00:00:00
> */
> +#define JAN_1970 2208988800LL /* 1970 - 1900 in seconds */
> +#define JAN_2030 ((JAN_1970 + 1893456000LL) << 31) /* 1. 1. 2030
> 00:00:00 */
>
> #define NTP_VERSION 4
> #define NTP_MAXSTRATUM 15
> Index: ntp_dns.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/ntp_dns.c,v
> retrieving revision 1.2
> diff -u -p -r1.2 ntp_dns.c
> --- ntp_dns.c 14 May 2009 12:23:33 -0000 1.2
> +++ ntp_dns.c 16 May 2009 19:04:48 -0000
> @@ -147,14 +147,15 @@ dns_dispatch_imsg(void)
> fatalx("invalid IMSG_HOST_DNS received");
> if ((cnt = host_dns(name, &hn, conf)) == -1)
> break;
> + if (cnt > MAX_SERVERS_DNS)
> + cnt = MAX_SERVERS_DNS;
> buf = imsg_create(ibuf_dns, IMSG_HOST_DNS,
> imsg.hdr.peerid, 0,
> cnt * sizeof(struct sockaddr_storage));
> if (buf == NULL)
> break;
> - if (cnt > 0)
> - for (h = hn; h != NULL; h = h->next)
> - imsg_add(buf, &h->ss, sizeof(h->ss));
> + for (h = hn; cnt-- && h != NULL; h = h->next)
> + imsg_add(buf, &h->ss, sizeof(h->ss));
>
> imsg_close(ibuf_dns, buf);
> break;
> Index: ntpd.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/ntpd.c,v
> retrieving revision 1.4
> diff -u -p -r1.4 ntpd.c
> --- ntpd.c 14 May 2009 12:23:33 -0000 1.4
> +++ ntpd.c 16 May 2009 19:04:48 -0000
> @@ -38,11 +38,11 @@ int main(int, char *[]);
> int check_child(pid_t, const char *);
> int dispatch_imsg(struct ntpd_conf *);
> void reset_adjtime(void);
> -int ntpd_adjtime(double);
> -void ntpd_adjfreq(double, int);
> -void ntpd_settime(double);
> +int ntpd_adjtime(int64_t);
> +void ntpd_adjfreq(int64_t, int);
> +void ntpd_settime(struct timeval *);
> void readfreq(void);
> -int writefreq(double);
> +int writefreq(int64_t);
>
> volatile sig_atomic_t quit = 0;
> volatile sig_atomic_t reconfig = 0;
> @@ -271,10 +271,11 @@ dispatch_imsg(struct ntpd_conf *lconf)
> {
> struct imsg imsg;
> int n, cnt;
> - double d;
> + struct timeval tv;
> char *name;
> struct ntp_addr *h, *hn;
> struct buf *buf;
> + int64_t d;
>
> if ((n = imsg_read(ibuf)) == -1)
> return (-1);
> @@ -306,13 +307,13 @@ dispatch_imsg(struct ntpd_conf *lconf)
> ntpd_adjfreq(d, 1);
> break;
> case IMSG_SETTIME:
> - if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d))
> + if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(tv))
> fatalx("invalid IMSG_SETTIME received");
> if (!lconf->settime)
> break;
> log_init(lconf->debug);
> - memcpy(&d, imsg.data, sizeof(d));
> - ntpd_settime(d);
> + memcpy(&tv, imsg.data, sizeof(tv));
> + ntpd_settime(&tv);
> /* daemonize now */
> if (!lconf->debug)
> if (daemon(1, 0))
> @@ -361,19 +362,30 @@ reset_adjtime(void)
> }
>
> int
> -ntpd_adjtime(double d)
> +ntpd_adjtime(int64_t d)
> {
> - struct timeval tv, olddelta;
> - int synced = 0;
> static int firstadj = 1;
> + struct timeval tv, tv1, olddelta;
> + char *s = "";
> + int synced = 0;
>
> - d += getoffset();
> - if (d >= (double)LOG_NEGLIGIBLE_ADJTIME / 1000 ||
> - d <= -1 * (double)LOG_NEGLIGIBLE_ADJTIME / 1000)
> - log_info("adjusting local clock by %fs", d);
> + getoffset(&olddelta);
> + int642timeval(d, &tv);
> + timeradd(&tv, &olddelta, &tv);
> +
> + if (d < 0) {
> + s = "-";
> + d = -d;
> + }
> +
> + int642timeval(d, &tv1);
> + if (tv1.tv_sec || tv1.tv_usec >= LOG_NEGLIGEE * 1000)
> + log_info("adjusting local clock by %s%ld.%06lus",
> + s, tv1.tv_sec, tv1.tv_usec);
> else
> - log_debug("adjusting local clock by %fs", d);
> - d_to_tv(d, &tv);
> + log_debug("adjusting local clock by %s%ld.%06lus",
> + s, tv1.tv_sec, tv1.tv_usec);
> +
> if (adjtime(&tv, &olddelta) == -1)
> log_warn("adjtime failed");
> else if (!firstadj && olddelta.tv_sec == 0 && olddelta.tv_usec == 0)
> @@ -383,44 +395,48 @@ ntpd_adjtime(double d)
> }
>
> void
> -ntpd_adjfreq(double relfreq, int wrlog)
> +ntpd_adjfreq(int64_t relfreq, int wrlog)
> {
> int64_t curfreq;
> - double ppmfreq;
> int r;
>
> if (adjfreq(NULL, &curfreq) == -1) {
> log_warn("adjfreq failed");
> return;
> }
> + curfreq += relfreq;
> + if (adjfreq(&curfreq, NULL) == -1)
> + log_warn("adjfreq failed");
>
> /*
> - * adjfreq's unit is ns/s shifted left 32; convert relfreq to
> - * that unit before adding. We log values in part per million.
> + * adjfreq's unit is ns/s shifted left 32.
> + * We log values in part per million.
> */
> - curfreq += relfreq * 1e9 * (1LL << 32);
> - r = writefreq(curfreq / 1e9 / (1LL << 32));
> - ppmfreq = relfreq * 1e6;
> + r = writefreq(curfreq);
> if (wrlog) {
> - if (ppmfreq >= LOG_NEGLIGIBLE_ADJFREQ ||
> - ppmfreq <= -LOG_NEGLIGIBLE_ADJFREQ)
> - log_info("adjusting clock frequency by %f to %fppm%s",
> - ppmfreq, curfreq / 1e3 / (1LL << 32),
> - r ? "" : " (no drift file)");
> - else
> - log_debug("adjusting clock frequency by %f to %fppm%s",
> - ppmfreq, curfreq / 1e3 / (1LL << 32),
> - r ? "" : " (no drift file)");
> - }
> + char *s1 = "", *s2 = "";
>
> - if (adjfreq(&curfreq, NULL) == -1)
> - log_warn("adjfreq failed");
> + if (relfreq < 0) {
> + relfreq = -relfreq;
> + s1 = "-";
> + }
> + if (curfreq < 0) {
> + curfreq = -curfreq;
> + s2 = "-";
> + }
> + log_info("adjusting clock frequency by %s0.%06d to "
> + "%s%d.%06dppm%s",
> + s1, (int)(relfreq >> 32) % 1000000,
> + s2, (int)(curfreq >> 32) / 1000000,
> + (int)(curfreq >> 32) % 1000000,
> + r ? " (no drift file)" : "");
> + }
> }
>
> void
> -ntpd_settime(double d)
> +ntpd_settime(struct timeval *tv)
> {
> - struct timeval tv, curtime;
> + struct timeval curtime;
> char buf[80];
> time_t tval;
>
> @@ -428,9 +444,8 @@ ntpd_settime(double d)
> log_warn("gettimeofday");
> return;
> }
> - d_to_tv(d, &tv);
> - curtime.tv_usec += tv.tv_usec + 1000000;
> - curtime.tv_sec += tv.tv_sec - 1 + (curtime.tv_usec / 1000000);
> + curtime.tv_usec += tv->tv_usec + 1000000;
> + curtime.tv_sec += tv->tv_sec - 1 + (curtime.tv_usec / 1000000);
> curtime.tv_usec %= 1000000;
>
> if (settimeofday(&curtime, NULL) == -1) {
> @@ -440,15 +455,15 @@ ntpd_settime(double d)
> tval = curtime.tv_sec;
> strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y",
> localtime(&tval));
> - log_info("set local clock to %s (offset %fs)", buf, d);
> + log_info("set local clock to %s (offset %ld.%06lus)", buf,
> + tv->tv_sec, tv->tv_usec);
> }
>
> void
> readfreq(void)
> {
> + int64_t current, d;
> FILE *fp;
> - int64_t current;
> - double d;
>
> fp = fopen(DRIFTFILE, "r");
> if (fp == NULL) {
> @@ -463,7 +478,7 @@ readfreq(void)
> if (adjfreq(NULL, ¤t) == -1)
> log_warn("adjfreq failed");
> else if (current == 0) {
> - if (fscanf(fp, "%le", &d) == 1)
> + if (fscanf(fp, "%lld", &d) == 1)
> ntpd_adjfreq(d, 0);
> else
> log_warnx("can't read %s", DRIFTFILE);
> @@ -472,7 +487,7 @@ readfreq(void)
> }
>
> int
> -writefreq(double d)
> +writefreq(int64_t d)
> {
> int r;
> FILE *fp;
> @@ -484,10 +499,10 @@ writefreq(double d)
> log_warn("can't open %s", DRIFTFILE);
> warnonce = 0;
> }
> - return 0;
> + return -1;
> }
>
> - fprintf(fp, "%e\n", d);
> + fprintf(fp, "%lld\n", d);
> r = ferror(fp);
> if (fclose(fp) != 0 || r != 0) {
> if (warnonce) {
> @@ -495,7 +510,7 @@ writefreq(double d)
> warnonce = 0;
> }
> unlink(DRIFTFILE);
> - return 0;
> + return -1;
> }
> - return 1;
> + return 0;
> }
> Index: ntpd.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/ntpd.h,v
> retrieving revision 1.4
> diff -u -p -r1.4 ntpd.h
> --- ntpd.h 14 May 2009 12:23:33 -0000 1.4
> +++ ntpd.h 16 May 2009 19:04:48 -0000
> @@ -34,7 +34,7 @@
> #define CONFFILE "/etc/ntpd.conf"
> #define DRIFTFILE "/var/db/ntpd.drift"
>
> -#define READ_BUF_SIZE 8192
> +#define READ_BUF_SIZE (256 * 10)
>
> #define INTERVAL_QUERY_NORMAL 30 /* sync to peers every
> n secs */
> #define INTERVAL_QUERY_PATHETIC 60
> @@ -47,15 +47,14 @@
>
> #define MAX_SERVERS_DNS 8
>
> -#define QSCALE_OFF_MIN 0.001
> -#define QSCALE_OFF_MAX 0.050
> +#define QSCALE_OFF_MIN 10000 /* us */
> +#define QSCALE_OFF_MAX 500000 /* us */
>
> #define QUERYTIME_MAX 15 /* single query might take n
> secs max */
> #define OFFSET_ARRAY_SIZE 8
> #define SENSOR_OFFSETS 7
> #define SETTIME_TIMEOUT 15 /* max seconds to wait with -s
> */
> -#define LOG_NEGLIGIBLE_ADJTIME 32 /* negligible drift to not log
> (ms) */
> -#define LOG_NEGLIGIBLE_ADJFREQ 0.05 /* negligible rate to not log
> (ppm) */
> +#define LOG_NEGLIGEE 32 /* negligible drift to not log
> (ms) */
> #define FREQUENCY_SAMPLES 8 /* samples for est. of
> permanent drift */
> #define MAX_FREQUENCY_ADJUST 128e-5 /* max correction per iteration
> */
> #define REPORT_INTERVAL (24*60*60) /* interval between status
> reports */
> @@ -94,9 +93,9 @@ struct ntp_addr_wrap {
> };
>
> struct ntp_status {
> - double rootdelay;
> - double rootdispersion;
> - double reftime;
> + int64_t rootdelay;
> + int64_t rootdispersion;
> + int64_t reftime;
> u_int32_t refid;
> u_int32_t send_refid;
> u_int8_t synced;
> @@ -108,9 +107,9 @@ struct ntp_status {
>
> struct ntp_offset {
> struct ntp_status status;
> - double offset;
> - double delay;
> - double error;
> + int64_t offset;
> + int64_t delay;
> + int64_t error;
> time_t rcvd;
> u_int8_t good;
> };
> @@ -126,56 +125,56 @@ struct ntp_peer {
> time_t next;
> time_t deadline;
> u_int32_t id;
> + int lasterror;
> + int senderrors;
> u_int8_t shift;
> u_int8_t trustlevel;
> u_int8_t weight;
> - int lasterror;
> - int senderrors;
> };
>
> struct ntp_sensor {
> TAILQ_ENTRY(ntp_sensor) entry;
> struct ntp_offset offsets[SENSOR_OFFSETS];
> struct ntp_offset update;
> + int64_t correction;
> time_t next;
> time_t last;
> char *device;
> u_int32_t refid;
> int sensordevid;
> - int correction;
> u_int8_t weight;
> u_int8_t shift;
> };
>
> struct ntp_conf_sensor {
> - TAILQ_ENTRY(ntp_conf_sensor) entry;
> - char *device;
> - char *refstr;
> - int correction;
> - u_int8_t weight;
> + TAILQ_ENTRY(ntp_conf_sensor) entry;
> + char *device;
> + char *refstr;
> + int correction;
> + u_int8_t weight;
> };
>
> struct ntp_freq {
> - double overall_offset;
> - double x, y;
> - double xx, xy;
> - int samples;
> - u_int num;
> + double x, y;
> + double xx, xy;
> + int64_t overall_offset;
> + int samples;
> + u_int num;
> };
>
> struct ntpd_conf {
> - TAILQ_HEAD(listen_addrs, listen_addr) listen_addrs;
> - TAILQ_HEAD(ntp_peers, ntp_peer) ntp_peers;
> - TAILQ_HEAD(ntp_sensors, ntp_sensor) ntp_sensors;
> - TAILQ_HEAD(ntp_conf_sensors, ntp_conf_sensor) ntp_conf_sensors;
> - struct ntp_status status;
> - struct ntp_freq freq;
> - u_int8_t listen_all;
> - u_int8_t settime;
> - u_int8_t debug;
> - u_int32_t scale;
> - u_int8_t noaction;
> - u_int8_t family;
> + TAILQ_HEAD(, listen_addr) listen_addrs;
> + TAILQ_HEAD(, ntp_peer) ntp_peers;
> + TAILQ_HEAD(, ntp_sensor) ntp_sensors;
> + TAILQ_HEAD(, ntp_conf_sensor) ntp_conf_sensors;
> + struct ntp_status status;
> + struct ntp_freq freq;
> + u_int32_t scale;
> + u_int8_t listen_all;
> + u_int8_t settime;
> + u_int8_t debug;
> + u_int8_t noaction;
> + u_int8_t family;
> };
>
> struct buf {
> @@ -201,7 +200,7 @@ struct buf_read {
> /* ipc messages */
>
> #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
> -#define MAX_IMSGSIZE 8192
> +#define MAX_IMSGSIZE (256 * 10)
>
> struct imsgbuf {
> int fd;
> @@ -264,14 +263,18 @@ int imsg_close(struct imsgbuf *, struct
> void imsg_free(struct imsg *);
>
> /* ntp.c */
> -pid_t ntp_main(int[2], struct ntpd_conf *, struct passwd *);
> -int priv_adjtime(void);
> -void priv_settime(double);
> -void priv_host_dns(char *, u_int32_t);
> -int offset_compare(const void *, const void *);
> -void update_scale(double);
> -time_t scale_interval(time_t);
> -time_t error_interval(void);
> +pid_t ntp_main(int[2], struct ntpd_conf *, struct passwd *);
> +int priv_adjtime(void);
> +void priv_settime(int64_t);
> +void priv_host_dns(char *, u_int32_t);
> +int offset_compare(const void *, const void *);
> +void update_scale(int64_t);
> +time_t scale_interval(time_t);
> +time_t error_interval(void);
> +int64_t gettime_corrected(void);
> +void getoffset(struct timeval *);
> +int64_t gettime(void);
> +time_t getmonotime(void);
> extern struct ntpd_conf *conf;
>
> /* parse.y */
> @@ -301,23 +304,12 @@ int client_dispatch(struct ntp_peer *, u
> void client_log_error(struct ntp_peer *, const char *, int);
> void set_next(struct ntp_peer *, time_t);
>
> -/* util.c */
> -double gettime_corrected(void);
> -double getoffset(void);
> -double gettime(void);
> -time_t getmonotime(void);
> -void d_to_tv(double, struct timeval *);
> -double lfp_to_d(struct l_fixedpt);
> -struct l_fixedpt d_to_lfp(double);
> -double sfp_to_d(struct s_fixedpt);
> -struct s_fixedpt d_to_sfp(double);
> -
> /* sensors.c */
> -void sensor_init(void);
> -int sensor_scan(void);
> -void sensor_query(struct ntp_sensor *);
> -int sensor_hotplugfd(void);
> -void sensor_hotplugevent(int);
> +void sensor_init(void);
> +int sensor_scan(void);
> +void sensor_query(struct ntp_sensor *);
> +int sensor_hotplugfd(void);
> +void sensor_hotplugevent(int);
>
> /* ntp_dns.c */
> pid_t ntp_dns(int[2], struct ntpd_conf *, struct passwd *);
> Index: sensors.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/sensors.c,v
> retrieving revision 1.3
> diff -u -p -r1.3 sensors.c
> --- sensors.c 13 May 2009 18:10:04 -0000 1.3
> +++ sensors.c 16 May 2009 19:04:48 -0000
> @@ -121,7 +121,7 @@ sensor_add(int sensordev, char *dxname)
>
> s->next = getmonotime();
> s->weight = cs->weight;
> - s->correction = cs->correction;
> + s->correction = us2int64(cs->correction);
> if ((s->device = strdup(dxname)) == NULL)
> fatal("sensor_add strdup");
> s->sensordevid = sensordev;
> @@ -135,8 +135,10 @@ sensor_add(int sensordev, char *dxname)
>
> TAILQ_INSERT_TAIL(&conf->ntp_sensors, s, entry);
>
> - log_debug("sensor %s added (weight %d, correction %.6f, refstr %.4s)",
> - s->device, s->weight, s->correction / 1e6, &s->refid);
> + log_debug(
> + "sensor %s added (weight %d, correction %d.%06u, refstr %-4s)",
> + s->device, s->weight,
> + cs->correction / 1000000, cs->correction % 1000000, &s->refid);
> }
>
> void
> @@ -152,6 +154,7 @@ sensor_query(struct ntp_sensor *s)
> {
> char dxname[MAXDEVNAMLEN];
> struct sensor sensor;
> + struct timeval tv;
>
> if (conf->settime)
> s->next = getmonotime() + SENSOR_QUERY_INTERVAL_SETTIME;
> @@ -186,16 +189,17 @@ sensor_query(struct ntp_sensor *s)
> * sensor.value = TS - TD in ns
> * if value is positive, system time is ahead
> */
> - s->offsets[s->shift].offset = (sensor.value / -1e9) - getoffset() +
> - (s->correction / 1e6);
> + getoffset(&tv);
> + s->offsets[s->shift].offset = s->correction +
> + us2int64(sensor.value / 1000) - timeval2int64(&tv);
> s->offsets[s->shift].rcvd = sensor.tv.tv_sec;
> s->offsets[s->shift].good = 1;
>
> s->offsets[s->shift].status.send_refid = s->refid;
> - s->offsets[s->shift].status.stratum = 0; /* increased when sent
> out */
> + s->offsets[s->shift].status.stratum = 0; /* increased when sent out */
> s->offsets[s->shift].status.rootdelay = 0;
> s->offsets[s->shift].status.rootdispersion = 0;
> - s->offsets[s->shift].status.reftime = sensor.tv.tv_sec;
> + s->offsets[s->shift].status.reftime = timeval2int64(&sensor.tv);
> s->offsets[s->shift].status.synced = 1;
>
> log_debug("sensor %s: offset %f", s->device,
> @@ -226,10 +230,9 @@ sensor_update(struct ntp_sensor *s)
>
> i = SENSOR_OFFSETS / 2;
> memcpy(&s->update, offsets[i], sizeof(s->update));
> - if (SENSOR_OFFSETS % 2 == 0) {
> + if (SENSOR_OFFSETS % 2 == 0)
> s->update.offset =
> (offsets[i - 1]->offset + offsets[i]->offset) / 2;
> - }
> free(offsets);
>
> log_debug("sensor update %s: offset %f", s->device, s->update.offset);
> Index: server.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/server.c,v
> retrieving revision 1.3
> diff -u -p -r1.3 server.c
> --- server.c 13 May 2009 18:10:04 -0000 1.3
> +++ server.c 16 May 2009 19:04:48 -0000
> @@ -127,11 +127,11 @@ server_dispatch(int fd, struct ntpd_conf
> {
> ssize_t size;
> u_int8_t version;
> - double rectime;
> struct sockaddr_storage fsa;
> socklen_t fsa_len;
> struct ntp_msg query, reply;
> char buf[NTP_MSGSIZE];
> + int64_t rectime;
>
> fsa_len = sizeof(fsa);
> if ((size = recvfrom(fd, &buf, sizeof(buf), 0,
> @@ -146,7 +146,6 @@ server_dispatch(int fd, struct ntpd_conf
> }
>
> rectime = gettime_corrected();
> -
> if (ntp_getmsg((struct sockaddr *)&fsa, buf, size, &query) == -1)
> return (0);
>
> @@ -163,15 +162,16 @@ server_dispatch(int fd, struct ntpd_conf
> else
> reply.status |= MODE_SYM_PAS;
>
> + reply.refid = lconf->status.refid;
> reply.stratum = lconf->status.stratum;
> reply.ppoll = query.ppoll;
> reply.precision = lconf->status.precision;
> - reply.rectime = d_to_lfp(rectime);
> - reply.reftime = d_to_lfp(lconf->status.reftime);
> - reply.xmttime = d_to_lfp(gettime_corrected());
> reply.orgtime = query.xmttime;
> - reply.rootdelay = d_to_sfp(lconf->status.rootdelay);
> - reply.refid = lconf->status.refid;
> + int642lfxt(rectime, &reply.rectime);
> + int642lfxt(lconf->status.reftime, &reply.reftime);
> + int642sfxt(lconf->status.rootdelay, &reply.rootdelay);
> + rectime = gettime_corrected();
> + int642lfxt(rectime, &reply.xmttime);
>
> ntp_sendmsg(fd, (struct sockaddr *)&fsa, &reply, size, 0);
> return (0);
> Index: util.c
> ===================================================================
> RCS file: util.c
> diff -N util.c
> --- util.c 26 Aug 2008 14:44:25 -0000 1.1.1.1
> +++ /dev/null 1 Jan 1970 00:00:00 -0000
> @@ -1,118 +0,0 @@
> -
> -/*
> - * Copyright (c) 2004 Alexander Guy <[email protected]>
> - *
> - * 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 MIND, 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.
> - */
> -
> -#include <sys/time.h>
> -#include <limits.h>
> -
> -#include "ntpd.h"
> -
> -double
> -gettime_corrected(void)
> -{
> - return (gettime() + getoffset());
> -}
> -
> -double
> -getoffset(void)
> -{
> - struct timeval tv;
> - if (adjtime(NULL, &tv) == -1)
> - return (0.0);
> - return (tv.tv_sec + 1.0e-6 * tv.tv_usec);
> -}
> -
> -double
> -gettime(void)
> -{
> - struct timeval tv;
> -
> - if (gettimeofday(&tv, NULL) == -1)
> - fatal("gettimeofday");
> -
> - return (tv.tv_sec + JAN_1970 + 1.0e-6 * tv.tv_usec);
> -}
> -
> -time_t
> -getmonotime(void)
> -{
> - struct timespec ts;
> -
> - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
> - fatal("clock_gettime");
> -
> - return (ts.tv_sec);
> -}
> -
> -
> -void
> -d_to_tv(double d, struct timeval *tv)
> -{
> - tv->tv_sec = (long)d;
> - tv->tv_usec = (d - tv->tv_sec) * 1000000;
> - while (tv->tv_usec < 0) {
> - tv->tv_usec += 1000000;
> - tv->tv_sec -= 1;
> - }
> -}
> -
> -double
> -lfp_to_d(struct l_fixedpt lfp)
> -{
> - double ret;
> -
> - lfp.int_partl = ntohl(lfp.int_partl);
> - lfp.fractionl = ntohl(lfp.fractionl);
> -
> - ret = (double)(lfp.int_partl) + ((double)lfp.fractionl / UINT_MAX);
> -
> - return (ret);
> -}
> -
> -struct l_fixedpt
> -d_to_lfp(double d)
> -{
> - struct l_fixedpt lfp;
> -
> - lfp.int_partl = htonl((u_int32_t)d);
> - lfp.fractionl = htonl((u_int32_t)((d - (u_int32_t)d) * UINT_MAX));
> -
> - return (lfp);
> -}
> -
> -double
> -sfp_to_d(struct s_fixedpt sfp)
> -{
> - double ret;
> -
> - sfp.int_parts = ntohs(sfp.int_parts);
> - sfp.fractions = ntohs(sfp.fractions);
> -
> - ret = (double)(sfp.int_parts) + ((double)sfp.fractions / USHRT_MAX);
> -
> - return (ret);
> -}
> -
> -struct s_fixedpt
> -d_to_sfp(double d)
> -{
> - struct s_fixedpt sfp;
> -
> - sfp.int_parts = htons((u_int16_t)d);
> - sfp.fractions = htons((u_int16_t)((d - (u_int16_t)d) * USHRT_MAX));
> -
> - return (sfp);
> -}