added a nasty lock testing program
authorAndrew Tridgell <tridge@samba.org>
Wed, 3 May 2000 13:54:28 +0000 (13:54 +0000)
committerAndrew Tridgell <tridge@samba.org>
Wed, 3 May 2000 13:54:28 +0000 (13:54 +0000)
it opens 2 connections to each of 2 servers, and opens 2 fnums on the
same file on each connection (a total of 8 file descriptors)

then it does random lock/unlock/reopen requests in a 100 byte range on
the file and compares the results from the 2 servers.

strangely enough, NT fails this test against itself right now - I'm
still trying to figure that out.

source/Makefile.in
source/utils/locktest.c [new file with mode: 0644]

index 0daada257d5af969b68a8035a7caabf176368637..076820ac7f1da496c705fb349b908f6200e7d82c 100644 (file)
@@ -267,7 +267,10 @@ NMBLOOKUP_OBJ = utils/nmblookup.o $(PARAM_OBJ) $(UBIQX_OBJ) \
 SMBTORTURE_OBJ = utils/torture.o utils/nbio.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
                  $(UBIQX_OBJ) $(LIB_OBJ)
 
-MASKTEST_OBJ = utils/masktest.o smbd/mangle.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
+MASKTEST_OBJ = utils/masktest.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
+                 $(UBIQX_OBJ) $(LIB_OBJ)
+
+LOCKTEST_OBJ = utils/locktest.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
                  $(UBIQX_OBJ) $(LIB_OBJ)
 
 RPCTORTURE_OBJ = utils/rpctorture.o \
@@ -306,6 +309,8 @@ smbtorture : CHECK bin/smbtorture
 
 masktest : CHECK bin/masktest
 
+locktest : CHECK bin/locktest
+
 rpctorture : CHECK bin/rpctorture
 
 debug2html : CHECK bin/debug2html
@@ -476,6 +481,10 @@ bin/masktest: $(MASKTEST_OBJ) bin/.dummy
        @echo Linking $@
        @$(CC) $(FLAGS) -o $@ $(MASKTEST_OBJ) $(LDFLAGS) $(LIBS)
 
+bin/locktest: $(LOCKTEST_OBJ) bin/.dummy
+       @echo Linking $@
+       @$(CC) $(FLAGS) -o $@ $(LOCKTEST_OBJ) $(LDFLAGS) $(LIBS)
+
 bin/rpctorture: $(RPCTORTURE_OBJ) bin/.dummy
        @echo Linking $@
        @$(CC) $(FLAGS) -o $@ $(RPCTORTURE_OBJ) $(LDFLAGS) $(LIBS)
