/* * Unix SMB/CIFS implementation. * * 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 . */ #include "source3/include/includes.h" #include "source3/torture/proto.h" #include "source3/libsmb/libsmb.h" #include "librpc/gen_ndr/ndr_spoolss_c.h" #include "lib/util/tevent_ntstatus.h" #include "source3/rpc_client/rpc_client.h" #include "source3/rpc_client/cli_pipe.h" #include "libcli/smb/smbXcli_base.h" extern int torture_nprocs; extern int torture_numops; struct rpc_scale_one_state { struct tevent_context *ev; struct cli_state *cli; size_t num_iterations; struct rpc_pipe_client *rpccli; DATA_BLOB buffer; uint32_t needed; uint32_t num_printers; union spoolss_PrinterInfo *printers; }; static void rpc_scale_one_opened(struct tevent_req *subreq); static void rpc_scale_one_bound(struct tevent_req *subreq); static void rpc_scale_one_listed(struct tevent_req *subreq); static struct tevent_req *rpc_scale_one_send( TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, size_t num_iterations) { struct tevent_req *req = NULL, *subreq = NULL; struct rpc_scale_one_state *state = NULL; req = tevent_req_create(mem_ctx, &state, struct rpc_scale_one_state); if (req == NULL) { return NULL; } state->ev = ev; state->cli = cli; state->num_iterations = num_iterations; subreq = rpc_pipe_open_np_send( state, ev, cli, &ndr_table_spoolss); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } tevent_req_set_callback(subreq, rpc_scale_one_opened, req); return req; } static void rpc_scale_one_opened(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( subreq, struct tevent_req); struct rpc_scale_one_state *state = tevent_req_data( req, struct rpc_scale_one_state); struct pipe_auth_data *auth = NULL; NTSTATUS status; status = rpc_pipe_open_np_recv(subreq, state, &state->rpccli); TALLOC_FREE(subreq); if (tevent_req_nterror(req, status)) { return; } status = rpccli_anon_bind_data(state, &auth); if (tevent_req_nterror(req, status)) { return; } subreq = rpc_pipe_bind_send(state, state->ev, state->rpccli, auth); if (tevent_req_nomem(subreq, req)) { return; } tevent_req_set_callback(subreq, rpc_scale_one_bound, req); } static void rpc_scale_one_bound(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( subreq, struct tevent_req); struct rpc_scale_one_state *state = tevent_req_data( req, struct rpc_scale_one_state); char *server = NULL; NTSTATUS status; status = rpc_pipe_bind_recv(subreq); if (tevent_req_nterror(req, status)) { return; } server = talloc_asprintf( state, "\\%s\n", smbXcli_conn_remote_name(state->cli->conn)); if (tevent_req_nomem(server, req)) { return; } state->buffer = data_blob_talloc(state, NULL, 4096); if (tevent_req_nomem(state->buffer.data, req)) { return; } subreq = dcerpc_spoolss_EnumPrinters_send( state, state->ev, state->rpccli->binding_handle, PRINTER_ENUM_LOCAL, server, 1, /* level */ &state->buffer, state->buffer.length, &state->num_printers, &state->printers, &state->needed); if (tevent_req_nomem(subreq, req)) { return; } tevent_req_set_callback(subreq, rpc_scale_one_listed, req); } static void rpc_scale_one_listed(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( subreq, struct tevent_req); struct rpc_scale_one_state *state = tevent_req_data( req, struct rpc_scale_one_state); NTSTATUS status; WERROR result; status = dcerpc_spoolss_EnumPrinters_recv(subreq, state, &result); if (tevent_req_nterror(req, status)) { return; } if (!W_ERROR_IS_OK(result)) { status = werror_to_ntstatus(result); tevent_req_nterror(req, status); return; } /* * This will trigger a sync close. Making that async will be a * lot of effort, and even with this being sync this test is * nasty enough. */ TALLOC_FREE(state->rpccli); state->num_iterations -= 1; if (state->num_iterations == 0) { tevent_req_done(req); return; } subreq = rpc_pipe_open_np_send( state, state->ev, state->cli, &ndr_table_spoolss); if (tevent_req_nomem(subreq, req)) { return; } tevent_req_set_callback(subreq, rpc_scale_one_opened, req); } static NTSTATUS rpc_scale_one_recv(struct tevent_req *req) { return tevent_req_simple_recv_ntstatus(req); } struct rpc_scale_state { size_t num_reqs; size_t done; }; static void rpc_scale_done(struct tevent_req *subreq); static struct tevent_req *rpc_scale_send( TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state **clis) { struct tevent_req *req = NULL; struct rpc_scale_state *state = NULL; size_t i, num_clis = talloc_array_length(clis); req = tevent_req_create(mem_ctx, &state, struct rpc_scale_state); if (req == NULL) { return NULL; } state->num_reqs = num_clis; for (i=0; idone += 1; if (state->done == state->num_reqs) { tevent_req_done(req); } } static NTSTATUS rpc_scale_recv(struct tevent_req *req) { return tevent_req_simple_recv_ntstatus(req); } bool run_rpc_scale(int dummy) { TALLOC_CTX *frame = talloc_stackframe(); struct cli_state **clis = NULL; struct tevent_req *req = NULL; struct tevent_context *ev = NULL; bool ok, result = false; NTSTATUS status; int i; clis = talloc_zero_array( talloc_tos(), struct cli_state *, torture_nprocs); if (clis == NULL) { fprintf(stderr, "talloc failed\n"); goto fail; } for (i=0; i