summaryrefslogtreecommitdiff
path: root/source3/torture
diff options
context:
space:
mode:
Diffstat (limited to 'source3/torture')
-rw-r--r--source3/torture/nbench.c497
-rw-r--r--source3/torture/proto.h2
-rw-r--r--source3/torture/torture.c1
3 files changed, 500 insertions, 0 deletions
diff --git a/source3/torture/nbench.c b/source3/torture/nbench.c
new file mode 100644
index 0000000000..5a83c38a46
--- /dev/null
+++ b/source3/torture/nbench.c
@@ -0,0 +1,497 @@
+/*
+ Unix SMB/CIFS implementation.
+ In-memory cache
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/proto.h"
+
+static long long int ival(const char *str)
+{
+ return strtoll(str, NULL, 0);
+}
+
+struct nbench_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
+ const char *cliname;
+ FILE *loadfile;
+ struct ftable *ftable;
+ void (*bw_report)(size_t nread,
+ size_t nwritten,
+ void *private_data);
+ void *bw_report_private;
+};
+
+struct lock_info {
+ struct lock_info *next, *prev;
+ off_t offset;
+ int size;
+};
+
+struct createx_params {
+ char *fname;
+ unsigned int cr_options;
+ unsigned int cr_disposition;
+ int handle;
+};
+
+struct ftable {
+ struct ftable *next, *prev;
+ struct createx_params cp;
+ struct lock_info *locks;
+ uint16_t fnum; /* the fd that we got back from the server */
+};
+
+enum nbench_cmd {
+ NBENCH_CMD_NTCREATEX,
+ NBENCH_CMD_CLOSE,
+ NBENCH_CMD_RENAME,
+ NBENCH_CMD_UNLINK,
+ NBENCH_CMD_DELTREE,
+ NBENCH_CMD_RMDIR,
+ NBENCH_CMD_MKDIR,
+ NBENCH_CMD_QUERY_PATH_INFORMATION,
+ NBENCH_CMD_QUERY_FILE_INFORMATION,
+ NBENCH_CMD_QUERY_FS_INFORMATION,
+ NBENCH_CMD_SET_FILE_INFORMATION,
+ NBENCH_CMD_FIND_FIRST,
+ NBENCH_CMD_WRITEX,
+ NBENCH_CMD_WRITE,
+ NBENCH_CMD_LOCKX,
+ NBENCH_CMD_UNLOCKX,
+ NBENCH_CMD_READX,
+ NBENCH_CMD_FLUSH,
+ NBENCH_CMD_SLEEP,
+};
+
+struct nbench_cmd_struct {
+ char **params;
+ int num_params;
+ NTSTATUS status;
+ enum nbench_cmd cmd;
+};
+
+static struct nbench_cmd_struct *nbench_parse(TALLOC_CTX *mem_ctx,
+ const char *line)
+{
+ struct nbench_cmd_struct *result;
+ char *cmd;
+ char *status;
+
+ result = TALLOC_P(mem_ctx, struct nbench_cmd_struct);
+ if (result == NULL) {
+ return NULL;
+ }
+ result->params = str_list_make_shell(mem_ctx, line, " ");
+ if (result->params == NULL) {
+ goto fail;
+ }
+ result->num_params = talloc_array_length(result->params) - 1;
+ if (result->num_params < 2) {
+ goto fail;
+ }
+ status = result->params[result->num_params-1];
+ if (strncmp(status, "NT_STATUS_", 10) != 0 &&
+ strncmp(status, "0x", 2) != 0) {
+ goto fail;
+ }
+ /* accept numeric or string status codes */
+ if (strncmp(status, "0x", 2) == 0) {
+ result->status = NT_STATUS(strtoul(status, NULL, 16));
+ } else {
+ result->status = nt_status_string_to_code(status);
+ }
+
+ cmd = result->params[0];
+
+ if (!strcmp(cmd, "NTCreateX")) {
+ result->cmd = NBENCH_CMD_NTCREATEX;
+ } else if (!strcmp(cmd, "Close")) {
+ result->cmd = NBENCH_CMD_CLOSE;
+ } else if (!strcmp(cmd, "Rename")) {
+ result->cmd = NBENCH_CMD_RENAME;
+ } else if (!strcmp(cmd, "Unlink")) {
+ result->cmd = NBENCH_CMD_UNLINK;
+ } else if (!strcmp(cmd, "Deltree")) {
+ result->cmd = NBENCH_CMD_DELTREE;
+ } else if (!strcmp(cmd, "Rmdir")) {
+ result->cmd = NBENCH_CMD_RMDIR;
+ } else if (!strcmp(cmd, "Mkdir")) {
+ result->cmd = NBENCH_CMD_MKDIR;
+ } else if (!strcmp(cmd, "QUERY_PATH_INFORMATION")) {
+ result->cmd = NBENCH_CMD_QUERY_PATH_INFORMATION;
+ } else if (!strcmp(cmd, "QUERY_FILE_INFORMATION")) {
+ result->cmd = NBENCH_CMD_QUERY_FILE_INFORMATION;
+ } else if (!strcmp(cmd, "QUERY_FS_INFORMATION")) {
+ result->cmd = NBENCH_CMD_QUERY_FS_INFORMATION;
+ } else if (!strcmp(cmd, "SET_FILE_INFORMATION")) {
+ result->cmd = NBENCH_CMD_SET_FILE_INFORMATION;
+ } else if (!strcmp(cmd, "FIND_FIRST")) {
+ result->cmd = NBENCH_CMD_FIND_FIRST;
+ } else if (!strcmp(cmd, "WriteX")) {
+ result->cmd = NBENCH_CMD_WRITEX;
+ } else if (!strcmp(cmd, "Write")) {
+ result->cmd = NBENCH_CMD_WRITE;
+ } else if (!strcmp(cmd, "LockX")) {
+ result->cmd = NBENCH_CMD_LOCKX;
+ } else if (!strcmp(cmd, "UnlockX")) {
+ result->cmd = NBENCH_CMD_UNLOCKX;
+ } else if (!strcmp(cmd, "ReadX")) {
+ result->cmd = NBENCH_CMD_READX;
+ } else if (!strcmp(cmd, "Flush")) {
+ result->cmd = NBENCH_CMD_FLUSH;
+ } else if (!strcmp(cmd, "Sleep")) {
+ result->cmd = NBENCH_CMD_SLEEP;
+ } else {
+ goto fail;
+ }
+ return result;
+fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+static struct ftable *ft_find(struct ftable *ftlist, int handle)
+{
+ while (ftlist != NULL) {
+ if (ftlist->cp.handle == handle) {
+ return ftlist;
+ }
+ ftlist = ftlist->next;
+ }
+ return NULL;
+}
+
+struct nbench_cmd_state {
+ struct tevent_context *ev;
+ struct nbench_state *state;
+ struct nbench_cmd_struct *cmd;
+ struct ftable *ft;
+ bool eof;
+};
+
+static void nbench_cmd_done(struct tevent_req *subreq);
+
+static struct tevent_req *nbench_cmd_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct nbench_state *nb_state)
+{
+ struct tevent_req *req, *subreq;
+ struct nbench_cmd_state *state;
+ char line[1024];
+ size_t len;
+
+ req = tevent_req_create(mem_ctx, &state, struct nbench_cmd_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->state = nb_state;
+
+ if (fgets(line, sizeof(line), nb_state->loadfile) == NULL) {
+ tevent_req_nterror(req, NT_STATUS_END_OF_FILE);
+ return tevent_req_post(req, ev);
+ }
+ len = strlen(line);
+ if (len == 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+ if (line[len-1] == '\n') {
+ line[len-1] = '\0';
+ }
+
+ state->cmd = nbench_parse(state, line);
+ if (state->cmd == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ switch (state->cmd->cmd) {
+ case NBENCH_CMD_NTCREATEX: {
+ uint32_t desired_access;
+ uint32_t share_mode;
+ unsigned int flags = 0;
+
+ state->ft = talloc(state, struct ftable);
+ if (tevent_req_nomem(state->ft, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->ft->cp.fname = talloc_all_string_sub(
+ state->ft, state->cmd->params[1], "client1",
+ nb_state->cliname);
+ if (tevent_req_nomem(state->ft->cp.fname, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->ft->cp.cr_options = ival(state->cmd->params[2]);
+ state->ft->cp.cr_disposition = ival(state->cmd->params[3]);
+ state->ft->cp.handle = ival(state->cmd->params[4]);
+
+ if (state->ft->cp.cr_options & FILE_DIRECTORY_FILE) {
+ desired_access = SEC_FILE_READ_DATA;
+ } else {
+ desired_access =
+ SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA |
+ SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE;
+ flags = EXTENDED_RESPONSE_REQUIRED
+ | REQUEST_OPLOCK | REQUEST_BATCH_OPLOCK;
+ }
+ share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+ subreq = cli_ntcreate_send(
+ state, ev, nb_state->cli, state->ft->cp.fname, flags,
+ desired_access, 0, share_mode,
+ state->ft->cp.cr_disposition,
+ state->ft->cp.cr_options, 0);
+ break;
+ }
+ case NBENCH_CMD_CLOSE: {
+ state->ft = ft_find(state->state->ftable,
+ ival(state->cmd->params[1]));
+ if (state->ft == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+ subreq = cli_close_send(
+ state, ev, nb_state->cli, state->ft->fnum);
+ break;
+ }
+ case NBENCH_CMD_MKDIR: {
+ char *fname;
+ fname = talloc_all_string_sub(
+ state, state->cmd->params[1], "client1",
+ nb_state->cliname);
+ if (tevent_req_nomem(state->ft->cp.fname, req)) {
+ return tevent_req_post(req, ev);
+ }
+ subreq = cli_mkdir_send(state, ev, nb_state->cli, fname);
+ break;
+ }
+ case NBENCH_CMD_QUERY_PATH_INFORMATION: {
+ char *fname;
+ fname = talloc_all_string_sub(
+ state, state->cmd->params[1], "client1",
+ nb_state->cliname);
+ if (tevent_req_nomem(state->ft->cp.fname, req)) {
+ return tevent_req_post(req, ev);
+ }
+ subreq = cli_qpathinfo_send(state, ev, nb_state->cli, fname,
+ ival(state->cmd->params[2]),
+ 0, nb_state->cli->max_xmit);
+ break;
+ }
+ default:
+ tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
+ return tevent_req_post(req, ev);
+ }
+
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, nbench_cmd_done, req);
+ return req;
+}
+
+static bool status_wrong(struct tevent_req *req, NTSTATUS expected,
+ NTSTATUS status)
+{
+ if (NT_STATUS_EQUAL(expected, status)) {
+ return false;
+ }
+ if (NT_STATUS_IS_OK(status)) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ tevent_req_nterror(req, status);
+ return true;
+}
+
+static void nbench_cmd_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct nbench_cmd_state *state = tevent_req_data(
+ req, struct nbench_cmd_state);
+ struct nbench_state *nbstate = state->state;
+ NTSTATUS status;
+
+ switch (state->cmd->cmd) {
+ case NBENCH_CMD_NTCREATEX: {
+ struct ftable *ft;
+ status = cli_ntcreate_recv(subreq, &state->ft->fnum);
+ TALLOC_FREE(subreq);
+ if (status_wrong(req, state->cmd->status, status)) {
+ return;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_done(req);
+ return;
+ }
+ ft = talloc_move(nbstate, &state->ft);
+ DLIST_ADD(nbstate->ftable, ft);
+ break;
+ }
+ case NBENCH_CMD_CLOSE: {
+ status = cli_close_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (status_wrong(req, state->cmd->status, status)) {
+ return;
+ }
+ DLIST_REMOVE(state->state->ftable, state->ft);
+ TALLOC_FREE(state->ft);
+ break;
+ }
+ case NBENCH_CMD_MKDIR: {
+ status = cli_mkdir_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (status_wrong(req, state->cmd->status, status)) {
+ return;
+ }
+ break;
+ }
+ case NBENCH_CMD_QUERY_PATH_INFORMATION: {
+ status = cli_qpathinfo_recv(subreq, NULL, NULL, NULL);
+ TALLOC_FREE(subreq);
+ if (status_wrong(req, state->cmd->status, status)) {
+ return;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ tevent_req_done(req);
+}
+
+static NTSTATUS nbench_cmd_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static void nbench_done(struct tevent_req *subreq);
+
+static struct tevent_req *nbench_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+ const char *cliname, FILE *loadfile,
+ void (*bw_report)(size_t nread, size_t nwritten, void *private_data),
+ void *bw_report_private)
+{
+ struct tevent_req *req, *subreq;
+ struct nbench_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct nbench_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->cli = cli;
+ state->cliname = cliname;
+ state->loadfile = loadfile;
+ state->bw_report = bw_report;
+ state->bw_report_private = bw_report_private;
+
+ subreq = nbench_cmd_send(state, ev, state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, nbench_done, req);
+ return req;
+}
+
+static void nbench_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct nbench_state *state = tevent_req_data(
+ req, struct nbench_state);
+ NTSTATUS status;
+
+ status = nbench_cmd_recv(subreq);
+ TALLOC_FREE(subreq);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
+ tevent_req_done(req);
+ return;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ subreq = nbench_cmd_send(state, state->ev, state);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, nbench_done, req);
+}
+
+static NTSTATUS nbench_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+bool run_nbench2(int dummy)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct cli_state *cli = NULL;
+ FILE *loadfile;
+ bool ret = false;
+ struct tevent_req *req;
+ NTSTATUS status;
+
+ loadfile = fopen("client.txt", "r");
+ if (loadfile == NULL) {
+ fprintf(stderr, "Could not open \"client.txt\": %s\n",
+ strerror(errno));
+ return false;
+ }
+ ev = tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ if (!torture_open_connection(&cli, 0)) {
+ goto fail;
+ }
+
+ req = nbench_send(talloc_tos(), ev, cli, "client1", loadfile,
+ NULL, NULL);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll(req, ev)) {
+ goto fail;
+ }
+ status = nbench_recv(req);
+ TALLOC_FREE(req);
+ printf("nbench returned %s\n", nt_errstr(status));
+
+ ret = true;
+fail:
+ if (cli != NULL) {
+ torture_close_connection(cli);
+ }
+ TALLOC_FREE(ev);
+ if (loadfile != NULL) {
+ fclose(loadfile);
+ loadfile = NULL;
+ }
+ TALLOC_FREE(frame);
+ return ret;
+}
diff --git a/source3/torture/proto.h b/source3/torture/proto.h
index d78a39d85a..4f9a1807aa 100644
--- a/source3/torture/proto.h
+++ b/source3/torture/proto.h
@@ -83,4 +83,6 @@ bool torture_casetable(int dummy);
bool run_posix_append(int dummy);
+bool run_nbench2(int dummy);
+
#endif /* __TORTURE_H__ */
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 90cbf90c1a..79128cf4a6 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -7492,6 +7492,7 @@ static struct {
{"RANDOMIPC", run_randomipc, 0},
{"NEGNOWAIT", run_negprot_nowait, 0},
{"NBENCH", run_nbench, 0},
+ {"NBENCH2", run_nbench2, 0},
{"OPLOCK1", run_oplock1, 0},
{"OPLOCK2", run_oplock2, 0},
{"OPLOCK3", run_oplock3, 0},