diff --git a/source/utils/locktest.c b/source/utils/locktest.c
new file mode 100644 (file)
index 0000000..44b5d92
--- /dev/null
@@ -0,0 +1,340 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 2.0
+   mask_match tester
+   Copyright (C) Andrew Tridgell 1999
+   
+   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"
+
+static fstring password;
+static fstring username;
+static fstring workgroup;
+static int got_pass;
+static int numops = 1000;
+
+#define FILENAME "locktest.dat"
+#define LOCKRANGE 100
+
+#define READ_PCT 75
+#define LOCK_PCT 45
+#define UNLOCK_PCT 45
+
+/* each server has two connections open to it. Each connection has two file
+   descriptors open on the file - 8 file descriptors in total 
+
+   we then do random locking ops in tamdem on the 4 fnums from each
+   server and ensure that the results match
+ */
+static void test_locks(struct cli_state *cli[2][2])
+{
+       int fnum[2][2][2];
+       int server, conn, f; 
+
+       cli_unlink(cli[0][0], FILENAME);
+       cli_unlink(cli[1][0], FILENAME);
+
+       for (server=0;server<2;server++)
+       for (conn=0;conn<2;conn++)
+       for (f=0;f<2;f++) {
+               fnum[server][conn][f] = cli_open(cli[server][conn], FILENAME,
+                                                O_RDWR|O_CREAT,
+                                                DENY_NONE);
+               if (fnum[server][conn][f] == -1) {
+                       fprintf(stderr,"Failed to open fnum[%d][%d][%d]\n",
+                               server, conn, f);
+                       return;
+               }
+       }
+
+       while (numops--) {
+               int start, len, op, r;
+               BOOL ret1, ret2;
+
+               conn = random() % 2;
+               f = random() % 2;
+               start = random() % (LOCKRANGE-1);
+               len = 1 + random() % (LOCKRANGE-start);
+
+               r = random() % 100;
+
+               if (r < READ_PCT) {
+                       op = READ_LOCK; 
+               } else {
+                       op = WRITE_LOCK; 
+               }
+
+               r = random() % 100;
+               
+               if (r < LOCK_PCT) {
+                       /* set a lock */
+                       ret1 = cli_lock(cli[0][conn], 
+                                       fnum[0][conn][f],
+                                       start, len, 0, op);
+                       ret2 = cli_lock(cli[1][conn], 
+                                       fnum[1][conn][f],
+                                       start, len, 0, op);
+                       if (ret1 != ret2) {
+                               printf("lock(%d): server1 gave %d  server2 gave %d\n", 
+                                       numops, (int)ret1, (int)ret2);
+                               return;
+                       }
+               } else if (r < LOCK_PCT+UNLOCK_PCT) {
+                       /* unset a lock */
+                       /* set a lock */
+                       ret1 = cli_unlock(cli[0][conn], 
+                                         fnum[0][conn][f],
+                                         start, len);
+                       ret2 = cli_unlock(cli[1][conn], 
+                                         fnum[1][conn][f],
+                                         start, len);
+                       if (ret1 != ret2) {
+                               printf("unlock(%d): server1 gave %d  server2 gave %d\n", 
+                                       numops, (int)ret1, (int)ret2);
+                               return;
+                       }
+               } else {
+                       /* reopen the file */
+                       cli_close(cli[0][conn], fnum[0][conn][f]);
+                       cli_close(cli[1][conn], fnum[1][conn][f]);
+                       fnum[0][conn][f] = cli_open(cli[0][conn], FILENAME,
+                                                   O_RDWR|O_CREAT,
+                                                   DENY_NONE);
+                       fnum[1][conn][f] = cli_open(cli[1][conn], FILENAME,
+                                                   O_RDWR|O_CREAT,
+                                                   DENY_NONE);
+                       if (fnum[0][conn][f] == -1) {
+                               printf("failed to reopen on share1\n");
+                               return;
+                       }
+                       if (fnum[1][conn][f] == -1) {
+                               printf("failed to reopen on share2\n");
+                               return;
+                       }
+               }
+               if (numops % 100 == 0) {
+                       printf("%d\n", numops);
+               }
+       }
+}
+
+
+/***************************************************** 
+return a connection to a server
+*******************************************************/
+struct cli_state *connect_one(char *share)
+{
+       struct cli_state *c;
+       struct nmb_name called, calling;
+       char *server_n;
+       fstring server;
+       struct in_addr ip;
+       extern struct in_addr ipzero;
+
+       fstrcpy(server,share+2);
+       share = strchr(server,'\\');
+       if (!share) return NULL;
+       *share = 0;
+       share++;
+
+       server_n = server;
+       
+       ip = ipzero;
+
+       make_nmb_name(&calling, "locktest", 0x0);
+       make_nmb_name(&called , server, 0x20);
+
+ again:
+       ip = ipzero;
+
+       /* have to open a new connection */
+       if (!(c=cli_initialise(NULL)) || (cli_set_port(c, 139) == 0) ||
+           !cli_connect(c, server_n, &ip)) {
+               DEBUG(0,("Connection to %s failed\n", server_n));
+               return NULL;
+       }
+
+       if (!cli_session_request(c, &calling, &called)) {
+               DEBUG(0,("session request to %s failed\n", called.name));
+               cli_shutdown(c);
+               if (strcmp(called.name, "*SMBSERVER")) {
+                       make_nmb_name(&called , "*SMBSERVER", 0x20);
+                       goto again;
+               }
+               return NULL;
+       }
+
+       DEBUG(4,(" session request ok\n"));
+
+       if (!cli_negprot(c)) {
+               DEBUG(0,("protocol negotiation failed\n"));
+               cli_shutdown(c);
+               return NULL;
+       }
+
+       if (!got_pass) {
+               char *pass = getpass("Password: ");
+               if (pass) {
+                       pstrcpy(password, pass);
+               }
+       }
+
+       if (!cli_session_setup(c, username, 
+                              password, strlen(password),
+                              password, strlen(password),
+                              workgroup)) {
+               DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
+               return NULL;
+       }
+
+       /*
+        * These next two lines are needed to emulate
+        * old client behaviour for people who have
+        * scripts based on client output.
+        * QUESTION ? Do we want to have a 'client compatibility
+        * mode to turn these on/off ? JRA.
+        */
+
+       if (*c->server_domain || *c->server_os || *c->server_type)
+               DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
+                       c->server_domain,c->server_os,c->server_type));
+       
+       DEBUG(4,(" session setup ok\n"));
+
+       if (!cli_send_tconX(c, share, "?????",
+                           password, strlen(password)+1)) {
+               DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
+               cli_shutdown(c);
+               return NULL;
+       }
+
+       DEBUG(4,(" tconx ok\n"));
+
+       return c;
+}
+
+
+static void usage(void)
+{
+       printf(
+"Usage:\n\
+  locktest //server1/share1 //server2/share2 [options..]\n\
+  options:\n\
+        -U user%%pass\n\
+        -s seed\n\
+");
+}
+
+/****************************************************************************
+  main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+       char *share1, *share2;
+       struct cli_state *cli[2][2];
+       extern char *optarg;
+       extern int optind;
+       extern FILE *dbf;
+       int opt;
+       char *p;
+       int seed;
+       static pstring servicesf = CONFIGFILE;
+
+       setlinebuf(stdout);
+
+       dbf = stderr;
+
+       if (argv[1][0] == '-' || argc < 3) {
+               usage();
+               exit(1);
+       }
+
+       share1 = argv[1];
+       share2 = argv[2];
+
+       all_string_sub(share1,"/","\\",0);
+       all_string_sub(share2,"/","\\",0);
+
+       setup_logging(argv[0],True);
+
+       argc -= 2;
+       argv += 2;
+
+       TimeInit();
+       charset_initialise();
+
+       lp_load(servicesf,True,False,False);
+       load_interfaces();
+
+       if (getenv("USER")) {
+               pstrcpy(username,getenv("USER"));
+       }
+
+       seed = time(NULL);
+
+       while ((opt = getopt(argc, argv, "U:s:ho:")) != EOF) {
+               switch (opt) {
+               case 'U':
+                       pstrcpy(username,optarg);
+                       p = strchr(username,'%');
+                       if (p) {
+                               *p = 0;
+                               pstrcpy(password, p+1);
+                               got_pass = 1;
+                       }
+                       break;
+               case 's':
+                       seed = atoi(optarg);
+                       break;
+               case 'o':
+                       numops = atoi(optarg);
+                       break;
+               case 'h':
+                       usage();
+                       exit(1);
+               default:
+                       printf("Unknown option %c (%d)\n", (char)opt, opt);
+                       exit(1);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       DEBUG(0,("seed=%d\n", seed));
+       srandom(seed);
+
+       cli[0][0] = connect_one(share1);
+       cli[0][1] = connect_one(share1);
+       if (!cli[0][0] || !cli[0][1]) {
+               DEBUG(0,("Failed to connect to %s\n", share1));
+               exit(1);
+       }
+
+       cli[1][0] = connect_one(share2);
+       cli[1][1] = connect_one(share2);
+       if (!cli[1][0] || !cli[1][1]) {
+               DEBUG(0,("Failed to connect to %s\n", share2));
+               exit(1);
+       }
+
+       test_locks(cli);
+
+       return(0);
+}