pidl: add [async] function property
authorDavid Disseldorp <ddiss@samba.org>
Sun, 29 Apr 2012 21:51:52 +0000 (23:51 +0200)
committerDavid Disseldorp <ddiss@samba.org>
Mon, 15 Apr 2013 16:15:18 +0000 (18:15 +0200)
With the "async" function property defined, the Samba3 rpc-server
dispatches the request to the backend asynchronously.

pidl/lib/Parse/Pidl/NDR.pm
pidl/lib/Parse/Pidl/Samba3/ServerNDR.pm

index 682715227f5c91f7c8a61093962330b8acfec7a5..51cdc0b0e29bb4319790da3e10ea270b8361a7fa 100644 (file)
@@ -1048,6 +1048,7 @@ my %property_list = (
 
        # function
        "noopnum"               => ["FUNCTION"],
+       "async"                 => ["FUNCTION"],
        "in"                    => ["ELEMENT"],
        "out"                   => ["ELEMENT"],
 
index 35c8eb98e20082a63fa07702fb49be4fa96a1331..809ae95f1ba8e7363b75916dc774001a95b5f27a 100644 (file)
@@ -90,6 +90,41 @@ sub AllocOutVar($$$$$)
        pidl "";
 }
 
+sub AsyncDispatchWithStruct($$$$$)
+{
+       my ($ev, $mem_ctx, $pipes_struct, $fn, $fail) = @_;
+       my $env = GenerateFunctionOutEnv($fn);
+       my $hasout = 0;
+       foreach (@{$fn->{ELEMENTS}}) {
+               if (grep(/out/, @{$_->{DIRECTION}})) { $hasout = 1; }
+       }
+
+       pidl "ZERO_STRUCT(r->out);" if ($hasout);
+
+       foreach (@{$fn->{ELEMENTS}}) {
+               my @dir = @{$_->{DIRECTION}};
+               if (grep(/in/, @dir) and grep(/out/, @dir)) {
+                       pidl "r->out.$_->{NAME} = r->in.$_->{NAME};";
+               }
+       }
+
+       foreach (@{$fn->{ELEMENTS}}) {
+               my @dir = @{$_->{DIRECTION}};
+               if (grep(/in/, @dir) and grep(/out/, @dir)) {
+                       # noop
+               } elsif (grep(/out/, @dir) and not
+                                has_property($_, "represent_as")) {
+                       AllocOutVar($_, $mem_ctx, "r->out.$_->{NAME}", $env, $fail);
+               }
+       }
+       pidl_hdr "struct tevent_req *_$fn->{NAME}_send(struct tevent_context *$ev, TALLOC_CTX *$mem_ctx, struct pipes_struct *$pipes_struct, struct $fn->{NAME} *r);";
+       pidl "subreq = _$fn->{NAME}_send($ev, $mem_ctx, $pipes_struct, r);";
+       pidl "if (subreq == NULL) {";
+       $fail->();
+       pidl "}";
+       pidl "tevent_req_set_callback(subreq, api_$fn->{NAME}_done, req);";
+}
+
 sub CallWithStruct($$$$)
 {
        my ($pipes_struct, $mem_ctx, $fn, $fail) = @_;
@@ -139,8 +174,10 @@ sub ParseFunctionAsyncState($$)
        pidl "struct api_$fn->{NAME}_state {";
        pidl "  struct $fn->{NAME} r;";
        pidl "  struct pipes_struct *p;";
+       pidl "  uint32_t ptr_count;";
        pidl "  bool ret;";
        pidl "};";
+       pidl "static void api_$fn->{NAME}_done(struct tevent_req *subreq);" if (has_property($fn, "async"));
        pidl "";
 }
 
@@ -156,10 +193,14 @@ sub ParseFunctionAsyncSend($$)
        pidl "{";
        indent;
        pidl "struct tevent_req *req;";
+       if (has_property($fn, "async")) {
+               pidl "struct tevent_req *subreq;"
+       } else {
+               pidl "struct ndr_push *push;";
+       }
        pidl "struct api_$fn->{NAME}_state *state;";
        pidl "const struct ndr_interface_call *call;";
        pidl "struct ndr_pull *pull;";
-       pidl "struct ndr_push *push;";
        pidl "enum ndr_err_code ndr_err;";
        pidl "struct $fn->{NAME} *r;";
        pidl "";
@@ -172,7 +213,7 @@ sub ParseFunctionAsyncSend($$)
        pidl "state->p = p;";
        pidl "r = &state->r;";
        pidl "";
-       pidl "pull = ndr_pull_init_blob(&p->in_data.data, r);";
+       pidl "pull = ndr_pull_init_blob(&p->in_data.data, state);";
        pidl "if (pull == NULL) {";
        pidl "  state->ret = false;";
        pidl "  tevent_req_done(req);";
