diff options
Diffstat (limited to 'src/providers/data_provider_fo.c')
-rw-r--r-- | src/providers/data_provider_fo.c | 71 |
1 files changed, 58 insertions, 13 deletions
diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c index c3f8c3ba7..5d634cab9 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 { @@ -408,31 +409,31 @@ 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)); + 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 */ @@ -442,8 +443,8 @@ static void be_resolve_server_done(struct tevent_req *subreq) 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); @@ -451,6 +452,14 @@ static void be_resolve_server_done(struct tevent_req *subreq) } /* all fine we got the server */ + if (state->svc->first_resolved == NULL) { + DEBUG(7, ("Saving the first resolved server\n")); + state->svc->first_resolved = state->srv; + } else if (state->svc->first_resolved == state->srv) { + DEBUG(2, ("The fail over cycled through all available servers\n")); + ret = ENOENT; + goto fail; + } if (debug_level >= 4 && fo_get_server_name(state->srv)) { struct resolv_hostent *srvaddr; @@ -459,8 +468,8 @@ static void be_resolve_server_done(struct tevent_req *subreq) 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; + ret = EFAULT; + goto fail; } inet_ntop(srvaddr->family, srvaddr->addr_list[0]->ipaddr, @@ -488,6 +497,12 @@ static void be_resolve_server_done(struct tevent_req *subreq) } tevent_req_done(req); + return; + +fail: + DEBUG(7, ("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) @@ -534,3 +549,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(3, ("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(3, ("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; + } +} |