ntp: simplifications; libbb: simpler resolution of numeric hostnames

function                                             old     new   delta
str2sockaddr                                         405     567    +162
ntp_init                                             310     317      +7
scale_interval                                        58      59      +1
error_interval                                        22      23      +1
ntpd_main                                           3257    3214     -43
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 4/1 up/down: 171/-43)           Total: 128 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2009-11-24 07:07:42 +01:00
parent 887d963037
commit ca6c7e42f9
2 changed files with 147 additions and 108 deletions

View File

@ -161,6 +161,7 @@ static len_and_sockaddr* str2sockaddr(
IF_FEATURE_IPV6(sa_family_t af,) IF_FEATURE_IPV6(sa_family_t af,)
int ai_flags) int ai_flags)
{ {
IF_NOT_FEATURE_IPV6(sa_family_t af = AF_INET;)
int rc; int rc;
len_and_sockaddr *r; len_and_sockaddr *r;
struct addrinfo *result = NULL; struct addrinfo *result = NULL;
@ -221,12 +222,40 @@ IF_FEATURE_IPV6(sa_family_t af,)
skip: ; skip: ;
} }
memset(&hint, 0 , sizeof(hint)); /* Next two if blocks allow to skip getaddrinfo()
#if !ENABLE_FEATURE_IPV6 * in case host is a numeric IP(v6) address,
hint.ai_family = AF_INET; /* do not try to find IPv6 */ * getaddrinfo() initializes DNS resolution machinery,
#else * scans network config and such - tens of syscalls.
hint.ai_family = af; */
/* If we were not asked specifically for IPv6,
* check whether this is a numeric IPv4 */
IF_FEATURE_IPV6(if(af != AF_INET6)) {
struct in_addr in4;
if (inet_aton(host, &in4) != 0) {
r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_in));
r->len = sizeof(struct sockaddr_in);
r->u.sa.sa_family = AF_INET;
r->u.sin.sin_addr = in4;
goto set_port;
}
}
#if ENABLE_FEATURE_IPV6
/* If we were not asked specifically for IPv4,
* check whether this is a numeric IPv6 */
if (af != AF_INET) {
struct in6_addr in6;
if (inet_pton(AF_INET6, host, &in6) > 0) {
r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_in6));
r->len = sizeof(struct sockaddr_in6);
r->u.sa.sa_family = AF_INET6;
r->u.sin6.sin6_addr = in6;
goto set_port;
}
}
#endif #endif
memset(&hint, 0 , sizeof(hint));
hint.ai_family = af;
/* Needed. Or else we will get each address thrice (or more) /* Needed. Or else we will get each address thrice (or more)
* for each possible socket type (tcp,udp,raw...): */ * for each possible socket type (tcp,udp,raw...): */
hint.ai_socktype = SOCK_STREAM; hint.ai_socktype = SOCK_STREAM;
@ -250,9 +279,11 @@ IF_FEATURE_IPV6(sa_family_t af,)
} }
} }
#endif #endif
r = xmalloc(offsetof(len_and_sockaddr, u.sa) + used_res->ai_addrlen); r = xmalloc(LSA_LEN_SIZE + used_res->ai_addrlen);
r->len = used_res->ai_addrlen; r->len = used_res->ai_addrlen;
memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen); memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen);
IF_FEATURE_IPV6(set_port:)
set_nport(r, htons(port)); set_nport(r, htons(port));
ret: ret:
freeaddrinfo(result); freeaddrinfo(result);

View File

