pidl:NDR/Client.pm: use dcerpc_binding_handl_call_params* if a dcerpc pipe is used
[metze/samba/wip.git] / pidl / lib / Parse / Pidl / Samba4 / NDR / Client.pm
index 32309580f40e9dddabe3aa1860e4ed135a7465ed..f9d743f82b5b6ab551c80717d00dee091f7ab5e3 100644 (file)
@@ -11,7 +11,8 @@ use Exporter;
 @EXPORT_OK = qw(Parse);
 
 use Parse::Pidl qw(fatal warning error);
-use Parse::Pidl::Util qw(has_property ParseExpr);
+use Parse::Pidl::Util qw(has_property ParseExpr genpad);
+use Parse::Pidl::NDR qw(ContainsPipe);
 use Parse::Pidl::Typelist qw(mapTypeName);
 use Parse::Pidl::Samba4 qw(choose_header is_intree DeclLong);
 use Parse::Pidl::Samba4::Header qw(GenerateFunctionInEnv GenerateFunctionOutEnv);
@@ -28,15 +29,6 @@ sub pidl_hdr($$) { my ($self, $txt) = @_; $self->{res_hdr} .= "$txt\n"; }
 sub pidl_both($$) { my ($self, $txt) = @_; $self->{hdr} .= "$txt\n"; $self->{res_hdr} .= "$txt\n"; }
 sub fn_declare($$) { my ($self,$n) = @_; $self->pidl($n); $self->pidl_hdr("$n;"); }
 
-sub genpad($)
-{
-       my ($s) = @_;
-       my $nt = int((length($s)+1)/8);
-       my $lt = ($nt*8)-1;
-       my $ns = (length($s)-$lt);
-       return "\t"x($nt)." "x($ns);
-}
-
 sub new($)
 {
        my ($class) = shift;
@@ -44,13 +36,42 @@ sub new($)
        bless($self, $class);
 }
 
