Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : test suite for echo rpc operations
4 :
5 : Copyright (C) Andrew Tridgell 2003
6 : Copyright (C) Stefan (metze) Metzmacher 2005
7 : Copyright (C) Jelmer Vernooij 2005
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "torture/rpc/torture_rpc.h"
25 : #include "lib/events/events.h"
26 : #include "librpc/gen_ndr/ndr_echo_c.h"
27 :
28 :
29 : /*
30 : test the AddOne interface
31 : */
32 : #define TEST_ADDONE(tctx, value) do { \
33 : n = i = value; \
34 : r.in.in_data = n; \
35 : r.out.out_data = &n; \
36 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_AddOne_r(b, tctx, &r), \
37 : talloc_asprintf(tctx, "AddOne(%d) failed", i)); \
38 : torture_assert (tctx, n == i+1, talloc_asprintf(tctx, "%d + 1 != %u (should be %u)\n", i, n, i+1)); \
39 : torture_comment (tctx, "%d + 1 = %u\n", i, n); \
40 : } while(0)
41 :
42 257 : static bool test_addone(struct torture_context *tctx,
43 : struct dcerpc_pipe *p)
44 : {
45 : uint32_t i;
46 : uint32_t n;
47 : struct echo_AddOne r;
48 257 : struct dcerpc_binding_handle *b = p->binding_handle;
49 :
50 2827 : for (i=0;i<10;i++) {
51 2570 : TEST_ADDONE(tctx, i);
52 : }
53 :
54 257 : TEST_ADDONE(tctx, 0x7FFFFFFE);
55 257 : TEST_ADDONE(tctx, 0xFFFFFFFE);
56 257 : TEST_ADDONE(tctx, 0xFFFFFFFF);
57 257 : TEST_ADDONE(tctx, random() & 0xFFFFFFFF);
58 257 : return true;
59 : }
60 :
61 : /*
62 : test the EchoData interface
63 : */
64 257 : static bool test_echodata(struct torture_context *tctx,
65 : struct dcerpc_pipe *p)
66 : {
67 : int i;
68 : uint8_t *data_in, *data_out;
69 : int len;
70 : struct echo_EchoData r;
71 257 : struct dcerpc_binding_handle *b = p->binding_handle;
72 :
73 381 : if (torture_setting_bool(tctx, "quick", false) &&
74 212 : (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
75 16 : len = 1 + (random() % 500);
76 : } else {
77 241 : len = 1 + (random() % 5000);
78 : }
79 :
80 257 : data_in = talloc_array(tctx, uint8_t, len);
81 257 : data_out = talloc_array(tctx, uint8_t, len);
82 595840 : for (i=0;i<len;i++) {
83 595583 : data_in[i] = i;
84 : }
85 :
86 257 : r.in.len = len;
87 257 : r.in.in_data = data_in;
88 :
89 257 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_EchoData_r(b, tctx, &r),
90 : talloc_asprintf(tctx, "EchoData(%d) failed\n", len));
91 :
92 257 : data_out = r.out.out_data;
93 :
94 595840 : for (i=0;i<len;i++) {
95 595583 : if (data_in[i] != data_out[i]) {
96 0 : torture_comment(tctx, "Bad data returned for len %d at offset %d\n",
97 : len, i);
98 0 : torture_comment(tctx, "in:\n");
99 0 : dump_data(0, data_in+i, MIN(len-i, 16));
100 0 : torture_comment(tctx, "out:\n");
101 0 : dump_data(0, data_out+i, MIN(len-1, 16));
102 0 : return false;
103 : }
104 : }
105 257 : return true;
106 : }
107 :
108 : /*
109 : test the SourceData interface
110 : */
111 257 : static bool test_sourcedata(struct torture_context *tctx,
112 : struct dcerpc_pipe *p)
113 : {
114 : int i;
115 : int len;
116 : struct echo_SourceData r;
117 257 : struct dcerpc_binding_handle *b = p->binding_handle;
118 :
119 381 : if (torture_setting_bool(tctx, "quick", false) &&
120 212 : (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
121 16 : len = 100 + (random() % 500);
122 : } else {
123 241 : len = 200000 + (random() % 5000);
124 : }
125 :
126 257 : r.in.len = len;
127 :
128 257 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_SourceData_r(b, tctx, &r),
129 : talloc_asprintf(tctx, "SourceData(%d) failed", len));
130 :
131 48806312 : for (i=0;i<len;i++) {
132 48806055 : uint8_t *v = (uint8_t *)r.out.data;
133 48806055 : torture_assert(tctx, v[i] == (i & 0xFF),
134 : talloc_asprintf(tctx,
135 : "bad data 0x%x at %d\n", (uint8_t)r.out.data[i], i));
136 : }
137 257 : return true;
138 : }
139 :
140 : /*
141 : test the SinkData interface
142 : */
143 257 : static bool test_sinkdata(struct torture_context *tctx,
144 : struct dcerpc_pipe *p)
145 : {
146 : int i;
147 : uint8_t *data_in;
148 : int len;
149 : struct echo_SinkData r;
150 257 : struct dcerpc_binding_handle *b = p->binding_handle;
151 :
152 381 : if (torture_setting_bool(tctx, "quick", false) &&
153 212 : (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
154 16 : len = 100 + (random() % 5000);
155 : } else {
156 241 : len = 200000 + (random() % 5000);
157 : }
158 :
159 257 : data_in = talloc_array(tctx, uint8_t, len);
160 48864745 : for (i=0;i<len;i++) {
161 48864488 : data_in[i] = i+1;
162 : }
163 :
164 257 : r.in.len = len;
165 257 : r.in.data = data_in;
166 :
167 257 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_SinkData_r(b, tctx, &r),
168 : talloc_asprintf(tctx, "SinkData(%d) failed", len));
169 :
170 257 : torture_comment(tctx, "sunk %d bytes\n", len);
171 257 : return true;
172 : }
173 :
174 :
175 : /*
176 : test the testcall interface
177 : */
178 257 : static bool test_testcall(struct torture_context *tctx,
179 : struct dcerpc_pipe *p)
180 : {
181 : struct echo_TestCall r;
182 257 : const char *s = NULL;
183 257 : struct dcerpc_binding_handle *b = p->binding_handle;
184 :
185 257 : r.in.s1 = "input string";
186 257 : r.out.s2 = &s;
187 :
188 257 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestCall_r(b, tctx, &r),
189 : "TestCall failed");
190 :
191 257 : torture_assert_str_equal(tctx, s, "input string", "Didn't receive back same string");
192 :
193 257 : return true;
194 : }
195 :
196 : /*
197 : test the testcall interface
198 : */
199 257 : static bool test_testcall2(struct torture_context *tctx,
200 : struct dcerpc_pipe *p)
201 : {
202 : struct echo_TestCall2 r;
203 : int i;
204 257 : struct dcerpc_binding_handle *b = p->binding_handle;
205 :
206 2056 : for (i=1;i<=7;i++) {
207 1799 : r.in.level = i;
208 1799 : r.out.info = talloc(tctx, union echo_Info);
209 :
210 1799 : torture_comment(tctx, "Testing TestCall2 level %d\n", i);
211 1799 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestCall2_r(b, tctx, &r),
212 : "TestCall2 failed");
213 1799 : torture_assert_ntstatus_ok(tctx, r.out.result, "TestCall2 failed");
214 : }
215 257 : return true;
216 : }
217 :
218 135 : static void test_sleep_done(struct tevent_req *subreq)
219 : {
220 135 : bool *done1 = (bool *)tevent_req_callback_data_void(subreq);
221 135 : *done1 = true;
222 135 : }
223 :
224 : /*
225 : test the TestSleep interface
226 : */
227 257 : static bool test_sleep(struct torture_context *tctx,
228 : struct dcerpc_pipe *p)
229 : {
230 : int i;
231 : #define ASYNC_COUNT 3
232 : struct tevent_req *req[ASYNC_COUNT];
233 : struct echo_TestSleep r[ASYNC_COUNT];
234 : bool done1[ASYNC_COUNT];
235 : bool done2[ASYNC_COUNT];
236 : struct timeval snd[ASYNC_COUNT];
237 : struct timeval rcv[ASYNC_COUNT];
238 : struct timeval diff[ASYNC_COUNT];
239 257 : int total_done = 0;
240 257 : struct dcerpc_binding_handle *b = p->binding_handle;
241 : enum dcerpc_transport_t transport;
242 : uint32_t assoc_group_id;
243 257 : struct dcerpc_pipe *p2 = NULL;
244 : NTSTATUS status;
245 :
246 257 : if (torture_setting_bool(tctx, "quick", false)) {
247 212 : torture_skip(tctx, "TestSleep disabled - use \"torture:quick=no\" to enable\n");
248 : }
249 45 : torture_comment(tctx, "Testing TestSleep - use \"torture:quick=yes\" to disable\n");
250 :
251 45 : transport = dcerpc_binding_get_transport(p->binding);
252 45 : assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
253 :
254 45 : torture_comment(tctx, "connect echo connection 2 with "
255 : "DCERPC_CONCURRENT_MULTIPLEX\n");
256 45 : status = torture_rpc_connection_transport(tctx, &p2,
257 : &ndr_table_rpcecho,
258 : transport,
259 : assoc_group_id,
260 : DCERPC_CONCURRENT_MULTIPLEX);
261 45 : torture_assert_ntstatus_ok(tctx, status, "opening echo connection 2");
262 45 : b = p2->binding_handle;
263 :
264 180 : for (i=0;i<ASYNC_COUNT;i++) {
265 135 : done1[i] = false;
266 135 : done2[i] = false;
267 135 : snd[i] = timeval_current();
268 135 : rcv[i] = timeval_zero();
269 135 : r[i].in.seconds = ASYNC_COUNT-i;
270 135 : req[i] = dcerpc_echo_TestSleep_r_send(tctx, tctx->ev, b, &r[i]);
271 135 : torture_assert(tctx, req[i], "Failed to send async sleep request\n");
272 135 : tevent_req_set_callback(req[i], test_sleep_done, &done1[i]);
273 : }
274 :
275 1876 : while (total_done < ASYNC_COUNT) {
276 1797 : torture_assert(tctx, tevent_loop_once(tctx->ev) == 0,
277 : "Event context loop failed");
278 7188 : for (i=0;i<ASYNC_COUNT;i++) {
279 5391 : if (done2[i] == false && done1[i] == true) {
280 : int rounded_tdiff;
281 135 : total_done++;
282 135 : done2[i] = true;
283 135 : rcv[i] = timeval_current();
284 135 : diff[i] = timeval_until(&snd[i], &rcv[i]);
285 135 : rounded_tdiff = (int)(0.5 + diff[i].tv_sec + (1.0e-6*diff[i].tv_usec));
286 135 : torture_comment(tctx, "rounded_tdiff=%d\n", rounded_tdiff);
287 135 : torture_assert_ntstatus_ok(tctx,
288 : dcerpc_echo_TestSleep_r_recv(req[i], tctx),
289 : talloc_asprintf(tctx, "TestSleep(%d) failed", i));
290 135 : torture_assert(tctx, r[i].out.result == r[i].in.seconds,
291 : talloc_asprintf(tctx, "Failed - Asked to sleep for %u seconds (server replied with %u seconds and the reply takes only %u seconds)",
292 : r[i].out.result, r[i].in.seconds, (unsigned int)diff[i].tv_sec));
293 135 : torture_assert(tctx, r[i].out.result <= rounded_tdiff,
294 : talloc_asprintf(tctx, "Failed - Slept for %u seconds (but reply takes only %u.%06u seconds)",
295 : r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec));
296 135 : if (r[i].out.result+1 == rounded_tdiff) {
297 0 : torture_comment(tctx, "Slept for %u seconds (but reply takes %u.%06u seconds - busy server?)\n",
298 0 : r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec);
299 135 : } else if (r[i].out.result == rounded_tdiff) {
300 237 : torture_comment(tctx, "Slept for %u seconds (reply takes %u.%06u seconds - ok)\n",
301 237 : r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec);
302 : } else {
303 0 : torture_fail(tctx, talloc_asprintf(tctx,
304 : "(Failed) - Not async - Slept for %u seconds (but reply takes %u.%06u seconds)\n",
305 : r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec));
306 : }
307 : }
308 : }
309 : }
310 45 : torture_comment(tctx, "\n");
311 45 : return true;
312 : }
313 :
314 : /*
315 : test enum handling
316 : */
317 257 : static bool test_enum(struct torture_context *tctx,
318 : struct dcerpc_pipe *p)
319 : {
320 : struct echo_TestEnum r;
321 257 : enum echo_Enum1 v = ECHO_ENUM1;
322 : struct echo_Enum2 e2;
323 : union echo_Enum3 e3;
324 257 : struct dcerpc_binding_handle *b = p->binding_handle;
325 :
326 257 : r.in.foo1 = &v;
327 257 : r.in.foo2 = &e2;
328 257 : r.in.foo3 = &e3;
329 257 : r.out.foo1 = &v;
330 257 : r.out.foo2 = &e2;
331 257 : r.out.foo3 = &e3;
332 :
333 257 : e2.e1 = 76;
334 257 : e2.e2 = ECHO_ENUM1_32;
335 257 : e3.e1 = ECHO_ENUM2;
336 :
337 257 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestEnum_r(b, tctx, &r),
338 : "TestEnum failed");
339 257 : return true;
340 : }
341 :
342 : /*
343 : test surrounding conformant array handling
344 : */
345 257 : static bool test_surrounding(struct torture_context *tctx,
346 : struct dcerpc_pipe *p)
347 : {
348 : struct echo_TestSurrounding r;
349 257 : struct dcerpc_binding_handle *b = p->binding_handle;
350 :
351 257 : ZERO_STRUCT(r);
352 257 : r.in.data = talloc(tctx, struct echo_Surrounding);
353 :
354 257 : r.in.data->x = 20;
355 257 : r.in.data->surrounding = talloc_zero_array(tctx, uint16_t, r.in.data->x);
356 :
357 257 : r.out.data = talloc(tctx, struct echo_Surrounding);
358 :
359 257 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestSurrounding_r(b, tctx, &r),
360 : "TestSurrounding failed");
361 :
362 257 : torture_assert(tctx, r.out.data->x == 2 * r.in.data->x,
363 : "TestSurrounding did not make the array twice as large");
364 :
365 257 : return true;
366 : }
367 :
368 : /*
369 : test multiple levels of pointers
370 : */
371 257 : static bool test_doublepointer(struct torture_context *tctx,
372 : struct dcerpc_pipe *p)
373 : {
374 : struct echo_TestDoublePointer r;
375 257 : uint16_t value = 12;
376 257 : uint16_t *pvalue = &value;
377 257 : uint16_t **ppvalue = &pvalue;
378 257 : struct dcerpc_binding_handle *b = p->binding_handle;
379 :
380 257 : ZERO_STRUCT(r);
381 257 : r.in.data = &ppvalue;
382 :
383 257 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestDoublePointer_r(b, tctx, &r),
384 : "TestDoublePointer failed");
385 :
386 257 : torture_assert_int_equal(tctx, value, r.out.result,
387 : "TestDoublePointer did not return original value");
388 257 : return true;
389 : }
390 :
391 :
392 : /*
393 : test request timeouts
394 : */
395 : #if 0 /* this test needs fixing to work over ncacn_np */
396 : static bool test_timeout(struct torture_context *tctx,
397 : struct dcerpc_pipe *p)
398 : {
399 : NTSTATUS status;
400 : struct rpc_request *req;
401 : struct echo_TestSleep r;
402 : int timeout_saved = p->request_timeout;
403 :
404 : if (torture_setting_bool(tctx, "quick", false)) {
405 : torture_skip(tctx, "timeout testing disabled - use \"torture:quick=no\" to enable\n");
406 : }
407 :
408 : torture_comment(tctx, "testing request timeouts\n");
409 : r.in.seconds = 2;
410 : p->request_timeout = 1;
411 :
412 : req = dcerpc_echo_TestSleep_send(p, tctx, &r);
413 : if (!req) {
414 : torture_comment(tctx, "Failed to send async sleep request\n");
415 : goto failed;
416 : }
417 : req->ignore_timeout = true;
418 :
419 : status = dcerpc_echo_TestSleep_recv(req);
420 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_IO_TIMEOUT,
421 : "request should have timed out");
422 :
423 : torture_comment(tctx, "testing request destruction\n");
424 : req = dcerpc_echo_TestSleep_send(p, tctx, &r);
425 : if (!req) {
426 : torture_comment(tctx, "Failed to send async sleep request\n");
427 : goto failed;
428 : }
429 : talloc_free(req);
430 :
431 : req = dcerpc_echo_TestSleep_send(p, tctx, &r);
432 : if (!req) {
433 : torture_comment(tctx, "Failed to send async sleep request\n");
434 : goto failed;
435 : }
436 : req->ignore_timeout = true;
437 : status = dcerpc_echo_TestSleep_recv(req);
438 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_IO_TIMEOUT,
439 : "request should have timed out");
440 :
441 : p->request_timeout = timeout_saved;
442 :
443 : return test_addone(tctx, p);
444 :
445 : failed:
446 : p->request_timeout = timeout_saved;
447 : return false;
448 : }
449 : #endif
450 :
451 964 : struct torture_suite *torture_rpc_echo(TALLOC_CTX *mem_ctx)
452 : {
453 964 : struct torture_suite *suite = torture_suite_create(mem_ctx, "echo");
454 : struct torture_rpc_tcase *tcase;
455 :
456 964 : tcase = torture_suite_add_rpc_iface_tcase(suite, "echo",
457 : &ndr_table_rpcecho);
458 :
459 964 : torture_rpc_tcase_add_test(tcase, "addone", test_addone);
460 964 : torture_rpc_tcase_add_test(tcase, "sinkdata", test_sinkdata);
461 964 : torture_rpc_tcase_add_test(tcase, "echodata", test_echodata);
462 964 : torture_rpc_tcase_add_test(tcase, "sourcedata", test_sourcedata);
463 964 : torture_rpc_tcase_add_test(tcase, "testcall", test_testcall);
464 964 : torture_rpc_tcase_add_test(tcase, "testcall2", test_testcall2);
465 964 : torture_rpc_tcase_add_test(tcase, "enum", test_enum);
466 964 : torture_rpc_tcase_add_test(tcase, "surrounding", test_surrounding);
467 964 : torture_rpc_tcase_add_test(tcase, "doublepointer", test_doublepointer);
468 964 : torture_rpc_tcase_add_test(tcase, "sleep", test_sleep);
469 : #if 0 /* this test needs fixing to work over ncacn_np */
470 : torture_rpc_tcase_add_test(tcase, "timeout", test_timeout);
471 : #endif
472 :
473 964 : return suite;
474 : }
|