svn commit: samba r17084 - in branches/SAMBA_4_0/source/smb_server: . smb2

metze at samba.org metze at samba.org
Mon Jul 17 09:44:15 GMT 2006


Author: metze
Date: 2006-07-17 09:44:13 +0000 (Mon, 17 Jul 2006)
New Revision: 17084

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

Log:
implement SMB2 Cancel in the server,
that makes it possible for clients to cancel
async requests, like NOTIFY...

metze
Modified:
   branches/SAMBA_4_0/source/smb_server/smb2/fileio.c
   branches/SAMBA_4_0/source/smb_server/smb2/receive.c
   branches/SAMBA_4_0/source/smb_server/smb2/smb2_server.h
   branches/SAMBA_4_0/source/smb_server/smb_server.h


Changeset:
Modified: branches/SAMBA_4_0/source/smb_server/smb2/fileio.c
===================================================================
--- branches/SAMBA_4_0/source/smb_server/smb2/fileio.c	2006-07-17 09:36:52 UTC (rev 17083)
+++ branches/SAMBA_4_0/source/smb_server/smb2/fileio.c	2006-07-17 09:44:13 UTC (rev 17084)
@@ -286,11 +286,6 @@
 	SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_ioctl(req->ntvfs, io));
 }
 
-void smb2srv_cancel_recv(struct smb2srv_request *req)
-{
-	smb2srv_send_error(req, NT_STATUS_NOT_IMPLEMENTED);
-}
-
 static void smb2srv_notify_send(struct ntvfs_request *ntvfs)
 {
 	struct smb2srv_request *req;

Modified: branches/SAMBA_4_0/source/smb_server/smb2/receive.c
===================================================================
--- branches/SAMBA_4_0/source/smb_server/smb2/receive.c	2006-07-17 09:36:52 UTC (rev 17083)
+++ branches/SAMBA_4_0/source/smb_server/smb2/receive.c	2006-07-17 09:44:13 UTC (rev 17084)
@@ -28,8 +28,22 @@
 #include "smb_server/smb2/smb2_server.h"
 #include "smbd/service_stream.h"
 #include "lib/stream/packet.h"
+#include "ntvfs/ntvfs.h"
 
+static int smb2srv_request_destructor(struct smb2srv_request *req)
+{
+	DLIST_REMOVE(req->smb_conn->requests2.list, req);
+	if (req->pending_id) {
+		idr_remove(req->smb_conn->requests2.idtree_req, req->pending_id);
+	}
+	return 0;
+}
 
+static int smb2srv_request_deny_destructor(struct smb2srv_request *req)
+{
+	return -1;
+}
+
 static struct smb2srv_request *smb2srv_init_request(struct smbsrv_connection *smb_conn)
 {
 	struct smb2srv_request *req;
@@ -39,12 +53,24 @@
 
 	req->smb_conn = smb_conn;
 
+	talloc_set_destructor(req, smb2srv_request_destructor);
+
 	return req;
 }
 
 NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_size,
 			     BOOL body_dynamic_present, uint32_t body_dynamic_size)
 {
+	uint32_t flags = 0x00000001;
+	uint32_t pid = IVAL(req->in.hdr, SMB2_HDR_PID);
+	uint32_t tid = IVAL(req->in.hdr, SMB2_HDR_TID);
+
+	if (req->pending_id) {
+		flags |= 0x00000002;
+		pid = req->pending_id;
+		tid = 0;
+	}
+
 	if (body_dynamic_present) {
 		if (body_dynamic_size == 0) {
 			body_dynamic_size = 1;
@@ -71,11 +97,11 @@
 	SIVAL(req->out.hdr, SMB2_HDR_STATUS,  NT_STATUS_V(req->status));
 	SSVAL(req->out.hdr, SMB2_HDR_OPCODE,  SVAL(req->in.hdr, SMB2_HDR_OPCODE));
 	SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1,0x0001);
-	SIVAL(req->out.hdr, SMB2_HDR_FLAGS,   0x00000001);
+	SIVAL(req->out.hdr, SMB2_HDR_FLAGS,   flags);
 	SIVAL(req->out.hdr, SMB2_HDR_UNKNOWN2,0);
 	SBVAL(req->out.hdr, SMB2_HDR_SEQNUM,  req->seqnum);
-	SIVAL(req->out.hdr, SMB2_HDR_PID,     IVAL(req->in.hdr, SMB2_HDR_PID));
-	SIVAL(req->out.hdr, SMB2_HDR_TID,     IVAL(req->in.hdr, SMB2_HDR_TID));
+	SIVAL(req->out.hdr, SMB2_HDR_PID,     pid);
+	SIVAL(req->out.hdr, SMB2_HDR_TID,     tid);
 	SBVAL(req->out.hdr, SMB2_HDR_UID,     BVAL(req->in.hdr, SMB2_HDR_UID));
 	memset(req->out.hdr+SMB2_HDR_SIG, 0, 16);
 
@@ -216,8 +242,6 @@
 		smb2srv_ioctl_recv(req);
 		return NT_STATUS_OK;
 	case SMB2_OP_CANCEL:
-		if (!req->session) goto nosession;
-		if (!req->tcon)	goto notcon;
 		smb2srv_cancel_recv(req);
 		return NT_STATUS_OK;
 	case SMB2_OP_KEEPALIVE:
@@ -329,6 +353,72 @@
 	return smb2srv_reply(req);
 }
 
+static NTSTATUS smb2srv_init_pending(struct smbsrv_connection *smb_conn)
+{
+	smb_conn->requests2.idtree_req = idr_init(smb_conn);
+	NT_STATUS_HAVE_NO_MEMORY(smb_conn->requests2.idtree_req);
+	smb_conn->requests2.idtree_limit	= 0x00FFFFFF & (UINT32_MAX - 1);
+	smb_conn->requests2.list		= NULL;
+
+	return NT_STATUS_OK;
+}
+
+NTSTATUS smb2srv_queue_pending(struct smb2srv_request *req)
+{
+	int id;
+
+	if (req->pending_id) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	id = idr_get_new_above(req->smb_conn->requests2.idtree_req, req, 
+			       1, req->smb_conn->requests2.idtree_limit);
+	if (id == -1) {
+		return NT_STATUS_INSUFFICIENT_RESOURCES;
+	}
+
+	DLIST_ADD_END(req->smb_conn->requests2.list, req, struct smb2srv_request *);
+	req->pending_id = id;
+
+	talloc_set_destructor(req, smb2srv_request_deny_destructor);
+	smb2srv_send_error(req, STATUS_PENDING);
+	talloc_set_destructor(req, smb2srv_request_destructor);
+
+	return NT_STATUS_OK;
+}
+
+void smb2srv_cancel_recv(struct smb2srv_request *req)
+{
+	uint32_t pending_id;
+	uint32_t flags;
+	void *p;
+	struct smb2srv_request *r;
+
+	if (!req->session) goto done;
+
+	flags		= IVAL(req->in.hdr, SMB2_HDR_FLAGS);
+	pending_id	= IVAL(req->in.hdr, SMB2_HDR_PID);
+
+	if (!(flags & 0x00000002)) {
+		/* TODO: what to do here? */
+		goto done;
+	}
+ 
+ 	p = idr_find(req->smb_conn->requests2.idtree_req, pending_id);
+	if (!p) goto done;
+
+	r = talloc_get_type(p, struct smb2srv_request);
+	if (!r) goto done;
+
+	if (!r->ntvfs) goto done;
+
+	ntvfs_cancel(r->ntvfs);
+
+done:
+	/* we never generate a reply for a SMB2 Cancel */
+	talloc_free(req);
+}
+
 /*
  * init the SMB2 protocol related stuff
  */
@@ -351,6 +441,9 @@
 	status = smbsrv_init_sessions(smb_conn, UINT64_MAX);
 	NT_STATUS_NOT_OK_RETURN(status);
 
+	status = smb2srv_init_pending(smb_conn);
+	NT_STATUS_NOT_OK_RETURN(status);
+
 	return NT_STATUS_OK;
 	
 }

