summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/providers/data_provider_be.c138
-rw-r--r--src/providers/dp_backend.h17
-rw-r--r--src/providers/ldap/sdap_async_connection.c9
-rw-r--r--src/providers/proxy.c10
4 files changed, 174 insertions, 0 deletions
diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
index e5a5ff7b0..27a4571a7 100644
--- a/src/providers/data_provider_be.c
+++ b/src/providers/data_provider_be.c
@@ -166,8 +166,146 @@ void be_mark_offline(struct be_ctx *ctx)
ctx->offstat.went_offline = time(NULL);
ctx->offstat.offline = true;
+ ctx->run_online_cb = true;
}
+
+struct be_conn_online_cb {
+ struct be_conn_online_cb *prev;
+ struct be_conn_online_cb *next;
+
+ be_conn_online_callback_t cb;
+ void *pvt;
+
+ struct be_ctx *be;
+};
+
+static int online_cb_destructor(TALLOC_CTX *ptr);
+int be_add_online_cb(TALLOC_CTX *mem_ctx,
+ struct be_ctx *ctx,
+ be_conn_online_callback_t cb,
+ void *pvt,
+ struct be_conn_online_cb **online_cb)
+{
+ struct be_conn_online_cb *on_cb;
+
+ if (!ctx || !cb) {
+ return EINVAL;
+ }
+
+ on_cb = talloc(mem_ctx, struct be_conn_online_cb);
+ if (!on_cb) {
+ return ENOMEM;
+ }
+
+ on_cb->cb = cb;
+ on_cb->pvt = pvt;
+ on_cb->be = ctx;
+
+ DLIST_ADD(ctx->online_cb_list, on_cb);
+
+ talloc_set_destructor((TALLOC_CTX *)on_cb, online_cb_destructor);
+
+ /* Make sure we run the callback for the first
+ * connection after startup.
+ */
+ ctx->run_online_cb = true;
+
+ if (online_cb) {
+ *online_cb = on_cb;
+ }
+
+ return EOK;
+}
+
+static int online_cb_destructor(TALLOC_CTX *ptr)
+{
+ struct be_conn_online_cb *cb =
+ talloc_get_type(ptr, struct be_conn_online_cb);
+ DLIST_REMOVE(cb->be->online_cb_list, cb);
+ return 0;
+}
+
+
+struct be_online_cb_ctx {
+ struct be_ctx *be;
+ struct be_conn_online_cb *callback;
+};
+
+static void be_run_online_cb_step(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *pvt);
+void be_run_online_cb(struct be_ctx *be) {
+ struct timeval soon;
+ struct tevent_timer *te;
+ struct be_online_cb_ctx *cb_ctx;
+
+ if (be->run_online_cb && be->online_cb_list) {
+ /* Reset the flag. We only want to run these
+ * callbacks when transitioning to online
+ */
+ be->run_online_cb = false;
+
+ DEBUG(3, ("Going online. Running callbacks.\n"));
+
+ cb_ctx = talloc(be, struct be_online_cb_ctx);
+ if (!cb_ctx) {
+ DEBUG(0, ("Out of memory. Could not invoke callbacks\n"));
+ return;
+ }
+ cb_ctx->be = be;
+ cb_ctx->callback = be->online_cb_list;
+
+ /* Delay 30ms so we don't block any other events */
+ soon = tevent_timeval_current_ofs(0, 30000);
+ te = tevent_add_timer(be->ev, cb_ctx, soon,
+ be_run_online_cb_step,
+ cb_ctx);
+ if (!te) {
+ DEBUG(0, ("Out of memory. Could not invoke callbacks\n"));
+ talloc_free(cb_ctx);
+ }
+ }
+}
+
+static void be_run_online_cb_step(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *pvt)
+{
+ struct be_online_cb_ctx *cb_ctx =
+ talloc_get_type(pvt, struct be_online_cb_ctx);
+ struct tevent_timer *tev;
+ struct timeval soon;
+
+ /* Call the callback */
+ cb_ctx->callback->cb(cb_ctx->callback->pvt);
+
+ if (cb_ctx->callback->next) {
+ cb_ctx->callback = cb_ctx->callback->next;
+
+ /* Delay 30ms so we don't block any other events */
+ soon = tevent_timeval_current_ofs(0, 30000);
+ tev = tevent_add_timer(cb_ctx->be->ev, cb_ctx, soon,
+ be_run_online_cb_step,
+ cb_ctx);
+ if (!te) {
+ DEBUG(0, ("Out of memory. Could not invoke callbacks\n"));
+ goto final;
+ }
+ return;
+ }
+
+final:
+ /* Steal the timer event onto the be_ctx so it doesn't
+ * get freed with the cb_ctx
+ */
+ talloc_steal(cb_ctx->be, te);
+ talloc_free(cb_ctx);
+}
+
+
static int be_check_online(DBusMessage *message, struct sbus_connection *conn)
{
struct be_client *becli;
diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h
index d657af18b..496c80700 100644
--- a/src/providers/dp_backend.h
+++ b/src/providers/dp_backend.h
@@ -35,6 +35,8 @@ typedef void (*be_shutdown_fn)(void *);
typedef void (*be_req_fn_t)(struct be_req *);
typedef void (*be_async_callback_t)(struct be_req *, int, int, const char *);
+typedef void (*be_conn_online_callback_t)(void *);
+
enum bet_type {
BET_NULL = 0,
BET_ID,
@@ -76,6 +78,8 @@ struct be_client {
struct be_failover_ctx;
+struct be_conn_online_cb;
+
struct be_ctx {
struct tevent_context *ev;
struct confdb_ctx *cdb;
@@ -85,6 +89,12 @@ struct be_ctx {
const char *conf_path;
struct be_failover_ctx *be_fo;
+ /* Functions to be invoked when the
+ * backend goes online
+ */
+ struct be_conn_online_cb *online_cb_list;
+ bool run_online_cb;
+
struct be_offline_status offstat;
struct sbus_connection *mon_conn;
@@ -126,6 +136,13 @@ struct be_acct_req {
bool be_is_offline(struct be_ctx *ctx);
void be_mark_offline(struct be_ctx *ctx);
+int be_add_online_cb(TALLOC_CTX *mem_ctx,
+ struct be_ctx *ctx,
+ be_conn_online_callback_t cb,
+ void *pvt,
+ struct be_conn_online_cb **online_cb);
+void be_run_online_cb(struct be_ctx *be);
+
/* from data_provider_fo.c */
typedef void (be_svc_callback_fn_t)(void *, struct fo_server *);
diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
index 17cd55863..bd8d4e960 100644
--- a/src/providers/ldap/sdap_async_connection.c
+++ b/src/providers/ldap/sdap_async_connection.c
@@ -813,6 +813,7 @@ struct sdap_cli_connect_state {
struct tevent_context *ev;
struct sdap_options *opts;
struct sdap_service *service;
+ struct be_ctx *be;
bool use_rootdse;
struct sysdb_attrs *rootdse;
@@ -851,6 +852,7 @@ struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx,
state->service = service;
state->be = be;
state->srv = NULL;
+ state->be = be;
if (rootdse) {
state->use_rootdse = true;
@@ -1123,6 +1125,8 @@ static void sdap_cli_auth_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
+ struct sdap_cli_connect_state *state = tevent_req_data(req,
+ struct sdap_cli_connect_state);
enum sdap_result result;
int ret;
@@ -1137,6 +1141,11 @@ static void sdap_cli_auth_done(struct tevent_req *subreq)
return;
}
+ /* Reconnection succeeded
+ * Run any post-connection routines
+ */
+ be_run_online_cb(state->be);
+
tevent_req_done(req);
}
diff --git a/src/providers/proxy.c b/src/providers/proxy.c
index c7aef3086..ac5cf7fe9 100644
--- a/src/providers/proxy.c
+++ b/src/providers/proxy.c
@@ -277,6 +277,16 @@ static void proxy_pam_handler(struct be_req *req) {
static void proxy_reply(struct be_req *req, int dp_err,
int error, const char *errstr)
{
+ if (!req->be_ctx->offstat.offline) {
+ /* This action took place online.
+ * Fire any online callbacks if necessary.
+ * Note: we're checking the offline value directly,
+ * because if the activity took a long time to
+ * complete, calling be_is_offline() might report false
+ * incorrectly.
+ */
+ be_run_online_cb(req->be_ctx);
+ }
return req->fn(req, dp_err, error, errstr);
}