static void wb_child_request_orphaned(struct tevent_req *subreq)
{
+ struct winbindd_child *child =
+ (struct winbindd_child *)tevent_req_callback_data_void(subreq);
+
DBG_WARNING("cleanup orphaned subreq[%p]\n", subreq);
TALLOC_FREE(subreq);
+
+ if (child->domain != NULL) {
+ /*
+ * If the child is attached to a domain,
+ * we need to make sure the domain queue
+ * can move forward, after the orphaned
+ * request is done.
+ */
+ tevent_queue_start(child->domain->queue);
+ }
}
int wb_child_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
talloc_move(subreq, &state->queue_subreq);
tevent_req_set_callback(subreq,
wb_child_request_orphaned,
- NULL);
+ state->child);
DBG_WARNING("keep orphaned subreq[%p]\n", subreq);
return;
TALLOC_FREE(state->subreq);
TALLOC_FREE(state->queue_subreq);
+ if (state->child->domain != NULL) {
+ /*
+ * If the child is attached to a domain,
+ * we need to make sure the domain queue
+ * can move forward, after the request
+ * is done.
+ */
+ tevent_queue_start(state->child->domain->queue);
+ }
+
if (req_state == TEVENT_REQ_DONE) {
/* transmitted request and got response */
return;
DLIST_REMOVE(winbindd_children, state->child);
}
-struct winbindd_child *choose_domain_child(struct winbindd_domain *domain)
+static struct winbindd_child *choose_domain_child(struct winbindd_domain *domain)
{
struct winbindd_child *shortest = &domain->children[0];
struct winbindd_child *current;
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;
struct winbindd_request *init_req;
struct winbindd_response *response;
+ struct tevent_req *pending_subreq;
};
+static void wb_domain_request_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct wb_domain_request_state *state = tevent_req_data(
+ req, struct wb_domain_request_state);
+
+ /*
+ * If we're completely done or got a failure.
+ * we should remove ourself from the domain queue,
+ * after removing the child subreq from the child queue
+ * and give the next one in the queue the chance
+ * to check for an idle child.
+ */
+ TALLOC_FREE(state->pending_subreq);
+ TALLOC_FREE(state->queue_entry);
+ tevent_queue_start(state->domain->queue);
+}
+
+static void 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);
struct winbindd_domain *domain,
struct winbindd_request *request)
{
- struct tevent_req *req, *subreq;
+ struct tevent_req *req;
struct wb_domain_request_state *state;
req = tevent_req_create(mem_ctx, &state,
state->ev = ev;
state->request = request;
+ tevent_req_set_cleanup_fn(req, wb_domain_request_cleanup);
+
+ state->queue_entry = tevent_queue_add_entry(
+ domain->queue, state->ev, req,
+ wb_domain_request_trigger, NULL);
+ if (tevent_req_nomem(state->queue_entry, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void 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 tevent_req *subreq = NULL;
+ size_t shortest_queue_length;
+
state->child = choose_domain_child(domain);
+ shortest_queue_length = tevent_queue_length(state->child->queue);
+ if (shortest_queue_length > 0) {
+ /*
+ * All children are busy, we need to stop
+ * the queue and untrigger our own queue
+ * entry. Once a pending request
+ * is done it calls tevent_queue_start
+ * and we get retriggered.
+ */
+ state->child = NULL;
+ tevent_queue_stop(state->domain->queue);
+ tevent_queue_entry_untrigger(state->queue_entry);
+ return;
+ }
if (domain->initialized) {
subreq = wb_child_request_send(state, state->ev, state->child,
state->request);
if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
+ return;
}
tevent_req_set_callback(subreq, wb_domain_request_done, req);
- return req;
+ state->pending_subreq = subreq;
+
+ /*
+ * Once the domain is initialized and
+ * once we placed our real request into the child queue,
+ * we can remove ourself from the domain queue
+ * and give the next one in the queue the chance
+ * to check for an idle child.
+ */
+ TALLOC_FREE(state->queue_entry);
+ return;
}
state->init_req = talloc_zero(state, struct winbindd_request);
if (tevent_req_nomem(state->init_req, req)) {
- return tevent_req_post(req, ev);
+ return;
}
if (IS_DC || domain->primary || domain->internal) {
subreq = wb_child_request_send(state, state->ev, state->child,
state->init_req);
if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
+ return;
}
tevent_req_set_callback(subreq, wb_domain_request_initialized,
req);
- return req;
+ state->pending_subreq = subreq;
+ return;
}
/*
- * Ask our DC for a DC name
+ * This is *not* the primary domain,
+ * let's ask our DC about a DC name.
+ *
+ * We prefer getting a dns name in dc_unc,
+ * which is indicated by DS_RETURN_DNS_NAME.
+ * For NT4 domains we still get the netbios name.
*/
- domain = find_our_domain();
-
- /* This is *not* the primary domain, let's ask our DC about a DC
- * name */
-
- state->init_req->cmd = WINBINDD_GETDCNAME;
- fstrcpy(state->init_req->domain_name, domain->name);
-
- subreq = wb_child_request_send(state, state->ev, state->child,
- state->request);
+ subreq = wb_dsgetdcname_send(state, state->ev,
+ state->domain->name,
+ NULL, /* domain_guid */
+ NULL, /* site_name */
+ DS_RETURN_DNS_NAME); /* flags */
if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
+ return;
}
tevent_req_set_callback(subreq, wb_domain_request_gotdc, req);
- return req;
+ state->pending_subreq = subreq;
+ return;
}
static void wb_domain_request_gotdc(struct tevent_req *subreq)
subreq, struct tevent_req);
struct wb_domain_request_state *state = tevent_req_data(
req, struct wb_domain_request_state);
- struct winbindd_response *response;
- int ret, err;
+ struct netr_DsRGetDCNameInfo *dcinfo = NULL;
+ NTSTATUS status;
+ const char *dcname = NULL;
- ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err);
+ state->pending_subreq = NULL;
+
+ status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
TALLOC_FREE(subreq);
- if (ret == -1) {
- tevent_req_error(req, err);
+ if (tevent_req_nterror(req, status)) {
return;
}
+ dcname = dcinfo->dc_unc;
+ while (dcname != NULL && *dcname == '\\') {
+ dcname++;
+ }
state->init_req->cmd = WINBINDD_INIT_CONNECTION;
fstrcpy(state->init_req->domain_name, state->domain->name);
state->init_req->data.init_conn.is_primary = False;
fstrcpy(state->init_req->data.init_conn.dcname,
- response->data.dc_name);
+ dcname);
- TALLOC_FREE(response);
+ TALLOC_FREE(dcinfo);
subreq = wb_child_request_send(state, state->ev, state->child,
state->init_req);
return;
}
tevent_req_set_callback(subreq, wb_domain_request_initialized, req);
+ state->pending_subreq = subreq;
}
static void wb_domain_request_initialized(struct tevent_req *subreq)
struct winbindd_response *response;
int ret, err;
+ state->pending_subreq = NULL;
+
ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err);
TALLOC_FREE(subreq);
if (ret == -1) {
return;
}
tevent_req_set_callback(subreq, wb_domain_request_done, req);
+ state->pending_subreq = subreq;
+
+ /*
+ * Once the domain is initialized and
+ * once we placed our real request into the child queue,
+ * we can remove ourself from the domain queue
+ * and give the next one in the queue the chance
+ * to check for an idle child.
+ */
+ TALLOC_FREE(state->queue_entry);
}
static void wb_domain_request_done(struct tevent_req *subreq)
req, struct wb_domain_request_state);
int ret, err;
+ state->pending_subreq = NULL;
+
ret = wb_child_request_recv(subreq, talloc_tos(), &state->response,
&err);
TALLOC_FREE(subreq);
child->table = table;
child->queue = tevent_queue_create(NULL, "winbind_child");
SMB_ASSERT(child->queue != NULL);
- child->binding_handle = wbint_binding_handle(NULL, domain, child);
- SMB_ASSERT(child->binding_handle != NULL);
+ if (domain == NULL) {
+ child->binding_handle = wbint_binding_handle(NULL, NULL, child);
+ SMB_ASSERT(child->binding_handle != NULL);
+ }
}
void winbind_child_died(pid_t pid)
talloc_destroy(mem_ctx);
}
-void winbind_msg_dump_event_list(struct messaging_context *msg_ctx,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- struct winbindd_child *child;
-
- DEBUG(10,("winbind_msg_dump_event_list received\n"));
-
- DBG_WARNING("dump event list no longer implemented\n");
-
- for (child = winbindd_children; child != NULL; child = child->next) {
-
- DEBUG(10,("winbind_msg_dump_event_list: sending message to pid %u\n",
- (unsigned int)child->pid));
-
- messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
- MSG_DUMP_EVENT_LIST,
- NULL, 0);
- }
-
-}
-
void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx,
void *private_data,
uint32_t msg_type,
}
}
-static void child_msg_dump_event_list(struct messaging_context *msg,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- DEBUG(5,("child_msg_dump_event_list received\n"));
- DBG_WARNING("dump_event_list no longer implemented\n");
-}
-
NTSTATUS winbindd_reinit_after_fork(const struct winbindd_child *myself,
const char *logfilename)
{
MSG_WINBIND_ONLINE, NULL);
messaging_deregister(server_messaging_context(),
MSG_WINBIND_ONLINESTATUS, NULL);
- messaging_deregister(server_messaging_context(),
- MSG_DUMP_EVENT_LIST, NULL);
messaging_deregister(server_messaging_context(),
MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
messaging_deregister(server_messaging_context(),
MSG_WINBIND_OFFLINE, child_msg_offline);
messaging_register(server_messaging_context(), NULL,
MSG_WINBIND_ONLINE, child_msg_online);
- messaging_register(server_messaging_context(), NULL,
- MSG_DUMP_EVENT_LIST, child_msg_dump_event_list);
messaging_register(server_messaging_context(), NULL,
MSG_DEBUG, debug_message);
messaging_register(server_messaging_context(), NULL,