Modified: branches/SAMBA_4_0/source/smb_server/smb2/smb2_server.h
===================================================================
--- branches/SAMBA_4_0/source/smb_server/smb2/smb2_server.h	2006-07-17 09:36:52 UTC (rev 17083)
+++ branches/SAMBA_4_0/source/smb_server/smb2/smb2_server.h	2006-07-17 09:44:13 UTC (rev 17084)
@@ -53,6 +53,9 @@
 	/* for matching request and reply */
 	uint64_t seqnum;
 
+	/* the id that can be used to cancel the request */
+	uint32_t pending_id;
+
 	struct smb2_request_buffer in;
 	struct smb2_request_buffer out;
 };
@@ -127,7 +130,13 @@
 */
 #define SMB2SRV_CALL_NTVFS_BACKEND(cmd) do { \
 	req->ntvfs->async_states->status = cmd; \
-	if (!(req->ntvfs->async_states->state & NTVFS_ASYNC_STATE_ASYNC)) { \
+	if (req->ntvfs->async_states->state & NTVFS_ASYNC_STATE_ASYNC) { \
+		NTSTATUS _status; \
+		_status = smb2srv_queue_pending(req); \
+		if (!NT_STATUS_IS_OK(_status)) { \
+			ntvfs_cancel(req->ntvfs); \
+		} \
+	} else { \
 		req->ntvfs->async_states->send_fn(req->ntvfs); \
 	} \
 } while (0)

Modified: branches/SAMBA_4_0/source/smb_server/smb_server.h
===================================================================
--- branches/SAMBA_4_0/source/smb_server/smb_server.h	2006-07-17 09:36:52 UTC (rev 17083)
+++ branches/SAMBA_4_0/source/smb_server/smb_server.h	2006-07-17 09:44:13 UTC (rev 17084)
@@ -324,9 +324,26 @@
 	/*
 	 * the server_context holds a linked list of pending requests,
 	 * this is used for finding the request structures on ntcancel requests
+	 * For SMB only
 	 */
 	struct smbsrv_request *requests;
 
+	/*
+	 * the server_context holds a linked list of pending requests,
+	 * and an idtree for finding the request structures on SMB2 Cancel
+	 * For SMB2 only
+	 */
+	struct {
+		/* an id tree used to allocate ids */
+		struct idr_context *idtree_req;
+
+		/* this is the limit of pending requests values for this connection */
+		uint32_t idtree_limit;
+
+		/* list of open tree connects */
+		struct smb2srv_request *list;
+	} requests2;
+
 	struct smb_signing_context signing;
 
 	struct stream_connection *connection;



More information about the samba-cvs mailing list