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 0 : struct nbench_cmd_struct *result;
96 0 : char *cmd;
97 0 : 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 0 : struct tevent_req *req, *subreq;
198 0 : struct nbench_cmd_state *state;
199 0 : char line[1024];
200 0 : 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 0 : uint32_t desired_access;
231 0 : 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(state,
278 : ev,
279 : nb_state->cli,
280 0 : state->ft->fnum,
281 : 0);
282 0 : break;
283 : }
284 0 : case NBENCH_CMD_MKDIR: {
285 0 : char *fname;
286 0 : fname = talloc_all_string_sub(
287 0 : state, state->cmd->params[1], "client1",
288 : nb_state->cliname);
289 0 : if (tevent_req_nomem(state->ft->cp.fname, req)) {
290 0 : return tevent_req_post(req, ev);
291 : }
292 0 : subreq = cli_mkdir_send(state, ev, nb_state->cli, fname);
293 0 : break;
294 : }
295 0 : case NBENCH_CMD_QUERY_PATH_INFORMATION: {
296 0 : char *fname;
297 0 : fname = talloc_all_string_sub(
298 0 : state, state->cmd->params[1], "client1",
299 : nb_state->cliname);
300 0 : if (tevent_req_nomem(state->ft->cp.fname, req)) {
301 0 : return tevent_req_post(req, ev);
302 : }
303 0 : subreq = cli_qpathinfo_send(state, ev, nb_state->cli, fname,
304 0 : ival(state->cmd->params[2]),
305 : 0, CLI_BUFFER_SIZE);
306 0 : break;
307 : }
308 0 : default:
309 0 : tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
310 0 : return tevent_req_post(req, ev);
311 : }
312 :
313 0 : if (tevent_req_nomem(subreq, req)) {
314 0 : return tevent_req_post(req, ev);
315 : }
316 0 : tevent_req_set_callback(subreq, nbench_cmd_done, req);
317 0 : return req;
318 : }
319 :
320 0 : static bool status_wrong(struct tevent_req *req, NTSTATUS expected,
321 : NTSTATUS status)
322 : {
323 0 : if (NT_STATUS_EQUAL(expected, status)) {
324 0 : return false;
325 : }
326 0 : if (NT_STATUS_IS_OK(status)) {
327 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
328 : }
329 0 : tevent_req_nterror(req, status);
330 0 : return true;
331 : }
332 :
333 0 : static void nbench_cmd_done(struct tevent_req *subreq)
334 : {
335 0 : struct tevent_req *req = tevent_req_callback_data(
336 : subreq, struct tevent_req);
337 0 : struct nbench_cmd_state *state = tevent_req_data(
338 : req, struct nbench_cmd_state);
339 0 : struct nbench_state *nbstate = state->state;
340 0 : NTSTATUS status;
341 :
342 0 : switch (state->cmd->cmd) {
343 0 : case NBENCH_CMD_NTCREATEX: {
344 0 : struct ftable *ft;
345 0 : status = cli_ntcreate_recv(subreq, &state->ft->fnum, NULL);
346 0 : TALLOC_FREE(subreq);
347 0 : if (status_wrong(req, state->cmd->status, status)) {
348 0 : return;
349 : }
350 0 : if (!NT_STATUS_IS_OK(status)) {
351 0 : tevent_req_done(req);
352 0 : return;
353 : }
354 0 : ft = talloc_move(nbstate, &state->ft);
355 0 : DLIST_ADD(nbstate->ftable, ft);
356 0 : break;
357 : }
358 0 : case NBENCH_CMD_CLOSE: {
359 0 : status = cli_close_recv(subreq);
360 0 : TALLOC_FREE(subreq);
361 0 : if (status_wrong(req, state->cmd->status, status)) {
362 0 : return;
363 : }
364 0 : DLIST_REMOVE(state->state->ftable, state->ft);
365 0 : TALLOC_FREE(state->ft);
366 0 : break;
367 : }
368 0 : case NBENCH_CMD_MKDIR: {
369 0 : status = cli_mkdir_recv(subreq);
370 0 : TALLOC_FREE(subreq);
371 0 : if (status_wrong(req, state->cmd->status, status)) {
372 0 : return;
373 : }
374 0 : break;
375 : }
376 0 : case NBENCH_CMD_QUERY_PATH_INFORMATION: {
377 0 : status = cli_qpathinfo_recv(subreq, NULL, NULL, NULL);
378 0 : TALLOC_FREE(subreq);
379 0 : if (status_wrong(req, state->cmd->status, status)) {
380 0 : return;
381 : }
382 0 : break;
383 : }
384 0 : default:
385 0 : break;
386 : }
387 0 : tevent_req_done(req);
388 : }
389 :
390 0 : static NTSTATUS nbench_cmd_recv(struct tevent_req *req)
391 : {
392 0 : return tevent_req_simple_recv_ntstatus(req);
393 : }
394 :
395 : static void nbench_done(struct tevent_req *subreq);
396 :
397 0 : static struct tevent_req *nbench_send(
398 : TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
399 : const char *cliname, FILE *loadfile,
400 : void (*bw_report)(size_t nread, size_t nwritten, void *private_data),
401 : void *bw_report_private)
402 : {
403 0 : struct tevent_req *req, *subreq;
404 0 : struct nbench_state *state;
405 :
406 0 : req = tevent_req_create(mem_ctx, &state, struct nbench_state);
407 0 : if (req == NULL) {
408 0 : return NULL;
409 : }
410 0 : state->ev = ev;
411 0 : state->cli = cli;
412 0 : state->cliname = cliname;
413 0 : state->loadfile = loadfile;
414 0 : state->bw_report = bw_report;
415 0 : state->bw_report_private = bw_report_private;
416 :
417 0 : subreq = nbench_cmd_send(state, ev, state);
418 0 : if (tevent_req_nomem(subreq, req)) {
419 0 : return tevent_req_post(req, ev);
420 : }
421 0 : tevent_req_set_callback(subreq, nbench_done, req);
422 0 : return req;
423 : }
424 :
425 0 : static void nbench_done(struct tevent_req *subreq)
426 : {
427 0 : struct tevent_req *req = tevent_req_callback_data(
428 : subreq, struct tevent_req);
429 0 : struct nbench_state *state = tevent_req_data(
430 : req, struct nbench_state);
431 0 : NTSTATUS status;
432 :
433 0 : status = nbench_cmd_recv(subreq);
434 0 : TALLOC_FREE(subreq);
435 :
436 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
437 0 : tevent_req_done(req);
438 0 : return;
439 : }
440 0 : if (!NT_STATUS_IS_OK(status)) {
441 0 : tevent_req_nterror(req, status);
442 0 : return;
443 : }
444 0 : subreq = nbench_cmd_send(state, state->ev, state);
445 0 : if (tevent_req_nomem(subreq, req)) {
446 0 : return;
447 : }
448 0 : tevent_req_set_callback(subreq, nbench_done, req);
449 : }
450 :
451 0 : static NTSTATUS nbench_recv(struct tevent_req *req)
452 : {
453 0 : return tevent_req_simple_recv_ntstatus(req);
454 : }
455 :
456 0 : bool run_nbench2(int dummy)
457 : {
458 0 : TALLOC_CTX *frame = talloc_stackframe();
459 0 : struct tevent_context *ev;
460 0 : struct cli_state *cli = NULL;
461 0 : FILE *loadfile;
462 0 : bool ret = false;
463 0 : struct tevent_req *req;
464 0 : NTSTATUS status;
465 :
466 0 : loadfile = fopen("client.txt", "r");
467 0 : if (loadfile == NULL) {
468 0 : fprintf(stderr, "Could not open \"client.txt\": %s\n",
469 0 : strerror(errno));
470 0 : return false;
471 : }
472 0 : ev = samba_tevent_context_init(talloc_tos());
473 0 : if (ev == NULL) {
474 0 : goto fail;
475 : }
476 0 : if (!torture_open_connection(&cli, 0)) {
477 0 : goto fail;
478 : }
479 :
480 0 : req = nbench_send(talloc_tos(), ev, cli, "client1", loadfile,
481 : NULL, NULL);
482 0 : if (req == NULL) {
483 0 : goto fail;
484 : }
485 0 : if (!tevent_req_poll(req, ev)) {
486 0 : goto fail;
487 : }
488 0 : status = nbench_recv(req);
489 0 : TALLOC_FREE(req);
490 0 : printf("nbench returned %s\n", nt_errstr(status));
491 :
492 0 : ret = true;
493 0 : fail:
494 0 : if (cli != NULL) {
495 0 : torture_close_connection(cli);
496 : }
497 0 : TALLOC_FREE(ev);
498 0 : if (loadfile != NULL) {
499 0 : fclose(loadfile);
500 0 : loadfile = NULL;
501 : }
502 0 : TALLOC_FREE(frame);
503 0 : return ret;
504 : }
|