From b1e3e8ead9c97a36034014a5ed316576fcc63f15 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 28 Jun 2016 11:40:16 +0200
Subject: [PATCH 1/7] 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.
---
 src/responder/common/data_provider/rdp.h         |  20 ++
 src/responder/common/data_provider/rdp_message.c | 260 +++++++++++++++++------
 src/responder/ifp/ifp_domains.c                  |  73 +------
 3 files changed, 217 insertions(+), 136 deletions(-)

diff --git a/src/responder/common/data_provider/rdp.h b/src/responder/common/data_provider/rdp.h
index 8a3ec803d8ea7914e2a54661e31dec084586582a..f0aed179a3d33de0462591e6c0bcd3c518105707 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 78af6f8967b378536b6456274fbcac4b609d1033..e226401567e4a1b2b9784a9aba21540ff5f0bc8d 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)
+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)
 {
-    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 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);
+    } else {
+        tevent_req_error(req, ret);
+    }
+    tevent_req_post(req, rctx->ev);
+
+    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;
     }
 
-    if (reply != NULL) {
-        dbus_message_unref(reply);
-    }
-    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 5333b25275e0847015f9cdd294eab5dbdda32f6c..80c57a486d277b2bff21023f72be2ccffc72ba09 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,9 @@ 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,
+    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);
-    if (req == NULL) {
-        return ENOMEM;
-    }
-
-    tevent_req_set_callback(req, ifp_domains_domain_list_services_done, sbus_req);
 
     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);
-}
-- 
2.1.0

