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