root/source4/torture/rpc/echo.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. test_addone
  2. test_echodata
  3. test_sourcedata
  4. test_sinkdata
  5. test_testcall
  6. test_testcall2
  7. test_sleep
  8. test_enum
  9. test_surrounding
  10. test_doublepointer
  11. test_timeout
  12. torture_rpc_echo

   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, 
     /* [<][>][^][v][top][bottom][index][help] */
  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,
     /* [<][>][^][v][top][bottom][index][help] */
  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,
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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 }

/* [<][>][^][v][top][bottom][index][help] */