From dd025b4cbd501e2f34461f9d8359a829b81f5c2f Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Tue, 27 Apr 2010 14:57:37 -0400 Subject: Add callback when the ID provider switches from offline to online Allow backends to set a callback in the be_ctx that should be invoked when the ID provider goes online. This can be used to perform regular maintenance tasks that are valid only when going online. --- src/providers/data_provider_be.c | 138 +++++++++++++++++++++++++++++ src/providers/dp_backend.h | 17 ++++ src/providers/ldap/sdap_async_connection.c | 9 ++ src/providers/proxy.c | 10 +++ 4 files changed, 174 insertions(+) diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c index e5a5ff7b..27a4571a 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 d657af18..496c8070 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 17cd5586..bd8d4e96 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 c7aef308..ac5cf7fe 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); } -- cgit