summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>1997-11-08 04:02:05 +0000
committerAndrew Tridgell <tridge@samba.org>1997-11-08 04:02:05 +0000
commita90d2061316d19c30d9f14c1e78d6f6266183ce0 (patch)
tree4e4477829f154a4fae7d5dc345b5457fc7e85fb9
parent029904995d27c4e765abf9334df34c399a535bea (diff)
downloadsamba-a90d2061316d19c30d9f14c1e78d6f6266183ce0.tar.gz
samba-a90d2061316d19c30d9f14c1e78d6f6266183ce0.tar.bz2
samba-a90d2061316d19c30d9f14c1e78d6f6266183ce0.zip
added two more sets of tests to the smbtorture test. The tests I added
are ones that I know Samba fails. They are: 1) correct support for retaining locks over a close (ie. the server must not use posix semantics) 2) support for lock timeouts 3) the server supports multiple locking contexts on the one SMB connection, distinguished by PID. 4) the server correctly fails overlapping locks made by the same PID (this goes against POSIX behaviour, which is why it is tricky to implement) 5) the server denies unlock requests by an incorrect client PID I've been discussing with Jeremy ways that we can re-implement the locking code to handle these correctly. This test code will be useful to see that we have got it right. (This used to be commit 097781e2992f12c545170c82ada2f4023a9784f5)
-rw-r--r--source3/include/proto.h1
-rw-r--r--source3/libsmb/clientgen.c10
-rw-r--r--source3/utils/torture.c336
3 files changed, 295 insertions, 52 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index d3d905481f..98c671ea86 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -69,6 +69,7 @@ void cli_shutdown(struct cli_state *cli);
char *cli_errstr(struct cli_state *cli);
void cli_error(struct cli_state *cli, int *eclass, int *num);
void cli_sockopt(struct cli_state *cli, char *options);
+int cli_setpid(struct cli_state *cli, int pid);
/*The following definitions come from clientutil.c */
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
index b2ecb07ded..b98f2fca69 100644
--- a/source3/libsmb/clientgen.c
+++ b/source3/libsmb/clientgen.c
@@ -1072,3 +1072,13 @@ void cli_sockopt(struct cli_state *cli, char *options)
{
set_socket_options(cli->fd, options);
}
+
+/****************************************************************************
+set the PID to use for smb messages. Return the old pid.
+****************************************************************************/
+int cli_setpid(struct cli_state *cli, int pid)
+{
+ int ret = cli->pid;
+ cli->pid = pid;
+ return ret;
+}
diff --git a/source3/utils/torture.c b/source3/utils/torture.c
index f3d76e0ee2..67a363df27 100644
--- a/source3/utils/torture.c
+++ b/source3/utils/torture.c
@@ -25,7 +25,6 @@
#include "includes.h"
-static struct cli_state cli;
static fstring host, workgroup, share, password, username, myname;
static char *sockops="";
@@ -45,62 +44,61 @@ static double end_timer()
}
-static int open_connection(void)
+static BOOL open_connection(struct cli_state *c)
{
- if (!cli_initialise(&cli) || !cli_connect(&cli, host, NULL)) {
+ if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
printf("Failed to connect with %s\n", host);
+ return False;
}
- if (!cli_session_request(&cli, host, 0x20, myname)) {
+ if (!cli_session_request(c, host, 0x20, myname)) {
printf("%s rejected the session\n",host);
- cli_shutdown(&cli);
- return -1;
+ cli_shutdown(c);
+ return False;
}
- if (!cli_negprot(&cli)) {
- printf("%s rejected the negprot (%s)\n",host, cli_errstr(&cli));
- cli_shutdown(&cli);
- return -1;
+ if (!cli_negprot(c)) {
+ printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
+ cli_shutdown(c);
+ return False;
}
- if (!cli_session_setup(&cli, username, password, strlen(password),
+ if (!cli_session_setup(c, username, password, strlen(password),
"", 0, workgroup)) {
- printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(&cli));
- cli_shutdown(&cli);
- return -1;
+ printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
+ cli_shutdown(c);
+ return False;
}
- if (!cli_send_tconX(&cli, share, "A:", password, strlen(password)+1)) {
- printf("%s refused tree connect (%s)\n", host, cli_errstr(&cli));
- cli_shutdown(&cli);
- return -1;
+ if (!cli_send_tconX(c, share, "A:", password, strlen(password)+1)) {
+ printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
+ cli_shutdown(c);
+ return False;
}
- return 0;
+ return True;
}
-static void close_connection(void)
+static void close_connection(struct cli_state *c)
{
- if (!cli_tdis(&cli)) {
- printf("tdis failed (%s)\n", cli_errstr(&cli));
+ if (!cli_tdis(c)) {
+ printf("tdis failed (%s)\n", cli_errstr(c));
}
- cli_shutdown(&cli);
+ cli_shutdown(c);
}
-
-
-static BOOL wait_lock(int fnum, uint32 offset, uint32 len)
+static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
{
- while (!cli_lock(&cli, fnum, offset, len, -1)) {
+ while (!cli_lock(c, fnum, offset, len, -1)) {
int eclass, num;
- cli_error(&cli, &eclass, &num);
+ cli_error(c, &eclass, &num);
if (eclass != ERRDOS || num != ERRlock) {
printf("lock failed (%s)\n",
- cli_errstr(&cli));
+ cli_errstr(c));
return False;
}
}
@@ -108,7 +106,7 @@ static BOOL wait_lock(int fnum, uint32 offset, uint32 len)
}
-static int rw_torture(int numops)
+static BOOL rw_torture(struct cli_state *c, int numops)
{
char *lockfname = "\\torture.lck";
fstring fname;
@@ -117,13 +115,13 @@ static int rw_torture(int numops)
int pid2, pid = getpid();
int i;
- fnum2 = cli_open(&cli, lockfname, O_RDWR | O_CREAT | O_EXCL,
+ fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL,
DENY_NONE);
if (fnum2 == -1)
- fnum2 = cli_open(&cli, lockfname, O_RDWR, DENY_NONE);
+ fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
if (fnum2 == -1) {
- printf("open of %s failed (%s)\n", lockfname, cli_errstr(&cli));
- return -1;
+ printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
+ return False;
}
@@ -134,46 +132,46 @@ static int rw_torture(int numops)
}
sprintf(fname,"\\torture.%u", n);
- if (!wait_lock(fnum2, n*sizeof(int), sizeof(int))) {
- return -1;
+ if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
+ return False;
}
- fnum = cli_open(&cli, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
+ fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
if (fnum == -1) {
- printf("open failed (%s)\n", cli_errstr(&cli));
+ printf("open failed (%s)\n", cli_errstr(c));
break;
}
- if (cli_write(&cli, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
- printf("write failed (%s)\n", cli_errstr(&cli));
+ if (cli_write(c, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
+ printf("write failed (%s)\n", cli_errstr(c));
}
pid2 = 0;
- if (cli_read(&cli, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
- printf("read failed (%s)\n", cli_errstr(&cli));
+ if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
+ printf("read failed (%s)\n", cli_errstr(c));
}
if (pid2 != pid) {
printf("data corruption!\n");
}
- if (!cli_close(&cli, fnum)) {
- printf("close failed (%s)\n", cli_errstr(&cli));
+ if (!cli_close(c, fnum)) {
+ printf("close failed (%s)\n", cli_errstr(c));
}
- if (!cli_unlink(&cli, fname)) {
- printf("unlink failed (%s)\n", cli_errstr(&cli));
+ if (!cli_unlink(c, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(c));
}
- if (!cli_unlock(&cli, fnum2, n*sizeof(int), sizeof(int), -1)) {
- printf("unlock failed (%s)\n", cli_errstr(&cli));
+ if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
+ printf("unlock failed (%s)\n", cli_errstr(c));
}
}
printf("%d\n", i);
- return 0;
+ return True;
}
static void usage(void)
@@ -195,15 +193,246 @@ static void usage(void)
static void run_torture(int numops)
{
- if (open_connection() == 0) {
+ static struct cli_state cli;
+
+ if (open_connection(&cli)) {
cli_sockopt(&cli, sockops);
printf("pid %d OK\n", getpid());
- rw_torture(numops);
+ rw_torture(&cli, numops);
+
+ close_connection(&cli);
+ }
+}
+
+/*
+ This test checks for two things:
+
+ 1) correct support for retaining locks over a close (ie. the server
+ must not use posix semantics)
+ 2) support for lock timeouts
+ */
+static void run_locktest1(void)
+{
+ static struct cli_state cli1, cli2;
+ char *fname = "\\locktest.lck";
+ int fnum1, fnum2, fnum3;
+ time_t t1, t2;
- close_connection();
+ if (!open_connection(&cli1) || !open_connection(&cli2)) {
+ return;
}
+ cli_sockopt(&cli1, sockops);
+ cli_sockopt(&cli2, sockops);
+
+ printf("starting locktest1\n");
+
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return;
+ }
+ fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return;
+ }
+ fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
+ if (fnum3 == -1) {
+ printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
+ return;
+ }
+
+ if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
+ printf("lock1 failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+
+ if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
+ printf("lock2 succeeded! This is a locking bug\n");
+ return;
+ } else {
+ int eclass, num;
+ cli_error(&cli2, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli2));
+ return;
+ }
+ }
+
+
+ printf("Testing lock timeouts\n");
+ t1 = time(NULL);
+ if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
+ printf("lock3 succeeded! This is a locking bug\n");
+ return;
+ } else {
+ int eclass, num;
+ cli_error(&cli2, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli2));
+ return;
+ }
+ }
+ t2 = time(NULL);
+
+ if (t2 - t1 < 5) {
+ printf("This server appears not to support timed lock requests\n");
+ }
+
+ if (!cli_close(&cli1, fnum2)) {
+ printf("close1 failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+ if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
+ printf("lock4 succeeded! This is a locking bug\n");
+ return;
+ } else {
+ int eclass, num;
+ cli_error(&cli2, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli2));
+ return;
+ }
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+ if (!cli_close(&cli2, fnum3)) {
+ printf("close3 failed (%s)\n", cli_errstr(&cli2));
+ return;
+ }
+
+ if (!cli_unlink(&cli1, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+
+ close_connection(&cli1);
+ close_connection(&cli2);
+
+ printf("Passed locktest1\n");
+}
+
+
+/*
+ This test checks that
+
+ 1) the server supports multiple locking contexts on the one SMB
+ connection, distinguished by PID.
+
+ 2) the server correctly fails overlapping locks made by the same PID (this
+ goes against POSIX behaviour, which is why it is tricky to implement)
+
+ 3) the server denies unlock requests by an incorrect client PID
+*/
+static void run_locktest2(void)
+{
+ static struct cli_state cli;
+ char *fname = "\\locktest.lck";
+ int fnum1, fnum2, fnum3;
+
+ if (!open_connection(&cli)) {
+ return;
+ }
+
+ cli_sockopt(&cli, sockops);
+
+ printf("starting locktest2\n");
+
+ cli_unlink(&cli, fname);
+
+ cli_setpid(&cli, 1);
+
+ fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return;
+ }
+
+ fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return;
+ }
+
+ cli_setpid(&cli, 2);
+
+ fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+ if (fnum3 == -1) {
+ printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return;
+ }
+
+ cli_setpid(&cli, 1);
+
+ if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
+ printf("lock1 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ if (cli_lock(&cli, fnum2, 0, 4, 0)) {
+ printf("lock2 succeeded! This is a locking bug\n");
+ } else {
+ int eclass, num;
+ cli_error(&cli, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli));
+ return;
+ }
+ }
+
+ cli_setpid(&cli, 2);
+
+ if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
+ printf("unlock1 succeeded! This is a locking bug\n");
+ }
+
+ if (cli_lock(&cli, fnum3, 0, 4, 0)) {
+ printf("lock3 succeeded! This is a locking bug\n");
+ } else {
+ int eclass, num;
+ cli_error(&cli, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli));
+ return;
+ }
+ }
+
+ cli_setpid(&cli, 1);
+
+ if (!cli_close(&cli, fnum1)) {
+ printf("close1 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ if (!cli_close(&cli, fnum2)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ if (!cli_close(&cli, fnum3)) {
+ printf("close3 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ close_connection(&cli);
+
+ printf("locktest2 finished\n");
}
@@ -317,6 +546,9 @@ static void create_procs(int nprocs, int numops)
create_procs(nprocs, numops);
printf("rw_torture: %g secs\n", end_timer());
+ run_locktest1();
+ run_locktest2();
+
return(0);
}