+sub ParseFunctionHasPipes($$)
+{
+       my ($self, $fn) = @_;
+
+       foreach my $e (@{$fn->{ELEMENTS}}) {
+               return 1 if ContainsPipe($e, $e->{LEVELS}[0]);
+       }
+
+       return 0;
+}
+
 sub ParseFunction_r_State($$$$)
 {
        my ($self, $if, $fn, $name) = @_;
        my $uname = uc $name;
 
+       my $in_pipes = 0;
+       foreach my $e (@{$fn->{ELEMENTS}}) {
+               next unless grep(/in/, @{$e->{DIRECTION}});
+               next unless ContainsPipe($e, $e->{LEVELS}[0]);
+               $in_pipes++;
+       }
+       my $out_pipes = 0;
+       foreach my $e (@{$fn->{ELEMENTS}}) {
+               next unless grep(/out/, @{$e->{DIRECTION}});
+               next unless ContainsPipe($e, $e->{LEVELS}[0]);
+               $out_pipes++;
+       }
+
        $self->pidl("struct dcerpc_$name\_r_state {");
        $self->indent;
+       if ($in_pipes > 0 or $out_pipes > 0) {
+               $self->pidl("struct dcerpc_pipe_handle_connection *in_pipes[$in_pipes];") if ($in_pipes > 0);
+               $self->pidl("struct dcerpc_pipe_handle_connection *out_pipes[$out_pipes];") if ($out_pipes > 0);
+               $self->pidl("struct dcerpc_binding_handle_call_params params;");
+       }
        $self->pidl("TALLOC_CTX *out_mem_ctx;");
        $self->deindent;
        $self->pidl("};");
@@ -89,10 +110,11 @@ sub ParseFunction_r_Send($$$$)
        $self->pidl("");
 
        my $out_params = 0;
-       foreach (@{$fn->{ELEMENTS}}) {
-               if (grep(/out/, @{$_->{DIRECTION}})) {
-                       $out_params++;
-               }
+       foreach my $e (@{$fn->{ELEMENTS}}) {
+               next unless grep(/out/, @{$e->{DIRECTION}});
+               next if ContainsPipe($e, $e->{LEVELS}[0]);
+               $out_params++;
+
        }
 
        my $submem;
@@ -110,9 +132,58 @@ sub ParseFunction_r_Send($$$$)
        }
        $self->pidl("");
 
-       $self->pidl("subreq = dcerpc_binding_handle_call_send(state, ev, h,");
-       $self->pidl("\t\tNULL, &ndr_table_$if->{NAME},");
-       $self->pidl("\t\tNDR_$uname, $submem, r);");
+       my $in_pipes = 0;
+       foreach my $e (@{$fn->{ELEMENTS}}) {
+               next unless grep(/in/, @{$e->{DIRECTION}});
+               next unless ContainsPipe($e, $e->{LEVELS}[0]);
+               $self->pidl("if (r->in.$e->{NAME} == NULL) {");
+               $self->indent;
+               $self->pidl("tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);");
+               $self->pidl("return tevent_req_post(req, ev);");
+               $self->deindent;
+               $self->pidl("}");
+               $self->pidl("state->in_pipes[$in_pipes] = r->in.".$e->{NAME}."->pc;");
+               $in_pipes++;
+       }
+       my $out_pipes = 0;
+       foreach my $e (@{$fn->{ELEMENTS}}) {
+               next unless grep(/out/, @{$e->{DIRECTION}});
+               next unless ContainsPipe($e, $e->{LEVELS}[0]);
+               $self->pidl("if (r->out.$e->{NAME} == NULL) {");
+               $self->indent;
+               $self->pidl("tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);");
+               $self->pidl("return tevent_req_post(req, ev);");
+               $self->deindent;
+               $self->pidl("}");
+               $self->pidl("state->out_pipes[$out_pipes] = r->out.".$e->{NAME}."->pc;");
+               $out_pipes++;
+       }
+
+       if ($in_pipes > 0 or $out_pipes > 0) {
+               $self->pidl("state->params.r_mem = $submem;");
+               $self->pidl("state->params.r_ptr = r;");
+               $self->pidl("state->params.in.num_pipes = $in_pipes;");
+               if ($in_pipes > 0) {
+                       $self->pidl("state->params.in.pipes = state->in_pipes;");
+               } else {
+                       $self->pidl("state->params.in.pipes = NULL;");
+               }
+               $self->pidl("state->params.out.num_pipes = $out_pipes;");
+               if ($out_pipes > 0) {
+                       $self->pidl("state->params.out.pipes = state->out_pipes;");
+               } else {
+                       $self->pidl("state->params.out.pipes = NULL;");
+               }
+               $self->pidl("");
+
+               $self->pidl("subreq = dcerpc_binding_handle_call_params_send(state, ev, h,");
+               $self->pidl("\t\tNULL, &ndr_table_$if->{NAME},");
+               $self->pidl("\t\tNDR_$uname, &state->params);");
+       } else {
+               $self->pidl("subreq = dcerpc_binding_handle_call_send(state, ev, h,");
+               $self->pidl("\t\tNULL, &ndr_table_$if->{NAME},");
+               $self->pidl("\t\tNDR_$uname, $submem, r);");
+       }
        $self->pidl("if (tevent_req_nomem(subreq, req)) {");
        $self->indent;
        $self->pidl("return tevent_req_post(req, ev);");
@@ -134,6 +205,19 @@ sub ParseFunction_r_Done($$$$)
 
        my $proto = "static void dcerpc_$name\_r_done(struct tevent_req *subreq)";
 
+       my $in_pipes = 0;
+       foreach my $e (@{$fn->{ELEMENTS}}) {
+               next unless grep(/in/, @{$e->{DIRECTION}});
+               next unless ContainsPipe($e, $e->{LEVELS}[0]);
+               $in_pipes++;
+       }
+       my $out_pipes = 0;
+       foreach my $e (@{$fn->{ELEMENTS}}) {
+               next unless grep(/out/, @{$e->{DIRECTION}});
+               next unless ContainsPipe($e, $e->{LEVELS}[0]);
+               $out_pipes++;
+       }
+
        $self->pidl("$proto");
        $self->pidl("{");
        $self->indent;
@@ -144,10 +228,14 @@ sub ParseFunction_r_Done($$$$)
        $self->pidl("NTSTATUS status;");
        $self->pidl("");
 
-       $self->pidl("status = dcerpc_binding_handle_call_recv(subreq);");
-       $self->pidl("if (!NT_STATUS_IS_OK(status)) {");
+       if ($in_pipes > 0 or $out_pipes > 0) {
+               $self->pidl("status = dcerpc_binding_handle_call_params_recv(subreq);");
+       } else {
+               $self->pidl("status = dcerpc_binding_handle_call_recv(subreq);");
+       }
+       $self->pidl("TALLOC_FREE(subreq);");
+       $self->pidl("if (tevent_req_nterror(req, status)) {");
        $self->indent;
-       $self->pidl("tevent_req_nterror(req, status);");
        $self->pidl("return;");
        $self->deindent;
        $self->pidl("}");
@@ -200,6 +288,17 @@ sub ParseFunction_r_Sync($$$$)
        my ($self, $if, $fn, $name) = @_;
        my $uname = uc $name;
 
+       if ($self->ParseFunctionHasPipes($fn)) {
+               $self->pidl_both("/*");
+               $self->pidl_both(" * The following function is skipped because");
+               $self->pidl_both(" * it uses pipes:");
+               $self->pidl_both(" *");
+               $self->pidl_both(" * dcerpc_$name\_r()");
+               $self->pidl_both(" */");
+               $self->pidl_both("");
+               return;
+       }
+
        my $proto = "NTSTATUS dcerpc_$name\_r(struct dcerpc_binding_handle *h, TALLOC_CTX *mem_ctx, struct $name *r)";
 
        $self->fn_declare($proto);
@@ -220,49 +319,6 @@ sub ParseFunction_r_Sync($$$$)
        $self->pidl("");
 }
 
