2 Unix SMB/CIFS implementation.
3 test suite for echo rpc operations
5 Copyright (C) Andrew Tridgell 2003
6 Copyright (C) Stefan (metze) Metzmacher 2005
7 Copyright (C) Jelmer Vernooij 2005
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.
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.
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/>.
24 #include "torture/rpc/torture_rpc.h"
25 #include "lib/events/events.h"
26 #include "librpc/gen_ndr/ndr_echo_c.h"
30 test the AddOne interface
32 #define TEST_ADDONE(tctx, value) do { \
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); \
42 static bool test_addone(struct torture_context
*tctx
,
43 struct dcerpc_pipe
*p
)
48 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
54 TEST_ADDONE(tctx
, 0x7FFFFFFE);
55 TEST_ADDONE(tctx
, 0xFFFFFFFE);
56 TEST_ADDONE(tctx
, 0xFFFFFFFF);
57 TEST_ADDONE(tctx
, random() & 0xFFFFFFFF);
62 test the EchoData interface
64 static bool test_echodata(struct torture_context
*tctx
,
65 struct dcerpc_pipe
*p
)
68 uint8_t *data_in
, *data_out
;
70 struct echo_EchoData r
;
71 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
72 const struct dcerpc_binding
*binding
= dcerpc_binding_handle_get_binding(b
);
73 uint16_t flags
= dcerpc_binding_get_flags(binding
);
75 if (torture_setting_bool(tctx
, "quick", false) &&
76 (flags
& DCERPC_DEBUG_VALIDATE_BOTH
)) {
77 len
= 1 + (random() % 500);
79 len
= 1 + (random() % 5000);
82 data_in
= talloc_array(tctx
, uint8_t, len
);
83 data_out
= talloc_array(tctx
, uint8_t, len
);
89 r
.in
.in_data
= data_in
;
91 torture_assert_ntstatus_ok(tctx
, dcerpc_echo_EchoData_r(b
, tctx
, &r
),
92 talloc_asprintf(tctx
, "EchoData(%d) failed\n", len
));
94 data_out
= r
.out
.out_data
;
97 if (data_in
[i
] != data_out
[i
]) {
98 torture_comment(tctx
, "Bad data returned for len %d at offset %d\n",
100 torture_comment(tctx
, "in:\n");
101 dump_data(0, data_in
+i
, MIN(len
-i
, 16));
102 torture_comment(tctx
, "out:\n");
103 dump_data(0, data_out
+i
, MIN(len
-1, 16));
111 test the SourceData interface
113 static bool test_sourcedata(struct torture_context
*tctx
,
114 struct dcerpc_pipe
*p
)
118 struct echo_SourceData r
;
119 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
120 const struct dcerpc_binding
*binding
= dcerpc_binding_handle_get_binding(b
);
121 uint16_t flags
= dcerpc_binding_get_flags(binding
);
123 if (torture_setting_bool(tctx
, "quick", false) &&
124 (flags
& DCERPC_DEBUG_VALIDATE_BOTH
)) {
125 len
= 100 + (random() % 500);
127 len
= 200000 + (random() % 5000);
132 torture_assert_ntstatus_ok(tctx
, dcerpc_echo_SourceData_r(b
, tctx
, &r
),
133 talloc_asprintf(tctx
, "SourceData(%d) failed", len
));
135 for (i
=0;i
<len
;i
++) {
136 uint8_t *v
= (uint8_t *)r
.out
.data
;
137 torture_assert(tctx
, v
[i
] == (i
& 0xFF),
138 talloc_asprintf(tctx
,
139 "bad data 0x%x at %d\n", (uint8_t)r
.out
.data
[i
], i
));
145 test the SinkData interface
147 static bool test_sinkdata(struct torture_context
*tctx
,
148 struct dcerpc_pipe
*p
)
153 struct echo_SinkData r
;
154 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
155 const struct dcerpc_binding
*binding
= dcerpc_binding_handle_get_binding(b
);
156 uint16_t flags
= dcerpc_binding_get_flags(binding
);
158 if (torture_setting_bool(tctx
, "quick", false) &&
159 (flags
& DCERPC_DEBUG_VALIDATE_BOTH
)) {
160 len
= 100 + (random() % 5000);
162 len
= 200000 + (random() % 5000);
165 data_in
= talloc_array(tctx
, uint8_t, len
);
166 for (i
=0;i
<len
;i
++) {
173 torture_assert_ntstatus_ok(tctx
, dcerpc_echo_SinkData_r(b
, tctx
, &r
),
174 talloc_asprintf(tctx
, "SinkData(%d) failed", len
));
176 torture_comment(tctx
, "sunk %d bytes\n", len
);
182 test the testcall interface
184 static bool test_testcall(struct torture_context
*tctx
,
185 struct dcerpc_pipe
*p
)
187 struct echo_TestCall r
;
188 const char *s
= NULL
;
189 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
191 r
.in
.s1
= "input string";
194 torture_assert_ntstatus_ok(tctx
, dcerpc_echo_TestCall_r(b
, tctx
, &r
),
197 torture_assert_str_equal(tctx
, s
, "input string", "Didn't receive back same string");
203 test the testcall interface
205 static bool test_testcall2(struct torture_context
*tctx
,
206 struct dcerpc_pipe
*p
)
208 struct echo_TestCall2 r
;
210 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
214 r
.out
.info
= talloc(tctx
, union echo_Info
);
216 torture_comment(tctx
, "Testing TestCall2 level %d\n", i
);
217 torture_assert_ntstatus_ok(tctx
, dcerpc_echo_TestCall2_r(b
, tctx
, &r
),
219 torture_assert_ntstatus_ok(tctx
, r
.out
.result
, "TestCall2 failed");
224 static void test_sleep_done(struct tevent_req
*subreq
)
226 bool *done1
= (bool *)tevent_req_callback_data_void(subreq
);
231 test the TestSleep interface
233 static bool test_sleep(struct torture_context
*tctx
,
234 struct dcerpc_pipe
*p
)
237 #define ASYNC_COUNT 3
238 struct tevent_req
*req
[ASYNC_COUNT
];
239 struct echo_TestSleep r
[ASYNC_COUNT
];
240 bool done1
[ASYNC_COUNT
];
241 bool done2
[ASYNC_COUNT
];
242 struct timeval snd
[ASYNC_COUNT
];
243 struct timeval rcv
[ASYNC_COUNT
];
244 struct timeval diff
[ASYNC_COUNT
];
246 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
247 const struct dcerpc_binding
*bd
= dcerpc_binding_handle_get_binding(b
);
248 enum dcerpc_transport_t transport
;
249 uint32_t assoc_group_id
;
250 struct dcerpc_pipe
*p2
= NULL
;
253 if (torture_setting_bool(tctx
, "quick", false)) {
254 torture_skip(tctx
, "TestSleep disabled - use \"torture:quick=no\" to enable\n");
256 torture_comment(tctx
, "Testing TestSleep - use \"torture:quick=yes\" to disable\n");
258 transport
= dcerpc_binding_get_transport(bd
);
259 assoc_group_id
= dcerpc_binding_get_assoc_group_id(bd
);
261 torture_comment(tctx
, "connect echo connection 2 with "
262 "DCERPC_CONCURRENT_MULTIPLEX\n");
263 status
= torture_rpc_connection_transport(tctx
, &p2
,
267 DCERPC_CONCURRENT_MULTIPLEX
);
268 torture_assert_ntstatus_ok(tctx
, status
, "opening echo connection 2");
269 b
= p2
->binding_handle
;
271 for (i
=0;i
<ASYNC_COUNT
;i
++) {
274 snd
[i
] = timeval_current();
275 rcv
[i
] = timeval_zero();
276 r
[i
].in
.seconds
= ASYNC_COUNT
-i
;
277 req
[i
] = dcerpc_echo_TestSleep_r_send(tctx
, tctx
->ev
, b
, &r
[i
]);
278 torture_assert(tctx
, req
[i
], "Failed to send async sleep request\n");
279 tevent_req_set_callback(req
[i
], test_sleep_done
, &done1
[i
]);
282 while (total_done
< ASYNC_COUNT
) {
283 torture_assert(tctx
, tevent_loop_once(tctx
->ev
) == 0,
284 "Event context loop failed");
285 for (i
=0;i
<ASYNC_COUNT
;i
++) {
286 if (done2
[i
] == false && done1
[i
] == true) {
290 rcv
[i
] = timeval_current();
291 diff
[i
] = tevent_timeval_until(
293 rounded_tdiff
= (int)(0.5 + diff
[i
].tv_sec
+ (1.0e-6*diff
[i
].tv_usec
));
294 torture_comment(tctx
, "rounded_tdiff=%d\n", rounded_tdiff
);
295 torture_assert_ntstatus_ok(tctx
,
296 dcerpc_echo_TestSleep_r_recv(req
[i
], tctx
),
297 talloc_asprintf(tctx
, "TestSleep(%d) failed", i
));
298 torture_assert(tctx
, r
[i
].out
.result
== r
[i
].in
.seconds
,
299 talloc_asprintf(tctx
, "Failed - Asked to sleep for %u seconds (server replied with %u seconds and the reply takes only %u seconds)",
300 r
[i
].out
.result
, r
[i
].in
.seconds
, (unsigned int)diff
[i
].tv_sec
));
301 torture_assert(tctx
, r
[i
].out
.result
<= rounded_tdiff
,
302 talloc_asprintf(tctx
, "Failed - Slept for %u seconds (but reply takes only %u.%06u seconds)",
303 r
[i
].out
.result
, (unsigned int)diff
[i
].tv_sec
, (unsigned int)diff
[i
].tv_usec
));
304 if (r
[i
].out
.result
+1 == rounded_tdiff
) {
305 torture_comment(tctx
, "Slept for %u seconds (but reply takes %u.%06u seconds - busy server?)\n",
306 r
[i
].out
.result
, (unsigned int)diff
[i
].tv_sec
, (unsigned int)diff
[i
].tv_usec
);
307 } else if (r
[i
].out
.result
== rounded_tdiff
) {
308 torture_comment(tctx
, "Slept for %u seconds (reply takes %u.%06u seconds - ok)\n",
309 r
[i
].out
.result
, (unsigned int)diff
[i
].tv_sec
, (unsigned int)diff
[i
].tv_usec
);
311 torture_fail(tctx
, talloc_asprintf(tctx
,
312 "(Failed) - Not async - Slept for %u seconds (but reply takes %u.%06u seconds)\n",
313 r
[i
].out
.result
, (unsigned int)diff
[i
].tv_sec
, (unsigned int)diff
[i
].tv_usec
));
318 torture_comment(tctx
, "\n");
325 static bool test_enum(struct torture_context
*tctx
,
326 struct dcerpc_pipe
*p
)
328 struct echo_TestEnum r
;
329 enum echo_Enum1 v
= ECHO_ENUM1
;
330 struct echo_Enum2 e2
;
332 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
342 e2
.e2
= ECHO_ENUM1_32
;
345 torture_assert_ntstatus_ok(tctx
, dcerpc_echo_TestEnum_r(b
, tctx
, &r
),
351 test surrounding conformant array handling
353 static bool test_surrounding(struct torture_context
*tctx
,
354 struct dcerpc_pipe
*p
)
356 struct echo_TestSurrounding r
;
357 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
360 r
.in
.data
= talloc(tctx
, struct echo_Surrounding
);
363 r
.in
.data
->surrounding
= talloc_zero_array(tctx
, uint16_t, r
.in
.data
->x
);
365 r
.out
.data
= talloc(tctx
, struct echo_Surrounding
);
367 torture_assert_ntstatus_ok(tctx
, dcerpc_echo_TestSurrounding_r(b
, tctx
, &r
),
368 "TestSurrounding failed");
370 torture_assert(tctx
, r
.out
.data
->x
== 2 * r
.in
.data
->x
,
371 "TestSurrounding did not make the array twice as large");
377 test multiple levels of pointers
379 static bool test_doublepointer(struct torture_context
*tctx
,
380 struct dcerpc_pipe
*p
)
382 struct echo_TestDoublePointer r
;
384 uint16_t *pvalue
= &value
;
385 uint16_t **ppvalue
= &pvalue
;
386 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
389 r
.in
.data
= &ppvalue
;
391 torture_assert_ntstatus_ok(tctx
, dcerpc_echo_TestDoublePointer_r(b
, tctx
, &r
),
392 "TestDoublePointer failed");
394 torture_assert_int_equal(tctx
, value
, r
.out
.result
,
395 "TestDoublePointer did not return original value");
401 test request timeouts
403 #if 0 /* this test needs fixing to work over ncacn_np */
404 static bool test_timeout(struct torture_context
*tctx
,
405 struct dcerpc_pipe
*p
)
408 struct rpc_request
*req
;
409 struct echo_TestSleep r
;
410 int timeout_saved
= p
->request_timeout
;
412 if (torture_setting_bool(tctx
, "quick", false)) {
413 torture_skip(tctx
, "timeout testing disabled - use \"torture:quick=no\" to enable\n");
416 torture_comment(tctx
, "testing request timeouts\n");
418 p
->request_timeout
= 1;
420 req
= dcerpc_echo_TestSleep_send(p
, tctx
, &r
);
422 torture_comment(tctx
, "Failed to send async sleep request\n");
425 req
->ignore_timeout
= true;
427 status
= dcerpc_echo_TestSleep_recv(req
);
428 torture_assert_ntstatus_equal(tctx
, status
, NT_STATUS_IO_TIMEOUT
,
429 "request should have timed out");
431 torture_comment(tctx
, "testing request destruction\n");
432 req
= dcerpc_echo_TestSleep_send(p
, tctx
, &r
);
434 torture_comment(tctx
, "Failed to send async sleep request\n");
439 req
= dcerpc_echo_TestSleep_send(p
, tctx
, &r
);
441 torture_comment(tctx
, "Failed to send async sleep request\n");
444 req
->ignore_timeout
= true;
445 status
= dcerpc_echo_TestSleep_recv(req
);
446 torture_assert_ntstatus_equal(tctx
, status
, NT_STATUS_IO_TIMEOUT
,
447 "request should have timed out");
449 p
->request_timeout
= timeout_saved
;
451 return test_addone(tctx
, p
);
454 p
->request_timeout
= timeout_saved
;
459 struct torture_suite
*torture_rpc_echo(TALLOC_CTX
*mem_ctx
)
461 struct torture_suite
*suite
= torture_suite_create(mem_ctx
, "echo");
462 struct torture_rpc_tcase
*tcase
;
464 tcase
= torture_suite_add_rpc_iface_tcase(suite
, "echo",
467 torture_rpc_tcase_add_test(tcase
, "addone", test_addone
);
468 torture_rpc_tcase_add_test(tcase
, "sinkdata", test_sinkdata
);
469 torture_rpc_tcase_add_test(tcase
, "echodata", test_echodata
);
470 torture_rpc_tcase_add_test(tcase
, "sourcedata", test_sourcedata
);
471 torture_rpc_tcase_add_test(tcase
, "testcall", test_testcall
);
472 torture_rpc_tcase_add_test(tcase
, "testcall2", test_testcall2
);
473 torture_rpc_tcase_add_test(tcase
, "enum", test_enum
);
474 torture_rpc_tcase_add_test(tcase
, "surrounding", test_surrounding
);
475 torture_rpc_tcase_add_test(tcase
, "doublepointer", test_doublepointer
);
476 torture_rpc_tcase_add_test(tcase
, "sleep", test_sleep
);
477 #if 0 /* this test needs fixing to work over ncacn_np */
478 torture_rpc_tcase_add_test(tcase
, "timeout", test_timeout
);