--- client.c
+++ client.c
@@ -27,7 +27,6 @@
 #include "ntpd.h"
 
 int	client_update(struct ntp_peer *);
-void	set_deadline(struct ntp_peer *, time_t);
 
 void
 set_next(struct ntp_peer *p, time_t t)
@@ -36,13 +35,55 @@
 	p->deadline = 0;
 }
 
-void
-set_deadline(struct ntp_peer *p, time_t t)
+static void  set_deadline( struct ntp_peer *p, time_t t )
 {
+/*	assert( p!=NULL ); */
 	p->deadline = time(NULL) + t;
+	p->deadlineError = 0;
+	p->next = 0;
+}
+
+static void  set_deadline_error( struct ntp_peer* p )
+{
+/*	assert( p!=NULL ); */
+	p->deadline = time(NULL);
+	p->deadlineError = 1;
 	p->next = 0;
 }
 
+#define CLIENT_UPDATE_GOOD  (good >= 8)
+
+static Tbool  check_client_update( const struct ntp_peer* p )
+{
+/*	assert( p!=NULL ); */
+	int	 i, good = 0;
+	for( i = 0; i<OFFSET_ARRAY_SIZE; ++i )
+		if( p->reply[i].good )  ++good;
+	return CLIENT_UPDATE_GOOD ? 1 : 0;
+}
+
+static time_t  calc_query_interval( struct ntp_peer* p, time_t interval, time_t genuine )
+{
+/*	assert( interval>0 ); */
+	/* here we compare to non-randomized value. we don't want to confuse user */
+	if( genuine<=tmDelayTrust || check_client_update(p) )
+	{	/* client ok, reinit own trust to start "full" cycle next time ...
+		   note: a clock sync will invalidate all our replies. this is, what we want */
+		p->trustFullQuery = MAX( TRUSTLEVEL_PATHETIC, 1 );  /* at least >0 */
+		return interval;  /* ... and go sleep */
+	}
+	if( p->trustFullQuery>0 )
+	{	/* here process our cycle until client is ok for syncing clock */
+		const u_int8_t  lev = p->trustFullQuery;
+		if( lev<TRUSTLEVEL_MAX )
+			++p->trustFullQuery;
+		return scale_interval( lev<TRUSTLEVEL_AGRESSIVE ? INTERVAL_QUERY_AGRESSIVE
+		                                                : INTERVAL_QUERY_NORMAL );
+	}
+	else
+		return scale_interval( INTERVAL_QUERY_NORMAL );  /* original behavior */
+}
+
 int
 client_peer_init(struct ntp_peer *p)
 {
@@ -54,7 +95,7 @@
 	p->shift = 0;
 	p->trustlevel = TRUSTLEVEL_PATHETIC;
 	p->lasterror = 0;
-
+	reset_error_interval(p);
 	return (client_addr_init(p));
 }
 
@@ -118,13 +159,21 @@
 	int	tos = IPTOS_LOWDELAY;
 
 	if (p->addr == NULL && client_nextaddr(p) == -1) {
-		set_next(p, error_interval());
+		set_next(p, error_interval(p,0));
+		p->errorReinit = 1;
 		return (0);
 	}
+	if( p->errorReinit )
+		reset_error_interval( p );
 
 	if (p->state < STATE_DNS_DONE || p->addr == NULL)
 		return (-1);
 
+	/* invalidate to old updates. time delay should be >tmDelayTrust because
+	   randomization and runtime delays. tmDelayTrust*2 is a good choice */
+	if( p->update.good && (p->update.rcvd+tmDelayTrust*2)<time(NULL) )
+		p->update.good = 0;
+
 	if (p->query->fd == -1) {
 		struct sockaddr *sa = (struct sockaddr *)&p->addr->ss;
 
@@ -134,8 +183,9 @@
 		if (connect(p->query->fd, sa, SA_LEN(sa)) == -1) {
 			if (errno == ECONNREFUSED || errno == ENETUNREACH ||
 			    errno == EHOSTUNREACH) {
+				time_t  interval = error_interval(p,1);
 				client_nextaddr(p);
-				set_next(p, error_interval());
+				set_next(p, interval);
 				return (-1);
 			} else
 				fatal("client_query connect");
@@ -165,7 +215,7 @@
 
 	if (ntp_sendmsg(p->query->fd, NULL, &p->query->msg,
 	    NTP_MSGSIZE_NOAUTH, 0) == -1) {
-		set_next(p, INTERVAL_QUERY_PATHETIC);
+		set_deadline_error(p);  /* fix: force trustlevel decrease */
 		return (-1);
 	}
 
@@ -190,7 +240,7 @@
 		    errno == ENETUNREACH || errno == ENETDOWN ||
 		    errno == ECONNREFUSED || errno == EADDRNOTAVAIL) {
 			client_log_error(p, "recvfrom", errno);
-			set_next(p, error_interval());
+			set_deadline_error(p);  /* fix: force trustlevel decrease */
 			return (0);
 		} else
 			fatal("recvfrom");
@@ -206,10 +256,9 @@
 
 	if ((msg.status & LI_ALARM) == LI_ALARM || msg.stratum == 0 ||
 	    msg.stratum > NTP_MAXSTRATUM) {
-		interval = error_interval();
-		set_next(p, interval);
-		log_info("reply from %s: not synced, next query %ds",
-		    log_sockaddr((struct sockaddr *)&p->addr->ss), interval);
+		set_deadline_error(p);  /* fix: force trustlevel decrease */
+		log_info("reply from %s: not synced",
+		    log_sockaddr((struct sockaddr *)&p->addr->ss));
 		return (0);
 	}
 
@@ -235,8 +284,7 @@
 	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) {
-		interval = error_interval();
-		set_next(p, interval);
+		set_deadline_error(p);  /* fix: force trustlevel decrease */
 		log_info("reply from %s: negative delay %f",
 		    log_sockaddr((struct sockaddr *)&p->addr->ss),
 		    p->reply[p->shift].delay);
@@ -256,14 +304,23 @@
 	p->reply[p->shift].status.poll = msg.ppoll;
 	p->reply[p->shift].status.stratum = msg.stratum;
 
-	if (p->trustlevel < TRUSTLEVEL_PATHETIC)
-		interval = scale_interval(INTERVAL_QUERY_PATHETIC);
-	else if (p->trustlevel < TRUSTLEVEL_AGRESSIVE)
-		interval = scale_interval(INTERVAL_QUERY_AGRESSIVE);
+	if( p->trustlevel<TRUSTLEVEL_AGRESSIVE )
+	{
+		p->trustFullQuery = 0;  /* disable our custom query cycle */
+		interval = scale_interval( p->trustlevel<TRUSTLEVEL_PATHETIC ? INTERVAL_QUERY_PATHETIC
+		                                                             : INTERVAL_QUERY_AGRESSIVE );
+	}
 	else
-		interval = scale_interval(INTERVAL_QUERY_NORMAL);
-
+	{
+		time_t  genuine;
+		interval = next_query_interval( &genuine );
+		if( interval==0 )
+			interval = scale_interval( INTERVAL_QUERY_NORMAL );       /* original behavior */
+		else
+			interval = calc_query_interval( p, interval, genuine ) ;  /* custom sync interval */
+	}
 	set_next(p, interval);
+	reset_error_interval(p);
 	p->state = STATE_REPLY_RECEIVED;
 
 	/* every received reply which we do not discard increases trust */
@@ -275,9 +332,10 @@
 		p->trustlevel++;
 	}
 
