added a oplock break handler hook to the client code, this allows for more complete...
authorAndrew Tridgell <tridge@samba.org>
Mon, 18 Jun 2001 08:26:15 +0000 (08:26 +0000)
committerAndrew Tridgell <tridge@samba.org>
Mon, 18 Jun 2001 08:26:15 +0000 (08:26 +0000)
(This used to be commit 3d4a3bfacd9ef225aeaab801e5a216d12814b60a)

source3/Makefile.in
source3/include/client.h
source3/include/proto.h
source3/libsmb/clientgen.c
source3/libsmb/clioplock.c [new file with mode: 0644]
source3/utils/torture.c

index 16c35ca41cd29c935f290a9dc03261727c7890eb..7d70e755b03cef648cd80083a8fbd73c7a510cdb 100644 (file)
@@ -121,6 +121,7 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
             libsmb/namequery.o libsmb/nmblib.o libsmb/clistr.o \
              libsmb/nterr.o libsmb/smbdes.o libsmb/smbencrypt.o \
              libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o \
+            libsmb/clioplock.o \
             libsmb/passchange.o libsmb/unexpected.o $(RPC_PARSE_OBJ1)
 
 LIBMSRPC_OBJ = libsmb/cli_lsarpc.o libsmb/cli_samr.o libsmb/cli_spoolss.o \
index bdc2383f8ef9844b53d66958906d9c047eec7e68..ecd97c143300e8a4d5f325fc3eab1d037378036f 100644 (file)
@@ -132,6 +132,9 @@ struct cli_state {
 
        BOOL use_oplocks; /* should we use oplocks? */
        BOOL use_level_II_oplocks; /* should we use level II oplocks? */
+
+       /* a oplock break request handler */
+       BOOL (*oplock_handler)(struct cli_state *cli, int fnum, unsigned char level);
 };
 
 #endif /* _CLIENT_H */
index b2f41e231f2eca10cb80148d8b48cf2f39a6bc6d..3bc62add3ecb8ae8e0be27fefcd4c9dabc4d5867 100644 (file)
@@ -1097,6 +1097,12 @@ BOOL cli_message_start(struct cli_state *cli, char *host, char *username,
 BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp);
 BOOL cli_message_end(struct cli_state *cli, int grp);
 
+/* The following definitions come from libsmb/clioplock.c  */
+
+BOOL cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level);
+void cli_oplock_handler(struct cli_state *cli, 
+                       BOOL (*handler)(struct cli_state *, int, unsigned char));
+
 /* The following definitions come from libsmb/cliprint.c  */
 
 int cli_print_queue(struct cli_state *cli, 
index 8e00bca82a9a6909ccab3efc5d332e767456039e..e9f55850ac18ee42615414018c0a558376c7a3a4 100644 (file)
@@ -25,7 +25,6 @@
 
 
 extern int DEBUGLEVEL;
-static void cli_process_oplock(struct cli_state *cli);
 
 /*
  * Change the port number used to call on 
@@ -53,7 +52,11 @@ BOOL cli_receive_smb(struct cli_state *cli)
                    CVAL(cli->inbuf,smb_com) == SMBlockingX &&
                    SVAL(cli->inbuf,smb_vwv6) == 0 &&
                    SVAL(cli->inbuf,smb_vwv7) == 0) {
-                       if (cli->use_oplocks) cli_process_oplock(cli);
+                       if (cli->oplock_handler) {
+                               int fnum = SVAL(cli->inbuf,smb_vwv2);
+                               unsigned char level = CVAL(cli->inbuf,smb_vwv3+1);
+                               if (!cli->oplock_handler(cli, fnum, level)) return False;
+                       }
                        /* try to prevent loops */
                        CVAL(cli->inbuf,smb_com) = 0xFF;
                        goto again;
@@ -125,51 +128,6 @@ void cli_setup_bcc(struct cli_state *cli, void *p)
 }
 
 
