• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source4/torture/basic/
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
39extern struct cli_credentials *cmdline_credentials;
40
41static 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
50static 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
144bool 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*/
153bool 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 */
187bool 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/*
236test how many open files this server supports on the one socket
237*/
238bool 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 */
344bool 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
386static void benchrw_callback(struct smbcli_request *req);
387enum 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
402struct 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*/
434static 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*/
495static 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_data = state;
514
515	return NT_STATUS_OK;
516}
517
518static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
519				  struct benchrw_state *state);
520static void benchrw_callback(struct smbcli_request *req);
521
522static void benchrw_rw_callback(struct smbcli_request *req)
523{
524	struct benchrw_state *state = req->async.private_data;
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*/
553static 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_data = state;
600
601	return NT_STATUS_OK;
602}
603
604/*
605 Called when the open is done. writes to the file.
606*/
607static 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_data = state;
648	return NT_STATUS_OK;
649}
650
651/*
652 Called when the mkdir is done. Opens a file.
653*/
654static 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_data = state;
695
696	return NT_STATUS_OK;
697}
698
699/*
700 handler for completion of a sub-request of the bench-rw test
701*/
702static void benchrw_callback(struct smbcli_request *req)
703{
704	struct benchrw_state *state = req->async.private_data;
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*/
776static 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*/
807static 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
835bool 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_data=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
949