LCOV - code coverage report
Current view: top level - source4/torture/rpc - echo.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 162 171 94.7 %
Date: 2021-09-23 10:06:22 Functions: 12 12 100.0 %

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

Generated by: LCOV version 1.13