+	TtimeBuf  tbuf;
 	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);
+	    "next query %s", log_sockaddr((struct sockaddr *)&p->addr->ss),
+	    p->reply[p->shift].offset, p->reply[p->shift].delay, tdiff_to_string(interval,&tbuf));
 
 	client_update(p);
 	if (settime)
@@ -314,7 +372,7 @@
 				best = i;
 		}
 
-	if (good < 8)
+	if (!CLIENT_UPDATE_GOOD)
 		return (-1);
 
 	memcpy(&p->update, &p->reply[best], sizeof(p->update));
--- ntp.c
+++ ntp.c
@@ -54,6 +54,38 @@
 void	peer_remove(struct ntp_peer *);
 int	offset_compare(const void *, const void *);
 
+static int  poll_ex(struct pollfd* fds, nfds_t fdsNum, int timeout, nfds_t pipeIdx, volatile sig_atomic_t* ntpQuit)
+{
+	int  nfds, res = 0, res_imsg = 0;
+	if (ibuf_main->w.queued > 0)
+		fds[pipeIdx].events |= POLLOUT;
+
+	if ((nfds = poll(fds, fdsNum, timeout)) == -1)
+		if (errno != EINTR) {
+			log_warn("poll error");
+			res = -1;
+		}
+
+	if (nfds > 0 && (fds[pipeIdx].revents & POLLOUT))
+		if (msgbuf_write(&ibuf_main->w) < 0) {
+			log_warn("pipe write error (to parent)");
+			res = -1;
+		}
+
+	if (nfds > 0 && fds[pipeIdx].revents & (POLLIN|POLLERR)) {
+		nfds--;
+		if( (res_imsg=ntp_dispatch_imsg())<0 )  res = -1;
+	}
+
+	if( ntpQuit!=NULL )
+	{  
+		if( res<0 )  *ntpQuit = 1;
+	}
+	else
+		nfds = res<0 ? res : res_imsg;
+	return nfds;
+}
+
 void
 ntp_sighdlr(int sig)
 {
@@ -71,6 +103,7 @@
 	int			 a, b, nfds, i, j, idx_peers, timeout, nullfd;
 	u_int			 pfd_elms = 0, idx2peer_elms = 0;
 	u_int			 listener_cnt, new_cnt, sent_cnt, trial_cnt;
+	Tbool			 trust_lost;
 	pid_t			 pid;
 	struct pollfd		*pfd = NULL;
 	struct passwd		*pw;
@@ -103,6 +136,11 @@
 	if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
 		fatal(NULL);
 
+	/* fix: we log to console if nconf->settime true. but later we will dump all output.
+	   not the best solution -> force all logs to syslog from now on for this child process */
+	if (nconf->settime && !nconf->debug)
+		log_init(nconf->debug);
+
 #ifdef NTPD_CHROOT_DIR
 	chrootdir = NTPD_CHROOT_DIR;
 #else
@@ -193,7 +231,8 @@
 
 		bzero(pfd, sizeof(struct pollfd) * pfd_elms);
 		bzero(idx2peer, sizeof(void *) * idx2peer_elms);
-		nextaction = time(NULL) + 3600;
+		/* max. 2147s because of internal overflow in poll() on some platforms */
+		nextaction = time(NULL) + 2147;
 		pfd[PFD_PIPE_MAIN].fd = ibuf_main->fd;
 		pfd[PFD_PIPE_MAIN].events = POLLIN;
 
@@ -206,6 +245,7 @@
 
 		idx_peers = i;
 		sent_cnt = trial_cnt = 0;
+		trust_lost = 0;
 		TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
 			if (p->next > 0 && p->next <= time(NULL)) {
 				if (p->state > STATE_DNS_INPROGRESS)
@@ -219,16 +259,24 @@
 			if (p->deadline > 0 && p->deadline < nextaction)
 				nextaction = p->deadline;
 			if (p->deadline > 0 && p->deadline <= time(NULL)) {
-				timeout = error_interval();
-				log_debug("no reply from %s received in time, "
-				    "next query %ds", log_sockaddr(
-				    (struct sockaddr *)&p->addr->ss), timeout);
+				timeout = error_interval(p,p->deadlineError);
+				if( !p->deadlineError )
+				{
+					TtimeBuf  tbuf;
+					log_debug("no reply from %s received in time, "
+						"next query %s", log_sockaddr(
+						(struct sockaddr *)&p->addr->ss), tdiff_to_string(timeout,&tbuf));
+				}
 				if (p->trustlevel >= TRUSTLEVEL_BADPEER &&
 				    (p->trustlevel /= 2) < TRUSTLEVEL_BADPEER)
+				{
 					log_info("peer %s now invalid",
 					    log_sockaddr(
 					    (struct sockaddr *)&p->addr->ss));
-				client_nextaddr(p);
+					trust_lost = 1;
+				}
+				if( !p->deadlineError )
+					client_nextaddr(p);  /* try next address only if client doesn't respond */
 				set_next(p, timeout);
 			}
 
@@ -244,30 +292,14 @@
 		    ((trial_cnt > 0 && sent_cnt == 0) || peer_cnt == 0))
 			priv_settime(0);	/* no good peers, don't wait */
 
-		if (ibuf_main->w.queued > 0)
-			pfd[PFD_PIPE_MAIN].events |= POLLOUT;
+		if( trust_lost )	 /* at least one client lost its trust. maybe all other clients */
+			priv_adjtime();  /* are valid for syncing, so we should try syncing clock */
 
 		timeout = nextaction - time(NULL);
 		if (timeout < 0)
 			timeout = 0;
 
-		if ((nfds = poll(pfd, i, timeout * 1000)) == -1)
-			if (errno != EINTR) {
-				log_warn("poll error");
-				ntp_quit = 1;
-			}
-
-		if (nfds > 0 && (pfd[PFD_PIPE_MAIN].revents & POLLOUT))
-			if (msgbuf_write(&ibuf_main->w) < 0) {
-				log_warn("pipe write error (to parent)");
-				ntp_quit = 1;
-			}
-
-		if (nfds > 0 && pfd[PFD_PIPE_MAIN].revents & (POLLIN|POLLERR)) {
-			nfds--;
-			if (ntp_dispatch_imsg() == -1)
-				ntp_quit = 1;
-		}
+		nfds = poll_ex(pfd, i, timeout * 1000, PFD_PIPE_MAIN, &ntp_quit);
 
 		for (j = 1; nfds > 0 && j < idx_peers; j++)
 			if (pfd[j].revents & (POLLIN|POLLERR)) {
@@ -280,7 +312,7 @@
 			if (pfd[j].revents & (POLLIN|POLLERR)) {
 				nfds--;
 				if (client_dispatch(idx2peer[j - idx_peers],
-				    conf->settime) == -1)
+						conf->settime||conf->settimeEx) == -1)
 					ntp_quit = 1;
 			}
 	}
