diff options
Diffstat (limited to 'server/sbus/sssd_dbus_connection.c')
-rw-r--r-- | server/sbus/sssd_dbus_connection.c | 282 |
1 files changed, 123 insertions, 159 deletions
diff --git a/server/sbus/sssd_dbus_connection.c b/server/sbus/sssd_dbus_connection.c index 8e4c3048..f2435bfb 100644 --- a/server/sbus/sssd_dbus_connection.c +++ b/server/sbus/sssd_dbus_connection.c @@ -7,30 +7,14 @@ /* Types */ struct dbus_ctx_list; -struct sbus_connection { - struct tevent_context *ev; - DBusConnection *dbus_conn; - char *address; - int connection_type; - int disconnect; - struct sbus_method_ctx *method_ctx_list; - sbus_conn_destructor_fn destructor; - void *pvt_data; /* Private data for this connection */ - - int retries; - int max_retries; - sbus_conn_reconn_callback_fn reconnect_callback; - /* Private data needed to reinit after reconnection */ - void *reconnect_pvt; -}; - -struct sbus_message_handler_ctx { +struct method_holder { + struct method_holder *prev, *next; struct sbus_connection *conn; struct sbus_method_ctx *method_ctx; + DBusObjectPathVTable *dbus_vtable; }; -static int _method_list_contains_path(struct sbus_method_ctx *list, - struct sbus_method_ctx *method); +static bool path_in_method_list(struct method_holder *list, const char *path); static void sbus_unreg_object_paths(struct sbus_connection *conn); static int sbus_auto_reconnect(struct sbus_connection *conn); @@ -48,7 +32,7 @@ static void sbus_dispatch(struct tevent_context *ev, conn = talloc_get_type(data, struct sbus_connection); - dbus_conn = conn->dbus_conn; + dbus_conn = conn->dbus.conn; DEBUG(6, ("dbus conn: %lX\n", dbus_conn)); if (conn->retries > 0) { @@ -138,7 +122,7 @@ static void sbus_conn_wakeup_main(void *data) } } -static int sbus_add_connection_int(struct sbus_connection **conn); +static int sbus_conn_set_fns(struct sbus_connection *conn); /* * integrate_connection_with_event_loop @@ -158,31 +142,22 @@ int sbus_add_connection(TALLOC_CTX *ctx, conn = talloc_zero(ctx, struct sbus_connection); conn->ev = ev; - conn->dbus_conn = dbus_conn; + conn->type = SBUS_CONNECTION; + conn->dbus.conn = dbus_conn; conn->connection_type = connection_type; - conn->disconnect = 0; - - /* This will be replaced on the first call to sbus_conn_add_method_ctx() */ - conn->method_ctx_list = NULL; - - /* This can be overridden by a call to sbus_reconnect_init() */ - conn->retries = 0; - conn->max_retries = 0; - conn->reconnect_callback = NULL; - *_conn = conn; - - ret = sbus_add_connection_int(_conn); + ret = sbus_conn_set_fns(conn); if (ret != EOK) { talloc_free(conn); } + + *_conn = conn; + return ret; } -static int sbus_add_connection_int(struct sbus_connection **_conn) +static int sbus_conn_set_fns(struct sbus_connection *conn) { - struct sbus_connection *conn = *_conn; - struct sbus_generic_dbus_ctx *gen_ctx; dbus_bool_t dbret; /* @@ -192,32 +167,23 @@ static int sbus_add_connection_int(struct sbus_connection **_conn) */ sbus_conn_set_destructor(conn, NULL); - gen_ctx = talloc_zero(conn, struct sbus_generic_dbus_ctx); - if (!gen_ctx) { - DEBUG(0, ("Out of memory!\n")); - return ENOMEM; - } - gen_ctx->ev = conn->ev; - gen_ctx->type = SBUS_CONNECTION; - gen_ctx->dbus.conn = conn->dbus_conn; - /* Set up DBusWatch functions */ - dbret = dbus_connection_set_watch_functions(conn->dbus_conn, + dbret = dbus_connection_set_watch_functions(conn->dbus.conn, sbus_add_watch, sbus_remove_watch, sbus_toggle_watch, - gen_ctx, NULL); + conn, NULL); if (!dbret) { DEBUG(2,("Error setting up D-BUS connection watch functions\n")); return EIO; } /* Set up DBusTimeout functions */ - dbret = dbus_connection_set_timeout_functions(conn->dbus_conn, + dbret = dbus_connection_set_timeout_functions(conn->dbus.conn, sbus_add_timeout, sbus_remove_timeout, sbus_toggle_timeout, - gen_ctx, NULL); + conn, NULL); if (!dbret) { DEBUG(2,("Error setting up D-BUS server timeout functions\n")); /* FIXME: free resources ? */ @@ -225,7 +191,7 @@ static int sbus_add_connection_int(struct sbus_connection **_conn) } /* Set up dispatch handler */ - dbus_connection_set_wakeup_main_function(conn->dbus_conn, + dbus_connection_set_wakeup_main_function(conn->dbus.conn, sbus_conn_wakeup_main, conn, NULL); @@ -238,9 +204,6 @@ static int sbus_add_connection_int(struct sbus_connection **_conn) */ sbus_conn_wakeup_main(conn); - /* Return the new toplevel object */ - *_conn = conn; - return EOK; } @@ -272,7 +235,7 @@ int sbus_new_connection(TALLOC_CTX *ctx, struct tevent_context *ev, /* Store the address for later reconnection */ (*conn)->address = talloc_strdup((*conn), address); - dbus_connection_set_exit_on_disconnect((*conn)->dbus_conn, FALSE); + dbus_connection_set_exit_on_disconnect((*conn)->dbus.conn, FALSE); return ret; } @@ -302,10 +265,10 @@ int sbus_default_connection_destructor(void *ctx) conn = talloc_get_type(ctx, struct sbus_connection); DEBUG(5, ("Invoking default destructor on connection %lX\n", - conn->dbus_conn)); + conn->dbus.conn)); if (conn->connection_type == SBUS_CONN_TYPE_PRIVATE) { /* Private connections must be closed explicitly */ - dbus_connection_close(conn->dbus_conn); + dbus_connection_close(conn->dbus.conn); } else if (conn->connection_type == SBUS_CONN_TYPE_SHARED) { /* Shared connections are destroyed when their last reference is removed */ @@ -319,7 +282,7 @@ int sbus_default_connection_destructor(void *ctx) /* Remove object path */ /* TODO: Remove object paths */ - dbus_connection_unref(conn->dbus_conn); + dbus_connection_unref(conn->dbus.conn); return 0; } @@ -330,7 +293,7 @@ int sbus_default_connection_destructor(void *ctx) */ DBusConnection *sbus_get_connection(struct sbus_connection *conn) { - return conn->dbus_conn; + return conn->dbus.conn; } void sbus_disconnect (struct sbus_connection *conn) @@ -339,11 +302,11 @@ void sbus_disconnect (struct sbus_connection *conn) return; } - DEBUG(5,("Disconnecting %lX\n", conn->dbus_conn)); + DEBUG(5,("Disconnecting %lX\n", conn->dbus.conn)); /******************************* - * Referencing conn->dbus_conn */ - dbus_connection_ref(conn->dbus_conn); + * Referencing conn->dbus.conn */ + dbus_connection_ref(conn->dbus.conn); conn->disconnect = 1; @@ -356,30 +319,30 @@ void sbus_disconnect (struct sbus_connection *conn) sbus_unreg_object_paths(conn); /* Disable watch functions */ - dbus_connection_set_watch_functions(conn->dbus_conn, + dbus_connection_set_watch_functions(conn->dbus.conn, NULL, NULL, NULL, NULL, NULL); /* Disable timeout functions */ - dbus_connection_set_timeout_functions(conn->dbus_conn, + dbus_connection_set_timeout_functions(conn->dbus.conn, NULL, NULL, NULL, NULL, NULL); /* Disable dispatch status function */ - dbus_connection_set_dispatch_status_function(conn->dbus_conn, + dbus_connection_set_dispatch_status_function(conn->dbus.conn, NULL, NULL, NULL); /* Disable wakeup main function */ - dbus_connection_set_wakeup_main_function(conn->dbus_conn, + dbus_connection_set_wakeup_main_function(conn->dbus.conn, NULL, NULL, NULL); /* Finalize the connection */ sbus_default_connection_destructor(conn); - dbus_connection_unref(conn->dbus_conn); + dbus_connection_unref(conn->dbus.conn); /* Unreferenced conn->dbus_conn * ******************************/ - DEBUG(5,("Disconnected %lX\n", conn->dbus_conn)); + DEBUG(5,("Disconnected %lX\n", conn->dbus.conn)); } static int sbus_reply_internal_error(DBusMessage *message, @@ -401,7 +364,7 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn, DBusMessage *message, void *user_data) { - struct sbus_message_handler_ctx *ctx; + struct method_holder *ctx; const char *method; const char *path; const char *msg_interface; @@ -412,7 +375,7 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn, if (!user_data) { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - ctx = talloc_get_type(user_data, struct sbus_message_handler_ctx); + ctx = talloc_get_type(user_data, struct method_holder); method = dbus_message_get_member(message); DEBUG(9, ("Received SBUS method [%s]\n", method)); @@ -433,8 +396,9 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn, if (strcmp(method, ctx->method_ctx->methods[i].method) == 0) { found = 1; ret = ctx->method_ctx->methods[i].fn(message, ctx->conn); - if (ret != EOK) return sbus_reply_internal_error(message, - ctx->conn); + if (ret != EOK) { + return sbus_reply_internal_error(message, ctx->conn); + } break; } } @@ -459,8 +423,9 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn, * an introspection function registered, user that. */ ret = ctx->method_ctx->introspect_fn(message, ctx->conn); - if (ret != EOK) return sbus_reply_internal_error(message, - ctx->conn); + if (ret != EOK) { + return sbus_reply_internal_error(message, ctx->conn); + } } } else @@ -476,50 +441,46 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn, int sbus_conn_add_method_ctx(struct sbus_connection *conn, struct sbus_method_ctx *method_ctx) { - DBusObjectPathVTable *connection_vtable; - struct sbus_message_handler_ctx *msg_handler_ctx; - TALLOC_CTX *tmp_ctx; - + struct method_holder *mh; dbus_bool_t dbret; - if (!conn || !method_ctx) { - return EINVAL; - } + const char *path; - if (_method_list_contains_path(conn->method_ctx_list, method_ctx)) { - DEBUG(0, ("Cannot add method context with identical path.\n")); + if (!conn || !method_ctx || !method_ctx->message_handler) { return EINVAL; } - if (method_ctx->message_handler == NULL) { + path = method_ctx->path; + + if (path_in_method_list(conn->method_list, path)) { + DEBUG(0, ("Cannot add method context with identical path.\n")); return EINVAL; } - DLIST_ADD(conn->method_ctx_list, method_ctx); - tmp_ctx = talloc_reference(conn, method_ctx); - if (tmp_ctx != method_ctx) { - /* talloc_reference only fails on insufficient memory */ + mh = talloc_zero(conn, struct method_holder); + if (!mh) { return ENOMEM; } + mh->conn = conn; /* Set up the vtable for the object path */ - connection_vtable = talloc_zero(conn, DBusObjectPathVTable); - if (!connection_vtable) { + mh->dbus_vtable = talloc_zero(conn, DBusObjectPathVTable); + if (!mh->dbus_vtable) { + talloc_free(mh); return ENOMEM; } - connection_vtable->message_function = method_ctx->message_handler; + mh->dbus_vtable->message_function = method_ctx->message_handler; - msg_handler_ctx = talloc_zero(conn, struct sbus_message_handler_ctx); - if (!msg_handler_ctx) { - talloc_free(connection_vtable); + mh->method_ctx = talloc_reference(mh, method_ctx); + if (!mh->method_ctx) { + /* talloc_reference only fails on insufficient memory */ + talloc_free(mh); return ENOMEM; } - msg_handler_ctx->conn = conn; - msg_handler_ctx->method_ctx = method_ctx; - dbret = dbus_connection_register_object_path(conn->dbus_conn, - method_ctx->path, - connection_vtable, - msg_handler_ctx); + DLIST_ADD(conn->method_list, mh); + + dbret = dbus_connection_register_object_path(conn->dbus.conn, + path, mh->dbus_vtable, mh); if (!dbret) { DEBUG(0, ("Could not register object path to the connection.\n")); return ENOMEM; @@ -528,38 +489,37 @@ int sbus_conn_add_method_ctx(struct sbus_connection *conn, return EOK; } -static int _method_list_contains_path(struct sbus_method_ctx *list, - struct sbus_method_ctx *method) +static bool path_in_method_list(struct method_holder *list, const char *path) { - struct sbus_method_ctx *iter; + struct method_holder *iter; - if (!list || !method) { - return 0; /* FALSE */ + if (!list || !path) { + return false; } iter = list; while (iter != NULL) { - if (strcmp(iter->path, method->path) == 0) - return 1; /* TRUE */ - + if (strcmp(iter->method_ctx->path, path) == 0) { + return true; + } iter = iter->next; } - return 0; /* FALSE */ + return false; } static void sbus_unreg_object_paths(struct sbus_connection *conn) { - struct sbus_method_ctx *iter = conn->method_ctx_list; - struct sbus_method_ctx *purge; + struct method_holder *iter = conn->method_list; + struct method_holder *purge; while (iter != NULL) { - dbus_connection_unregister_object_path(conn->dbus_conn, - iter->path); - DLIST_REMOVE(conn->method_ctx_list, iter); + dbus_connection_unregister_object_path(conn->dbus.conn, + iter->method_ctx->path); + DLIST_REMOVE(conn->method_list, iter); purge = iter; iter = iter->next; - talloc_unlink(conn, purge); + talloc_free(purge); } } @@ -577,38 +537,39 @@ static void sbus_reconnect(struct tevent_context *ev, struct tevent_timer *te, struct timeval tv, void *data) { - struct sbus_connection *conn = talloc_get_type(data, struct sbus_connection); - DBusConnection *dbus_conn; + struct sbus_connection *conn; + struct method_holder *mh; DBusError dbus_error; - struct tevent_timer *event; - struct sbus_method_ctx *iter; - struct sbus_method_ctx *purge; + dbus_bool_t dbret; int ret; + conn = talloc_get_type(data, struct sbus_connection); + dbus_error_init(&dbus_error); + DEBUG(3, ("Making reconnection attempt %d to [%s]\n", conn->retries, conn->address)); - /* Make a new connection to the D-BUS address */ - dbus_error_init(&dbus_error); - dbus_conn = dbus_connection_open(conn->address, &dbus_error); - if (dbus_conn) { - /* We successfully reconnected. Set up mainloop - * integration. - */ + conn->dbus.conn = dbus_connection_open(conn->address, &dbus_error); + if (conn->dbus.conn) { + /* We successfully reconnected. Set up mainloop integration. */ DEBUG(3, ("Reconnected to [%s]\n", conn->address)); - conn->dbus_conn = dbus_conn; - ret = sbus_add_connection_int(&conn); + ret = sbus_conn_set_fns(conn); if (ret != EOK) { - dbus_connection_unref(dbus_conn); + dbus_connection_unref(conn->dbus.conn); goto failed; } - /* Remove object paths (the reconnection callback must re-add these */ - iter = conn->method_ctx_list; - while (iter != NULL) { - DLIST_REMOVE(conn->method_ctx_list, iter); - purge = iter; - iter = iter->next; - talloc_unlink(conn, purge); + /* Re-register object paths */ + mh = conn->method_list; + while (mh) { + dbret = dbus_connection_register_object_path(conn->dbus.conn, + mh->method_ctx->path, + mh->dbus_vtable, mh); + if (!dbret) { + DEBUG(0, ("Could not register object path.\n")); + dbus_connection_unref(conn->dbus.conn); + goto failed; + } + mh = mh->next; } /* Reset retries to 0 to resume dispatch processing */ @@ -618,8 +579,8 @@ static void sbus_reconnect(struct tevent_context *ev, * reconnection was successful */ conn->reconnect_callback(conn, - SBUS_RECONNECT_SUCCESS, - conn->reconnect_pvt); + SBUS_RECONNECT_SUCCESS, + conn->reconnect_pvt); return; } @@ -634,28 +595,30 @@ failed: /* Check if we've passed our last chance or if we've lost track of * our retry count somehow */ - if (((conn->max_retries > 0) && - (conn->retries > conn->max_retries)) || - conn->retries <= 0) { + if ((conn->retries > conn->max_retries) || (conn->retries <= 0)) { conn->reconnect_callback(conn, - SBUS_RECONNECT_EXCEEDED_RETRIES, - conn->reconnect_pvt); + SBUS_RECONNECT_EXCEEDED_RETRIES, + conn->reconnect_pvt); } if (conn->retries == 2) { - tv.tv_sec += 3; /* Wait 3 seconds before the second reconnect attempt */ + /* Wait 3 seconds before the second reconnect attempt */ + tv.tv_sec += 3; } else if (conn->retries == 3) { - tv.tv_sec += 10; /* Wait 10 seconds before the third reconnect attempt */ + /* Wait 10 seconds before the third reconnect attempt */ + tv.tv_sec += 10; } else { - tv.tv_sec += 30; /* Wait 30 seconds before all subsequent reconnect attempts */ + /* Wait 30 seconds before all subsequent reconnect attempts */ + tv.tv_sec += 30; } - event = tevent_add_timer(conn->ev, conn, tv, sbus_reconnect, conn); - if (event == NULL) { + + te = tevent_add_timer(conn->ev, conn, tv, sbus_reconnect, conn); + if (!te) { conn->reconnect_callback(conn, - SBUS_RECONNECT_ERROR, - conn->reconnect_pvt); + SBUS_RECONNECT_ERROR, + conn->reconnect_pvt); } } @@ -670,18 +633,19 @@ static int sbus_auto_reconnect(struct sbus_connection *conn) struct timeval tv; conn->retries++; - if ((conn->max_retries > 0) && - (conn->retries >= conn->max_retries)) { - /* Return EAGAIN (to tell the calling process it + if (conn->retries >= conn->max_retries) { + /* Return EIO (to tell the calling process it * needs to create a new connection from scratch */ - return EAGAIN; + return EIO; } gettimeofday(&tv, NULL); tv.tv_sec += 1; /* Wait 1 second before the first reconnect attempt */ te = tevent_add_timer(conn->ev, conn, tv, sbus_reconnect, conn); - if (te == NULL) return EAGAIN; + if (!te) { + return EIO; + } return EOK; } @@ -692,7 +656,7 @@ void sbus_reconnect_init(struct sbus_connection *conn, sbus_conn_reconn_callback_fn callback, void *pvt) { - if(max_retries == 0 || callback == NULL) return; + if (max_retries < 0 || callback == NULL) return; conn->retries = 0; conn->max_retries = max_retries; @@ -708,6 +672,6 @@ bool sbus_conn_disconnecting(struct sbus_connection *conn) void sbus_conn_send_reply(struct sbus_connection *conn, DBusMessage *reply) { - dbus_connection_send(conn->dbus_conn, reply, NULL); + dbus_connection_send(conn->dbus.conn, reply, NULL); } |