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 if (!tevent_req_set_endtime(req
, ev
, timeout
)) {
116 return tevent_req_post(req
, ev
);
120 subreq
= comm_write_send(state
, ev
, client
->comm
, buf
, buflen
);
121 if (tevent_req_nomem(subreq
, req
)) {
122 return tevent_req_post(req
, ev
);
124 tevent_req_set_callback(subreq
, ctdb_client_control_done
, req
);
129 static int ctdb_client_control_state_destructor(
130 struct ctdb_client_control_state
*state
)
132 reqid_remove(state
->client
->idr
, state
->reqid
);
136 static void ctdb_client_control_done(struct tevent_req
*subreq
)
138 struct tevent_req
*req
= tevent_req_callback_data(
139 subreq
, struct tevent_req
);
140 struct ctdb_client_control_state
*state
= tevent_req_data(
141 req
, struct ctdb_client_control_state
);
145 status
= comm_write_recv(subreq
, &ret
);
148 tevent_req_error(req
, ret
);
152 /* Daemon will not reply, so we set status to 0 */
153 if (state
->flags
& CTDB_CTRL_FLAG_NOREPLY
) {
154 state
->reply
->status
= 0;
155 tevent_req_done(req
);
158 /* wait for the reply or timeout */
161 void ctdb_client_reply_control(struct ctdb_client_context
*client
,
162 uint8_t *buf
, size_t buflen
, uint32_t reqid
)
164 struct ctdb_req_header h
;
165 struct ctdb_client_control_state
*state
;
168 state
= reqid_find(client
->idr
, reqid
,
169 struct ctdb_client_control_state
);
174 if (reqid
!= state
->reqid
) {
178 ret
= ctdb_reply_control_pull(buf
, buflen
, state
->opcode
, &h
,
179 state
->reply
, state
->reply
);
181 tevent_req_error(state
->req
, ret
);
185 tevent_req_done(state
->req
);
188 bool ctdb_client_control_recv(struct tevent_req
*req
, int *perr
,
190 struct ctdb_reply_control
**reply
)
192 struct ctdb_client_control_state
*state
= tevent_req_data(
193 req
, struct ctdb_client_control_state
);
196 if (tevent_req_is_unix_error(req
, &err
)) {
204 *reply
= talloc_steal(mem_ctx
, state
->reply
);
211 * Handle multiple nodes - there cannot be any return data
214 struct ctdb_client_control_multi_state
{
220 struct ctdb_reply_control
**reply
;
223 struct control_index_state
{
224 struct tevent_req
*req
;
228 static void ctdb_client_control_multi_done(struct tevent_req
*subreq
);
230 struct tevent_req
*ctdb_client_control_multi_send(
232 struct tevent_context
*ev
,
233 struct ctdb_client_context
*client
,
234 uint32_t *pnn_list
, int count
,
235 struct timeval timeout
,
236 struct ctdb_req_control
*request
)
238 struct tevent_req
*req
, *subreq
;
239 struct ctdb_client_control_multi_state
*state
;
242 if (pnn_list
== NULL
|| count
== 0) {
246 req
= tevent_req_create(mem_ctx
, &state
,
247 struct ctdb_client_control_multi_state
);
252 state
->pnn_list
= pnn_list
;
253 state
->count
= count
;
256 state
->err_list
= talloc_zero_array(state
, int, count
);
257 if (tevent_req_nomem(state
->err_list
, req
)) {
258 return tevent_req_post(req
, ev
);
260 state
->reply
= talloc_zero_array(state
, struct ctdb_reply_control
*,
262 if (tevent_req_nomem(state
->reply
, req
)) {
263 return tevent_req_post(req
, ev
);
266 for (i
=0; i
<count
; i
++) {
267 struct control_index_state
*substate
;
269 subreq
= ctdb_client_control_send(state
, ev
, client
,
270 pnn_list
[i
], timeout
,
272 if (tevent_req_nomem(subreq
, req
)) {
273 return tevent_req_post(req
, ev
);
276 substate
= talloc(subreq
, struct control_index_state
);
277 if (tevent_req_nomem(substate
, req
)) {
278 return tevent_req_post(req
, ev
);
284 tevent_req_set_callback(subreq
, ctdb_client_control_multi_done
,
291 static void ctdb_client_control_multi_done(struct tevent_req
*subreq
)
293 struct control_index_state
*substate
= tevent_req_callback_data(
294 subreq
, struct control_index_state
);
295 struct tevent_req
*req
= substate
->req
;
296 int idx
= substate
->index
;
297 struct ctdb_client_control_multi_state
*state
= tevent_req_data(
298 req
, struct ctdb_client_control_multi_state
);
302 status
= ctdb_client_control_recv(subreq
, &ret
, state
->reply
,
306 if (state
->err
== 0) {
308 state
->err_list
[idx
] = state
->err
;
311 if (state
->reply
[idx
]->status
!= 0) {
312 if (state
->err
== 0) {
313 state
->err
= state
->reply
[idx
]->status
;
314 state
->err_list
[idx
] = state
->err
;
321 if (state
->done
== state
->count
) {
322 tevent_req_done(req
);
326 bool ctdb_client_control_multi_recv(struct tevent_req
*req
, int *perr
,
327 TALLOC_CTX
*mem_ctx
, int **perr_list
,
328 struct ctdb_reply_control
***preply
)
330 struct ctdb_client_control_multi_state
*state
= tevent_req_data(
331 req
, struct ctdb_client_control_multi_state
);
334 if (tevent_req_is_unix_error(req
, &err
)) {
338 if (perr_list
!= NULL
) {
339 *perr_list
= talloc_steal(mem_ctx
, state
->err_list
);
348 if (perr_list
!= NULL
) {
349 *perr_list
= talloc_steal(mem_ctx
, state
->err_list
);
352 if (preply
!= NULL
) {
353 *preply
= talloc_steal(mem_ctx
, state
->reply
);
356 if (state
->err
!= 0) {
363 int ctdb_client_control_multi_error(uint32_t *pnn_list
, int count
,
364 int *err_list
, uint32_t *pnn
)
368 for (i
=0; i
<count
; i
++) {
369 if (err_list
[i
] != 0) {
379 * Sync version of control send/recv
382 int ctdb_client_control(TALLOC_CTX
*mem_ctx
,
383 struct tevent_context
*ev
,
384 struct ctdb_client_context
*client
,
386 struct timeval timeout
,
387 struct ctdb_req_control
*request
,
388 struct ctdb_reply_control
**reply
)
390 struct tevent_req
*req
;
394 req
= ctdb_client_control_send(mem_ctx
, ev
, client
, destnode
, timeout
,
400 tevent_req_poll(req
, ev
);
402 status
= ctdb_client_control_recv(req
, &ret
, mem_ctx
, reply
);
410 int ctdb_client_control_multi(TALLOC_CTX
*mem_ctx
,
411 struct tevent_context
*ev
,
412 struct ctdb_client_context
*client
,
413 uint32_t *pnn_list
, int count
,
414 struct timeval timeout
,
415 struct ctdb_req_control
*request
,
417 struct ctdb_reply_control
***preply
)
419 struct tevent_req
*req
;
423 req
= ctdb_client_control_multi_send(mem_ctx
, ev
, client
,
430 tevent_req_poll(req
, ev
);
432 status
= ctdb_client_control_multi_recv(req
, &ret
, mem_ctx
, perr_list
,