@@ -297,7 +329,7 @@
 ntp_dispatch_imsg(void)
 {
 	struct imsg		 imsg;
-	int			 n;
+	int			 n, ret = 0;
 	struct ntp_peer		*peer, *npeer;
 	u_int16_t		 dlen;
 	u_char			*p;
@@ -320,6 +352,7 @@
 
 		switch (imsg.hdr.type) {
 		case IMSG_ADJTIME:
+			ret |= 1L<<IMSG_ADJTIME;
 			memcpy(&n, imsg.data, sizeof(n));
 			if (n == 1 && !conf->status.synced) {
 				log_info("clock is now synced");
@@ -329,7 +362,11 @@
 				conf->status.synced = 0;
 			}
 			break;
+		case IMSG_SETTIME:
+			ret |= 1L<<IMSG_SETTIME;
+			break;
 		case IMSG_HOST_DNS:
+			ret |= 1L<<IMSG_HOST_DNS;
 			TAILQ_FOREACH(peer, &conf->ntp_peers, entry)
 				if (peer->id == imsg.hdr.peerid)
 					break;
@@ -383,7 +420,7 @@
 		}
 		imsg_free(&imsg);
 	}
-	return (0);
+	return (ret);
 }
 
 void
@@ -493,13 +530,25 @@
 	struct ntp_peer *p;
 
 	imsg_compose(ibuf_main, IMSG_SETTIME, 0, 0, &offset, sizeof(offset));
-	conf->settime = 0;
+	conf->settime = conf->settimeEx = 0;
 
 	TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
 		if (p->next)
-			p->next -= offset;
+			p->next += offset;
 		if (p->deadline)
-			p->deadline -= offset;
+			p->deadline += offset;
+	}
+
+	/* wait until time set (max. 5s) to prevent changes during execution of main loop */
+	struct pollfd  pfd;
+	int    i, res;
+	for( i=0; i<10; ++i )
+	{
+		pfd.fd = ibuf_main->fd;
+		pfd.events = POLLIN;
+		res = poll_ex(&pfd, 1, 500, 0, NULL);
+		if (res<0 || (res&(1L<<IMSG_SETTIME))!=0)
+			break;
 	}
 }
 
@@ -514,7 +563,8 @@
 
 void
 update_scale(double offset)
