LCOV - code coverage report
Current view: top level - source4/torture/rpc - echo.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 197 207 95.2 %
Date: 2024-04-21 15:09:00 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         267 : static bool test_addone(struct torture_context *tctx, 
      43             :                         struct dcerpc_pipe *p)
      44             : {
      45           2 :         uint32_t i;
      46           2 :         uint32_t n;
      47           2 :         struct echo_AddOne r;
      48         267 :         struct dcerpc_binding_handle *b = p->binding_handle;
      49             : 
      50        2937 :         for (i=0;i<10;i++) {
      51        2670 :                 TEST_ADDONE(tctx, i);
      52             :         }
      53             : 
      54         267 :         TEST_ADDONE(tctx, 0x7FFFFFFE);
      55         267 :         TEST_ADDONE(tctx, 0xFFFFFFFE);
      56         267 :         TEST_ADDONE(tctx, 0xFFFFFFFF);
      57         267 :         TEST_ADDONE(tctx, random() & 0xFFFFFFFF);
      58         267 :         return true;
      59             : }
      60             : 
      61             : /*
      62             :   test the EchoData interface
      63             : */
      64         267 : static bool test_echodata(struct torture_context *tctx,
      65             :                           struct dcerpc_pipe *p)
      66             : {
      67           2 :         int i;
      68           2 :         uint8_t *data_in, *data_out;
      69           2 :         int len;
      70           2 :         struct echo_EchoData r;
      71         267 :         struct dcerpc_binding_handle *b = p->binding_handle;
      72             : 
      73         267 :         if (torture_setting_bool(tctx, "quick", false) &&
      74         222 :             (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
      75          16 :                 len = 1 + (random() % 500);
      76             :         } else {
      77         251 :                 len = 1 + (random() % 5000);
      78             :         }
      79             : 
      80         267 :         data_in = talloc_array(tctx, uint8_t, len);
      81         267 :         data_out = talloc_array(tctx, uint8_t, len);
      82      643435 :         for (i=0;i<len;i++) {
      83      643166 :                 data_in[i] = i;
      84             :         }
      85             :         
      86         267 :         r.in.len = len;
      87         267 :         r.in.in_data = data_in;
      88             : 
      89         267 :         torture_assert_ntstatus_ok(tctx, dcerpc_echo_EchoData_r(b, tctx, &r),
      90             :                 talloc_asprintf(tctx, "EchoData(%d) failed\n", len));
      91             : 
      92         267 :         data_out = r.out.out_data;
      93             : 
      94      643433 :         for (i=0;i<len;i++) {
      95      643166 :                 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         265 :         return true;
     106             : }
     107             : 
     108             : /*
     109             :   test the SourceData interface
     110             : */
     111         267 : static bool test_sourcedata(struct torture_context *tctx,
     112             :                             struct dcerpc_pipe *p)
     113             : {
     114           2 :         int i;
     115           2 :         int len;
     116           2 :         struct echo_SourceData r;
     117         267 :         struct dcerpc_binding_handle *b = p->binding_handle;
     118             : 
     119         267 :         if (torture_setting_bool(tctx, "quick", false) &&
     120         222 :             (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
     121          16 :                 len = 100 + (random() % 500);
     122             :         } else {
     123         251 :                 len = 200000 + (random() % 5000);
     124             :         }
     125             : 
     126         267 :         r.in.len = len;
     127             : 
     128         267 :         torture_assert_ntstatus_ok(tctx, dcerpc_echo_SourceData_r(b, tctx, &r),
     129             :                 talloc_asprintf(tctx, "SourceData(%d) failed", len));
     130             : 
     131    50892622 :         for (i=0;i<len;i++) {
     132    50892355 :                 uint8_t *v = (uint8_t *)r.out.data;
     133    50892355 :                 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         265 :         return true;
     138             : }
     139             : 
     140             : /*
     141             :   test the SinkData interface
     142             : */
     143         267 : static bool test_sinkdata(struct torture_context *tctx, 
     144             :                           struct dcerpc_pipe *p)
     145             : {
     146           2 :         int i;
     147           2 :         uint8_t *data_in;
     148           2 :         int len;
     149           2 :         struct echo_SinkData r;
     150         267 :         struct dcerpc_binding_handle *b = p->binding_handle;
     151             : 
     152         267 :         if (torture_setting_bool(tctx, "quick", false) &&
     153         222 :             (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
     154          16 :                 len = 100 + (random() % 5000);
     155             :         } else {
     156         251 :                 len = 200000 + (random() % 5000);
     157             :         }
     158             : 
     159         267 :         data_in = talloc_array(tctx, uint8_t, len);
     160    50919144 :         for (i=0;i<len;i++) {
     161    50918875 :                 data_in[i] = i+1;
     162             :         }
     163             : 
     164         267 :         r.in.len = len;
     165         267 :         r.in.data = data_in;
     166             : 
     167         267 :         torture_assert_ntstatus_ok(tctx, dcerpc_echo_SinkData_r(b, tctx, &r),
     168             :                 talloc_asprintf(tctx, "SinkData(%d) failed", len));
     169             : 
     170         267 :         torture_comment(tctx, "sunk %d bytes\n", len);
     171         267 :         return true;
     172             : }
     173             : 
     174             : 
     175             : /*
     176             :   test the testcall interface
     177             : */
     178         267 : static bool test_testcall(struct torture_context *tctx,
     179             :                           struct dcerpc_pipe *p)
     180             : {
     181           2 :         struct echo_TestCall r;
     182         267 :         const char *s = NULL;
     183         267 :         struct dcerpc_binding_handle *b = p->binding_handle;
     184             : 
     185         267 :         r.in.s1 = "input string";
     186         267 :         r.out.s2 = &s;
     187             : 
     188         267 :         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         267 : static bool test_testcall2(struct torture_context *tctx,
     200             :                            struct dcerpc_pipe *p)
     201             : {
     202           2 :         struct echo_TestCall2 r;
     203           2 :         int i;
     204         267 :         struct dcerpc_binding_handle *b = p->binding_handle;
     205             : 
     206        2108 :         for (i=1;i<=7;i++) {
     207        1845 :                 r.in.level = i;
     208        1845 :                 r.out.info = talloc(tctx, union echo_Info);
     209             : 
     210        1845 :                 torture_comment(tctx, "Testing TestCall2 level %d\n", i);
     211        1845 :                 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         267 : static bool test_sleep(struct torture_context *tctx,
     228             :                        struct dcerpc_pipe *p)
     229             : {
     230           2 :         int i;
     231             : #define ASYNC_COUNT 3
     232           2 :         struct tevent_req *req[ASYNC_COUNT];
     233           2 :         struct echo_TestSleep r[ASYNC_COUNT];
     234           2 :         bool done1[ASYNC_COUNT];
     235           2 :         bool done2[ASYNC_COUNT];
     236           2 :         struct timeval snd[ASYNC_COUNT];
     237           2 :         struct timeval rcv[ASYNC_COUNT];
     238           2 :         struct timeval diff[ASYNC_COUNT];
     239         267 :         int total_done = 0;
     240         267 :         struct dcerpc_binding_handle *b = p->binding_handle;
     241           2 :         enum dcerpc_transport_t transport;
     242           2 :         uint32_t assoc_group_id;
     243         267 :         struct dcerpc_pipe *p2 = NULL;
     244           2 :         NTSTATUS status;
     245             : 
     246         267 :         if (torture_setting_bool(tctx, "quick", false)) {
     247         222 :                 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        1842 :         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           0 :                                 int rounded_tdiff;
     281         135 :                                 total_done++;
     282         135 :                                 done2[i] = true;
     283         135 :                                 rcv[i]  = timeval_current();
     284         135 :                                 diff[i] = tevent_timeval_until(
     285         135 :                                         &snd[i], &rcv[i]);
     286         135 :                                 rounded_tdiff = (int)(0.5 + diff[i].tv_sec + (1.0e-6*diff[i].tv_usec));
     287         135 :                                 torture_comment(tctx, "rounded_tdiff=%d\n", rounded_tdiff);
     288         135 :                                 torture_assert_ntstatus_ok(tctx,
     289             :                                         dcerpc_echo_TestSleep_r_recv(req[i], tctx),
     290             :                                         talloc_asprintf(tctx, "TestSleep(%d) failed", i));
     291         135 :                                 torture_assert(tctx, r[i].out.result == r[i].in.seconds,
     292             :                                         talloc_asprintf(tctx, "Failed - Asked to sleep for %u seconds (server replied with %u seconds and the reply takes only %u seconds)", 
     293             :                                                 r[i].out.result, r[i].in.seconds, (unsigned int)diff[i].tv_sec));
     294         135 :                                 torture_assert(tctx, r[i].out.result <= rounded_tdiff, 
     295             :                                         talloc_asprintf(tctx, "Failed - Slept for %u seconds (but reply takes only %u.%06u seconds)", 
     296             :                                                 r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec));
     297         135 :                                 if (r[i].out.result+1 == rounded_tdiff) {
     298           0 :                                         torture_comment(tctx, "Slept for %u seconds (but reply takes %u.%06u seconds - busy server?)\n", 
     299           0 :                                                         r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec);
     300         135 :                                 } else if (r[i].out.result == rounded_tdiff) {
     301         135 :                                         torture_comment(tctx, "Slept for %u seconds (reply takes %u.%06u seconds - ok)\n", 
     302         135 :                                                         r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec);
     303             :                                 } else {
     304           0 :                                         torture_fail(tctx, talloc_asprintf(tctx,
     305             :                                                      "(Failed) - Not async - Slept for %u seconds (but reply takes %u.%06u seconds)\n",
     306             :                                                      r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec));
     307             :                                 }
     308             :                         }
     309             :                 }
     310             :         }
     311          45 :         torture_comment(tctx, "\n");
     312          45 :         return true;
     313             : }
     314             : 
     315             : /*
     316             :   test enum handling
     317             : */
     318         267 : static bool test_enum(struct torture_context *tctx,
     319             :                                                   struct dcerpc_pipe *p)
     320             : {
     321           2 :         struct echo_TestEnum r;
     322         267 :         enum echo_Enum1 v = ECHO_ENUM1;
     323           2 :         struct echo_Enum2 e2;
     324           2 :         union echo_Enum3 e3;
     325         267 :         struct dcerpc_binding_handle *b = p->binding_handle;
     326             : 
     327         267 :         r.in.foo1 = &v;
     328         267 :         r.in.foo2 = &e2;
     329         267 :         r.in.foo3 = &e3;
     330         267 :         r.out.foo1 = &v;
     331         267 :         r.out.foo2 = &e2;
     332         267 :         r.out.foo3 = &e3;
     333             : 
     334         267 :         e2.e1 = 76;
     335         267 :         e2.e2 = ECHO_ENUM1_32;
     336         267 :         e3.e1 = ECHO_ENUM2;
     337             : 
     338         267 :         torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestEnum_r(b, tctx, &r),
     339             :                 "TestEnum failed");
     340         263 :         return true;
     341             : }
     342             : 
     343             : /*
     344             :   test surrounding conformant array handling
     345             : */
     346         267 : static bool test_surrounding(struct torture_context *tctx,
     347             :                                                   struct dcerpc_pipe *p)
     348             : {
     349           2 :         struct echo_TestSurrounding r;
     350         267 :         struct dcerpc_binding_handle *b = p->binding_handle;
     351             : 
     352         267 :         ZERO_STRUCT(r);
     353         267 :         r.in.data = talloc(tctx, struct echo_Surrounding);
     354             : 
     355         267 :         r.in.data->x = 20;
     356         267 :         r.in.data->surrounding = talloc_zero_array(tctx, uint16_t, r.in.data->x);
     357             : 
     358         267 :         r.out.data = talloc(tctx, struct echo_Surrounding);
     359             : 
     360         267 :         torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestSurrounding_r(b, tctx, &r),
     361             :                 "TestSurrounding failed");
     362             :         
     363         263 :         torture_assert(tctx, r.out.data->x == 2 * r.in.data->x,
     364             :                 "TestSurrounding did not make the array twice as large");
     365             : 
     366         261 :         return true;
     367             : }
     368             : 
     369             : /*
     370             :   test multiple levels of pointers
     371             : */
     372         267 : static bool test_doublepointer(struct torture_context *tctx,
     373             :                                struct dcerpc_pipe *p)
     374             : {
     375           2 :         struct echo_TestDoublePointer r;
     376         267 :         uint16_t value = 12;
     377         267 :         uint16_t *pvalue = &value;
     378         267 :         uint16_t **ppvalue = &pvalue;
     379         267 :         struct dcerpc_binding_handle *b = p->binding_handle;
     380             : 
     381         267 :         ZERO_STRUCT(r);
     382         267 :         r.in.data = &ppvalue;
     383             : 
     384         267 :         torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestDoublePointer_r(b, tctx, &r),
     385             :                 "TestDoublePointer failed");
     386             : 
     387         263 :         torture_assert_int_equal(tctx, value, r.out.result, 
     388             :                                         "TestDoublePointer did not return original value");
     389         261 :         return true;
     390             : }
     391             : 
     392             : 
     393             : /*
     394             :   test request timeouts
     395             : */
     396             : #if 0 /* this test needs fixing to work over ncacn_np */
     397             : static bool test_timeout(struct torture_context *tctx,
     398             :                                                  struct dcerpc_pipe *p)
     399             : {
     400             :         NTSTATUS status;
     401             :         struct rpc_request *req;
     402             :         struct echo_TestSleep r;
     403             :         int timeout_saved = p->request_timeout;
     404             : 
     405             :         if (torture_setting_bool(tctx, "quick", false)) {
     406             :                 torture_skip(tctx, "timeout testing disabled - use \"torture:quick=no\" to enable\n");
     407             :         }
     408             : 
     409             :         torture_comment(tctx, "testing request timeouts\n");
     410             :         r.in.seconds = 2;
     411             :         p->request_timeout = 1;
     412             : 
     413             :         req = dcerpc_echo_TestSleep_send(p, tctx, &r);
     414             :         if (!req) {
     415             :                 torture_comment(tctx, "Failed to send async sleep request\n");
     416             :                 goto failed;
     417             :         }
     418             :         req->ignore_timeout = true;
     419             : 
     420             :         status  = dcerpc_echo_TestSleep_recv(req);
     421             :         torture_assert_ntstatus_equal(tctx, status, NT_STATUS_IO_TIMEOUT, 
     422             :                                                                   "request should have timed out");
     423             : 
     424             :         torture_comment(tctx, "testing request destruction\n");
     425             :         req = dcerpc_echo_TestSleep_send(p, tctx, &r);
     426             :         if (!req) {
     427             :                 torture_comment(tctx, "Failed to send async sleep request\n");
     428             :                 goto failed;
     429             :         }
     430             :         talloc_free(req);
     431             : 
     432             :         req = dcerpc_echo_TestSleep_send(p, tctx, &r);
     433             :         if (!req) {
     434             :                 torture_comment(tctx, "Failed to send async sleep request\n");
     435             :                 goto failed;
     436             :         }
     437             :         req->ignore_timeout = true;
     438             :         status  = dcerpc_echo_TestSleep_recv(req);
     439             :         torture_assert_ntstatus_equal(tctx, status, NT_STATUS_IO_TIMEOUT, 
     440             :                 "request should have timed out");
     441             : 
     442             :         p->request_timeout = timeout_saved;
     443             :         
     444             :         return test_addone(tctx, p);
     445             : 
     446             : failed:
     447             :         p->request_timeout = timeout_saved;
     448             :         return false;
     449             : }
     450             : #endif
     451             : 
     452        2354 : struct torture_suite *torture_rpc_echo(TALLOC_CTX *mem_ctx)
     453             : {
     454        2354 :         struct torture_suite *suite = torture_suite_create(mem_ctx, "echo");
     455         125 :         struct torture_rpc_tcase *tcase;
     456             : 
     457        2354 :         tcase = torture_suite_add_rpc_iface_tcase(suite, "echo", 
     458             :                                                   &ndr_table_rpcecho);
     459             : 
     460        2354 :         torture_rpc_tcase_add_test(tcase, "addone", test_addone);
     461        2354 :         torture_rpc_tcase_add_test(tcase, "sinkdata", test_sinkdata);
     462        2354 :         torture_rpc_tcase_add_test(tcase, "echodata", test_echodata);
     463        2354 :         torture_rpc_tcase_add_test(tcase, "sourcedata", test_sourcedata);
     464        2354 :         torture_rpc_tcase_add_test(tcase, "testcall", test_testcall);
     465        2354 :         torture_rpc_tcase_add_test(tcase, "testcall2", test_testcall2);
     466        2354 :         torture_rpc_tcase_add_test(tcase, "enum", test_enum);
     467        2354 :         torture_rpc_tcase_add_test(tcase, "surrounding", test_surrounding);
     468        2354 :         torture_rpc_tcase_add_test(tcase, "doublepointer", test_doublepointer);
     469        2354 :         torture_rpc_tcase_add_test(tcase, "sleep", test_sleep);
     470             : #if 0 /* this test needs fixing to work over ncacn_np */
     471             :         torture_rpc_tcase_add_test(tcase, "timeout", test_timeout);
     472             : #endif
     473             : 
     474        2354 :         return suite;
     475             : }

Generated by: LCOV version 1.14