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