summaryrefslogtreecommitdiff
path: root/source4/librpc/rpc/dcerpc.c
diff options
context:
space:
mode:
authorVolker Lendecke <vlendec@samba.org>2005-11-02 05:34:17 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:45:41 -0500
commit66d3ee9ccb9807ca443962ef2a887627505c537c (patch)
tree44802dcc76d9271d0ba02408c9fd87423623cf7e /source4/librpc/rpc/dcerpc.c
parent66caa3234d14321b579e5d8befa3a12579c6a68e (diff)
downloadsamba-66d3ee9ccb9807ca443962ef2a887627505c537c.tar.gz
samba-66d3ee9ccb9807ca443962ef2a887627505c537c.tar.bz2
samba-66d3ee9ccb9807ca443962ef2a887627505c537c.zip
r11473: Based on work by Jelmer, implement the [async] flag for rpc requests. If it's
not there (it's not yet on *any* call... :-)), the rpc client strictly sequences calls to an rpc pipe. Might need some more work on the exact sequencing semantics when a pipe with both sync and async calls is actually deployed, but I want it in for winbind simplification. Volker (This used to be commit b8f324e4f000971b7dafc263c16dd4af958ee7f9)
Diffstat (limited to 'source4/librpc/rpc/dcerpc.c')
-rw-r--r--source4/librpc/rpc/dcerpc.c110
1 files changed, 82 insertions, 28 deletions
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
index 2c0dbcd5f3..ea1ae76b4e 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -28,6 +28,8 @@
#include "librpc/gen_ndr/ndr_dcerpc.h"
#include "librpc/gen_ndr/ndr_misc.h"
+static void dcerpc_ship_next_request(struct dcerpc_connection *c);
+
static struct dcerpc_interface_list *dcerpc_pipes = NULL;
/*
@@ -857,6 +859,10 @@ req_done:
if (req->async.callback) {
req->async.callback(req);
}
+
+ if (c->request_queue != NULL) {
+ dcerpc_ship_next_request(c);
+ }
}
/*
@@ -893,16 +899,13 @@ static int dcerpc_req_destructor(void *ptr)
/*
perform the send side of a async dcerpc request
*/
-struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
- const struct GUID *object,
- uint16_t opnum,
- DATA_BLOB *stub_data)
+static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
+ const struct GUID *object,
+ uint16_t opnum,
+ BOOL async,
+ DATA_BLOB *stub_data)
{
struct rpc_request *req;
- struct ncacn_packet pkt;
- DATA_BLOB blob;
- uint32_t remaining, chunk_size;
- BOOL first_packet = True;
p->conn->transport.recv_data = dcerpc_request_recv_data;
@@ -918,8 +921,69 @@ struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
req->payload = data_blob(NULL, 0);
req->flags = 0;
req->fault_code = 0;
+ req->async_call = async;
req->async.callback = NULL;
+ if (object != NULL) {
+ req->object = talloc_memdup(req, object, sizeof(*object));
+ if (req->object == NULL) {
+ talloc_free(req);
+ return NULL;
+ }
+ } else {
+ req->object = NULL;
+ }
+
+ req->opnum = opnum;
+ req->request_data.length = stub_data->length;
+ req->request_data.data = talloc_reference(req, stub_data->data);
+ if (req->request_data.data == NULL) {
+ return NULL;
+ }
+
+ DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
+
+ dcerpc_ship_next_request(p->conn);
+
+ if (p->request_timeout) {
+ event_add_timed(dcerpc_event_context(p), req,
+ timeval_current_ofs(p->request_timeout, 0),
+ dcerpc_timeout_handler, req);
+ }
+
+ talloc_set_destructor(req, dcerpc_req_destructor);
+ return req;
+}
+
+/*
+ Send a request using the transport
+*/
+
+static void dcerpc_ship_next_request(struct dcerpc_connection *c)
+{
+ struct rpc_request *req;
+ struct dcerpc_pipe *p;
+ DATA_BLOB *stub_data;
+ struct ncacn_packet pkt;
+ DATA_BLOB blob;
+ uint32_t remaining, chunk_size;
+ BOOL first_packet = True;
+
+ req = c->request_queue;
+ if (req == NULL) {
+ return;
+ }
+
+ p = req->p;
+ stub_data = &req->request_data;
+
+ if (!req->async_call && (c->pending != NULL)) {
+ return;
+ }
+
+ DLIST_REMOVE(c->request_queue, req);
+ DLIST_ADD(c->pending, req);
+
init_ncacn_hdr(p->conn, &pkt);
remaining = stub_data->length;
@@ -934,16 +998,14 @@ struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
pkt.pfc_flags = 0;
pkt.u.request.alloc_hint = remaining;
pkt.u.request.context_id = p->context_id;
- pkt.u.request.opnum = opnum;
+ pkt.u.request.opnum = req->opnum;
- if (object) {
- pkt.u.request.object.object = *object;
+ if (req->object) {
+ pkt.u.request.object.object = *req->object;
pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
- chunk_size -= ndr_size_GUID(object,0);
+ chunk_size -= ndr_size_GUID(req->object,0);
}
- DLIST_ADD(p->conn->pending, req);
-
/* we send a series of pdus without waiting for a reply */
while (remaining > 0 || first_packet) {
uint32_t chunk = MIN(chunk_size, remaining);
@@ -968,28 +1030,18 @@ struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
if (!NT_STATUS_IS_OK(req->status)) {
req->state = RPC_REQUEST_DONE;
DLIST_REMOVE(p->conn->pending, req);
- return req;
+ return;
}
req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
if (!NT_STATUS_IS_OK(req->status)) {
req->state = RPC_REQUEST_DONE;
DLIST_REMOVE(p->conn->pending, req);
- return req;
+ return;
}
remaining -= chunk;
}
-
- if (p->request_timeout) {
- event_add_timed(dcerpc_event_context(p), req,
- timeval_current_ofs(p->request_timeout, 0),
- dcerpc_timeout_handler, req);
- }
-
- talloc_set_destructor(req, dcerpc_req_destructor);
-
- return req;
}
/*
@@ -1036,13 +1088,14 @@ NTSTATUS dcerpc_request_recv(struct rpc_request *req,
NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
struct GUID *object,
uint16_t opnum,
+ BOOL async,
TALLOC_CTX *mem_ctx,
DATA_BLOB *stub_data_in,
DATA_BLOB *stub_data_out)
{
struct rpc_request *req;
- req = dcerpc_request_send(p, object, opnum, stub_data_in);
+ req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
if (req == NULL) {
return NT_STATUS_NO_MEMORY;
}
@@ -1251,7 +1304,8 @@ struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
dump_data(10, request.data, request.length);
/* make the actual dcerpc request */
- req = dcerpc_request_send(p, object, opnum, &request);
+ req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
+ &request);
if (req != NULL) {
req->ndr.table = table;