From 6436efa410df3f26e719747bfd391d36d9566f92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Mon, 7 May 2012 10:52:26 +0200
Subject: [PATCH 16/29] sudo ldap provider: add new timer API

---
 Makefile.am                                |    1 +
 src/providers/ldap/sdap_async_sudo_timer.c |  165 ++++++++++++++++++++++++++++
 src/providers/ldap/sdap_sudo.h             |    8 +-
 3 files changed, 168 insertions(+), 6 deletions(-)
 create mode 100644 src/providers/ldap/sdap_async_sudo_timer.c

diff --git a/Makefile.am b/Makefile.am
index a71d6e9c445bc9a0b0306e513e69be615a046383..7da284011f1460352ba91f42f40257e84431d972 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1102,6 +1102,7 @@ if BUILD_SUDO
 libsss_ldap_common_la_SOURCES += \
     src/providers/ldap/sdap_sudo_cache.c \
     src/providers/ldap/sdap_async_sudo.c \
+    src/providers/ldap/sdap_async_sudo_timer.c \
     src/providers/ldap/sdap_sudo.c
 endif
 
diff --git a/src/providers/ldap/sdap_async_sudo_timer.c b/src/providers/ldap/sdap_async_sudo_timer.c
new file mode 100644
index 0000000000000000000000000000000000000000..4c5fc73ecd6aa5f1d2030ff071d6dcd48bbfd294
--- /dev/null
+++ b/src/providers/ldap/sdap_async_sudo_timer.c
@@ -0,0 +1,165 @@
+/*
+    Authors:
+        Pavel Březina <pbrezina@redhat.com>
+
+    Copyright (C) 2011 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <errno.h>
+#include <tevent.h>
+#include <talloc.h>
+
+#include "util/util.h"
+#include "providers/ldap/sdap.h"
+#include "providers/ldap/sdap_id_op.h"
+#include "providers/ldap/sdap_sudo.h"
+
+struct sdap_sudo_timer_state {
+    struct tevent_context *ev;
+    struct sdap_id_ctx *id_ctx;
+    struct timeval when;     /* absolute time when the timer should be fired */
+    time_t timeout;          /* relative time how many seconds wait before
+                                canceling fn request */
+    sdap_sudo_timer_fn_t fn; /* request executed on 'when' */
+
+    struct tevent_req *subreq;
+};
+
+static void sdap_sudo_timer(struct tevent_context *ev,
+                            struct tevent_timer *tt,
+                            struct timeval tv, void *pvt);
+
+static void sdap_sudo_timer_done(struct tevent_req *subreq);
+
+static void sdap_sudo_timer_timeout(struct tevent_context *ev,
+                                    struct tevent_timer *tt,
+                                    struct timeval tv, void *pvt);
+
+struct tevent_req * sdap_sudo_timer_send(TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev,
+                                         struct sdap_id_ctx *id_ctx,
+                                         struct timeval when,
+                                         time_t timeout,
+                                         sdap_sudo_timer_fn_t fn)
+{
+    struct tevent_req *req = NULL;
+    struct tevent_timer *timer = NULL;
+    struct sdap_sudo_timer_state *state = NULL;
+
+    /* create request */
+    req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_timer_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_FATAL_FAILURE, ("tevent_req_create() failed\n"));
+        return NULL;
+    }
+
+    state->ev = ev;
+    state->id_ctx = id_ctx;
+    state->when = when;
+    state->timeout = timeout;
+    state->fn = fn;
+
+    /* set timer */
+    timer = tevent_add_timer(ev, req, when, sdap_sudo_timer, req);
+    if (timer == NULL) {
+        DEBUG(SSSDBG_FATAL_FAILURE, ("tevent_add_timer() failed\n"));
+        talloc_zfree(req);
+        return NULL;
+    }
+
+    return req;
+}
+
+int sdap_sudo_timer_recv(TALLOC_CTX *mem_ctx,
+                         struct tevent_req *req,
+                         struct tevent_req **_subreq)
+{
+    struct sdap_sudo_timer_state *state = NULL;
+
+    state = tevent_req_data(req, struct sdap_sudo_timer_state);
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    *_subreq = talloc_steal(mem_ctx, state->subreq);
+
+    return EOK;
+}
+
+static void sdap_sudo_timer(struct tevent_context *ev,
+                            struct tevent_timer *tt,
+                            struct timeval tv, void *pvt)
+{
+    struct tevent_req *req = NULL;
+    struct tevent_req *subreq = NULL;
+    struct sdap_sudo_timer_state *state = NULL;
+    struct tevent_timer *timeout = NULL;
+
+    req = talloc_get_type(pvt, struct tevent_req);
+    state = tevent_req_data(req, struct sdap_sudo_timer_state);
+
+    /* issue request */
+    state->subreq = state->fn(state, state->id_ctx);
+    if (state->subreq == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to issue timed request!\n"));
+        tevent_req_error(req, ENOMEM);
+        return;
+    }
+
+    tevent_req_set_callback(state->subreq, sdap_sudo_timer_done, req);
+
+    /* schedule timeout */
+    tv = tevent_timeval_current_ofs(state->timeout, 0);
+    timeout = tevent_add_timer(state->ev, subreq, tv,
+                               sdap_sudo_timer_timeout, req);
+    if (timeout == NULL) {
+        /* If we can't guarantee a timeout, we
+         * need to cancel the request, to avoid
+         * the possibility of starting another
+         * concurrently
+         */
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to set timeout, "
+                                    "canceling request!\n"));
+        talloc_zfree(subreq);
+        tevent_req_error(req, ENOMEM);
+    }
+}
+
+static void sdap_sudo_timer_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = NULL;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    /* do not free subreq, it is returned in recv */
+
+    tevent_req_done(req);
+}
+
+static void sdap_sudo_timer_timeout(struct tevent_context *ev,
+                                    struct tevent_timer *tt,
+                                    struct timeval tv, void *pvt)
+{
+    struct tevent_req *req = NULL;
+    struct sdap_sudo_timer_state *state = NULL;
+
+    req = talloc_get_type(pvt, struct tevent_req);
+    state = tevent_req_data(req, struct sdap_sudo_timer_state);
+
+    DEBUG(SSSDBG_CRIT_FAILURE, ("Request timed out. Is timeout too small?"
+                                " (%ds)!\n", state->timeout));
+
+    talloc_zfree(state->subreq);
+
+    tevent_req_error(req, EAGAIN);
+}
diff --git a/src/providers/ldap/sdap_sudo.h b/src/providers/ldap/sdap_sudo.h
index 7be69841070dc2de32b79c2cbc9cef9176283a2e..26a0139c9b858cef9b2514ec333e6202d54d0139 100644
--- a/src/providers/ldap/sdap_sudo.h
+++ b/src/providers/ldap/sdap_sudo.h
@@ -43,15 +43,11 @@ int sdap_sudo_refresh_recv(struct tevent_req *req,
 /* timer */
 
 typedef struct tevent_req * (*sdap_sudo_timer_fn_t)(TALLOC_CTX *mem_ctx,
-                                        struct be_ctx *be_ctx,
-                                        struct sdap_options *opts,
-                                        struct sdap_id_conn_cache *conn_cache);
+                                                    struct sdap_id_ctx *id_ctx);
 
 struct tevent_req * sdap_sudo_timer_send(TALLOC_CTX *mem_ctx,
                                          struct tevent_context *ev,
-                                         struct be_ctx *be_ctx,
-                                         struct sdap_options *opts,
-                                         struct sdap_id_conn_cache *conn_cache,
+                                         struct sdap_id_ctx *id_ctx,
                                          struct timeval when,
                                          time_t timeout,
                                          sdap_sudo_timer_fn_t fn);
-- 
1.7.6.5

