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