r16333: Move more code out of the core smbtorture. It now no longer
[kai/samba-autobuild/.git] / source4 / torture / misc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB torture tester
4    Copyright (C) Andrew Tridgell 1997-2003
5    Copyright (C) Jelmer Vernooij 2006
6    
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.
11    
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.
16    
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.
20 */
21
22 #include "includes.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "system/time.h"
25 #include "system/wait.h"
26 #include "system/filesys.h"
27 #include "libcli/raw/ioctl.h"
28 #include "libcli/libcli.h"
29 #include "lib/events/events.h"
30 #include "libcli/resolve/resolve.h"
31 #include "auth/credentials/credentials.h"
32 #include "librpc/gen_ndr/ndr_nbt.h"
33 #include "torture/torture.h"
34 #include "torture/util.h"
35
36 static BOOL wait_lock(struct smbcli_state *c, int fnum, uint32_t offset, uint32_t len)
37 {
38         while (NT_STATUS_IS_ERR(smbcli_lock(c->tree, fnum, offset, len, -1, WRITE_LOCK))) {
39                 if (!check_error(__location__, c, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return False;
40         }
41         return True;
42 }
43
44
45 static BOOL rw_torture(struct smbcli_state *c)
46 {
47         const char *lockfname = "\\torture.lck";
48         char *fname;
49         int fnum;
50         int fnum2;
51         pid_t pid2, pid = getpid();
52         int i, j;
53         uint8_t buf[1024];
54         BOOL correct = True;
55
56         fnum2 = smbcli_open(c->tree, lockfname, O_RDWR | O_CREAT | O_EXCL, 
57                          DENY_NONE);
58         if (fnum2 == -1)
59                 fnum2 = smbcli_open(c->tree, lockfname, O_RDWR, DENY_NONE);
60         if (fnum2 == -1) {
61                 printf("open of %s failed (%s)\n", lockfname, smbcli_errstr(c->tree));
62                 return False;
63         }
64
65
66         for (i=0;i<torture_numops;i++) {
67                 uint_t n = (uint_t)random()%10;
68                 if (i % 10 == 0) {
69                         printf("%d\r", i); fflush(stdout);
70                 }
71                 asprintf(&fname, "\\torture.%u", n);
72
73                 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
74                         return False;
75                 }
76
77                 fnum = smbcli_open(c->tree, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
78                 if (fnum == -1) {
79                         printf("open failed (%s)\n", smbcli_errstr(c->tree));
80                         correct = False;
81                         break;
82                 }
83
84                 if (smbcli_write(c->tree, fnum, 0, &pid, 0, sizeof(pid)) != sizeof(pid)) {
85                         printf("write failed (%s)\n", smbcli_errstr(c->tree));
86                         correct = False;
87                 }
88
89                 for (j=0;j<50;j++) {
90                         if (smbcli_write(c->tree, fnum, 0, buf, 
91                                       sizeof(pid)+(j*sizeof(buf)), 
92                                       sizeof(buf)) != sizeof(buf)) {
93                                 printf("write failed (%s)\n", smbcli_errstr(c->tree));
94                                 correct = False;
95                         }
96                 }
97
98                 pid2 = 0;
99
100                 if (smbcli_read(c->tree, fnum, &pid2, 0, sizeof(pid)) != sizeof(pid)) {
101                         printf("read failed (%s)\n", smbcli_errstr(c->tree));
102                         correct = False;
103                 }
104
105                 if (pid2 != pid) {
106                         printf("data corruption!\n");
107                         correct = False;
108                 }
109
110                 if (NT_STATUS_IS_ERR(smbcli_close(c->tree, fnum))) {
111                         printf("close failed (%s)\n", smbcli_errstr(c->tree));
112                         correct = False;
113                 }
114
115                 if (NT_STATUS_IS_ERR(smbcli_unlink(c->tree, fname))) {
116                         printf("unlink failed (%s)\n", smbcli_errstr(c->tree));
117                         correct = False;
118                 }
119
120                 if (NT_STATUS_IS_ERR(smbcli_unlock(c->tree, fnum2, n*sizeof(int), sizeof(int)))) {
121                         printf("unlock failed (%s)\n", smbcli_errstr(c->tree));
122                         correct = False;
123                 }
124                 free(fname);
125         }
126
127         smbcli_close(c->tree, fnum2);
128         smbcli_unlink(c->tree, lockfname);
129
130         printf("%d\n", i);
131
132         return correct;
133 }
134
135 static BOOL run_torture(struct smbcli_state *cli, int dummy)
136 {
137     BOOL ret;
138
139         ret = rw_torture(cli);
140         
141         if (!torture_close_connection(cli)) {
142                 ret = False;
143         }
144
145         return ret;
146 }
147
148
149 /*
150   see how many RPC pipes we can open at once
151 */
152 static BOOL run_pipe_number(struct torture_context *torture)
153 {
154         struct smbcli_state *cli1;
155         const char *pipe_name = "\\WKSSVC";
156         int fnum;
157         int num_pipes = 0;
158
159         printf("starting pipenumber test\n");
160         if (!torture_open_connection(&cli1)) {
161                 return False;
162         }
163
164         while(1) {
165                 fnum = smbcli_nt_create_full(cli1->tree, pipe_name, 0, SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
166                                    NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OPEN_IF, 0, 0);
167
168                 if (fnum == -1) {
169                         printf("Open of pipe %s failed with error (%s)\n", pipe_name, smbcli_errstr(cli1->tree));
170                         break;
171                 }
172                 num_pipes++;
173                 printf("%d\r", num_pipes);
174                 fflush(stdout);
175         }
176
177         printf("pipe_number test - we can open %d %s pipes.\n", num_pipes, pipe_name );
178         torture_close_connection(cli1);
179         return True;
180 }
181
182
183
184
185 /*
186   open N connections to the server and just hold them open
187   used for testing performance when there are N idle users
188   already connected
189  */
190  static BOOL torture_holdcon(struct torture_context *torture)
191 {
192         int i;
193         struct smbcli_state **cli;
194         int num_dead = 0;
195
196         printf("Opening %d connections\n", torture_numops);
197         
198         cli = malloc_array_p(struct smbcli_state *, torture_numops);
199
200         for (i=0;i<torture_numops;i++) {
201                 if (!torture_open_connection(&cli[i])) {
202                         return False;
203                 }
204                 printf("opened %d connections\r", i);
205                 fflush(stdout);
206         }
207
208         printf("\nStarting pings\n");
209
210         while (1) {
211                 for (i=0;i<torture_numops;i++) {
212                         NTSTATUS status;
213                         if (cli[i]) {
214                                 status = smbcli_chkpath(cli[i]->tree, "\\");
215                                 if (!NT_STATUS_IS_OK(status)) {
216                                         printf("Connection %d is dead\n", i);
217                                         cli[i] = NULL;
218                                         num_dead++;
219                                 }
220                                 usleep(100);
221                         }
222                 }
223
224                 if (num_dead == torture_numops) {
225                         printf("All connections dead - finishing\n");
226                         break;
227                 }
228
229                 printf(".");
230                 fflush(stdout);
231         }
232
233         return True;
234 }
235
236 /*
237 test how many open files this server supports on the one socket
238 */
239 static BOOL run_maxfidtest(struct smbcli_state *cli, int dummy)
240 {
241 #define MAXFID_TEMPLATE "\\maxfid\\fid%d\\maxfid.%d.%d"
242         char *fname;
243         int fnums[0x11000], i;
244         int retries=4, maxfid;
245         BOOL correct = True;
246
247         if (retries <= 0) {
248                 printf("failed to connect\n");
249                 return False;
250         }
251
252         if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
253                 printf("Failed to deltree \\maxfid - %s\n",
254                        smbcli_errstr(cli->tree));
255                 return False;
256         }
257         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\maxfid"))) {
258                 printf("Failed to mkdir \\maxfid, error=%s\n", 
259                        smbcli_errstr(cli->tree));
260                 return False;
261         }
262
263         printf("Testing maximum number of open files\n");
264
265         for (i=0; i<0x11000; i++) {
266                 if (i % 1000 == 0) {
267                         asprintf(&fname, "\\maxfid\\fid%d", i/1000);
268                         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, fname))) {
269                                 printf("Failed to mkdir %s, error=%s\n", 
270                                        fname, smbcli_errstr(cli->tree));
271                                 return False;
272                         }
273                         free(fname);
274                 }
275                 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
276                 if ((fnums[i] = smbcli_open(cli->tree, fname, 
277                                         O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
278                     -1) {
279                         printf("open of %s failed (%s)\n", 
280                                fname, smbcli_errstr(cli->tree));
281                         printf("maximum fnum is %d\n", i);
282                         break;
283                 }
284                 free(fname);
285                 printf("%6d\r", i);
286         }
287         printf("%6d\n", i);
288         i--;
289
290         maxfid = i;
291
292         printf("cleaning up\n");
293         for (i=0;i<maxfid/2;i++) {
294                 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
295                 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[i]))) {
296                         printf("Close of fnum %d failed - %s\n", fnums[i], smbcli_errstr(cli->tree));
297                 }
298                 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
299                         printf("unlink of %s failed (%s)\n", 
300                                fname, smbcli_errstr(cli->tree));
301                         correct = False;
302                 }
303                 free(fname);
304
305                 asprintf(&fname, MAXFID_TEMPLATE, (maxfid-i)/1000, maxfid-i,(int)getpid());
306                 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[maxfid-i]))) {
307                         printf("Close of fnum %d failed - %s\n", fnums[maxfid-i], smbcli_errstr(cli->tree));
308                 }
309                 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
310                         printf("unlink of %s failed (%s)\n", 
311                                fname, smbcli_errstr(cli->tree));
312                         correct = False;
313                 }
314                 free(fname);
315
316                 printf("%6d %6d\r", i, maxfid-i);
317         }
318         printf("%6d\n", 0);
319
320         if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
321                 printf("Failed to deltree \\maxfid - %s\n",
322                        smbcli_errstr(cli->tree));
323                 return False;
324         }
325
326         printf("maxfid test finished\n");
327         if (!torture_close_connection(cli)) {
328                 correct = False;
329         }
330         return correct;
331 #undef MAXFID_TEMPLATE
332 }
333
334
335
336 /*
337   sees what IOCTLs are supported
338  */
339 static BOOL torture_ioctl_test(struct torture_context *torture)
340 {
341         struct smbcli_state *cli;
342         uint16_t device, function;
343         int fnum;
344         const char *fname = "\\ioctl.dat";
345         NTSTATUS status;
346         union smb_ioctl parms;
347         TALLOC_CTX *mem_ctx;
348
349         if (!torture_open_connection(&cli)) {
350                 return False;
351         }
352
353         mem_ctx = talloc_init("ioctl_test");
354
355         printf("starting ioctl test\n");
356
357         smbcli_unlink(cli->tree, fname);
358
359         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
360         if (fnum == -1) {
361                 printf("open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
362                 return False;
363         }
364
365         parms.ioctl.level = RAW_IOCTL_IOCTL;
366         parms.ioctl.in.file.fnum = fnum;
367         parms.ioctl.in.request = IOCTL_QUERY_JOB_INFO;
368         status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
369         printf("ioctl job info: %s\n", smbcli_errstr(cli->tree));
370
371         for (device=0;device<0x100;device++) {
372                 printf("testing device=0x%x\n", device);
373                 for (function=0;function<0x100;function++) {
374                         parms.ioctl.in.request = (device << 16) | function;
375                         status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
376
377                         if (NT_STATUS_IS_OK(status)) {
378                                 printf("ioctl device=0x%x function=0x%x OK : %d bytes\n", 
379                                         device, function, (int)parms.ioctl.out.blob.length);
380                         }
381                 }
382         }
383
384         if (!torture_close_connection(cli)) {
385                 return False;
386         }
387
388         return True;
389 }
390
391
392 NTSTATUS torture_misc_init(void)
393 {
394         register_torture_op("BENCH-HOLDCON", torture_holdcon);
395         register_torture_op("SCAN-PIPE_NUMBER", run_pipe_number);
396         register_torture_op("SCAN-IOCTL", torture_ioctl_test);
397         register_torture_multi_op("BENCH-TORTURE", run_torture);
398         register_torture_multi_op("SCAN-MAXFID", run_maxfidtest);
399
400         return NT_STATUS_OK;
401 }