summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/providers/data_provider_fo.c90
-rw-r--r--src/providers/dp_backend.h6
-rw-r--r--src/providers/fail_over.c21
-rw-r--r--src/providers/fail_over.h6
-rw-r--r--src/providers/ldap/sdap_id_op.c3
5 files changed, 81 insertions, 45 deletions
diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
index 21059d394..dff0aef24 100644
--- a/src/providers/data_provider_fo.c
+++ b/src/providers/data_provider_fo.c
@@ -155,22 +155,42 @@ static int be_svc_data_destroy(void *memptr)
return 0;
}
-int be_fo_add_service(struct be_ctx *ctx, const char *service_name)
+/*
+ * Find registered be_svc_data by service name.
+ */
+static struct be_svc_data *be_fo_find_svc_data(struct be_ctx *ctx,
+ const char *service_name)
{
- struct fo_service *service;
struct be_svc_data *svc;
- int ret;
+
+ if (!ctx || !ctx->be_fo) {
+ return 0;
+ }
DLIST_FOR_EACH(svc, ctx->be_fo->svcs) {
if (strcmp(svc->name, service_name) == 0) {
- DEBUG(6, ("Failover service already initialized!\n"));
- /* we already have a service up and configured,
- * can happen when using both id and auth provider
- */
- return EOK;
+ return svc;
}
}
+ return 0;
+}
+
+int be_fo_add_service(struct be_ctx *ctx, const char *service_name)
+{
+ struct fo_service *service;
+ struct be_svc_data *svc;
+ int ret;
+
+ svc = be_fo_find_svc_data(ctx, service_name);
+ if (svc) {
+ DEBUG(6, ("Failover service already initialized!\n"));
+ /* we already have a service up and configured,
+ * can happen when using both id and auth provider
+ */
+ return EOK;
+ }
+
/* if not in the be service list, try to create new one */
ret = fo_new_service(ctx->be_fo->fo_ctx, service_name, &service);
@@ -217,11 +237,7 @@ int be_fo_service_add_callback(TALLOC_CTX *memctx,
struct be_svc_callback *callback;
struct be_svc_data *svc;
- DLIST_FOR_EACH(svc, ctx->be_fo->svcs) {
- if (strcmp(svc->name, service_name) == 0) {
- break;
- }
- }
+ svc = be_fo_find_svc_data(ctx, service_name);
if (NULL == svc) {
return ENOENT;
}
@@ -249,11 +265,7 @@ int be_fo_add_srv_server(struct be_ctx *ctx, const char *service_name,
char *domain;
int ret;
- DLIST_FOR_EACH(svc, ctx->be_fo->svcs) {
- if (strcmp(svc->name, service_name) == 0) {
- break;
- }
- }
+ svc = be_fo_find_svc_data(ctx, service_name);
if (NULL == svc) {
return ENOENT;
}
@@ -281,16 +293,7 @@ int be_fo_get_server_count(struct be_ctx *ctx, const char *service_name)
{
struct be_svc_data *svc_data;
- if (!ctx->be_fo) {
- return 0;
- }
-
- DLIST_FOR_EACH(svc_data, ctx->be_fo->svcs) {
- if (strcmp(svc_data->name, service_name) == 0) {
- break;
- }
- }
-
+ svc_data = be_fo_find_svc_data(ctx, service_name);
if (!svc_data) {
return 0;
}
@@ -304,11 +307,7 @@ int be_fo_add_server(struct be_ctx *ctx, const char *service_name,
struct be_svc_data *svc;
int ret;
- DLIST_FOR_EACH(svc, ctx->be_fo->svcs) {
- if (strcmp(svc->name, service_name) == 0) {
- break;
- }
- }
+ svc = be_fo_find_svc_data(ctx, service_name);
if (NULL == svc) {
return ENOENT;
}
@@ -349,19 +348,14 @@ struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx,
state->ev = ev;
state->ctx = ctx;
- DLIST_FOR_EACH(svc, ctx->be_fo->svcs) {
- if (strcmp(svc->name, service_name) == 0) {
- state->svc = svc;
- break;
- }
- }
-
+ svc = be_fo_find_svc_data(ctx, service_name);
if (NULL == svc) {
tevent_req_error(req, EINVAL);
tevent_req_post(req, ev);
return req;
}
+ state->svc = svc;
state->attempts = 0;
subreq = fo_resolve_service_send(state, ev,
@@ -474,16 +468,22 @@ int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv)
return EOK;
}
+void be_fo_try_next_server(struct be_ctx *ctx, const char *service_name)
+{
+ struct be_svc_data *svc;
+
+ svc = be_fo_find_svc_data(ctx, service_name);
+ if (svc) {
+ fo_try_next_server(svc->fo_service);
+ }
+}
+
int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx,
const char *service_name)
{
struct be_svc_data *svc;
- DLIST_FOR_EACH(svc, ctx->be_fo->svcs) {
- if (strcmp(svc->name, service_name) == 0) {
- break;
- }
- }
+ svc = be_fo_find_svc_data(ctx, service_name);
if (NULL == svc) {
return ENOENT;
}
diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h
index 69872b6c4..a31e458f7 100644
--- a/src/providers/dp_backend.h
+++ b/src/providers/dp_backend.h
@@ -177,6 +177,12 @@ struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx,
struct be_ctx *ctx,
const char *service_name);
int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv);
+/*
+ * Instruct fail-over to try next server on the next connect attempt.
+ * Should be used after connection to service was unexpectedly dropped
+ * but there is no authoritative information on whether active server is down.
+ */
+void be_fo_try_next_server(struct be_ctx *ctx, const char *service_name);
int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx,
const char *service_name);
diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
index f364a8c5f..3dab38a34 100644
--- a/src/providers/fail_over.c
+++ b/src/providers/fail_over.c
@@ -1275,6 +1275,27 @@ fo_set_port_status(struct fo_server *server, enum port_status status)
}
}
+void fo_try_next_server(struct fo_service *service)
+{
+ struct fo_server *server;
+
+ if (!service) {
+ DEBUG(1, ("Bug: No service supplied\n"));
+ return;
+ }
+
+ server = service->active_server;
+ if (!server) {
+ return;
+ }
+
+ service->active_server = 0;
+
+ if (server->port_status == PORT_WORKING) {
+ server->port_status = PORT_NEUTRAL;
+ }
+}
+
void *
fo_get_server_user_data(struct fo_server *server)
{
diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h
index 24b2c1f5f..f1a071da9 100644
--- a/src/providers/fail_over.h
+++ b/src/providers/fail_over.h
@@ -155,6 +155,12 @@ void fo_set_server_status(struct fo_server *server,
void fo_set_port_status(struct fo_server *server,
enum port_status status);
+/*
+ * Instruct fail-over to try next server on the next connect attempt.
+ * Should be used after connection to service was unexpectedly dropped
+ * but there is no authoritative information on whether active server is down.
+ */
+void fo_try_next_server(struct fo_service *service);
void *fo_get_server_user_data(struct fo_server *server);
diff --git a/src/providers/ldap/sdap_id_op.c b/src/providers/ldap/sdap_id_op.c
index de498bd77..1e20c75e1 100644
--- a/src/providers/ldap/sdap_id_op.c
+++ b/src/providers/ldap/sdap_id_op.c
@@ -703,6 +703,9 @@ int sdap_id_op_done(struct sdap_id_op *op, int retval, int *dp_err_out)
&& op->conn_data == op->conn_cache->cached_connection) {
/* do not reuse failed connection */
op->conn_cache->cached_connection = NULL;
+
+ DEBUG(5, ("communication error on cached connection, moving to next server\n"));
+ be_fo_try_next_server(op->conn_cache->be, op->conn_cache->service->name);
}
int dp_err;