02631d0b444eb139e7c194d15d9340efea4c20a6
[kai/samba.git] / source4 / torture / rpc / echo.c
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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "torture/torture.h"
26 #include "lib/events/events.h"
27 #include "librpc/gen_ndr/ndr_echo.h"
28
29
30 /*
31   test the AddOne interface
32 */
33 #define TEST_ADDONE(value) do { \
34         n = i = value; \
35         r.in.in_data = n; \
36         r.out.out_data = &n; \
37         status = dcerpc_echo_AddOne(p, mem_ctx, &r); \
38         if (!NT_STATUS_IS_OK(status)) { \
39                 printf("AddOne(%d) failed - %s\n", i, nt_errstr(status)); \
40                 return False; \
41         } \
42         if (n != i+1) { \
43                 printf("%d + 1 != %u (should be %u)\n", i, n, i+1); \
44                 ret = False; \
45         } else { \
46                 printf("%d + 1 = %u\n", i, n); \
47         } \
48 } while(0)
49
50 static BOOL test_addone(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
51 {
52         BOOL ret = True;
53         uint32_t i;
54         NTSTATUS status;
55         uint32_t n;
56         struct echo_AddOne r;
57
58         printf("\nTesting AddOne\n");
59
60         for (i=0;i<10;i++) {
61                 TEST_ADDONE(i);
62         }
63
64         TEST_ADDONE(0x7FFFFFFE);
65         TEST_ADDONE(0xFFFFFFFE);
66         TEST_ADDONE(0xFFFFFFFF);
67         TEST_ADDONE(random() & 0xFFFFFFFF);
68
69         return ret;
70 }
71
72 /*
73   test the EchoData interface
74 */
75 static BOOL test_echodata(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
76 {
77         int i;
78         NTSTATUS status;
79         uint8_t *data_in, *data_out;
80         int len;
81         struct echo_EchoData r;
82
83         if (lp_parm_bool(-1, "torture", "quick", False) &&
84             (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
85                 len = 1 + (random() % 500);
86         } else {
87                 len = 1 + (random() % 5000);
88         }
89
90         printf("\nTesting EchoData\n");
91
92         data_in = talloc_size(mem_ctx, len);
93         data_out = talloc_size(mem_ctx, len);
94         for (i=0;i<len;i++) {
95                 data_in[i] = i;
96         }
97         
98         r.in.len = len;
99         r.in.in_data = data_in;
100
101         status = dcerpc_echo_EchoData(p, mem_ctx, &r);
102         if (!NT_STATUS_IS_OK(status)) {
103                 printf("EchoData(%d) failed - %s\n", len, nt_errstr(status));
104                 return False;
105         }
106
107         data_out = r.out.out_data;
108
109         for (i=0;i<len;i++) {
110                 if (data_in[i] != data_out[i]) {
111                         printf("Bad data returned for len %d at offset %d\n", 
112                                len, i);
113                         printf("in:\n");
114                         dump_data(0, data_in+i, MIN(len-i, 16));
115                         printf("out:\n");
116                         dump_data(0, data_out+i, MIN(len-1, 16));
117                         return False;
118                 }
119         }
120
121
122         return True;
123 }
124
125
126 /*
127   test the SourceData interface
128 */
129 static BOOL test_sourcedata(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
130 {
131         int i;
132         NTSTATUS status;
133         int len;
134         struct echo_SourceData r;
135
136         if (lp_parm_bool(-1, "torture", "quick", False) &&
137             (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
138                 len = 100 + (random() % 500);
139         } else {
140                 len = 200000 + (random() % 5000);
141         }
142
143         printf("\nTesting SourceData\n");
144
145         r.in.len = len;
146
147         status = dcerpc_echo_SourceData(p, mem_ctx, &r);
148         if (!NT_STATUS_IS_OK(status)) {
149                 printf("SourceData(%d) failed - %s\n", len, nt_errstr(status));
150                 return False;
151         }
152
153         for (i=0;i<len;i++) {
154                 uint8_t *v = (uint8_t *)r.out.data;
155                 if (v[i] != (i & 0xFF)) {
156                         printf("bad data 0x%x at %d\n", (uint8_t)r.out.data[i], i);
157                         return False;
158                 }
159         }
160
161         return True;
162 }
163
164 /*
165   test the SinkData interface
166 */
167 static BOOL test_sinkdata(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
168 {
169         int i;
170         NTSTATUS status;
171         uint8_t *data_in;
172         int len;
173         struct echo_SinkData r;
174
175         if (lp_parm_bool(-1, "torture", "quick", False) &&
176             (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
177                 len = 100 + (random() % 5000);
178         } else {
179                 len = 200000 + (random() % 5000);
180         }
181
182         printf("\nTesting SinkData\n");
183
184         data_in = talloc_size(mem_ctx, len);
185         for (i=0;i<len;i++) {
186                 data_in[i] = i+1;
187         }
188
189         r.in.len = len;
190         r.in.data = data_in;
191
192         status = dcerpc_echo_SinkData(p, mem_ctx, &r);
193         if (!NT_STATUS_IS_OK(status)) {
194                 printf("SinkData(%d) failed - %s\n", len, nt_errstr(status));
195                 return False;
196         }
197
198         printf("sunk %d bytes\n", len);
199
200         return True;
201 }
202
203
204 /*
205   test the testcall interface
206 */
207 static BOOL test_testcall(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
208 {
209         NTSTATUS status;
210         struct echo_TestCall r;
211
212         r.in.s1 = "input string";
213
214         printf("\nTesting TestCall\n");
215         status = dcerpc_echo_TestCall(p, mem_ctx, &r);
216         if (!NT_STATUS_IS_OK(status)) {
217                 printf("TestCall failed - %s\n", nt_errstr(status));
218                 return False;
219         }
220
221         return True;
222 }
223
224 /*
225   test the testcall interface
226 */
227 static BOOL test_testcall2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
228 {
229         NTSTATUS status;
230         struct echo_TestCall2 r;
231         int i;
232         BOOL ret = True;
233
234         for (i=1;i<=7;i++) {
235                 r.in.level = i;
236                 r.out.info = talloc(mem_ctx, union echo_Info);
237
238                 printf("\nTesting TestCall2 level %d\n", i);
239                 status = dcerpc_echo_TestCall2(p, mem_ctx, &r);
240                 if (!NT_STATUS_IS_OK(status)) {
241                         printf("TestCall2 failed - %s\n", nt_errstr(status));
242                         ret = False;
243                 }
244         }
245
246         return ret;
247 }
248
249 /*
250   test the TestSleep interface
251 */
252 static BOOL test_sleep(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
253 {
254         int i;
255         NTSTATUS status;
256 #define ASYNC_COUNT 3
257         struct rpc_request *req[ASYNC_COUNT];
258         struct echo_TestSleep r[ASYNC_COUNT];
259         BOOL done[ASYNC_COUNT];
260         struct timeval snd[ASYNC_COUNT];
261         struct timeval rcv[ASYNC_COUNT];
262         struct timeval diff[ASYNC_COUNT];
263         struct event_context *ctx;
264         int total_done = 0;
265         BOOL ret = True;
266
267         if (lp_parm_bool(-1, "torture", "quick", False)) {
268                 printf("TestSleep disabled - use \"torture:quick=no\" to enable\n");
269                 return True;
270         }
271         printf("Testing TestSleep - use \"torture:quick=no\" to disable\n");
272
273         for (i=0;i<ASYNC_COUNT;i++) {
274                 done[i]         = False;
275                 snd[i]          = timeval_current();
276                 rcv[i]          = timeval_zero();
277                 r[i].in.seconds = ASYNC_COUNT-i;
278                 req[i] = dcerpc_echo_TestSleep_send(p, mem_ctx, &r[i]);
279                 if (!req[i]) {
280                         printf("Failed to send async sleep request\n");
281                         return False;
282                 }
283         }
284
285         ctx = dcerpc_event_context(p);
286         while (total_done < ASYNC_COUNT) {
287                 if (event_loop_once(ctx) != 0) {
288                         return False;
289                 }
290                 for (i=0;i<ASYNC_COUNT;i++) {
291                         if (done[i] == False && req[i]->state == RPC_REQUEST_DONE) {
292                                 total_done++;
293                                 done[i] = True;
294                                 rcv[i]  = timeval_current();
295                                 diff[i] = timeval_until(&snd[i], &rcv[i]);
296                                 status  = dcerpc_ndr_request_recv(req[i]);
297                                 if (!NT_STATUS_IS_OK(status)) {
298                                         printf("TestSleep(%d) failed - %s\n",
299                                                i, nt_errstr(status));
300                                         ret = False;
301                                 } else if (r[i].out.result != r[i].in.seconds) {
302                                         printf("Failed - Asked to sleep for %u seconds (server replied with %u seconds and the reply takes only %u seconds)\n", 
303                                                 r[i].out.result, r[i].in.seconds, (uint_t)diff[i].tv_sec);
304                                         ret = False;
305                                 } else {
306                                         if (r[i].out.result > diff[i].tv_sec) {
307                                                 printf("Failed - Slept for %u seconds (but reply takes only %u.%06u seconds)\n", 
308                                                         r[i].out.result, (uint_t)diff[i].tv_sec, (uint_t)diff[i].tv_usec);
309                                         } else if (r[i].out.result+1 == diff[i].tv_sec) {
310                                                 printf("Slept for %u seconds (but reply takes %u.%06u seconds - busy server?)\n", 
311                                                         r[i].out.result, (uint_t)diff[i].tv_sec, (uint_t)diff[i].tv_usec);
312                                         } else if (r[i].out.result == diff[i].tv_sec) {
313                                                 printf("Slept for %u seconds (reply takes %u.%06u seconds - ok)\n", 
314                                                         r[i].out.result, (uint_t)diff[i].tv_sec, (uint_t)diff[i].tv_usec);
315                                         } else {
316                                                 printf("(Failed) - Not async - Slept for %u seconds (but reply takes %u.%06u seconds)\n", 
317                                                         r[i].out.result, (uint_t)diff[i].tv_sec, (uint_t)diff[i].tv_usec);
318                                                 /* TODO: let the test fail here, when we support async rpc on ncacn_np
319                                                 ret = False;*/
320                                         }
321                                 }
322                         }
323                 }
324         }
325
326         return ret;
327 }
328
329 /*
330   test enum handling
331 */
332 static BOOL test_enum(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
333 {
334         NTSTATUS status;
335         struct echo_TestEnum r;
336         BOOL ret = True;
337         enum echo_Enum1 v = ECHO_ENUM1;
338         struct echo_Enum2 e2;
339         union echo_Enum3 e3;
340
341         r.in.foo1 = &v;
342         r.in.foo2 = &e2;
343         r.in.foo3 = &e3;
344         r.out.foo1 = &v;
345         r.out.foo2 = &e2;
346         r.out.foo3 = &e3;
347
348         e2.e1 = 76;
349         e2.e2 = ECHO_ENUM1_32;
350         e3.e1 = ECHO_ENUM2;
351
352         printf("\nTesting TestEnum\n");
353         status = dcerpc_echo_TestEnum(p, mem_ctx, &r);
354         if (!NT_STATUS_IS_OK(status)) {
355                 printf("TestEnum failed - %s\n", nt_errstr(status));
356                 ret = False;
357         }
358
359         return ret;
360 }
361
362 /*
363   test surrounding conformant array handling
364 */
365 static BOOL test_surrounding(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
366 {
367         NTSTATUS status;
368         struct echo_TestSurrounding r;
369         BOOL ret = True;
370
371         ZERO_STRUCT(r);
372         r.in.data = talloc(mem_ctx, struct echo_Surrounding);
373
374         r.in.data->x = 20;
375         r.in.data->surrounding = talloc_zero_array(mem_ctx, uint16_t, r.in.data->x);
376
377         r.out.data = talloc(mem_ctx, struct echo_Surrounding);
378
379         printf("\nTesting TestSurrounding\n");
380         status = dcerpc_echo_TestSurrounding(p, mem_ctx, &r);
381         if (!NT_STATUS_IS_OK(status)) {
382                 printf("TestSurrounding failed - %s\n", nt_errstr(status));
383                 return False;
384         }
385         
386         if (r.out.data->x != 2 * r.in.data->x) {
387                 printf("TestSurrounding did not make the array twice as large\n");
388                 ret = False;
389         }
390
391         return ret;
392 }
393
394 /*
395   test multiple levels of pointers
396 */
397 static BOOL test_doublepointer(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
398 {
399         NTSTATUS status;
400         struct echo_TestDoublePointer r;
401         BOOL ret = True;
402         uint16_t value = 12;
403         uint16_t *pvalue = &value;
404         uint16_t **ppvalue = &pvalue;
405
406         ZERO_STRUCT(r);
407         r.in.data = &ppvalue;
408
409         printf("\nTesting TestDoublePointer\n");
410         status = dcerpc_echo_TestDoublePointer(p, mem_ctx, &r);
411         if (!NT_STATUS_IS_OK(status)) {
412                 printf("TestDoublePointer failed - %s\n", nt_errstr(status));
413                 ret = False;
414         }
415
416         if (value != r.out.result) {
417                 printf("TestDoublePointer did not return original value (%d != %d)\n", value, r.out.result);
418                 ret = False;
419         }
420
421         return ret;
422 }
423
424
425 /*
426   test request timeouts
427 */
428 static BOOL test_timeout(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
429 {
430         NTSTATUS status;
431         struct rpc_request *req;
432         struct echo_TestSleep r;
433         int timeout_saved = p->request_timeout;
434
435         if (lp_parm_bool(-1, "torture", "quick", False)) {
436                 printf("timeout testing disabled - use \"torture:quick=no\" to enable\n");
437                 return True;
438         }
439
440         printf("testing request timeouts\n");
441         r.in.seconds = 2;
442         p->request_timeout = 1;
443
444         req = dcerpc_echo_TestSleep_send(p, mem_ctx, &r);
445         if (!req) {
446                 printf("Failed to send async sleep request\n");
447                 goto failed;
448         }
449
450         status  = dcerpc_ndr_request_recv(req);
451         if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
452                 printf("request should have timed out - %s\n", nt_errstr(status));
453                 goto failed;
454         }
455
456         printf("testing request destruction\n");
457         req = dcerpc_echo_TestSleep_send(p, mem_ctx, &r);
458         if (!req) {
459                 printf("Failed to send async sleep request\n");
460                 goto failed;
461         }
462         talloc_free(req);
463
464         req = dcerpc_echo_TestSleep_send(p, mem_ctx, &r);
465         if (!req) {
466                 printf("Failed to send async sleep request\n");
467                 goto failed;
468         }
469         status  = dcerpc_ndr_request_recv(req);
470         if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
471                 printf("request should have timed out - %s\n", nt_errstr(status));
472                 goto failed;
473         }       
474
475         p->request_timeout = timeout_saved;
476         return test_addone(p, mem_ctx);
477
478 failed:
479         p->request_timeout = timeout_saved;
480         return False;
481 }
482
483
484 BOOL torture_rpc_echo(void)
485 {
486         NTSTATUS status;
487         struct dcerpc_pipe *p;
488         TALLOC_CTX *mem_ctx;
489         BOOL ret = True;
490
491         mem_ctx = talloc_init("torture_rpc_echo");
492
493         status = torture_rpc_connection(mem_ctx, 
494                                         &p, 
495                                         &dcerpc_table_rpcecho);
496         if (!NT_STATUS_IS_OK(status)) {
497                 return False;
498         }
499
500         ret &= test_addone(p, mem_ctx);
501         ret &= test_sinkdata(p, mem_ctx);
502         ret &= test_echodata(p, mem_ctx);
503         ret &= test_sourcedata(p, mem_ctx);
504         ret &= test_testcall(p, mem_ctx);
505         ret &= test_testcall2(p, mem_ctx);
506         ret &= test_enum(p, mem_ctx);
507         ret &= test_surrounding(p, mem_ctx);
508         ret &= test_doublepointer(p, mem_ctx);
509         ret &= test_sleep(p, mem_ctx);
510         ret &= test_timeout(p, mem_ctx);
511
512         printf("\n");
513         
514         talloc_free(mem_ctx);
515
516         return ret;
517 }