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 267 : static bool test_addone(struct torture_context *tctx,
43 : struct dcerpc_pipe *p)
44 : {
45 2 : uint32_t i;
46 2 : uint32_t n;
47 2 : struct echo_AddOne r;
48 267 : struct dcerpc_binding_handle *b = p->binding_handle;
49 :
50 2937 : for (i=0;i<10;i++) {
51 2670 : TEST_ADDONE(tctx, i);
52 : }
53 :
54 267 : TEST_ADDONE(tctx, 0x7FFFFFFE);
55 267 : TEST_ADDONE(tctx, 0xFFFFFFFE);
56 267 : TEST_ADDONE(tctx, 0xFFFFFFFF);
57 267 : TEST_ADDONE(tctx, random() & 0xFFFFFFFF);
58 267 : return true;
59 : }
60 :
61 : /*
62 : test the EchoData interface
63 : */
64 267 : static bool test_echodata(struct torture_context *tctx,
65 : struct dcerpc_pipe *p)
66 : {
67 2 : int i;
68 2 : uint8_t *data_in, *data_out;
69 2 : int len;
70 2 : struct echo_EchoData r;
71 267 : struct dcerpc_binding_handle *b = p->binding_handle;
72 :
73 267 : if (torture_setting_bool(tctx, "quick", false) &&
74 222 : (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
75 16 : len = 1 + (random() % 500);
76 : } else {
77 251 : len = 1 + (random() % 5000);
78 : }
79 :
80 267 : data_in = talloc_array(tctx, uint8_t, len);
81 267 : data_out = talloc_array(tctx, uint8_t, len);
82 643435 : for (i=0;i<len;i++) {
83 643166 : data_in[i] = i;
84 : }
85 :
86 267 : r.in.len = len;
87 267 : r.in.in_data = data_in;
88 :
89 267 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_EchoData_r(b, tctx, &r),
90 : talloc_asprintf(tctx, "EchoData(%d) failed\n", len));
91 :
92 267 : data_out = r.out.out_data;
93 :
94 643433 : for (i=0;i<len;i++) {
95 643166 : 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 265 : return true;
106 : }
107 :
108 : /*
109 : test the SourceData interface
110 : */
111 267 : static bool test_sourcedata(struct torture_context *tctx,
112 : struct dcerpc_pipe *p)
113 : {
114 2 : int i;
115 2 : int len;
116 2 : struct echo_SourceData r;
117 267 : struct dcerpc_binding_handle *b = p->binding_handle;
118 :
119 267 : if (torture_setting_bool(tctx, "quick", false) &&
120 222 : (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
121 16 : len = 100 + (random() % 500);
122 : } else {
123 251 : len = 200000 + (random() % 5000);
124 : }
125 :
126 267 : r.in.len = len;
127 :
128 267 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_SourceData_r(b, tctx, &r),
129 : talloc_asprintf(tctx, "SourceData(%d) failed", len));
130 :
131 50892622 : for (i=0;i<len;i++) {
132 50892355 : uint8_t *v = (uint8_t *)r.out.data;
133 50892355 : 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 265 : return true;
138 : }
139 :
140 : /*
141 : test the SinkData interface
142 : */
143 267 : static bool test_sinkdata(struct torture_context *tctx,
144 : struct dcerpc_pipe *p)
145 : {
146 2 : int i;
147 2 : uint8_t *data_in;
148 2 : int len;
149 2 : struct echo_SinkData r;
150 267 : struct dcerpc_binding_handle *b = p->binding_handle;
151 :
152 267 : if (torture_setting_bool(tctx, "quick", false) &&
153 222 : (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
154 16 : len = 100 + (random() % 5000);
155 : } else {
156 251 : len = 200000 + (random() % 5000);
157 : }
158 :
159 267 : data_in = talloc_array(tctx, uint8_t, len);
160 50919144 : for (i=0;i<len;i++) {
161 50918875 : data_in[i] = i+1;
162 : }
163 :
164 267 : r.in.len = len;
165 267 : r.in.data = data_in;
166 :
167 267 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_SinkData_r(b, tctx, &r),
168 : talloc_asprintf(tctx, "SinkData(%d) failed", len));
169 :
170 267 : torture_comment(tctx, "sunk %d bytes\n", len);
171 267 : return true;
172 : }
173 :
174 :
175 : /*
176 : test the testcall interface
177 : */
178 267 : static bool test_testcall(struct torture_context *tctx,
179 : struct dcerpc_pipe *p)
180 : {
181 2 : struct echo_TestCall r;
182 267 : const char *s = NULL;
183 267 : struct dcerpc_binding_handle *b = p->binding_handle;
184 :
185 267 : r.in.s1 = "input string";
186 267 : r.out.s2 = &s;
187 :
188 267 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestCall_r(b, tctx, &r),
189 : "TestCall failed");
190 :
191 263 : torture_assert_str_equal(tctx, s, "input string", "Didn't receive back same string");
192 :
193 261 : return true;
194 : }
195 :
196 : /*
197 : test the testcall interface
198 : */
199 267 : static bool test_testcall2(struct torture_context *tctx,
200 : struct dcerpc_pipe *p)
201 : {
202 2 : struct echo_TestCall2 r;
203 2 : int i;
204 267 : struct dcerpc_binding_handle *b = p->binding_handle;
205 :
206 2108 : for (i=1;i<=7;i++) {
207 1845 : r.in.level = i;
208 1845 : r.out.info = talloc(tctx, union echo_Info);
209 :
210 1845 : torture_comment(tctx, "Testing TestCall2 level %d\n", i);
211 1845 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestCall2_r(b, tctx, &r),
212 : "TestCall2 failed");
213 1841 : torture_assert_ntstatus_ok(tctx, r.out.result, "TestCall2 failed");
214 : }
215 261 : 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 267 : static bool test_sleep(struct torture_context *tctx,
228 : struct dcerpc_pipe *p)
229 : {
230 2 : int i;
231 : #define ASYNC_COUNT 3
232 2 : struct tevent_req *req[ASYNC_COUNT];
233 2 : struct echo_TestSleep r[ASYNC_COUNT];
234 2 : bool done1[ASYNC_COUNT];
235 2 : bool done2[ASYNC_COUNT];
236 2 : struct timeval snd[ASYNC_COUNT];
237 2 : struct timeval rcv[ASYNC_COUNT];
238 2 : struct timeval diff[ASYNC_COUNT];
239 267 : int total_done = 0;
240 267 : struct dcerpc_binding_handle *b = p->binding_handle;
241 2 : enum dcerpc_transport_t transport;
242 2 : uint32_t assoc_group_id;
243 267 : struct dcerpc_pipe *p2 = NULL;
244 2 : NTSTATUS status;
245 :
246 267 : if (torture_setting_bool(tctx, "quick", false)) {
247 222 : 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 1842 : 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 0 : int rounded_tdiff;
281 135 : total_done++;
282 135 : done2[i] = true;
283 135 : rcv[i] = timeval_current();
284 135 : diff[i] = tevent_timeval_until(
285 135 : &snd[i], &rcv[i]);
286 135 : rounded_tdiff = (int)(0.5 + diff[i].tv_sec + (1.0e-6*diff[i].tv_usec));
287 135 : torture_comment(tctx, "rounded_tdiff=%d\n", rounded_tdiff);
288 135 : torture_assert_ntstatus_ok(tctx,
289 : dcerpc_echo_TestSleep_r_recv(req[i], tctx),
290 : talloc_asprintf(tctx, "TestSleep(%d) failed", i));
291 135 : torture_assert(tctx, r[i].out.result == r[i].in.seconds,
292 : talloc_asprintf(tctx, "Failed - Asked to sleep for %u seconds (server replied with %u seconds and the reply takes only %u seconds)",
293 : r[i].out.result, r[i].in.seconds, (unsigned int)diff[i].tv_sec));
294 135 : torture_assert(tctx, r[i].out.result <= rounded_tdiff,
295 : talloc_asprintf(tctx, "Failed - Slept for %u seconds (but reply takes only %u.%06u seconds)",
296 : r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec));
297 135 : if (r[i].out.result+1 == rounded_tdiff) {
298 0 : torture_comment(tctx, "Slept for %u seconds (but reply takes %u.%06u seconds - busy server?)\n",
299 0 : r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec);
300 135 : } else if (r[i].out.result == rounded_tdiff) {
301 135 : torture_comment(tctx, "Slept for %u seconds (reply takes %u.%06u seconds - ok)\n",
302 135 : r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec);
303 : } else {
304 0 : torture_fail(tctx, talloc_asprintf(tctx,
305 : "(Failed) - Not async - Slept for %u seconds (but reply takes %u.%06u seconds)\n",
306 : r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec));
307 : }
308 : }
309 : }
310 : }
311 45 : torture_comment(tctx, "\n");
312 45 : return true;
313 : }
314 :
315 : /*
316 : test enum handling
317 : */
318 267 : static bool test_enum(struct torture_context *tctx,
319 : struct dcerpc_pipe *p)
320 : {
321 2 : struct echo_TestEnum r;
322 267 : enum echo_Enum1 v = ECHO_ENUM1;
323 2 : struct echo_Enum2 e2;
324 2 : union echo_Enum3 e3;
325 267 : struct dcerpc_binding_handle *b = p->binding_handle;
326 :
327 267 : r.in.foo1 = &v;
328 267 : r.in.foo2 = &e2;
329 267 : r.in.foo3 = &e3;
330 267 : r.out.foo1 = &v;
331 267 : r.out.foo2 = &e2;
332 267 : r.out.foo3 = &e3;
333 :
334 267 : e2.e1 = 76;
335 267 : e2.e2 = ECHO_ENUM1_32;
336 267 : e3.e1 = ECHO_ENUM2;
337 :
338 267 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestEnum_r(b, tctx, &r),
339 : "TestEnum failed");
340 263 : return true;
341 : }
342 :
343 : /*
344 : test surrounding conformant array handling
345 : */
346 267 : static bool test_surrounding(struct torture_context *tctx,
347 : struct dcerpc_pipe *p)
348 : {
349 2 : struct echo_TestSurrounding r;
350 267 : struct dcerpc_binding_handle *b = p->binding_handle;
351 :
352 267 : ZERO_STRUCT(r);
353 267 : r.in.data = talloc(tctx, struct echo_Surrounding);
354 :
355 267 : r.in.data->x = 20;
356 267 : r.in.data->surrounding = talloc_zero_array(tctx, uint16_t, r.in.data->x);
357 :
358 267 : r.out.data = talloc(tctx, struct echo_Surrounding);
359 :
360 267 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestSurrounding_r(b, tctx, &r),
361 : "TestSurrounding failed");
362 :
363 263 : torture_assert(tctx, r.out.data->x == 2 * r.in.data->x,
364 : "TestSurrounding did not make the array twice as large");
365 :
366 261 : return true;
367 : }
368 :
369 : /*
370 : test multiple levels of pointers
371 : */
372 267 : static bool test_doublepointer(struct torture_context *tctx,
373 : struct dcerpc_pipe *p)
374 : {
375 2 : struct echo_TestDoublePointer r;
376 267 : uint16_t value = 12;
377 267 : uint16_t *pvalue = &value;
378 267 : uint16_t **ppvalue = &pvalue;
379 267 : struct dcerpc_binding_handle *b = p->binding_handle;
380 :
381 267 : ZERO_STRUCT(r);
382 267 : r.in.data = &ppvalue;
383 :
384 267 : torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestDoublePointer_r(b, tctx, &r),
385 : "TestDoublePointer failed");
386 :
387 263 : torture_assert_int_equal(tctx, value, r.out.result,
388 : "TestDoublePointer did not return original value");
389 261 : return true;
390 : }
391 :
392 :
393 : /*
394 : test request timeouts
395 : */
396 : #if 0 /* this test needs fixing to work over ncacn_np */
397 : static bool test_timeout(struct torture_context *tctx,
398 : struct dcerpc_pipe *p)
399 : {
400 : NTSTATUS status;
401 : struct rpc_request *req;
402 : struct echo_TestSleep r;
403 : int timeout_saved = p->request_timeout;
404 :
405 : if (torture_setting_bool(tctx, "quick", false)) {
406 : torture_skip(tctx, "timeout testing disabled - use \"torture:quick=no\" to enable\n");
407 : }
408 :
409 : torture_comment(tctx, "testing request timeouts\n");
410 : r.in.seconds = 2;
411 : p->request_timeout = 1;
412 :
413 : req = dcerpc_echo_TestSleep_send(p, tctx, &r);
414 : if (!req) {
415 : torture_comment(tctx, "Failed to send async sleep request\n");
416 : goto failed;
417 : }
418 : req->ignore_timeout = true;
419 :
420 : status = dcerpc_echo_TestSleep_recv(req);
421 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_IO_TIMEOUT,
422 : "request should have timed out");
423 :
424 : torture_comment(tctx, "testing request destruction\n");
425 : req = dcerpc_echo_TestSleep_send(p, tctx, &r);
426 : if (!req) {
427 : torture_comment(tctx, "Failed to send async sleep request\n");
428 : goto failed;
429 : }
430 : talloc_free(req);
431 :
432 : req = dcerpc_echo_TestSleep_send(p, tctx, &r);
433 : if (!req) {
434 : torture_comment(tctx, "Failed to send async sleep request\n");
435 : goto failed;
436 : }
437 : req->ignore_timeout = true;
438 : status = dcerpc_echo_TestSleep_recv(req);
439 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_IO_TIMEOUT,
440 : "request should have timed out");
441 :
442 : p->request_timeout = timeout_saved;
443 :
444 : return test_addone(tctx, p);
445 :
446 : failed:
447 : p->request_timeout = timeout_saved;
448 : return false;
449 : }
450 : #endif
451 :
452 2354 : struct torture_suite *torture_rpc_echo(TALLOC_CTX *mem_ctx)
453 : {
454 2354 : struct torture_suite *suite = torture_suite_create(mem_ctx, "echo");
455 125 : struct torture_rpc_tcase *tcase;
456 :
457 2354 : tcase = torture_suite_add_rpc_iface_tcase(suite, "echo",
458 : &ndr_table_rpcecho);
459 :
460 2354 : torture_rpc_tcase_add_test(tcase, "addone", test_addone);
461 2354 : torture_rpc_tcase_add_test(tcase, "sinkdata", test_sinkdata);
462 2354 : torture_rpc_tcase_add_test(tcase, "echodata", test_echodata);
463 2354 : torture_rpc_tcase_add_test(tcase, "sourcedata", test_sourcedata);
464 2354 : torture_rpc_tcase_add_test(tcase, "testcall", test_testcall);
465 2354 : torture_rpc_tcase_add_test(tcase, "testcall2", test_testcall2);
466 2354 : torture_rpc_tcase_add_test(tcase, "enum", test_enum);
467 2354 : torture_rpc_tcase_add_test(tcase, "surrounding", test_surrounding);
468 2354 : torture_rpc_tcase_add_test(tcase, "doublepointer", test_doublepointer);
469 2354 : torture_rpc_tcase_add_test(tcase, "sleep", test_sleep);
470 : #if 0 /* this test needs fixing to work over ncacn_np */
471 : torture_rpc_tcase_add_test(tcase, "timeout", test_timeout);
472 : #endif
473 :
474 2354 : return suite;
475 : }
|