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