libsmb: Pass NTTIME to interpret_long_date()
[samba.git] / source3 / torture / nbench.c
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 static long long int ival(const char *str)
27 {
28         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 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         result = talloc(mem_ctx, struct nbench_cmd_struct);
100         if (result == NULL) {
101                 return NULL;
102         }
103         result->params = str_list_make_shell(mem_ctx, line, " ");
104         if (result->params == NULL) {
105                 goto fail;
106         }
107         result->num_params = talloc_array_length(result->params) - 1;
108         if (result->num_params < 2) {
109                 goto fail;
110         }
111         status = result->params[result->num_params-1];
112         if (strncmp(status, "NT_STATUS_", 10) != 0 &&
113             strncmp(status, "0x", 2) != 0) {
114                 goto fail;
115         }
116         /* accept numeric or string status codes */
117         if (strncmp(status, "0x", 2) == 0) {
118                 result->status = NT_STATUS(strtoul(status, NULL, 16));
119         } else {
120                 result->status = nt_status_string_to_code(status);
121         }
122
123         cmd = result->params[0];
124
125         if (!strcmp(cmd, "NTCreateX")) {
126                 result->cmd = NBENCH_CMD_NTCREATEX;
127         } else if (!strcmp(cmd, "Close")) {
128                 result->cmd = NBENCH_CMD_CLOSE;
129         } else if (!strcmp(cmd, "Rename")) {
130                 result->cmd = NBENCH_CMD_RENAME;
131         } else if (!strcmp(cmd, "Unlink")) {
132                 result->cmd = NBENCH_CMD_UNLINK;
133         } else if (!strcmp(cmd, "Deltree")) {
134                 result->cmd = NBENCH_CMD_DELTREE;
135         } else if (!strcmp(cmd, "Rmdir")) {
136                 result->cmd = NBENCH_CMD_RMDIR;
137         } else if (!strcmp(cmd, "Mkdir")) {
138                 result->cmd = NBENCH_CMD_MKDIR;
139         } else if (!strcmp(cmd, "QUERY_PATH_INFORMATION")) {
140                 result->cmd = NBENCH_CMD_QUERY_PATH_INFORMATION;
141         } else if (!strcmp(cmd, "QUERY_FILE_INFORMATION")) {
142                 result->cmd = NBENCH_CMD_QUERY_FILE_INFORMATION;
143         } else if (!strcmp(cmd, "QUERY_FS_INFORMATION")) {
144                 result->cmd = NBENCH_CMD_QUERY_FS_INFORMATION;
145         } else if (!strcmp(cmd, "SET_FILE_INFORMATION")) {
146                 result->cmd = NBENCH_CMD_SET_FILE_INFORMATION;
147         } else if (!strcmp(cmd, "FIND_FIRST")) {
148                 result->cmd = NBENCH_CMD_FIND_FIRST;
149         } else if (!strcmp(cmd, "WriteX")) {
150                 result->cmd = NBENCH_CMD_WRITEX;
151         } else if (!strcmp(cmd, "Write")) {
152                 result->cmd = NBENCH_CMD_WRITE;
153         } else if (!strcmp(cmd, "LockX")) {
154                 result->cmd = NBENCH_CMD_LOCKX;
155         } else if (!strcmp(cmd, "UnlockX")) {
156                 result->cmd = NBENCH_CMD_UNLOCKX;
157         } else if (!strcmp(cmd, "ReadX")) {
158                 result->cmd = NBENCH_CMD_READX;
159         } else if (!strcmp(cmd, "Flush")) {
160                 result->cmd = NBENCH_CMD_FLUSH;
161         } else if (!strcmp(cmd, "Sleep")) {
162                 result->cmd = NBENCH_CMD_SLEEP;
163         } else {
164                 goto fail;
165         }
166         return result;
167 fail:
168         TALLOC_FREE(result);
169         return NULL;
170 }
171
172 static struct ftable *ft_find(struct ftable *ftlist, int handle)
173 {
174         while (ftlist != NULL) {
175                 if (ftlist->cp.handle == handle) {
176                         return ftlist;
177                 }
178                 ftlist = ftlist->next;
179         }
180         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 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         req = tevent_req_create(mem_ctx, &state, struct nbench_cmd_state);
203         if (req == NULL) {
204                 return NULL;
205         }
206         state->ev = ev;
207         state->state = nb_state;
208
209         if (fgets(line, sizeof(line), nb_state->loadfile) == NULL) {
210                 tevent_req_nterror(req, NT_STATUS_END_OF_FILE);
211                 return tevent_req_post(req, ev);
212         }
213         len = strlen(line);
214         if (len == 0) {
215                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
216                 return tevent_req_post(req, ev);
217         }
218         if (line[len-1] == '\n') {
219                 line[len-1] = '\0';
220         }
221
222         state->cmd = nbench_parse(state, line);
223         if (state->cmd == NULL) {
224                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
225                 return tevent_req_post(req, ev);
226         }
227
228         switch (state->cmd->cmd) {
229         case NBENCH_CMD_NTCREATEX: {
230                 uint32_t desired_access;
231                 uint32_t share_mode;
232                 unsigned int flags = 0;
233
234                 state->ft = talloc(state, struct ftable);
235                 if (tevent_req_nomem(state->ft, req)) {
236                         return tevent_req_post(req, ev);
237                 }
238
239                 state->ft->cp.fname = talloc_all_string_sub(
240                         state->ft, state->cmd->params[1], "client1",
241                         nb_state->cliname);
242                 if (tevent_req_nomem(state->ft->cp.fname, req)) {
243                         return tevent_req_post(req, ev);
244                 }
245                 state->ft->cp.cr_options = ival(state->cmd->params[2]);
246                 state->ft->cp.cr_disposition = ival(state->cmd->params[3]);
247                 state->ft->cp.handle = ival(state->cmd->params[4]);
248
249                 if (state->ft->cp.cr_options & FILE_DIRECTORY_FILE) {
250                         desired_access = SEC_FILE_READ_DATA;
251                 } else {
252                         desired_access =
253                                 SEC_FILE_READ_DATA |
254                                 SEC_FILE_WRITE_DATA |
255                                 SEC_FILE_READ_ATTRIBUTE |
256                                 SEC_FILE_WRITE_ATTRIBUTE;
257                         flags = EXTENDED_RESPONSE_REQUIRED
258                                 | REQUEST_OPLOCK | REQUEST_BATCH_OPLOCK;
259                 }
260                 share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
261
262                 subreq = cli_ntcreate_send(
263                         state, ev, nb_state->cli, state->ft->cp.fname, flags,
264                         desired_access, 0, share_mode,
265                         state->ft->cp.cr_disposition,
266                         state->ft->cp.cr_options,
267                         SMB2_IMPERSONATION_IMPERSONATION, 0);
268                 break;
269         }
270         case NBENCH_CMD_CLOSE: {
271                 state->ft = ft_find(state->state->ftable,
272                                     ival(state->cmd->params[1]));
273                 if (state->ft == NULL) {
274                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
275                         return tevent_req_post(req, ev);
276                 }
277                 subreq = cli_close_send(
278                         state, ev, nb_state->cli, state->ft->fnum);
279                 break;
280         }
281         case NBENCH_CMD_MKDIR: {
282                 char *fname;
283                 fname = talloc_all_string_sub(
284                         state, state->cmd->params[1], "client1",
285                         nb_state->cliname);
286                 if (tevent_req_nomem(state->ft->cp.fname, req)) {
287                         return tevent_req_post(req, ev);
288                 }
289                 subreq = cli_mkdir_send(state, ev, nb_state->cli, fname);
290                 break;
291         }
292         case NBENCH_CMD_QUERY_PATH_INFORMATION: {
293                 char *fname;
294                 fname = talloc_all_string_sub(
295                         state, state->cmd->params[1], "client1",
296                         nb_state->cliname);
297                 if (tevent_req_nomem(state->ft->cp.fname, req)) {
298                         return tevent_req_post(req, ev);
299                 }
300                 subreq = cli_qpathinfo_send(state, ev, nb_state->cli, fname,
301                                             ival(state->cmd->params[2]),
302                                             0, CLI_BUFFER_SIZE);
303                 break;
304         }
305         default:
306                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
307                 return tevent_req_post(req, ev);
308         }
309
310         if (tevent_req_nomem(subreq, req)) {
311                 return tevent_req_post(req, ev);
312         }
313         tevent_req_set_callback(subreq, nbench_cmd_done, req);
314         return req;
315 }
316
317 static bool status_wrong(struct tevent_req *req, NTSTATUS expected,
318                          NTSTATUS status)
319 {
320         if (NT_STATUS_EQUAL(expected, status)) {
321                 return false;
322         }
323         if (NT_STATUS_IS_OK(status)) {
324                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
325         }
326         tevent_req_nterror(req, status);
327         return true;
328 }
329
330 static void nbench_cmd_done(struct tevent_req *subreq)
331 {
332         struct tevent_req *req = tevent_req_callback_data(
333                 subreq, struct tevent_req);
334         struct nbench_cmd_state *state = tevent_req_data(
335                 req, struct nbench_cmd_state);
336         struct nbench_state *nbstate = state->state;
337         NTSTATUS status;
338
339         switch (state->cmd->cmd) {
340         case NBENCH_CMD_NTCREATEX: {
341                 struct ftable *ft;
342                 status = cli_ntcreate_recv(subreq, &state->ft->fnum, NULL);
343                 TALLOC_FREE(subreq);
344                 if (status_wrong(req, state->cmd->status, status)) {
345                         return;
346                 }
347                 if (!NT_STATUS_IS_OK(status)) {
348                         tevent_req_done(req);
349                         return;
350                 }
351                 ft = talloc_move(nbstate, &state->ft);
352                 DLIST_ADD(nbstate->ftable, ft);
353                 break;
354         }
355         case NBENCH_CMD_CLOSE: {
356                 status = cli_close_recv(subreq);
357                 TALLOC_FREE(subreq);
358                 if (status_wrong(req, state->cmd->status, status)) {
359                         return;
360                 }
361                 DLIST_REMOVE(state->state->ftable, state->ft);
362                 TALLOC_FREE(state->ft);
363                 break;
364         }
365         case NBENCH_CMD_MKDIR: {
366                 status = cli_mkdir_recv(subreq);
367                 TALLOC_FREE(subreq);
368                 if (status_wrong(req, state->cmd->status, status)) {
369                         return;
370                 }
371                 break;
372         }
373         case NBENCH_CMD_QUERY_PATH_INFORMATION: {
374                 status = cli_qpathinfo_recv(subreq, NULL, NULL, NULL);
375                 TALLOC_FREE(subreq);
376                 if (status_wrong(req, state->cmd->status, status)) {
377                         return;
378                 }
379                 break;
380         }
381         default:
382                 break;
383         }
384         tevent_req_done(req);
385 }
386
387 static NTSTATUS nbench_cmd_recv(struct tevent_req *req)
388 {
389         return tevent_req_simple_recv_ntstatus(req);
390 }
391
392 static void nbench_done(struct tevent_req *subreq);
393
394 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         req = tevent_req_create(mem_ctx, &state, struct nbench_state);
404         if (req == NULL) {
405                 return NULL;
406         }
407         state->ev = ev;
408         state->cli = cli;
409         state->cliname = cliname;
410         state->loadfile = loadfile;
411         state->bw_report = bw_report;
412         state->bw_report_private = bw_report_private;
413
414         subreq = nbench_cmd_send(state, ev, state);
415         if (tevent_req_nomem(subreq, req)) {
416                 return tevent_req_post(req, ev);
417         }
418         tevent_req_set_callback(subreq, nbench_done, req);
419         return req;
420 }
421
422 static void nbench_done(struct tevent_req *subreq)
423 {
424         struct tevent_req *req = tevent_req_callback_data(
425                 subreq, struct tevent_req);
426         struct nbench_state *state = tevent_req_data(
427                 req, struct nbench_state);
428         NTSTATUS status;
429
430         status = nbench_cmd_recv(subreq);
431         TALLOC_FREE(subreq);
432
433         if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
434                 tevent_req_done(req);
435                 return;
436         }
437         if (!NT_STATUS_IS_OK(status)) {
438                 tevent_req_nterror(req, status);
439                 return;
440         }
441         subreq = nbench_cmd_send(state, state->ev, state);
442         if (tevent_req_nomem(subreq, req)) {
443                 return;
444         }
445         tevent_req_set_callback(subreq, nbench_done, req);
446 }
447
448 static NTSTATUS nbench_recv(struct tevent_req *req)
449 {
450         return tevent_req_simple_recv_ntstatus(req);
451 }
452
453 bool run_nbench2(int dummy)
454 {
455         TALLOC_CTX *frame = talloc_stackframe();
456         struct tevent_context *ev;
457         struct cli_state *cli = NULL;
458         FILE *loadfile;
459         bool ret = false;
460         struct tevent_req *req;
461         NTSTATUS status;
462
463         loadfile = fopen("client.txt", "r");
464         if (loadfile == NULL) {
465                 fprintf(stderr, "Could not open \"client.txt\": %s\n",
466                         strerror(errno));
467                 return false;
468         }
469         ev = samba_tevent_context_init(talloc_tos());
470         if (ev == NULL) {
471                 goto fail;
472         }
473         if (!torture_open_connection(&cli, 0)) {
474                 goto fail;
475         }
476
477         req = nbench_send(talloc_tos(), ev, cli, "client1", loadfile,
478                           NULL, NULL);
479         if (req == NULL) {
480                 goto fail;
481         }
482         if (!tevent_req_poll(req, ev)) {
483                 goto fail;
484         }
485         status = nbench_recv(req);
486         TALLOC_FREE(req);
487         printf("nbench returned %s\n", nt_errstr(status));
488
489         ret = true;
490 fail:
491         if (cli != NULL) {
492                 torture_close_connection(cli);
493         }
494         TALLOC_FREE(ev);
495         if (loadfile != NULL) {
496                 fclose(loadfile);
497                 loadfile = NULL;
498         }
499         TALLOC_FREE(frame);
500         return ret;
501 }