r23792: convert Samba4 to GPLv3
[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 "system/time.h"
24 #include "system/wait.h"
25 #include "system/filesys.h"
26 #include "libcli/raw/ioctl.h"
27 #include "libcli/libcli.h"
28 #include "lib/events/events.h"
29 #include "libcli/resolve/resolve.h"
30 #include "auth/credentials/credentials.h"
31 #include "librpc/gen_ndr/ndr_nbt.h"
32 #include "torture/torture.h"
33 #include "torture/util.h"
34 #include "libcli/smb_composite/smb_composite.h"
35 #include "libcli/composite/composite.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], 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 test how many open files this server supports on the one socket
235 */
236 BOOL run_maxfidtest(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
237 {
238 #define MAXFID_TEMPLATE "\\maxfid\\fid%d\\maxfid.%d.%d"
239         char *fname;
240         int fnums[0x11000], i;
241         int retries=4, maxfid;
242         BOOL correct = True;
243
244         if (retries <= 0) {
245                 torture_comment(tctx, "failed to connect\n");
246                 return False;
247         }
248
249         if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
250                 torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
251                        smbcli_errstr(cli->tree));
252                 return False;
253         }
254         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\maxfid"))) {
255                 torture_comment(tctx, "Failed to mkdir \\maxfid, error=%s\n", 
256                        smbcli_errstr(cli->tree));
257                 return False;
258         }
259
260         torture_comment(tctx, "Testing maximum number of open files\n");
261
262         for (i=0; i<0x11000; i++) {
263                 if (i % 1000 == 0) {
264                         asprintf(&fname, "\\maxfid\\fid%d", i/1000);
265                         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, fname))) {
266                                 torture_comment(tctx, "Failed to mkdir %s, error=%s\n", 
267                                        fname, smbcli_errstr(cli->tree));
268                                 return False;
269                         }
270                         free(fname);
271                 }
272                 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
273                 if ((fnums[i] = smbcli_open(cli->tree, fname, 
274                                         O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
275                     -1) {
276                         torture_comment(tctx, "open of %s failed (%s)\n", 
277                                fname, smbcli_errstr(cli->tree));
278                         torture_comment(tctx, "maximum fnum is %d\n", i);
279                         break;
280                 }
281                 free(fname);
282                 if (torture_setting_bool(tctx, "progress", true)) {
283                         torture_comment(tctx, "%6d\r", i);
284                         fflush(stdout);
285                 }
286         }
287         torture_comment(tctx, "%6d\n", i);
288         i--;
289
290         maxfid = i;
291
292         torture_comment(tctx, "cleaning up\n");
293         for (i=0;i<maxfid/2;i++) {
294                 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
295                 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[i]))) {
296                         torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[i], smbcli_errstr(cli->tree));
297                 }
298                 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
299                         torture_comment(tctx, "unlink of %s failed (%s)\n", 
300                                fname, smbcli_errstr(cli->tree));
301                         correct = False;
302                 }
303                 free(fname);
304
305                 asprintf(&fname, MAXFID_TEMPLATE, (maxfid-i)/1000, maxfid-i,(int)getpid());
306                 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[maxfid-i]))) {
307                         torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[maxfid-i], smbcli_errstr(cli->tree));
308                 }
309                 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
310                         torture_comment(tctx, "unlink of %s failed (%s)\n", 
311                                fname, smbcli_errstr(cli->tree));
312                         correct = False;
313                 }
314                 free(fname);
315
316                 if (torture_setting_bool(tctx, "progress", true)) {
317                         torture_comment(tctx, "%6d %6d\r", i, maxfid-i);
318                         fflush(stdout);
319                 }
320         }
321         torture_comment(tctx, "%6d\n", 0);
322
323         if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
324                 torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
325                        smbcli_errstr(cli->tree));
326                 return False;
327         }
328
329         torture_comment(tctx, "maxfid test finished\n");
330         if (!torture_close_connection(cli)) {
331                 correct = False;
332         }
333         return correct;
334 #undef MAXFID_TEMPLATE
335 }
336
337
338
339 /*
340   sees what IOCTLs are supported
341  */
342 BOOL torture_ioctl_test(struct torture_context *tctx, 
343                                                 struct smbcli_state *cli)
344 {
345         uint16_t device, function;
346         int fnum;
347         const char *fname = "\\ioctl.dat";
348         NTSTATUS status;
349         union smb_ioctl parms;
350         TALLOC_CTX *mem_ctx;
351
352         mem_ctx = talloc_named_const(tctx, 0, "ioctl_test");
353
354         smbcli_unlink(cli->tree, fname);
355
356         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
357         if (fnum == -1) {
358                 torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
359                 return False;
360         }
361
362         parms.ioctl.level = RAW_IOCTL_IOCTL;
363         parms.ioctl.in.file.fnum = fnum;
364         parms.ioctl.in.request = IOCTL_QUERY_JOB_INFO;
365         status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
366         torture_comment(tctx, "ioctl job info: %s\n", smbcli_errstr(cli->tree));
367
368         for (device=0;device<0x100;device++) {
369                 torture_comment(tctx, "testing device=0x%x\n", device);
370                 for (function=0;function<0x100;function++) {
371                         parms.ioctl.in.request = (device << 16) | function;
372                         status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
373
374                         if (NT_STATUS_IS_OK(status)) {
375                                 torture_comment(tctx, "ioctl device=0x%x function=0x%x OK : %d bytes\n", 
376                                         device, function, (int)parms.ioctl.out.blob.length);
377                         }
378                 }
379         }
380
381         return True;
382 }
383
384 static void benchrw_callback(struct smbcli_request *req);
385 enum benchrw_stage {
386         START,
387         OPEN_CONNECTION,
388         CLEANUP_TESTDIR,
389         MK_TESTDIR,
390         OPEN_FILE,
391         INITIAL_WRITE,
392         READ_WRITE_DATA,
393         MAX_OPS_REACHED,
394         ERROR,
395         CLOSE_FILE,
396         CLEANUP,
397         FINISHED
398 };
399
400 struct benchrw_state {
401         struct torture_context *tctx;
402         char *dname;
403         char *fname;
404         uint16_t fnum;
405         int nr;
406         struct smbcli_tree      *cli;           
407         uint8_t *buffer;
408         int writecnt;
409         int readcnt;
410         int completed;
411         int num_parallel_requests;
412         void *req_params;
413         enum benchrw_stage mode;
414         struct params{
415                 struct unclist{
416                         const char *host;
417                         const char *share;
418                 } **unc;
419                 const char *workgroup;
420                 int retry;
421                 unsigned int writeblocks;
422                 unsigned int blocksize;
423                 unsigned int writeratio;
424                 int num_parallel_requests;
425         } *lp_params;
426 };
427
428 /* 
429         init params using lp_parm_xxx 
430         return number of unclist entries
431 */
432 static int init_benchrw_params(struct torture_context *tctx,
433                                struct params *lpar)
434 {
435         char **unc_list = NULL;
436         int num_unc_names = 0, conn_index=0, empty_lines=0;
437         const char *p;
438         lpar->retry = torture_setting_int(tctx, "retry",3);
439         lpar->blocksize = torture_setting_int(tctx, "blocksize",65535);
440         lpar->writeblocks = torture_setting_int(tctx, "writeblocks",15);
441         lpar->writeratio = torture_setting_int(tctx, "writeratio",5);
442         lpar->num_parallel_requests = torture_setting_int(
443                 tctx, "parallel_requests", 5);
444         lpar->workgroup = lp_workgroup();
445         
446         p = torture_setting_string(tctx, "unclist", NULL);
447         if (p) {
448                 char *h, *s;
449                 unc_list = file_lines_load(p, &num_unc_names, NULL);
450                 if (!unc_list || num_unc_names <= 0) {
451                         torture_comment(tctx, "Failed to load unc names list "
452                                         "from '%s'\n", p);
453                         exit(1);
454                 }
455                 
456                 lpar->unc = talloc_array(tctx, struct unclist *,
457                                          (num_unc_names-empty_lines));
458                 for(conn_index = 0; conn_index < num_unc_names; conn_index++) {
459                         /* ignore empty lines */
460                         if(strlen(unc_list[conn_index % num_unc_names])==0){
461                                 empty_lines++;
462                                 continue;
463                         }
464                         if (!smbcli_parse_unc(
465                                     unc_list[conn_index % num_unc_names],
466                                     NULL, &h, &s)) {
467                                 torture_comment(
468                                         tctx, "Failed to parse UNC "
469                                         "name %s\n",
470                                         unc_list[conn_index % num_unc_names]);
471                                 exit(1);
472                         }
473                         lpar->unc[conn_index-empty_lines] =
474                                 talloc(tctx, struct unclist);
475                         lpar->unc[conn_index-empty_lines]->host = h;
476                         lpar->unc[conn_index-empty_lines]->share = s;   
477                 }
478                 return num_unc_names-empty_lines;
479         }else{
480                 lpar->unc = talloc_array(tctx, struct unclist *, 1);
481                 lpar->unc[0] = talloc(tctx,struct unclist);
482                 lpar->unc[0]->host  = torture_setting_string(tctx, "host",
483                                                              NULL);
484                 lpar->unc[0]->share = torture_setting_string(tctx, "share",
485                                                              NULL);
486                 return 1;
487         }
488 }
489
490 /*
491  Called when the reads & writes are finished. closes the file.
492 */
493 static NTSTATUS benchrw_close(struct torture_context *tctx,
494                               struct smbcli_request *req,
495                               struct benchrw_state *state)
496 {
497         union smb_close close_parms;
498         
499         NT_STATUS_NOT_OK_RETURN(req->status);
500         
501         torture_comment(tctx, "Close file %d (%d)\n",state->nr,state->fnum);
502         close_parms.close.level = RAW_CLOSE_CLOSE;
503         close_parms.close.in.file.fnum = state->fnum ;
504         close_parms.close.in.write_time = 0;
505         state->mode=CLOSE_FILE;
506         
507         req = smb_raw_close_send(state->cli, &close_parms);
508         NT_STATUS_HAVE_NO_MEMORY(req);
509         /*register the callback function!*/
510         req->async.fn = benchrw_callback;
511         req->async.private = state;
512         
513         return NT_STATUS_OK;
514 }
515
516 static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
517                                   struct benchrw_state *state);
518 static void benchrw_callback(struct smbcli_request *req);
519
520 static void benchrw_rw_callback(struct smbcli_request *req)
521 {
522         struct benchrw_state *state = req->async.private;
523         struct torture_context *tctx = state->tctx;
524
525         if (!NT_STATUS_IS_OK(req->status)) {
526                 state->mode = ERROR;
527                 return;
528         }
529
530         state->completed++;
531         state->num_parallel_requests--;
532
533         if ((state->completed >= torture_numops)
534             && (state->num_parallel_requests == 0)) {
535                 benchrw_callback(req);
536                 talloc_free(req);
537                 return;
538         }
539
540         talloc_free(req);
541
542         if (state->completed + state->num_parallel_requests
543             < torture_numops) {
544                 benchrw_readwrite(tctx, state);
545         }
546 }
547
548 /*
549  Called when the initial write is completed is done. write or read a file.
550 */
551 static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
552                                   struct benchrw_state *state)
553 {
554         struct smbcli_request *req;
555         union smb_read  rd;
556         union smb_write wr;
557         
558         /* randomize between writes and reads*/
559         if ( random() % state->lp_params->writeratio == 0) {
560                 torture_comment(tctx, "Callback WRITE file:%d (%d/%d)\n",
561                                 state->nr,state->completed,torture_numops);
562                 wr.generic.level = RAW_WRITE_WRITEX  ;
563                 wr.writex.in.file.fnum  = state->fnum ;
564                 wr.writex.in.offset     = 0;
565                 wr.writex.in.wmode      = 0             ;
566                 wr.writex.in.remaining  = 0;
567                 wr.writex.in.count      = state->lp_params->blocksize;
568                 wr.writex.in.data       = state->buffer;
569                 state->readcnt=0;
570                 req = smb_raw_write_send(state->cli,&wr);
571         }
572         else {
573                 torture_comment(tctx,
574                                 "Callback READ file:%d (%d/%d) Offset:%d\n",
575                                 state->nr,state->completed,torture_numops,
576                                 (state->readcnt*state->lp_params->blocksize));
577                 rd.generic.level = RAW_READ_READX;
578                 rd.readx.in.file.fnum   = state->fnum   ;
579                 rd.readx.in.offset      = state->readcnt*state->lp_params->blocksize; 
580                 rd.readx.in.mincnt      = state->lp_params->blocksize;
581                 rd.readx.in.maxcnt      = rd.readx.in.mincnt;
582                 rd.readx.in.remaining   = 0     ;
583                 rd.readx.out.data       = state->buffer;
584                 rd.readx.in.read_for_execute = False;
585                 if(state->readcnt < state->lp_params->writeblocks){
586                         state->readcnt++;       
587                 }else{
588                         /*start reading from beginn of file*/
589                         state->readcnt=0;
590                 }
591                 req = smb_raw_read_send(state->cli,&rd);
592         }
593         state->num_parallel_requests += 1;
594         NT_STATUS_HAVE_NO_MEMORY(req);
595         /*register the callback function!*/
596         req->async.fn = benchrw_rw_callback;
597         req->async.private = state;
598         
599         return NT_STATUS_OK;
600 }
601
602 /*
603  Called when the open is done. writes to the file.
604 */
605 static NTSTATUS benchrw_open(struct torture_context *tctx,
606                              struct smbcli_request *req,
607                              struct benchrw_state *state)
608 {
609         union smb_write wr;
610         if(state->mode == OPEN_FILE){
611                 NTSTATUS status;
612                 status = smb_raw_open_recv(req,tctx,(
613                                         union smb_open*)state->req_params);
614                 NT_STATUS_NOT_OK_RETURN(status);
615         
616                 state->fnum = ((union smb_open*)state->req_params)
617                                                 ->openx.out.file.fnum;
618                 torture_comment(tctx, "File opened (%d)\n",state->fnum);
619                 state->mode=INITIAL_WRITE;
620         }
621                 
622         torture_comment(tctx, "Write initial test file:%d (%d/%d)\n",state->nr,
623                 (state->writecnt+1)*state->lp_params->blocksize,
624                 (state->lp_params->writeblocks*state->lp_params->blocksize));
625         wr.generic.level = RAW_WRITE_WRITEX  ;
626         wr.writex.in.file.fnum  = state->fnum ;
627         wr.writex.in.offset     = state->writecnt * 
628                                         state->lp_params->blocksize;
629         wr.writex.in.wmode      = 0             ;
630         wr.writex.in.remaining  = (state->lp_params->writeblocks *
631                                                 state->lp_params->blocksize)-
632                                                 ((state->writecnt+1)*state->
633                                                 lp_params->blocksize);
634         wr.writex.in.count      = state->lp_params->blocksize;
635         wr.writex.in.data       = state->buffer;
636         state->writecnt++;
637         if(state->writecnt == state->lp_params->writeblocks){
638                 state->mode=READ_WRITE_DATA;
639         }
640         req = smb_raw_write_send(state->cli,&wr);
641         NT_STATUS_HAVE_NO_MEMORY(req);
642         
643         /*register the callback function!*/
644         req->async.fn = benchrw_callback;
645         req->async.private = state;
646         return NT_STATUS_OK;
647
648
649 /*
650  Called when the mkdir is done. Opens a file.
651 */
652 static NTSTATUS benchrw_mkdir(struct torture_context *tctx,
653                               struct smbcli_request *req,
654                               struct benchrw_state *state)
655 {
656         union smb_open *open_parms;     
657         uint8_t *writedata;     
658                 
659         NT_STATUS_NOT_OK_RETURN(req->status);
660         
661         /* open/create the files */
662         torture_comment(tctx, "Open File %d/%d\n",state->nr+1,
663                         lp_parm_int(-1, "torture", "nprocs", 4));
664         open_parms=talloc_zero(tctx, union smb_open);
665         NT_STATUS_HAVE_NO_MEMORY(open_parms);
666         open_parms->openx.level = RAW_OPEN_OPENX;
667         open_parms->openx.in.flags = 0;
668         open_parms->openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
669         open_parms->openx.in.search_attrs = 
670                         FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
671         open_parms->openx.in.file_attrs = 0;
672         open_parms->openx.in.write_time = 0;
673         open_parms->openx.in.open_func = OPENX_OPEN_FUNC_CREATE;
674         open_parms->openx.in.size = 0;
675         open_parms->openx.in.timeout = 0;
676         open_parms->openx.in.fname = state->fname;
677                 
678         writedata = talloc_size(tctx,state->lp_params->blocksize);
679         NT_STATUS_HAVE_NO_MEMORY(writedata);
680         generate_random_buffer(writedata,state->lp_params->blocksize);
681         state->buffer=writedata;
682         state->writecnt=1;
683         state->readcnt=0;
684         state->req_params=open_parms;           
685         state->mode=OPEN_FILE;  
686                         
687         req = smb_raw_open_send(state->cli,open_parms);
688         NT_STATUS_HAVE_NO_MEMORY(req);
689         
690         /*register the callback function!*/
691         req->async.fn = benchrw_callback;
692         req->async.private = state;
693                 
694         return NT_STATUS_OK;
695 }
696
697 /*
698  handler for completion of a sub-request of the bench-rw test
699 */
700 static void benchrw_callback(struct smbcli_request *req)
701 {
702         struct benchrw_state *state = req->async.private;
703         struct torture_context *tctx = state->tctx;
704         
705         /*dont send new requests when torture_numops is reached*/
706         if ((state->mode == READ_WRITE_DATA)
707             && (state->completed >= torture_numops)) {
708                 state->mode=MAX_OPS_REACHED;
709         }
710         
711         switch (state->mode) {
712         
713         case MK_TESTDIR:
714                 if (!NT_STATUS_IS_OK(benchrw_mkdir(tctx, req,state))) {
715                         torture_comment(tctx, "Failed to create the test "
716                                         "directory - %s\n", 
717                                         nt_errstr(req->status));
718                         state->mode=ERROR;
719                         return;
720                 }
721                 break;  
722         case OPEN_FILE:
723         case INITIAL_WRITE:
724                 if (!NT_STATUS_IS_OK(benchrw_open(tctx, req,state))){
725                         torture_comment(tctx, "Failed to open/write the "
726                                         "file - %s\n", 
727                                         nt_errstr(req->status));
728                         state->mode=ERROR;
729                         state->readcnt=0;
730                         return;
731                 }
732                 break;
733         case READ_WRITE_DATA:
734                 while (state->num_parallel_requests
735                        < state->lp_params->num_parallel_requests) {
736                         NTSTATUS status;
737                         status = benchrw_readwrite(tctx,state);
738                         if (!NT_STATUS_IS_OK(status)){
739                                 torture_comment(tctx, "Failed to read/write "
740                                                 "the file - %s\n", 
741                                                 nt_errstr(req->status));
742                                 state->mode=ERROR;
743                                 return;
744                         }
745                 }
746                 break;
747         case MAX_OPS_REACHED:
748                 if (!NT_STATUS_IS_OK(benchrw_close(tctx,req,state))){
749                         torture_comment(tctx, "Failed to read/write/close "
750                                         "the file - %s\n", 
751                                         nt_errstr(req->status));
752                         state->mode=ERROR;
753                         return;
754                 }
755                 break;
756         case CLOSE_FILE:
757                 torture_comment(tctx, "File %d closed\n",state->nr);
758                 if (!NT_STATUS_IS_OK(req->status)) {
759                         torture_comment(tctx, "Failed to close the "
760                                         "file - %s\n",
761                                         nt_errstr(req->status));
762                         state->mode=ERROR;
763                         return;
764                 }
765                 state->mode=CLEANUP;
766                 return; 
767         default:
768                 break;
769         }
770         
771 }
772
773 /* open connection async callback function*/
774 static void async_open_callback(struct composite_context *con)
775 {
776         struct benchrw_state *state = con->async.private_data;
777         struct torture_context *tctx = state->tctx;
778         int retry = state->lp_params->retry;
779                 
780         if (NT_STATUS_IS_OK(con->status)) {
781                 state->cli=((struct smb_composite_connect*)
782                                         state->req_params)->out.tree;
783                 state->mode=CLEANUP_TESTDIR;
784         }else{
785                 if(state->writecnt < retry){
786                         torture_comment(tctx, "Failed to open connection: "
787                                         "%d, Retry (%d/%d)\n",
788                                         state->nr,state->writecnt,retry);
789                         state->writecnt++;
790                         state->mode=START;
791                         usleep(1000);   
792                 }else{
793                         torture_comment(tctx, "Failed to open connection "
794                                         "(%d) - %s\n",
795                                         state->nr, nt_errstr(con->status));
796                         state->mode=ERROR;
797                 }
798                 return;
799         }       
800 }
801
802 /*
803  establishs a smbcli_tree from scratch (async)
804 */
805 static struct composite_context *torture_connect_async(
806                                 struct torture_context *tctx,
807                                 struct smb_composite_connect *smb,
808                                 TALLOC_CTX *mem_ctx,
809                                 struct event_context *ev,
810                                 const char *host,
811                                 const char *share,
812                                 const char *workgroup)
813 {
814         torture_comment(tctx, "Open Connection to %s/%s\n",host,share);
815         smb->in.dest_host=talloc_strdup(mem_ctx,host);
816         smb->in.service=talloc_strdup(mem_ctx,share);
817         smb->in.port=0;
818         smb->in.called_name = strupper_talloc(mem_ctx, host);
819         smb->in.service_type=NULL;
820         smb->in.credentials=cmdline_credentials;
821         smb->in.fallback_to_anonymous=False;
822         smb->in.workgroup=workgroup;
823         
824         return smb_composite_connect_send(smb,mem_ctx,ev);
825 }
826
827 BOOL run_benchrw(struct torture_context *tctx)
828 {
829         struct smb_composite_connect *smb_con;
830         const char *fname = "\\rwtest.dat";
831         struct smbcli_request *req;
832         struct benchrw_state **state;
833         int i , num_unc_names;
834         struct event_context    *ev     ;       
835         struct composite_context *req1;
836         struct params lpparams;
837         union smb_mkdir parms;
838         int finished = 0;
839         BOOL success=True;
840         int torture_nprocs = lp_parm_int(-1, "torture", "nprocs", 4);
841         
842         torture_comment(tctx, "Start BENCH-READWRITE num_ops=%d "
843                         "num_nprocs=%d\n",
844                         torture_numops, torture_nprocs);
845
846         /*init talloc context*/
847         ev = tctx->ev;
848         state = talloc_array(tctx, struct benchrw_state *, torture_nprocs);
849
850         /* init params using lp_parm_xxx */
851         num_unc_names = init_benchrw_params(tctx,&lpparams);
852         
853         /* init private data structs*/
854         for(i = 0; i<torture_nprocs;i++){
855                 state[i]=talloc(tctx,struct benchrw_state);
856                 state[i]->tctx = tctx;
857                 state[i]->completed=0;
858                 state[i]->num_parallel_requests=0;
859                 state[i]->lp_params=&lpparams;
860                 state[i]->nr=i;
861                 state[i]->dname=talloc_asprintf(tctx,"benchrw%d",i);
862                 state[i]->fname=talloc_asprintf(tctx,"%s%s",
863                                                 state[i]->dname,fname); 
864                 state[i]->mode=START;
865                 state[i]->writecnt=0;
866         }
867         
868         torture_comment(tctx, "Starting async requests\n");     
869         while(finished != torture_nprocs){
870                 finished=0;
871                 for(i = 0; i<torture_nprocs;i++){
872                         switch (state[i]->mode){
873                         /*open multiple connections with the same userid */
874                         case START:
875                                 smb_con = talloc(
876                                         tctx,struct smb_composite_connect) ;
877                                 state[i]->req_params=smb_con; 
878                                 state[i]->mode=OPEN_CONNECTION;
879                                 req1 = torture_connect_async(
880                                         tctx, smb_con, tctx,ev,
881                                         lpparams.unc[i % num_unc_names]->host,
882                                         lpparams.unc[i % num_unc_names]->share,
883                                         lpparams.workgroup);
884                                 /* register callback fn + private data */
885                                 req1->async.fn = async_open_callback;
886                                 req1->async.private_data=state[i];
887                                 break;
888                         /*setup test dirs (sync)*/
889                         case CLEANUP_TESTDIR:
890                                 torture_comment(tctx, "Setup test dir %d\n",i);
891                                 smb_raw_exit(state[i]->cli->session);
892                                 if (smbcli_deltree(state[i]->cli, 
893                                                 state[i]->dname) == -1) {
894                                         torture_comment(
895                                                 tctx,
896                                                 "Unable to delete %s - %s\n", 
897                                                 state[i]->dname,
898                                                 smbcli_errstr(state[i]->cli));
899                                         state[i]->mode=ERROR;
900                                         break;
901                                 }
902                                 state[i]->mode=MK_TESTDIR;
903                                 parms.mkdir.level = RAW_MKDIR_MKDIR;
904                                 parms.mkdir.in.path = state[i]->dname;
905                                 req = smb_raw_mkdir_send(state[i]->cli,&parms);
906                                 /* register callback fn + private data */
907                                 req->async.fn = benchrw_callback;
908                                 req->async.private=state[i];
909                                 break;
910                         /* error occured , finish */
911                         case ERROR:
912                                 finished++;
913                                 success=False;
914                                 break;
915                         /* cleanup , close connection */
916                         case CLEANUP:
917                                 torture_comment(tctx, "Deleting test dir %s "
918                                                 "%d/%d\n",state[i]->dname,
919                                                 i+1,torture_nprocs);
920                                 smbcli_deltree(state[i]->cli,state[i]->dname);
921                                 if (NT_STATUS_IS_ERR(smb_tree_disconnect(
922                                                              state[i]->cli))) {
923                                         torture_comment(tctx, "ERROR: Tree "
924                                                         "disconnect failed");
925                                         state[i]->mode=ERROR;
926                                         break;
927                                 }
928                                 state[i]->mode=FINISHED;
929                         case FINISHED:
930                                 finished++;
931                                 break;
932                         default:
933                                 event_loop_once(ev);
934                         }
935                 }
936         }
937                                 
938         return success; 
939 }
940