8f6fa66ca4a1f7f6faf0e45c308a624f473ad531
[sfrench/samba-autobuild/.git] / source4 / torture / basic / 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 #include "libcli/smb_composite/smb_composite.h"
36 #include "libcli/composite/composite.h"
37
38 extern struct cli_credentials *cmdline_credentials;
39         
40 static BOOL wait_lock(struct smbcli_state *c, int fnum, uint32_t offset, uint32_t len)
41 {
42         while (NT_STATUS_IS_ERR(smbcli_lock(c->tree, fnum, offset, len, -1, WRITE_LOCK))) {
43                 if (!check_error(__location__, c, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return False;
44         }
45         return True;
46 }
47
48
49 static BOOL rw_torture(struct torture_context *tctx, struct smbcli_state *c)
50 {
51         const char *lockfname = "\\torture.lck";
52         char *fname;
53         int fnum;
54         int fnum2;
55         pid_t pid2, pid = getpid();
56         int i, j;
57         uint8_t buf[1024];
58         BOOL correct = True;
59
60         fnum2 = smbcli_open(c->tree, lockfname, O_RDWR | O_CREAT | O_EXCL, 
61                          DENY_NONE);
62         if (fnum2 == -1)
63                 fnum2 = smbcli_open(c->tree, lockfname, O_RDWR, DENY_NONE);
64         if (fnum2 == -1) {
65                 torture_comment(tctx, "open of %s failed (%s)\n", lockfname, smbcli_errstr(c->tree));
66                 return False;
67         }
68
69
70         for (i=0;i<torture_numops;i++) {
71                 uint_t n = (uint_t)random()%10;
72                 if (i % 10 == 0) {
73                         torture_comment(tctx, "%d\r", i); fflush(stdout);
74                 }
75                 asprintf(&fname, "\\torture.%u", n);
76
77                 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
78                         return False;
79                 }
80
81                 fnum = smbcli_open(c->tree, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
82                 if (fnum == -1) {
83                         torture_comment(tctx, "open failed (%s)\n", smbcli_errstr(c->tree));
84                         correct = False;
85                         break;
86                 }
87
88                 if (smbcli_write(c->tree, fnum, 0, &pid, 0, sizeof(pid)) != sizeof(pid)) {
89                         torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c->tree));
90                         correct = False;
91                 }
92
93                 for (j=0;j<50;j++) {
94                         if (smbcli_write(c->tree, fnum, 0, buf, 
95                                       sizeof(pid)+(j*sizeof(buf)), 
96                                       sizeof(buf)) != sizeof(buf)) {
97                                 torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c->tree));
98                                 correct = False;
99                         }
100                 }
101
102                 pid2 = 0;
103
104                 if (smbcli_read(c->tree, fnum, &pid2, 0, sizeof(pid)) != sizeof(pid)) {
105                         torture_comment(tctx, "read failed (%s)\n", smbcli_errstr(c->tree));
106                         correct = False;
107                 }
108
109                 if (pid2 != pid) {
110                         torture_comment(tctx, "data corruption!\n");
111                         correct = False;
112                 }
113
114                 if (NT_STATUS_IS_ERR(smbcli_close(c->tree, fnum))) {
115                         torture_comment(tctx, "close failed (%s)\n", smbcli_errstr(c->tree));
116                         correct = False;
117                 }
118
119                 if (NT_STATUS_IS_ERR(smbcli_unlink(c->tree, fname))) {
120                         torture_comment(tctx, "unlink failed (%s)\n", smbcli_errstr(c->tree));
121                         correct = False;
122                 }
123
124                 if (NT_STATUS_IS_ERR(smbcli_unlock(c->tree, fnum2, n*sizeof(int), sizeof(int)))) {
125                         torture_comment(tctx, "unlock failed (%s)\n", smbcli_errstr(c->tree));
126                         correct = False;
127                 }
128                 free(fname);
129         }
130
131         smbcli_close(c->tree, fnum2);
132         smbcli_unlink(c->tree, lockfname);
133
134         torture_comment(tctx, "%d\n", i);
135
136         return correct;
137 }
138
139 BOOL run_torture(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
140 {
141         return rw_torture(tctx, cli);
142 }
143
144
145 /*
146   see how many RPC pipes we can open at once
147 */
148 BOOL run_pipe_number(struct torture_context *tctx, 
149                                          struct smbcli_state *cli1)
150 {
151         const char *pipe_name = "\\WKSSVC";
152         int fnum;
153         int num_pipes = 0;
154
155         while(1) {
156                 fnum = smbcli_nt_create_full(cli1->tree, pipe_name, 0, SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
157                                    NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OPEN_IF, 0, 0);
158
159                 if (fnum == -1) {
160                         torture_comment(tctx, "Open of pipe %s failed with error (%s)\n", pipe_name, smbcli_errstr(cli1->tree));
161                         break;
162                 }
163                 num_pipes++;
164                 torture_comment(tctx, "%d\r", num_pipes);
165                 fflush(stdout);
166         }
167
168         torture_comment(tctx, "pipe_number test - we can open %d %s pipes.\n", num_pipes, pipe_name );
169         return True;
170 }
171
172
173
174
175 /*
176   open N connections to the server and just hold them open
177   used for testing performance when there are N idle users
178   already connected
179  */
180 BOOL torture_holdcon(struct torture_context *tctx)
181 {
182         int i;
183         struct smbcli_state **cli;
184         int num_dead = 0;
185
186         torture_comment(tctx, "Opening %d connections\n", torture_numops);
187         
188         cli = malloc_array_p(struct smbcli_state *, torture_numops);
189
190         for (i=0;i<torture_numops;i++) {
191                 if (!torture_open_connection(&cli[i], i)) {
192                         return False;
193                 }
194                 torture_comment(tctx, "opened %d connections\r", i);
195                 fflush(stdout);
196         }
197
198         torture_comment(tctx, "\nStarting pings\n");
199
200         while (1) {
201                 for (i=0;i<torture_numops;i++) {
202                         NTSTATUS status;
203                         if (cli[i]) {
204                                 status = smbcli_chkpath(cli[i]->tree, "\\");
205                                 if (!NT_STATUS_IS_OK(status)) {
206                                         torture_comment(tctx, "Connection %d is dead\n", i);
207                                         cli[i] = NULL;
208                                         num_dead++;
209                                 }
210                                 usleep(100);
211                         }
212                 }
213
214                 if (num_dead == torture_numops) {
215                         torture_comment(tctx, "All connections dead - finishing\n");
216                         break;
217                 }
218
219                 torture_comment(tctx, ".");
220                 fflush(stdout);
221         }
222
223         return True;
224 }
225
226 /*
227 test how many open files this server supports on the one socket
228 */
229 BOOL run_maxfidtest(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
230 {
231 #define MAXFID_TEMPLATE "\\maxfid\\fid%d\\maxfid.%d.%d"
232         char *fname;
233         int fnums[0x11000], i;
234         int retries=4, maxfid;
235         BOOL correct = True;
236
237         if (retries <= 0) {
238                 torture_comment(tctx, "failed to connect\n");
239                 return False;
240         }
241
242         if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
243                 torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
244                        smbcli_errstr(cli->tree));
245                 return False;
246         }
247         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\maxfid"))) {
248                 torture_comment(tctx, "Failed to mkdir \\maxfid, error=%s\n", 
249                        smbcli_errstr(cli->tree));
250                 return False;
251         }
252
253         torture_comment(tctx, "Testing maximum number of open files\n");
254
255         for (i=0; i<0x11000; i++) {
256                 if (i % 1000 == 0) {
257                         asprintf(&fname, "\\maxfid\\fid%d", i/1000);
258                         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, fname))) {
259                                 torture_comment(tctx, "Failed to mkdir %s, error=%s\n", 
260                                        fname, smbcli_errstr(cli->tree));
261                                 return False;
262                         }
263                         free(fname);
264                 }
265                 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
266                 if ((fnums[i] = smbcli_open(cli->tree, fname, 
267                                         O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
268                     -1) {
269                         torture_comment(tctx, "open of %s failed (%s)\n", 
270                                fname, smbcli_errstr(cli->tree));
271                         torture_comment(tctx, "maximum fnum is %d\n", i);
272                         break;
273                 }
274                 free(fname);
275                 torture_comment(tctx, "%6d\r", i);
276         }
277         torture_comment(tctx, "%6d\n", i);
278         i--;
279
280         maxfid = i;
281
282         torture_comment(tctx, "cleaning up\n");
283         for (i=0;i<maxfid/2;i++) {
284                 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
285                 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[i]))) {
286                         torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[i], smbcli_errstr(cli->tree));
287                 }
288                 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
289                         torture_comment(tctx, "unlink of %s failed (%s)\n", 
290                                fname, smbcli_errstr(cli->tree));
291                         correct = False;
292                 }
293                 free(fname);
294
295                 asprintf(&fname, MAXFID_TEMPLATE, (maxfid-i)/1000, maxfid-i,(int)getpid());
296                 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[maxfid-i]))) {
297                         torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[maxfid-i], smbcli_errstr(cli->tree));
298                 }
299                 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
300                         torture_comment(tctx, "unlink of %s failed (%s)\n", 
301                                fname, smbcli_errstr(cli->tree));
302                         correct = False;
303                 }
304                 free(fname);
305
306                 torture_comment(tctx, "%6d %6d\r", i, maxfid-i);
307         }
308         torture_comment(tctx, "%6d\n", 0);
309
310         if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
311                 torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
312                        smbcli_errstr(cli->tree));
313                 return False;
314         }
315
316         torture_comment(tctx, "maxfid test finished\n");
317         if (!torture_close_connection(cli)) {
318                 correct = False;
319         }
320         return correct;
321 #undef MAXFID_TEMPLATE
322 }
323
324
325
326 /*
327   sees what IOCTLs are supported
328  */
329 BOOL torture_ioctl_test(struct torture_context *tctx, 
330                                                 struct smbcli_state *cli)
331 {
332         uint16_t device, function;
333         int fnum;
334         const char *fname = "\\ioctl.dat";
335         NTSTATUS status;
336         union smb_ioctl parms;
337         TALLOC_CTX *mem_ctx;
338
339         mem_ctx = talloc_named_const(tctx, 0, "ioctl_test");
340
341         smbcli_unlink(cli->tree, fname);
342
343         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
344         if (fnum == -1) {
345                 torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
346                 return False;
347         }
348
349         parms.ioctl.level = RAW_IOCTL_IOCTL;
350         parms.ioctl.in.file.fnum = fnum;
351         parms.ioctl.in.request = IOCTL_QUERY_JOB_INFO;
352         status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
353         torture_comment(tctx, "ioctl job info: %s\n", smbcli_errstr(cli->tree));
354
355         for (device=0;device<0x100;device++) {
356                 torture_comment(tctx, "testing device=0x%x\n", device);
357                 for (function=0;function<0x100;function++) {
358                         parms.ioctl.in.request = (device << 16) | function;
359                         status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
360
361                         if (NT_STATUS_IS_OK(status)) {
362                                 torture_comment(tctx, "ioctl device=0x%x function=0x%x OK : %d bytes\n", 
363                                         device, function, (int)parms.ioctl.out.blob.length);
364                         }
365                 }
366         }
367
368         return True;
369 }
370
371 static void benchrw_callback(struct smbcli_request *req);
372 enum benchrw_stage {
373         START,
374         OPEN_CONNECTION,
375         CLEANUP_TESTDIR,
376         MK_TESTDIR,
377         OPEN_FILE,
378         INITIAL_WRITE,
379         READ_WRITE_DATA,
380         MAX_OPS_REACHED,
381         ERROR,
382         CLOSE_FILE,
383         CLEANUP,
384         FINISHED
385 };
386
387 struct benchrw_state {
388         struct torture_context *tctx;
389         char *dname;
390         char *fname;
391         uint16_t fnum;
392         int nr;
393         struct smbcli_tree      *cli;           
394         uint8_t *buffer;
395         int writecnt;
396         int readcnt;
397         int completed;
398         void *req_params;
399         enum benchrw_stage mode;
400         struct params{
401                 struct unclist{
402                         const char *host;
403                         const char *share;
404                 } **unc;
405                 const char *workgroup;
406                 int retry;
407                 unsigned int writeblocks;
408                 unsigned int blocksize;
409                 unsigned int writeratio;
410         } *lp_params;
411 };
412
413 /* 
414         init params using lp_parm_xxx 
415         return number of unclist entries
416 */
417 static int init_benchrw_params(struct torture_context *tctx,
418                                struct params *lpar)
419 {
420         char **unc_list = NULL;
421         int num_unc_names = 0, conn_index=0, empty_lines=0;
422         const char *p;
423         lpar->retry = torture_setting_int(tctx, "retry",3);
424         lpar->blocksize = torture_setting_int(tctx, "blocksize",65535);
425         lpar->writeblocks = torture_setting_int(tctx, "writeblocks",15);
426         lpar->writeratio = torture_setting_int(tctx, "writeratio",5);
427         lpar->workgroup = lp_workgroup();
428         
429         p = torture_setting_string(tctx, "unclist", NULL);
430         if (p) {
431                 char *h, *s;
432                 unc_list = file_lines_load(p, &num_unc_names, NULL);
433                 if (!unc_list || num_unc_names <= 0) {
434                         torture_comment(tctx, "Failed to load unc names list "
435                                         "from '%s'\n", p);
436                         exit(1);
437                 }
438                 
439                 lpar->unc = talloc_array(tctx, struct unclist *,
440                                          (num_unc_names-empty_lines));
441                 for(conn_index = 0; conn_index < num_unc_names; conn_index++) {
442                         /* ignore empty lines */
443                         if(strlen(unc_list[conn_index % num_unc_names])==0){
444                                 empty_lines++;
445                                 continue;
446                         }
447                         if (!smbcli_parse_unc(
448                                     unc_list[conn_index % num_unc_names],
449                                     NULL, &h, &s)) {
450                                 torture_comment(
451                                         tctx, "Failed to parse UNC "
452                                         "name %s\n",
453                                         unc_list[conn_index % num_unc_names]);
454                                 exit(1);
455                         }
456                         lpar->unc[conn_index-empty_lines] =
457                                 talloc(tctx, struct unclist);
458                         lpar->unc[conn_index-empty_lines]->host = h;
459                         lpar->unc[conn_index-empty_lines]->share = s;   
460                 }
461                 return num_unc_names-empty_lines;
462         }else{
463                 lpar->unc = talloc_array(tctx, struct unclist *, 1);
464                 lpar->unc[0] = talloc(tctx,struct unclist);
465                 lpar->unc[0]->host  = torture_setting_string(tctx, "host",
466                                                              NULL);
467                 lpar->unc[0]->share = torture_setting_string(tctx, "share",
468                                                              NULL);
469                 return 1;
470         }
471 }
472
473 /*
474  Called when the reads & writes are finished. closes the file.
475 */
476 static NTSTATUS benchrw_close(struct torture_context *tctx,
477                               struct smbcli_request *req,
478                               struct benchrw_state *state)
479 {
480         union smb_close close_parms;
481         
482         NT_STATUS_NOT_OK_RETURN(req->status);
483         
484         torture_comment(tctx, "Close file %d (%d)\n",state->nr,state->fnum);
485         close_parms.close.level = RAW_CLOSE_CLOSE;
486         close_parms.close.in.file.fnum = state->fnum ;
487         close_parms.close.in.write_time = 0;
488         state->mode=CLOSE_FILE;
489         
490         req = smb_raw_close_send(state->cli, &close_parms);
491         NT_STATUS_HAVE_NO_MEMORY(req);
492         /*register the callback function!*/
493         req->async.fn = benchrw_callback;
494         req->async.private = state;
495         
496         return NT_STATUS_OK;
497 }
498
499 /*
500  Called when the initial write is completed is done. write or read a file.
501 */
502 static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
503                                   struct smbcli_request *req,
504                                   struct benchrw_state *state)
505 {
506         union smb_read  rd;
507         union smb_write wr;
508         
509         NT_STATUS_NOT_OK_RETURN(req->status);
510         talloc_free(req);
511         
512         state->completed++;
513         /*rotate between writes and reads*/
514         if( state->completed % state->lp_params->writeratio == 0){
515                 torture_comment(tctx, "Callback WRITE file:%d (%d/%d)\n",
516                                 state->nr,state->completed,torture_numops);
517                 wr.generic.level = RAW_WRITE_WRITEX  ;
518                 wr.writex.in.file.fnum  = state->fnum ;
519                 wr.writex.in.offset     = 0;
520                 wr.writex.in.wmode      = 0             ;
521                 wr.writex.in.remaining  = 0;
522                 wr.writex.in.count      = state->lp_params->blocksize;
523                 wr.writex.in.data       = state->buffer;
524                 state->readcnt=0;
525                 req = smb_raw_write_send(state->cli,&wr);
526         }else{
527                 torture_comment(tctx,
528                                 "Callback READ file:%d (%d/%d) Offset:%d\n",
529                                 state->nr,state->completed,torture_numops,
530                                 (state->readcnt*state->lp_params->blocksize));
531                 rd.generic.level = RAW_READ_READ    ;
532                 rd.read.in.file.fnum    = state->fnum   ;
533                 rd.read.in.offset       = state->readcnt * 
534                                         state->lp_params->blocksize;
535                 rd.read.in.count        = state->lp_params->blocksize;
536                 rd.read.in.remaining    = 0     ;
537                 rd.read.out.data        = state->buffer;
538                 if(state->readcnt < state->lp_params->writeblocks){
539                         state->readcnt++;       
540                 }else{
541                         /*start reading from beginn of file*/
542                         state->readcnt=0;
543                 }
544                 req = smb_raw_read_send(state->cli,&rd);
545         }
546         NT_STATUS_HAVE_NO_MEMORY(req);
547         /*register the callback function!*/
548         req->async.fn = benchrw_callback;
549         req->async.private = state;
550         
551         return NT_STATUS_OK;
552 }
553
554 /*
555  Called when the open is done. writes to the file.
556 */
557 static NTSTATUS benchrw_open(struct torture_context *tctx,
558                              struct smbcli_request *req,
559                              struct benchrw_state *state)
560 {
561         union smb_write wr;
562         if(state->mode == OPEN_FILE){
563                 NTSTATUS status;
564                 status = smb_raw_open_recv(req,tctx,(
565                                         union smb_open*)state->req_params);
566                 NT_STATUS_NOT_OK_RETURN(status);
567         
568                 state->fnum = ((union smb_open*)state->req_params)
569                                                 ->openx.out.file.fnum;
570                 torture_comment(tctx, "File opened (%d)\n",state->fnum);
571                 state->mode=INITIAL_WRITE;
572         }
573                 
574         torture_comment(tctx, "Write initial test file:%d (%d/%d)\n",state->nr,
575                 (state->writecnt+1)*state->lp_params->blocksize,
576                 (state->lp_params->writeblocks*state->lp_params->blocksize));
577         wr.generic.level = RAW_WRITE_WRITEX  ;
578         wr.writex.in.file.fnum  = state->fnum ;
579         wr.writex.in.offset     = state->writecnt * 
580                                         state->lp_params->blocksize;
581         wr.writex.in.wmode      = 0             ;
582         wr.writex.in.remaining  = (state->lp_params->writeblocks *
583                                                 state->lp_params->blocksize)-
584                                                 ((state->writecnt+1)*state->
585                                                 lp_params->blocksize);
586         wr.writex.in.count      = state->lp_params->blocksize;
587         wr.writex.in.data       = state->buffer;
588         state->writecnt++;
589         if(state->writecnt == state->lp_params->writeblocks){
590                 state->mode=READ_WRITE_DATA;
591         }
592         req = smb_raw_write_send(state->cli,&wr);
593         NT_STATUS_HAVE_NO_MEMORY(req);
594         
595         /*register the callback function!*/
596         req->async.fn = benchrw_callback;
597         req->async.private = state;
598         return NT_STATUS_OK;
599
600
601 /*
602  Called when the mkdir is done. Opens a file.
603 */
604 static NTSTATUS benchrw_mkdir(struct torture_context *tctx,
605                               struct smbcli_request *req,
606                               struct benchrw_state *state)
607 {
608         union smb_open *open_parms;     
609         uint8_t *writedata;     
610                 
611         NT_STATUS_NOT_OK_RETURN(req->status);
612         
613         /* open/create the files */
614         torture_comment(tctx, "Open File %d/%d\n",state->nr+1,
615                         lp_parm_int(-1, "torture", "nprocs", 4));
616         open_parms=talloc_zero(tctx, union smb_open);
617         NT_STATUS_HAVE_NO_MEMORY(open_parms);
618         open_parms->openx.level = RAW_OPEN_OPENX;
619         open_parms->openx.in.flags = 0;
620         open_parms->openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
621         open_parms->openx.in.search_attrs = 
622                         FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
623         open_parms->openx.in.file_attrs = 0;
624         open_parms->openx.in.write_time = 0;
625         open_parms->openx.in.open_func = OPENX_OPEN_FUNC_CREATE;
626         open_parms->openx.in.size = 0;
627         open_parms->openx.in.timeout = 0;
628         open_parms->openx.in.fname = state->fname;
629                 
630         writedata = talloc_size(tctx,state->lp_params->blocksize);
631         NT_STATUS_HAVE_NO_MEMORY(writedata);
632         generate_random_buffer(writedata,state->lp_params->blocksize);
633         state->buffer=writedata;
634         state->writecnt=1;
635         state->readcnt=0;
636         state->req_params=open_parms;           
637         state->mode=OPEN_FILE;  
638                         
639         req = smb_raw_open_send(state->cli,open_parms);
640         NT_STATUS_HAVE_NO_MEMORY(req);
641         
642         /*register the callback function!*/
643         req->async.fn = benchrw_callback;
644         req->async.private = state;
645                 
646         return NT_STATUS_OK;
647 }
648
649 /*
650  handler for completion of a sub-request of the bench-rw test
651 */
652 static void benchrw_callback(struct smbcli_request *req)
653 {
654         struct benchrw_state *state = req->async.private;
655         struct torture_context *tctx = state->tctx;
656         
657         /*dont send new requests when torture_numops is reached*/
658         if(state->completed >= torture_numops){
659                 state->completed=0;
660                 state->mode=MAX_OPS_REACHED;
661         }
662         
663         switch (state->mode) {
664         
665         case MK_TESTDIR:
666                 if (!NT_STATUS_IS_OK(benchrw_mkdir(tctx, req,state))) {
667                         torture_comment(tctx, "Failed to create the test "
668                                         "directory - %s\n", 
669                                         nt_errstr(req->status));
670                         state->mode=ERROR;
671                         return;
672                 }
673                 break;  
674         case OPEN_FILE:
675         case INITIAL_WRITE:
676                 if (!NT_STATUS_IS_OK(benchrw_open(tctx, req,state))){
677                         torture_comment(tctx, "Failed to open/write the "
678                                         "file - %s\n", 
679                                         nt_errstr(req->status));
680                         state->mode=ERROR;
681                         return;
682                 }
683                 break;
684         case READ_WRITE_DATA:
685                 if (!NT_STATUS_IS_OK(benchrw_readwrite(tctx,req,state))){
686                         torture_comment(tctx, "Failed to read/write the "
687                                         "file - %s\n", 
688                                         nt_errstr(req->status));
689                         state->mode=ERROR;
690                         return;
691                 }
692                 break;
693         case MAX_OPS_REACHED:
694                 if (!NT_STATUS_IS_OK(benchrw_close(tctx,req,state))){
695                         torture_comment(tctx, "Failed to read/write/close "
696                                         "the file - %s\n", 
697                                         nt_errstr(req->status));
698                         state->mode=ERROR;
699                         return;
700                 }
701                 break;
702         case CLOSE_FILE:
703                 torture_comment(tctx, "File %d closed\n",state->nr);
704                 if (!NT_STATUS_IS_OK(req->status)) {
705                         torture_comment(tctx, "Failed to close the "
706                                         "file - %s\n",
707                                         nt_errstr(req->status));
708                         state->mode=ERROR;
709                         return;
710                 }
711                 state->mode=CLEANUP;
712                 return; 
713         default:
714                 break;
715         }
716         
717 }
718
719 /* open connection async callback function*/
720 static void async_open_callback(struct composite_context *con)
721 {
722         struct benchrw_state *state = con->async.private_data;
723         struct torture_context *tctx = state->tctx;
724         int retry = state->lp_params->retry;
725                 
726         if (NT_STATUS_IS_OK(con->status)) {
727                 state->cli=((struct smb_composite_connect*)
728                                         state->req_params)->out.tree;
729                 state->mode=CLEANUP_TESTDIR;
730         }else{
731                 if(state->writecnt < retry){
732                         torture_comment(tctx, "Failed to open connection: "
733                                         "%d, Retry (%d/%d)\n",
734                                         state->nr,state->writecnt,retry);
735                         state->writecnt++;
736                         state->mode=START;
737                         usleep(1000);   
738                 }else{
739                         torture_comment(tctx, "Failed to open connection "
740                                         "(%d) - %s\n",
741                                         state->nr, nt_errstr(con->status));
742                         state->mode=ERROR;
743                 }
744                 return;
745         }       
746 }
747
748 /*
749  establishs a smbcli_tree from scratch (async)
750 */
751 static struct composite_context *torture_connect_async(
752                                 struct torture_context *tctx,
753                                 struct smb_composite_connect *smb,
754                                 TALLOC_CTX *mem_ctx,
755                                 struct event_context *ev,
756                                 const char *host,
757                                 const char *share,
758                                 const char *workgroup)
759 {
760         torture_comment(tctx, "Open Connection to %s/%s\n",host,share);
761         smb->in.dest_host=talloc_strdup(mem_ctx,host);
762         smb->in.service=talloc_strdup(mem_ctx,share);
763         smb->in.port=0;
764         smb->in.called_name = strupper_talloc(mem_ctx, host);
765         smb->in.service_type=NULL;
766         smb->in.credentials=cmdline_credentials;
767         smb->in.fallback_to_anonymous=False;
768         smb->in.workgroup=workgroup;
769         
770         return smb_composite_connect_send(smb,mem_ctx,ev);
771 }
772
773 BOOL run_benchrw(struct torture_context *tctx)
774 {
775         struct smb_composite_connect *smb_con;
776         const char *fname = "\\rwtest.dat";
777         struct smbcli_request *req;
778         struct benchrw_state **state;
779         int i , num_unc_names;
780         struct event_context    *ev     ;       
781         struct composite_context *req1;
782         struct params lpparams;
783         union smb_mkdir parms;
784         int finished = 0;
785         BOOL success=True;
786         int torture_nprocs = lp_parm_int(-1, "torture", "nprocs", 4);
787         
788         torture_comment(tctx, "Start BENCH-READWRITE num_ops=%d "
789                         "num_nprocs=%d\n",
790                         torture_numops, torture_nprocs);
791
792         /*init talloc context*/
793         ev = event_context_init(tctx);
794         state = talloc_array(tctx, struct benchrw_state *, torture_nprocs);
795
796         /* init params using lp_parm_xxx */
797         num_unc_names = init_benchrw_params(tctx,&lpparams);
798         
799         /* init private data structs*/
800         for(i = 0; i<torture_nprocs;i++){
801                 state[i]=talloc(tctx,struct benchrw_state);
802                 state[i]->tctx = tctx;
803                 state[i]->completed=0;
804                 state[i]->lp_params=&lpparams;
805                 state[i]->nr=i;
806                 state[i]->dname=talloc_asprintf(tctx,"benchrw%d",i);
807                 state[i]->fname=talloc_asprintf(tctx,"%s%s",
808                                                 state[i]->dname,fname); 
809                 state[i]->mode=START;
810                 state[i]->writecnt=0;
811         }
812         
813         torture_comment(tctx, "Starting async requests\n");     
814         while(finished != torture_nprocs){
815                 finished=0;
816                 for(i = 0; i<torture_nprocs;i++){
817                         switch (state[i]->mode){
818                         /*open multiple connections with the same userid */
819                         case START:
820                                 smb_con = talloc(
821                                         tctx,struct smb_composite_connect) ;
822                                 state[i]->req_params=smb_con; 
823                                 state[i]->mode=OPEN_CONNECTION;
824                                 req1 = torture_connect_async(
825                                         tctx, smb_con, tctx,ev,
826                                         lpparams.unc[i % num_unc_names]->host,
827                                         lpparams.unc[i % num_unc_names]->share,
828                                         lpparams.workgroup);
829                                 /* register callback fn + private data */
830                                 req1->async.fn = async_open_callback;
831                                 req1->async.private_data=state[i];
832                                 break;
833                         /*setup test dirs (sync)*/
834                         case CLEANUP_TESTDIR:
835                                 torture_comment(tctx, "Setup test dir %d\n",i);
836                                 smb_raw_exit(state[i]->cli->session);
837                                 if (smbcli_deltree(state[i]->cli, 
838                                                 state[i]->dname) == -1) {
839                                         torture_comment(
840                                                 tctx,
841                                                 "Unable to delete %s - %s\n", 
842                                                 state[i]->dname,
843                                                 smbcli_errstr(state[i]->cli));
844                                         state[i]->mode=ERROR;
845                                         break;
846                                 }
847                                 state[i]->mode=MK_TESTDIR;
848                                 parms.mkdir.level = RAW_MKDIR_MKDIR;
849                                 parms.mkdir.in.path = state[i]->dname;
850                                 req = smb_raw_mkdir_send(state[i]->cli,&parms);
851                                 /* register callback fn + private data */
852                                 req->async.fn = benchrw_callback;
853                                 req->async.private=state[i];
854                                 break;
855                         /* error occured , finish */
856                         case ERROR:
857                                 finished++;
858                                 success=False;
859                                 break;
860                         /* cleanup , close connection */
861                         case CLEANUP:
862                                 torture_comment(tctx, "Deleting test dir %s "
863                                                 "%d/%d\n",state[i]->dname,
864                                                 i+1,torture_nprocs);
865                                 smbcli_deltree(state[i]->cli,state[i]->dname);
866                                 if (NT_STATUS_IS_ERR(smb_tree_disconnect(
867                                                              state[i]->cli))) {
868                                         torture_comment(tctx, "ERROR: Tree "
869                                                         "disconnect failed");
870                                         state[i]->mode=ERROR;
871                                         break;
872                                 }
873                                 state[i]->mode=FINISHED;
874                         case FINISHED:
875                                 finished++;
876                                 break;
877                         default:
878                                 event_loop_once(ev);
879                         }
880                 }
881         }
882                                 
883         return success; 
884 }
885