summaryrefslogtreecommitdiffstats
path: root/src/providers/data_provider_be.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/providers/data_provider_be.c')
-rw-r--r--src/providers/data_provider_be.c138
1 files changed, 138 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;