4 Copyright (C) Amitay Isaacs 2015
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 "system/network.h"
22 #include "system/filesys.h"
28 #include "lib/util/tevent_unix.h"
30 #include "common/reqid.h"
31 #include "common/srvid.h"
32 #include "common/comm.h"
34 #include "protocol/protocol.h"
35 #include "protocol/protocol_api.h"
37 #include "client/client_private.h"
38 #include "client/client.h"
42 * Handle REQ_CONTROL and REPLY_CONTROL
45 struct ctdb_client_control_state
{
46 struct ctdb_client_context
*client
;
50 struct ctdb_reply_control
*reply
;
51 struct tevent_req
*req
;
54 static int ctdb_client_control_state_destructor(
55 struct ctdb_client_control_state
*state
);
56 static void ctdb_client_control_done(struct tevent_req
*subreq
);
58 struct tevent_req
*ctdb_client_control_send(TALLOC_CTX
*mem_ctx
,
59 struct tevent_context
*ev
,
60 struct ctdb_client_context
*client
,
62 struct timeval timeout
,
63 struct ctdb_req_control
*request
)
65 struct ctdb_req_header h
;
66 struct tevent_req
*req
, *subreq
;
67 struct ctdb_client_control_state
*state
;
70 size_t datalen
, buflen
;
73 req
= tevent_req_create(mem_ctx
, &state
,
74 struct ctdb_client_control_state
);
79 reqid
= reqid_new(client
->idr
, state
);
80 if (reqid
== REQID_INVALID
) {
85 state
->client
= client
;
86 state
->flags
= request
->flags
;
87 state
->opcode
= request
->opcode
;
90 state
->reply
= talloc_zero(state
, struct ctdb_reply_control
);
91 if (tevent_req_nomem(state
->reply
, req
)) {
92 return tevent_req_post(req
, ev
);
94 state
->reply
->rdata
.opcode
= request
->rdata
.opcode
;
96 talloc_set_destructor(state
, ctdb_client_control_state_destructor
);
98 ctdb_req_header_fill(&h
, 0, CTDB_REQ_CONTROL
, destnode
,
101 datalen
= ctdb_req_control_len(&h
, request
);
102 ret
= ctdb_allocate_pkt(state
, datalen
, &buf
, &buflen
);
104 tevent_req_error(req
, ret
);
105 return tevent_req_post(req
, ev
);
108 ret
= ctdb_req_control_push(&h
, request
, buf
, &buflen
);
110 tevent_req_error(req
, ret
);
111 return tevent_req_post(req
, ev
);
114 if (!tevent_timeval_is_zero(&timeout
)) {
115 tevent_req_set_endtime(req
, ev
, timeout
);
118 subreq
= comm_write_send(state
, ev
, client
->comm
, buf
, buflen
);
119 if (tevent_req_nomem(subreq
, req
)) {
120 return tevent_req_post(req
, ev
);
122 tevent_req_set_callback(subreq
, ctdb_client_control_done
, req
);
127 static int ctdb_client_control_state_destructor(
128 struct ctdb_client_control_state
*state
)
130 reqid_remove(state
->client
->idr
, state
->reqid
);
134 static void ctdb_client_control_done(struct tevent_req
*subreq
)
136 struct tevent_req
*req
= tevent_req_callback_data(
137 subreq
, struct tevent_req
);
138 struct ctdb_client_control_state
*state
= tevent_req_data(
139 req
, struct ctdb_client_control_state
);
143 status
= comm_write_recv(subreq
, &ret
);
146 tevent_req_error(req
, ret
);
150 /* Daemon will not reply, so we set status to 0 */
151 if (state
->flags
& CTDB_CTRL_FLAG_NOREPLY
) {
152 state
->reply
->status
= 0;
153 tevent_req_done(req
);
156 /* wait for the reply or timeout */
159 void ctdb_client_reply_control(struct ctdb_client_context
*client
,
160 uint8_t *buf
, size_t buflen
, uint32_t reqid
)
162 struct ctdb_req_header h
;
163 struct ctdb_client_control_state
*state
;
166 state
= reqid_find(client
->idr
, reqid
,
167 struct ctdb_client_control_state
);
172 if (reqid
!= state
->reqid
) {
176 ret
= ctdb_reply_control_pull(buf
, buflen
, state
->opcode
, &h
,
177 state
->reply
, state
->reply
);
179 tevent_req_error(state
->req
, ret
);
183 tevent_req_done(state
->req
);
186 bool ctdb_client_control_recv(struct tevent_req
*req
, int *perr
,
188 struct ctdb_reply_control
**reply
)
190 struct ctdb_client_control_state
*state
= tevent_req_data(
191 req
, struct ctdb_client_control_state
);
194 if (tevent_req_is_unix_error(req
, &err
)) {
202 *reply
= talloc_steal(mem_ctx
, state
->reply
);
209 * Handle multiple nodes - there cannot be any return data
212 struct ctdb_client_control_multi_state
{
218 struct ctdb_reply_control
**reply
;
221 struct control_index_state
{
222 struct tevent_req
*req
;
226 static void ctdb_client_control_multi_done(struct tevent_req
*subreq
);
228 struct tevent_req
*ctdb_client_control_multi_send(
230 struct tevent_context
*ev
,
231 struct ctdb_client_context
*client
,
232 uint32_t *pnn_list
, int count
,
233 struct timeval timeout
,
234 struct ctdb_req_control
*request
)
236 struct tevent_req
*req
, *subreq
;
237 struct ctdb_client_control_multi_state
*state
;
240 if (pnn_list
== NULL
|| count
== 0) {
244 req
= tevent_req_create(mem_ctx
, &state
,
245 struct ctdb_client_control_multi_state
);
250 state
->pnn_list
= pnn_list
;
251 state
->count
= count
;
254 state
->err_list
= talloc_zero_array(state
, int, count
);
255 if (tevent_req_nomem(state
->err_list
, req
)) {
256 return tevent_req_post(req
, ev
);
258 state
->reply
= talloc_zero_array(state
, struct ctdb_reply_control
*,
260 if (tevent_req_nomem(state
->reply
, req
)) {
261 return tevent_req_post(req
, ev
);
264 for (i
=0; i
<count
; i
++) {
265 struct control_index_state
*substate
;
267 subreq
= ctdb_client_control_send(state
, ev
, client
,
268 pnn_list
[i
], timeout
,
270 if (tevent_req_nomem(subreq
, req
)) {
271 return tevent_req_post(req
, ev
);
274 substate
= talloc(subreq
, struct control_index_state
);
275 if (tevent_req_nomem(substate
, req
)) {
276 return tevent_req_post(req
, ev
);
282 tevent_req_set_callback(subreq
, ctdb_client_control_multi_done
,
289 static void ctdb_client_control_multi_done(struct tevent_req
*subreq
)
291 struct control_index_state
*substate
= tevent_req_callback_data(
292 subreq
, struct control_index_state
);
293 struct tevent_req
*req
= substate
->req
;
294 int idx
= substate
->index
;
295 struct ctdb_client_control_multi_state
*state
= tevent_req_data(
296 req
, struct ctdb_client_control_multi_state
);
300 status
= ctdb_client_control_recv(subreq
, &ret
, state
->reply
,
304 if (state
->err
== 0) {
306 state
->err_list
[idx
] = state
->err
;
309 if (state
->reply
[idx
]->status
!= 0) {
310 if (state
->err
== 0) {
311 state
->err
= state
->reply
[idx
]->status
;
312 state
->err_list
[idx
] = state
->err
;
319 if (state
->done
== state
->count
) {
320 tevent_req_done(req
);
324 bool ctdb_client_control_multi_recv(struct tevent_req
*req
, int *perr
,
325 TALLOC_CTX
*mem_ctx
, int **perr_list
,
326 struct ctdb_reply_control
***preply
)
328 struct ctdb_client_control_multi_state
*state
= tevent_req_data(
329 req
, struct ctdb_client_control_multi_state
);
332 if (tevent_req_is_unix_error(req
, &err
)) {
336 if (perr_list
!= NULL
) {
337 *perr_list
= talloc_steal(mem_ctx
, state
->err_list
);
346 if (perr_list
!= NULL
) {
347 *perr_list
= talloc_steal(mem_ctx
, state
->err_list
);
350 if (preply
!= NULL
) {
351 *preply
= talloc_steal(mem_ctx
, state
->reply
);
354 if (state
->err
!= 0) {
361 int ctdb_client_control_multi_error(uint32_t *pnn_list
, int count
,
362 int *err_list
, uint32_t *pnn
)
366 for (i
=0; i
<count
; i
++) {
367 if (err_list
[i
] != 0) {
377 * Sync version of control send/recv
380 int ctdb_client_control(TALLOC_CTX
*mem_ctx
,
381 struct tevent_context
*ev
,
382 struct ctdb_client_context
*client
,
384 struct timeval timeout
,
385 struct ctdb_req_control
*request
,
386 struct ctdb_reply_control
**reply
)
388 struct tevent_req
*req
;
392 req
= ctdb_client_control_send(mem_ctx
, ev
, client
, destnode
, timeout
,
398 tevent_req_poll(req
, ev
);
400 status
= ctdb_client_control_recv(req
, &ret
, mem_ctx
, reply
);
408 int ctdb_client_control_multi(TALLOC_CTX
*mem_ctx
,
409 struct tevent_context
*ev
,
410 struct ctdb_client_context
*client
,
411 uint32_t *pnn_list
, int count
,
412 struct timeval timeout
,
413 struct ctdb_req_control
*request
,
415 struct ctdb_reply_control
***preply
)
417 struct tevent_req
*req
;
421 req
= ctdb_client_control_multi_send(mem_ctx
, ev
, client
,
428 tevent_req_poll(req
, ev
);
430 status
= ctdb_client_control_multi_recv(req
, &ret
, mem_ctx
, perr_list
,