Unfinished patch for winbind overload problem

Volker Lendecke Volker.Lendecke at SerNet.DE
Wed Feb 14 10:45:24 UTC 2018


Hi!

For your information only: Attached find a patch that completes
b4384b7f0ec with just a single queue. For me it works, but Metze does
not want to extend tevent_queue. So he's working on an alternative
approach. For everybody interested, feel free to pick up this patch in
distros.

Volker

-- 
Besuchen Sie die verinice.XP 2018 in Berlin,
Anwenderkonferenz für Informationssicherheit
vom 21.-23.03.2018 im Sofitel Kurfürstendamm
Info & Anmeldung hier: http://veriniceXP.org

SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de
-------------- next part --------------
From 2e3852a2333699119b8b05abe26868dd44d2eae4 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 11 Feb 2018 19:49:19 +0100
Subject: [PATCH 1/4] tevent: Add a helper variable

Easier to read for me :-)

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/tevent/tevent_queue.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/lib/tevent/tevent_queue.c b/lib/tevent/tevent_queue.c
index 5516c6cb1e5..2f82e28a4f6 100644
--- a/lib/tevent/tevent_queue.c
+++ b/lib/tevent/tevent_queue.c
@@ -136,17 +136,19 @@ static void tevent_queue_immediate_trigger(struct tevent_context *ev,
 	struct tevent_queue *q =
 		talloc_get_type_abort(private_data,
 		struct tevent_queue);
+	struct tevent_queue_entry *e;
 
 	if (!q->running) {
 		return;
 	}
 
-	if (!q->list) {
+	e = q->list;
+	if (e == NULL) {
 		return;
 	}
 
-	q->list->triggered = true;
-	q->list->trigger(q->list->req, q->list->private_data);
+	e->triggered = true;
+	e->trigger(e->req, e->private_data);
 }
 
 static struct tevent_queue_entry *tevent_queue_add_internal(
-- 
2.11.0


From 467cba727791d3c33c9c3c21f645e6371682122e Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 11 Feb 2018 19:50:06 +0100
Subject: [PATCH 2/4] tevent: Simplify tevent_queue_add a bit

Easier to read for me :-)

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/tevent/tevent_queue.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/lib/tevent/tevent_queue.c b/lib/tevent/tevent_queue.c
index 2f82e28a4f6..d76f4f126d0 100644
--- a/lib/tevent/tevent_queue.c
+++ b/lib/tevent/tevent_queue.c
@@ -239,11 +239,7 @@ bool tevent_queue_add(struct tevent_queue *queue,
 
 	e = tevent_queue_add_internal(queue, ev, req,
 				      trigger, private_data, false);
-	if (e == NULL) {
-		return false;
-	}
-
-	return true;
+	return (e != NULL);
 }
 
 struct tevent_queue_entry *tevent_queue_add_entry(
-- 
2.11.0


From 7c1f45f29fc8a04c2ca513bd3f4d8c33000109f0 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 11 Feb 2018 19:51:12 +0100
Subject: [PATCH 3/4] tevent: Add tevent_queue_add_retryable_entry

---
 lib/tevent/ABI/tevent-0.9.36.sigs | 100 ++++++++++++++++++++++++++++++++++++++
 lib/tevent/tevent.h               |  38 +++++++++++++++
 lib/tevent/tevent_queue.c         |  47 ++++++++++++++----
 lib/tevent/wscript                |   2 +-
 4 files changed, 176 insertions(+), 11 deletions(-)
 create mode 100644 lib/tevent/ABI/tevent-0.9.36.sigs

diff --git a/lib/tevent/ABI/tevent-0.9.36.sigs b/lib/tevent/ABI/tevent-0.9.36.sigs
new file mode 100644
index 00000000000..916d80e86e7
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.36.sigs
@@ -0,0 +1,100 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_retryable_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_retryable_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
index 7284a8559d2..23756e63777 100644
--- a/lib/tevent/tevent.h
+++ b/lib/tevent/tevent.h
@@ -1541,6 +1541,8 @@ struct tevent_queue *_tevent_queue_create(TALLOC_CTX *mem_ctx,
  */
 typedef void (*tevent_queue_trigger_fn_t)(struct tevent_req *req,
 					  void *private_data);
+typedef bool (*tevent_queue_retryable_trigger_fn_t)(struct tevent_req *req,
+						    void *private_data);
 
 /**
  * @brief Add a tevent request to the queue.
@@ -1601,6 +1603,42 @@ struct tevent_queue_entry *tevent_queue_add_entry(
 					void *private_data);
 
 /**
+ * @brief Add a tevent request to the queue.
+ *
+ * The request can be removed from the queue by calling talloc_free()
+ * (or a similar function) on the returned queue entry. This
+ * is the only difference to tevent_queue_add().
+ *
+ * @param[in]  queue    The queue to add the request.
+ *
+ * @param[in]  ev       The event handle to use for the request.
+ *
+ * @param[in]  req      The tevent request to add to the queue.
+ *
+ * @param[in]  trigger  The function triggered by the queue when the request
+ *                      is called. Since tevent 0.9.14 it's possible to
+ *                      pass NULL, in order to just add a "blocker" to the
+ *                      queue. If the trigger returns false, the queue will
+ *                      implicitly stopped. Upon restart, the request that
+ *                      failed will be re-triggered.
+ *
+ * @param[in]  private_data The private data passed to the trigger function.
+ *
+ * @return              a pointer to the tevent_queue_entry if the request
+ *                      has been successfully added, NULL otherwise.
+ *
+ * @see tevent_queue_add()
+ * @see tevent_queue_add_optimize_empty()
+ */
+
+struct tevent_queue_entry *tevent_queue_add_retryable_entry(
+	struct tevent_queue *queue,
+	struct tevent_context *ev,
+	struct tevent_req *req,
+	tevent_queue_retryable_trigger_fn_t trigger,
+	void *private_data);
+
+/**
  * @brief Add a tevent request to the queue using a possible optimization.
  *
  * This tries to optimize for the empty queue case and may calls
diff --git a/lib/tevent/tevent_queue.c b/lib/tevent/tevent_queue.c
index d76f4f126d0..1a1729d94ae 100644
--- a/lib/tevent/tevent_queue.c
+++ b/lib/tevent/tevent_queue.c
@@ -37,6 +37,7 @@ struct tevent_queue_entry {
 	struct tevent_context *ev;
 
 	tevent_queue_trigger_fn_t trigger;
+	tevent_queue_retryable_trigger_fn_t retryable_trigger;
 	void *private_data;
 };
 
@@ -147,17 +148,31 @@ static void tevent_queue_immediate_trigger(struct tevent_context *ev,
 		return;
 	}
 
+	if (e->retryable_trigger != NULL) {
+		bool ok;
+
+		e->triggered = true;
+		ok = e->retryable_trigger(e->req, e->private_data);
+		if (ok) {
+			return;
+		}
+		e->triggered = false;
+		tevent_queue_stop(q);
+		return;
+	}
+
 	e->triggered = true;
 	e->trigger(e->req, e->private_data);
 }
 
 static struct tevent_queue_entry *tevent_queue_add_internal(
-					struct tevent_queue *queue,
-					struct tevent_context *ev,
-					struct tevent_req *req,
-					tevent_queue_trigger_fn_t trigger,
-					void *private_data,
-					bool allow_direct)
+	struct tevent_queue *queue,
+	struct tevent_context *ev,
+	struct tevent_req *req,
+	tevent_queue_trigger_fn_t trigger,
+	tevent_queue_retryable_trigger_fn_t retryable_trigger,
+	void *private_data,
+	bool allow_direct)
 {
 	struct tevent_queue_entry *e;
 
@@ -170,12 +185,13 @@ static struct tevent_queue_entry *tevent_queue_add_internal(
 	e->req = req;
 	e->ev = ev;
 	e->trigger = trigger;
+	e->retryable_trigger = retryable_trigger;
 	e->private_data = private_data;
 
 	/*
 	 * if there is no trigger, it is just a blocker
 	 */
-	if (trigger == NULL) {
+	if ((trigger == NULL) && (retryable_trigger == NULL)) {
 		e->triggered = true;
 	}
 
@@ -238,7 +254,7 @@ bool tevent_queue_add(struct tevent_queue *queue,
 	struct tevent_queue_entry *e;
 
 	e = tevent_queue_add_internal(queue, ev, req,
-				      trigger, private_data, false);
+				      trigger, NULL, private_data, false);
 	return (e != NULL);
 }
 
@@ -250,7 +266,7 @@ struct tevent_queue_entry *tevent_queue_add_entry(
 					void *private_data)
 {
 	return tevent_queue_add_internal(queue, ev, req,
-					 trigger, private_data, false);
+					 trigger, NULL, private_data, false);
 }
 
 struct tevent_queue_entry *tevent_queue_add_optimize_empty(
@@ -261,7 +277,18 @@ struct tevent_queue_entry *tevent_queue_add_optimize_empty(
 					void *private_data)
 {
 	return tevent_queue_add_internal(queue, ev, req,
-					 trigger, private_data, true);
+					 trigger, NULL, private_data, true);
+}
+
+struct tevent_queue_entry *tevent_queue_add_retryable_entry(
+	struct tevent_queue *queue,
+	struct tevent_context *ev,
+	struct tevent_req *req,
+	tevent_queue_retryable_trigger_fn_t trigger,
+	void *private_data)
+{
+	return tevent_queue_add_internal(queue, ev, req, NULL,
+					 trigger, private_data, false);
 }
 
 void tevent_queue_start(struct tevent_queue *queue)
diff --git a/lib/tevent/wscript b/lib/tevent/wscript
index 2c67f1f57ee..94d190f3b60 100644
--- a/lib/tevent/wscript
+++ b/lib/tevent/wscript
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 APPNAME = 'tevent'
-VERSION = '0.9.35'
+VERSION = '0.9.36'
 
 blddir = 'bin'
 
-- 
2.11.0


From 6f46a85def62b710e3808f71ec0053c4da2b871b Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 13 Feb 2018 16:04:44 +0100
Subject: [PATCH 4/4] winbind: Use one queue for all domain children

---
 source3/winbindd/winbindd.h          |  3 ++
 source3/winbindd/winbindd_dual.c     | 71 +++++++++++++++++++++++++++++-------
 source3/winbindd/winbindd_dual_ndr.c | 58 ++++++++++++++++++++++++++---
 source3/winbindd/winbindd_util.c     | 12 ++++++
 4 files changed, 125 insertions(+), 19 deletions(-)

diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h
index 3e4b256ef32..081722f6a90 100644
--- a/source3/winbindd/winbindd.h
+++ b/source3/winbindd/winbindd.h
@@ -184,6 +184,9 @@ struct winbindd_domain {
 
 	struct winbindd_child *children;
 
+	struct tevent_queue *queue;
+	struct dcerpc_binding_handle *binding_handle;
+
 	/* Callback we use to try put us back online. */
 
 	uint32_t check_online_timeout;
diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c
index 7fb5aa899e4..b7b409da10e 100644
--- a/source3/winbindd/winbindd_dual.c
+++ b/source3/winbindd/winbindd_dual.c
@@ -277,14 +277,12 @@ struct winbindd_child *choose_domain_child(struct winbindd_domain *domain)
 
 struct dcerpc_binding_handle *dom_child_handle(struct winbindd_domain *domain)
 {
-	struct winbindd_child *child;
-
-	child = choose_domain_child(domain);
-	return child->binding_handle;
+	return domain->binding_handle;
 }
 
 struct wb_domain_request_state {
 	struct tevent_context *ev;
+	struct tevent_queue_entry *queue_entry;
 	struct winbindd_domain *domain;
 	struct winbindd_child *child;
 	struct winbindd_request *request;
@@ -292,6 +290,8 @@ struct wb_domain_request_state {
 	struct winbindd_response *response;
 };
 
+static bool wb_domain_request_trigger(struct tevent_req *req,
+				      void *private_data);
 static void wb_domain_request_gotdc(struct tevent_req *subreq);
 static void wb_domain_request_initialized(struct tevent_req *subreq);
 static void wb_domain_request_done(struct tevent_req *subreq);
@@ -310,21 +310,21 @@ struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx,
 		return NULL;
 	}
 
-	state->child = choose_domain_child(domain);
+	state->domain = domain;
+	state->ev = ev;
+	state->request = request;
 
 	if (domain->initialized) {
-		subreq = wb_child_request_send(state, ev, state->child,
-					       request);
-		if (tevent_req_nomem(subreq, req)) {
+		state->queue_entry = tevent_queue_add_retryable_entry(
+			domain->queue, ev, req, wb_domain_request_trigger,
+			NULL);
+		if (tevent_req_nomem(state->queue_entry, req)) {
 			return tevent_req_post(req, ev);
 		}
-		tevent_req_set_callback(subreq, wb_domain_request_done, req);
 		return req;
 	}
 
-	state->domain = domain;
-	state->ev = ev;
-	state->request = request;
+	state->child = choose_domain_child(domain);
 
 	state->init_req = talloc_zero(state, struct winbindd_request);
 	if (tevent_req_nomem(state->init_req, req)) {
@@ -359,7 +359,7 @@ struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx,
 	state->init_req->cmd = WINBINDD_GETDCNAME;
 	fstrcpy(state->init_req->domain_name, domain->name);
 
-	subreq = wb_child_request_send(state, ev, state->child, request);
+	subreq = wb_child_request_send(state, ev, state->child, state->request);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
@@ -367,6 +367,45 @@ struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx,
 	return req;
 }
 
+static bool wb_domain_request_trigger(struct tevent_req *req,
+				      void *private_data)
+{
+	struct wb_domain_request_state *state = tevent_req_data(
+		req, struct wb_domain_request_state);
+	struct winbindd_domain *domain = state->domain;
+	struct winbindd_child *child = NULL;
+	struct tevent_req *subreq;
+	int i;
+
+	for (i=0; i<lp_winbind_max_domain_connections(); i++) {
+		struct winbindd_child *c = &domain->children[i];
+
+		if (tevent_queue_length(c->queue) == 0) {
+			child = c;
+			break;
+		}
+	}
+
+	if (child == NULL) {
+		return false;
+	}
+
+	subreq = wb_child_request_send(state, state->ev, child,
+				       state->request);
+	if (tevent_req_nomem(subreq, req)) {
+		/* "true" means trigger was okay, try the next one */
+		return true;
+	}
+	tevent_req_set_callback(subreq, wb_domain_request_done, req);
+
+	/*
+	 * Trigger the next entry, there might be more children idle
+	 */
+	TALLOC_FREE(state->queue_entry);
+
+	return true;
+}
+
 static void wb_domain_request_gotdc(struct tevent_req *subreq)
 {
 	struct tevent_req *req = tevent_req_callback_data(
@@ -462,6 +501,7 @@ static void wb_domain_request_done(struct tevent_req *subreq)
 		subreq, struct tevent_req);
 	struct wb_domain_request_state *state = tevent_req_data(
 		req, struct wb_domain_request_state);
+	struct tevent_queue *queue = state->domain->queue;
 	int ret, err;
 
 	ret = wb_child_request_recv(subreq, talloc_tos(), &state->response,
@@ -472,6 +512,11 @@ static void wb_domain_request_done(struct tevent_req *subreq)
 		return;
 	}
 	tevent_req_done(req);
+
+	/*
+	 * We just freed up a child. Trigger the domain queue
+	 */
+	tevent_queue_start(queue);
 }
 
 int wb_domain_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
diff --git a/source3/winbindd/winbindd_dual_ndr.c b/source3/winbindd/winbindd_dual_ndr.c
index 00c7df1f863..479dec41bd4 100644
--- a/source3/winbindd/winbindd_dual_ndr.c
+++ b/source3/winbindd/winbindd_dual_ndr.c
@@ -42,7 +42,7 @@ static bool wbint_bh_is_connected(struct dcerpc_binding_handle *h)
 	struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
 				     struct wbint_bh_state);
 
-	if (!hs->child) {
+	if ((hs->domain == NULL) && (hs->child == NULL)) {
 		return false;
 	}
 
@@ -65,7 +65,8 @@ struct wbint_bh_raw_call_state {
 	DATA_BLOB out_data;
 };
 
-static void wbint_bh_raw_call_done(struct tevent_req *subreq);
+static void wbint_bh_raw_call_child_done(struct tevent_req *subreq);
+static void wbint_bh_raw_call_domain_done(struct tevent_req *subreq);
 
 static struct tevent_req *wbint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
 						  struct tevent_context *ev,
@@ -114,17 +115,28 @@ static struct tevent_req *wbint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
 	state->request.extra_data.data = (char *)state->in_data.data;
 	state->request.extra_len = state->in_data.length;
 
-	subreq = wb_child_request_send(state, ev, hs->child,
-				       &state->request);
+	if (hs->child != NULL) {
+		subreq = wb_child_request_send(state, ev, hs->child,
+					       &state->request);
+		if (tevent_req_nomem(subreq, req)) {
+			return tevent_req_post(req, ev);
+		}
+		tevent_req_set_callback(
+			subreq, wbint_bh_raw_call_child_done, req);
+		return req;
+	}
+
+	subreq = wb_domain_request_send(state, ev, hs->domain,
+					&state->request);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
-	tevent_req_set_callback(subreq, wbint_bh_raw_call_done, req);
+	tevent_req_set_callback(subreq, wbint_bh_raw_call_domain_done, req);
 
 	return req;
 }
 
-static void wbint_bh_raw_call_done(struct tevent_req *subreq)
+static void wbint_bh_raw_call_child_done(struct tevent_req *subreq)
 {
 	struct tevent_req *req =
 		tevent_req_callback_data(subreq,
@@ -158,6 +170,40 @@ static void wbint_bh_raw_call_done(struct tevent_req *subreq)
 	tevent_req_done(req);
 }
 
+static void wbint_bh_raw_call_domain_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+		tevent_req_callback_data(subreq,
+		struct tevent_req);
+	struct wbint_bh_raw_call_state *state =
+		tevent_req_data(req,
+		struct wbint_bh_raw_call_state);
+	int ret, err;
+
+	ret = wb_domain_request_recv(subreq, state, &state->response, &err);
+	TALLOC_FREE(subreq);
+	if (ret == -1) {
+		NTSTATUS status = map_nt_error_from_unix(err);
+		tevent_req_nterror(req, status);
+		return;
+	}
+
+	state->out_data = data_blob_talloc(state,
+		state->response->extra_data.data,
+		state->response->length - sizeof(struct winbindd_response));
+	if (state->response->extra_data.data && !state->out_data.data) {
+		tevent_req_oom(req);
+		return;
+	}
+
+	if (state->domain != NULL) {
+		wcache_store_ndr(state->domain, state->opnum,
+				 &state->in_data, &state->out_data);
+	}
+
+	tevent_req_done(req);
+}
+
 static NTSTATUS wbint_bh_raw_call_recv(struct tevent_req *req,
 					TALLOC_CTX *mem_ctx,
 					uint8_t **out_data,
diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index 6292cce9d51..1cd6fd72870 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -228,6 +228,18 @@ static NTSTATUS add_trusted_domain(const char *domain_name,
 		return NT_STATUS_NO_MEMORY;
 	}
 
+	domain->queue = tevent_queue_create(domain, "winbind_domain");
+	if (domain->queue == NULL) {
+		TALLOC_FREE(domain);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	domain->binding_handle = wbint_binding_handle(domain, domain, NULL);
+	if (domain->binding_handle == NULL) {
+		TALLOC_FREE(domain);
+		return NT_STATUS_NO_MEMORY;
+	}
+
 	domain->name = talloc_strdup(domain, domain_name);
 	if (domain->name == NULL) {
 		TALLOC_FREE(domain);
-- 
2.11.0



More information about the samba-technical mailing list