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 reqid_remove(state
->client
->idr
, state
->reqid
);
145 state
->reply
->status
= 0;
146 tevent_req_done(req
);
149 /* wait for the reply or timeout */
152 void ctdb_client_reply_control(struct ctdb_client_context
*client
,
153 uint8_t *buf
, size_t buflen
, uint32_t reqid
)
155 struct ctdb_req_header h
;
156 struct ctdb_client_control_state
*state
;
159 state
= reqid_find(client
->idr
, reqid
,
160 struct ctdb_client_control_state
);
165 if (reqid
!= state
->reqid
) {
169 ret
= ctdb_reply_control_pull(buf
, buflen
, state
->opcode
, &h
,
170 state
->reply
, state
->reply
);
172 tevent_req_error(state
->req
, ret
);
176 tevent_req_done(state
->req
);
179 bool ctdb_client_control_recv(struct tevent_req
*req
, int *perr
,
181 struct ctdb_reply_control
**reply
)
183 struct ctdb_client_control_state
*state
= tevent_req_data(
184 req
, struct ctdb_client_control_state
);
187 if (tevent_req_is_unix_error(req
, &err
)) {
195 *reply
= talloc_steal(mem_ctx
, state
->reply
);
202 * Handle multiple nodes - there cannot be any return data
205 struct ctdb_client_control_multi_state
{
211 struct ctdb_reply_control
**reply
;
214 struct control_index_state
{
215 struct tevent_req
*req
;
219 static void ctdb_client_control_multi_done(struct tevent_req
*subreq
);
221 struct tevent_req
*ctdb_client_control_multi_send(
223 struct tevent_context
*ev
,
224 struct ctdb_client_context
*client
,
225 uint32_t *pnn_list
, int count
,
226 struct timeval timeout
,
227 struct ctdb_req_control
*request
)
229 struct tevent_req
*req
, *subreq
;
230 struct ctdb_client_control_multi_state
*state
;
233 if (pnn_list
== NULL
|| count
== 0) {
237 req
= tevent_req_create(mem_ctx
, &state
,
238 struct ctdb_client_control_multi_state
);
243 state
->pnn_list
= pnn_list
;
244 state
->count
= count
;
247 state
->err_list
= talloc_zero_array(state
, int, count
);
248 if (tevent_req_nomem(state
->err_list
, req
)) {
249 return tevent_req_post(req
, ev
);
251 state
->reply
= talloc_zero_array(state
, struct ctdb_reply_control
*,
253 if (tevent_req_nomem(state
->reply
, req
)) {
254 return tevent_req_post(req
, ev
);
257 for (i
=0; i
<count
; i
++) {
258 struct control_index_state
*substate
;
260 subreq
= ctdb_client_control_send(state
, ev
, client
,
261 pnn_list
[i
], timeout
,
263 if (tevent_req_nomem(subreq
, req
)) {
264 return tevent_req_post(req
, ev
);
267 substate
= talloc(subreq
, struct control_index_state
);
268 if (tevent_req_nomem(substate
, req
)) {
269 return tevent_req_post(req
, ev
);
275 tevent_req_set_callback(subreq
, ctdb_client_control_multi_done
,
282 static void ctdb_client_control_multi_done(struct tevent_req
*subreq
)
284 struct control_index_state
*substate
= tevent_req_callback_data(
285 subreq
, struct control_index_state
);
286 struct tevent_req
*req
= substate
->req
;
287 int idx
= substate
->index
;
288 struct ctdb_client_control_multi_state
*state
= tevent_req_data(
289 req
, struct ctdb_client_control_multi_state
);
293 status
= ctdb_client_control_recv(subreq
, &ret
, state
->reply
,
297 if (state
->err
== 0) {
299 state
->err_list
[idx
] = state
->err
;
302 if (state
->reply
[idx
]->status
!= 0) {
303 if (state
->err
== 0) {
304 state
->err
= state
->reply
[idx
]->status
;
305 state
->err_list
[idx
] = state
->err
;
312 if (state
->done
== state
->count
) {
313 tevent_req_done(req
);
317 bool ctdb_client_control_multi_recv(struct tevent_req
*req
, int *perr
,
318 TALLOC_CTX
*mem_ctx
, int **perr_list
,
319 struct ctdb_reply_control
***preply
)
321 struct ctdb_client_control_multi_state
*state
= tevent_req_data(
322 req
, struct ctdb_client_control_multi_state
);
325 if (tevent_req_is_unix_error(req
, &err
)) {
329 if (perr_list
!= NULL
) {
330 *perr_list
= talloc_steal(mem_ctx
, state
->err_list
);
339 if (perr_list
!= NULL
) {
340 *perr_list
= talloc_steal(mem_ctx
, state
->err_list
);
343 if (preply
!= NULL
) {
344 *preply
= talloc_steal(mem_ctx
, state
->reply
);
347 if (state
->err
!= 0) {
354 int ctdb_client_control_multi_error(uint32_t *pnn_list
, int count
,
355 int *err_list
, uint32_t *pnn
)
359 for (i
=0; i
<count
; i
++) {
360 if (err_list
[i
] != 0) {
370 * Sync version of control send/recv
373 int ctdb_client_control(TALLOC_CTX
*mem_ctx
,
374 struct tevent_context
*ev
,
375 struct ctdb_client_context
*client
,
377 struct timeval timeout
,
378 struct ctdb_req_control
*request
,
379 struct ctdb_reply_control
**reply
)
381 struct tevent_req
*req
;
385 req
= ctdb_client_control_send(mem_ctx
, ev
, client
, destnode
, timeout
,
391 tevent_req_poll(req
, ev
);
393 status
= ctdb_client_control_recv(req
, &ret
, mem_ctx
, reply
);
401 int ctdb_client_control_multi(TALLOC_CTX
*mem_ctx
,
402 struct tevent_context
*ev
,
403 struct ctdb_client_context
*client
,
404 uint32_t *pnn_list
, int count
,
405 struct timeval timeout
,
406 struct ctdb_req_control
*request
,
408 struct ctdb_reply_control
***preply
)
410 struct tevent_req
*req
;
414 req
= ctdb_client_control_multi_send(mem_ctx
, ev
, client
,
421 tevent_req_poll(req
, ev
);
423 status
= ctdb_client_control_multi_recv(req
, &ret
, mem_ctx
, perr_list
,