-{
+{	/* do not scale if custom sync intervals */
+	if( conf->syncAt!=NULL || conf->syncEvery!=NULL )  return;
 	if (offset < 0)
 		offset = -offset;
 
@@ -526,23 +576,92 @@
 		conf->scale = QSCALE_OFF_MAX / offset;
 }
 
+static inline time_t  randomize( time_t d )
+{	/* modulo for randomized offset calculation:
+	   10% of d but limited to range tmRandomizeMin..tmRandomizeMax */
+/*	assert( d>=0 ); */
+	const time_t  upperLimit = MIN( tmRandomizeMax, d/10 );
+	const time_t  r = arc4random() % MAX( tmRandomizeMin, upperLimit );
+	return d + r;
+}
+
 time_t
 scale_interval(time_t requested)
 {
-	time_t interval, r;
+	return randomize( requested * conf->scale );
+}
 
-	interval = requested * conf->scale;
-	r = arc4random() % MAX(5, interval / 10);
-	return (interval + r);
+static inline time_t  error_interval_org( void )
+{
+	return randomize( INTERVAL_QUERY_PATHETIC * QSCALE_OFF_MAX / QSCALE_OFF_MIN );
 }
 
-time_t
-error_interval(void)
+static inline time_t  next_sync_at( void )
 {
-	time_t interval, r;
+	if( conf->syncAt==NULL )  return 0;
+	TtimeDelay   current = seconds_since_midnight();
+	TdelayItem*  n;
+	for( n=conf->syncAt; n!=NULL; n=n->next )
+		if( n->val > current )  break;
+	return n!=NULL ? n->val - current                        /* sync this day */
+	               : conf->syncAt->val + 24*3600 - current;  /* snyc next day */
+}
 
-	interval = INTERVAL_QUERY_PATHETIC * QSCALE_OFF_MAX / QSCALE_OFF_MIN;
-	r = arc4random() % (interval / 10);
-	return (interval + r);
+static inline time_t  next_sync_every( void )
+{	/* we support only one sync_every option */
+	return conf->syncEvery!=NULL ? conf->syncEvery->val : 0;
 }
 
+time_t	next_query_interval( time_t* genuine )
+{
+	const time_t  syncAt    = next_sync_at();
+	const time_t  syncEvery = next_sync_every();
+	if( syncEvery==0 || (syncAt!=0 && syncAt<syncEvery) )
+	{	/* if both delays 0 do not randomize */
+		if( genuine!=NULL )  *genuine = syncAt;
+		return syncAt!=0 && conf->syncAtRandomize ? randomize(syncAt) : syncAt;
+	}
+	else
+	{	/* on equal delays we use the randomized one */
+		if( genuine!=NULL )  *genuine = syncEvery;
+		return randomize( syncEvery );
+	}
+}
+
+time_t	error_interval( struct ntp_peer* p, Tbool log )
+{
+/*	assert( p!=NULL ); */
+	time_t  interval;
+	if( p->errorRetry==NULL )
+		interval = error_interval_org();
+	else
+	{
+		if( p->errorRetry->val==tmDelayQuery )
+		{
+			interval = next_query_interval( NULL );
+			if( interval==0 )  /* no custom sync option, return original error interval */
+				interval = error_interval_org();
+		}
+		else
+			interval = randomize( p->errorRetry->val );
+		p->errorRetry = (p->errorRetry->next==NULL || p->errorRetry->next->val==tmDelayRepeat)
+		                  ? conf->errorRetryRepeat : p->errorRetry->next;
+	}
+	if( log )
+	{
+		TtimeBuf  tbuf;
+		tdiff_to_string( interval, &tbuf );
+		if( p->addr!=NULL )
+			log_debug( "%s: next query %s", log_sockaddr((struct sockaddr *)&p->addr->ss), tbuf.str );
+		else
+			log_debug( "next query %s", tbuf.str );
+	}
+	return interval;
+}
+
+void  reset_error_interval( struct ntp_peer* p )
+{
+/*	assert( p!=NULL ); */
+	p->errorRetry  = conf->errorRetry;
+	p->errorReinit = 0;
+}
--- ntpd.c
+++ ntpd.c
@@ -43,7 +43,7 @@
 int		main(int, char *[]);
 int		check_child(pid_t, const char *);
 int		dispatch_imsg(struct ntpd_conf *);
-int		ntpd_adjtime(double);
+int		ntpd_adjtime(double,const struct ntpd_conf *);
 void		ntpd_settime(double);
 
 volatile sig_atomic_t	 quit = 0;
@@ -73,7 +73,7 @@
 {
 	extern char *__progname;
 
-	fprintf(stderr, "usage: %s [-dSs] [-f file]\n", __progname);
+	fprintf(stderr, "usage: %s [-dSsw] [-f file]\n", __progname);
 	exit(1);
 }
 
@@ -100,7 +100,7 @@
 	log_init(1);		/* log to stderr until daemonized */
 	res_init();		/* XXX */
 
-	while ((ch = getopt(argc, argv, "df:sS")) != -1) {
+	while ((ch = getopt(argc, argv, "df:sSw")) != -1) {
 		switch (ch) {
 		case 'd':
 			conf.debug = 1;
@@ -109,10 +109,15 @@
 			conffile = optarg;
 			break;
 		case 's':
-			conf.settime = 1;
+			conf.settime   = 1;
+			conf.settimeEx = 0;
 			break;
 		case 'S':
-			conf.settime = 0;
+			conf.settime = conf.settimeEx = 0;
+			break;
+		case 'w':
+			conf.settime   = 0;
+			conf.settimeEx = 1;
 			break;
 		default:
 			usage();
@@ -226,6 +231,7 @@
 
 	msgbuf_clear(&ibuf->w);
 	free(ibuf);
+	cleanup_config(&conf);
 	log_info("Terminating");
 	return (0);
 }
@@ -283,22 +289,24 @@
 			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d))
 				fatalx("invalid IMSG_ADJTIME received");
 			memcpy(&d, imsg.data, sizeof(d));
-			n = ntpd_adjtime(d);
+			n = ntpd_adjtime(d,conf);
 			imsg_compose(ibuf, IMSG_ADJTIME, 0, 0, &n, sizeof(n));
 			break;
 		case IMSG_SETTIME:
 			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d))
 				fatalx("invalid IMSG_SETTIME received");
