2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1997-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 static fstring host, workgroup, share, password, username, myname;
27 static int max_protocol = PROTOCOL_NT1;
28 static char *sockops="";
31 static struct timeval tp1,tp2;
33 static void start_timer(void)
35 gettimeofday(&tp1,NULL);
38 static double end_timer(void)
40 gettimeofday(&tp2,NULL);
41 return((tp2.tv_sec - tp1.tv_sec) +
42 (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
46 static BOOL open_connection(struct cli_state *c)
48 struct nmb_name called, calling;
50 if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
51 printf("Failed to connect with %s\n", host);
55 make_nmb_name(&calling, myname, 0x0, "");
56 make_nmb_name(&called , host, 0x20, "");
58 if (!cli_session_request(c, &calling, &called)) {
59 printf("%s rejected the session\n",host);
64 c->protocol = max_protocol;
66 if (!cli_negprot(c)) {
67 printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
72 if (!cli_session_setup(c, username, password, strlen(password),
74 printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
79 if (!cli_send_tconX(c, share,
80 strstr(share,"IPC$")?"IPC":"A:",
81 password, strlen(password)+1)) {
82 printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
92 static void close_connection(struct cli_state *c)
95 printf("tdis failed (%s)\n", cli_errstr(c));
102 /* check if the server produced the expected error code */
103 static BOOL check_error(struct cli_state *c,
104 uint8 eclass, uint32 ecode, uint32 nterr)
109 eno = cli_error(c, &class, &num);
110 if ((eclass != class || ecode != num) &&
111 num != (nterr&0xFFFFFF)) {
112 printf("unexpected error code class=%d code=%d\n",
113 (int)class, (int)num);
114 printf(" expected %d/%d %d\n",
115 (int)eclass, (int)ecode, (int)nterr);
122 static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
124 while (!cli_lock(c, fnum, offset, len, -1)) {
125 if (!check_error(c, ERRDOS, ERRlock, 0)) return False;
131 static BOOL rw_torture(struct cli_state *c, int numops)
133 char *lockfname = "\\torture.lck";
137 int pid2, pid = getpid();
141 fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL,
144 fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
146 printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
151 for (i=0;i<numops;i++) {
152 unsigned n = (unsigned)sys_random()%10;
154 printf("%d\r", i); fflush(stdout);
156 slprintf(fname, sizeof(fstring) - 1, "\\torture.%u", n);
158 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
162 fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
164 printf("open failed (%s)\n", cli_errstr(c));
168 if (cli_write(c, fnum, 0, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
169 printf("write failed (%s)\n", cli_errstr(c));
173 if (cli_write(c, fnum, 0, (char *)buf,
174 sizeof(pid)+(j*sizeof(buf)),
175 sizeof(buf)) != sizeof(buf)) {
176 printf("write failed (%s)\n", cli_errstr(c));
182 if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
183 printf("read failed (%s)\n", cli_errstr(c));
187 printf("data corruption!\n");
190 if (!cli_close(c, fnum)) {
191 printf("close failed (%s)\n", cli_errstr(c));
194 if (!cli_unlink(c, fname)) {
195 printf("unlink failed (%s)\n", cli_errstr(c));
198 if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
199 printf("unlock failed (%s)\n", cli_errstr(c));
204 cli_unlink(c, lockfname);
211 static void usage(void)
213 printf("Usage: smbtorture //server/share <options>\n");
215 printf("\t-U user%%pass\n");
216 printf("\t-N numprocs\n");
217 printf("\t-n my_netbios_name\n");
218 printf("\t-W workgroup\n");
219 printf("\t-o num_operations\n");
220 printf("\t-O socket_options\n");
221 printf("\t-m maximum protocol\n");
229 static void run_torture(int numops)
231 static struct cli_state cli;
233 if (open_connection(&cli)) {
234 cli_sockopt(&cli, sockops);
236 printf("pid %d OK\n", getpid());
238 rw_torture(&cli, numops);
240 close_connection(&cli);
245 This test checks for two things:
247 1) correct support for retaining locks over a close (ie. the server
248 must not use posix semantics)
249 2) support for lock timeouts
251 static void run_locktest1(void)
253 static struct cli_state cli1, cli2;
254 char *fname = "\\lockt1.lck";
255 int fnum1, fnum2, fnum3;
258 if (!open_connection(&cli1) || !open_connection(&cli2)) {
261 cli_sockopt(&cli1, sockops);
262 cli_sockopt(&cli2, sockops);
264 printf("starting locktest1\n");
266 cli_unlink(&cli1, fname);
268 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
270 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
273 fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
275 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
278 fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
280 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
284 if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
285 printf("lock1 failed (%s)\n", cli_errstr(&cli1));
290 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
291 printf("lock2 succeeded! This is a locking bug\n");
294 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
298 printf("Testing lock timeouts\n");
300 if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
301 printf("lock3 succeeded! This is a locking bug\n");
304 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
309 printf("error: This server appears not to support timed lock requests\n");
312 if (!cli_close(&cli1, fnum2)) {
313 printf("close1 failed (%s)\n", cli_errstr(&cli1));
317 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
318 printf("lock4 succeeded! This is a locking bug\n");
321 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
324 if (!cli_close(&cli1, fnum1)) {
325 printf("close2 failed (%s)\n", cli_errstr(&cli1));
329 if (!cli_close(&cli2, fnum3)) {
330 printf("close3 failed (%s)\n", cli_errstr(&cli2));
334 if (!cli_unlink(&cli1, fname)) {
335 printf("unlink failed (%s)\n", cli_errstr(&cli1));
340 close_connection(&cli1);
341 close_connection(&cli2);
343 printf("Passed locktest1\n");
348 This test checks that
350 1) the server supports multiple locking contexts on the one SMB
351 connection, distinguished by PID.
353 2) the server correctly fails overlapping locks made by the same PID (this
354 goes against POSIX behaviour, which is why it is tricky to implement)
356 3) the server denies unlock requests by an incorrect client PID
358 static void run_locktest2(void)
360 static struct cli_state cli;
361 char *fname = "\\lockt2.lck";
362 int fnum1, fnum2, fnum3;
364 if (!open_connection(&cli)) {
368 cli_sockopt(&cli, sockops);
370 printf("starting locktest2\n");
372 cli_unlink(&cli, fname);
376 fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
378 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
382 fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
384 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
390 fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
392 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
398 if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
399 printf("lock1 failed (%s)\n", cli_errstr(&cli));
403 if (cli_lock(&cli, fnum2, 0, 4, 0)) {
404 printf("lock2 succeeded! This is a locking bug\n");
406 if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
411 if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
412 printf("unlock1 succeeded! This is a locking bug\n");
415 if (cli_lock(&cli, fnum3, 0, 4, 0)) {
416 printf("lock3 succeeded! This is a locking bug\n");
418 if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
423 if (!cli_close(&cli, fnum1)) {
424 printf("close1 failed (%s)\n", cli_errstr(&cli));
428 if (!cli_close(&cli, fnum2)) {
429 printf("close2 failed (%s)\n", cli_errstr(&cli));
433 if (!cli_close(&cli, fnum3)) {
434 printf("close3 failed (%s)\n", cli_errstr(&cli));
438 close_connection(&cli);
440 printf("locktest2 finished\n");
445 This test checks that
447 1) the server supports the full offset range in lock requests
449 static void run_locktest3(int numops)
451 static struct cli_state cli1, cli2;
452 char *fname = "\\lockt3.lck";
456 #define NEXT_OFFSET offset += (~(uint32)0) / numops
458 if (!open_connection(&cli1) || !open_connection(&cli2)) {
461 cli_sockopt(&cli1, sockops);
462 cli_sockopt(&cli2, sockops);
464 printf("starting locktest3\n");
466 cli_unlink(&cli1, fname);
468 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
470 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
473 fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
475 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
479 for (offset=i=0;i<numops;i++) {
481 if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
482 printf("lock1 %d failed (%s)\n",
488 if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
489 printf("lock2 %d failed (%s)\n",
496 for (offset=i=0;i<numops;i++) {
499 if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
500 printf("error: lock1 %d succeeded!\n", i);
504 if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
505 printf("error: lock2 %d succeeded!\n", i);
509 if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
510 printf("error: lock3 %d succeeded!\n", i);
514 if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
515 printf("error: lock4 %d succeeded!\n", i);
520 for (offset=i=0;i<numops;i++) {
523 if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
524 printf("unlock1 %d failed (%s)\n",
530 if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
531 printf("unlock2 %d failed (%s)\n",
538 if (!cli_close(&cli1, fnum1)) {
539 printf("close1 failed (%s)\n", cli_errstr(&cli1));
542 if (!cli_close(&cli2, fnum2)) {
543 printf("close2 failed (%s)\n", cli_errstr(&cli2));
546 if (!cli_unlink(&cli1, fname)) {
547 printf("unlink failed (%s)\n", cli_errstr(&cli1));
551 close_connection(&cli1);
552 close_connection(&cli2);
554 printf("finished locktest3\n");
559 This test checks that
561 1) the server does not allow an unlink on a file that is open
563 static void run_unlinktest(void)
565 static struct cli_state cli;
566 char *fname = "\\unlink.tst";
569 if (!open_connection(&cli)) {
573 cli_sockopt(&cli, sockops);
575 printf("starting unlink test\n");
577 cli_unlink(&cli, fname);
581 fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
583 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
587 if (cli_unlink(&cli, fname)) {
588 printf("error: server allowed unlink on an open file\n");
591 cli_close(&cli, fnum);
592 cli_unlink(&cli, fname);
594 close_connection(&cli);
596 printf("unlink test finished\n");
601 test how many open files this server supports on the one socket
603 static void run_maxfidtest(int n)
605 static struct cli_state cli;
606 char *template = "\\maxfid.%d.%d";
613 while (!open_connection(&cli) && retries--) msleep(random() % 2000);
616 printf("failed to connect\n");
620 cli_sockopt(&cli, sockops);
622 printf("starting maxfid test\n");
626 slprintf(fname,sizeof(fname)-1,template, fnum,getpid());
627 if (cli_open(&cli, fname,
628 O_RDWR|O_CREAT|O_TRUNC, DENY_NONE) ==
630 printf("open of %s failed (%s)\n",
631 fname, cli_errstr(&cli));
632 printf("maximum fnum is %d\n", fnum);
638 printf("cleaning up\n");
641 slprintf(fname,sizeof(fname)-1,template, fnum,getpid());
642 if (cli_unlink(&cli, fname)) {
643 printf("unlink of %s failed (%s)\n",
644 fname, cli_errstr(&cli));
648 printf("maxfid test finished\n");
649 close_connection(&cli);
652 /* generate a random buffer */
653 static void rand_buf(char *buf, int len)
661 /* send random IPC commands */
662 static void run_randomipc(void)
668 int api, param_len, i;
669 static struct cli_state cli;
671 printf("starting random ipc test\n");
673 if (!open_connection(&cli)) {
677 for (i=0;i<50000;i++) {
678 api = sys_random() % 500;
679 param_len = (sys_random() % 64);
681 rand_buf(param, param_len);
687 NULL, 0, BUFFER_SIZE,
692 close_connection(&cli);
694 printf("finished random ipc test\n");
699 static void browse_callback(const char *sname, uint32 stype,
702 printf("\t%20.20s %08x %s\n", sname, stype, comment);
708 This test checks the browse list code
711 static void run_browsetest(void)
713 static struct cli_state cli;
715 printf("starting browse test\n");
717 if (!open_connection(&cli)) {
721 printf("domain list:\n");
722 cli_NetServerEnum(&cli, workgroup,
726 printf("machine list:\n");
727 cli_NetServerEnum(&cli, workgroup,
731 close_connection(&cli);
733 printf("browse test finished\n");
738 This checks how the getatr calls works
740 static void run_attrtest(void)
742 static struct cli_state cli;
745 char *fname = "\\attrib.tst";
747 printf("starting attrib test\n");
749 if (!open_connection(&cli)) {
753 cli_unlink(&cli, fname);
754 fnum = cli_open(&cli, fname,
755 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
756 cli_close(&cli, fnum);
757 if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
758 printf("getatr failed (%s)\n", cli_errstr(&cli));
761 if (abs(t - time(NULL)) > 2) {
762 printf("ERROR: SMBgetatr bug. time is %s",
767 t2 = t-60*60*24; /* 1 day ago */
769 if (!cli_setatr(&cli, fname, 0, t2)) {
770 printf("setatr failed (%s)\n", cli_errstr(&cli));
773 if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
774 printf("getatr failed (%s)\n", cli_errstr(&cli));
778 printf("ERROR: getatr/setatr bug. times are\n%s",
780 printf("%s", ctime(&t2));
783 cli_unlink(&cli, fname);
785 close_connection(&cli);
787 printf("attrib test finished\n");
792 This checks a couple of trans2 calls
794 static void run_trans2test(void)
796 static struct cli_state cli;
799 time_t c_time, a_time, m_time, w_time, m_time2;
800 char *fname = "\\trans2.tst";
801 char *dname = "\\trans2";
802 char *fname2 = "\\trans2\\trans2.tst";
804 printf("starting trans2 test\n");
806 if (!open_connection(&cli)) {
810 cli_unlink(&cli, fname);
811 fnum = cli_open(&cli, fname,
812 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
813 if (!cli_qfileinfo(&cli, fnum, NULL, &size, &c_time, &a_time, &m_time)) {
814 printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli));
816 cli_close(&cli, fnum);
820 cli_unlink(&cli, fname);
821 fnum = cli_open(&cli, fname,
822 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
823 cli_close(&cli, fnum);
825 if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size, NULL)) {
826 printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli));
828 if (c_time != m_time) {
829 printf("create time=%s", ctime(&c_time));
830 printf("modify time=%s", ctime(&m_time));
831 printf("This system appears to have sticky create times\n");
833 if (a_time % (60*60) == 0) {
834 printf("access time=%s", ctime(&a_time));
835 printf("This system appears to set a midnight access time\n");
838 if (abs(m_time - time(NULL)) > 60*60*24*7) {
839 printf("ERROR: totally incorrect times - maybe word reversed?\n");
844 cli_unlink(&cli, fname);
845 fnum = cli_open(&cli, fname,
846 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
847 cli_close(&cli, fnum);
848 if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time,
849 &w_time, &size, NULL)) {
850 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
852 if (w_time < 60*60*24*2) {
853 printf("write time=%s", ctime(&w_time));
854 printf("This system appears to set a initial 0 write time\n");
858 cli_unlink(&cli, fname);
861 /* check if the server updates the directory modification time
862 when creating a new file */
863 if (!cli_mkdir(&cli, dname)) {
864 printf("ERROR: mkdir failed (%s)\n", cli_errstr(&cli));
867 if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time,
868 &w_time, &size, NULL)) {
869 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
872 fnum = cli_open(&cli, fname2,
873 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
874 cli_write(&cli, fnum, 0, (char *)&fnum, 0, sizeof(fnum));
875 cli_close(&cli, fnum);
876 if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2,
877 &w_time, &size, NULL)) {
878 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
880 if (m_time2 == m_time)
881 printf("This system does not update directory modification times\n");
883 cli_unlink(&cli, fname2);
884 cli_rmdir(&cli, dname);
887 close_connection(&cli);
889 printf("trans2 test finished\n");
893 static void create_procs(int nprocs, int numops, void (*fn)(int ))
897 for (i=0;i<nprocs;i++) {
899 int mypid = getpid();
900 sys_srandom(mypid ^ time(NULL));
906 for (i=0;i<nprocs;i++)
907 waitpid(0, &status, 0);
912 /****************************************************************************
914 ****************************************************************************/
915 int main(int argc,char *argv[])
917 int nprocs=1, numops=100;
927 charset_initialise();
933 for(p = argv[1]; *p; p++)
937 if (strncmp(argv[1], "//", 2)) {
941 fstrcpy(host, &argv[1][2]);
942 p = strchr(&host[2],'/');
949 get_myname(myname,NULL);
951 if (*username == 0 && getenv("LOGNAME")) {
952 pstrcpy(username,getenv("LOGNAME"));
959 while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != EOF) {
962 fstrcpy(workgroup,optarg);
965 max_protocol = interpret_protocol(optarg, max_protocol);
968 nprocs = atoi(optarg);
971 numops = atoi(optarg);
977 fstrcpy(myname, optarg);
980 pstrcpy(username,optarg);
981 p = strchr(username,'%');
984 pstrcpy(password, p+1);
989 printf("Unknown option %c (%d)\n", (char)opt, opt);
996 p = getpass("Password:");
998 pstrcpy(password, p);
1003 printf("host=%s share=%s user=%s myname=%s\n",
1004 host, share, username, myname);
1008 run_locktest3(numops);
1014 create_procs(nprocs, numops, run_maxfidtest);
1017 create_procs(nprocs, numops, run_torture);
1018 printf("rw_torture: %g secs\n", end_timer());