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.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;