-sub ParseFunction_Compat_Sync($$$$)
-{
-       my ($self, $if, $fn, $name) = @_;
-       my $uname = uc $name;
-
-       my $proto = "NTSTATUS dcerpc_$name\_compat(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r)";
-
-       $self->pidl_hdr("#ifdef DCERPC_CALL_$uname\_COMPAT");
-       $self->pidl_hdr("#define dcerpc_$name(p, m, r) dcerpc_$name\_compat(p, m, r)");
-       $self->pidl_hdr("#endif /* DCERPC_CALL_$uname\_COMPAT */");
-
-       $self->fn_declare($proto);
-       $self->pidl("{");
-       $self->indent;
-       $self->pidl("NTSTATUS status;");
-       $self->pidl("");
-
-       $self->pidl("status = dcerpc_$name\_r(p->binding_handle, mem_ctx, r);");
-       $self->pidl("");
-
-       $self->pidl("if (NT_STATUS_IS_RPC(status)) {");
-       $self->indent;
-       $self->pidl("status = NT_STATUS_NET_WRITE_FAULT;");
-       $self->deindent;
-       $self->pidl("}");
-       $self->pidl("");
-
-       if (defined($fn->{RETURN_TYPE}) and $fn->{RETURN_TYPE} eq "NTSTATUS") {
-               $self->pidl("if (NT_STATUS_IS_OK(status)) {");
-               $self->indent;
-               $self->pidl("status = r->out.result;");
-               $self->deindent;
-               $self->pidl("}");
-               $self->pidl("");
-       }
-
-       $self->pidl("return status;");
-
-       $self->deindent;
-       $self->pidl("}");
-       $self->pidl("");
-}
-
 sub ElementDirection($)
 {
        my ($e) = @_;
@@ -278,7 +334,7 @@ sub HeaderProperties($$)
        my($props,$ignores) = @_;
        my $ret = "";
 
-       foreach my $d (keys %{$props}) {
+       foreach my $d (sort(keys %{$props})) {
                next if (grep(/^$d$/, @$ignores));
                if($props->{$d} ne "1") {
                        $ret.= "$d($props->{$d}),";
@@ -419,11 +475,16 @@ sub ParseOutputArgument($$$$$$)
                        $self->pidl("$copy_len_var = $out_length_is;");
                }
 
+               my $dest_ptr = "$o$e->{NAME}";
+               my $elem_size = "sizeof(*$dest_ptr)";
+               $self->pidl("if ($dest_ptr != $out_var) {");
+               $self->indent;
                if (has_property($e, "charset")) {
-                       $self->pidl("memcpy(discard_const_p(uint8_t *, $o$e->{NAME}), $out_var, $copy_len_var * sizeof(*$o$e->{NAME}));");
-               } else {
-                       $self->pidl("memcpy($o$e->{NAME}, $out_var, $copy_len_var * sizeof(*$o$e->{NAME}));");
+                       $dest_ptr = "discard_const_p(uint8_t *, $dest_ptr)";
                }
+               $self->pidl("memcpy($dest_ptr, $out_var, $copy_len_var * $elem_size);");
+               $self->deindent;
+               $self->pidl("}");
 
                $self->deindent;
                $self->pidl("}");
@@ -510,13 +571,16 @@ sub ParseFunction_Send($$$$)
                next unless grep(/out/, @{$e->{DIRECTION}});
 
                $self->ParseCopyArgument($fn, $e, "state->orig.out.", "_");
+
+               next if ContainsPipe($e, $e->{LEVELS}[0]);
+
                $out_params++;
        }
        $self->pidl("");
 
        if (defined($fn->{RETURN_TYPE})) {
                $self->pidl("/* Result */");
-               $self->pidl("ZERO_STRUCT(state->orig.out.result);");
+               $self->pidl("NDR_ZERO_STRUCT(state->orig.out.result);");
                $self->pidl("");
        }
 
@@ -579,9 +643,8 @@ sub ParseFunction_Done($$$$)
 
        $self->pidl("status = dcerpc_$name\_r_recv(subreq, mem_ctx);");
        $self->pidl("TALLOC_FREE(subreq);");
-       $self->pidl("if (!NT_STATUS_IS_OK(status)) {");
+       $self->pidl("if (tevent_req_nterror(req, status)) {");
        $self->indent;
-       $self->pidl("tevent_req_nterror(req, status);");
        $self->pidl("return;");
        $self->deindent;
        $self->pidl("}");
@@ -589,6 +652,7 @@ sub ParseFunction_Done($$$$)
 
        $self->pidl("/* Copy out parameters */");
        foreach my $e (@{$fn->{ELEMENTS}}) {
+               next if ContainsPipe($e, $e->{LEVELS}[0]);
                next unless (grep(/out/, @{$e->{DIRECTION}}));
 
                $self->ParseOutputArgument($fn, $e,
@@ -605,7 +669,7 @@ sub ParseFunction_Done($$$$)
        }
 
        $self->pidl("/* Reset temporary structure */");
-       $self->pidl("ZERO_STRUCT(state->tmp);");
+       $self->pidl("NDR_ZERO_STRUCT(state->tmp);");
        $self->pidl("");
 
        $self->pidl("tevent_req_done(req);");
@@ -665,6 +729,17 @@ sub ParseFunction_Sync($$$$)
 {
        my ($self, $if, $fn, $name) = @_;
 
+       if ($self->ParseFunctionHasPipes($fn)) {
+               $self->pidl_both("/*");
+               $self->pidl_both(" * The following function is skipped because");
+               $self->pidl_both(" * it uses pipes:");
+               $self->pidl_both(" *");
+               $self->pidl_both(" * dcerpc_$name()");
+               $self->pidl_both(" */");
+               $self->pidl_both("");
+               return;
+       }
+
        my $uname = uc $name;
        my $fn_args = "";
        my $fn_str = "NTSTATUS dcerpc_$name";
@@ -682,9 +757,7 @@ sub ParseFunction_Sync($$$$)
                $fn_args .= ",\n" . $pad . mapTypeName($fn->{RETURN_TYPE}). " *result";
        }
 
-       $self->pidl_hdr("#ifndef DCERPC_CALL_$uname\_COMPAT");
        $self->fn_declare("$fn_str($fn_args)");
-       $self->pidl_hdr("#endif /* DCERPC_CALL_$uname\_COMPAT */");
        $self->pidl("{");
        $self->indent;
        $self->pidl("struct $name r;");
@@ -699,6 +772,20 @@ sub ParseFunction_Sync($$$$)
        }
        $self->pidl("");
 
+       $self->pidl("/* Out parameters */");
+       foreach my $e (@{$fn->{ELEMENTS}}) {
+               next unless grep(/out/, @{$e->{DIRECTION}});
+
+               $self->ParseCopyArgument($fn, $e, "r.out.", "_");
+       }
+       $self->pidl("");
+
+       if (defined($fn->{RETURN_TYPE})) {
+               $self->pidl("/* Result */");
+               $self->pidl("NDR_ZERO_STRUCT(r.out.result);");
+               $self->pidl("");
+       }
+
        $self->pidl("status = dcerpc_$name\_r(h, mem_ctx, &r);");
        $self->pidl("if (!NT_STATUS_IS_OK(status)) {");
        $self->indent;
@@ -709,6 +796,7 @@ sub ParseFunction_Sync($$$$)
 
        $self->pidl("/* Return variables */");
        foreach my $e (@{$fn->{ELEMENTS}}) {
+               next if ContainsPipe($e, $e->{LEVELS}[0]);
                next unless (grep(/out/, @{$e->{DIRECTION}}));
 
                $self->ParseOutputArgument($fn, $e, "r.", "_", "sync");
@@ -740,8 +828,6 @@ sub ParseFunction($$$)
        $self->ParseFunction_r_Recv($if, $fn, $fn->{NAME});
        $self->ParseFunction_r_Sync($if, $fn, $fn->{NAME});
 
-       $self->ParseFunction_Compat_Sync($if, $fn, $fn->{NAME});
-
        foreach my $e (@{$fn->{ELEMENTS}}) {
                next unless (grep(/out/, @{$e->{DIRECTION}}));
 
@@ -793,6 +879,379 @@ sub ParseFunction($$$)
        $self->pidl_hdr("");
 }
 
+sub ParsePipeCreate($$$)
+{
+       my ($self, $t, $cname) = @_;
+
+       $self->pidl_both("/* $t->{NAME} */");
+
+       $self->pidl_hdr("struct $t->{NAME};");
+       $self->pidl("struct $t->{NAME} {");
+       $self->indent;
+       $self->pidl("struct dcerpc_pipe_handle_connection *pc;");
+       $self->deindent;
+       $self->pidl("};");
+       $self->pidl("");
+
+       my $proto = "struct $t->{NAME} *dcerpc_$t->{NAME}\_create(TALLOC_CTX *mem_ctx)";
+
+       $self->pidl_hdr("$proto;");
+       $self->pidl("$proto");
+       $self->pidl("{");
+       $self->indent;
+
+       $self->pidl("struct $t->{NAME} *p;");
+       $self->pidl("");
+
+       $self->pidl("p = talloc_zero(mem_ctx, struct $t->{NAME});");
+       $self->pidl("if (p == NULL) {");
+       $self->indent;
+       $self->pidl("return NULL;");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+
+       my $cname = "$t->{NAME}_chunk";
+
+       $self->pidl("/* the pipe is disconnected by default */");
+       $self->pidl("p->pc = dcerpc_pipe_handle_connection_create(p,");
+       $self->pidl("\t\t\t\"$cname\",");
+       $self->pidl("\t\t\tsizeof(struct $cname));");
+       $self->pidl("if (p->pc == NULL) {");
+       $self->indent;
+       $self->pidl("TALLOC_FREE(p);");
+       $self->pidl("return NULL;");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("return p;");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+}
+
+sub ParsePipeChunkPush_State($$$)
+{
+       my ($self, $t, $cname) = @_;
+
+       my $state_str = "struct dcerpc_$cname\_push_state";
+       my $done_fn = "dcerpc_$cname\_push_done";
+
+       $self->pidl("$state_str {");
+       $self->indent;
+       $self->pidl("uint8_t dummy;");
+       $self->deindent;
+       $self->pidl("};");
+       $self->pidl("");
+
+       $self->pidl("static void $done_fn(struct tevent_req *subreq);");
+       $self->pidl("");
+}
+
+sub ParsePipeChunkPush_Send($$$)
+{
+       my ($self, $t, $cname) = @_;
+
+       my $fn_args = "";
+       my $state_str = "struct dcerpc_$cname\_push_state";
+       my $done_fn = "dcerpc_$cname\_push_done";
+       my $fn_str = "struct tevent_req *dcerpc_$cname\_push_send";
+       my $pad = genpad($fn_str);
+
+       $fn_args .= "TALLOC_CTX *mem_ctx";
+       $fn_args .= ",\n" . $pad . "struct tevent_context *ev";
+       $fn_args .= ",\n" . $pad . "struct $t->{NAME} *p";
+       $fn_args .= ",\n" . $pad . "const struct $cname *chunk";
+
+       $self->fn_declare("$fn_str($fn_args)");
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("struct tevent_req *req;");
+       $self->pidl("$state_str *state;");
+       $self->pidl("struct tevent_req *subreq;");
+       $self->pidl("");
+
+       $self->pidl("req = tevent_req_create(mem_ctx, &state,");
+       $self->pidl("\t\t\t$state_str);");
+       $self->pidl("if (req == NULL) {");
+       $self->indent;
+       $self->pidl("return NULL;");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("subreq = dcerpc_pipe_handle_push_send(state, ev,");
+       $self->pidl("\t\t\tp->pc, chunk);");
+       $self->pidl("if (tevent_req_nomem(subreq, req)) {");
+       $self->indent;
+       $self->pidl("return tevent_req_post(req, ev);");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("tevent_req_set_callback(subreq, $done_fn, req);");
+       $self->pidl("");
+
+       $self->pidl("return req;");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+}
+
+sub ParsePipeChunkPush_Done($$$)
+{
+       my ($self, $t, $cname) = @_;
+
+       my $fn_args = "";
+       my $state_str = "struct dcerpc_$cname\_push_state";
+       my $fn_str = "static void dcerpc_$cname\_push_done";
+       my $pad = genpad($fn_str);
+
+       $fn_args .= "struct tevent_req *subreq";
+
+       $self->pidl("$fn_str($fn_args)");
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("struct tevent_req *req =");
+       $self->pidl("\ttevent_req_callback_data(subreq,");
+       $self->pidl("\tstruct tevent_req);");
+       # unused
+       #$self->pidl("$state_str *state =");
+       #$self->pidl("\ttevent_req_data(req,");
+       #$self->pidl("\t$state_str);");
+       $self->pidl("NTSTATUS status;");
+       $self->pidl("");
+
+       $self->pidl("status = dcerpc_pipe_handle_push_recv(subreq);");
+       $self->pidl("TALLOC_FREE(subreq);");
+       $self->pidl("if (tevent_req_nterror(req, status)) {");
+       $self->indent;
+       $self->pidl("return;");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("tevent_req_done(req);");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+}
+
+sub ParsePipeChunkPush_Recv($$$)
+{
+       my ($self, $t, $cname) = @_;
+
+       my $fn_args = "";
+       my $state_str = "struct dcerpc_$cname\_push_state";
+       my $fn_str = "NTSTATUS dcerpc_$cname\_push_recv";
+       my $pad = genpad($fn_str);
+
+       $fn_args .= "struct tevent_req *req";
+
+       $self->fn_declare("$fn_str($fn_args)");
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("$state_str *state =");
+       $self->pidl("\ttevent_req_data(req,");
+       $self->pidl("\t$state_str);");
+       $self->pidl("NTSTATUS status;");
+       $self->pidl("");
+
+       $self->pidl("if (tevent_req_is_nterror(req, &status)) {");
+       $self->indent;
+       $self->pidl("/*");
+       $self->pidl(" * We want the tevent_req_data() protection,");
+       $self->pidl(" * but don't need 'state', so just pretend we use it");
+       $self->pidl(" * in order to avoid compiler warnings.");
+       $self->pidl(" */");
+       $self->pidl("state->dummy = 0;");
+       $self->pidl("tevent_req_received(req);");
+       $self->pidl("return status;");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("tevent_req_received(req);");
+       $self->pidl("return NT_STATUS_OK;");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+}
+
+sub ParsePipeChunkPull_State($$$)
+{
+       my ($self, $t, $cname) = @_;
+
+       my $state_str = "struct dcerpc_$cname\_pull_state";
+       my $done_fn = "dcerpc_$cname\_pull_done";
+
+       $self->pidl("$state_str {");
+       $self->indent;
+       $self->pidl("struct $cname *chunk;");
+       $self->deindent;
+       $self->pidl("};");
+       $self->pidl("");
+
+       $self->pidl("static void $done_fn(struct tevent_req *subreq);");
+       $self->pidl("");
+}
+
+sub ParsePipeChunkPull_Send($$$)
+{
+       my ($self, $t, $cname) = @_;
+
+       my $fn_args = "";
+       my $state_str = "struct dcerpc_$cname\_pull_state";
+       my $done_fn = "dcerpc_$cname\_pull_done";
+       my $fn_str = "struct tevent_req *dcerpc_$cname\_pull_send";
+       my $pad = genpad($fn_str);
+
+       $fn_args .= "TALLOC_CTX *mem_ctx";
+       $fn_args .= ",\n" . $pad . "struct tevent_context *ev";
+       $fn_args .= ",\n" . $pad . "struct $t->{NAME} *p";
+
+       $self->fn_declare("$fn_str($fn_args)");
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("struct tevent_req *req;");
+       $self->pidl("$state_str *state;");
+       $self->pidl("struct tevent_req *subreq;");
+       $self->pidl("");
+
+       $self->pidl("req = tevent_req_create(mem_ctx, &state,");
+       $self->pidl("\t\t\t$state_str);");
+       $self->pidl("if (req == NULL) {");
+       $self->indent;
+       $self->pidl("return NULL;");
+       $self->deindent;
+       $self->pidl("}");
+
+       $self->pidl("state->chunk = talloc_zero(state, struct $cname);");
+       $self->pidl("if (tevent_req_nomem(state->chunk, req)) {");
+       $self->indent;
+       $self->pidl("return tevent_req_post(req, ev);");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("subreq = dcerpc_pipe_handle_pull_send(state, ev,");
+       $self->pidl("\t\t\tp->pc, state->chunk, state->chunk);");
+       $self->pidl("if (tevent_req_nomem(subreq, req)) {");
+       $self->indent;
+       $self->pidl("return tevent_req_post(req, ev);");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("tevent_req_set_callback(subreq, $done_fn, req);");
+       $self->pidl("");
+
+       $self->pidl("return req;");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+}
+
+sub ParsePipeChunkPull_Done($$$)
+{
+       my ($self, $t, $cname) = @_;
+
+       my $fn_args = "";
+       my $state_str = "struct dcerpc_$cname\_pull_state";
+       my $fn_str = "static void dcerpc_$cname\_pull_done";
+       my $pad = genpad($fn_str);
+
+       $fn_args .= "struct tevent_req *subreq";
+
+       $self->pidl("$fn_str($fn_args)");
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("struct tevent_req *req =");
+       $self->pidl("\ttevent_req_callback_data(subreq,");
+       $self->pidl("\tstruct tevent_req);");
+       # unused
+       #$self->pidl("$state_str *state =");
+       #$self->pidl("\ttevent_req_data(req,");
+       #$self->pidl("\t$state_str);");
+       $self->pidl("NTSTATUS status;");
+       $self->pidl("");
+
+       $self->pidl("status = dcerpc_pipe_handle_pull_recv(subreq);");
+       $self->pidl("TALLOC_FREE(subreq);");
+       $self->pidl("if (tevent_req_nterror(req, status)) {");
+       $self->indent;
+       $self->pidl("return;");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("tevent_req_done(req);");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+}
+
+sub ParsePipeChunkPull_Recv($$$)
+{
+       my ($self, $t, $cname) = @_;
+
+       my $fn_args = "";
+       my $state_str = "struct dcerpc_$cname\_pull_state";
+       my $fn_str = "NTSTATUS dcerpc_$cname\_pull_recv";
+       my $pad = genpad($fn_str);
+
+       $fn_args .= "struct tevent_req *req";
+       $fn_args .= ",\n" . $pad . "TALLOC_CTX *mem_ctx";
+       $fn_args .= ",\n" . $pad . "struct $cname **chunk";
+
+       $self->fn_declare("$fn_str($fn_args)");
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("$state_str *state =");
+       $self->pidl("\ttevent_req_data(req,");
+       $self->pidl("\t$state_str);");
+       $self->pidl("NTSTATUS status;");
+       $self->pidl("");
+
+       $self->pidl("if (tevent_req_is_nterror(req, &status)) {");
+       $self->indent;
+       $self->pidl("tevent_req_received(req);");
+       $self->pidl("return status;");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("*chunk = talloc_move(mem_ctx, &state->chunk);");
+       $self->pidl("");
+
+       $self->pidl("tevent_req_received(req);");
+       $self->pidl("return NT_STATUS_OK;");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("");
+}
+
+sub ParsePipe($$)
+{
+       my ($self, $t) = @_;
+
+       my $pipe = $t;
+       $pipe = $t->{DATA} if ($t->{TYPE} eq "TYPEDEF");
+       my $struct = $pipe->{DATA};
+
+       my $name = "$struct->{NAME}";
+
+       $self->ParsePipeCreate($t, $name);
+
+       $self->ParsePipeChunkPush_State($t, $name);
+       $self->ParsePipeChunkPush_Send($t, $name);
+       $self->ParsePipeChunkPush_Done($t, $name);
+       $self->ParsePipeChunkPush_Recv($t, $name);
+
+       $self->ParsePipeChunkPull_State($t, $name);
+       $self->ParsePipeChunkPull_Send($t, $name);
+       $self->ParsePipeChunkPull_Done($t, $name);
+       $self->ParsePipeChunkPull_Recv($t, $name);
+       $self->pidl_both("");
+}
+
 my %done;
 
 #####################################################################
@@ -811,19 +1270,16 @@ sub ParseInterface($$)
                $self->pidl_hdr("");
        }
 
-       $self->pidl_hdr("#ifdef DCERPC_IFACE_$ifu\_COMPAT");
-       foreach my $fn (@{$if->{FUNCTIONS}}) {
-               next if has_property($fn, "noopnum");
-               next if has_property($fn, "todo");
-               my $fnu = uc($fn->{NAME});
-               $self->pidl_hdr("#define DCERPC_CALL_$fnu\_COMPAT 1");
-       }
-       $self->pidl_hdr("#endif /* DCERPC_IFACE_$ifu\_COMPAT */");
-       $self->pidl_hdr("");
-
        $self->pidl("/* $if->{NAME} - client functions generated by pidl */");
        $self->pidl("");
 
+       foreach my $t (reverse @{$if->{TYPES}}) {
+               next unless Parse::Pidl::Typelist::typeIs($t, "PIPE");
+
+               $self->ParsePipe($t);
+               $done{$t->{NAME}} = 1;
+       }
+
        foreach my $fn (@{$if->{FUNCTIONS}}) {
                next if defined($done{$fn->{NAME}});
                next if has_property($fn, "noopnum");