-			if (!conf->settime)
+			if (!conf->settime && !conf->settimeEx)
 				break;
-			log_init(conf->debug);
+			if (conf->settime)
+				log_init(conf->debug);
 			memcpy(&d, imsg.data, sizeof(d));
 			ntpd_settime(d);
-			/* daemonize now */
-			if (!conf->debug)
+			/* daemonize now if genuine settime option */
+			if (conf->settime && !conf->debug)
 				if (daemon(1, 0))
 					fatal("daemon");
-			conf->settime = 0;
+			conf->settime = conf->settimeEx = 0;
+			imsg_compose(ibuf, IMSG_SETTIME, 0, 0, &d, sizeof(d));
 			break;
 		case IMSG_HOST_DNS:
 			name = imsg.data;
@@ -328,18 +336,57 @@
 	return (0);
 }
 
+static void  ntpd_settime_ex( double d )
+{
+	struct timeval	tv, curtime;
+	char		buf[80];
+	time_t		tval;
+	TtimeBuf	tbuf;
+
+	if (gettimeofday(&curtime, NULL) == -1) {
+		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 %= 1000000;
+
+	if (settimeofday(&curtime, NULL) == -1) {
+		log_warn("settimeofday");
+		return;
+	}
+	tval = curtime.tv_sec;
+	strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y",
+	    localtime(&tval));
+	tdiff_to_string( d, &tbuf );
+	if (d >= (double)LOG_NEGLIGEE / 1000 ||
+	    d <= -1 * (double)LOG_NEGLIGEE / 1000)
+		log_info("set local clock to %s (offset %s)", buf, tbuf.str);
+	else
+		log_debug("set local clock to %s (offset %s)", buf, tbuf.str);
+}
+
 int
-ntpd_adjtime(double d)
+ntpd_adjtime(double d,const struct ntpd_conf *conf)
 {
+	if( conf->syncAt!=NULL || conf->syncEvery!=NULL )
+	{	/* custom sync intervals, so we use settime */
+		ntpd_settime_ex( d );
+		return 1;
+	}
+
 	struct timeval	tv, olddelta;
 	int		synced = 0;
+	TtimeBuf	tbuf;
 	static int	firstadj = 1;
 
+	tdiff_to_string( d, &tbuf );
 	if (d >= (double)LOG_NEGLIGEE / 1000 ||
 	    d <= -1 * (double)LOG_NEGLIGEE / 1000)
-		log_info("adjusting local clock by %fs", d);
+		log_info("adjusting local clock by %s", tbuf.str);
 	else
-		log_debug("adjusting local clock by %fs", d);
+		log_debug("adjusting local clock by %s", tbuf.str);
 	d_to_tv(d, &tv);
 	if (adjtime(&tv, &olddelta) == -1)
 		log_warn("adjtime failed");
@@ -352,29 +399,8 @@
 void
 ntpd_settime(double d)
 {
-	struct timeval	tv, curtime;
-	char		buf[80];
-	time_t		tval;
-
 	/* if the offset is small, don't call settimeofday */
 	if (d < SETTIME_MIN_OFFSET && d > -SETTIME_MIN_OFFSET)
 		return;
-
-	if (gettimeofday(&curtime, NULL) == -1) {
-		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 %= 1000000;
-
-	if (settimeofday(&curtime, NULL) == -1) {
-		log_warn("settimeofday");
-		return;
-	}
-	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);
+	ntpd_settime_ex( d );
 }
--- ntpd.h
+++ ntpd.h
@@ -63,6 +63,25 @@
 #define	SETTIME_TIMEOUT		15	/* max seconds to wait with -s */
 #define	LOG_NEGLIGEE		128	/* negligible drift to not log (ms) */
 
+typedef u_int32_t		 TtimeDelay;
+typedef u_int8_t		 Tbool;
+static const TtimeDelay	 tmDelayQuery   =  0;     /* special delay value (until next query) */
+static const TtimeDelay	 tmDelayRepeat  = -1;     /* special delay value (repeat sequence) */
+static const TtimeDelay	 tmDelayMin     = 10;     /* min time delay supported for sync & error intervals */
+static const TtimeDelay	 tmDelayMax     = 7*24*3600;  /* max time delay supported for sync & error intervals */
+static const time_t	     tmDelayTrust   = 30*60;  /* if last query exceeds delay, we start full query cycle */
+static const time_t	     tmRandomizeMin =  5;     /* min randomized offset is maximum of 5s or delay/10 */
+static const time_t	     tmRandomizeMax = 90;     /* max randomized offset is 90 sec */
+
+typedef struct time_delay {
+	struct time_delay*	 next;
+	TtimeDelay			 val;
+} TdelayItem;
+
+typedef struct time_buf {
+	char	 str[64];
+} TtimeBuf;
+
 enum client_state {
 	STATE_NONE,
 	STATE_DNS_INPROGRESS,
@@ -121,10 +140,14 @@
 	enum client_state		 state;
 	time_t				 next;
 	time_t				 deadline;
+	Tbool			 deadlineError;
 	u_int32_t			 id;
 	u_int8_t			 shift;
 	u_int8_t			 trustlevel;
+	u_int8_t			 trustFullQuery;
 	int				 lasterror;
+	TdelayItem*				errorRetry;
+	Tbool				 errorReinit;
 };
 
 struct ntpd_conf {
@@ -133,8 +156,14 @@
 	struct ntp_status			status;
 	u_int8_t				listen_all;
 	u_int8_t				settime;
+	Tbool					settimeEx;
 	u_int8_t				debug;
 	u_int32_t				scale;
+	TdelayItem*				syncAt;
+	Tbool					syncAtRandomize;
+	TdelayItem*				syncEvery;
+	TdelayItem*				errorRetry;
+	TdelayItem*				errorRetryRepeat;
 };
 
 struct buf {
@@ -229,6 +258,7 @@
 
 /* parse.y */
 int	 parse_config(const char *, struct ntpd_conf *);
+void	 cleanup_config(struct ntpd_conf *);
 
 /* config.c */
 int		 host(const char *, struct ntp_addr **);
@@ -253,13 +283,17 @@
 void	client_log_error(struct ntp_peer *, const char *, int);
 void	update_scale(double);
 time_t	scale_interval(time_t);
-time_t	error_interval(void);
+time_t	next_query_interval(time_t*);
+time_t	error_interval(struct ntp_peer *, Tbool);
+void	reset_error_interval(struct ntp_peer *);
 void	set_next(struct ntp_peer *, time_t);
 
 /* util.c */
 double			gettime(void);
+TtimeDelay		seconds_since_midnight(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);
+const char*		tdiff_to_string(double, TtimeBuf*);
--- parse.y
+++ parse.y
@@ -43,6 +43,17 @@
 static int			 errors = 0;
 const char			*infile;
 
+static const char    chDelayQuery = '*', chDelayRepeat = 'r';
+static size_t        errorRetryNumRepeat;
+
+static TdelayItem*   delayListMerge(TdelayItem* toEntry,TdelayItem* entry);
+static TdelayItem*   delayListMergeSorted(TdelayItem* toEntry,TdelayItem* entry);
+static TdelayItem*   delayListReverse(TdelayItem* entry);
+static void          delayListFree(TdelayItem* entry);
+static TdelayItem*   parseTime(char* str);
+static TdelayItem*   parseDelay(char* str,size_t* numRepeat);
+static Tbool         checkDelayRepeat(const TdelayItem* toEntry,const TdelayItem* entry);
+
 int	 yyerror(const char *, ...);
 int	 yyparse(void);
 int	 kw_cmp(const void *, const void *);
@@ -57,6 +68,7 @@
 		u_int32_t		 number;
 		char			*string;
 		struct ntp_addr_wrap	*addr;
+		TdelayItem		*delay;
 	} v;
 	int lineno;
 } YYSTYPE;
