4 Copyright (C) Amitay Isaacs 2016
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/filesys.h"
22 #include "system/network.h"
27 #include "lib/util/debug.h"
28 #include "lib/util/tevent_unix.h"
30 #include "common/logging.h"
31 #include "common/reqid.h"
32 #include "common/comm.h"
34 #include "protocol/protocol_api.h"
36 #include "client/client_event.h"
38 struct ctdb_event_context
{
39 struct reqid_context
*idr
;
40 struct comm_context
*comm
;
43 ctdb_client_callback_func_t callback
;
47 static int ctdb_event_connect(struct ctdb_event_context
*eclient
,
48 struct tevent_context
*ev
,
49 const char *sockpath
);
51 static int ctdb_event_context_destructor(struct ctdb_event_context
*eclient
);
53 int ctdb_event_init(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
54 const char *sockpath
, struct ctdb_event_context
**out
)
56 struct ctdb_event_context
*eclient
;
59 eclient
= talloc_zero(mem_ctx
, struct ctdb_event_context
);
60 if (eclient
== NULL
) {
61 DEBUG(DEBUG_ERR
, (__location__
" memory allocation error\n"));
65 ret
= reqid_init(eclient
, INT_MAX
-200, &eclient
->idr
);
67 DEBUG(DEBUG_ERR
, ("reqid_init() failed, ret=%d\n", ret
));
74 ret
= ctdb_event_connect(eclient
, ev
, sockpath
);
80 talloc_set_destructor(eclient
, ctdb_event_context_destructor
);
86 static int ctdb_event_context_destructor(struct ctdb_event_context
*eclient
)
88 if (eclient
->fd
!= -1) {
95 static void event_read_handler(uint8_t *buf
, size_t buflen
,
97 static void event_dead_handler(void *private_data
);
99 static int ctdb_event_connect(struct ctdb_event_context
*eclient
,
100 struct tevent_context
*ev
, const char *sockpath
)
102 struct sockaddr_un addr
;
106 if (sockpath
== NULL
) {
107 DEBUG(DEBUG_ERR
, ("socket path cannot be NULL\n"));
111 memset(&addr
, 0, sizeof(addr
));
112 addr
.sun_family
= AF_UNIX
;
113 len
= strlcpy(addr
.sun_path
, sockpath
, sizeof(addr
.sun_path
));
114 if (len
>= sizeof(addr
.sun_path
)) {
115 DEBUG(DEBUG_ERR
, ("socket path too long, len=%zu\n",
120 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
123 DEBUG(DEBUG_ERR
, ("socket() failed, errno=%d\n", ret
));
127 ret
= connect(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
130 DEBUG(DEBUG_ERR
, ("connect() failed, errno=%d\n", ret
));
136 ret
= comm_setup(eclient
, ev
, fd
, event_read_handler
, eclient
,
137 event_dead_handler
, eclient
, &eclient
->comm
);
139 DEBUG(DEBUG_ERR
, ("comm_setup() failed, ret=%d\n", ret
));
148 static void ctdb_event_msg_reply(struct ctdb_event_context
*eclient
,
149 uint8_t *buf
, size_t buflen
);
151 static void event_read_handler(uint8_t *buf
, size_t buflen
,
154 struct ctdb_event_context
*eclient
= talloc_get_type_abort(
155 private_data
, struct ctdb_event_context
);
157 ctdb_event_msg_reply(eclient
, buf
, buflen
);
160 static void event_dead_handler(void *private_data
)
162 struct ctdb_event_context
*eclient
= talloc_get_type_abort(
163 private_data
, struct ctdb_event_context
);
164 ctdb_client_callback_func_t callback
= eclient
->callback
;
165 void *callback_data
= eclient
->private_data
;
167 talloc_free(eclient
);
168 if (callback
!= NULL
) {
169 callback(callback_data
);
173 DEBUG(DEBUG_NOTICE
, ("connection to daemon closed, exiting\n"));
177 void ctdb_event_set_disconnect_callback(struct ctdb_event_context
*eclient
,
178 ctdb_client_callback_func_t callback
,
181 eclient
->callback
= callback
;
182 eclient
->private_data
= private_data
;
186 * Handle eventd_request and eventd_reply
189 struct ctdb_event_msg_state
{
190 struct ctdb_event_context
*eclient
;
193 struct tevent_req
*req
;
194 struct ctdb_event_reply
*reply
;
197 static int ctdb_event_msg_state_destructor(struct ctdb_event_msg_state
*state
);
198 static void ctdb_event_msg_done(struct tevent_req
*subreq
);
200 struct tevent_req
*ctdb_event_msg_send(TALLOC_CTX
*mem_ctx
,
201 struct tevent_context
*ev
,
202 struct ctdb_event_context
*eclient
,
203 struct ctdb_event_request
*request
)
205 struct tevent_req
*req
, *subreq
;
206 struct ctdb_event_msg_state
*state
;
211 req
= tevent_req_create(mem_ctx
, &state
, struct ctdb_event_msg_state
);
216 state
->eclient
= eclient
;
218 state
->reqid
= reqid_new(eclient
->idr
, state
);
219 if (state
->reqid
== REQID_INVALID
) {
225 talloc_set_destructor(state
, ctdb_event_msg_state_destructor
);
227 ctdb_event_header_fill(&request
->header
, state
->reqid
);
229 buflen
= ctdb_event_request_len(request
);
230 buf
= talloc_size(state
, buflen
);
231 if (tevent_req_nomem(buf
, req
)) {
232 return tevent_req_post(req
, ev
);
235 ret
= ctdb_event_request_push(request
, buf
, &buflen
);
237 tevent_req_error(req
, ret
);
238 return tevent_req_post(req
, ev
);
241 subreq
= comm_write_send(state
, ev
, eclient
->comm
, buf
, buflen
);
242 if (tevent_req_nomem(subreq
, req
)) {
243 return tevent_req_post(req
, ev
);
245 tevent_req_set_callback(subreq
, ctdb_event_msg_done
, req
);
250 static int ctdb_event_msg_state_destructor(struct ctdb_event_msg_state
*state
)
252 reqid_remove(state
->eclient
->idr
, state
->reqid
);
256 static void ctdb_event_msg_done(struct tevent_req
*subreq
)
258 struct tevent_req
*req
= tevent_req_callback_data(
259 subreq
, struct tevent_req
);
263 status
= comm_write_recv(subreq
, &ret
);
266 tevent_req_error(req
, ret
);
270 /* Wait for the reply or timeout */
273 static void ctdb_event_msg_reply(struct ctdb_event_context
*eclient
,
274 uint8_t *buf
, size_t buflen
)
276 struct ctdb_event_reply
*reply
;
277 struct ctdb_event_msg_state
*state
;
280 reply
= talloc_zero(eclient
, struct ctdb_event_reply
);
282 D_WARNING("memory allocation error\n");
286 ret
= ctdb_event_reply_pull(buf
, buflen
, reply
, reply
);
288 D_WARNING("Invalid packet received, ret=%d\n", ret
);
292 state
= reqid_find(eclient
->idr
, reply
->header
.reqid
,
293 struct ctdb_event_msg_state
);
298 if (reply
->header
.reqid
!= state
->reqid
) {
302 state
->reply
= talloc_steal(state
, reply
);
303 tevent_req_done(state
->req
);
306 bool ctdb_event_msg_recv(struct tevent_req
*req
, int *perr
,
308 struct ctdb_event_reply
**reply
)
310 struct ctdb_event_msg_state
*state
= tevent_req_data(
311 req
, struct ctdb_event_msg_state
);
314 if (tevent_req_is_unix_error(req
, &ret
)) {
322 *reply
= talloc_steal(mem_ctx
, state
->reply
);
332 struct tevent_req
*ctdb_event_run_send(TALLOC_CTX
*mem_ctx
,
333 struct tevent_context
*ev
,
334 struct ctdb_event_context
*eclient
,
335 enum ctdb_event event
,
336 uint32_t timeout
, const char *arg_str
)
338 struct ctdb_event_request request
;
339 struct ctdb_event_request_run rdata
;
342 rdata
.timeout
= timeout
;
343 rdata
.arg_str
= arg_str
;
345 request
.rdata
.command
= CTDB_EVENT_COMMAND_RUN
;
346 request
.rdata
.data
.run
= &rdata
;
348 return ctdb_event_msg_send(mem_ctx
, ev
, eclient
, &request
);
351 bool ctdb_event_run_recv(struct tevent_req
*req
, int *perr
, int *result
)
353 struct ctdb_event_reply
*reply
;
357 status
= ctdb_event_msg_recv(req
, &ret
, req
, &reply
);
365 if (reply
->rdata
.command
!= CTDB_EVENT_COMMAND_RUN
) {
373 if (result
!= NULL
) {
374 *result
= reply
->rdata
.result
;
385 struct tevent_req
*ctdb_event_status_send(TALLOC_CTX
*mem_ctx
,
386 struct tevent_context
*ev
,
387 struct ctdb_event_context
*eclient
,
388 enum ctdb_event event
,
389 enum ctdb_event_status_state state
)
391 struct ctdb_event_request request
;
392 struct ctdb_event_request_status rdata
;
397 request
.rdata
.command
= CTDB_EVENT_COMMAND_STATUS
;
398 request
.rdata
.data
.status
= &rdata
;
400 return ctdb_event_msg_send(mem_ctx
, ev
, eclient
, &request
);
403 bool ctdb_event_status_recv(struct tevent_req
*req
, int *perr
,
404 int32_t *result
, int *event_status
,
406 struct ctdb_script_list
**script_list
)
408 struct ctdb_event_reply
*reply
;
412 status
= ctdb_event_msg_recv(req
, &ret
, req
, &reply
);
420 if (reply
->rdata
.command
!= CTDB_EVENT_COMMAND_STATUS
) {
428 if (result
!= NULL
) {
429 *result
= reply
->rdata
.result
;
431 if (event_status
!= NULL
) {
432 *event_status
= reply
->rdata
.data
.status
->status
;
434 if (script_list
!= NULL
) {
435 *script_list
= talloc_steal(mem_ctx
,
436 reply
->rdata
.data
.status
->script_list
);
447 struct tevent_req
*ctdb_event_script_list_send(
449 struct tevent_context
*ev
,
450 struct ctdb_event_context
*eclient
)
452 struct ctdb_event_request request
;
454 request
.rdata
.command
= CTDB_EVENT_COMMAND_SCRIPT_LIST
;
456 return ctdb_event_msg_send(mem_ctx
, ev
, eclient
, &request
);
459 bool ctdb_event_script_list_recv(struct tevent_req
*req
, int *perr
,
460 int32_t *result
, TALLOC_CTX
*mem_ctx
,
461 struct ctdb_script_list
**script_list
)
463 struct ctdb_event_reply
*reply
;
467 status
= ctdb_event_msg_recv(req
, &ret
, req
, &reply
);
475 if (reply
->rdata
.command
!= CTDB_EVENT_COMMAND_SCRIPT_LIST
) {
483 if (result
!= NULL
) {
484 *result
= reply
->rdata
.result
;
486 if (script_list
!= NULL
) {
487 *script_list
= talloc_steal(mem_ctx
,
488 reply
->rdata
.data
.script_list
->script_list
);
499 struct tevent_req
*ctdb_event_script_enable_send(
501 struct tevent_context
*ev
,
502 struct ctdb_event_context
*eclient
,
503 const char *script_name
)
505 struct ctdb_event_request request
;
506 struct ctdb_event_request_script_enable rdata
;
508 rdata
.script_name
= script_name
;
510 request
.rdata
.command
= CTDB_EVENT_COMMAND_SCRIPT_ENABLE
;
511 request
.rdata
.data
.script_enable
= &rdata
;
513 return ctdb_event_msg_send(mem_ctx
, ev
, eclient
, &request
);
516 bool ctdb_event_script_enable_recv(struct tevent_req
*req
, int *perr
,
519 struct ctdb_event_reply
*reply
;
523 status
= ctdb_event_msg_recv(req
, &ret
, req
, &reply
);
531 if (reply
->rdata
.command
!= CTDB_EVENT_COMMAND_SCRIPT_ENABLE
) {
539 if (result
!= NULL
) {
540 *result
= reply
->rdata
.result
;
551 struct tevent_req
*ctdb_event_script_disable_send(
553 struct tevent_context
*ev
,
554 struct ctdb_event_context
*eclient
,
555 const char *script_name
)
557 struct ctdb_event_request request
;
558 struct ctdb_event_request_script_disable rdata
;
560 rdata
.script_name
= script_name
;
562 request
.rdata
.command
= CTDB_EVENT_COMMAND_SCRIPT_DISABLE
;
563 request
.rdata
.data
.script_disable
= &rdata
;
565 return ctdb_event_msg_send(mem_ctx
, ev
, eclient
, &request
);
568 bool ctdb_event_script_disable_recv(struct tevent_req
*req
, int *perr
,
571 struct ctdb_event_reply
*reply
;
575 status
= ctdb_event_msg_recv(req
, &ret
, req
, &reply
);
583 if (reply
->rdata
.command
!= CTDB_EVENT_COMMAND_SCRIPT_DISABLE
) {
591 if (result
!= NULL
) {
592 *result
= reply
->rdata
.result
;