#endif
#define SYSLOG_CLASS LOG_DAEMON
+#define INITIAL_TIMER 10
char *def_realm = NULL;
int runonce = 0;
+/*
+ * Global fd to close upon alarm time-out.
+ */
+volatile int gfd = -1;
+
/*
* This struct simulates the use of _kadm5_server_handle_t
*
exit(ret);
}
+void resync_alarm(int sn)
+{
+ close (gfd);
+ if (debug)
+ fprintf(stderr, _("resync_alarm: closing fd: %d\n"), gfd);
+ gfd = -1;
+}
+
int do_standalone(iprop_role iproprole)
{
struct sockaddr_in my_sin, frominet;
int finet, s;
GETPEERNAME_ARG3_TYPE fromlen;
int ret;
+ /*
+ * Timer for accept/read calls, in case of network type errors.
+ */
+ int backoff_timer = INITIAL_TIMER;
+
+retry:
finet = socket(AF_INET, SOCK_STREAM, 0);
if (finet < 0) {
if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on)) < 0)
com_err(progname, errno,
- _("in setsockopt(SO_REUSEADDR)"));
+ _("while setting socket option (SO_REUSEADDR)"));
linger.l_onoff = 1;
linger.l_linger = 2;
if (setsockopt(finet, SOL_SOCKET, SO_LINGER,
(void *)&linger, sizeof(linger)) < 0)
com_err(progname, errno,
- _("in setsockopt(SO_LINGER)"));
+ _("while setting socket option (SO_LINGER)"));
+ /*
+ * We also want to set a timer so that the slave is not waiting
+ * until infinity for an update from the master.
+ */
+ gfd = finet;
+ signal(SIGALRM, resync_alarm);
+ if (debug) {
+ fprintf(stderr, "do_standalone: setting resync alarm to %d\n",
+ backoff_timer);
+ }
+ if (alarm(backoff_timer) != 0) {
+ if (debug) {
+ fprintf(stderr,
+ _("%s: alarm already set\n"), progname);
+ }
+ }
+ backoff_timer *= 2;
}
if ((ret = bind(finet, (struct sockaddr *) &my_sin, sizeof(my_sin))) < 0) {
if (debug) {
s = accept(finet, (struct sockaddr *) &frominet, &fromlen);
if (s < 0) {
- if (errno != EINTR)
- com_err(progname, errno,
- "from accept system call");
- continue;
+ int e = errno;
+ if (e != EINTR) {
+ com_err(progname, e,
+ _("while accepting connection"));
+ if (e != EBADF)
+ backoff_timer = INITIAL_TIMER;
+ }
+ /*
+ * If we got EBADF, an alarm signal handler closed
+ * the file descriptor on us.
+ */
+ if (e != EBADF)
+ close(finet);
+ /*
+ * An alarm could have been set and the fd closed, we
+ * should retry in case of transient network error for
+ * up to a couple of minutes.
+ */
+ if (backoff_timer > 120)
+ return EINTR;
+ goto retry;
}
+ alarm(0);
+ gfd = -1;
if (debug && iproprole != IPROP_SLAVE)
child_pid = 0;
else
close(s);
_exit(0);
default:
+ /*
+ * Errors should not be considered fatal in the
+ * iprop case as we could have transient type
+ * errors, such as network outage, etc. Sleeping
+ * 3s for 2s linger interval.
+ */
if (wait(&status) < 0) {
com_err(progname, errno,
_("while waiting to receive database"));
- exit(1);
+ if (iproprole != IPROP_SLAVE)
+ exit(1);
+ sleep(3);
}
close(s);
krb5_enctype etype;
int database_fd;
+ if (kpropd_context->kdblog_context &&
+ kpropd_context->kdblog_context->iproprole == IPROP_SLAVE) {
+ /*
+ * We also want to set a timer so that the slave is not waiting
+ * until infinity for an update from the master.
+ */
+ if (debug)
+ fprintf(stderr, "doit: setting resync alarm to 5s\n");
+ signal(SIGALRM, resync_alarm);
+ gfd = fd;
+ if (alarm(5) != 0) {
+ if (debug) {
+ fprintf(stderr,
+ _("%s: alarm already set\n"), progname);
+ }
+ }
+ }
fromlen = sizeof (from);
if (getpeername(fd, (struct sockaddr *) &from, &fromlen) < 0) {
#ifdef ENOTSOCK
*/
kerberos_authenticate(kpropd_context, fd, &client, &etype, from);
+ /*
+ * Turn off alarm upon successful authentication from master.
+ */
+ alarm(0);
+
if (!authorized_principal(kpropd_context, client, etype)) {
char *name;
* the full dump
*/
ret = do_standalone(log_ctx->iproprole);
- if (ret)
- syslog(LOG_WARNING,
- _("kpropd: Full resync, "
- "invalid return."));
if (debug) {
if (ret)
fprintf(stderr,
_("Full resync "
"was successful\n"));
}
- frdone = 1;
+ if (ret) {
+ syslog(LOG_WARNING,
+ _("kpropd: Full resync, invalid return."));
+ frdone = 0;
+ } else
+ frdone = 1;
break;
case UPDATE_BUSY:
} else if (error->error) {
com_err(progname,
(krb5_error_code) error->error + ERROR_TABLE_BASE_krb5,
- "signalled from server");
+ "signaled from server");
if (error->text.data)
fprintf(stderr,
"Error text from client: %s\n",