s3: Early start of an async nbench
[Samba/gebeck_regimport.git] / source3 / torture / nbench.c
blob5a83c38a46894b0fae263af4cff2259fa66323db
1 /*
2 Unix SMB/CIFS implementation.
3 In-memory cache
4 Copyright (C) Volker Lendecke 2007
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "torture/proto.h"
23 static long long int ival(const char *str)
25 return strtoll(str, NULL, 0);
28 struct nbench_state {
29 struct tevent_context *ev;
30 struct cli_state *cli;
31 const char *cliname;
32 FILE *loadfile;
33 struct ftable *ftable;
34 void (*bw_report)(size_t nread,
35 size_t nwritten,
36 void *private_data);
37 void *bw_report_private;
40 struct lock_info {
41 struct lock_info *next, *prev;
42 off_t offset;
43 int size;
46 struct createx_params {
47 char *fname;
48 unsigned int cr_options;
49 unsigned int cr_disposition;
50 int handle;
53 struct ftable {
54 struct ftable *next, *prev;
55 struct createx_params cp;
56 struct lock_info *locks;
57 uint16_t fnum; /* the fd that we got back from the server */
60 enum nbench_cmd {
61 NBENCH_CMD_NTCREATEX,
62 NBENCH_CMD_CLOSE,
63 NBENCH_CMD_RENAME,
64 NBENCH_CMD_UNLINK,
65 NBENCH_CMD_DELTREE,
66 NBENCH_CMD_RMDIR,
67 NBENCH_CMD_MKDIR,
68 NBENCH_CMD_QUERY_PATH_INFORMATION,
69 NBENCH_CMD_QUERY_FILE_INFORMATION,
70 NBENCH_CMD_QUERY_FS_INFORMATION,
71 NBENCH_CMD_SET_FILE_INFORMATION,
72 NBENCH_CMD_FIND_FIRST,
73 NBENCH_CMD_WRITEX,
74 NBENCH_CMD_WRITE,
75 NBENCH_CMD_LOCKX,
76 NBENCH_CMD_UNLOCKX,
77 NBENCH_CMD_READX,
78 NBENCH_CMD_FLUSH,
79 NBENCH_CMD_SLEEP,
82 struct nbench_cmd_struct {
83 char **params;
84 int num_params;
85 NTSTATUS status;
86 enum nbench_cmd cmd;
89 static struct nbench_cmd_struct *nbench_parse(TALLOC_CTX *mem_ctx,
90 const char *line)
92 struct nbench_cmd_struct *result;
93 char *cmd;
94 char *status;
96 result = TALLOC_P(mem_ctx, struct nbench_cmd_struct);
97 if (result == NULL) {
98 return NULL;
100 result->params = str_list_make_shell(mem_ctx, line, " ");
101 if (result->params == NULL) {
102 goto fail;
104 result->num_params = talloc_array_length(result->params) - 1;
105 if (result->num_params < 2) {
106 goto fail;
108 status = result->params[result->num_params-1];
109 if (strncmp(status, "NT_STATUS_", 10) != 0 &&
110 strncmp(status, "0x", 2) != 0) {
111 goto fail;
113 /* accept numeric or string status codes */
114 if (strncmp(status, "0x", 2) == 0) {
115 result->status = NT_STATUS(strtoul(status, NULL, 16));
116 } else {
117 result->status = nt_status_string_to_code(status);
120 cmd = result->params[0];
122 if (!strcmp(cmd, "NTCreateX")) {
123 result->cmd = NBENCH_CMD_NTCREATEX;
124 } else if (!strcmp(cmd, "Close")) {
125 result->cmd = NBENCH_CMD_CLOSE;
126 } else if (!strcmp(cmd, "Rename")) {
127 result->cmd = NBENCH_CMD_RENAME;
128 } else if (!strcmp(cmd, "Unlink")) {
129 result->cmd = NBENCH_CMD_UNLINK;
130 } else if (!strcmp(cmd, "Deltree")) {
131 result->cmd = NBENCH_CMD_DELTREE;
132 } else if (!strcmp(cmd, "Rmdir")) {
133 result->cmd = NBENCH_CMD_RMDIR;
134 } else if (!strcmp(cmd, "Mkdir")) {
135 result->cmd = NBENCH_CMD_MKDIR;
136 } else if (!strcmp(cmd, "QUERY_PATH_INFORMATION")) {
137 result->cmd = NBENCH_CMD_QUERY_PATH_INFORMATION;
138 } else if (!strcmp(cmd, "QUERY_FILE_INFORMATION")) {
139 result->cmd = NBENCH_CMD_QUERY_FILE_INFORMATION;
140 } else if (!strcmp(cmd, "QUERY_FS_INFORMATION")) {
141 result->cmd = NBENCH_CMD_QUERY_FS_INFORMATION;
142 } else if (!strcmp(cmd, "SET_FILE_INFORMATION")) {
143 result->cmd = NBENCH_CMD_SET_FILE_INFORMATION;
144 } else if (!strcmp(cmd, "FIND_FIRST")) {
145 result->cmd = NBENCH_CMD_FIND_FIRST;
146 } else if (!strcmp(cmd, "WriteX")) {
147 result->cmd = NBENCH_CMD_WRITEX;
148 } else if (!strcmp(cmd, "Write")) {
149 result->cmd = NBENCH_CMD_WRITE;
150 } else if (!strcmp(cmd, "LockX")) {
151 result->cmd = NBENCH_CMD_LOCKX;
152 } else if (!strcmp(cmd, "UnlockX")) {
153 result->cmd = NBENCH_CMD_UNLOCKX;
154 } else if (!strcmp(cmd, "ReadX")) {
155 result->cmd = NBENCH_CMD_READX;
156 } else if (!strcmp(cmd, "Flush")) {
157 result->cmd = NBENCH_CMD_FLUSH;
158 } else if (!strcmp(cmd, "Sleep")) {
159 result->cmd = NBENCH_CMD_SLEEP;
160 } else {
161 goto fail;
163 return result;
164 fail:
165 TALLOC_FREE(result);
166 return NULL;
169 static struct ftable *ft_find(struct ftable *ftlist, int handle)
171 while (ftlist != NULL) {
172 if (ftlist->cp.handle == handle) {
173 return ftlist;
175 ftlist = ftlist->next;
177 return NULL;
180 struct nbench_cmd_state {
181 struct tevent_context *ev;
182 struct nbench_state *state;
183 struct nbench_cmd_struct *cmd;
184 struct ftable *ft;
185 bool eof;
188 static void nbench_cmd_done(struct tevent_req *subreq);
190 static struct tevent_req *nbench_cmd_send(TALLOC_CTX *mem_ctx,
191 struct tevent_context *ev,
192 struct nbench_state *nb_state)
194 struct tevent_req *req, *subreq;
195 struct nbench_cmd_state *state;
196 char line[1024];
197 size_t len;
199 req = tevent_req_create(mem_ctx, &state, struct nbench_cmd_state);
200 if (req == NULL) {
201 return NULL;
203 state->ev = ev;
204 state->state = nb_state;
206 if (fgets(line, sizeof(line), nb_state->loadfile) == NULL) {
207 tevent_req_nterror(req, NT_STATUS_END_OF_FILE);
208 return tevent_req_post(req, ev);
210 len = strlen(line);
211 if (len == 0) {
212 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
213 return tevent_req_post(req, ev);
215 if (line[len-1] == '\n') {
216 line[len-1] = '\0';
219 state->cmd = nbench_parse(state, line);
220 if (state->cmd == NULL) {
221 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
222 return tevent_req_post(req, ev);
225 switch (state->cmd->cmd) {
226 case NBENCH_CMD_NTCREATEX: {
227 uint32_t desired_access;
228 uint32_t share_mode;
229 unsigned int flags = 0;
231 state->ft = talloc(state, struct ftable);
232 if (tevent_req_nomem(state->ft, req)) {
233 return tevent_req_post(req, ev);
236 state->ft->cp.fname = talloc_all_string_sub(
237 state->ft, state->cmd->params[1], "client1",
238 nb_state->cliname);
239 if (tevent_req_nomem(state->ft->cp.fname, req)) {
240 return tevent_req_post(req, ev);
242 state->ft->cp.cr_options = ival(state->cmd->params[2]);
243 state->ft->cp.cr_disposition = ival(state->cmd->params[3]);
244 state->ft->cp.handle = ival(state->cmd->params[4]);
246 if (state->ft->cp.cr_options & FILE_DIRECTORY_FILE) {
247 desired_access = SEC_FILE_READ_DATA;
248 } else {
249 desired_access =
250 SEC_FILE_READ_DATA |
251 SEC_FILE_WRITE_DATA |
252 SEC_FILE_READ_ATTRIBUTE |
253 SEC_FILE_WRITE_ATTRIBUTE;
254 flags = EXTENDED_RESPONSE_REQUIRED
255 | REQUEST_OPLOCK | REQUEST_BATCH_OPLOCK;
257 share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
259 subreq = cli_ntcreate_send(
260 state, ev, nb_state->cli, state->ft->cp.fname, flags,
261 desired_access, 0, share_mode,
262 state->ft->cp.cr_disposition,
263 state->ft->cp.cr_options, 0);
264 break;
266 case NBENCH_CMD_CLOSE: {
267 state->ft = ft_find(state->state->ftable,
268 ival(state->cmd->params[1]));
269 if (state->ft == NULL) {
270 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
271 return tevent_req_post(req, ev);
273 subreq = cli_close_send(
274 state, ev, nb_state->cli, state->ft->fnum);
275 break;
277 case NBENCH_CMD_MKDIR: {
278 char *fname;
279 fname = talloc_all_string_sub(
280 state, state->cmd->params[1], "client1",
281 nb_state->cliname);
282 if (tevent_req_nomem(state->ft->cp.fname, req)) {
283 return tevent_req_post(req, ev);
285 subreq = cli_mkdir_send(state, ev, nb_state->cli, fname);
286 break;
288 case NBENCH_CMD_QUERY_PATH_INFORMATION: {
289 char *fname;
290 fname = talloc_all_string_sub(
291 state, state->cmd->params[1], "client1",
292 nb_state->cliname);
293 if (tevent_req_nomem(state->ft->cp.fname, req)) {
294 return tevent_req_post(req, ev);
296 subreq = cli_qpathinfo_send(state, ev, nb_state->cli, fname,
297 ival(state->cmd->params[2]),
298 0, nb_state->cli->max_xmit);
299 break;
301 default:
302 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
303 return tevent_req_post(req, ev);
306 if (tevent_req_nomem(subreq, req)) {
307 return tevent_req_post(req, ev);
309 tevent_req_set_callback(subreq, nbench_cmd_done, req);
310 return req;
313 static bool status_wrong(struct tevent_req *req, NTSTATUS expected,
314 NTSTATUS status)
316 if (NT_STATUS_EQUAL(expected, status)) {
317 return false;
319 if (NT_STATUS_IS_OK(status)) {
320 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
322 tevent_req_nterror(req, status);
323 return true;
326 static void nbench_cmd_done(struct tevent_req *subreq)
328 struct tevent_req *req = tevent_req_callback_data(
329 subreq, struct tevent_req);
330 struct nbench_cmd_state *state = tevent_req_data(
331 req, struct nbench_cmd_state);
332 struct nbench_state *nbstate = state->state;
333 NTSTATUS status;
335 switch (state->cmd->cmd) {
336 case NBENCH_CMD_NTCREATEX: {
337 struct ftable *ft;
338 status = cli_ntcreate_recv(subreq, &state->ft->fnum);
339 TALLOC_FREE(subreq);
340 if (status_wrong(req, state->cmd->status, status)) {
341 return;
343 if (!NT_STATUS_IS_OK(status)) {
344 tevent_req_done(req);
345 return;
347 ft = talloc_move(nbstate, &state->ft);
348 DLIST_ADD(nbstate->ftable, ft);
349 break;
351 case NBENCH_CMD_CLOSE: {
352 status = cli_close_recv(subreq);
353 TALLOC_FREE(subreq);
354 if (status_wrong(req, state->cmd->status, status)) {
355 return;
357 DLIST_REMOVE(state->state->ftable, state->ft);
358 TALLOC_FREE(state->ft);
359 break;
361 case NBENCH_CMD_MKDIR: {
362 status = cli_mkdir_recv(subreq);
363 TALLOC_FREE(subreq);
364 if (status_wrong(req, state->cmd->status, status)) {
365 return;
367 break;
369 case NBENCH_CMD_QUERY_PATH_INFORMATION: {
370 status = cli_qpathinfo_recv(subreq, NULL, NULL, NULL);
371 TALLOC_FREE(subreq);
372 if (status_wrong(req, state->cmd->status, status)) {
373 return;
375 break;
377 default:
378 break;
380 tevent_req_done(req);
383 static NTSTATUS nbench_cmd_recv(struct tevent_req *req)
385 return tevent_req_simple_recv_ntstatus(req);
388 static void nbench_done(struct tevent_req *subreq);
390 static struct tevent_req *nbench_send(
391 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
392 const char *cliname, FILE *loadfile,
393 void (*bw_report)(size_t nread, size_t nwritten, void *private_data),
394 void *bw_report_private)
396 struct tevent_req *req, *subreq;
397 struct nbench_state *state;
399 req = tevent_req_create(mem_ctx, &state, struct nbench_state);
400 if (req == NULL) {
401 return NULL;
403 state->ev = ev;
404 state->cli = cli;
405 state->cliname = cliname;
406 state->loadfile = loadfile;
407 state->bw_report = bw_report;
408 state->bw_report_private = bw_report_private;
410 subreq = nbench_cmd_send(state, ev, state);
411 if (tevent_req_nomem(subreq, req)) {
412 return tevent_req_post(req, ev);
414 tevent_req_set_callback(subreq, nbench_done, req);
415 return req;
418 static void nbench_done(struct tevent_req *subreq)
420 struct tevent_req *req = tevent_req_callback_data(
421 subreq, struct tevent_req);
422 struct nbench_state *state = tevent_req_data(
423 req, struct nbench_state);
424 NTSTATUS status;
426 status = nbench_cmd_recv(subreq);
427 TALLOC_FREE(subreq);
429 if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
430 tevent_req_done(req);
431 return;
433 if (!NT_STATUS_IS_OK(status)) {
434 tevent_req_nterror(req, status);
435 return;
437 subreq = nbench_cmd_send(state, state->ev, state);
438 if (tevent_req_nomem(subreq, req)) {
439 return;
441 tevent_req_set_callback(subreq, nbench_done, req);
444 static NTSTATUS nbench_recv(struct tevent_req *req)
446 return tevent_req_simple_recv_ntstatus(req);
449 bool run_nbench2(int dummy)
451 TALLOC_CTX *frame = talloc_stackframe();
452 struct tevent_context *ev;
453 struct cli_state *cli = NULL;
454 FILE *loadfile;
455 bool ret = false;
456 struct tevent_req *req;
457 NTSTATUS status;
459 loadfile = fopen("client.txt", "r");
460 if (loadfile == NULL) {
461 fprintf(stderr, "Could not open \"client.txt\": %s\n",
462 strerror(errno));
463 return false;
465 ev = tevent_context_init(talloc_tos());
466 if (ev == NULL) {
467 goto fail;
469 if (!torture_open_connection(&cli, 0)) {
470 goto fail;
473 req = nbench_send(talloc_tos(), ev, cli, "client1", loadfile,
474 NULL, NULL);
475 if (req == NULL) {
476 goto fail;
478 if (!tevent_req_poll(req, ev)) {
479 goto fail;
481 status = nbench_recv(req);
482 TALLOC_FREE(req);
483 printf("nbench returned %s\n", nt_errstr(status));
485 ret = true;
486 fail:
487 if (cli != NULL) {
488 torture_close_connection(cli);
490 TALLOC_FREE(ev);
491 if (loadfile != NULL) {
492 fclose(loadfile);
493 loadfile = NULL;
495 TALLOC_FREE(frame);
496 return ret;