docs: fix a typo in history file
[bbaumbach/samba-autobuild/.git] / source4 / lib / messaging / tests / irpc.c
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 static NTSTATUS irpc_AddOne(struct irpc_message *irpc, struct echo_AddOne *r)
46 {
47         *r->out.out_data = r->in.in_data + 1;
48         if (test_debug) {
49                 printf("irpc_AddOne: in=%u in+1=%u out=%u\n", 
50                         r->in.in_data, r->in.in_data+1, *r->out.out_data);
51         }
52         return NT_STATUS_OK;
53 }
54
55 /*
56   a deferred reply to echodata
57 */
58 static void deferred_echodata(struct tevent_context *ev, struct tevent_timer *te, 
59                               struct timeval t, void *private_data)
60 {
61         struct irpc_message *irpc = talloc_get_type(private_data, struct irpc_message);
62         struct echo_EchoData *r = (struct echo_EchoData *)irpc->data;
63         r->out.out_data = (uint8_t *)talloc_memdup(r, r->in.in_data, r->in.len);
64         if (r->out.out_data == NULL) {
65                 irpc_send_reply(irpc, NT_STATUS_NO_MEMORY);
66         }
67         printf("sending deferred reply\n");
68         irpc_send_reply(irpc, NT_STATUS_OK);
69 }
70
71
72 /*
73   serve up EchoData over the irpc system
74 */
75 static NTSTATUS irpc_EchoData(struct irpc_message *irpc, struct echo_EchoData *r)
76 {
77         struct irpc_test_data *data = talloc_get_type_abort(irpc->private_data, struct irpc_test_data);
78         irpc->defer_reply = true;
79         tevent_add_timer(data->ev, irpc, timeval_zero(), deferred_echodata, irpc);
80         return NT_STATUS_OK;
81 }
82
83
84 /*
85   test a addone call over the internal messaging system
86 */
87 static bool test_addone(struct torture_context *test, const void *_data,
88                         const void *_value)
89 {
90         struct echo_AddOne r;
91         NTSTATUS status;
92         const struct irpc_test_data *data = (const struct irpc_test_data *)_data;
93         uint32_t value = *(const uint32_t *)_value;
94         struct dcerpc_binding_handle *irpc_handle;
95
96         irpc_handle = irpc_binding_handle(test, data->msg_ctx1,
97                                           cluster_id(0, MSG_ID2),
98                                           &ndr_table_rpcecho);
99         torture_assert(test, irpc_handle, "no memory");
100
101         /* make the call */
102         r.in.in_data = value;
103
104         test_debug = true;
105         /*
106          * Note: this makes use of nested event loops
107          * as client and server use the same loop.
108          */
109         dcerpc_binding_handle_set_sync_ev(irpc_handle, data->ev);
110         status = dcerpc_echo_AddOne_r(irpc_handle, test, &r);
111         test_debug = false;
112         torture_assert_ntstatus_ok(test, status, "AddOne failed");
113
114         /* check the answer */
115         torture_assert(test, *r.out.out_data == r.in.in_data + 1, 
116                                    "AddOne wrong answer");
117
118         torture_comment(test, "%u + 1 = %u\n", r.in.in_data, *r.out.out_data);
119         return true;
120 }
121
122 /*
123   test a echodata call over the internal messaging system
124 */
125 static bool test_echodata(struct torture_context *tctx,
126                                                   const void *tcase_data,
127                                                   const void *test_data)
128 {
129         struct echo_EchoData r;
130         NTSTATUS status;
131         const struct irpc_test_data *data = (const struct irpc_test_data *)tcase_data;
132         TALLOC_CTX *mem_ctx = tctx;
133         struct dcerpc_binding_handle *irpc_handle;
134
135         irpc_handle = irpc_binding_handle(mem_ctx, data->msg_ctx1,
136                                           cluster_id(0, MSG_ID2),
137                                           &ndr_table_rpcecho);
138         torture_assert(tctx, irpc_handle, "no memory");
139
140         /* make the call */
141         r.in.in_data = (unsigned char *)talloc_strdup(mem_ctx, "0123456789");
142         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         dcerpc_binding_handle_set_sync_ev(irpc_handle, data->ev);
149         status = dcerpc_echo_EchoData_r(irpc_handle, mem_ctx, &r);
150         torture_assert_ntstatus_ok(tctx, status, "EchoData failed");
151
152         /* check the answer */
153         if (memcmp(r.out.out_data, r.in.in_data, r.in.len) != 0) {
154                 NDR_PRINT_OUT_DEBUG(echo_EchoData, &r);
155                 torture_fail(tctx, "EchoData wrong answer");
156         }
157
158         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         return true;
164 }
165
166 struct irpc_callback_state {
167         struct echo_AddOne r;
168         int *pong_count;
169 };
170
171 static void irpc_callback(struct tevent_req *subreq)
172 {
173         struct irpc_callback_state *s =
174                 tevent_req_callback_data(subreq,
175                 struct irpc_callback_state);
176         NTSTATUS status;
177
178         status = dcerpc_echo_AddOne_r_recv(subreq, s);
179         TALLOC_FREE(subreq);
180         if (!NT_STATUS_IS_OK(status)) {
181                 printf("irpc call failed - %s\n", nt_errstr(status));
182         }
183         if (*s->r.out.out_data != s->r.in.in_data + 1) {
184                 printf("AddOne wrong answer - %u + 1 = %u should be %u\n", 
185                        s->r.in.in_data, *s->r.out.out_data, s->r.in.in_data+1);
186         }
187         (*s->pong_count)++;
188 }
189
190 /*
191   test echo speed
192 */
193 static bool test_speed(struct torture_context *tctx,
194                                            const void *tcase_data,
195                                            const void *test_data)
196 {
197         int ping_count = 0;
198         int pong_count = 0;
199         const struct irpc_test_data *data = (const struct irpc_test_data *)tcase_data;
200         struct timeval tv;
201         TALLOC_CTX *mem_ctx = tctx;
202         int timelimit = torture_setting_int(tctx, "timelimit", 10);
203         struct dcerpc_binding_handle *irpc_handle;
204
205         irpc_handle = irpc_binding_handle(mem_ctx, data->msg_ctx1,
206                                           cluster_id(0, MSG_ID2),
207                                           &ndr_table_rpcecho);
208         torture_assert(tctx, irpc_handle, "no memory");
209
210         tv = timeval_current();
211
212         torture_comment(tctx, "Sending echo for %d seconds\n", timelimit);
213         while (timeval_elapsed(&tv) < timelimit) {
214                 struct tevent_req *subreq;
215                 struct irpc_callback_state *s;
216
217                 s = talloc_zero(mem_ctx, struct irpc_callback_state);
218                 torture_assert(tctx, s != NULL, "no mem");
219
220                 s->pong_count = &pong_count;
221
222                 subreq = dcerpc_echo_AddOne_r_send(mem_ctx,
223                                                    tctx->ev,
224                                                    irpc_handle,
225                                                    &s->r);
226                 torture_assert(tctx, subreq != NULL, "AddOne send failed");
227
228                 tevent_req_set_callback(subreq, irpc_callback, s);
229
230                 ping_count++;
231
232                 while (ping_count > pong_count + 20) {
233                         tevent_loop_once(data->ev);
234                 }
235         }
236
237         torture_comment(tctx, "waiting for %d remaining replies (done %d)\n", 
238                ping_count - pong_count, pong_count);
239         while (timeval_elapsed(&tv) < 30 && pong_count < ping_count) {
240                 tevent_loop_once(data->ev);
241         }
242
243         torture_assert_int_equal(tctx, ping_count, pong_count, "ping test failed");
244
245         torture_comment(tctx, "echo rate of %.0f messages/sec\n", 
246                (ping_count+pong_count)/timeval_elapsed(&tv));
247         return true;
248 }
249
250
251 static bool irpc_setup(struct torture_context *tctx, void **_data)
252 {
253         struct irpc_test_data *data;
254
255         *_data = data = talloc(tctx, struct irpc_test_data);
256
257         lpcfg_set_cmdline(tctx->lp_ctx, "pid directory", "piddir.tmp");
258
259         data->ev = tctx->ev;
260         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         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         IRPC_REGISTER(data->msg_ctx1, rpcecho, ECHO_ADDONE, irpc_AddOne, data);
276         IRPC_REGISTER(data->msg_ctx2, rpcecho, ECHO_ADDONE, irpc_AddOne, data);
277
278         IRPC_REGISTER(data->msg_ctx1, rpcecho, ECHO_ECHODATA, irpc_EchoData, data);
279         IRPC_REGISTER(data->msg_ctx2, rpcecho, ECHO_ECHODATA, irpc_EchoData, data);
280
281         return true;
282 }
283
284 struct torture_suite *torture_local_irpc(TALLOC_CTX *mem_ctx)
285 {
286         struct torture_suite *suite = torture_suite_create(mem_ctx, "irpc");
287         struct torture_tcase *tcase = torture_suite_add_tcase(suite, "irpc");
288         int i;
289         uint32_t *values = talloc_array(tcase, uint32_t, 5);
290
291         values[0] = 0;
292         values[1] = 0x7FFFFFFE;
293         values[2] = 0xFFFFFFFE;
294         values[3] = 0xFFFFFFFF;
295         values[4] = random() & 0xFFFFFFFF;
296
297         tcase->setup = irpc_setup;
298
299         for (i = 0; i < 5; i++) {
300                 torture_tcase_add_test_const(tcase, "addone", test_addone,
301                                 (void *)&values[i]);
302         }
303
304         torture_tcase_add_test_const(tcase, "echodata", test_echodata, NULL);
305         torture_tcase_add_test_const(tcase, "speed", test_speed, NULL);
306
307         return suite;
308 }