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"
23 static long long int ival(const char *str
)
25 return strtoll(str
, NULL
, 0);
29 struct tevent_context
*ev
;
30 struct cli_state
*cli
;
33 struct ftable
*ftable
;
34 void (*bw_report
)(size_t nread
,
37 void *bw_report_private
;
41 struct lock_info
*next
, *prev
;
46 struct createx_params
{
48 unsigned int cr_options
;
49 unsigned int cr_disposition
;
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 */
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
,
82 struct nbench_cmd_struct
{
89 static struct nbench_cmd_struct
*nbench_parse(TALLOC_CTX
*mem_ctx
,
92 struct nbench_cmd_struct
*result
;
96 result
= TALLOC_P(mem_ctx
, struct nbench_cmd_struct
);
100 result
->params
= str_list_make_shell(mem_ctx
, line
, " ");
101 if (result
->params
== NULL
) {
104 result
->num_params
= talloc_array_length(result
->params
) - 1;
105 if (result
->num_params
< 2) {
108 status
= result
->params
[result
->num_params
-1];
109 if (strncmp(status
, "NT_STATUS_", 10) != 0 &&
110 strncmp(status
, "0x", 2) != 0) {
113 /* accept numeric or string status codes */
114 if (strncmp(status
, "0x", 2) == 0) {
115 result
->status
= NT_STATUS(strtoul(status
, NULL
, 16));
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
;
169 static struct ftable
*ft_find(struct ftable
*ftlist
, int handle
)
171 while (ftlist
!= NULL
) {
172 if (ftlist
->cp
.handle
== handle
) {
175 ftlist
= ftlist
->next
;
180 struct nbench_cmd_state
{
181 struct tevent_context
*ev
;
182 struct nbench_state
*state
;
183 struct nbench_cmd_struct
*cmd
;
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
;
199 req
= tevent_req_create(mem_ctx
, &state
, struct nbench_cmd_state
);
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
);
212 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
213 return tevent_req_post(req
, ev
);
215 if (line
[len
-1] == '\n') {
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
;
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",
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
;
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);
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
);
277 case NBENCH_CMD_MKDIR
: {
279 fname
= talloc_all_string_sub(
280 state
, state
->cmd
->params
[1], "client1",
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
);
288 case NBENCH_CMD_QUERY_PATH_INFORMATION
: {
290 fname
= talloc_all_string_sub(
291 state
, state
->cmd
->params
[1], "client1",
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
);
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
);
313 static bool status_wrong(struct tevent_req
*req
, NTSTATUS expected
,
316 if (NT_STATUS_EQUAL(expected
, status
)) {
319 if (NT_STATUS_IS_OK(status
)) {
320 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
322 tevent_req_nterror(req
, status
);
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
;
335 switch (state
->cmd
->cmd
) {
336 case NBENCH_CMD_NTCREATEX
: {
338 status
= cli_ntcreate_recv(subreq
, &state
->ft
->fnum
);
340 if (status_wrong(req
, state
->cmd
->status
, status
)) {
343 if (!NT_STATUS_IS_OK(status
)) {
344 tevent_req_done(req
);
347 ft
= talloc_move(nbstate
, &state
->ft
);
348 DLIST_ADD(nbstate
->ftable
, ft
);
351 case NBENCH_CMD_CLOSE
: {
352 status
= cli_close_recv(subreq
);
354 if (status_wrong(req
, state
->cmd
->status
, status
)) {
357 DLIST_REMOVE(state
->state
->ftable
, state
->ft
);
358 TALLOC_FREE(state
->ft
);
361 case NBENCH_CMD_MKDIR
: {
362 status
= cli_mkdir_recv(subreq
);
364 if (status_wrong(req
, state
->cmd
->status
, status
)) {
369 case NBENCH_CMD_QUERY_PATH_INFORMATION
: {
370 status
= cli_qpathinfo_recv(subreq
, NULL
, NULL
, NULL
);
372 if (status_wrong(req
, state
->cmd
->status
, status
)) {
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
);
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
);
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
);
426 status
= nbench_cmd_recv(subreq
);
429 if (NT_STATUS_EQUAL(status
, NT_STATUS_END_OF_FILE
)) {
430 tevent_req_done(req
);
433 if (!NT_STATUS_IS_OK(status
)) {
434 tevent_req_nterror(req
, status
);
437 subreq
= nbench_cmd_send(state
, state
->ev
, state
);
438 if (tevent_req_nomem(subreq
, req
)) {
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
;
456 struct tevent_req
*req
;
459 loadfile
= fopen("client.txt", "r");
460 if (loadfile
== NULL
) {
461 fprintf(stderr
, "Could not open \"client.txt\": %s\n",
465 ev
= tevent_context_init(talloc_tos());
469 if (!torture_open_connection(&cli
, 0)) {
473 req
= nbench_send(talloc_tos(), ev
, cli
, "client1", loadfile
,
478 if (!tevent_req_poll(req
, ev
)) {
481 status
= nbench_recv(req
);
483 printf("nbench returned %s\n", nt_errstr(status
));
488 torture_close_connection(cli
);
491 if (loadfile
!= NULL
) {