From ca6c7e42f93eb2b0ce246eafd8b0e4ac27414f6b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 24 Nov 2009 07:07:42 +0100 Subject: 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 --- libbb/xconnect.c | 41 +++++++++-- networking/ntpd.c | 208 ++++++++++++++++++++++++++++-------------------------- 2 files changed, 144 insertions(+), 105 deletions(-) diff --git a/libbb/xconnect.c b/libbb/xconnect.c index f018ca9d9..81a2b048f 100644 --- a/libbb/xconnect.c +++ b/libbb/xconnect.c @@ -161,6 +161,7 @@ static len_and_sockaddr* str2sockaddr( IF_FEATURE_IPV6(sa_family_t af,) int ai_flags) { +IF_NOT_FEATURE_IPV6(sa_family_t af = AF_INET;) int rc; len_and_sockaddr *r; struct addrinfo *result = NULL; @@ -221,12 +222,40 @@ IF_FEATURE_IPV6(sa_family_t af,) skip: ; } + /* Next two if blocks allow to skip getaddrinfo() + * in case host is a numeric IP(v6) address, + * getaddrinfo() initializes DNS resolution machinery, + * scans network config and such - tens of syscalls. + */ + /* 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 + memset(&hint, 0 , sizeof(hint)); -#if !ENABLE_FEATURE_IPV6 - hint.ai_family = AF_INET; /* do not try to find IPv6 */ -#else hint.ai_family = af; -#endif /* Needed. Or else we will get each address thrice (or more) * for each possible socket type (tcp,udp,raw...): */ hint.ai_socktype = SOCK_STREAM; @@ -250,9 +279,11 @@ IF_FEATURE_IPV6(sa_family_t af,) } } #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; memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen); + + IF_FEATURE_IPV6(set_port:) set_nport(r, htons(port)); ret: freeaddrinfo(result); diff --git a/networking/ntpd.c b/networking/ntpd.c index 8ee42e627..4e661ce98 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -5,7 +5,6 @@ * * Licensed under GPLv2, see file LICENSE in this tarball for details. */ - #include "libbb.h" #include /* For IPTOS_LOWDELAY definition */ @@ -59,30 +58,32 @@ typedef struct { uint16_t fractions; } s_fixedpt_t; -#define NTP_DIGESTSIZE 16 -#define NTP_MSGSIZE_NOAUTH 48 -#define NTP_MSGSIZE (NTP_MSGSIZE_NOAUTH + 4 + NTP_DIGESTSIZE) +enum { + NTP_DIGESTSIZE = 16, + NTP_MSGSIZE_NOAUTH = 48, + NTP_MSGSIZE = (NTP_MSGSIZE_NOAUTH + 4 + NTP_DIGESTSIZE), +}; typedef struct { - uint8_t status; /* status of local clock and leap info */ - uint8_t stratum; /* Stratum level */ - uint8_t ppoll; /* poll value */ - int8_t precision; + uint8_t status; /* status of local clock and leap info */ + uint8_t stratum; /* stratum level */ + uint8_t ppoll; /* poll value */ + int8_t precision; s_fixedpt_t rootdelay; s_fixedpt_t dispersion; - uint32_t refid; + uint32_t refid; l_fixedpt_t reftime; l_fixedpt_t orgtime; l_fixedpt_t rectime; l_fixedpt_t xmttime; - uint32_t keyid; - uint8_t digest[NTP_DIGESTSIZE]; + uint32_t keyid; + uint8_t digest[NTP_DIGESTSIZE]; } ntp_msg_t; typedef struct { - int fd; - ntp_msg_t msg; - double xmttime; + int fd; + ntp_msg_t msg; + double xmttime; } ntp_query_t; enum { @@ -97,6 +98,7 @@ enum { /* Status Masks */ MODE_MASK = (7 << 0), VERSION_MASK = (7 << 3), + VERSION_SHIFT = 3, LI_MASK = (3 << 6), /* Mode values */ @@ -107,7 +109,7 @@ enum { MODE_SERVER = 4, /* server */ MODE_BROADCAST = 5, /* broadcast */ 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 */ @@ -115,7 +117,7 @@ enum { enum client_state { STATE_NONE, STATE_QUERY_SENT, - STATE_REPLY_RECEIVED + STATE_REPLY_RECEIVED, }; typedef struct { @@ -132,24 +134,27 @@ typedef struct { } ntp_status_t; typedef struct { - ntp_status_t status; - double offset; - double delay; - double error; - time_t rcvd; - uint8_t good; + ntp_status_t status; + double offset; + double delay; + double error; + time_t rcvd; + uint8_t good; } ntp_offset_t; typedef struct { +//TODO: +// (1) store dotted addr str, to avoid constant translations +// (2) periodically re-resolve DNS names len_and_sockaddr *lsa; - ntp_query_t query; - ntp_offset_t reply[OFFSET_ARRAY_SIZE]; - ntp_offset_t update; - enum client_state state; - time_t next; - time_t deadline; - uint8_t shift; - uint8_t trustlevel; + ntp_query_t query; + ntp_offset_t reply[OFFSET_ARRAY_SIZE]; + ntp_offset_t update; + enum client_state state; + time_t next; + time_t deadline; + uint8_t shift; + uint8_t trustlevel; } ntp_peer_t; enum { @@ -211,8 +216,7 @@ add_peers(const char *s) static double gettime(void) { - struct timeval tv; - + struct timeval tv; gettimeofday(&tv, NULL); /* never fails */ return (tv.tv_sec + JAN_1970 + 1.0e-6 * tv.tv_usec); } @@ -228,45 +232,43 @@ d_to_tv(double d, struct timeval *tv) static double lfp_to_d(l_fixedpt_t lfp) { - double ret; - + double ret; lfp.int_partl = ntohl(lfp.int_partl); 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; } -#if ENABLE_FEATURE_NTPD_SERVER -static l_fixedpt_t -d_to_lfp(double d) -{ - l_fixedpt_t lfp; - - lfp.int_partl = htonl((uint32_t)d); - lfp.fractionl = htonl((uint32_t)((d - (u_int32_t)d) * UINT_MAX)); - return lfp; -} -#endif - static double sfp_to_d(s_fixedpt_t sfp) { - double ret; - + double ret; sfp.int_parts = ntohs(sfp.int_parts); sfp.fractions = ntohs(sfp.fractions); - ret = (double)(sfp.int_parts) + ((double)sfp.fractions / USHRT_MAX); + ret = (double)sfp.int_parts + ((double)sfp.fractions / USHRT_MAX); return ret; } #if ENABLE_FEATURE_NTPD_SERVER +static l_fixedpt_t +d_to_lfp(double d) +{ + l_fixedpt_t lfp; + lfp.int_partl = (uint32_t)d; + lfp.fractionl = (uint32_t)((d - lfp.int_partl) * UINT_MAX); + lfp.int_partl = htonl(lfp.int_partl); + lfp.fractionl = htonl(lfp.fractionl); + return lfp; +} + static s_fixedpt_t d_to_sfp(double d) { - s_fixedpt_t sfp; - - sfp.int_parts = htons((uint16_t)d); - sfp.fractions = htons((uint16_t)((d - (u_int16_t)d) * USHRT_MAX)); + s_fixedpt_t sfp; + sfp.int_parts = (uint16_t)d; + sfp.fractions = (uint16_t)((d - sfp.int_parts) * USHRT_MAX); + sfp.int_parts = htons(sfp.int_parts); + sfp.fractions = htons(sfp.fractions); return sfp; } #endif @@ -282,9 +284,8 @@ static time_t error_interval(void) { time_t interval, r; - interval = INTERVAL_QUERY_PATHETIC * QSCALE_OFF_MAX / QSCALE_OFF_MIN; - r = random() % (interval / 10); + r = (unsigned)random() % (unsigned long)(interval / 10); return (interval + r); } @@ -352,12 +353,8 @@ client_query(ntp_peer_t *p) static int offset_compare(const void *aa, const void *bb) { - const ntp_peer_t * const *a; - const ntp_peer_t * const *b; - - a = aa; - b = bb; - + const ntp_peer_t *const *a = aa; + const ntp_peer_t *const *b = bb; if ((*a)->update.offset < (*b)->update.offset) return -1; return ((*a)->update.offset > (*b)->update.offset); @@ -368,7 +365,6 @@ updated_scale(double offset) { if (offset < 0) offset = -offset; - if (offset > QSCALE_OFF_MAX) return 1; if (offset < QSCALE_OFF_MIN) @@ -559,9 +555,8 @@ static time_t scale_interval(time_t requested) { time_t interval, r; - interval = requested * G.scale; - r = random() % MAX(5, interval / 10); + r = (unsigned)random() % (unsigned long)(MAX(5, interval / 10)); return (interval + r); } @@ -577,9 +572,10 @@ client_dispatch(ntp_peer_t *p) 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) { - bb_perror_msg("recvfrom(%s) error", addr); + bb_perror_msg("recv(%s) error", addr); if (errno == EHOSTUNREACH || errno == EHOSTDOWN || errno == ENETUNREACH || errno == ENETDOWN || errno == ECONNREFUSED || errno == EADDRNOTAVAIL @@ -693,48 +689,58 @@ client_dispatch(ntp_peer_t *p) static void server_dispatch(int fd) { - ssize_t size; - uint8_t version; - double rectime; - len_and_sockaddr *to; - struct sockaddr *from; - ntp_msg_t query, reply; + ssize_t size; + uint8_t version; + double rectime; + len_and_sockaddr *to; + struct sockaddr *from; + ntp_msg_t msg; + uint8_t query_status; + uint8_t query_ppoll; + l_fixedpt_t query_xmttime; to = get_sock_lsa(G.listen_fd); from = xzalloc(to->len); - 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"); +//TODO: use MGS_DONTWAIT flag? + size = recv_from_to(fd, &msg, sizeof(msg), 0, from, &to->u.sa, to->len); 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); free(addr); goto bail; } - rectime = gettime(); - version = (query.status & VERSION_MASK) >> 3; + query_status = msg.status; + query_ppoll = msg.ppoll; + query_xmttime = msg.xmttime; - memset(&reply, 0, sizeof(reply)); - reply.status = G.status.synced ? G.status.leap : LI_ALARM; - reply.status |= (query.status & VERSION_MASK); - reply.status |= ((query.status & MODE_MASK) == MODE_CLIENT) ? + /* Build a reply packet */ + memset(&msg, 0, sizeof(msg)); + msg.status = G.status.synced ? G.status.leap : LI_ALARM; + msg.status |= (query_status & VERSION_MASK); + msg.status |= ((query_status & MODE_MASK) == MODE_CLIENT) ? MODE_SERVER : MODE_SYM_PAS; - reply.stratum = G.status.stratum; - reply.ppoll = query.ppoll; - reply.precision = G.status.precision; - reply.rectime = d_to_lfp(rectime); - reply.reftime = d_to_lfp(G.status.reftime); - reply.xmttime = d_to_lfp(gettime()); - reply.orgtime = query.xmttime; - reply.rootdelay = d_to_sfp(G.status.rootdelay); - reply.refid = (version > 3) ? G.status.refid4 : G.status.refid; + msg.stratum = G.status.stratum; + msg.ppoll = query_ppoll; + msg.precision = G.status.precision; + rectime = gettime(); + msg.xmttime = msg.rectime = d_to_lfp(rectime); + msg.reftime = d_to_lfp(G.status.reftime); + //msg.xmttime = d_to_lfp(gettime()); // = msg.rectime + msg.orgtime = query_xmttime; + 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, * this makes to/from look swapped here: */ - sendmsg_wrap(fd, /*from:*/ &to->u.sa, /*to:*/ from, /*addrlen:*/ to->len, - &reply, size); + sendmsg_wrap(fd, + /*from:*/ &to->u.sa, /*to:*/ from, /*addrlen:*/ to->len, + &msg, size); bail: free(to); @@ -835,7 +841,8 @@ static NOINLINE void ntp_init(char **argv) unsigned opts; llist_t *peers; - tzset(); + srandom(getpid()); + /* tzset(); - why? it's called automatically when needed, no? */ if (getuid()) 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) { llist_t *item; - unsigned i, j, idx_peers; + unsigned i, j, first_peer_idx; unsigned sent_cnt, trial_cnt; int nfds, timeout; time_t nextaction; @@ -926,7 +933,7 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) i++; } #endif - idx_peers = i; + first_peer_idx = i; sent_cnt = trial_cnt = 0; for (item = g.ntp_peers; item != NULL; item = item->link) { 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) { pfd[i].fd = p->query.fd; pfd[i].events = POLLIN; - idx2peer[i - idx_peers] = p; + idx2peer[i - first_peer_idx] = p; i++; } } @@ -978,7 +985,8 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) j = 0; #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)) { nfds--; server_dispatch(pfd[j].fd); @@ -988,7 +996,7 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) for (; nfds > 0 && j < i; j++) { if (pfd[j].revents & (POLLIN|POLLERR)) { nfds--; - client_dispatch(idx2peer[j - idx_peers]); + client_dispatch(idx2peer[j - first_peer_idx]); } } } /* while (!bb_got_signal) */ -- cgit v1.2.3