@@ -66,8 +78,13 @@
 %token	LISTEN ON
 %token	SERVER SERVERS
 %token	ERROR
-%token	<v.string>		STRING
-%type	<v.addr>		address
+%token	SYNC AT EVERY RANDOMIZE
+%token	ERR RETRY
+%token	<v.string>	STRING QUOTED
+%type		<v.string>		TEXT
+%type		<v.addr>		address
+%type		<v.delay>		syncDelay  syncDelays
+%type		<v.delay>		errDelay   errDelays
 %%
 
 grammar		: /* empty */
@@ -178,9 +195,33 @@
 			free($2->name);
 			free($2);
 		}
+		| SYNC AT RANDOMIZE	{
+			conf->syncAtRandomize = 1;
+		}
+		| SYNC AT syncDelays	{
+			conf->syncAt = delayListMergeSorted( conf->syncAt, $3 );
+		}
+		| SYNC EVERY STRING	{
+			if( conf->syncEvery!=NULL ) {  /* we support only one delay here */
+				yyerror( "option \"sync every\" allowed only once" );
+				free( $3 );
+				YYERROR;
+			}
+			if( (conf->syncEvery=parseDelay($3,NULL))==NULL )  YYERROR;
+		}
+		| ERR RETRY errDelays	{
+			if( !checkDelayRepeat( conf->errorRetry, $3 ) ) {
+				delayListFree( $3 );
+				YYERROR;
+			}
+			conf->errorRetry = delayListMerge( conf->errorRetry, $3 );
+		}
 		;
 
