2 * Unix SMB/CIFS implementation.
3 * Test async ctdb_req_send/recv
4 * Copyright (C) Volker Lendecke 2020
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "torture/proto.h"
22 #include "ctdbd_conn.h"
23 #include "lib/cluster_support.h"
24 #include "ctdb/include/ctdb_protocol.h"
25 #include "lib/util/tevent_unix.h"
27 extern int torture_nprocs
;
28 extern int torture_numops
;
30 struct ctdb_echo_state
{
31 struct ctdb_req_control_old req
;
36 static void ctdb_echo_done(struct tevent_req
*subreq
);
38 static struct tevent_req
*ctdb_echo_send(
40 struct tevent_context
*ev
,
41 struct ctdbd_connection
*conn
,
44 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
45 struct ctdb_echo_state
*state
= NULL
;
46 struct ctdb_req_header
*hdr
= NULL
;
49 req
= tevent_req_create(
50 mem_ctx
, &state
, struct ctdb_echo_state
);
55 hdr
= &state
->req
.hdr
;
56 ctdbd_prep_hdr_next_reqid(conn
, hdr
);
57 hdr
->operation
= CTDB_REQ_CONTROL
;
58 state
->req
.opcode
= CTDB_CONTROL_ECHO_DATA
;
60 state
->iov
[0] = (struct iovec
) {
61 .iov_base
= &state
->req
,
62 .iov_len
= offsetof(struct ctdb_req_control_old
, data
),
65 datalen
= generate_random() % 1024;
67 state
->echodata
.dptr
= talloc_array(state
, uint8_t, datalen
+8);
68 if (tevent_req_nomem(state
->echodata
.dptr
, req
)) {
69 return tevent_req_post(req
, ev
);
71 state
->echodata
.dsize
= talloc_get_size(state
->echodata
.dptr
);
72 generate_random_buffer(
73 state
->echodata
.dptr
, state
->echodata
.dsize
);
75 memcpy(state
->echodata
.dptr
, &delay
, sizeof(delay
));
76 memcpy(state
->echodata
.dptr
+4, &datalen
, sizeof(datalen
));
78 state
->req
.datalen
= state
->echodata
.dsize
;
80 state
->iov
[1] = (struct iovec
) {
81 .iov_base
= state
->echodata
.dptr
,
82 .iov_len
= state
->echodata
.dsize
,
86 offsetof(struct ctdb_req_control_old
, data
) +
89 subreq
= ctdbd_req_send(
90 state
, ev
, conn
, state
->iov
, ARRAY_SIZE(state
->iov
));
91 if (tevent_req_nomem(subreq
, req
)) {
92 return tevent_req_post(req
, ev
);
94 tevent_req_set_callback(subreq
, ctdb_echo_done
, req
);
99 static void ctdb_echo_done(struct tevent_req
*subreq
)
101 struct tevent_req
*req
= tevent_req_callback_data(
102 subreq
, struct tevent_req
);
103 struct ctdb_echo_state
*state
= tevent_req_data(
104 req
, struct ctdb_echo_state
);
105 struct ctdb_req_header
*hdr
= NULL
;
106 struct ctdb_reply_control_old
*reply
= NULL
;
109 ret
= ctdbd_req_recv(subreq
, state
, &hdr
);
111 if (tevent_req_error(req
, ret
)) {
112 printf("ctdbd_req_recv(%"PRIu32
") returned %d (%s)\n",
113 state
->req
.hdr
.reqid
,
118 if (hdr
->operation
!= CTDB_REPLY_CONTROL
) {
119 printf("Expected CTDB_REPLY_CONTROL, got %"PRIu32
"\n",
121 tevent_req_error(req
, EIO
);
124 reply
= (struct ctdb_reply_control_old
*)hdr
;
125 if (reply
->status
!= 0) {
126 printf("reply->status = %"PRIi32
"\n", reply
->status
);
127 tevent_req_error(req
, EIO
);
130 if (reply
->datalen
!= state
->req
.datalen
) {
131 printf("state->echodata.dsize=%zu datalen=%"PRIu32
"\n",
132 state
->echodata
.dsize
,
134 tevent_req_error(req
, EIO
);
137 cmp
= memcmp(reply
->data
,
138 state
->echodata
.dptr
,
139 state
->echodata
.dsize
);
141 printf("data mismatch\n");
142 tevent_req_error(req
, EIO
);
146 tevent_req_done(req
);
149 static int ctdb_echo_recv(struct tevent_req
*req
)
151 return tevent_req_simple_recv_unix(req
);
154 struct ctdb_ping_flood_state
{
155 struct tevent_context
*ev
;
156 struct ctdbd_connection
*conn
;
161 static void ctdb_ping_flood_next(struct tevent_req
*subreq
);
162 static void ctdb_ping_flood_done(struct tevent_req
*subreq
);
164 static struct tevent_req
*ctdb_ping_flood_send(
166 struct tevent_context
*ev
,
167 struct ctdbd_connection
*conn
,
171 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
172 struct ctdb_ping_flood_state
*state
= NULL
;
175 req
= tevent_req_create(
176 mem_ctx
, &state
, struct ctdb_ping_flood_state
);
183 for (i
=0; i
<num_parallel
; i
++) {
184 subreq
= ctdb_echo_send(
188 generate_random() % 10);
189 if (tevent_req_nomem(subreq
, req
)) {
190 return tevent_req_post(req
, ev
);
192 tevent_req_set_callback(subreq
, ctdb_ping_flood_next
, req
);
194 state
->num_running
= num_parallel
;
196 subreq
= tevent_wakeup_send(
199 tevent_timeval_current_ofs(0, usecs
));
200 if (tevent_req_nomem(subreq
, req
)) {
201 return tevent_req_post(req
, ev
);
203 tevent_req_set_callback(subreq
, ctdb_ping_flood_done
, req
);
208 static void ctdb_ping_flood_next(struct tevent_req
*subreq
)
210 struct tevent_req
*req
= tevent_req_callback_data(
211 subreq
, struct tevent_req
);
212 struct ctdb_ping_flood_state
*state
= tevent_req_data(
213 req
, struct ctdb_ping_flood_state
);
216 ret
= ctdb_echo_recv(subreq
);
218 if (tevent_req_error(req
, ret
)) {
221 state
->num_running
-= 1;
224 if (state
->num_running
== 0) {
225 tevent_req_done(req
);
230 subreq
= ctdb_echo_send(
234 generate_random() % 10);
235 if (tevent_req_nomem(subreq
, req
)) {
238 tevent_req_set_callback(subreq
, ctdb_ping_flood_next
, req
);
239 state
->num_running
+= 1;
242 static void ctdb_ping_flood_done(struct tevent_req
*subreq
)
244 struct tevent_req
*req
= tevent_req_callback_data(
245 subreq
, struct tevent_req
);
246 struct ctdb_ping_flood_state
*state
= tevent_req_data(
247 req
, struct ctdb_ping_flood_state
);
250 ok
= tevent_wakeup_recv(subreq
);
259 static int ctdb_ping_flood_recv(struct tevent_req
*req
)
261 return tevent_req_simple_recv_unix(req
);
264 bool run_ctdbd_conn1(int dummy
)
266 struct ctdbd_connection
*conn
= NULL
;
267 struct tevent_context
*ev
= NULL
;
268 struct tevent_req
*req
= NULL
;
273 ev
= samba_tevent_context_init(talloc_tos());
275 printf("samba_tevent_context_init failed\n");
279 ret
= ctdbd_init_async_connection(
280 ev
, lp_ctdbd_socket(), 0, &conn
);
282 printf("ctdbd_init_async_connection failed: %s\n",
287 req
= ctdb_ping_flood_send(
288 ev
, ev
, conn
, torture_nprocs
, torture_numops
* 1000);
290 printf("ctdb_ping_flood_send failed\n");
294 ok
= tevent_req_poll_unix(req
, ev
, &ret
);
296 printf("tevent_req_poll_unix failed: %s\n",
301 ret
= ctdb_ping_flood_recv(req
);
304 printf("ctdb_ping_flood failed: %s\n", strerror(ret
));