/*
Eventd client api
Copyright (C) Amitay Isaacs 2016
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see .
*/
#include "replace.h"
#include "system/network.h"
#include
#include
#include "lib/util/debug.h"
#include "lib/util/tevent_unix.h"
#include "common/logging.h"
#include "common/sock_client.h"
#include "protocol/protocol_api.h"
#include "client/client_event.h"
struct ctdb_event_context {
struct sock_client_context *sockc;
};
static int ctdb_event_msg_request_push(void *request_data, uint32_t reqid,
TALLOC_CTX *mem_ctx,
uint8_t **buf, size_t *buflen,
void *private_data)
{
struct ctdb_event_request *request =
(struct ctdb_event_request *)request_data;
int ret;
sock_packet_header_set_reqid(&request->header, reqid);
*buflen = ctdb_event_request_len(request);
*buf = talloc_size(mem_ctx, *buflen);
if (*buf == NULL) {
return ENOMEM;
}
ret = ctdb_event_request_push(request, *buf, buflen);
if (ret != 0) {
return ret;
}
return 0;
}
static int ctdb_event_msg_reply_pull(uint8_t *buf, size_t buflen,
TALLOC_CTX *mem_ctx, void **reply_data,
void *private_data)
{
struct ctdb_event_reply *reply;
int ret;
reply = talloc_zero(mem_ctx, struct ctdb_event_reply);
if (reply == NULL) {
return ENOMEM;
}
ret = ctdb_event_reply_pull(buf, buflen, reply, reply);
if (ret != 0) {
talloc_free(reply);
return ret;
}
*reply_data = reply;
return 0;
}
static int ctdb_event_msg_reply_reqid(uint8_t *buf, size_t buflen,
uint32_t *reqid, void *private_data)
{
struct sock_packet_header header;
size_t np;
int ret;
ret = sock_packet_header_pull(buf, buflen, &header, &np);
if (ret != 0) {
return ret;
}
*reqid = header.reqid;
return 0;
}
struct sock_client_proto_funcs event_proto_funcs = {
.request_push = ctdb_event_msg_request_push,
.reply_pull = ctdb_event_msg_reply_pull,
.reply_reqid = ctdb_event_msg_reply_reqid,
};
int ctdb_event_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
const char *sockpath, struct ctdb_event_context **out)
{
struct ctdb_event_context *eclient;
int ret;
eclient = talloc_zero(mem_ctx, struct ctdb_event_context);
if (eclient == NULL) {
DEBUG(DEBUG_ERR, (__location__ " memory allocation error\n"));
return ENOMEM;
}
ret = sock_client_setup(eclient, ev, sockpath,
&event_proto_funcs, eclient,
&eclient->sockc);
if (ret != 0) {
talloc_free(eclient);
return ret;
}
*out = eclient;
return 0;
}
void ctdb_event_set_disconnect_callback(struct ctdb_event_context *eclient,
ctdb_client_callback_func_t callback,
void *private_data)
{
sock_client_set_disconnect_callback(eclient->sockc,
callback, private_data);
}
/*
* Handle eventd_request and eventd_reply
*/
struct tevent_req *ctdb_event_msg_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct ctdb_event_context *eclient,
struct ctdb_event_request *request)
{
struct tevent_req *req;
req = sock_client_msg_send(mem_ctx, ev, eclient->sockc,
tevent_timeval_zero(), request);
return req;
}
bool ctdb_event_msg_recv(struct tevent_req *req, int *perr,
TALLOC_CTX *mem_ctx,
struct ctdb_event_reply **reply)
{
void *reply_data;
bool status;
status = sock_client_msg_recv(req, perr, mem_ctx, &reply_data);
if (status && reply != NULL) {
*reply = talloc_get_type_abort(
reply_data, struct ctdb_event_reply);
}
return status;
}
/*
* Run an event
*/
struct tevent_req *ctdb_event_run_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct ctdb_event_context *eclient,
enum ctdb_event event,
uint32_t timeout, const char *arg_str)
{
struct ctdb_event_request request;
struct ctdb_event_request_run rdata;
rdata.event = event;
rdata.timeout = timeout;
rdata.arg_str = arg_str;
request.rdata.command = CTDB_EVENT_COMMAND_RUN;
request.rdata.data.run = &rdata;
return ctdb_event_msg_send(mem_ctx, ev, eclient, &request);
}
bool ctdb_event_run_recv(struct tevent_req *req, int *perr, int *result)
{
struct ctdb_event_reply *reply;
int ret;
bool status;
status = ctdb_event_msg_recv(req, &ret, req, &reply);
if (! status) {
if (perr != NULL) {
*perr = ret;
}
return false;
}
if (reply->rdata.command != CTDB_EVENT_COMMAND_RUN) {
if (perr != NULL) {
*perr = EPROTO;
}
talloc_free(reply);
return false;
}
if (result != NULL) {
*result = reply->rdata.result;
}
talloc_free(reply);
return true;
}
/*
* Get event status
*/
struct tevent_req *ctdb_event_status_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct ctdb_event_context *eclient,
enum ctdb_event event,
enum ctdb_event_status_state state)
{
struct ctdb_event_request request;
struct ctdb_event_request_status rdata;
rdata.event = event;
rdata.state = state;
request.rdata.command = CTDB_EVENT_COMMAND_STATUS;
request.rdata.data.status = &rdata;
return ctdb_event_msg_send(mem_ctx, ev, eclient, &request);
}
bool ctdb_event_status_recv(struct tevent_req *req, int *perr,
int32_t *result, int *event_status,
TALLOC_CTX *mem_ctx,
struct ctdb_script_list **script_list)
{
struct ctdb_event_reply *reply;
int ret;
bool status;
status = ctdb_event_msg_recv(req, &ret, req, &reply);
if (! status) {
if (perr != NULL) {
*perr = ret;
}
return false;
}
if (reply->rdata.command != CTDB_EVENT_COMMAND_STATUS) {
if (perr != NULL) {
*perr = EPROTO;
}
talloc_free(reply);
return false;
}
if (result != NULL) {
*result = reply->rdata.result;
}
if (event_status != NULL) {
*event_status = reply->rdata.data.status->status;
}
if (script_list != NULL) {
*script_list = talloc_steal(mem_ctx,
reply->rdata.data.status->script_list);
}
talloc_free(reply);
return true;
}
/*
* Get script list
*/
struct tevent_req *ctdb_event_script_list_send(
TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct ctdb_event_context *eclient)
{
struct ctdb_event_request request;
request.rdata.command = CTDB_EVENT_COMMAND_SCRIPT_LIST;
return ctdb_event_msg_send(mem_ctx, ev, eclient, &request);
}
bool ctdb_event_script_list_recv(struct tevent_req *req, int *perr,
int32_t *result, TALLOC_CTX *mem_ctx,
struct ctdb_script_list **script_list)
{
struct ctdb_event_reply *reply;
int ret;
bool status;
status = ctdb_event_msg_recv(req, &ret, req, &reply);
if (! status) {
if (perr != NULL) {
*perr = ret;
}
return false;
}
if (reply->rdata.command != CTDB_EVENT_COMMAND_SCRIPT_LIST) {
if (perr != NULL) {
*perr = EPROTO;
}
talloc_free(reply);
return false;
}
if (result != NULL) {
*result = reply->rdata.result;
}
if (script_list != NULL) {
*script_list = talloc_steal(mem_ctx,
reply->rdata.data.script_list->script_list);
}
talloc_free(reply);
return true;
}
/*
* Enable a script
*/
struct tevent_req *ctdb_event_script_enable_send(
TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct ctdb_event_context *eclient,
const char *script_name)
{
struct ctdb_event_request request;
struct ctdb_event_request_script_enable rdata;
rdata.script_name = script_name;
request.rdata.command = CTDB_EVENT_COMMAND_SCRIPT_ENABLE;
request.rdata.data.script_enable = &rdata;
return ctdb_event_msg_send(mem_ctx, ev, eclient, &request);
}
bool ctdb_event_script_enable_recv(struct tevent_req *req, int *perr,
int *result)
{
struct ctdb_event_reply *reply;
int ret;
bool status;
status = ctdb_event_msg_recv(req, &ret, req, &reply);
if (! status) {
if (perr != NULL) {
*perr = ret;
}
return false;
}
if (reply->rdata.command != CTDB_EVENT_COMMAND_SCRIPT_ENABLE) {
if (perr != NULL) {
*perr = EPROTO;
}
talloc_free(reply);
return false;
}
if (result != NULL) {
*result = reply->rdata.result;
}
talloc_free(reply);
return true;
}
/*
* Disable a script
*/
struct tevent_req *ctdb_event_script_disable_send(
TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct ctdb_event_context *eclient,
const char *script_name)
{
struct ctdb_event_request request;
struct ctdb_event_request_script_disable rdata;
rdata.script_name = script_name;
request.rdata.command = CTDB_EVENT_COMMAND_SCRIPT_DISABLE;
request.rdata.data.script_disable = &rdata;
return ctdb_event_msg_send(mem_ctx, ev, eclient, &request);
}
bool ctdb_event_script_disable_recv(struct tevent_req *req, int *perr,
int *result)
{
struct ctdb_event_reply *reply;
int ret;
bool status;
status = ctdb_event_msg_recv(req, &ret, req, &reply);
if (! status) {
if (perr != NULL) {
*perr = ret;
}
return false;
}
if (reply->rdata.command != CTDB_EVENT_COMMAND_SCRIPT_DISABLE) {
if (perr != NULL) {
*perr = EPROTO;
}
talloc_free(reply);
return false;
}
if (result != NULL) {
*result = reply->rdata.result;
}
talloc_free(reply);
return true;
}