# 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;
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;";
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;";
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) {";
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);";
}
);
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) {";
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 "/*";
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;
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;
}
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,
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;
}
}
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) {
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;
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,
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 {
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.
********************************************************************/
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);
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;
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) {
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)
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);
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;