@@ -189,12 +230,28 @@ sub ParseFunctionAsyncSend($$)
        pidl "  tevent_req_done(req);";
        pidl "  return tevent_req_post(req, ev);";
        pidl "}";
+       pidl "state->ptr_count = pull->ptr_count;";
        pidl "";
        pidl "if (DEBUGLEVEL >= 10) {";
        pidl "\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_IN, r);";
        pidl "}";
        pidl "";
 
+       if (has_property($fn, "async")) {
+               AsyncDispatchWithStruct("ev", "state", "p", $fn,
+                       sub {
+                               pidl "  state->ret = false;";
+                               pidl "  tevent_req_done(req);";
+                               pidl "  return tevent_req_post(req, ev);";
+                       }
+               );
+               pidl "return req;";
+               deindent;
+               pidl "}";
+               pidl "";
+               return;
+       }
+
        CallWithStruct("p", "state", $fn,
                sub {
                        pidl "  state->ret = false;";
@@ -215,7 +272,7 @@ sub ParseFunctionAsyncSend($$)
        pidl "\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_OUT | NDR_SET_VALUES, r);";
        pidl "}";
        pidl "";
-       pidl "push = ndr_push_init_ctx(r);";
+       pidl "push = ndr_push_init_ctx(state);";
        pidl "if (push == NULL) {";
        pidl "  state->ret = false;";
        pidl "  tevent_req_done(req);";
@@ -245,6 +302,73 @@ sub ParseFunctionAsyncSend($$)
        pidl "";
 }
 
+sub ParseFunctionAsyncDone($$)
+{
+       my ($if,$fn) = @_;
+       my $op = "NDR_".uc($fn->{NAME});
+
+       pidl "static void api_$fn->{NAME}_done(struct tevent_req *subreq)";
+       pidl "{";
+       indent;
+       pidl "struct tevent_req *req = tevent_req_callback_data(subreq,";
+       pidl "                                                  struct tevent_req);";
+       pidl "struct api_$fn->{NAME}_state *state";
+       pidl "  = tevent_req_data(req, struct api_$fn->{NAME}_state);";
+       pidl "const struct ndr_interface_call *call;";
+       pidl "struct ndr_push *push;";
+       pidl "enum ndr_err_code ndr_err;";
+       pidl "";
+       pidl "call = &ndr_table_$if->{NAME}.calls[$op];";
+
+       if ($fn->{RETURN_TYPE}) {
+               pidl "state->r.out.result = _$fn->{NAME}_recv(subreq);";
+               pidl_hdr "$fn->{RETURN_TYPE} _$fn->{NAME}_recv(struct tevent_req *subreq);";
+       } else {
+               pidl "_$fn->{NAME}_recv(subreq);";
+               pidl_hdr "void _$fn->{NAME}_recv(struct tevent_req *subreq);";
+       }
+       pidl "";
+       pidl "if (state->p->fault_state) {";
+       pidl "  /* Return true here, srv_pipe_hnd.c will take care */";
+       pidl "  state->ret = true;";
+       pidl "  tevent_req_done(req);";
+       pidl "  return;";
+       pidl "}";
+       pidl "";
+       pidl "if (DEBUGLEVEL >= 10) {";
+       pidl "\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_OUT | NDR_SET_VALUES, &state->r);";
+       pidl "}";
+       pidl "";
+       pidl "push = ndr_push_init_ctx(state);";
+       pidl "if (push == NULL) {";
+       pidl "  state->ret = false;";
+       pidl "  tevent_req_done(req);";
+       pidl "  return;";
+       pidl "}";
+       pidl "";
+       pidl "/*";
+       pidl " * carry over the pointer count to the reply in case we are";
+       pidl " * using full pointer. See NDR specification for full pointers";
+       pidl " */";
+       pidl "push->ptr_count = state->ptr_count;";
+       pidl "";
+       pidl "ndr_err = call->ndr_push(push, NDR_OUT, &state->r);";
+       pidl "if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {";
+       pidl "  state->ret = false;";
+       pidl "  tevent_req_done(req);";
+       pidl "  return;";
+       pidl "}";
+       pidl "";
+       pidl "state->p->out_data.rdata = ndr_push_blob(push);";
+       pidl "";
+       pidl "state->ret = true;";
+       pidl "tevent_req_done(req);";
+       pidl "return;";
+       deindent;
+       pidl "}";
+       pidl "";
+}
+
 sub ParseFunctionAsyncRecv($$)
 {
        my ($if,$fn) = @_;
@@ -271,6 +395,9 @@ sub ParseFunction($$)
        my ($if,$fn) = @_;
        ParseFunctionAsyncState($if, $fn);
        ParseFunctionAsyncSend($if, $fn);
+       if (has_property($fn, "async")) {
+               ParseFunctionAsyncDone($if, $fn);
+       }
        ParseFunctionAsyncRecv($if, $fn);
 }