~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/torture/rpc/echo.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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