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 2 of the License, or
+ 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,
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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "lib/cmdline/popt_common.h"
#include "libcli/composite/composite.h"
#include "libcli/smb_composite/smb_composite.h"
+#include "libcli/resolve/resolve.h"
+#include "param/param.h"
#define BASEDIR "\\benchopen"
static int open_retries;
static char **fnames;
static int num_connected;
+static struct timed_event *report_te;
struct benchopen_state {
+ struct torture_context *tctx;
TALLOC_CTX *mem_ctx;
struct event_context *ev;
struct smbcli_state *cli;
struct smbcli_tree *tree;
int client_num;
+ int old_fnum;
int fnum;
int file_num;
int count;
int lastcount;
- BOOL waiting_open, waiting_close;
union smb_open open_parms;
union smb_close close_parms;
struct smbcli_request *req_open;
struct smbcli_request *req_close;
struct smb_composite_connect reconnect;
+ struct timed_event *te;
/* these are used for reconnections */
- int dest_port;
+ const char **dest_ports;
const char *dest_host;
const char *called_name;
const char *service_type;
status = smb_composite_connect_recv(ctx, state->mem_ctx);
if (!NT_STATUS_IS_OK(status)) {
- event_add_timed(state->ev, state->mem_ctx,
- timeval_current_ofs(1,0),
- reopen_connection, state);
+ talloc_free(state->te);
+ state->te = event_add_timed(state->ev, state->mem_ctx,
+ timeval_current_ofs(1,0),
+ reopen_connection, state);
return;
}
DEBUG(0,("reconnect to %s finished (%u connected)\n", state->dest_host,
num_connected));
+ state->fnum = -1;
+ state->old_fnum = -1;
next_open(state);
}
struct smb_composite_connect *io = &state->reconnect;
char *host, *share;
- if (!torture_get_conn_index(state->client_num, state->mem_ctx, &host, &share)) {
+ state->te = NULL;
+
+ if (!torture_get_conn_index(state->client_num, state->mem_ctx, state->tctx, &host, &share)) {
DEBUG(0,("Can't find host/share for reconnect?!\n"));
exit(1);
}
io->in.dest_host = state->dest_host;
- io->in.port = state->dest_port;
+ io->in.dest_ports = state->dest_ports;
io->in.called_name = state->called_name;
io->in.service = share;
io->in.service_type = state->service_type;
io->in.credentials = cmdline_credentials;
- io->in.fallback_to_anonymous = False;
- io->in.workgroup = lp_workgroup();
+ io->in.fallback_to_anonymous = false;
+ io->in.workgroup = lp_workgroup(state->tctx->lp_ctx);
+ lp_smbcli_options(state->tctx->lp_ctx, &io->in.options);
/* kill off the remnants of the old connection */
talloc_free(state->tree);
state->tree = NULL;
state->fnum = -1;
- state->waiting_open = False;
- state->waiting_close = False;
- ctx = smb_composite_connect_send(io, state->mem_ctx, state->ev);
+ ctx = smb_composite_connect_send(io, state->mem_ctx,
+ lp_resolve_context(state->tctx->lp_ctx),
+ state->ev);
if (ctx == NULL) {
DEBUG(0,("Failed to setup async reconnect\n"));
exit(1);
{
state->count++;
- state->file_num = (state->file_num+1) % (nprocs+1);
+ state->file_num = (state->file_num+1) % (3*nprocs);
+
+ DEBUG(2,("[%d] opening %u\n", state->client_num, state->file_num));
state->open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
state->open_parms.ntcreatex.in.flags = 0;
state->open_parms.ntcreatex.in.root_fid = 0;
state->req_open = smb_raw_open_send(state->tree, &state->open_parms);
state->req_open->async.fn = open_completed;
state->req_open->async.private = state;
- state->waiting_open = True;
+}
- if (state->fnum == -1) {
+
+static void next_close(struct benchopen_state *state)
+{
+ DEBUG(2,("[%d] closing %d\n", state->client_num, state->old_fnum));
+ if (state->old_fnum == -1) {
return;
}
-
state->close_parms.close.level = RAW_CLOSE_CLOSE;
- state->close_parms.close.in.file.fnum = state->fnum;
+ state->close_parms.close.in.file.fnum = state->old_fnum;
state->close_parms.close.in.write_time = 0;
state->req_close = smb_raw_close_send(state->tree, &state->close_parms);
state->req_close->async.fn = close_completed;
state->req_close->async.private = state;
- state->waiting_close = True;
+ state->old_fnum = -1;
}
/*
state->cli = NULL;
num_connected--;
DEBUG(0,("reopening connection to %s\n", state->dest_host));
- event_add_timed(state->ev, state->mem_ctx,
- timeval_current_ofs(1,0),
- reopen_connection, state);
+ talloc_free(state->te);
+ state->te = event_add_timed(state->ev, state->mem_ctx,
+ timeval_current_ofs(1,0),
+ reopen_connection, state);
return;
}
if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+ DEBUG(2,("[%d] retrying open\n", state->client_num));
open_retries++;
state->req_open = smb_raw_open_send(state->tree, &state->open_parms);
state->req_open->async.fn = open_completed;
return;
}
+ state->old_fnum = state->fnum;
state->fnum = state->open_parms.ntcreatex.out.file.fnum;
- state->waiting_open = False;
- if (!state->waiting_close) {
- next_open(state);
+ DEBUG(2,("[%d] open completed: fnum=%d old_fnum=%d\n",
+ state->client_num, state->fnum, state->old_fnum));
+
+ if (state->old_fnum != -1) {
+ next_close(state);
}
+
+ next_open(state);
}
/*
state->cli = NULL;
num_connected--;
DEBUG(0,("reopening connection to %s\n", state->dest_host));
- event_add_timed(state->ev, state->mem_ctx,
- timeval_current_ofs(1,0),
- reopen_connection, state);
+ talloc_free(state->te);
+ state->te = event_add_timed(state->ev, state->mem_ctx,
+ timeval_current_ofs(1,0),
+ reopen_connection, state);
return;
}
return;
}
- state->waiting_close = False;
-
- if (!state->waiting_open) {
- next_open(state);
- }
+ DEBUG(2,("[%d] close completed: fnum=%d old_fnum=%d\n",
+ state->client_num, state->fnum, state->old_fnum));
}
+static void echo_completion(struct smbcli_request *req)
+{
+ struct benchopen_state *state = (struct benchopen_state *)req->async.private;
+ NTSTATUS status = smbcli_request_simple_recv(req);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT)) {
+ talloc_free(state->tree);
+ state->tree = NULL;
+ num_connected--;
+ DEBUG(0,("reopening connection to %s\n", state->dest_host));
+ talloc_free(state->te);
+ state->te = event_add_timed(state->ev, state->mem_ctx,
+ timeval_current_ofs(1,0),
+ reopen_connection, state);
+ }
+}
static void report_rate(struct event_context *ev, struct timed_event *te,
struct timeval t, void *private_data)
}
printf("\r");
fflush(stdout);
- event_add_timed(ev, state, timeval_current_ofs(1, 0), report_rate, state);
+ report_te = event_add_timed(ev, state, timeval_current_ofs(1, 0),
+ report_rate, state);
+
+ /* send an echo on each interface to ensure it stays alive - this helps
+ with IP takeover */
+ for (i=0;i<nprocs;i++) {
+ struct smb_echo p;
+ struct smbcli_request *req;
+
+ if (!state[i].tree) {
+ continue;
+ }
+
+ p.in.repeat_count = 1;
+ p.in.size = 0;
+ p.in.data = NULL;
+ req = smb_raw_echo_send(state[i].tree->session->transport, &p);
+ req->async.private = &state[i];
+ req->async.fn = echo_completion;
+ }
}
/*
benchmark open calls
*/
-BOOL torture_bench_open(struct torture_context *torture)
+bool torture_bench_open(struct torture_context *torture)
{
- BOOL ret = True;
+ bool ret = true;
TALLOC_CTX *mem_ctx = talloc_new(torture);
int i;
int timelimit = torture_setting_int(torture, "timelimit", 10);
struct event_context *ev = event_context_find(mem_ctx);
struct benchopen_state *state;
int total = 0, minops=0;
- bool progress;
+ bool progress=false;
progress = torture_setting_bool(torture, "progress", true);
- nprocs = lp_parm_int(-1, "torture", "nprocs", 4);
+ nprocs = torture_setting_int(torture, "nprocs", 4);
state = talloc_zero_array(mem_ctx, struct benchopen_state, nprocs);
printf("Opening %d connections\n", nprocs);
for (i=0;i<nprocs;i++) {
+ state[i].tctx = torture;
state[i].mem_ctx = talloc_new(state);
state[i].client_num = i;
state[i].ev = ev;
- if (!torture_open_connection_ev(&state[i].cli, i, ev)) {
- return False;
+ if (!torture_open_connection_ev(&state[i].cli, i, torture, ev)) {
+ return false;
}
talloc_steal(mem_ctx, state);
state[i].tree = state[i].cli->tree;
state[i].dest_host = talloc_strdup(state[i].mem_ctx,
state[i].cli->tree->session->transport->socket->hostname);
- state[i].dest_port = state[i].cli->tree->session->transport->socket->port;
+ state[i].dest_ports = talloc_array(state[i].mem_ctx,
+ const char *, 2);
+ state[i].dest_ports[0] = talloc_asprintf(state[i].dest_ports,
+ "%u", state[i].cli->tree->session->transport->socket->port);
+ state[i].dest_ports[1] = NULL;
state[i].called_name = talloc_strdup(state[i].mem_ctx,
state[i].cli->tree->session->transport->called.name);
state[i].service_type = talloc_strdup(state[i].mem_ctx,
goto failed;
}
- fnames = talloc_array(mem_ctx, char *, nprocs+1);
- for (i=0;i<nprocs+1;i++) {
+ fnames = talloc_array(mem_ctx, char *, 3*nprocs);
+ for (i=0;i<3*nprocs;i++) {
fnames[i] = talloc_asprintf(fnames, "%s\\file%d.dat", BASEDIR, i);
}
for (i=0;i<nprocs;i++) {
- state[i].fnum = -1;
state[i].file_num = i;
+ state[i].fnum = smbcli_open(state[i].tree,
+ fnames[state->file_num],
+ O_RDWR|O_CREAT, DENY_ALL);
+ state[i].old_fnum = -1;
next_open(&state[i]);
}
tv = timeval_current();
if (progress) {
- event_add_timed(ev, state, timeval_current_ofs(1, 0), report_rate, state);
+ report_te = event_add_timed(ev, state, timeval_current_ofs(1, 0),
+ report_rate, state);
}
printf("Running for %d seconds\n", timelimit);
}
}
+ talloc_free(report_te);
+
printf("%.2f ops/second (%d retries)\n",
total/timeval_elapsed(&tv), open_retries);
minops = state[0].count;
failed:
talloc_free(mem_ctx);
- return False;
+ return false;
}