svn commit: samba r21811 - in branches/SAMBA_4_0/source/librpc/rpc: .

tridge at samba.org tridge at samba.org
Tue Mar 13 03:43:16 GMT 2007


Author: tridge
Date: 2007-03-13 03:43:16 +0000 (Tue, 13 Mar 2007)
New Revision: 21811

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=21811

Log:

fixed a queueing error in the dcerpc client code. WHen the
dcerpc_ship_next_request() logic was added the penidng queue was split
in two, but we also needed to update the code which removes requests
from the queue to know about the two queues. Following the pattern
used in other client libs, I based which queue to remove from on
req->state, and added a new state RPC_REQUEST_QUEUED. This fixes a
crash that happens when rpc requests time out.

This patch also fixes the handling of timed out bind requests, and the
talloc_reference handling in dcerpc_ndr_request_recv().

Modified:
   branches/SAMBA_4_0/source/librpc/rpc/dcerpc.c
   branches/SAMBA_4_0/source/librpc/rpc/dcerpc.h


Changeset:
Modified: branches/SAMBA_4_0/source/librpc/rpc/dcerpc.c
===================================================================
--- branches/SAMBA_4_0/source/librpc/rpc/dcerpc.c	2007-03-13 02:58:05 UTC (rev 21810)
+++ branches/SAMBA_4_0/source/librpc/rpc/dcerpc.c	2007-03-13 03:43:16 UTC (rev 21811)
@@ -530,6 +530,25 @@
 }
 
 /*
+  remove requests from the pending or queued queues
+ */
+static int dcerpc_req_dequeue(struct rpc_request *req)
+{
+	switch (req->state) {
+	case RPC_REQUEST_QUEUED:
+		DLIST_REMOVE(req->p->conn->request_queue, req);
+		break;
+	case RPC_REQUEST_PENDING:
+		DLIST_REMOVE(req->p->conn->pending, req);
+		break;
+	case RPC_REQUEST_DONE:
+		break;
+	}
+	return 0;
+}
+
+
+/*
   mark the dcerpc connection dead. All outstanding requests get an error
 */
 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
@@ -537,9 +556,9 @@
 	/* all pending requests get the error */
 	while (conn->pending) {
 		struct rpc_request *req = conn->pending;
+		dcerpc_req_dequeue(req);
 		req->state = RPC_REQUEST_DONE;
 		req->status = status;
-		DLIST_REMOVE(conn->pending, req);
 		if (req->async.callback) {
 			req->async.callback(req);
 		}
@@ -639,13 +658,14 @@
 {
 	struct rpc_request *req = talloc_get_type(private, struct rpc_request);
 
-	if (req->state != RPC_REQUEST_PENDING) {
+	if (req->state == RPC_REQUEST_DONE) {
 		return;
 	}
 
+	dcerpc_req_dequeue(req);
+
 	req->status = NT_STATUS_IO_TIMEOUT;
 	req->state = RPC_REQUEST_DONE;
-	DLIST_REMOVE(req->p->conn->pending, req);
 	if (req->async.callback) {
 		req->async.callback(req);
 	}
@@ -716,6 +736,7 @@
 	req->p = p;
 	req->recv_handler = dcerpc_bind_recv_handler;
 	DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
+	talloc_set_destructor(req, dcerpc_req_dequeue);
 
 	c->status = p->conn->transport.send_request(p->conn, &blob,
 						    True);
@@ -821,8 +842,8 @@
 	talloc_steal(req, raw_packet->data);
 
 	if (req->recv_handler != NULL) {
+		dcerpc_req_dequeue(req);
 		req->state = RPC_REQUEST_DONE;
-		DLIST_REMOVE(c->pending, req);
 		req->recv_handler(req, raw_packet, pkt);
 		return;
 	}
@@ -894,15 +915,6 @@
 }
 
 /*
-  make sure requests are cleaned up 
- */
-static int dcerpc_req_destructor(struct rpc_request *req)
-{
-	DLIST_REMOVE(req->p->conn->pending, req);
-	return 0;
-}
-
-/*
   perform the send side of a async dcerpc request
 */
 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, 
@@ -923,7 +935,7 @@
 	req->p = p;
 	req->call_id = next_call_id(p->conn);
 	req->status = NT_STATUS_OK;
-	req->state = RPC_REQUEST_PENDING;
+	req->state = RPC_REQUEST_QUEUED;
 	req->payload = data_blob(NULL, 0);
 	req->flags = 0;
 	req->fault_code = 0;
@@ -950,6 +962,7 @@
 	}
 
 	DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
+	talloc_set_destructor(req, dcerpc_req_dequeue);
 
 	dcerpc_ship_next_request(p->conn);
 
@@ -959,7 +972,6 @@
 				dcerpc_timeout_handler, req);
 	}
 
-	talloc_set_destructor(req, dcerpc_req_destructor);
 	return req;
 }
 
@@ -991,6 +1003,7 @@
 
 	DLIST_REMOVE(c->request_queue, req);
 	DLIST_ADD(c->pending, req);
+	req->state = RPC_REQUEST_PENDING;
 
 	init_ncacn_hdr(p->conn, &pkt);
 
@@ -1072,7 +1085,7 @@
 {
 	NTSTATUS status;
 
-	while (req->state == RPC_REQUEST_PENDING) {
+	while (req->state != RPC_REQUEST_DONE) {
 		struct event_context *ctx = dcerpc_event_context(req->p);
 		if (event_loop_once(ctx) != 0) {
 			return NT_STATUS_CONNECTION_DISCONNECTED;
@@ -1366,10 +1379,13 @@
 
 	/* make sure the recv code doesn't free the request, as we
 	   need to grab the flags element before it is freed */
-	talloc_increase_ref_count(req);
+	if (talloc_reference(p, req) == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
 
 	status = dcerpc_request_recv(req, mem_ctx, &response);
 	if (!NT_STATUS_IS_OK(status)) {
+		talloc_unlink(p, req);
 		return status;
 	}
 
@@ -1378,14 +1394,14 @@
 	/* prepare for ndr_pull_* */
 	pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
 	if (!pull) {
-		talloc_free(req);
+		talloc_unlink(p, req);
 		return NT_STATUS_NO_MEMORY;
 	}
 
 	if (pull->data) {
 		pull->data = talloc_steal(pull, pull->data);
 	}
-	talloc_free(req);
+	talloc_unlink(p, req);
 
 	if (flags & DCERPC_PULL_BIGENDIAN) {
 		pull->flags |= LIBNDR_FLAG_BIGENDIAN;
@@ -1590,6 +1606,7 @@
 	req->p = p;
 	req->recv_handler = dcerpc_alter_recv_handler;
 	DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
+	talloc_set_destructor(req, dcerpc_req_dequeue);
 
 	c->status = p->conn->transport.send_request(p->conn, &blob, True);
 	if (!composite_is_ok(c)) return c;

Modified: branches/SAMBA_4_0/source/librpc/rpc/dcerpc.h
===================================================================
--- branches/SAMBA_4_0/source/librpc/rpc/dcerpc.h	2007-03-13 02:58:05 UTC (rev 21810)
+++ branches/SAMBA_4_0/source/librpc/rpc/dcerpc.h	2007-03-13 03:43:16 UTC (rev 21811)
@@ -216,6 +216,7 @@
 
 
 enum rpc_request_state {
+	RPC_REQUEST_QUEUED,
 	RPC_REQUEST_PENDING,
 	RPC_REQUEST_DONE
 };



More information about the samba-cvs mailing list