-address		: STRING		{
+TEXT	: STRING | QUOTED
+		;
+
+address		: TEXT		{
 			if (($$ = calloc(1, sizeof(struct ntp_addr_wrap))) ==
 			    NULL)
 				fatal(NULL);
@@ -195,6 +236,26 @@
 		}
 		;
 
+syncDelay	: STRING	{ if( ($$=parseTime($1))==NULL)  YYERROR; }
+		;
+
+syncDelays	: syncDelays syncDelay	{ $$=delayListMergeSorted( $1, $2 ); }
+		|	syncDelay
+		;
+errDelay	: STRING	{ if( ($$=parseDelay($1,&errorRetryNumRepeat))==NULL)  YYERROR; }
+		;
+
+errDelays	: errDelays errDelay	{
+			if( !checkDelayRepeat( $1, NULL ) ) {
+				delayListFree( $1 );
+				delayListFree( $2 );
+				YYERROR;
+			}
+			$$=delayListMerge( $1, $2 );
+		}
+		|	errDelay
+		;
+
 %%
 
 struct keywords {
@@ -229,10 +290,16 @@
 {
 	/* this has to be sorted always */
 	static const struct keywords keywords[] = {
+		{ "at",		AT},
+		{ "error",		ERR},
+		{ "every",		EVERY},
 		{ "listen",		LISTEN},
 		{ "on",			ON},
+		{ "randomize",		RANDOMIZE},
+		{ "retry",		RETRY},
 		{ "server",		SERVER},
-		{ "servers",		SERVERS}
+		{ "servers",		SERVERS},
+		{ "sync",		SYNC},
 	};
 	const struct keywords	*p;
 
@@ -372,7 +439,7 @@
 		yylval.v.string = strdup(buf);
 		if (yylval.v.string == NULL)
 			fatal("yylex: strdup");
-		return (STRING);
+		return (QUOTED);
 	}
 
 #define allowed_in_string(x) \
@@ -413,6 +480,9 @@
 	errors = 0;
 	TAILQ_INIT(&conf->listen_addrs);
 	TAILQ_INIT(&conf->ntp_peers);
+	xconf->syncAt = xconf->syncEvery = xconf->errorRetry = NULL;
+	xconf->syncAtRandomize = 0;
+	errorRetryNumRepeat    = 1;  /* repeat last item by default */
 
 	if ((fin = fopen(filename, "r")) == NULL) {
 		log_warn("%s", filename);
@@ -424,5 +494,224 @@
 
 	fclose(fin);
 
+	if( errors )
+		cleanup_config( xconf );
+	else
+	{
+		xconf->errorRetry = delayListReverse( xconf->errorRetry );
+		TdelayItem*  n = xconf->errorRetry;
+		if( errorRetryNumRepeat>0 )
+		{
+			int  num;
+			for( num=0; n!=NULL && n->val!=tmDelayRepeat; n=n->next,++num )  {}
+			n = xconf->errorRetry;
+			for( num-=errorRetryNumRepeat; num>0; n=n->next,--num )  {}
+		}
+		xconf->errorRetryRepeat = n;
+	}
+
 	return (errors ? -1 : 0);
 }
+
+void  cleanup_config( struct ntpd_conf* xconf )
+{
+/*	assert( xconf!=NULL ); */
+	while( !TAILQ_EMPTY(&xconf->listen_addrs) )
+	{
+		struct listen_addr*  addr = TAILQ_FIRST( &xconf->listen_addrs );
+		TAILQ_REMOVE( &xconf->listen_addrs, addr, entry );
+		free( addr );
+	}
+	while( !TAILQ_EMPTY(&xconf->ntp_peers) )
+	{
+		struct ntp_peer*  peer = TAILQ_FIRST( &xconf->ntp_peers );
+		TAILQ_REMOVE( &xconf->ntp_peers, peer, entry );
+		free( peer );
+	}
+	delayListFree( xconf->syncAt );
+	delayListFree( xconf->syncEvery );
+	delayListFree( xconf->errorRetry );
+	xconf->syncAt = xconf->syncEvery = xconf->errorRetry = xconf->errorRetryRepeat = NULL;
+}
+
+TdelayItem*  delayListMerge( TdelayItem* toEntry, TdelayItem* entry )
+{
+/*	assert( entry!=NULL ); */
+	if( toEntry!=NULL )
+	{
+		TdelayItem*  n;
+		for( n=entry; n->next!=NULL; n=n->next )  {}
+		n->next = toEntry;
+	}
+	return entry;
+}
+
+TdelayItem*  delayListMergeSorted( TdelayItem* toEntry, TdelayItem* entry )
+{	/* toEntry and entry needs to be sorted! */
+	TdelayItem  head, *to, *from;
+	head.next = toEntry;
+	for( to=&head,from=entry; to->next!=NULL && from!=NULL; to=to->next )
+	{
+		if( from->val < to->next->val )
+		{	/* less, insert at current destination */
+			TdelayItem*  t = from;
+			from = from->next;
+			t->next = to->next;
+			to->next = t;
+		}
+		else if( from->val == to->next->val )
+		{	/* equal, remove item */
+			TdelayItem*  t = from;
+			from = from->next;
+			free( t );
+		}
+	}
+	if( from!=NULL )
+		to->next = from;  /* append sorted rest */
+	return head.next;
+}
+
+TdelayItem*  delayListReverse( TdelayItem* entry )
+{
+	TdelayItem  *to, *from;
+	for( to=NULL,from=entry; from!=NULL; )
+	{
+		TdelayItem*  t = from;
+		from = from->next;
+		t->next = to;
+		to = t;
+	}
+	return to;
+}
+
+void  delayListFree( TdelayItem* entry )
+{
+	TdelayItem*  n;
+	for( n=entry; n!=NULL; )
+	{
+		TdelayItem*  t = n;
+		n = n->next;
+		free( t );
+	}
+}
+
+static int  parseDigits2( const char** p )
+{
+	const char*  s = *p;
+	if( !isdigit(s[0]) || !isdigit(s[1]) )
+		return -1;
+	*p += 2;
+	return (s[0]-'0') * 10 + s[1]-'0';
+}
+
+static int  parseDigits1( const char** p )
+{
+	int  res = parseDigits2( p );
+	if( res<0 && isdigit(**p) )
+		return *(*p)++ - '0';
+	return res;
+}
+
+TdelayItem*  parseTime( char* str )
+{
+/*	assert( str!=NULL ); */
+	const char*  p = str;
+	int          h, m, s = 0;
+	/* time format -> {h}h:mm{:ss} */
+	if( (h=parseDigits1(&p))>=0 && *p++==':' && (m=parseDigits2(&p))>=0 &&     /* parse {h}h:mm */
+	    ( *p=='\0' || (*p++==':' && (s=parseDigits2(&p))>=0 && *p=='\0') ) &&  /* parse {:ss} */
+	    h<24 && m<60 && s<60 )                                                 /* validate h/m/s */
+	{
+		free(str);
+		TdelayItem*  res = calloc( 1, sizeof(TdelayItem) );
+		if( res==NULL )
+			fatal( NULL );
+		res->val = (h*60 + m)*60 + s;
+		return res;
+	}
+	else
+	{
+		yyerror( "could not parse time \"%s\"", str );
+		free( str );
+		return NULL;
+	}
+}
+
+static int  parseSuffix( const char* str )
+{
+/*	assert( str!=NULL ); */
+	if( *str=='\0' )      return 1;     /* no suffix -> seconds */
+	if( str[1]!='\0' )    return -1;    /* suffix has more chars -> error */
+	if( *str=='s' )       return 1;     /* seconds */
+	else if( *str=='m' )  return 60;    /* minutes */
+	else if( *str=='h' )  return 3600;  /* hours */
+	else                  return -1;    /* error */
+}
+
+TdelayItem*  parseDelay( char* str, size_t* numRepeat )
+{
+/*	assert( str!=NULL ); */
+	TtimeDelay  delay;
+	if( numRepeat && *str==chDelayQuery && str[1]=='\0' )
+		delay = tmDelayQuery;
+	else if( numRepeat && *str==chDelayRepeat )
+	{	/* allowed suffixes for repeat -> 1..n or nothing */
+		const char*  beg = str+1;
+		char*  end;
+		long   val = strtol( beg, &end, 10 );
+		if( val<0 || val==LONG_MAX || (val==0 && beg!=end) || *end!='\0' )
+			goto errDelay;
+		*numRepeat = val;
+		delay = tmDelayRepeat;
+	}
+	else
+	{
+		int    suffix;
+		char*  end;
+		long   val = strtol( str, &end, 10 );
+		if( val<0 || val==LONG_MAX || (val==0 && str==end) || (suffix=parseSuffix(end))<0 )
+			goto errDelay;
+		delay = val * suffix;
+		if( delay<tmDelayMin || delay>tmDelayMax )
+		{
+			TtimeBuf  tbufMin, tbufMax;
+			yyerror( "time delay \"%s\" out of range (%s .. %s)", str,
+				tdiff_to_string(tmDelayMin,&tbufMin), tdiff_to_string(tmDelayMax,&tbufMax) );
+			free( str );
+			return NULL;
+		}
+	}
+	free(str);
+	TdelayItem*  res = calloc( 1, sizeof(TdelayItem) );
+	if( res==NULL )
+		fatal( NULL );
+	res->val = delay;
+	return res;
+errDelay:
+	yyerror( "could not parse time delay \"%s\"", str );
+	free( str );
+	return NULL;
+}
+
+Tbool  checkDelayRepeat( const TdelayItem* toEntry, const TdelayItem* entry )
+{
+	if( toEntry!=NULL && toEntry->val==tmDelayRepeat )
+	{
+		yyerror( "further items follow time delay \"%c\"", chDelayRepeat );
+		return 0;
+	}
+	if( entry==NULL || entry->val!=tmDelayRepeat )
+		return 1;  /* no repeat found, everything ok */
+
+	size_t  num;
+	const TdelayItem*  n = toEntry;
+	for( num=0; n!=NULL; n=n->next,++num )  {}          /* count last items */
+	for( n=entry->next; n!=NULL; n=n->next,++num )  {}  /* add count of new items (without repeat) */
+	if( num==0 )
+		yyerror( "time delay \"%c\" is first item", chDelayRepeat );
+	else if( num<errorRetryNumRepeat )
+		yyerror( "time delay \"%c\" out of range (1 .. %d)", chDelayRepeat, num );
+	else
+		return 1;  /* repeat ok */
+	return 0;
+}
--- util.c
+++ util.c
@@ -32,6 +32,14 @@
 	return (tv.tv_sec + JAN_1970 + 1.0e-6 * tv.tv_usec);
 }
 
+TtimeDelay  seconds_since_midnight( void )
+{
+	time_t      t  = time( NULL );
+	struct tm*  lt = localtime( &t );
+	if( lt==NULL )
+		fatal( "localtime" );
+	return lt->tm_hour*3600 + lt->tm_min*60 + lt->tm_sec;
+}
 
 void
 d_to_tv(double d, struct timeval *tv)
@@ -87,3 +95,30 @@
 
 	return (sfp);
 }
