Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : *
4 : * This program is free software; you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation; either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "source3/include/includes.h"
19 : #include "source3/torture/proto.h"
20 : #include "source3/libsmb/libsmb.h"
21 : #include "librpc/gen_ndr/ndr_spoolss_c.h"
22 : #include "lib/util/tevent_ntstatus.h"
23 : #include "source3/rpc_client/rpc_client.h"
24 : #include "source3/rpc_client/cli_pipe.h"
25 : #include "libcli/smb/smbXcli_base.h"
26 :
27 : extern int torture_nprocs;
28 : extern int torture_numops;
29 :
30 : struct rpc_scale_one_state {
31 : struct tevent_context *ev;
32 : struct cli_state *cli;
33 : size_t num_iterations;
34 : struct rpc_pipe_client *rpccli;
35 : DATA_BLOB buffer;
36 : uint32_t needed;
37 : uint32_t num_printers;
38 : union spoolss_PrinterInfo *printers;
39 : };
40 :
41 : static void rpc_scale_one_opened(struct tevent_req *subreq);
42 : static void rpc_scale_one_bound(struct tevent_req *subreq);
43 : static void rpc_scale_one_listed(struct tevent_req *subreq);
44 :
45 0 : static struct tevent_req *rpc_scale_one_send(
46 : TALLOC_CTX *mem_ctx,
47 : struct tevent_context *ev,
48 : struct cli_state *cli,
49 : size_t num_iterations)
50 : {
51 0 : struct tevent_req *req = NULL, *subreq = NULL;
52 0 : struct rpc_scale_one_state *state = NULL;
53 :
54 0 : req = tevent_req_create(mem_ctx, &state, struct rpc_scale_one_state);
55 0 : if (req == NULL) {
56 0 : return NULL;
57 : }
58 0 : state->ev = ev;
59 0 : state->cli = cli;
60 0 : state->num_iterations = num_iterations;
61 :
62 0 : subreq = rpc_pipe_open_np_send(
63 : state, ev, cli, &ndr_table_spoolss);
64 0 : if (tevent_req_nomem(subreq, req)) {
65 0 : return tevent_req_post(req, ev);
66 : }
67 0 : tevent_req_set_callback(subreq, rpc_scale_one_opened, req);
68 0 : return req;
69 : }
70 :
71 0 : static void rpc_scale_one_opened(struct tevent_req *subreq)
72 : {
73 0 : struct tevent_req *req = tevent_req_callback_data(
74 : subreq, struct tevent_req);
75 0 : struct rpc_scale_one_state *state = tevent_req_data(
76 : req, struct rpc_scale_one_state);
77 0 : struct pipe_auth_data *auth = NULL;
78 0 : NTSTATUS status;
79 :
80 0 : status = rpc_pipe_open_np_recv(subreq, state, &state->rpccli);
81 0 : TALLOC_FREE(subreq);
82 0 : if (tevent_req_nterror(req, status)) {
83 0 : return;
84 : }
85 :
86 0 : status = rpccli_anon_bind_data(state, &auth);
87 0 : if (tevent_req_nterror(req, status)) {
88 0 : return;
89 : }
90 :
91 0 : subreq = rpc_pipe_bind_send(state, state->ev, state->rpccli, auth);
92 0 : if (tevent_req_nomem(subreq, req)) {
93 0 : return;
94 : }
95 0 : tevent_req_set_callback(subreq, rpc_scale_one_bound, req);
96 : }
97 :
98 0 : static void rpc_scale_one_bound(struct tevent_req *subreq)
99 : {
100 0 : struct tevent_req *req = tevent_req_callback_data(
101 : subreq, struct tevent_req);
102 0 : struct rpc_scale_one_state *state = tevent_req_data(
103 : req, struct rpc_scale_one_state);
104 0 : char *server = NULL;
105 0 : NTSTATUS status;
106 :
107 0 : status = rpc_pipe_bind_recv(subreq);
108 0 : if (tevent_req_nterror(req, status)) {
109 0 : return;
110 : }
111 :
112 0 : server = talloc_asprintf(
113 : state,
114 : "\\%s\n",
115 0 : smbXcli_conn_remote_name(state->cli->conn));
116 0 : if (tevent_req_nomem(server, req)) {
117 0 : return;
118 : }
119 0 : state->buffer = data_blob_talloc(state, NULL, 4096);
120 0 : if (tevent_req_nomem(state->buffer.data, req)) {
121 0 : return;
122 : }
123 :
124 0 : subreq = dcerpc_spoolss_EnumPrinters_send(
125 : state,
126 : state->ev,
127 0 : state->rpccli->binding_handle,
128 : PRINTER_ENUM_LOCAL,
129 : server,
130 : 1, /* level */
131 : &state->buffer,
132 0 : state->buffer.length,
133 : &state->num_printers,
134 : &state->printers,
135 : &state->needed);
136 0 : if (tevent_req_nomem(subreq, req)) {
137 0 : return;
138 : }
139 0 : tevent_req_set_callback(subreq, rpc_scale_one_listed, req);
140 : }
141 :
142 0 : static void rpc_scale_one_listed(struct tevent_req *subreq)
143 : {
144 0 : struct tevent_req *req = tevent_req_callback_data(
145 : subreq, struct tevent_req);
146 0 : struct rpc_scale_one_state *state = tevent_req_data(
147 : req, struct rpc_scale_one_state);
148 0 : NTSTATUS status;
149 0 : WERROR result;
150 :
151 0 : status = dcerpc_spoolss_EnumPrinters_recv(subreq, state, &result);
152 0 : if (tevent_req_nterror(req, status)) {
153 0 : return;
154 : }
155 :
156 0 : if (!W_ERROR_IS_OK(result)) {
157 0 : status = werror_to_ntstatus(result);
158 0 : tevent_req_nterror(req, status);
159 0 : return;
160 : }
161 :
162 : /*
163 : * This will trigger a sync close. Making that async will be a
164 : * lot of effort, and even with this being sync this test is
165 : * nasty enough.
166 : */
167 0 : TALLOC_FREE(state->rpccli);
168 :
169 0 : state->num_iterations -= 1;
170 :
171 0 : if (state->num_iterations == 0) {
172 0 : tevent_req_done(req);
173 0 : return;
174 : }
175 :
176 0 : subreq = rpc_pipe_open_np_send(
177 : state, state->ev, state->cli, &ndr_table_spoolss);
178 0 : if (tevent_req_nomem(subreq, req)) {
179 0 : return;
180 : }
181 0 : tevent_req_set_callback(subreq, rpc_scale_one_opened, req);
182 : }
183 :
184 0 : static NTSTATUS rpc_scale_one_recv(struct tevent_req *req)
185 : {
186 0 : return tevent_req_simple_recv_ntstatus(req);
187 : }
188 :
189 : struct rpc_scale_state {
190 : size_t num_reqs;
191 : size_t done;
192 : };
193 :
194 : static void rpc_scale_done(struct tevent_req *subreq);
195 :
196 0 : static struct tevent_req *rpc_scale_send(
197 : TALLOC_CTX *mem_ctx,
198 : struct tevent_context *ev,
199 : struct cli_state **clis)
200 : {
201 0 : struct tevent_req *req = NULL;
202 0 : struct rpc_scale_state *state = NULL;
203 0 : size_t i, num_clis = talloc_array_length(clis);
204 :
205 0 : req = tevent_req_create(mem_ctx, &state, struct rpc_scale_state);
206 0 : if (req == NULL) {
207 0 : return NULL;
208 : }
209 0 : state->num_reqs = num_clis;
210 :
211 0 : for (i=0; i<num_clis; i++) {
212 0 : struct tevent_req *subreq = rpc_scale_one_send(
213 0 : state, ev, clis[i], torture_numops);
214 0 : if (tevent_req_nomem(subreq, req)) {
215 0 : return tevent_req_post(req, ev);
216 : }
217 0 : tevent_req_set_callback(subreq, rpc_scale_done, req);
218 : }
219 0 : return req;
220 : }
221 :
222 0 : static void rpc_scale_done(struct tevent_req *subreq)
223 : {
224 0 : struct tevent_req *req = tevent_req_callback_data(
225 : subreq, struct tevent_req);
226 0 : struct rpc_scale_state *state = tevent_req_data(
227 : req, struct rpc_scale_state);
228 0 : NTSTATUS status;
229 :
230 0 : status = rpc_scale_one_recv(subreq);
231 0 : TALLOC_FREE(subreq);
232 0 : if (tevent_req_nterror(req, status)) {
233 0 : return;
234 : }
235 :
236 0 : state->done += 1;
237 :
238 0 : if (state->done == state->num_reqs) {
239 0 : tevent_req_done(req);
240 : }
241 : }
242 :
243 0 : static NTSTATUS rpc_scale_recv(struct tevent_req *req)
244 : {
245 0 : return tevent_req_simple_recv_ntstatus(req);
246 : }
247 :
248 0 : bool run_rpc_scale(int dummy)
249 : {
250 0 : TALLOC_CTX *frame = talloc_stackframe();
251 0 : struct cli_state **clis = NULL;
252 0 : struct tevent_req *req = NULL;
253 0 : struct tevent_context *ev = NULL;
254 0 : bool ok, result = false;
255 0 : NTSTATUS status;
256 0 : int i;
257 :
258 0 : clis = talloc_zero_array(
259 : talloc_tos(), struct cli_state *, torture_nprocs);
260 0 : if (clis == NULL) {
261 0 : fprintf(stderr, "talloc failed\n");
262 0 : goto fail;
263 : }
264 :
265 0 : for (i=0; i<torture_nprocs; i++) {
266 0 : ok = torture_open_connection_flags(&clis[i], i, 0);
267 0 : if (!ok) {
268 0 : fprintf(stderr, "could not open connection %d\n", i);
269 0 : goto fail;
270 : }
271 : }
272 :
273 0 : ev = samba_tevent_context_init(talloc_tos());
274 0 : if (ev == NULL) {
275 0 : goto fail;
276 : }
277 :
278 0 : req = rpc_scale_send(talloc_tos(), ev, clis);
279 0 : if (req == NULL) {
280 0 : goto fail;
281 : }
282 :
283 0 : ok = tevent_req_poll_ntstatus(req, ev, &status);
284 0 : if (!ok) {
285 0 : fprintf(stderr,
286 : "rpc_scale_send failed: %s\n",
287 : nt_errstr(status));
288 0 : goto fail;
289 : }
290 :
291 0 : status = rpc_scale_recv(req);
292 0 : if (!NT_STATUS_IS_OK(status)) {
293 0 : fprintf(stderr, "rpc_scale failed: %s\n", nt_errstr(status));
294 0 : goto fail;
295 : }
296 :
297 0 : result = true;
298 0 : fail:
299 0 : TALLOC_FREE(frame);
300 0 : return result;
301 : }
|