-/****************************************************************************
-process an oplock break request from the server
-****************************************************************************/
-static void cli_process_oplock(struct cli_state *cli)
-{
-       char *oldbuf = cli->outbuf;
-       pstring buf;
-       int fnum;
-       unsigned char level;
-
-       fnum = SVAL(cli->inbuf,smb_vwv2);
-       level = CVAL(cli->inbuf,smb_vwv3+1);
-
-       /* damn, we really need to keep a record of open files so we
-          can detect a oplock break and a close crossing on the
-          wire. for now this swallows the errors */
-       if (fnum == 0) return;
-
-       /* Ignore level II break to none's. */
-       if (level == OPLOCKLEVEL_NONE)
-               return;
-
-       cli->outbuf = buf;
-
-        memset(buf,'\0',smb_size);
-        set_message(buf,8,0,True);
-
-        CVAL(buf,smb_com) = SMBlockingX;
-       SSVAL(buf,smb_tid, cli->cnum);
-        cli_setup_packet(cli);
-       SSVAL(buf,smb_vwv0,0xFF);
-       SSVAL(buf,smb_vwv1,0);
-       SSVAL(buf,smb_vwv2,fnum);
-       if (cli->use_level_II_oplocks)
-               SSVAL(buf,smb_vwv3,0x102); /* levelII oplock break ack */
-       else
-               SSVAL(buf,smb_vwv3,2); /* exclusive oplock break ack */
-       SIVAL(buf,smb_vwv4,0); /* timoeut */
-       SSVAL(buf,smb_vwv6,0); /* unlockcount */
-       SSVAL(buf,smb_vwv7,0); /* lockcount */
-
-        cli_send_smb(cli);     
-
-       cli->outbuf = oldbuf;
-}
 
 /****************************************************************************
 initialise a client structure
@@ -219,6 +177,8 @@ struct cli_state *cli_initialise(struct cli_state *cli)
        cli->max_xmit = cli->bufsize;
        cli->outbuf = (char *)malloc(cli->bufsize);
        cli->inbuf = (char *)malloc(cli->bufsize);
+       cli->oplock_handler = cli_oplock_ack;
+
        if (!cli->outbuf || !cli->inbuf)
        {
                return NULL;
diff --git a/source3/libsmb/clioplock.c b/source3/libsmb/clioplock.c
new file mode 100644 (file)
index 0000000..a52dcf3
--- /dev/null
@@ -0,0 +1,72 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 3.0
+   SMB client oplock functions
+   Copyright (C) Andrew Tridgell 2001
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+extern int DEBUGLEVEL;
+
+
+/****************************************************************************
+send an ack for an oplock break request
+****************************************************************************/
+BOOL cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level)
+{
+       char *oldbuf = cli->outbuf;
+       pstring buf;
+       BOOL ret;
+
+       cli->outbuf = buf;
+
+        memset(buf,'\0',smb_size);
+        set_message(buf,8,0,True);
+
+        CVAL(buf,smb_com) = SMBlockingX;
+       SSVAL(buf,smb_tid, cli->cnum);
+        cli_setup_packet(cli);
+       SSVAL(buf,smb_vwv0,0xFF);
+       SSVAL(buf,smb_vwv1,0);
+       SSVAL(buf,smb_vwv2,fnum);
+       if (level == 1)
+               SSVAL(buf,smb_vwv3,0x102); /* levelII oplock break ack */
+       else
+               SSVAL(buf,smb_vwv3,2); /* exclusive oplock break ack */
+       SIVAL(buf,smb_vwv4,0); /* timoeut */
+       SSVAL(buf,smb_vwv6,0); /* unlockcount */
+       SSVAL(buf,smb_vwv7,0); /* lockcount */
+
+        ret = cli_send_smb(cli);       
+
+       cli->outbuf = oldbuf;
+
+       return ret;
+}
+
+
+/****************************************************************************
+set the oplock handler for a connection
+****************************************************************************/
+void cli_oplock_handler(struct cli_state *cli, 
+                       BOOL (*handler)(struct cli_state *, int, unsigned char))
+{
+       cli->oplock_handler = handler;
+}
+
index 982be771516639534eb5d4fdabdaf658b8656bb1..5f08887a607e5131a4370dc3f7a19326ab72069b 100644 (file)
@@ -2091,6 +2091,49 @@ static void run_oplock2(int dummy)
        printf("finished oplock test 2\n");
 }
 
+/* handler for oplock 3 tests */
+static BOOL oplock3_handler(struct cli_state *cli, int fnum, unsigned char level)
+{
+       printf("got oplock break fnum=%d level=%d\n",
+              fnum, level);
+       return cli_oplock_ack(cli, fnum, level);
+}
+
+static void run_oplock3(int dummy)
+{
+       static struct cli_state cli;
+       char *fname = "\\oplockt3.dat";
+       int fnum;
+       char buf[4] = "abcd";
+
+       printf("starting oplock test 3\n");
+
+       if (fork() == 0) {
+               /* Child code */
+               if (!open_connection(&cli)) return;
+               sleep(2);
+               /* try to trigger a oplock break in parent */
+               fnum = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+               cli_write(&cli, fnum, 0, buf, 0, 4);
+               exit(0);
+       }
+
+       /* parent code */
+       use_oplocks = True;
+       use_level_II_oplocks = True;
+       if (!open_connection(&cli)) return;
+       cli_oplock_handler(&cli, oplock3_handler);
+       fnum = cli_open(&cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+       cli_write(&cli, fnum, 0, buf, 0, 4);
+       cli_close(&cli, fnum);
+       fnum = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+       cli.timeout = 20000;
+       cli_receive_smb(&cli);
+       printf("finished oplock test 3\n");
+}
+
+
+
 /*
   Test delete on close semantics.
  */
@@ -2764,6 +2807,7 @@ static struct {
        {"NBWNT",  run_nbwnt, 0},
        {"OPLOCK1",  run_oplock1, 0},
        {"OPLOCK2",  run_oplock2, 0},
+       {"OPLOCK3",  run_oplock3, 0},
        {"DIR",  run_dirtest, 0},
        {"DENY1",  run_denytest1, 0},
        {"DENY2",  run_denytest2, 0},
@@ -2790,8 +2834,8 @@ static void run_test(char *name)
        }
        
        for (i=0;torture_ops[i].name;i++) {
-               fstrcpy(randomfname, "\\XXXXXXX");
-               mktemp(randomfname);
+               snprintf(randomfname, sizeof(randomfname), "\\XX%x", 
+                        (unsigned)random());
 
                if (strequal(name, torture_ops[i].name)) {
                        start_timer();