2 Unix SMB/CIFS implementation.
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/>.
21 #include "torture/proto.h"
22 #include "libsmb/libsmb.h"
23 #include "libsmb/clirap.h"
24 #include "../lib/util/tevent_ntstatus.h"
26 static long long int ival(const char *str
)
28 return strtoll(str
, NULL
, 0);
32 struct tevent_context
*ev
;
33 struct cli_state
*cli
;
36 struct ftable
*ftable
;
37 void (*bw_report
)(size_t nread
,
40 void *bw_report_private
;
44 struct lock_info
*next
, *prev
;
49 struct createx_params
{
51 unsigned int cr_options
;
52 unsigned int cr_disposition
;
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 */
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
,
85 struct nbench_cmd_struct
{
92 static struct nbench_cmd_struct
*nbench_parse(TALLOC_CTX
*mem_ctx
,
95 struct nbench_cmd_struct
*result
;
99 result
= talloc(mem_ctx
, struct nbench_cmd_struct
);
100 if (result
== NULL
) {
103 result
->params
= str_list_make_shell(mem_ctx
, line
, " ");
104 if (result
->params
== NULL
) {
107 result
->num_params
= talloc_array_length(result
->params
) - 1;
108 if (result
->num_params
< 2) {
111 status
= result
->params
[result
->num_params
-1];
112 if (strncmp(status
, "NT_STATUS_", 10) != 0 &&
113 strncmp(status
, "0x", 2) != 0) {
116 /* accept numeric or string status codes */
117 if (strncmp(status
, "0x", 2) == 0) {
118 result
->status
= NT_STATUS(strtoul(status
, NULL
, 16));
120 result
->status
= nt_status_string_to_code(status
);
123 cmd
= result
->params
[0];
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
;
172 static struct ftable
*ft_find(struct ftable
*ftlist
, int handle
)
174 while (ftlist
!= NULL
) {
175 if (ftlist
->cp
.handle
== handle
) {
178 ftlist
= ftlist
->next
;
183 struct nbench_cmd_state
{
184 struct tevent_context
*ev
;
185 struct nbench_state
*state
;
186 struct nbench_cmd_struct
*cmd
;
191 static void nbench_cmd_done(struct tevent_req
*subreq
);
193 static struct tevent_req
*nbench_cmd_send(TALLOC_CTX
*mem_ctx
,
194 struct tevent_context
*ev
,
195 struct nbench_state
*nb_state
)
197 struct tevent_req
*req
, *subreq
;
198 struct nbench_cmd_state
*state
;
202 req
= tevent_req_create(mem_ctx
, &state
, struct nbench_cmd_state
);
207 state
->state
= nb_state
;
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
);
215 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
216 return tevent_req_post(req
, ev
);
218 if (line
[len
-1] == '\n') {
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
);
228 switch (state
->cmd
->cmd
) {
229 case NBENCH_CMD_NTCREATEX
: {
230 uint32_t desired_access
;
232 unsigned int flags
= 0;
234 state
->ft
= talloc(state
, struct ftable
);
235 if (tevent_req_nomem(state
->ft
, req
)) {
236 return tevent_req_post(req
, ev
);
239 state
->ft
->cp
.fname
= talloc_all_string_sub(
240 state
->ft
, state
->cmd
->params
[1], "client1",
242 if (tevent_req_nomem(state
->ft
->cp
.fname
, req
)) {
243 return tevent_req_post(req
, ev
);
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]);
249 if (state
->ft
->cp
.cr_options
& FILE_DIRECTORY_FILE
) {
250 desired_access
= 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
;
260 share_mode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
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);
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
);
277 subreq
= cli_close_send(
278 state
, ev
, nb_state
->cli
, state
->ft
->fnum
);
281 case NBENCH_CMD_MKDIR
: {
283 fname
= talloc_all_string_sub(
284 state
, state
->cmd
->params
[1], "client1",
286 if (tevent_req_nomem(state
->ft
->cp
.fname
, req
)) {
287 return tevent_req_post(req
, ev
);
289 subreq
= cli_mkdir_send(state
, ev
, nb_state
->cli
, fname
);
292 case NBENCH_CMD_QUERY_PATH_INFORMATION
: {
294 fname
= talloc_all_string_sub(
295 state
, state
->cmd
->params
[1], "client1",
297 if (tevent_req_nomem(state
->ft
->cp
.fname
, req
)) {
298 return tevent_req_post(req
, ev
);
300 subreq
= cli_qpathinfo_send(state
, ev
, nb_state
->cli
, fname
,
301 ival(state
->cmd
->params
[2]),
306 tevent_req_nterror(req
, NT_STATUS_NOT_IMPLEMENTED
);
307 return tevent_req_post(req
, ev
);
310 if (tevent_req_nomem(subreq
, req
)) {
311 return tevent_req_post(req
, ev
);
313 tevent_req_set_callback(subreq
, nbench_cmd_done
, req
);
317 static bool status_wrong(struct tevent_req
*req
, NTSTATUS expected
,
320 if (NT_STATUS_EQUAL(expected
, status
)) {
323 if (NT_STATUS_IS_OK(status
)) {
324 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
326 tevent_req_nterror(req
, status
);
330 static void nbench_cmd_done(struct tevent_req
*subreq
)
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
;
339 switch (state
->cmd
->cmd
) {
340 case NBENCH_CMD_NTCREATEX
: {
342 status
= cli_ntcreate_recv(subreq
, &state
->ft
->fnum
, NULL
);
344 if (status_wrong(req
, state
->cmd
->status
, status
)) {
347 if (!NT_STATUS_IS_OK(status
)) {
348 tevent_req_done(req
);
351 ft
= talloc_move(nbstate
, &state
->ft
);
352 DLIST_ADD(nbstate
->ftable
, ft
);
355 case NBENCH_CMD_CLOSE
: {
356 status
= cli_close_recv(subreq
);
358 if (status_wrong(req
, state
->cmd
->status
, status
)) {
361 DLIST_REMOVE(state
->state
->ftable
, state
->ft
);
362 TALLOC_FREE(state
->ft
);
365 case NBENCH_CMD_MKDIR
: {
366 status
= cli_mkdir_recv(subreq
);
368 if (status_wrong(req
, state
->cmd
->status
, status
)) {
373 case NBENCH_CMD_QUERY_PATH_INFORMATION
: {
374 status
= cli_qpathinfo_recv(subreq
, NULL
, NULL
, NULL
);
376 if (status_wrong(req
, state
->cmd
->status
, status
)) {
384 tevent_req_done(req
);
387 static NTSTATUS
nbench_cmd_recv(struct tevent_req
*req
)
389 return tevent_req_simple_recv_ntstatus(req
);
392 static void nbench_done(struct tevent_req
*subreq
);
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
)
400 struct tevent_req
*req
, *subreq
;
401 struct nbench_state
*state
;
403 req
= tevent_req_create(mem_ctx
, &state
, struct nbench_state
);
409 state
->cliname
= cliname
;
410 state
->loadfile
= loadfile
;
411 state
->bw_report
= bw_report
;
412 state
->bw_report_private
= bw_report_private
;
414 subreq
= nbench_cmd_send(state
, ev
, state
);
415 if (tevent_req_nomem(subreq
, req
)) {
416 return tevent_req_post(req
, ev
);
418 tevent_req_set_callback(subreq
, nbench_done
, req
);
422 static void nbench_done(struct tevent_req
*subreq
)
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
);
430 status
= nbench_cmd_recv(subreq
);
433 if (NT_STATUS_EQUAL(status
, NT_STATUS_END_OF_FILE
)) {
434 tevent_req_done(req
);
437 if (!NT_STATUS_IS_OK(status
)) {
438 tevent_req_nterror(req
, status
);
441 subreq
= nbench_cmd_send(state
, state
->ev
, state
);
442 if (tevent_req_nomem(subreq
, req
)) {
445 tevent_req_set_callback(subreq
, nbench_done
, req
);
448 static NTSTATUS
nbench_recv(struct tevent_req
*req
)
450 return tevent_req_simple_recv_ntstatus(req
);
453 bool run_nbench2(int dummy
)
455 TALLOC_CTX
*frame
= talloc_stackframe();
456 struct tevent_context
*ev
;
457 struct cli_state
*cli
= NULL
;
460 struct tevent_req
*req
;
463 loadfile
= fopen("client.txt", "r");
464 if (loadfile
== NULL
) {
465 fprintf(stderr
, "Could not open \"client.txt\": %s\n",
469 ev
= samba_tevent_context_init(talloc_tos());
473 if (!torture_open_connection(&cli
, 0)) {
477 req
= nbench_send(talloc_tos(), ev
, cli
, "client1", loadfile
,
482 if (!tevent_req_poll(req
, ev
)) {
485 status
= nbench_recv(req
);
487 printf("nbench returned %s\n", nt_errstr(status
));
492 torture_close_connection(cli
);
495 if (loadfile
!= NULL
) {