From a40d9cc11d17d9c3c22a0462cd8c419d1e79ffb8 Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Aug 16 2016 12:38:52 +0000 Subject: rdp: add ability to forward reply to the client request In cases where the InfoPipe servers just as a middle-man between the DataProvider and a client we can simply forward the reply reducing amount of coded needed in the InfoPipe. Reviewed-by: Lukáš Slebodník Reviewed-by: Jakub Hrozek --- diff --git a/src/responder/common/data_provider/rdp.h b/src/responder/common/data_provider/rdp.h index 8a3ec80..f0aed17 100644 --- a/src/responder/common/data_provider/rdp.h +++ b/src/responder/common/data_provider/rdp.h @@ -54,6 +54,26 @@ errno_t _rdp_message_recv(struct tevent_req *req, #define rdp_message_recv(req, ...) \ _rdp_message_recv(req, ##__VA_ARGS__, DBUS_TYPE_INVALID) +/** + * Send D-Bus message to Data Provider but instead of returning the reply + * to the caller it forwards the reply to the client request. No further + * processing is required by the caller. In case of a failure the client + * request is freed since there is nothing we can do. + */ +void _rdp_message_send_and_reply(struct sbus_request *sbus_req, + struct resp_ctx *rctx, + struct sss_domain_info *domain, + const char *path, + const char *iface, + const char *method, + int first_arg_type, + ...); + +#define rdp_message_send_and_reply(sbus_req, rctx, domain, path, iface, \ + method, ...) \ + _rdp_message_send_and_reply(sbus_req, rctx, domain, path, iface, method, \ + ##__VA_ARGS__, DBUS_TYPE_INVALID) + errno_t rdp_register_client(struct be_conn *be_conn, const char *client_name); diff --git a/src/responder/common/data_provider/rdp_message.c b/src/responder/common/data_provider/rdp_message.c index 78af6f8..e226401 100644 --- a/src/responder/common/data_provider/rdp_message.c +++ b/src/responder/common/data_provider/rdp_message.c @@ -53,104 +53,72 @@ static errno_t rdp_error_to_errno(DBusError *error) return EIO; } -struct rdp_message_state { - struct DBusMessage *reply; -}; - -static int rdp_message_state_destructor(struct rdp_message_state *state) -{ - if (state->reply != NULL) { - dbus_message_unref(state->reply); - } - - return 0; -} - -static void rdp_message_done(DBusPendingCall *pending, void *ptr); - -struct tevent_req *_rdp_message_send(TALLOC_CTX *mem_ctx, - struct resp_ctx *rctx, - struct sss_domain_info *domain, - const char *path, - const char *iface, - const char *method, - int first_arg_type, - ...) +static errno_t +rdp_message_send_internal(struct resp_ctx *rctx, + struct sss_domain_info *domain, + DBusPendingCallNotifyFunction notify_fn, + void *notify_fn_data, + const char *path, + const char *iface, + const char *method, + int first_arg_type, + va_list va) { - struct rdp_message_state *state; struct be_conn *be_conn; - struct tevent_req *req; - DBusMessage *msg; + DBusMessage *msg = NULL; dbus_bool_t bret; errno_t ret; - va_list va; - - req = tevent_req_create(mem_ctx, &state, struct rdp_message_state); - if (req == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); - return NULL; - } - - talloc_set_destructor(state, rdp_message_state_destructor); ret = sss_dp_get_domain_conn(rctx, domain->conn_name, &be_conn); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "BUG: The Data Provider connection for " "%s is not available!\n", domain->name); - ret = ERR_INTERNAL; - goto immediately; + goto done; } msg = dbus_message_new_method_call(NULL, path, iface, method); if (msg == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create message\n"); ret = ENOMEM; - goto immediately; + goto done; } - va_start(va, first_arg_type); bret = dbus_message_append_args_valist(msg, first_arg_type, va); - va_end(va); if (!bret) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n"); ret = EIO; - goto immediately; + goto done; } DEBUG(SSSDBG_TRACE_FUNC, "DP Request: %s %s.%s\n", path, iface, method); - ret = sbus_conn_send(be_conn->conn, msg, 30000, - rdp_message_done, req, NULL); + ret = sbus_conn_send(be_conn->conn, msg, 3000, + notify_fn, notify_fn_data, NULL); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to contact Data Provider " "[%d]: %s\n", ret, sss_strerror(ret)); - goto immediately; + goto done; } - return req; + ret = EOK; -immediately: - if (ret == EOK) { - tevent_req_done(req); - } else { - tevent_req_error(req, ret); +done: + if (msg != NULL) { + dbus_message_unref(msg); } - tevent_req_post(req, rctx->ev); - return req; + return ret; } -static void rdp_message_done(DBusPendingCall *pending, void *ptr) +static errno_t rdp_process_pending_call(DBusPendingCall *pending, + DBusMessage **_reply) { - struct rdp_message_state *state; - DBusMessage *reply = NULL; - struct tevent_req *req; - DBusError error; + DBusMessage *reply; dbus_bool_t bret; + DBusError error; errno_t ret; - req = talloc_get_type(ptr, struct tevent_req); - state = tevent_req_data(req, struct rdp_message_state); + *_reply = NULL; dbus_error_init(&error); @@ -165,9 +133,8 @@ static void rdp_message_done(DBusPendingCall *pending, void *ptr) switch (dbus_message_get_type(reply)) { case DBUS_MESSAGE_TYPE_METHOD_RETURN: DEBUG(SSSDBG_TRACE_FUNC, "DP Success\n"); - state->reply = reply; ret = EOK; - goto done; + break; case DBUS_MESSAGE_TYPE_ERROR: bret = dbus_set_error_from_message(&error, reply); @@ -180,28 +147,105 @@ static void rdp_message_done(DBusPendingCall *pending, void *ptr) DEBUG(SSSDBG_CRIT_FAILURE, "DP Error [%s]: %s\n", error.name, (error.message == NULL ? "(null)" : error.message)); ret = rdp_error_to_errno(&error); - goto done; + break; default: + dbus_message_unref(reply); DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected type?\n"); ret = ERR_INTERNAL; goto done; } - ret = ERR_INTERNAL; + *_reply = reply; done: dbus_pending_call_unref(pending); dbus_error_free(&error); + return ret; +} + +struct rdp_message_state { + struct DBusMessage *reply; +}; + +static int rdp_message_state_destructor(struct rdp_message_state *state) +{ + if (state->reply != NULL) { + dbus_message_unref(state->reply); + } + + return 0; +} + +static void rdp_message_done(DBusPendingCall *pending, void *ptr); + +struct tevent_req *_rdp_message_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_domain_info *domain, + const char *path, + const char *iface, + const char *method, + int first_arg_type, + ...) +{ + struct rdp_message_state *state; + struct tevent_req *req; + errno_t ret; + va_list va; + + req = tevent_req_create(mem_ctx, &state, struct rdp_message_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); + return NULL; + } + + talloc_set_destructor(state, rdp_message_state_destructor); + + va_start(va, first_arg_type); + ret = rdp_message_send_internal(rctx, domain, rdp_message_done, req, + path, iface, method, first_arg_type, va); + va_end(va); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to contact Data Provider " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto immediately; + } + + return req; + +immediately: if (ret == EOK) { tevent_req_done(req); - return; + } else { + tevent_req_error(req, ret); } + tevent_req_post(req, rctx->ev); - if (reply != NULL) { - dbus_message_unref(reply); + return req; +} + +static void rdp_message_done(DBusPendingCall *pending, void *ptr) +{ + struct rdp_message_state *state; + struct tevent_req *req; + errno_t ret; + + req = talloc_get_type(ptr, struct tevent_req); + state = tevent_req_data(req, struct rdp_message_state); + + ret = rdp_process_pending_call(pending, &state->reply); + if (ret != EOK) { + if (state->reply != NULL) { + dbus_message_unref(state->reply); + } + + state->reply = NULL; + + tevent_req_error(req, ret); + return; } - tevent_req_error(req, ret); + + tevent_req_done(req); } errno_t _rdp_message_recv(struct tevent_req *req, @@ -241,3 +285,85 @@ done: return ret; } +static void rdp_message_send_and_reply_done(DBusPendingCall *pending, + void *ptr); + +void _rdp_message_send_and_reply(struct sbus_request *sbus_req, + struct resp_ctx *rctx, + struct sss_domain_info *domain, + const char *path, + const char *iface, + const char *method, + int first_arg_type, + ...) +{ + errno_t ret; + va_list va; + + va_start(va, first_arg_type); + ret = rdp_message_send_internal(rctx, domain, + rdp_message_send_and_reply_done, sbus_req, + path, iface, method, first_arg_type, va); + va_end(va); + + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to contact Data Provider " + "[%d]: %s\n", ret, sss_strerror(ret)); + talloc_free(sbus_req); + } +} + +static void rdp_message_send_and_reply_done(DBusPendingCall *pending, + void *ptr) +{ + struct sbus_request *sbus_req; + DBusMessage *reply = NULL; + dbus_uint32_t serial; + const char *sender; + dbus_bool_t dbret; + errno_t ret; + + sbus_req = talloc_get_type(ptr, struct sbus_request); + + ret = rdp_process_pending_call(pending, &reply); + if (reply == NULL) { + /* Something bad happened. Just kill the request. */ + ret = EIO; + goto done; + } + + /* Otherwise we have a valid reply and we do not care about returned + * value. We set destination and serial in reply to point to the original + * client request. */ + + sender = dbus_message_get_sender(sbus_req->message); + serial = dbus_message_get_serial(sbus_req->message); + + dbret = dbus_message_set_destination(reply, sender); + if (dbret == false) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set reply sender!\n"); + ret = EIO; + goto done; + } + + dbret = dbus_message_set_reply_serial(reply, serial); + if (dbret == false) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set reply serial!\n"); + ret = EIO; + goto done; + } + + sbus_request_finish(sbus_req, reply); + + ret = EOK; + +done: + if (reply != NULL) { + dbus_message_unref(reply); + } + + if (ret != EOK) { + /* Something bad happend, just kill the request. */ + talloc_free(sbus_req); + } +} diff --git a/src/responder/ifp/ifp_domains.c b/src/responder/ifp/ifp_domains.c index 5333b25..8bfd39f 100644 --- a/src/responder/ifp/ifp_domains.c +++ b/src/responder/ifp/ifp_domains.c @@ -538,14 +538,11 @@ void ifp_dom_get_parent_domain(struct sbus_request *dbus_req, dom->parent->name); } -static void ifp_domains_domain_is_online_done(struct tevent_req *req); - int ifp_domains_domain_is_online(struct sbus_request *sbus_req, void *data) { struct ifp_ctx *ifp_ctx; struct sss_domain_info *dom; - struct tevent_req *req; DBusError *error; ifp_ctx = talloc_get_type(data, struct ifp_ctx); @@ -558,49 +555,18 @@ int ifp_domains_domain_is_online(struct sbus_request *sbus_req, return EOK; } - req = rdp_message_send(sbus_req, ifp_ctx->rctx, dom, DP_PATH, - IFACE_DP_BACKEND, IFACE_DP_BACKEND_ISONLINE, - DBUS_TYPE_STRING, &dom->name); - if (req == NULL) { - return ENOMEM; - } - - tevent_req_set_callback(req, ifp_domains_domain_is_online_done, sbus_req); + rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH, + IFACE_DP_BACKEND, IFACE_DP_BACKEND_ISONLINE, + DBUS_TYPE_STRING, &dom->name); return EOK; } -static void ifp_domains_domain_is_online_done(struct tevent_req *req) -{ - struct sbus_request *sbus_req; - DBusError *error; - bool is_online; - errno_t ret; - - sbus_req = tevent_req_callback_data(req, struct sbus_request); - - ret = rdp_message_recv(req, DBUS_TYPE_BOOLEAN, &is_online); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Unable to get online status [%d]: %s\n", - ret, sss_strerror(ret)); - error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, - "Unable to get online status [%d]: %s", - ret, sss_strerror(ret)); - sbus_request_fail_and_finish(sbus_req, error); - return; - } - - iface_ifp_domains_domain_IsOnline_finish(sbus_req, is_online); -} - -static void ifp_domains_domain_list_services_done(struct tevent_req *req); - int ifp_domains_domain_list_services(struct sbus_request *sbus_req, void *data) { struct ifp_ctx *ifp_ctx; struct sss_domain_info *dom; - struct tevent_req *req; DBusError *error; ifp_ctx = talloc_get_type(data, struct ifp_ctx); @@ -613,40 +579,10 @@ int ifp_domains_domain_list_services(struct sbus_request *sbus_req, return EOK; } - req = rdp_message_send(sbus_req, ifp_ctx->rctx, dom, DP_PATH, - IFACE_DP_FAILOVER, IFACE_DP_FAILOVER_LISTSERVICES, - DBUS_TYPE_STRING, &dom->name); - if (req == NULL) { - return ENOMEM; - } - - tevent_req_set_callback(req, ifp_domains_domain_list_services_done, sbus_req); + rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH, + IFACE_DP_FAILOVER, + IFACE_DP_FAILOVER_LISTSERVICES, + DBUS_TYPE_STRING, &dom->name); return EOK; } - -static void ifp_domains_domain_list_services_done(struct tevent_req *req) -{ - struct sbus_request *sbus_req; - DBusError *error; - int num_services; - const char **services; - errno_t ret; - - sbus_req = tevent_req_callback_data(req, struct sbus_request); - - ret = rdp_message_recv(req, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, - &services, &num_services); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Unable to get failover services [%d]: %s\n", - ret, sss_strerror(ret)); - error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, - "Unable to get failover services [%d]: %s", - ret, sss_strerror(ret)); - sbus_request_fail_and_finish(sbus_req, error); - return; - } - - iface_ifp_domains_domain_ListServices_finish(sbus_req, services, - num_services); -}