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