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
;
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
);
95 talloc_set_destructor(state
, ctdb_client_control_state_destructor
);
97 ctdb_req_header_fill(&h
, 0, CTDB_REQ_CONTROL
, destnode
,
100 ret
= ctdb_req_control_push(&h
, request
, state
, &buf
, &buflen
);
102 tevent_req_error(req
, ret
);
103 return tevent_req_post(req
, ev
);
106 if (!tevent_timeval_is_zero(&timeout
)) {
107 tevent_req_set_endtime(req
, ev
, timeout
);
110 subreq
= comm_write_send(state
, ev
, client
->comm
, buf
, buflen
);
111 if (tevent_req_nomem(subreq
, req
)) {
112 return tevent_req_post(req
, ev
);
114 tevent_req_set_callback(subreq
, ctdb_client_control_done
, req
);
119 static int ctdb_client_control_state_destructor(
120 struct ctdb_client_control_state
*state
)
122 reqid_remove(state
->client
->idr
, state
->reqid
);
126 static void ctdb_client_control_done(struct tevent_req
*subreq
)
128 struct tevent_req
*req
= tevent_req_callback_data(
129 subreq
, struct tevent_req
);
130 struct ctdb_client_control_state
*state
= tevent_req_data(
131 req
, struct ctdb_client_control_state
);
135 status
= comm_write_recv(subreq
, &ret
);
138 tevent_req_error(req
, ret
);
142 /* Daemon will not reply, so we set status to 0 */
143 if (state
->flags
& CTDB_CTRL_FLAG_NOREPLY
) {
144 state
->reply
->status
= 0;
145 tevent_req_done(req
);
148 /* wait for the reply or timeout */
151 void ctdb_client_reply_control(struct ctdb_client_context
*client
,
152 uint8_t *buf
, size_t buflen
, uint32_t reqid
)
154 struct ctdb_req_header h
;
155 struct ctdb_client_control_state
*state
;
158 state
= reqid_find(client
->idr
, reqid
,
159 struct ctdb_client_control_state
);
164 if (reqid
!= state
->reqid
) {
168 ret
= ctdb_reply_control_pull(buf
, buflen
, state
->opcode
, &h
,
169 state
->reply
, state
->reply
);
171 tevent_req_error(state
->req
, ret
);
175 tevent_req_done(state
->req
);
178 bool ctdb_client_control_recv(struct tevent_req
*req
, int *perr
,
180 struct ctdb_reply_control
**reply
)
182 struct ctdb_client_control_state
*state
= tevent_req_data(
183 req
, struct ctdb_client_control_state
);
186 if (tevent_req_is_unix_error(req
, &err
)) {
194 *reply
= talloc_steal(mem_ctx
, state
->reply
);
201 * Handle multiple nodes - there cannot be any return data
204 struct ctdb_client_control_multi_state
{
210 struct ctdb_reply_control
**reply
;
213 struct control_index_state
{
214 struct tevent_req
*req
;
218 static void ctdb_client_control_multi_done(struct tevent_req
*subreq
);
220 struct tevent_req
*ctdb_client_control_multi_send(
222 struct tevent_context
*ev
,
223 struct ctdb_client_context
*client
,
224 uint32_t *pnn_list
, int count
,
225 struct timeval timeout
,
226 struct ctdb_req_control
*request
)
228 struct tevent_req
*req
, *subreq
;
229 struct ctdb_client_control_multi_state
*state
;
232 if (pnn_list
== NULL
|| count
== 0) {
236 req
= tevent_req_create(mem_ctx
, &state
,
237 struct ctdb_client_control_multi_state
);
242 state
->pnn_list
= pnn_list
;
243 state
->count
= count
;
246 state
->err_list
= talloc_zero_array(state
, int, count
);
247 if (tevent_req_nomem(state
->err_list
, req
)) {
248 return tevent_req_post(req
, ev
);
250 state
->reply
= talloc_zero_array(state
, struct ctdb_reply_control
*,
252 if (tevent_req_nomem(state
->reply
, req
)) {
253 return tevent_req_post(req
, ev
);
256 for (i
=0; i
<count
; i
++) {
257 struct control_index_state
*substate
;
259 subreq
= ctdb_client_control_send(state
, ev
, client
,
260 pnn_list
[i
], timeout
,
262 if (tevent_req_nomem(subreq
, req
)) {
263 return tevent_req_post(req
, ev
);
266 substate
= talloc(subreq
, struct control_index_state
);
267 if (tevent_req_nomem(substate
, req
)) {
268 return tevent_req_post(req
, ev
);
274 tevent_req_set_callback(subreq
, ctdb_client_control_multi_done
,
281 static void ctdb_client_control_multi_done(struct tevent_req
*subreq
)
283 struct control_index_state
*substate
= tevent_req_callback_data(
284 subreq
, struct control_index_state
);
285 struct tevent_req
*req
= substate
->req
;
286 int idx
= substate
->index
;
287 struct ctdb_client_control_multi_state
*state
= tevent_req_data(
288 req
, struct ctdb_client_control_multi_state
);
292 status
= ctdb_client_control_recv(subreq
, &ret
, state
->reply
,
296 if (state
->err
== 0) {
298 state
->err_list
[idx
] = state
->err
;
301 if (state
->reply
[idx
]->status
!= 0) {
302 if (state
->err
== 0) {
303 state
->err
= state
->reply
[idx
]->status
;
304 state
->err_list
[idx
] = state
->err
;
311 if (state
->done
== state
->count
) {
312 tevent_req_done(req
);
316 bool ctdb_client_control_multi_recv(struct tevent_req
*req
, int *perr
,
317 TALLOC_CTX
*mem_ctx
, int **perr_list
,
318 struct ctdb_reply_control
***preply
)
320 struct ctdb_client_control_multi_state
*state
= tevent_req_data(
321 req
, struct ctdb_client_control_multi_state
);
324 if (tevent_req_is_unix_error(req
, &err
)) {
328 if (perr_list
!= NULL
) {
329 *perr_list
= talloc_steal(mem_ctx
, state
->err_list
);
338 if (perr_list
!= NULL
) {
339 *perr_list
= talloc_steal(mem_ctx
, state
->err_list
);
342 if (preply
!= NULL
) {
343 *preply
= talloc_steal(mem_ctx
, state
->reply
);
346 if (state
->err
!= 0) {
353 int ctdb_client_control_multi_error(uint32_t *pnn_list
, int count
,
354 int *err_list
, uint32_t *pnn
)
358 for (i
=0; i
<count
; i
++) {
359 if (err_list
[i
] != 0) {
369 * Sync version of control send/recv
372 int ctdb_client_control(TALLOC_CTX
*mem_ctx
,
373 struct tevent_context
*ev
,
374 struct ctdb_client_context
*client
,
376 struct timeval timeout
,
377 struct ctdb_req_control
*request
,
378 struct ctdb_reply_control
**reply
)
380 struct tevent_req
*req
;
384 req
= ctdb_client_control_send(mem_ctx
, ev
, client
, destnode
, timeout
,
390 tevent_req_poll(req
, ev
);
392 status
= ctdb_client_control_recv(req
, &ret
, mem_ctx
, reply
);
400 int ctdb_client_control_multi(TALLOC_CTX
*mem_ctx
,
401 struct tevent_context
*ev
,
402 struct ctdb_client_context
*client
,
403 uint32_t *pnn_list
, int count
,
404 struct timeval timeout
,
405 struct ctdb_req_control
*request
,
407 struct ctdb_reply_control
***preply
)
409 struct tevent_req
*req
;
413 req
= ctdb_client_control_multi_send(mem_ctx
, ev
, client
,
420 tevent_req_poll(req
, ev
);
422 status
= ctdb_client_control_multi_recv(req
, &ret
, mem_ctx
, perr_list
,