Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : local test for irpc code
5 :
6 : Copyright (C) Andrew Tridgell 2004
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "lib/events/events.h"
24 : #include "lib/messaging/irpc.h"
25 : #include "librpc/gen_ndr/ndr_echo.h"
26 : #include "librpc/gen_ndr/ndr_echo_c.h"
27 : #include "torture/torture.h"
28 : #include "cluster/cluster.h"
29 : #include "param/param.h"
30 : #include "torture/local/proto.h"
31 :
32 : const uint32_t MSG_ID1 = 1, MSG_ID2 = 2;
33 :
34 : static bool test_debug;
35 :
36 : struct irpc_test_data
37 : {
38 : struct imessaging_context *msg_ctx1, *msg_ctx2;
39 : struct tevent_context *ev;
40 : };
41 :
42 : /*
43 : serve up AddOne over the irpc system
44 : */
45 16533 : static NTSTATUS irpc_AddOne(struct irpc_message *irpc, struct echo_AddOne *r)
46 : {
47 16533 : *r->out.out_data = r->in.in_data + 1;
48 16533 : if (test_debug) {
49 16538 : printf("irpc_AddOne: in=%u in+1=%u out=%u\n",
50 5 : r->in.in_data, r->in.in_data+1, *r->out.out_data);
51 : }
52 16533 : return NT_STATUS_OK;
53 : }
54 :
55 : /*
56 : a deferred reply to echodata
57 : */
58 1 : static void deferred_echodata(struct tevent_context *ev, struct tevent_timer *te,
59 : struct timeval t, void *private_data)
60 : {
61 1 : struct irpc_message *irpc = talloc_get_type(private_data, struct irpc_message);
62 1 : struct echo_EchoData *r = (struct echo_EchoData *)irpc->data;
63 1 : r->out.out_data = (uint8_t *)talloc_memdup(r, r->in.in_data, r->in.len);
64 1 : if (r->out.out_data == NULL) {
65 0 : irpc_send_reply(irpc, NT_STATUS_NO_MEMORY);
66 : }
67 1 : printf("sending deferred reply\n");
68 1 : irpc_send_reply(irpc, NT_STATUS_OK);
69 1 : }
70 :
71 :
72 : /*
73 : serve up EchoData over the irpc system
74 : */
75 1 : static NTSTATUS irpc_EchoData(struct irpc_message *irpc, struct echo_EchoData *r)
76 : {
77 1 : struct irpc_test_data *data = talloc_get_type_abort(irpc->private_data, struct irpc_test_data);
78 1 : irpc->defer_reply = true;
79 1 : tevent_add_timer(data->ev, irpc, timeval_zero(), deferred_echodata, irpc);
80 1 : return NT_STATUS_OK;
81 : }
82 :
83 :
84 : /*
85 : test a addone call over the internal messaging system
86 : */
87 5 : static bool test_addone(struct torture_context *test, const void *_data,
88 : const void *_value)
89 : {
90 5 : struct echo_AddOne r;
91 5 : NTSTATUS status;
92 5 : const struct irpc_test_data *data = (const struct irpc_test_data *)_data;
93 5 : uint32_t value = *(const uint32_t *)_value;
94 5 : struct dcerpc_binding_handle *irpc_handle;
95 :
96 5 : irpc_handle = irpc_binding_handle(test, data->msg_ctx1,
97 : cluster_id(0, MSG_ID2),
98 : &ndr_table_rpcecho);
99 5 : torture_assert(test, irpc_handle, "no memory");
100 :
101 : /* make the call */
102 5 : r.in.in_data = value;
103 :
104 5 : test_debug = true;
105 : /*
106 : * Note: this makes use of nested event loops
107 : * as client and server use the same loop.
108 : */
109 5 : dcerpc_binding_handle_set_sync_ev(irpc_handle, data->ev);
110 5 : status = dcerpc_echo_AddOne_r(irpc_handle, test, &r);
111 5 : test_debug = false;
112 5 : torture_assert_ntstatus_ok(test, status, "AddOne failed");
113 :
114 : /* check the answer */
115 5 : torture_assert(test, *r.out.out_data == r.in.in_data + 1,
116 : "AddOne wrong answer");
117 :
118 5 : torture_comment(test, "%u + 1 = %u\n", r.in.in_data, *r.out.out_data);
119 5 : return true;
120 : }
121 :
122 : /*
123 : test a echodata call over the internal messaging system
124 : */
125 1 : static bool test_echodata(struct torture_context *tctx,
126 : const void *tcase_data,
127 : const void *test_data)
128 : {
129 1 : struct echo_EchoData r;
130 1 : NTSTATUS status;
131 1 : const struct irpc_test_data *data = (const struct irpc_test_data *)tcase_data;
132 1 : TALLOC_CTX *mem_ctx = tctx;
133 1 : struct dcerpc_binding_handle *irpc_handle;
134 :
135 1 : irpc_handle = irpc_binding_handle(mem_ctx, data->msg_ctx1,
136 : cluster_id(0, MSG_ID2),
137 : &ndr_table_rpcecho);
138 1 : torture_assert(tctx, irpc_handle, "no memory");
139 :
140 : /* make the call */
141 1 : r.in.in_data = (unsigned char *)talloc_strdup(mem_ctx, "0123456789");
142 1 : r.in.len = strlen((char *)r.in.in_data);
143 :
144 : /*
145 : * Note: this makes use of nested event loops
146 : * as client and server use the same loop.
147 : */
148 1 : dcerpc_binding_handle_set_sync_ev(irpc_handle, data->ev);
149 1 : status = dcerpc_echo_EchoData_r(irpc_handle, mem_ctx, &r);
150 1 : torture_assert_ntstatus_ok(tctx, status, "EchoData failed");
151 :
152 : /* check the answer */
153 1 : if (memcmp(r.out.out_data, r.in.in_data, r.in.len) != 0) {
154 0 : NDR_PRINT_OUT_DEBUG(echo_EchoData, &r);
155 0 : torture_fail(tctx, "EchoData wrong answer");
156 : }
157 :
158 1 : torture_comment(tctx, "Echo '%*.*s' -> '%*.*s'\n",
159 : r.in.len, r.in.len,
160 : r.in.in_data,
161 : r.in.len, r.in.len,
162 : r.out.out_data);
163 1 : return true;
164 : }
165 :
166 : struct irpc_callback_state {
167 : struct echo_AddOne r;
168 : int *pong_count;
169 : };
170 :
171 16528 : static void irpc_callback(struct tevent_req *subreq)
172 : {
173 16528 : struct irpc_callback_state *s =
174 16528 : tevent_req_callback_data(subreq,
175 : struct irpc_callback_state);
176 16528 : NTSTATUS status;
177 :
178 16528 : status = dcerpc_echo_AddOne_r_recv(subreq, s);
179 16528 : TALLOC_FREE(subreq);
180 16528 : if (!NT_STATUS_IS_OK(status)) {
181 0 : printf("irpc call failed - %s\n", nt_errstr(status));
182 : }
183 16528 : if (*s->r.out.out_data != s->r.in.in_data + 1) {
184 0 : printf("AddOne wrong answer - %u + 1 = %u should be %u\n",
185 0 : s->r.in.in_data, *s->r.out.out_data, s->r.in.in_data+1);
186 : }
187 16528 : (*s->pong_count)++;
188 16528 : }
189 :
190 : /*
191 : test echo speed
192 : */
193 1 : static bool test_speed(struct torture_context *tctx,
194 : const void *tcase_data,
195 : const void *test_data)
196 : {
197 1 : int ping_count = 0;
198 1 : int pong_count = 0;
199 1 : const struct irpc_test_data *data = (const struct irpc_test_data *)tcase_data;
200 1 : struct timeval tv;
201 1 : TALLOC_CTX *mem_ctx = tctx;
202 1 : int timelimit = torture_setting_int(tctx, "timelimit", 10);
203 1 : struct dcerpc_binding_handle *irpc_handle;
204 :
205 1 : irpc_handle = irpc_binding_handle(mem_ctx, data->msg_ctx1,
206 : cluster_id(0, MSG_ID2),
207 : &ndr_table_rpcecho);
208 1 : torture_assert(tctx, irpc_handle, "no memory");
209 :
210 1 : tv = timeval_current();
211 :
212 1 : torture_comment(tctx, "Sending echo for %d seconds\n", timelimit);
213 16529 : while (timeval_elapsed(&tv) < timelimit) {
214 16528 : struct tevent_req *subreq;
215 16528 : struct irpc_callback_state *s;
216 :
217 16528 : s = talloc_zero(mem_ctx, struct irpc_callback_state);
218 16528 : torture_assert(tctx, s != NULL, "no mem");
219 :
220 16528 : s->pong_count = &pong_count;
221 :
222 16528 : subreq = dcerpc_echo_AddOne_r_send(mem_ctx,
223 : tctx->ev,
224 : irpc_handle,
225 : &s->r);
226 16528 : torture_assert(tctx, subreq != NULL, "AddOne send failed");
227 :
228 16528 : tevent_req_set_callback(subreq, irpc_callback, s);
229 :
230 16528 : ping_count++;
231 :
232 148508 : while (ping_count > pong_count + 20) {
233 131980 : tevent_loop_once(data->ev);
234 : }
235 : }
236 :
237 1 : torture_comment(tctx, "waiting for %d remaining replies (done %d)\n",
238 : ping_count - pong_count, pong_count);
239 82 : while (timeval_elapsed(&tv) < 30 && pong_count < ping_count) {
240 81 : tevent_loop_once(data->ev);
241 : }
242 :
243 1 : torture_assert_int_equal(tctx, ping_count, pong_count, "ping test failed");
244 :
245 2 : torture_comment(tctx, "echo rate of %.0f messages/sec\n",
246 1 : (ping_count+pong_count)/timeval_elapsed(&tv));
247 1 : return true;
248 : }
249 :
250 :
251 1 : static bool irpc_setup(struct torture_context *tctx, void **_data)
252 : {
253 1 : struct irpc_test_data *data;
254 :
255 1 : *_data = data = talloc(tctx, struct irpc_test_data);
256 :
257 1 : lpcfg_set_cmdline(tctx->lp_ctx, "pid directory", "piddir.tmp");
258 :
259 1 : data->ev = tctx->ev;
260 1 : torture_assert(tctx, data->msg_ctx1 =
261 : imessaging_init(tctx,
262 : tctx->lp_ctx,
263 : cluster_id(0, MSG_ID1),
264 : data->ev),
265 : "Failed to init first messaging context");
266 :
267 1 : torture_assert(tctx, data->msg_ctx2 =
268 : imessaging_init(tctx,
269 : tctx->lp_ctx,
270 : cluster_id(0, MSG_ID2),
271 : data->ev),
272 : "Failed to init second messaging context");
273 :
274 : /* register the server side function */
275 1 : IRPC_REGISTER(data->msg_ctx1, rpcecho, ECHO_ADDONE, irpc_AddOne, data);
276 1 : IRPC_REGISTER(data->msg_ctx2, rpcecho, ECHO_ADDONE, irpc_AddOne, data);
277 :
278 1 : IRPC_REGISTER(data->msg_ctx1, rpcecho, ECHO_ECHODATA, irpc_EchoData, data);
279 1 : IRPC_REGISTER(data->msg_ctx2, rpcecho, ECHO_ECHODATA, irpc_EchoData, data);
280 :
281 1 : return true;
282 : }
283 :
284 2354 : struct torture_suite *torture_local_irpc(TALLOC_CTX *mem_ctx)
285 : {
286 2354 : struct torture_suite *suite = torture_suite_create(mem_ctx, "irpc");
287 2354 : struct torture_tcase *tcase = torture_suite_add_tcase(suite, "irpc");
288 125 : int i;
289 2354 : uint32_t *values = talloc_array(tcase, uint32_t, 5);
290 :
291 2354 : values[0] = 0;
292 2354 : values[1] = 0x7FFFFFFE;
293 2354 : values[2] = 0xFFFFFFFE;
294 2354 : values[3] = 0xFFFFFFFF;
295 2354 : values[4] = random() & 0xFFFFFFFF;
296 :
297 2354 : tcase->setup = irpc_setup;
298 :
299 14124 : for (i = 0; i < 5; i++) {
300 11770 : torture_tcase_add_test_const(tcase, "addone", test_addone,
301 11770 : (void *)&values[i]);
302 : }
303 :
304 2354 : torture_tcase_add_test_const(tcase, "echodata", test_echodata, NULL);
305 2354 : torture_tcase_add_test_const(tcase, "speed", test_speed, NULL);
306 :
307 2354 : return suite;
308 : }
|