add async_ndr_call() similar to async_request()
authorStefan Metzmacher <metze@sernet.de>
Thu, 6 Sep 2007 16:03:57 +0000 (18:03 +0200)
committerStefan Metzmacher <metze@sernet.de>
Thu, 11 Oct 2007 15:21:45 +0000 (17:21 +0200)
metze

source/winbindd/winbindd_dual.c

index 228501b..097180f 100644 (file)
@@ -153,8 +153,12 @@ struct winbindd_async_request {
        struct winbindd_async_request *next, *prev;
        TALLOC_CTX *mem_ctx;
        struct winbindd_child *child;
-       struct winbindd_request *request;
-       struct winbindd_response *response;
+       bool is_ndr;
+       struct {
+               struct winbindd_request *request;
+               struct winbindd_response *response;
+       } old;
+       struct winbindd_ndr_call *call;
        void (*continuation)(void *private_data, BOOL success);
        struct timed_event *reply_timeout_event;
        pid_t child_pid; /* pid of the child we're waiting on. Used to detect
@@ -162,7 +166,7 @@ struct winbindd_async_request {
        void *private_data;
 };
 
-static void async_main_request_sent(void *private_data, BOOL success);
+static void async_old_main_request_sent(void *private_data, BOOL success);
 static void async_request_sent(void *private_data, BOOL success);
 static void async_reply_recv(void *private_data, BOOL success);
 static void schedule_async_request(struct winbindd_child *child);
@@ -187,10 +191,11 @@ void async_request(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
 
        state->mem_ctx = mem_ctx;
        state->child = child;
-       state->request = request;
-       state->response = response;
        state->continuation = continuation;
        state->private_data = private_data;
+       state->is_ndr = false;
+       state->old.request = request;
+       state->old.response = response;
 
        DLIST_ADD_END(child->requests, state, struct winbindd_async_request *);
 
@@ -199,7 +204,48 @@ void async_request(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
        return;
 }
 
-static void async_main_request_sent(void *private_data, BOOL success)
+void async_ndr_call(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
+                   struct winbindd_ndr_call *call,
+                   void (*continuation)(void *private_data, BOOL success),
+                   void *private_data)
+{
+       struct winbindd_async_request *state;
+       NTSTATUS status;
+
+       SMB_ASSERT(continuation != NULL);
+
+       state = TALLOC_P(mem_ctx, struct winbindd_async_request);
+
+       if (state == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               continuation(private_data, False);
+               return;
+       }
+
+       state->mem_ctx = mem_ctx;
+       state->child = child;
+       state->continuation = continuation;
+       state->private_data = private_data;
+       state->is_ndr = true;
+       state->call = call;
+
+       status = winbindd_push_ndr_request(state->mem_ctx,
+                                          state->call);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("failed to push request: %s\n",
+                       nt_errstr(status)));
+               continuation(private_data, False);
+               return;
+       }
+
+       DLIST_ADD_END(child->requests, state, struct winbindd_async_request *);
+
+       schedule_async_request(child);
+
+       return;
+}
+
+static void async_old_main_request_sent(void *private_data, BOOL success)
 {
        struct winbindd_async_request *state =
                talloc_get_type_abort(private_data, struct winbindd_async_request);
@@ -207,19 +253,20 @@ static void async_main_request_sent(void *private_data, BOOL success)
        if (!success) {
                DEBUG(5, ("Could not send async request\n"));
 
-               state->response->length = sizeof(struct winbindd_response);
-               state->response->result = WINBINDD_ERROR;
+               state->old.response->length = sizeof(struct winbindd_response);
+               state->old.response->result = WINBINDD_ERROR;
                state->continuation(state->private_data, False);
                return;
        }
 
-       if (state->request->extra_len == 0) {
+       if (state->old.request->extra_len == 0) {
                async_request_sent(private_data, True);
                return;
        }
 
-       setup_async_write(&state->child->event, state->request->extra_data.data,
-                         state->request->extra_len,
+       setup_async_write(&state->child->event,
+                         state->old.request->extra_data.data,
+                         state->old.request->extra_len,
                          async_request_sent, state);
 }
 
@@ -267,11 +314,73 @@ static void async_request_fail(struct winbindd_async_request *state)
                winbind_child_died(state->child_pid);
        }
 
-       state->response->length = sizeof(struct winbindd_response);
-       state->response->result = WINBINDD_ERROR;
+       if (state->is_ndr) {
+               state->call->out.header = state->call->in.header;
+               state->call->out.header.flags = 0;
+               state->call->out.header.flags |= WINBIND_HEADER_FLAGS_RESPONSE;
+               state->call->out.header.flags |= WINBIND_HEADER_FLAGS_ERROR;
+               state->call->ndr.result = WINBIND_STATUS_UNKNOWN_ERROR;
+       } else {
+               cache_cleanup_response(state->child_pid);
+               state->old.response->length = sizeof(struct winbindd_response);
+               state->old.response->result = WINBINDD_ERROR;
+       }
+
        state->continuation(state->private_data, False);
 }
 
+static void async_old_request_sent(struct winbindd_async_request *state)
+{
+       /* Request successfully sent to the child, setup the wait for reply */
+
+       setup_async_read(&state->child->event,
+                        &state->old.response->result,
+                        sizeof(state->old.response->result),
+                        async_reply_recv, state);
+}
+
+static void async_ndr_reply_recv_auto(void *private_data_data, BOOL success)
+{
+       struct winbindd_async_request *state =
+               talloc_get_type_abort(private_data_data, struct winbindd_async_request);
+       size_t autodetect_len = sizeof(state->call->autodetect);
+       NTSTATUS status;
+
+       if (!success) {
+               DEBUG(5, ("Could not recv async response from child pid %u\n",
+                       (unsigned int)state->child_pid ));
+               async_request_fail(state);
+               return;
+       }
+
+       status = winbindd_ndr_parse_autodetect(state->mem_ctx,
+                                              state->call,
+                                              WINBIND_MAX_LENGTH_PRIVILEGED,
+                                              False);
+       if (!NT_STATUS_IS_OK(status)) {
+               async_request_fail(state);
+               return;
+       }
+
+       setup_async_read(&state->child->event,
+                        state->call->out.packet.data + autodetect_len,
+                        state->call->out.packet.length - autodetect_len,
+                        async_reply_recv, state);
+}
+
+static void async_ndr_request_sent(struct winbindd_async_request *state)
+{
+       /*
+        * Request successfully sent to the child,
+        * setup the wait for first bytes of the reply
+        */
+
+       setup_async_read(&state->child->event,
+                        state->call->autodetect,
+                        sizeof(state->call->autodetect),
+                        async_ndr_reply_recv_auto, state);
+}
+
 static void async_request_sent(void *private_data_data, BOOL success)
 {
        struct winbindd_async_request *state =
@@ -286,10 +395,11 @@ static void async_request_sent(void *private_data_data, BOOL success)
 
        /* Request successfully sent to the child, setup the wait for reply */
 
-       setup_async_read(&state->child->event,
-                        &state->response->result,
-                        sizeof(state->response->result),
-                        async_reply_recv, state);
+       if (state->is_ndr) {
+               async_ndr_request_sent(state);
+       } else {
+               async_old_request_sent(state);
+       }
 
        /* 
         * Set up a timeout of 300 seconds for the response.
@@ -308,35 +418,60 @@ static void async_request_sent(void *private_data_data, BOOL success)
        }
 }
 
+static BOOL async_old_reply_recv(struct winbindd_async_request *state)
+{
+       state->old.response->length = sizeof(struct winbindd_response);
+
+       SMB_ASSERT(cache_retrieve_response(state->child_pid,
+                                          state->old.response));
+
+       cache_cleanup_response(state->child_pid);
+
+       return True;
+}
+
+static BOOL async_ndr_reply_recv(struct winbindd_async_request *state)
+{
+       NTSTATUS status;
+
+       status = winbindd_pull_ndr_response(state->mem_ctx,
+                                           state->call);
+       if (!NT_STATUS_IS_OK(status)) {
+               return False;
+       }
+
+       if (state->call->ndr.result != WINBIND_STATUS_OK) {
+               return False;
+       }
+
+       return True;
+}
+
 static void async_reply_recv(void *private_data, BOOL success)
 {
        struct winbindd_async_request *state =
                talloc_get_type_abort(private_data, struct winbindd_async_request);
-       struct winbindd_child *child = state->child;
-
-       TALLOC_FREE(state->reply_timeout_event);
-
-       state->response->length = sizeof(struct winbindd_response);
 
        if (!success) {
                DEBUG(5, ("Could not receive async reply from child pid %u\n",
                        (unsigned int)state->child_pid ));
 
-               cache_cleanup_response(state->child_pid);
                async_request_fail(state);
                return;
        }
 
-       SMB_ASSERT(cache_retrieve_response(state->child_pid,
-                                          state->response));
+       TALLOC_FREE(state->reply_timeout_event);
+       DLIST_REMOVE(state->child->requests, state);
 
-       cache_cleanup_response(state->child_pid);
-       
-       DLIST_REMOVE(child->requests, state);
+       if (state->is_ndr) {
+               success = async_ndr_reply_recv(state);
+       } else {
+               success = async_old_reply_recv(state);
+       }
 
-       schedule_async_request(child);
+       schedule_async_request(state->child);
 
-       state->continuation(state->private_data, True);
+       state->continuation(state->private_data, success);
 }
 
 static BOOL fork_domain_child(struct winbindd_child *child);
@@ -368,9 +503,15 @@ static void schedule_async_request(struct winbindd_child *child)
        /* Now we know who we're sending to - remember the pid. */
        request->child_pid = child->pid;
 
-       setup_async_write(&child->event, request->request,
-                         sizeof(*request->request),
-                         async_main_request_sent, request);
+       if (request->is_ndr) {
+               setup_async_write(&child->event, request->call->in.packet.data,
+                                 request->call->in.packet.length,
+                                 async_request_sent, request);
+       } else {
+               setup_async_write(&child->event, request->old.request,
+                                 sizeof(*request->old.request),
+                                 async_old_main_request_sent, request);
+       }
 
        return;
 }