+
+const char*  tdiff_to_string( double diff, TtimeBuf* buf )
+{
+/*	assert( buf!=NULL && sizeof(buf->str)>=64 ); */
+	static const int  mn = MAX(INT_MIN,-2147483647-1);  /** min -68 years */
+	static const int  mx = MIN(INT_MAX, 2147483647);    /** max  68 years */
+	char*  p = buf->str;
+	if( diff<0 )  *p++ = '-';
+	if( diff<mn || diff>mx )  /* prevent buffer overflow */
+		strcpy( p, "INFs" );
+	else
+	{
+		double  s = (diff<0 ? -diff : diff) + .0000005;  /* round to precision */
+		int     m, h, d = (int)s, prec = 6;   /* max decimal precision */
+		int     dec = (int)((s-d)*1000000.);  /* "shift" decimals according precision */
+		for( ; prec>0; --prec,dec/=10 )       /* remove all trailing '0' */
+			if( (dec%10)!=0 )  break;
+		d /= 60;  m = d%60;  s -= d*60;
+		d /= 60;  h = d%24;
+		d /= 24;
+		if( d>0 )       sprintf( p, "%dd %dh %dm %.*fs", d, h, m, prec, s );
+		else if( h>0 )  sprintf( p, "%dh %dm %.*fs", h, m, prec, s );
+		else if( m>0 )  sprintf( p, "%dm %.*fs", m, prec, s );
+		else            sprintf( p, "%.*fs", prec, s );
+	}
+	return buf->str;
+}