@ -5,7 +5,6 @@
* *
* Licensed under GPLv2, see file LICENSE in this tarball for details. * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/ */
#include "libbb.h" #include "libbb.h"
#include <netinet/ip.h> /* For IPTOS_LOWDELAY definition */ #include <netinet/ip.h> /* For IPTOS_LOWDELAY definition */
@ -59,30 +58,32 @@ typedef struct {
uint16_t fractions; uint16_t fractions;
} s_fixedpt_t; } s_fixedpt_t;
#define NTP_DIGESTSIZE 16 enum {
#define NTP_MSGSIZE_NOAUTH 48 NTP_DIGESTSIZE = 16,
#define NTP_MSGSIZE (NTP_MSGSIZE_NOAUTH + 4 + NTP_DIGESTSIZE) NTP_MSGSIZE_NOAUTH = 48,
NTP_MSGSIZE = (NTP_MSGSIZE_NOAUTH + 4 + NTP_DIGESTSIZE),
};
typedef struct { typedef struct {
uint8_t status; /* status of local clock and leap info */ uint8_t status; /* status of local clock and leap info */
uint8_t stratum; /* Stratum level */ uint8_t stratum; /* stratum level */
uint8_t ppoll; /* poll value */ uint8_t ppoll; /* poll value */
int8_t precision; int8_t precision;
s_fixedpt_t rootdelay; s_fixedpt_t rootdelay;
s_fixedpt_t dispersion; s_fixedpt_t dispersion;
uint32_t refid; uint32_t refid;
l_fixedpt_t reftime; l_fixedpt_t reftime;
l_fixedpt_t orgtime; l_fixedpt_t orgtime;
l_fixedpt_t rectime; l_fixedpt_t rectime;
l_fixedpt_t xmttime; l_fixedpt_t xmttime;
uint32_t keyid; uint32_t keyid;
uint8_t digest[NTP_DIGESTSIZE]; uint8_t digest[NTP_DIGESTSIZE];
} ntp_msg_t; } ntp_msg_t;
typedef struct { typedef struct {
int fd; int fd;
ntp_msg_t msg; ntp_msg_t msg;
double xmttime; double xmttime;
} ntp_query_t; } ntp_query_t;
enum { enum {
@ -97,6 +98,7 @@ enum {
/* Status Masks */ /* Status Masks */
MODE_MASK = (7 << 0), MODE_MASK = (7 << 0),
VERSION_MASK = (7 << 3), VERSION_MASK = (7 << 3),
VERSION_SHIFT = 3,
LI_MASK = (3 << 6), LI_MASK = (3 << 6),
/* Mode values */ /* Mode values */
@ -107,7 +109,7 @@ enum {
MODE_SERVER = 4, /* server */ MODE_SERVER = 4, /* server */
MODE_BROADCAST = 5, /* broadcast */ MODE_BROADCAST = 5, /* broadcast */
MODE_RES1 = 6, /* reserved for NTP control message */ MODE_RES1 = 6, /* reserved for NTP control message */
MODE_RES2 = 7 /* reserved for private use */ MODE_RES2 = 7, /* reserved for private use */
}; };
#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */ #define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
@ -115,7 +117,7 @@ enum {
enum client_state { enum client_state {
STATE_NONE, STATE_NONE,
STATE_QUERY_SENT, STATE_QUERY_SENT,
STATE_REPLY_RECEIVED STATE_REPLY_RECEIVED,
}; };
typedef struct { typedef struct {
@ -132,24 +134,27 @@ typedef struct {
} ntp_status_t; } ntp_status_t;
typedef struct { typedef struct {
ntp_status_t status; ntp_status_t status;
double offset; double offset;
double delay; double delay;
double error; double error;
time_t rcvd; time_t rcvd;
uint8_t good; uint8_t good;
} ntp_offset_t; } ntp_offset_t;
typedef struct { typedef struct {
//TODO:
// (1) store dotted addr str, to avoid constant translations
// (2) periodically re-resolve DNS names
len_and_sockaddr *lsa; len_and_sockaddr *lsa;
ntp_query_t query; ntp_query_t query;
ntp_offset_t reply[OFFSET_ARRAY_SIZE]; ntp_offset_t reply[OFFSET_ARRAY_SIZE];
ntp_offset_t update; ntp_offset_t update;
enum client_state state; enum client_state state;
time_t next; time_t next;
time_t deadline; time_t deadline;
uint8_t shift; uint8_t shift;
uint8_t trustlevel; uint8_t trustlevel;
} ntp_peer_t; } ntp_peer_t;
enum { enum {
@ -211,8 +216,7 @@ add_peers(const char *s)
static double static double
gettime(void) gettime(void)
{ {
struct timeval tv; struct timeval tv;
gettimeofday(&tv, NULL); /* never fails */ gettimeofday(&tv, NULL); /* never fails */
return (tv.tv_sec + JAN_1970 + 1.0e-6 * tv.tv_usec); return (tv.tv_sec + JAN_1970 + 1.0e-6 * tv.tv_usec);
} }
@ -228,11 +232,20 @@ d_to_tv(double d, struct timeval *tv)
static double static double
lfp_to_d(l_fixedpt_t lfp) lfp_to_d(l_fixedpt_t lfp)
{ {
double ret; double ret;
lfp.int_partl = ntohl(lfp.int_partl); lfp.int_partl = ntohl(lfp.int_partl);
lfp.fractionl = ntohl(lfp.fractionl); lfp.fractionl = ntohl(lfp.fractionl);
ret = (double)(lfp.int_partl) + ((double)lfp.fractionl / UINT_MAX); ret = (double)lfp.int_partl + ((double)lfp.fractionl / UINT_MAX);
return ret;
}
static double
sfp_to_d(s_fixedpt_t 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; return ret;
} }
@ -240,33 +253,22 @@ lfp_to_d(l_fixedpt_t lfp)
static l_fixedpt_t static l_fixedpt_t
d_to_lfp(double d) d_to_lfp(double d)
{ {
l_fixedpt_t lfp; l_fixedpt_t lfp;
lfp.int_partl = (uint32_t)d;
lfp.int_partl = htonl((uint32_t)d); lfp.fractionl = (uint32_t)((d - lfp.int_partl) * UINT_MAX);
lfp.fractionl = htonl((uint32_t)((d - (u_int32_t)d) * UINT_MAX)); lfp.int_partl = htonl(lfp.int_partl);
lfp.fractionl = htonl(lfp.fractionl);
return lfp; return lfp;
} }
#endif
static double
sfp_to_d(s_fixedpt_t 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;
}
#if ENABLE_FEATURE_NTPD_SERVER
static s_fixedpt_t static s_fixedpt_t
d_to_sfp(double d) d_to_sfp(double d)
{ {
s_fixedpt_t sfp; s_fixedpt_t sfp;
sfp.int_parts = (uint16_t)d;
sfp.int_parts = htons((uint16_t)d); sfp.fractions = (uint16_t)((d - sfp.int_parts) * USHRT_MAX);
sfp.fractions = htons((uint16_t)((d - (u_int16_t)d) * USHRT_MAX)); sfp.int_parts = htons(sfp.int_parts);
sfp.fractions = htons(sfp.fractions);
return sfp; return sfp;
} }
#endif #endif
@ -282,9 +284,8 @@ static time_t
error_interval(void) error_interval(void)
{ {
time_t interval, r; time_t interval, r;
interval = INTERVAL_QUERY_PATHETIC * QSCALE_OFF_MAX / QSCALE_OFF_MIN; interval = INTERVAL_QUERY_PATHETIC * QSCALE_OFF_MAX / QSCALE_OFF_MIN;
r = random() % (interval / 10); r = (unsigned)random() % (unsigned long)(interval / 10);
return (interval + r); return (interval + r);
} }
@ -352,12 +353,8 @@ client_query(ntp_peer_t *p)
static int static int
offset_compare(const void *aa, const void *bb) offset_compare(const void *aa, const void *bb)
{ {
const ntp_peer_t * const *a; const ntp_peer_t *const *a = aa;
const ntp_peer_t * const *b; const ntp_peer_t *const *b = bb;
a = aa;
b = bb;
if ((*a)->update.offset < (*b)->update.offset) if ((*a)->update.offset < (*b)->update.offset)
return -1; return -1;
return ((*a)->update.offset > (*b)->update.offset); return ((*a)->update.offset > (*b)->update.offset);
@ -368,7 +365,6 @@ updated_scale(double offset)
{ {
if (offset < 0) if (offset < 0)
offset = -offset; offset = -offset;
if (offset > QSCALE_OFF_MAX) if (offset > QSCALE_OFF_MAX)
return 1; return 1;
if (offset < QSCALE_OFF_MIN) if (offset < QSCALE_OFF_MIN)
@ -559,9 +555,8 @@ static time_t
scale_interval(time_t requested) scale_interval(time_t requested)
{ {
time_t interval, r; time_t interval, r;
interval = requested * G.scale; interval = requested * G.scale;
r = random() % MAX(5, interval / 10); r = (unsigned)random() % (unsigned long)(MAX(5, interval / 10));
return (interval + r); return (interval + r);
} }
@ -577,9 +572,10 @@ client_dispatch(ntp_peer_t *p)
addr = xmalloc_sockaddr2dotted_noport(&p->lsa->u.sa); addr = xmalloc_sockaddr2dotted_noport(&p->lsa->u.sa);
size = recvfrom(p->query.fd, &msg, sizeof(msg), 0, NULL, NULL); //TODO: use MSG_DONTWAIT flag?
size = recv(p->query.fd, &msg, sizeof(msg), 0);
if (size == -1) { if (size == -1) {
bb_perror_msg("recvfrom(%s) error", addr); bb_perror_msg("recv(%s) error", addr);
if (errno == EHOSTUNREACH || errno == EHOSTDOWN if (errno == EHOSTUNREACH || errno == EHOSTDOWN
|| errno == ENETUNREACH || errno == ENETDOWN || errno == ENETUNREACH || errno == ENETDOWN
|| errno == ECONNREFUSED || errno == EADDRNOTAVAIL || errno == ECONNREFUSED || errno == EADDRNOTAVAIL
@ -693,48 +689,58 @@ client_dispatch(ntp_peer_t *p)
static void static void
server_dispatch(int fd) server_dispatch(int fd)
{ {
ssize_t size; ssize_t size;
uint8_t version; uint8_t version;
double rectime; double rectime;
len_and_sockaddr *to; len_and_sockaddr *to;
struct sockaddr *from; struct sockaddr *from;
ntp_msg_t query, reply; ntp_msg_t msg;
uint8_t query_status;
uint8_t query_ppoll;
l_fixedpt_t query_xmttime;
to = get_sock_lsa(G.listen_fd); to = get_sock_lsa(G.listen_fd);
from = xzalloc(to->len); from = xzalloc(to->len);
size = recv_from_to(fd, &query, sizeof(query), 0, from, &to->u.sa, to->len); //TODO: use MGS_DONTWAIT flag?
if (size == -1) size = recv_from_to(fd, &msg, sizeof(msg), 0, from, &to->u.sa, to->len);
bb_error_msg_and_die("recv_from_to");
if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) { if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) {
char *addr = xmalloc_sockaddr2dotted_noport(from); char *addr;
if (size < 0)
bb_error_msg_and_die("recv_from_to");
addr = xmalloc_sockaddr2dotted_noport(from);
bb_error_msg("malformed packet received from %s", addr); bb_error_msg("malformed packet received from %s", addr);
free(addr); free(addr);
goto bail; goto bail;
} }
rectime = gettime(); query_status = msg.status;
version = (query.status & VERSION_MASK) >> 3; query_ppoll = msg.ppoll;
query_xmttime = msg.xmttime;
memset(&reply, 0, sizeof(reply)); /* Build a reply packet */
reply.status = G.status.synced ? G.status.leap : LI_ALARM; memset(&msg, 0, sizeof(msg));
reply.status |= (query.status & VERSION_MASK); msg.status = G.status.synced ? G.status.leap : LI_ALARM;
reply.status |= ((query.status & MODE_MASK) == MODE_CLIENT) ? msg.status |= (query_status & VERSION_MASK);
msg.status |= ((query_status & MODE_MASK) == MODE_CLIENT) ?
MODE_SERVER : MODE_SYM_PAS; MODE_SERVER : MODE_SYM_PAS;
reply.stratum = G.status.stratum; msg.stratum = G.status.stratum;
reply.ppoll = query.ppoll; msg.ppoll = query_ppoll;
reply.precision = G.status.precision; msg.precision = G.status.precision;
reply.rectime = d_to_lfp(rectime); rectime = gettime();
reply.reftime = d_to_lfp(G.status.reftime); msg.xmttime = msg.rectime = d_to_lfp(rectime);
reply.xmttime = d_to_lfp(gettime()); msg.reftime = d_to_lfp(G.status.reftime);
reply.orgtime = query.xmttime; //msg.xmttime = d_to_lfp(gettime()); // = msg.rectime
reply.rootdelay = d_to_sfp(G.status.rootdelay); msg.orgtime = query_xmttime;
reply.refid = (version > 3) ? G.status.refid4 : G.status.refid; msg.rootdelay = d_to_sfp(G.status.rootdelay);
version = (query_status & VERSION_MASK); /* ... >> VERSION_SHIFT - done below instead */
msg.refid = (version > (3 << VERSION_SHIFT)) ? G.status.refid4 : G.status.refid;
/* We reply from the address packet was sent to, /* We reply from the address packet was sent to,
* this makes to/from look swapped here: */ * this makes to/from look swapped here: */
sendmsg_wrap(fd, /*from:*/ &to->u.sa, /*to:*/ from, /*addrlen:*/ to->len, sendmsg_wrap(fd,
&reply, size); /*from:*/ &to->u.sa, /*to:*/ from, /*addrlen:*/ to->len,
&msg, size);
bail: bail:
free(to); free(to);
@ -835,7 +841,8 @@ static NOINLINE void ntp_init(char **argv)
unsigned opts; unsigned opts;
llist_t *peers; llist_t *peers;
tzset(); srandom(getpid());
/* tzset(); - why? it's called automatically when needed, no? */
if (getuid()) if (getuid())
bb_error_msg_and_die("need root privileges"); bb_error_msg_and_die("need root privileges");
@ -911,7 +918,7 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
while (!bb_got_signal) { while (!bb_got_signal) {
llist_t *item; llist_t *item;
unsigned i, j, idx_peers; unsigned i, j, first_peer_idx;
unsigned sent_cnt, trial_cnt; unsigned sent_cnt, trial_cnt;
int nfds, timeout; int nfds, timeout;
time_t nextaction; time_t nextaction;
@ -926,7 +933,7 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
i++; i++;
} }
#endif #endif
idx_peers = i; first_peer_idx = i;
sent_cnt = trial_cnt = 0; sent_cnt = trial_cnt = 0;
for (item = g.ntp_peers; item != NULL; item = item->link) { for (item = g.ntp_peers; item != NULL; item = item->link) {
ntp_peer_t *p = (ntp_peer_t *) item->data; ntp_peer_t *p = (ntp_peer_t *) item->data;
@ -960,7 +967,7 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
if (p->state == STATE_QUERY_SENT) { if (p->state == STATE_QUERY_SENT) {
pfd[i].fd = p->query.fd; pfd[i].fd = p->query.fd;
pfd[i].events = POLLIN; pfd[i].events = POLLIN;
idx2peer[i - idx_peers] = p; idx2peer[i - first_peer_idx] = p;
i++; i++;
} }
} }
@ -978,7 +985,8 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
j = 0; j = 0;
#if ENABLE_FEATURE_NTPD_SERVER #if ENABLE_FEATURE_NTPD_SERVER
for (; nfds > 0 && j < idx_peers; j++) { //TODO: simplify. There is only one server fd!
for (; nfds > 0 && j < first_peer_idx; j++) {
if (pfd[j].revents & (POLLIN|POLLERR)) { if (pfd[j].revents & (POLLIN|POLLERR)) {
nfds--; nfds--;
server_dispatch(pfd[j].fd); server_dispatch(pfd[j].fd);
@ -988,7 +996,7 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
for (; nfds > 0 && j < i; j++) { for (; nfds > 0 && j < i; j++) {
if (pfd[j].revents & (POLLIN|POLLERR)) { if (pfd[j].revents & (POLLIN|POLLERR)) {
nfds--; nfds--;
client_dispatch(idx2peer[j - idx_peers]); client_dispatch(idx2peer[j - first_peer_idx]);
} }
} }
} /* while (!bb_got_signal) */ } /* while (!bb_got_signal) */