From b300bad539e9a9ad7f3a88dc91253afff0425cb6 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Mon, 5 Mar 2012 21:09:37 +0100 Subject: Only do one cycle when resolving a server https://fedorahosted.org/sssd/ticket/1214 --- src/providers/data_provider_fo.c | 90 ++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 21 deletions(-) (limited to 'src/providers/data_provider_fo.c') diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c index 4c2c0b4a..c358e68d 100644 --- a/src/providers/data_provider_fo.c +++ b/src/providers/data_provider_fo.c @@ -46,6 +46,7 @@ struct be_svc_data { bool run_callbacks; struct be_svc_callback *callbacks; + struct fo_server *first_resolved; }; struct be_failover_ctx { @@ -398,42 +399,43 @@ static void be_resolve_server_done(struct tevent_req *subreq) switch (ret) { case EOK: if (!state->srv) { - tevent_req_error(req, EFAULT); - return; + ret = EFAULT; + goto fail; } break; case ENOENT: /* all servers have been tried and none * was found good, go offline */ - tevent_req_error(req, EIO); - return; + ret = EIO; + goto fail; default: /* mark server as bad and retry */ if (!state->srv) { - tevent_req_error(req, EFAULT); - return; + ret = EFAULT; + goto fail; } - DEBUG(6, ("Couldn't resolve server (%s), resolver returned (%d)\n", - fo_get_server_str_name(state->srv), ret)); + DEBUG(SSSDBG_MINOR_FAILURE, + ("Couldn't resolve server (%s), resolver returned (%d)\n", + fo_get_server_str_name(state->srv), ret)); state->attempts++; if (state->attempts >= 10) { DEBUG(2, ("Failed to find a server after 10 attempts\n")); - tevent_req_error(req, EIO); - return; + ret = EIO; + goto fail; } /* now try next one */ - DEBUG(6, ("Trying with the next one!\n")); + DEBUG(SSSDBG_TRACE_LIBS, ("Trying with the next one!\n")); subreq = fo_resolve_service_send(state, state->ev, state->ctx->be_fo->resolv, state->ctx->be_fo->fo_ctx, state->svc->fo_service); if (!subreq) { - tevent_req_error(req, ENOMEM); - return; + ret = ENOMEM; + goto fail; } tevent_req_set_callback(subreq, be_resolve_server_done, req); @@ -441,24 +443,34 @@ static void be_resolve_server_done(struct tevent_req *subreq) } /* all fine we got the server */ + if (state->svc->first_resolved == NULL) { + DEBUG(SSSDBG_TRACE_LIBS, ("Saving the first resolved server\n")); + state->svc->first_resolved = state->srv; + } else if (state->svc->first_resolved == state->srv) { + DEBUG(SSSDBG_OP_FAILURE, + ("The fail over cycled through all available servers\n")); + ret = ENOENT; + goto fail; + } - if (DEBUG_IS_SET(SSSDBG_CONF_SETTINGS) && fo_get_server_name(state->srv)) { + if (DEBUG_IS_SET(SSSDBG_FUNC_DATA) && fo_get_server_name(state->srv)) { struct resolv_hostent *srvaddr; char ipaddr[128]; srvaddr = fo_get_server_hostent(state->srv); if (!srvaddr) { - DEBUG(3, ("FATAL: No hostent available for server (%s)\n", - fo_get_server_str_name(state->srv))); - tevent_req_error(req, EFAULT); - return; + DEBUG(SSSDBG_CRIT_FAILURE, + ("FATAL: No hostent available for server (%s)\n", + fo_get_server_str_name(state->srv))); + ret = EFAULT; + goto fail; } inet_ntop(srvaddr->family, srvaddr->addr_list[0]->ipaddr, ipaddr, 128); - DEBUG(4, ("Found address for server %s: [%s] TTL %d\n", - fo_get_server_str_name(state->srv), ipaddr, - srvaddr->addr_list[0]->ttl)); + DEBUG(SSSDBG_FUNC_DATA, ("Found address for server %s: [%s] TTL %d\n", + fo_get_server_str_name(state->srv), ipaddr, + srvaddr->addr_list[0]->ttl)); } srv_status_change = fo_get_server_hostname_last_change(state->srv); @@ -478,6 +490,12 @@ static void be_resolve_server_done(struct tevent_req *subreq) } tevent_req_done(req); + return; + +fail: + DEBUG(SSSDBG_TRACE_LIBS, ("Server resolution failed: %d\n", ret)); + state->svc->first_resolved = NULL; + tevent_req_error(req, ret); } int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv) @@ -524,3 +542,33 @@ void reset_fo(struct be_ctx *be_ctx) fo_reset_services(be_ctx->be_fo->fo_ctx); } +void be_fo_set_port_status(struct be_ctx *ctx, + struct fo_server *server, + enum port_status status) +{ + struct be_svc_data *svc; + struct fo_service *fsvc; + + fo_set_port_status(server, status); + + fsvc = fo_get_server_service(server); + if (!fsvc) { + DEBUG(SSSDBG_OP_FAILURE, ("BUG: No service associated with server\n")); + return; + } + + DLIST_FOR_EACH(svc, ctx->be_fo->svcs) { + if (svc->fo_service == fsvc) break; + } + + if (!svc) { + DEBUG(SSSDBG_OP_FAILURE, ("BUG: Unknown service\n")); + return; + } + + if (status == PORT_WORKING) { + /* We were successful in connecting to the server. Cycle through all + * available servers next time */ + svc->first_resolved = NULL; + } +} -- cgit