pidl:s3-rpc: make pidl rpc server api calls async
authorDavid Disseldorp <ddiss@samba.org>
Fri, 27 Apr 2012 15:11:20 +0000 (17:11 +0200)
committerDavid Disseldorp <ddiss@samba.org>
Wed, 19 Sep 2012 03:59:02 +0000 (05:59 +0200)
pidl/lib/Parse/Pidl/Samba3/ServerNDR.pm
source3/rpc_server/rpc_ncacn_np.c
source3/rpc_server/rpc_pipes.h
source3/rpc_server/srv_pipe.c
source3/winbindd/winbindd_dual_ndr.c

index d433f60eb7dedaf032eb501b4117a2bf4114152f..bc31e9738ddbbaf641e55296cbf0aa29ab0547da 100644 (file)
@@ -2,6 +2,7 @@
 # Samba3 server generator for IDL structures
 # on top of Samba4 style NDR functions
 # Copyright jelmer@samba.org 2005-2006
+# Copyright (C) David Disseldorp 2012
 # released under the GNU GPL
 
 package Parse::Pidl::Samba3::ServerNDR;
@@ -132,15 +133,30 @@ sub CallWithStruct($$$$)
        pidl "$ret;";
 }
 
-sub ParseFunction($$)
+sub ParseFunctionAsyncState($$)
+{
+       my ($if,$fn) = @_;
+       pidl "struct api_$fn->{NAME}_state {";
+       pidl "  struct $fn->{NAME} r;";
+       pidl "  struct pipes_struct *p;";
+       pidl "  bool ret;";
+       pidl "};";
+       pidl "";
+}
+
+sub ParseFunctionAsyncSend($$)
 {
        my ($if,$fn) = @_;
 
        my $op = "NDR_".uc($fn->{NAME});
 
-       pidl "static bool api_$fn->{NAME}(struct pipes_struct *p)";
+       pidl "static struct tevent_req *api_$fn->{NAME}_send(struct tevent_context *ev,";
+       pidl "                                        TALLOC_CTX *mem_ctx,";
+       pidl "                                        struct pipes_struct *p)";
        pidl "{";
        indent;
+       pidl "struct tevent_req *req;";
+       pidl "struct api_$fn->{NAME}_state *state;";
        pidl "const struct ndr_interface_call *call;";
        pidl "struct ndr_pull *pull;";
        pidl "struct ndr_push *push;";
@@ -149,15 +165,18 @@ sub ParseFunction($$)
        pidl "";
        pidl "call = &ndr_table_$if->{NAME}.calls[$op];";
        pidl "";
-       pidl "r = talloc(talloc_tos(), struct $fn->{NAME});";
-       pidl "if (r == NULL) {";
-       pidl "\treturn false;";
+       pidl "req = tevent_req_create(mem_ctx, &state, struct api_$fn->{NAME}_state);";
+       pidl "if (req == NULL) {";
+       pidl "  return NULL;";
        pidl "}";
+       pidl "state->p = p;";
+       pidl "r = &state->r;";
        pidl "";
        pidl "pull = ndr_pull_init_blob(&p->in_data.data, r);";
        pidl "if (pull == NULL) {";
-       pidl "\ttalloc_free(r);";
-       pidl "\treturn false;";
+       pidl "  state->ret = false;";
+       pidl "  tevent_req_done(req);";
+       pidl "  return tevent_req_post(req, ev);";
        pidl "}";
        pidl "";
        pidl "pull->flags |= LIBNDR_FLAG_REF_ALLOC;";
@@ -166,8 +185,9 @@ sub ParseFunction($$)
        pidl "}";
        pidl "ndr_err = call->ndr_pull(pull, NDR_IN, r);";
        pidl "if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {";
-       pidl "\ttalloc_free(r);";
-       pidl "\treturn false;";
+       pidl "  state->ret = false;";
+       pidl "  tevent_req_done(req);";
+       pidl "  return tevent_req_post(req, ev);";
        pidl "}";
        pidl "";
        pidl "if (DEBUGLEVEL >= 10) {";
@@ -175,10 +195,11 @@ sub ParseFunction($$)
        pidl "}";
        pidl "";
 
-       CallWithStruct("p", "r", $fn, 
-       sub { 
-                       pidl "\ttalloc_free(r);";
-                       pidl "\treturn false;";
+       CallWithStruct("p", "state", $fn,
+               sub {
+                       pidl "  state->ret = false;";
+                       pidl "  tevent_req_done(req);";
+                       pidl "  return tevent_req_post(req, ev);";
                }
        );
 
@@ -186,7 +207,9 @@ sub ParseFunction($$)
        pidl "if (p->fault_state) {";
        pidl "\ttalloc_free(r);";
        pidl "\t/* Return true here, srv_pipe_hnd.c will take care */";
-       pidl "\treturn true;";
+       pidl "\tstate->ret = true;";
+       pidl "\ttevent_req_done(req);";
+       pidl "\treturn tevent_req_post(req, ev);";
        pidl "}";
        pidl "";
        pidl "if (DEBUGLEVEL >= 10) {";
@@ -195,8 +218,9 @@ sub ParseFunction($$)
        pidl "";
        pidl "push = ndr_push_init_ctx(r);";
        pidl "if (push == NULL) {";
-       pidl "\ttalloc_free(r);";
-       pidl "\treturn false;";
+       pidl "  state->ret = false;";
+       pidl "  tevent_req_done(req);";
+       pidl "  return tevent_req_post(req, ev);";
        pidl "}";
        pidl "";
        pidl "/*";
@@ -207,21 +231,50 @@ sub ParseFunction($$)
        pidl "";
        pidl "ndr_err = call->ndr_push(push, NDR_OUT, r);";
        pidl "if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {";
-       pidl "\ttalloc_free(r);";
-       pidl "\treturn false;";
+       pidl "  state->ret = false;";
+       pidl "  tevent_req_done(req);";
+       pidl "  return tevent_req_post(req, ev);";
        pidl "}";
        pidl "";
        pidl "p->out_data.rdata = ndr_push_blob(push);";
-       pidl "talloc_steal(p->mem_ctx, p->out_data.rdata.data);";
        pidl "";
-       pidl "talloc_free(r);";
+       pidl "state->ret = true;";
+       pidl "tevent_req_done(req);";
+       pidl "return tevent_req_post(req, ev);";
+       deindent;
+       pidl "}";
+       pidl "";
+}
+
+sub ParseFunctionAsyncRecv($$)
+{
+       my ($if,$fn) = @_;
+
+       my $op = "NDR_".uc($fn->{NAME});
+
+       pidl "static bool api_$fn->{NAME}_recv(struct tevent_req *req)";
+       pidl "{";
+       indent;
+       pidl "struct api_$fn->{NAME}_state *state ";
+       pidl "  = tevent_req_data(req, struct api_$fn->{NAME}_state);";
+       pidl "bool ret = state->ret;";
        pidl "";
-       pidl "return true;";
+       pidl "talloc_steal(state->p->mem_ctx, state->p->out_data.rdata.data);";
+       pidl "tevent_req_received(req);";
+       pidl "return ret;";
        deindent;
        pidl "}";
        pidl "";
 }
 
+sub ParseFunction($$)
+{
+       my ($if,$fn) = @_;
+       ParseFunctionAsyncState($if, $fn);
+       ParseFunctionAsyncSend($if, $fn);
+       ParseFunctionAsyncRecv($if, $fn);
+}
+
 sub ParseInterface($)
 {
        my $if = shift;
@@ -244,7 +297,8 @@ sub ParseInterface($)
 
        foreach (@{$if->{FUNCTIONS}}) {
                next if ($_->{PROPERTIES}{noopnum});
-               pidl "{\"" . uc($_->{NAME}) . "\", NDR_" . uc($_->{NAME}) . ", api_$_->{NAME}},";
+               pidl "{\"" . uc($_->{NAME}) . "\", NDR_" . uc($_->{NAME}) . ",";
+               pidl " api_$_->{NAME}_send, api_$_->{NAME}_recv},";
        }
 
        deindent;
index 89798b272c366d8bcb9bfb74397a790b2356d1e9..76d76fa58517f9291df35a8d8b3ae2d75657f90a 100644 (file)
@@ -103,9 +103,13 @@ struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx,
 }
 
 struct rpcint_dispatch_state {
+       const struct api_struct *cmd;
        NTSTATUS status;
        DATA_BLOB out_data;
+       struct pipes_struct *p;
 };
+static void rpcint_dispatch_done(struct tevent_req *subreq);
+
 static struct tevent_req *rpcint_dispatch_send(struct tevent_context *ev,
                                               TALLOC_CTX *mem_ctx,
                                               struct pipes_struct *p,
@@ -116,19 +120,20 @@ static struct tevent_req *rpcint_dispatch_send(struct tevent_context *ev,
        uint32_t num_cmds = fns->n_cmds;
        const struct api_struct *cmds = fns->cmds;
        uint32_t i;
-       bool ok;
        struct rpcint_dispatch_state *state;
+       struct tevent_req *subreq;
        struct tevent_req *req = tevent_req_create(mem_ctx, &state,
                                                struct rpcint_dispatch_state);
        if (req == NULL) {
                return NULL;
        }
+       state->p = p;
 
        /* set opnum */
        p->opnum = opnum;
 
        for (i = 0; i < num_cmds; i++) {
-               if (cmds[i].opnum == opnum && cmds[i].fn != NULL) {
+               if (cmds[i].opnum == opnum && cmds[i].fn_send != NULL) {
                        break;
                }
        }
@@ -139,17 +144,36 @@ static struct tevent_req *rpcint_dispatch_send(struct tevent_context *ev,
                return tevent_req_post(req, ev);
        }
 
+       state->cmd = &cmds[i];
        p->in_data.data = *in_data;
        p->out_data.rdata = data_blob_null;
 
-       ok = cmds[i].fn(p);
+       subreq = state->cmd->fn_send(ev, state, p);
+       if (tevent_req_nomem(subreq, req)) {
+               state->status = NT_STATUS_NO_MEMORY;
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, rpcint_dispatch_done, req);
+       return req;
+}
+
+static void rpcint_dispatch_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                         struct tevent_req);
+       struct rpcint_dispatch_state *state
+                       = tevent_req_data(req, struct rpcint_dispatch_state);
+       struct pipes_struct *p = state->p;
+       bool ok;
+
+       ok = state->cmd->fn_recv(subreq);
        p->in_data.data = data_blob_null;
        if (!ok) {
                data_blob_free(&p->out_data.rdata);
                talloc_free_children(p->mem_ctx);
                state->status = NT_STATUS_RPC_CALL_FAILED;
                tevent_req_done(req);
-               return tevent_req_post(req, ev);
+               return;
        }
 
        if (p->fault_state) {
@@ -158,7 +182,7 @@ static struct tevent_req *rpcint_dispatch_send(struct tevent_context *ev,
                data_blob_free(&p->out_data.rdata);
                talloc_free_children(p->mem_ctx);
                tevent_req_done(req);
-               return tevent_req_post(req, ev);
+               return;
        }
 
        state->out_data = p->out_data.rdata;
@@ -168,7 +192,6 @@ static struct tevent_req *rpcint_dispatch_send(struct tevent_context *ev,
        state->status = NT_STATUS_OK;
        talloc_free_children(p->mem_ctx);
        tevent_req_done(req);
-       return tevent_req_post(req, ev);
 }
 
 static NTSTATUS rpcint_dispatch_recv(struct tevent_req *req,
index 4be57d8f96760d487767a03907eb98123aa1951a..d796da417452c557d1bd33dc267f48bb73671c20 100644 (file)
@@ -80,7 +80,10 @@ struct pipes_struct;
 struct api_struct {
        const char *name;
        uint8 opnum;
-       bool (*fn) (struct pipes_struct *);
+       struct tevent_req *(*fn_send)(struct tevent_context *,
+                                     TALLOC_CTX *,
+                                     struct pipes_struct *);
+       bool (*fn_recv)(struct tevent_req *);
 };
 
 struct pipe_rpc_fns {
index 79c616baee8eb6fce0c9075ce153b3e9a8e222bc..c1cb3c539f18dbac935b0991ebce188ec495edc7 100644 (file)
@@ -1384,8 +1384,14 @@ static bool api_pipe_request_recv(struct tevent_req *req)
 
 
 struct api_rpcTNP_state {
+       const struct api_struct *cmd;
        bool ret;
+       struct pipes_struct *p;
+       struct ncacn_packet *pkt;
+       uint32_t offset1;
+       const char *pipe_name;
 };
+static void api_rpcTNP_done(struct tevent_req *subreq);
 /*******************************************************************
  Calls the underlying RPC function for a named pipe.
  ********************************************************************/
@@ -1398,23 +1404,24 @@ static struct tevent_req *api_rpcTNP_send(struct tevent_context *ev,
                                          const struct ndr_syntax_id *syntax)
 {
        int fn_num;
-       uint32_t offset1;
        struct api_rpcTNP_state *state;
+       struct tevent_req *subreq;
        struct tevent_req *req = tevent_req_create(p->mem_ctx, &state,
                                                   struct api_rpcTNP_state);
        if (req == NULL) {
                return NULL;
        }
+       state->p = p;
+       state->pipe_name = get_pipe_name_from_syntax(state, syntax);
+       state->pkt = pkt;
 
        /* interpret the command */
        DEBUG(4,("api_rpcTNP: %s op 0x%x - ",
-                get_pipe_name_from_syntax(talloc_tos(), syntax),
-                pkt->u.request.opnum));
+                state->pipe_name, pkt->u.request.opnum));
 
        if (DEBUGLEVEL >= 50) {
                fstring name;
-               slprintf(name, sizeof(name)-1, "in_%s",
-                        get_pipe_name_from_syntax(talloc_tos(), syntax));
+               slprintf(name, sizeof(name)-1, "in_%s", state->pipe_name);
                dump_pdu_region(name, pkt->u.request.opnum,
                                &p->in_data.data, 0,
                                p->in_data.data.length);
@@ -1422,7 +1429,7 @@ static struct tevent_req *api_rpcTNP_send(struct tevent_context *ev,
 
        for (fn_num = 0; fn_num < n_cmds; fn_num++) {
                if (api_rpc_cmds[fn_num].opnum == pkt->u.request.opnum &&
-                   api_rpc_cmds[fn_num].fn != NULL) {
+                   api_rpc_cmds[fn_num].fn_send != NULL) {
                        DEBUG(3, ("api_rpcTNP: rpc command: %s\n",
                                  api_rpc_cmds[fn_num].name));
                        break;
@@ -1442,19 +1449,38 @@ static struct tevent_req *api_rpcTNP_send(struct tevent_context *ev,
                return tevent_req_post(req, ev);
        }
 
-       offset1 = p->out_data.rdata.length;
+       state->cmd = &api_rpc_cmds[fn_num];
+       state->offset1 = p->out_data.rdata.length;
 
-        DEBUG(6, ("api_rpc_cmds[%d].fn == %p\n", 
-                fn_num, api_rpc_cmds[fn_num].fn));
+        DEBUG(6, ("api_rpc_cmds[%d].fn_send == %p\n",
+                 fn_num, state->cmd->fn_send));
        /* do the actual command */
-       if(!api_rpc_cmds[fn_num].fn(p)) {
+       subreq = state->cmd->fn_send(ev, state, p);
+       if (tevent_req_nomem(subreq, req)) {
+               state->ret = false;
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, api_rpcTNP_done, req);
+
+       return req;
+}
+
+static void api_rpcTNP_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                         struct tevent_req);
+       struct api_rpcTNP_state *state
+               = tevent_req_data(req, struct api_rpcTNP_state);
+       struct pipes_struct *p = state->p;
+
+       state->ret = state->cmd->fn_recv(subreq);
+       if (!state->ret) {
                DEBUG(0,("api_rpcTNP: %s: %s failed.\n",
-                        get_pipe_name_from_syntax(talloc_tos(), syntax),
-                        api_rpc_cmds[fn_num].name));
+                        state->pipe_name,
+                        state->cmd->name));
                data_blob_free(&p->out_data.rdata);
-               state->ret = false;
                tevent_req_done(req);
-               return tevent_req_post(req, ev);
+               return;
        }
 
        if (p->fault_state) {
@@ -1463,32 +1489,27 @@ static struct tevent_req *api_rpcTNP_send(struct tevent_context *ev,
                p->fault_state = 0;
                state->ret = true;
                tevent_req_done(req);
-               return tevent_req_post(req, ev);
+               return;
        }
 
        if (DEBUGLEVEL >= 50) {
                fstring name;
-               slprintf(name, sizeof(name)-1, "out_%s",
-                        get_pipe_name_from_syntax(talloc_tos(), syntax));
-               dump_pdu_region(name, pkt->u.request.opnum,
-                               &p->out_data.rdata, offset1,
+               slprintf(name, sizeof(name)-1, "out_%s", state->pipe_name);
+               dump_pdu_region(name, state->pkt->u.request.opnum,
+                               &p->out_data.rdata, state->offset1,
                                p->out_data.rdata.length);
        }
 
-       DEBUG(5,("api_rpcTNP: called %s successfully\n",
-                get_pipe_name_from_syntax(talloc_tos(), syntax)));
+       DEBUG(5,("api_rpcTNP: called %s successfully\n", state->pipe_name));
 
        /* Check for buffer underflow in rpc parsing */
        if ((DEBUGLEVEL >= 10) &&
-           (pkt->frag_length < p->in_data.data.length)) {
+           (state->pkt->frag_length < p->in_data.data.length)) {
                DEBUG(10, ("api_rpcTNP: rpc input buffer underflow (parse error?)\n"));
-               dump_data(10, p->in_data.data.data + pkt->frag_length,
-                             p->in_data.data.length - pkt->frag_length);
+               dump_data(10, p->in_data.data.data + state->pkt->frag_length,
+                             p->in_data.data.length - state->pkt->frag_length);
        }
-
-       state->ret = true;
        tevent_req_done(req);
-       return tevent_req_post(req, ev);
 }
 
 static bool api_rpcTNP_recv(struct tevent_req *req)
index f3611be786377abe623c5192b9a8aa4a77b27d67..e6959e2104779aa579f1c472f702c7ad1c3fdf22 100644 (file)
@@ -303,6 +303,8 @@ enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain,
        struct api_struct *fns;
        int num_fns;
        bool ret;
+       struct tevent_req *subreq;
+       struct tevent_context *ev = winbind_event_context();
 
        wbint_get_pipe_fns(&fns, &num_fns);
 
@@ -319,7 +321,19 @@ enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain,
        p.in_data.data = data_blob_const(state->request->extra_data.data,
                                         state->request->extra_len);
 
-       ret = fns[state->request->data.ndrcmd].fn(&p);
+       subreq = fns[state->request->data.ndrcmd].fn_send(ev, p.mem_ctx, &p);
+       if (subreq == NULL) {
+               TALLOC_FREE(p.mem_ctx);
+               return WINBINDD_ERROR;
+       }
+
+       ret = tevent_req_poll(subreq, ev);
+       if (!ret) {
+               TALLOC_FREE(p.mem_ctx);
+               return WINBINDD_ERROR;
+       }
+
+       ret = fns[state->request->data.ndrcmd].fn_recv(subreq);
        if (!ret) {
                TALLOC_FREE(p.mem_ctx);
                return WINBINDD_ERROR;