Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : In-memory cache
4 : Copyright (C) Volker Lendecke 2007
5 :
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.
10 :
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.
15 :
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/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "torture/proto.h"
22 : #include "libsmb/libsmb.h"
23 : #include "libsmb/clirap.h"
24 : #include "../lib/util/tevent_ntstatus.h"
25 :
26 0 : static long long int ival(const char *str)
27 : {
28 0 : return strtoll(str, NULL, 0);
29 : }
30 :
31 : struct nbench_state {
32 : struct tevent_context *ev;
33 : struct cli_state *cli;
34 : const char *cliname;
35 : FILE *loadfile;
36 : struct ftable *ftable;
37 : void (*bw_report)(size_t nread,
38 : size_t nwritten,
39 : void *private_data);
40 : void *bw_report_private;
41 : };
42 :
43 : struct lock_info {
44 : struct lock_info *next, *prev;
45 : off_t offset;
46 : int size;
47 : };
48 :
49 : struct createx_params {
50 : char *fname;
51 : unsigned int cr_options;
52 : unsigned int cr_disposition;
53 : int handle;
54 : };
55 :
56 : struct ftable {
57 : struct ftable *next, *prev;
58 : struct createx_params cp;
59 : struct lock_info *locks;
60 : uint16_t fnum; /* the fd that we got back from the server */
61 : };
62 :
63 : enum nbench_cmd {
64 : NBENCH_CMD_NTCREATEX,
65 : NBENCH_CMD_CLOSE,
66 : NBENCH_CMD_RENAME,
67 : NBENCH_CMD_UNLINK,
68 : NBENCH_CMD_DELTREE,
69 : NBENCH_CMD_RMDIR,
70 : NBENCH_CMD_MKDIR,
71 : NBENCH_CMD_QUERY_PATH_INFORMATION,
72 : NBENCH_CMD_QUERY_FILE_INFORMATION,
73 : NBENCH_CMD_QUERY_FS_INFORMATION,
74 : NBENCH_CMD_SET_FILE_INFORMATION,
75 : NBENCH_CMD_FIND_FIRST,
76 : NBENCH_CMD_WRITEX,
77 : NBENCH_CMD_WRITE,
78 : NBENCH_CMD_LOCKX,
79 : NBENCH_CMD_UNLOCKX,
80 : NBENCH_CMD_READX,
81 : NBENCH_CMD_FLUSH,
82 : NBENCH_CMD_SLEEP,
83 : };
84 :
85 : struct nbench_cmd_struct {
86 : char **params;
87 : int num_params;
88 : NTSTATUS status;
89 : enum nbench_cmd cmd;
90 : };
91 :
92 0 : static struct nbench_cmd_struct *nbench_parse(TALLOC_CTX *mem_ctx,
93 : const char *line)
94 : {
95 : struct nbench_cmd_struct *result;
96 : char *cmd;
97 : char *status;
98 :
99 0 : result = talloc(mem_ctx, struct nbench_cmd_struct);
100 0 : if (result == NULL) {
101 0 : return NULL;
102 : }
103 0 : result->params = str_list_make_shell(mem_ctx, line, " ");
104 0 : if (result->params == NULL) {
105 0 : goto fail;
106 : }
107 0 : result->num_params = talloc_array_length(result->params) - 1;
108 0 : if (result->num_params < 2) {
109 0 : goto fail;
110 : }
111 0 : status = result->params[result->num_params-1];
112 0 : if (strncmp(status, "NT_STATUS_", 10) != 0 &&
113 0 : strncmp(status, "0x", 2) != 0) {
114 0 : goto fail;
115 : }
116 : /* accept numeric or string status codes */
117 0 : if (strncmp(status, "0x", 2) == 0) {
118 0 : result->status = NT_STATUS(strtoul(status, NULL, 16));
119 : } else {
120 0 : result->status = nt_status_string_to_code(status);
121 : }
122 :
123 0 : cmd = result->params[0];
124 :
125 0 : if (!strcmp(cmd, "NTCreateX")) {
126 0 : result->cmd = NBENCH_CMD_NTCREATEX;
127 0 : } else if (!strcmp(cmd, "Close")) {
128 0 : result->cmd = NBENCH_CMD_CLOSE;
129 0 : } else if (!strcmp(cmd, "Rename")) {
130 0 : result->cmd = NBENCH_CMD_RENAME;
131 0 : } else if (!strcmp(cmd, "Unlink")) {
132 0 : result->cmd = NBENCH_CMD_UNLINK;
133 0 : } else if (!strcmp(cmd, "Deltree")) {
134 0 : result->cmd = NBENCH_CMD_DELTREE;
135 0 : } else if (!strcmp(cmd, "Rmdir")) {
136 0 : result->cmd = NBENCH_CMD_RMDIR;
137 0 : } else if (!strcmp(cmd, "Mkdir")) {
138 0 : result->cmd = NBENCH_CMD_MKDIR;
139 0 : } else if (!strcmp(cmd, "QUERY_PATH_INFORMATION")) {
140 0 : result->cmd = NBENCH_CMD_QUERY_PATH_INFORMATION;
141 0 : } else if (!strcmp(cmd, "QUERY_FILE_INFORMATION")) {
142 0 : result->cmd = NBENCH_CMD_QUERY_FILE_INFORMATION;
143 0 : } else if (!strcmp(cmd, "QUERY_FS_INFORMATION")) {
144 0 : result->cmd = NBENCH_CMD_QUERY_FS_INFORMATION;
145 0 : } else if (!strcmp(cmd, "SET_FILE_INFORMATION")) {
146 0 : result->cmd = NBENCH_CMD_SET_FILE_INFORMATION;
147 0 : } else if (!strcmp(cmd, "FIND_FIRST")) {
148 0 : result->cmd = NBENCH_CMD_FIND_FIRST;
149 0 : } else if (!strcmp(cmd, "WriteX")) {
150 0 : result->cmd = NBENCH_CMD_WRITEX;
151 0 : } else if (!strcmp(cmd, "Write")) {
152 0 : result->cmd = NBENCH_CMD_WRITE;
153 0 : } else if (!strcmp(cmd, "LockX")) {
154 0 : result->cmd = NBENCH_CMD_LOCKX;
155 0 : } else if (!strcmp(cmd, "UnlockX")) {
156 0 : result->cmd = NBENCH_CMD_UNLOCKX;
157 0 : } else if (!strcmp(cmd, "ReadX")) {
158 0 : result->cmd = NBENCH_CMD_READX;
159 0 : } else if (!strcmp(cmd, "Flush")) {
160 0 : result->cmd = NBENCH_CMD_FLUSH;
161 0 : } else if (!strcmp(cmd, "Sleep")) {
162 0 : result->cmd = NBENCH_CMD_SLEEP;
163 : } else {
164 0 : goto fail;
165 : }
166 0 : return result;
167 0 : fail:
168 0 : TALLOC_FREE(result);
169 0 : return NULL;
170 : }
171 :
172 0 : static struct ftable *ft_find(struct ftable *ftlist, int handle)
173 : {
174 0 : while (ftlist != NULL) {
175 0 : if (ftlist->cp.handle == handle) {
176 0 : return ftlist;
177 : }
178 0 : ftlist = ftlist->next;
179 : }
180 0 : return NULL;
181 : }
182 :
183 : struct nbench_cmd_state {
184 : struct tevent_context *ev;
185 : struct nbench_state *state;
186 : struct nbench_cmd_struct *cmd;
187 : struct ftable *ft;
188 : bool eof;
189 : };
190 :
191 : static void nbench_cmd_done(struct tevent_req *subreq);
192 :
193 0 : static struct tevent_req *nbench_cmd_send(TALLOC_CTX *mem_ctx,
194 : struct tevent_context *ev,
195 : struct nbench_state *nb_state)
196 : {
197 : struct tevent_req *req, *subreq;
198 : struct nbench_cmd_state *state;
199 : char line[1024];
200 : size_t len;
201 :
202 0 : req = tevent_req_create(mem_ctx, &state, struct nbench_cmd_state);
203 0 : if (req == NULL) {
204 0 : return NULL;
205 : }
206 0 : state->ev = ev;
207 0 : state->state = nb_state;
208 :
209 0 : if (fgets(line, sizeof(line), nb_state->loadfile) == NULL) {
210 0 : tevent_req_nterror(req, NT_STATUS_END_OF_FILE);
211 0 : return tevent_req_post(req, ev);
212 : }
213 0 : len = strlen(line);
214 0 : if (len == 0) {
215 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
216 0 : return tevent_req_post(req, ev);
217 : }
218 0 : if (line[len-1] == '\n') {
219 0 : line[len-1] = '\0';
220 : }
221 :
222 0 : state->cmd = nbench_parse(state, line);
223 0 : if (state->cmd == NULL) {
224 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
225 0 : return tevent_req_post(req, ev);
226 : }
227 :
228 0 : switch (state->cmd->cmd) {
229 0 : case NBENCH_CMD_NTCREATEX: {
230 : uint32_t desired_access;
231 : uint32_t share_mode;
232 0 : unsigned int flags = 0;
233 :
234 0 : state->ft = talloc(state, struct ftable);
235 0 : if (tevent_req_nomem(state->ft, req)) {
236 0 : return tevent_req_post(req, ev);
237 : }
238 :
239 0 : state->ft->cp.fname = talloc_all_string_sub(
240 0 : state->ft, state->cmd->params[1], "client1",
241 : nb_state->cliname);
242 0 : if (tevent_req_nomem(state->ft->cp.fname, req)) {
243 0 : return tevent_req_post(req, ev);
244 : }
245 0 : state->ft->cp.cr_options = ival(state->cmd->params[2]);
246 0 : state->ft->cp.cr_disposition = ival(state->cmd->params[3]);
247 0 : state->ft->cp.handle = ival(state->cmd->params[4]);
248 :
249 0 : if (state->ft->cp.cr_options & FILE_DIRECTORY_FILE) {
250 0 : desired_access = SEC_FILE_READ_DATA;
251 : } else {
252 0 : desired_access =
253 : SEC_FILE_READ_DATA |
254 : SEC_FILE_WRITE_DATA |
255 : SEC_FILE_READ_ATTRIBUTE |
256 : SEC_FILE_WRITE_ATTRIBUTE;
257 0 : flags = EXTENDED_RESPONSE_REQUIRED
258 : | REQUEST_OPLOCK | REQUEST_BATCH_OPLOCK;
259 : }
260 0 : share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
261 :
262 0 : subreq = cli_ntcreate_send(
263 0 : state, ev, nb_state->cli, state->ft->cp.fname, flags,
264 : desired_access, 0, share_mode,
265 0 : state->ft->cp.cr_disposition,
266 0 : state->ft->cp.cr_options,
267 : SMB2_IMPERSONATION_IMPERSONATION, 0);
268 0 : break;
269 : }
270 0 : case NBENCH_CMD_CLOSE: {
271 0 : state->ft = ft_find(state->state->ftable,
272 0 : ival(state->cmd->params[1]));
273 0 : if (state->ft == NULL) {
274 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
275 0 : return tevent_req_post(req, ev);
276 : }
277 0 : subreq = cli_close_send(
278 0 : state, ev, nb_state->cli, state->ft->fnum);
279 0 : break;
280 : }
281 0 : case NBENCH_CMD_MKDIR: {
282 : char *fname;
283 0 : fname = talloc_all_string_sub(
284 0 : state, state->cmd->params[1], "client1",
285 : nb_state->cliname);
286 0 : if (tevent_req_nomem(state->ft->cp.fname, req)) {
287 0 : return tevent_req_post(req, ev);
288 : }
289 0 : subreq = cli_mkdir_send(state, ev, nb_state->cli, fname);
290 0 : break;
291 : }
292 0 : case NBENCH_CMD_QUERY_PATH_INFORMATION: {
293 : char *fname;
294 0 : fname = talloc_all_string_sub(
295 0 : state, state->cmd->params[1], "client1",
296 : nb_state->cliname);
297 0 : if (tevent_req_nomem(state->ft->cp.fname, req)) {
298 0 : return tevent_req_post(req, ev);
299 : }
300 0 : subreq = cli_qpathinfo_send(state, ev, nb_state->cli, fname,
301 0 : ival(state->cmd->params[2]),
302 : 0, CLI_BUFFER_SIZE);
303 0 : break;
304 : }
305 0 : default:
306 0 : tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
307 0 : return tevent_req_post(req, ev);
308 : }
309 :
310 0 : if (tevent_req_nomem(subreq, req)) {
311 0 : return tevent_req_post(req, ev);
312 : }
313 0 : tevent_req_set_callback(subreq, nbench_cmd_done, req);
314 0 : return req;
315 : }
316 :
317 0 : static bool status_wrong(struct tevent_req *req, NTSTATUS expected,
318 : NTSTATUS status)
319 : {
320 0 : if (NT_STATUS_EQUAL(expected, status)) {
321 0 : return false;
322 : }
323 0 : if (NT_STATUS_IS_OK(status)) {
324 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
325 : }
326 0 : tevent_req_nterror(req, status);
327 0 : return true;
328 : }
329 :
330 0 : static void nbench_cmd_done(struct tevent_req *subreq)
331 : {
332 0 : struct tevent_req *req = tevent_req_callback_data(
333 : subreq, struct tevent_req);
334 0 : struct nbench_cmd_state *state = tevent_req_data(
335 : req, struct nbench_cmd_state);
336 0 : struct nbench_state *nbstate = state->state;
337 : NTSTATUS status;
338 :
339 0 : switch (state->cmd->cmd) {
340 0 : case NBENCH_CMD_NTCREATEX: {
341 : struct ftable *ft;
342 0 : status = cli_ntcreate_recv(subreq, &state->ft->fnum, NULL);
343 0 : TALLOC_FREE(subreq);
344 0 : if (status_wrong(req, state->cmd->status, status)) {
345 0 : return;
346 : }
347 0 : if (!NT_STATUS_IS_OK(status)) {
348 0 : tevent_req_done(req);
349 0 : return;
350 : }
351 0 : ft = talloc_move(nbstate, &state->ft);
352 0 : DLIST_ADD(nbstate->ftable, ft);
353 0 : break;
354 : }
355 0 : case NBENCH_CMD_CLOSE: {
356 0 : status = cli_close_recv(subreq);
357 0 : TALLOC_FREE(subreq);
358 0 : if (status_wrong(req, state->cmd->status, status)) {
359 0 : return;
360 : }
361 0 : DLIST_REMOVE(state->state->ftable, state->ft);
362 0 : TALLOC_FREE(state->ft);
363 0 : break;
364 : }
365 0 : case NBENCH_CMD_MKDIR: {
366 0 : status = cli_mkdir_recv(subreq);
367 0 : TALLOC_FREE(subreq);
368 0 : if (status_wrong(req, state->cmd->status, status)) {
369 0 : return;
370 : }
371 0 : break;
372 : }
373 0 : case NBENCH_CMD_QUERY_PATH_INFORMATION: {
374 0 : status = cli_qpathinfo_recv(subreq, NULL, NULL, NULL);
375 0 : TALLOC_FREE(subreq);
376 0 : if (status_wrong(req, state->cmd->status, status)) {
377 0 : return;
378 : }
379 0 : break;
380 : }
381 0 : default:
382 0 : break;
383 : }
384 0 : tevent_req_done(req);
385 : }
386 :
387 0 : static NTSTATUS nbench_cmd_recv(struct tevent_req *req)
388 : {
389 0 : return tevent_req_simple_recv_ntstatus(req);
390 : }
391 :
392 : static void nbench_done(struct tevent_req *subreq);
393 :
394 0 : static struct tevent_req *nbench_send(
395 : TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
396 : const char *cliname, FILE *loadfile,
397 : void (*bw_report)(size_t nread, size_t nwritten, void *private_data),
398 : void *bw_report_private)
399 : {
400 : struct tevent_req *req, *subreq;
401 : struct nbench_state *state;
402 :
403 0 : req = tevent_req_create(mem_ctx, &state, struct nbench_state);
404 0 : if (req == NULL) {
405 0 : return NULL;
406 : }
407 0 : state->ev = ev;
408 0 : state->cli = cli;
409 0 : state->cliname = cliname;
410 0 : state->loadfile = loadfile;
411 0 : state->bw_report = bw_report;
412 0 : state->bw_report_private = bw_report_private;
413 :
414 0 : subreq = nbench_cmd_send(state, ev, state);
415 0 : if (tevent_req_nomem(subreq, req)) {
416 0 : return tevent_req_post(req, ev);
417 : }
418 0 : tevent_req_set_callback(subreq, nbench_done, req);
419 0 : return req;
420 : }
421 :
422 0 : static void nbench_done(struct tevent_req *subreq)
423 : {
424 0 : struct tevent_req *req = tevent_req_callback_data(
425 : subreq, struct tevent_req);
426 0 : struct nbench_state *state = tevent_req_data(
427 : req, struct nbench_state);
428 : NTSTATUS status;
429 :
430 0 : status = nbench_cmd_recv(subreq);
431 0 : TALLOC_FREE(subreq);
432 :
433 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
434 0 : tevent_req_done(req);
435 0 : return;
436 : }
437 0 : if (!NT_STATUS_IS_OK(status)) {
438 0 : tevent_req_nterror(req, status);
439 0 : return;
440 : }
441 0 : subreq = nbench_cmd_send(state, state->ev, state);
442 0 : if (tevent_req_nomem(subreq, req)) {
443 0 : return;
444 : }
445 0 : tevent_req_set_callback(subreq, nbench_done, req);
446 : }
447 :
448 0 : static NTSTATUS nbench_recv(struct tevent_req *req)
449 : {
450 0 : return tevent_req_simple_recv_ntstatus(req);
451 : }
452 :
453 0 : bool run_nbench2(int dummy)
454 : {
455 0 : TALLOC_CTX *frame = talloc_stackframe();
456 : struct tevent_context *ev;
457 0 : struct cli_state *cli = NULL;
458 : FILE *loadfile;
459 0 : bool ret = false;
460 : struct tevent_req *req;
461 : NTSTATUS status;
462 :
463 0 : loadfile = fopen("client.txt", "r");
464 0 : if (loadfile == NULL) {
465 0 : fprintf(stderr, "Could not open \"client.txt\": %s\n",
466 0 : strerror(errno));
467 0 : return false;
468 : }
469 0 : ev = samba_tevent_context_init(talloc_tos());
470 0 : if (ev == NULL) {
471 0 : goto fail;
472 : }
473 0 : if (!torture_open_connection(&cli, 0)) {
474 0 : goto fail;
475 : }
476 :
477 0 : req = nbench_send(talloc_tos(), ev, cli, "client1", loadfile,
478 : NULL, NULL);
479 0 : if (req == NULL) {
480 0 : goto fail;
481 : }
482 0 : if (!tevent_req_poll(req, ev)) {
483 0 : goto fail;
484 : }
485 0 : status = nbench_recv(req);
486 0 : TALLOC_FREE(req);
487 0 : printf("nbench returned %s\n", nt_errstr(status));
488 :
489 0 : ret = true;
490 0 : fail:
491 0 : if (cli != NULL) {
492 0 : torture_close_connection(cli);
493 : }
494 0 : TALLOC_FREE(ev);
495 0 : if (loadfile != NULL) {
496 0 : fclose(loadfile);
497 0 : loadfile = NULL;
498 : }
499 0 : TALLOC_FREE(frame);
500 0 : return ret;
501 : }
|