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