aboutsummaryrefslogtreecommitdiff
path: root/lib/krb5/send_to_kdc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/krb5/send_to_kdc.c')
-rw-r--r--lib/krb5/send_to_kdc.c72
1 files changed, 54 insertions, 18 deletions
diff --git a/lib/krb5/send_to_kdc.c b/lib/krb5/send_to_kdc.c
index 066b849a7576..a920db78b649 100644
--- a/lib/krb5/send_to_kdc.c
+++ b/lib/krb5/send_to_kdc.c
@@ -314,6 +314,7 @@ static void
debug_host(krb5_context context, int level, struct host *host, const char *fmt, ...)
{
const char *proto = "unknown";
+ const char *state;
char name[NI_MAXHOST], port[NI_MAXSERV];
char *text = NULL;
va_list ap;
@@ -339,8 +340,17 @@ debug_host(krb5_context context, int level, struct host *host, const char *fmt,
name, sizeof(name), port, sizeof(port), NI_NUMERICHOST) != 0)
name[0] = '\0';
- _krb5_debug(context, level, "%s: %s %s:%s (%s) tid: %08x", text,
- proto, name, port, host->hi->hostname, host->tid);
+ switch (host->state) {
+ case CONNECT: state = "CONNECT"; break;
+ case CONNECTING: state = "CONNECTING"; break;
+ case CONNECTED: state = "CONNECTED"; break;
+ case WAITING_REPLY: state = "WAITING_REPLY"; break;
+ case DEAD: state = "DEAD"; break;
+ default: state = "unknown"; break;
+ }
+
+ _krb5_debug(context, level, "%s: %s %s:%s (%s) state=%s tid: %08x", text,
+ proto, name, port, host->hi->hostname, state, host->tid);
free(text);
}
@@ -881,11 +891,18 @@ submit_request(krb5_context context, krb5_sendto_ctx ctx, krb5_krbhst_info *hi)
host->tries = host->fun->ntries;
/*
- * Connect directly next host, wait a host_timeout for each next address
+ * Connect directly next host, wait a host_timeout for each next address.
+ * We try host_connect() here, checking the return code because as we do
+ * non-blocking connects, any error here indicates that the address is just
+ * offline. That is, it's something like "No route to host" which is not
+ * worth retrying. And so, we fail directly and immediately to the next
+ * address for this host without enqueueing the address for retries.
*/
- if (submitted_host == 0)
+ if (submitted_host == 0) {
host_connect(context, ctx, host);
- else {
+ if (host->state == DEAD)
+ continue;
+ } else {
debug_host(context, 5, host,
"Queuing host in future (in %ds), its the %lu address on the same name",
(int)(context->host_timeout * submitted_host), submitted_host + 1);
@@ -893,16 +910,14 @@ submit_request(krb5_context context, krb5_sendto_ctx ctx, krb5_krbhst_info *hi)
}
heim_array_append_value(ctx->hosts, host);
-
heim_release(host);
-
submitted_host++;
}
if (freeai)
freeaddrinfo(ai);
- if (!submitted_host)
+ if (submitted_host == 0)
return KRB5_KDC_UNREACH;
return 0;
@@ -913,7 +928,7 @@ struct wait_ctx {
krb5_sendto_ctx ctx;
fd_set rfds;
fd_set wfds;
- unsigned max_fd;
+ rk_socket_t max_fd;
int got_reply;
time_t timenow;
};
@@ -924,16 +939,16 @@ wait_setup(heim_object_t obj, void *iter_ctx, int *stop)
struct wait_ctx *wait_ctx = iter_ctx;
struct host *h = (struct host *)obj;
+ if (h->state == CONNECT) {
+ if (h->timeout >= wait_ctx->timenow)
+ return;
+ host_connect(wait_ctx->context, wait_ctx->ctx, h);
+ }
+
/* skip dead hosts */
if (h->state == DEAD)
return;
- if (h->state == CONNECT) {
- if (h->timeout < wait_ctx->timenow)
- host_connect(wait_ctx->context, wait_ctx->ctx, h);
- return;
- }
-
/* if host timed out, dec tries and (retry or kill host) */
if (h->timeout < wait_ctx->timenow) {
heim_assert(h->tries != 0, "tries should not reach 0");
@@ -961,9 +976,10 @@ wait_setup(heim_object_t obj, void *iter_ctx, int *stop)
FD_SET(h->fd, &wait_ctx->wfds);
break;
default:
+ debug_host(wait_ctx->context, 5, h, "invalid sendto host state");
heim_abort("invalid sendto host state");
}
- if (h->fd > wait_ctx->max_fd)
+ if (h->fd > wait_ctx->max_fd || wait_ctx->max_fd == rk_INVALID_SOCKET)
wait_ctx->max_fd = h->fd;
}
@@ -975,6 +991,15 @@ wait_filter_dead(heim_object_t obj, void *ctx)
}
static void
+wait_accelerate(heim_object_t obj, void *ctx, int *stop)
+{
+ struct host *h = (struct host *)obj;
+
+ if (h->state == CONNECT && h->timeout > 0)
+ h->timeout--;
+}
+
+static void
wait_process(heim_object_t obj, void *ctx, int *stop)
{
struct wait_ctx *wait_ctx = ctx;
@@ -1007,7 +1032,7 @@ wait_response(krb5_context context, int *action, krb5_sendto_ctx ctx)
wait_ctx.ctx = ctx;
FD_ZERO(&wait_ctx.rfds);
FD_ZERO(&wait_ctx.wfds);
- wait_ctx.max_fd = 0;
+ wait_ctx.max_fd = rk_INVALID_SOCKET;
/* oh, we have a reply, it must be a plugin that got it for us */
if (ctx->response.length) {
@@ -1033,6 +1058,17 @@ wait_response(krb5_context context, int *action, krb5_sendto_ctx ctx)
return 0;
}
+ if (wait_ctx.max_fd == rk_INVALID_SOCKET) {
+ /*
+ * If we don't find a host which can make progress, then
+ * we accelerate the process by moving all of the contestants
+ * up by 1s.
+ */
+ _krb5_debug(context, 5, "wait_response: moving the contestants forward");
+ heim_array_iterate_f(ctx->hosts, &wait_ctx, wait_accelerate);
+ return 0;
+ }
+
tv.tv_sec = 1;
tv.tv_usec = 0;
@@ -1173,7 +1209,7 @@ krb5_sendto_context(krb5_context context,
action = KRB5_SENDTO_CONTINUE;
if (ret == 0) {
- _krb5_debug(context, 5, "submissing new requests to new host");
+ _krb5_debug(context, 5, "submitting new requests to new host");
if (submit_request(context, ctx, hi) != 0)
action = KRB5_SENDTO_TIMEOUT;
} else {