char *netrc_file, *tmpbuf;
pid_t pid;
int lastsig = 0;
+ time_t awoke = 0, due = 0;
#if defined(__FreeBSD__) && defined(__FreeBSD_USE_KVM)
dropprivs();
continue;
}
+ /* check due counts on idle connections */
+ if (awoke < due && !ctl->server.idle_ready)
+ {
+ if (outlevel >= O_VERBOSE)
+ report(stdout,
+ GT_("no idle data available, not querying %s\n"),
+ ctl->server.pollname);
+ continue;
+ }
+
/* check skip interval first so that it counts all polls */
if (run.poll_interval && ctl->server.interval)
{
* spinning uselessly.
*/
int unwedged = 0;
+ int delay = 0;
+ time_t now = 0;
for (ctl = querylist; ctl; ctl = ctl->next)
if (ctl->active && !(implicitmode && ctl->server.skip))
if (getuid() == ROOT_UID)
set_signal_handler(SIGHUP, donothing);
+ /*
+ * Calculate next wakeup time (due) and how long we have to
+ * sleep to get there (delay). Idle polls may occur during the
+ * middle of the sleep so we can't just sleep the full amount
+ * every time.
+ *
+ * Also watch for clock adjustments so we don't get stuck.
+ */
+ now = time(NULL);
+ if (awoke >= due)
+ {
+ delay = run.poll_interval;
+ due = now + delay;
+ report(stdout, GT_("Full poll completed\n"));
+ }
+ else if (now >= due)
+ {
+ awoke = now;
+ report(stdout, GT_("Poll interval expired during idle poll, skipping sleep\n"));
+ continue;
+ }
+ else if ((due-now) > run.poll_interval)
+ {
+ delay = run.poll_interval;
+ due = now + delay;
+ report(stdout, GT_("Great Scott! Someone must have reset the clocks!\n"));
+ }
+ else
+ {
+ delay = due-now;
+ report(stdout, GT_("Idle poll finished, polling in %d seconds.\n"));
+ }
+
/*
* OK, now pause until it's time for the next poll cycle.
* A nonzero return indicates we received a wakeup signal;
* unwedge all servers in case the problem has been
* manually repaired.
*/
- if ((lastsig = interruptible_idle(run.poll_interval)))
+ if ((lastsig = interruptible_idle(delay)))
{
if (outlevel > O_SILENT)
#ifdef SYS_SIGLIST_DECLARED
if ((outlevel > O_SILENT && !run.use_syslog && isatty(1))
|| outlevel > O_NORMAL)
report(stdout, GT_("awakened at %s\n"), timestamp());
+
+ /* force full poll when we wakeup from a signal */
+ awoke = time(NULL);
+ if (lastsig)
+ due = awoke;
}
} while (run.poll_interval);
#include <signal.h>
#include <errno.h>
#include <fetchmail.h> /* for ROOT_UID */
+#include <socket.h> /* for SockClose */
#ifndef TRUE
#define TRUE 1
struct timeval timeout;
struct query *ctl;
int maxfd;
- fd_set rfds;
+ fd_set rfds, efds;
timeout.tv_sec = seconds;
timeout.tv_usec = 0;
*/
maxfd = 0;
FD_ZERO(&rfds);
+ FD_ZERO(&efds);
for (ctl = querylist; ctl; ctl = ctl->next) {
if (ctl->server.idle_socket) {
FD_SET(ctl->server.idle_socket, &rfds);
+ FD_SET(ctl->server.idle_socket, &efds);
if (ctl->server.idle_socket > maxfd)
maxfd = ctl->server.idle_socket;
ctl->server.idle_ready = FALSE;
/* Wait for the next event */
do {
lastsig = 0;
- select(maxfd+1, &rfds,0,0, &timeout);
+ if (select(maxfd+1, &rfds,0,&efds, &timeout) < 0) {
+ /* fds are invalid on errors */
+ FD_ZERO(&rfds);
+ FD_ZERO(&efds);
+ }
} while (lastsig == SIGCHLD);
/* Set ready flags on sockets with data available */
report(stdout, "IDLE> data available on socket=%d\n",
ctl->server.idle_socket);
}
+ if (ctl->server.idle_socket &&
+ FD_ISSET(ctl->server.idle_socket, &efds)) {
+ SockClose(ctl->server.idle_socket);
+ ctl->server.idle_socket = 0;
+ report(stdout, "IDLE> error on socket=%d\n",
+ ctl->server.idle_socket);
+ }
}
#endif
if (lastsig == SIGUSR1 || ((seconds && getuid() == ROOT_UID)