s4:smbtorture: Fix samba3.smb.dir on btrfs
[samba4-gss.git] / source3 / torture / test_ctdbd_conn.c
blob124a334b55d31a451a3c275579ff5565dc83e82d
1 /*
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/>.
20 #include "includes.h"
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;
32 struct iovec iov[2];
33 TDB_DATA echodata;
36 static void ctdb_echo_done(struct tevent_req *subreq);
38 static struct tevent_req *ctdb_echo_send(
39 TALLOC_CTX *mem_ctx,
40 struct tevent_context *ev,
41 struct ctdbd_connection *conn,
42 uint32_t delay)
44 struct tevent_req *req = NULL, *subreq = NULL;
45 struct ctdb_echo_state *state = NULL;
46 struct ctdb_req_header *hdr = NULL;
47 uint32_t datalen;
49 req = tevent_req_create(
50 mem_ctx, &state, struct ctdb_echo_state);
51 if (req == NULL) {
52 return NULL;
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,
85 hdr->length =
86 offsetof(struct ctdb_req_control_old, data) +
87 state->req.datalen;
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);
96 return 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;
107 int cmp, ret;
109 ret = ctdbd_req_recv(subreq, state, &hdr);
110 TALLOC_FREE(subreq);
111 if (tevent_req_error(req, ret)) {
112 printf("ctdbd_req_recv(%"PRIu32") returned %d (%s)\n",
113 state->req.hdr.reqid,
114 ret,
115 strerror(ret));
116 return;
118 if (hdr->operation != CTDB_REPLY_CONTROL) {
119 printf("Expected CTDB_REPLY_CONTROL, got %"PRIu32"\n",
120 hdr->operation);
121 tevent_req_error(req, EIO);
122 return;
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);
128 return;
130 if (reply->datalen != state->req.datalen) {
131 printf("state->echodata.dsize=%zu datalen=%"PRIu32"\n",
132 state->echodata.dsize,
133 reply->datalen);
134 tevent_req_error(req, EIO);
135 return;
137 cmp = memcmp(reply->data,
138 state->echodata.dptr,
139 state->echodata.dsize);
140 if (cmp != 0) {
141 printf("data mismatch\n");
142 tevent_req_error(req, EIO);
143 return;
145 TALLOC_FREE(reply);
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;
157 size_t num_running;
158 bool done;
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(
165 TALLOC_CTX *mem_ctx,
166 struct tevent_context *ev,
167 struct ctdbd_connection *conn,
168 size_t num_parallel,
169 unsigned usecs)
171 struct tevent_req *req = NULL, *subreq = NULL;
172 struct ctdb_ping_flood_state *state = NULL;
173 size_t i;
175 req = tevent_req_create(
176 mem_ctx, &state, struct ctdb_ping_flood_state);
177 if (req == NULL) {
178 return NULL;
180 state->ev = ev;
181 state->conn = conn;
183 for (i=0; i<num_parallel; i++) {
184 subreq = ctdb_echo_send(
185 state,
186 state->ev,
187 state->conn,
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(
197 state,
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);
205 return 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);
214 int ret;
216 ret = ctdb_echo_recv(subreq);
217 TALLOC_FREE(subreq);
218 if (tevent_req_error(req, ret)) {
219 return;
221 state->num_running -= 1;
223 if (state->done) {
224 if (state->num_running == 0) {
225 tevent_req_done(req);
227 return;
230 subreq = ctdb_echo_send(
231 state,
232 state->ev,
233 state->conn,
234 generate_random() % 10);
235 if (tevent_req_nomem(subreq, req)) {
236 return;
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);
248 bool ok;
250 ok = tevent_wakeup_recv(subreq);
251 TALLOC_FREE(subreq);
252 if (!ok) {
253 tevent_req_oom(req);
254 return;
256 state->done = true;
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;
269 int ret;
270 bool ok;
271 bool result = false;
273 ev = samba_tevent_context_init(talloc_tos());
274 if (ev == NULL) {
275 printf("samba_tevent_context_init failed\n");
276 goto done;
279 ret = ctdbd_init_async_connection(
280 ev, lp_ctdbd_socket(), 0, &conn);
281 if (ret != 0) {
282 printf("ctdbd_init_async_connection failed: %s\n",
283 strerror(ret));
284 goto done;
287 req = ctdb_ping_flood_send(
288 ev, ev, conn, torture_nprocs, torture_numops * 1000);
289 if (req == NULL) {
290 printf("ctdb_ping_flood_send failed\n");
291 goto done;
294 ok = tevent_req_poll_unix(req, ev, &ret);
295 if (!ok) {
296 printf("tevent_req_poll_unix failed: %s\n",
297 strerror(ret));
298 goto done;
301 ret = ctdb_ping_flood_recv(req);
302 TALLOC_FREE(req);
303 if (ret != 0) {
304 printf("ctdb_ping_flood failed: %s\n", strerror(ret));
305 goto done;
308 result = true;
309 done:
310 TALLOC_FREE(conn);
311 return result;