On Saturday 21 November 2009 18:26, Adam Tkac wrote:
> Hi all,
>
> I just finished the NTP client/server applet. Would it be possible to
> merge it to the main repository, please?
I did some changes - see the attached patch. Some
of these simplififications are quite obvious,
please do similar ones next time yourself.
I did a VERY limited testing and found one bug. Fix
(on top of attached):
- bb_signals(SIGTERM|SIGINT, record_signo);
- bb_signals(SIGPIPE|SIGHUP, SIG_IGN);
+ bb_signals((1 << SIGTERM) | (1 << SIGINT), record_signo);
+ bb_signals((1 << SIGPIPE) | (1 << SIGHUP), SIG_IGN);
I also changed the options to make them resemble upstream ntpd:
# ./busybox ntpd --help
BusyBox v1.16.0.git (2009-11-22 00:03:34 CET) multi-call binary.
Usage: ntpd [-dngl] [-p PEER]...
NTP client/server
Options:
-d Verbose
-n Do not daemonize
-g Set system time even if offset is > 1000 sec
-l Run as server on port 123
-p PEER Obtain time from PEER (may be repeated)
The applet definitely needs more testing.
Please git pull and do a few run tests. When you research
a problem, add
if (G.verbose > SOME_NUMBER)
bb_error_msg(...debug printout...);
so that in future other users may use -d[dddd] to get
the same info.
--
vda
diff -d -urpN busybox.1/networking/ntpd.c busybox.2/networking/ntpd.c
--- busybox.1/networking/ntpd.c 2009-11-22 02:44:21.000000000 +0100
+++ busybox.2/networking/ntpd.c 2009-11-22 02:45:12.000000000 +0100
@@ -159,14 +159,14 @@ typedef struct {
llist_t *ntp_peers;
ntp_status_t status;
uint8_t settime;
- uint8_t foreground;
uint32_t scale;
uint8_t firstadj;
smallint peer_cnt;
} ntpd_conf_t;
-static ntpd_conf_t *G;
-volatile sig_atomic_t quit = 0;
+static const int const_IPTOS_LOWDELAY = IPTOS_LOWDELAY;
+
+#define G (*ptr_to_globals)
static void
set_next(ntp_peer_t *p, time_t t)
@@ -178,50 +178,21 @@ set_next(ntp_peer_t *p, time_t t)
static void
add_peers(const char *s)
{
- struct addrinfo hints, *res0, *res;
- int error;
- ntp_peer_t *p;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = PF_UNSPEC;
- hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
- error = getaddrinfo(s, NULL, &hints, &res0);
- if (error)
- bb_error_msg_and_die("DNS resolution failed for "
- "peer %s", optarg);
-
- for (res = res0; res != NULL; res = res->ai_next) {
- if (res->ai_family != AF_INET
-#if ENABLE_FEATURE_IPV6
- && res->ai_family != AF_INET6
-#endif
- )
- continue;
-
- p = xzalloc(sizeof(*p));
- p->lsa = xzalloc(sizeof(*p->lsa));
- p->lsa->len =
-#if ENABLE_FEATURE_IPV6
- res->ai_family == AF_INET6 ?
- sizeof(struct sockaddr_in6) :
-#endif
- sizeof(struct sockaddr_in);
-
- memcpy(&p->lsa->u.sa, res->ai_addr, p->lsa->len);
- p->lsa->u.sa.sa_family = res->ai_family;
- set_nport(p->lsa, htons(123));
+ ntp_peer_t *p;
- p->query.fd = -1;
- p->query.msg.status = MODE_CLIENT | (NTP_VERSION << 3);
+ p = xzalloc(sizeof(*p));
+//TODO: big ntpd uses all IPs, not just 1st, do we need to mimic that?
+ p->lsa = xhost2sockaddr(s, 123);
+ p->query.fd = -1;
+ p->query.msg.status = MODE_CLIENT | (NTP_VERSION << 3);
+ if (STATE_NONE != 0)
p->state = STATE_NONE;
- p->trustlevel = TRUSTLEVEL_PATHETIC;
- p->query.fd = -1;
- set_next(p, 0);
+ p->trustlevel = TRUSTLEVEL_PATHETIC;
+ p->query.fd = -1;
+ set_next(p, 0);
- llist_add_to(&G->ntp_peers, p);
- G->peer_cnt++;
- }
- freeaddrinfo(res0);
+ llist_add_to(&G->ntp_peers, p);
+ G->peer_cnt++;
}
static double
@@ -229,9 +200,7 @@ gettime(void)
{
struct timeval tv;
- if (gettimeofday(&tv, NULL) == -1)
- bb_error_msg_and_die("gettimeofday");
-
+ gettimeofday(&tv, NULL); /* never fails */
return (tv.tv_sec + JAN_1970 + 1.0e-6 * tv.tv_usec);
}
@@ -314,38 +283,34 @@ error_interval(void)
}
static int
-sendmsg_wrap(int fd, const len_and_sockaddr *from, const len_and_sockaddr *to,
- ntp_msg_t *msg, ssize_t len)
+sendmsg_wrap(int fd,
+ const struct sockaddr *from, const struct sockaddr *to, socklen_t addrlen,
+ ntp_msg_t *msg, ssize_t len)
{
ssize_t ret;
- if (from == NULL) {
- ret = sendto(fd, msg, len, 0, &to->u.sa, to->len);
+ errno = 0;
+ if (!from) {
+ ret = sendto(fd, msg, len, 0, to, addrlen);
} else {
- ret = send_to_from(fd, msg, len, 0, &to->u.sa, &from->u.sa,
- to->len);
+ ret = send_to_from(fd, msg, len, 0, to, from, addrlen);
}
-
if (ret != len) {
- bb_error_msg("ntp_sendmsg failed");
+ bb_perror_msg("send failed");
return -1;
}
-
return 0;
}
static int
client_query(ntp_peer_t *p)
{
- int tos = IPTOS_LOWDELAY;
-
if (p->query.fd == -1) {
p->query.fd = xsocket(p->lsa->u.sa.sa_family, SOCK_DGRAM, 0);
#if ENABLE_FEATURE_IPV6
if (p->lsa->u.sa.sa_family == AF_INET)
#endif
- setsockopt(p->query.fd, IPPROTO_IP, IP_TOS, &tos,
- sizeof(tos));
+ setsockopt(p->query.fd, IPPROTO_IP, IP_TOS, &const_IPTOS_LOWDELAY, sizeof(const_IPTOS_LOWDELAY));
}
/*
@@ -366,7 +331,7 @@ client_query(ntp_peer_t *p)
p->query.msg.xmttime.fractionl = random();
p->query.xmttime = gettime();
- if (sendmsg_wrap(p->query.fd, NULL, p->lsa,
+ if (sendmsg_wrap(p->query.fd, /*from:*/ NULL, /*to:*/ &p->lsa->u.sa, /*addrlen:*/ p->lsa->len,
&p->query.msg, NTP_MSGSIZE_NOAUTH) == -1) {
set_next(p, INTERVAL_QUERY_PATHETIC);
return -1;
@@ -389,37 +354,35 @@ offset_compare(const void *aa, const voi
if ((*a)->update.offset < (*b)->update.offset)
return -1;
- if ((*a)->update.offset > (*b)->update.offset)
- return 1;
- return 0;
+ return ((*a)->update.offset > (*b)->update.offset);
}
-static void
-update_scale(double offset)
+static uint32_t
+updated_scale(double offset)
{
if (offset < 0)
offset = -offset;
if (offset > QSCALE_OFF_MAX)
- G->scale = 1;
- else if (offset < QSCALE_OFF_MIN)
- G->scale = QSCALE_OFF_MAX / QSCALE_OFF_MIN;
- else
- G->scale = QSCALE_OFF_MAX / offset;
+ return 1;
+ if (offset < QSCALE_OFF_MIN)
+ return QSCALE_OFF_MAX / QSCALE_OFF_MIN;
+ return QSCALE_OFF_MAX / offset;
}
static void
adjtime_wrap(void)
{
ntp_peer_t *p;
- int offset_cnt = 0, i = 0;
+ unsigned offset_cnt;
+ int i = 0;
ntp_peer_t **peers;
double offset_median;
llist_t *item;
len_and_sockaddr *lsa;
struct timeval tv, olddelta;
-
+ offset_cnt = 0;
for (item = G->ntp_peers; item != NULL; item = item->link) {
p = (ntp_peer_t *) item->data;
if (p->trustlevel < TRUSTLEVEL_BADPEER)
@@ -439,8 +402,9 @@ adjtime_wrap(void)
qsort(peers, offset_cnt, sizeof(ntp_peer_t *), offset_compare);
- if (offset_cnt > 0) {
- if (offset_cnt > 1 && offset_cnt % 2 == 0) {
+ if (offset_cnt != 0) {
+ if ((offset_cnt & 1) == 0) {
+//TODO: try offset_cnt /= 2...
offset_median =
(peers[offset_cnt / 2 - 1]->update.offset +
peers[offset_cnt / 2]->update.offset) / 2;
@@ -452,10 +416,8 @@ adjtime_wrap(void)
peers[offset_cnt / 2]->update.status.stratum);
} else {
offset_median = peers[offset_cnt / 2]->update.offset;
- G->status.rootdelay =
- peers[offset_cnt / 2]->update.delay;
- G->status.stratum =
- peers[offset_cnt / 2]->update.status.stratum;
+ G->status.rootdelay = peers[offset_cnt / 2]->update.delay;
+ G->status.stratum = peers[offset_cnt / 2]->update.status.stratum;
}
G->status.leap = peers[offset_cnt / 2]->update.status.leap;
@@ -479,15 +441,14 @@ adjtime_wrap(void)
G->firstadj = 0;
G->status.reftime = gettime();
G->status.stratum++; /* one more than selected peer */
- update_scale(offset_median);
+ G->scale = updated_scale(offset_median);
- G->status.refid4 =
- peers[offset_cnt / 2]->update.status.refid4;
+ G->status.refid4 = peers[offset_cnt / 2]->update.status.refid4;
lsa = peers[offset_cnt / 2]->lsa;
G->status.refid =
#if ENABLE_FEATURE_IPV6
- lsa->u.sa.sa_family == AF_INET6 ?
+ lsa->u.sa.sa_family != AF_INET ?
G->status.refid4 :
#endif
lsa->u.sin.sin_addr.s_addr;
@@ -519,10 +480,7 @@ settime(double offset)
if (offset < SETTIME_MIN_OFFSET && offset > -SETTIME_MIN_OFFSET)
return;
- if (gettimeofday(&curtime, NULL) == -1) {
- bb_error_msg("gettimeofday");
- return;
- }
+ gettimeofday(&curtime, NULL); /* never fails */
d_to_tv(offset, &tv);
curtime.tv_usec += tv.tv_usec + 1000000;
@@ -611,16 +569,18 @@ client_dispatch(ntp_peer_t *p)
addr = xmalloc_sockaddr2dotted_noport(&p->lsa->u.sa);
- if ((size = recvfrom(p->query.fd, &msg, sizeof(msg), 0,
- NULL, NULL)) == -1) {
- if (errno == EHOSTUNREACH || errno == EHOSTDOWN ||
- errno == ENETUNREACH || errno == ENETDOWN ||
- errno == ECONNREFUSED || errno == EADDRNOTAVAIL) {
- bb_error_msg("recvfrom failed %s", addr);
+ size = recvfrom(p->query.fd, &msg, sizeof(msg), 0, NULL, NULL);
+ if (size == -1) {
+ bb_perror_msg("recvfrom(%s) error", addr);
+ if (errno == EHOSTUNREACH || errno == EHOSTDOWN
+ || errno == ENETUNREACH || errno == ENETDOWN
+ || errno == ECONNREFUSED || errno == EADDRNOTAVAIL
+ ) {
+//TODO: always do this?
set_next(p, error_interval());
- return;
- } else
- bb_error_msg_and_die("recvfrom");
+ goto bail;
+ }
+ xfunc_die();
}
T4 = gettime();
@@ -726,36 +686,27 @@ client_dispatch(ntp_peer_t *p)
static void
server_dispatch(int fd)
{
- ssize_t size;
- uint8_t version;
- double rectime;
- len_and_sockaddr *from, *to;
- ntp_msg_t query, reply;
- char *addr;
+ ssize_t size;
+ uint8_t version;
+ double rectime;
+ len_and_sockaddr *to;
+ struct sockaddr *from;
+ ntp_msg_t query, reply;
to = get_sock_lsa(G->listen_fd);
- from = xzalloc(LSA_LEN_SIZE + to->len);
+ from = xzalloc(to->len);
- if ((size = recv_from_to(fd, &query, sizeof(query), 0,
- &from->u.sa, &to->u.sa, to->len)) == -1)
+ size = recv_from_to(fd, &query, sizeof(query), 0, from, &to->u.sa, to->len);
+ if (size == -1)
bb_error_msg_and_die("recv_from_to");
-
- rectime = gettime();
-
- from->len =
-#if ENABLE_FEATURE_IPV6
- (from->u.sa.sa_family == AF_INET6) ?
- sizeof(struct sockaddr_in6) :
-#endif
- sizeof(struct sockaddr_in);
-
- addr = xmalloc_sockaddr2dotted_noport(&from->u.sa);
-
if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) {
+ char *addr = xmalloc_sockaddr2dotted_noport(from);
bb_error_msg("malformed packet received from %s", addr);
+ free(addr);
goto bail;
}
+ rectime = gettime();
version = (query.status & VERSION_MASK) >> 3;
memset(&reply, 0, sizeof(reply));
@@ -773,67 +724,63 @@ server_dispatch(int fd)
reply.rootdelay = d_to_sfp(G->status.rootdelay);
reply.refid = (version > 3) ? G->status.refid4 : G->status.refid;
- sendmsg_wrap(fd, to, from, &reply, size);
+ /* We reply from the address packet was sent to,
+ * this makes to/from look swapped here: */
+ sendmsg_wrap(fd, /*from:*/ &to->u.sa, /*to:*/ from, /*addrlen:*/ to->len,
+ &reply, size);
bail:
free(to);
free(from);
- free(addr);
}
#endif
-static void
-sighdlr(int sig)
-{
- switch (sig) {
- case SIGINT:
- case SIGTERM:
- quit = 1;
- break;
- }
-}
-
+static void ntp_main(void) NORETURN;
static void
ntp_main(void)
{
- int a, b, nfds, i, j, idx_peers, timeout;
- uint new_cnt, sent_cnt, trial_cnt;
- struct pollfd *pfd = NULL;
- ntp_peer_t *p, **idx2peer = NULL;
- time_t nextaction;
- llist_t *item;
+ unsigned new_cnt;
+ struct pollfd *pfd;
+ ntp_peer_t **idx2peer;
- bb_signals(SIGTERM|SIGINT, sighdlr);
+ bb_signals(SIGTERM|SIGINT, record_signo);
bb_signals(SIGPIPE|SIGHUP, SIG_IGN);
+ {
+ int prec = 0;
+ int b;
#if 0
- struct timespec tp;
-
- We can use sys_clock_getres but assuming 10ms tick should be fine.
- clock_getres(CLOCK_REALTIME, &tp);
- tp.tv_sec = 0;
- tp.tv_nsec = 10000000;
-
- b = 1000000000 / tp.tv_nsec; /* convert to Hz */
+ struct timespec tp;
+ /* We can use sys_clock_getres but assuming 10ms tick should be fine */
+ clock_getres(CLOCK_REALTIME, &tp);
+ tp.tv_sec = 0;
+ tp.tv_nsec = 10000000;
+ b = 1000000000 / tp.tv_nsec; /* convert to Hz */
#else
- b = 100; /* b = 1000000000/10000000 = 100 */
+ b = 100; /* b = 1000000000/10000000 = 100 */
#endif
- for (a = 0; b > 1; a--, b >>= 1)
- ;
- G->status.precision = a;
+ while (b > 1)
+ prec--, b >>= 1;
+ G->status.precision = prec;
+ }
G->scale = 1;
idx2peer = xzalloc(sizeof(void *) * G->peer_cnt);
new_cnt = G->peer_cnt;
-
#if ENABLE_FEATURE_NTPD_SERVER
if (G->listen_fd != -1)
new_cnt++;
#endif
- pfd = xzalloc(sizeof(struct pollfd) * new_cnt);
+ pfd = xzalloc(sizeof(pfd[0]) * new_cnt);
+
+ while (!bb_got_signal) {
+ llist_t *item;
+ unsigned i, j, idx_peers;
+ unsigned sent_cnt, trial_cnt;
+ int nfds, timeout;
+ time_t nextaction;
- while (quit == 0) {
nextaction = time(NULL) + 3600;
i = 0;
@@ -847,7 +794,7 @@ ntp_main(void)
idx_peers = i;
sent_cnt = trial_cnt = 0;
for (item = G->ntp_peers; item != NULL; item = item->link) {
- p = (ntp_peer_t *) item->data;
+ ntp_peer_t *p = (ntp_peer_t *) item->data;
if (p->next > 0 && p->next <= time(NULL)) {
trial_cnt++;
@@ -900,8 +847,9 @@ ntp_main(void)
} while (nfds == -1 && errno == ENOMEM);
#endif
+ j = 0;
#if ENABLE_FEATURE_NTPD_SERVER
- for (j = 0; nfds > 0 && j < idx_peers; j++) {
+ for (; nfds > 0 && j < idx_peers; j++) {
if (pfd[j].revents & (POLLIN|POLLERR)) {
nfds--;
server_dispatch(pfd[j].fd);
@@ -914,9 +862,9 @@ ntp_main(void)
client_dispatch(idx2peer[j - idx_peers]);
}
}
- }
+ } /* while (!bb_got_signal) */
- _exit(0);
+ kill_myself_with_sig(bb_got_signal);
}
/* Upstream ntpd's options:
@@ -1004,21 +952,16 @@ ntp_main(void)
* Note: The kernel time discipline is disabled with this option.
*/
-int ntpd_main(int argc UNUSED_PARAM, char *argv[]) MAIN_EXTERNALLY_VISIBLE;
-int ntpd_main(int argc UNUSED_PARAM, char *argv[])
+int ntpd_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ntpd_main(int argc UNUSED_PARAM, char **argv)
{
ntpd_conf_t conf;
-#if ENABLE_FEATURE_NTPD_SERVER
- int tos = IPTOS_LOWDELAY;
-#endif
smallint opts;
llist_t *peers = NULL;
- G = &conf;
-
memset(&conf, 0, sizeof(conf));
+ SET_PTR_TO_GLOBALS(&conf);
- logmode = LOGMODE_STDIO;
tzset();
#if ENABLE_FEATURE_NTPD_SERVER
@@ -1028,15 +971,11 @@ int ntpd_main(int argc UNUSED_PARAM, cha
opt_complementary = "p::";
opts = getopt32(argv, "f" IF_FEATURE_NTPD_SERVER("l") "p:s", &peers);
-
- if (opts & OPT_f)
- conf.foreground = 1;
#if ENABLE_FEATURE_NTPD_SERVER
if (opts & OPT_l) {
conf.listen_fd = create_and_bind_dgram_or_die("0.0.0.0", 123);
socket_want_pktinfo(conf.listen_fd);
- setsockopt(conf.listen_fd, IPPROTO_IP, IP_TOS, &tos,
- sizeof(tos));
+ setsockopt(conf.listen_fd, IPPROTO_IP, IP_TOS, &const_IPTOS_LOWDELAY, sizeof(const_IPTOS_LOWDELAY));
}
#endif
while (peers)
@@ -1045,16 +984,13 @@ int ntpd_main(int argc UNUSED_PARAM, cha
conf.settime = 1;
if (getuid()) {
- fprintf(stderr, "ntpd: need root privileges\n");
- exit(1);
+ bb_error_msg_and_die("need root privileges");
}
- if (!conf.foreground) {
+ if (!(opts & OPT_f)) {
logmode = LOGMODE_NONE;
bb_daemonize(DAEMON_DEVNULL_STDIO);
}
ntp_main();
-
- return 0;
}
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox