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