Logo Search packages:      
Sourcecode: heartbeat-2 version File versions  Download package

clientlib.c

/* 
 * Client Library for Local Resource Manager  API.
 *
 * Author:  Huang Zhen <zhenh@cn.ibm.com>
 * Copyright (c) 2004 International Business Machines
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
#include <portability.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>

#include <glib.h>
#include <heartbeat.h>
#include <clplumbing/ipc.h>
#include <ha_msg.h>
#include <lrm/lrm_api.h>

#include <lrm/lrm_msg.h>

/* FIXME: Notice: this define should be replaced when merge to the whole pkg*/
#define     LRM_MAXPIDLEN     256
#define LRM_ID          "lrm"

#define LOG_FAIL_create_lrm_msg(msg_type)                   \
      cl_log(LOG_ERR, "%s(%d): failed to create a %s message with "     \
            "function create_lrm_msg."                      \
      ,     __FUNCTION__, __LINE__, msg_type)

#define LOG_FAIL_create_lrm_rsc_msg(msg_type)                     \
      cl_log(LOG_ERR, "%s(%d): failed to create a %s message with "     \
            "function create_lrm_rsc_msg."                        \
      ,     __FUNCTION__, __LINE__, msg_type)

#define LOG_FAIL_receive_reply(msg_type)                          \
      cl_log(LOG_ERR, "%s(%d): failed to receive a reply message of %s."      \
      ,     __FUNCTION__, __LINE__, msg_type)

#define LOG_FAIL_SEND_MSG(msg_type, chan_name)                    \
      cl_log(LOG_ERR, "%s(%d): failed to send a %s message to lrmd "    \
            "via %s channel."                         \
      ,     __FUNCTION__, __LINE__, msg_type, chan_name)

#define LOG_GOT_FAIL_RET(priority, msg_type)                      \
      cl_log(priority, "%s(%d): got a return code HA_FAIL from "  \
            "a reply message of %s with function get_ret_from_msg."     \
      ,     __FUNCTION__, __LINE__, msg_type)

#define LOG_BASIC_ERROR(apiname)                \
      cl_log(LOG_ERR, "%s(%d): %s failed."            \
      , __FUNCTION__, __LINE__, apiname)

#define LOG_FAIL_GET_MSG_FIELD(priority, field_name, msg)         \
            {cl_log(priority, "%s(%d): failed to get the value "  \
                  "of field %s from a ha_msg"               \
            ,     __FUNCTION__, __LINE__, field_name);            \
            cl_log(LOG_INFO, "%s: Message follows:", __FUNCTION__);     \
            cl_log_message(LOG_INFO, (msg));                \
            }

/* declare the functions used by the lrm_ops structure*/
static int lrm_signon (ll_lrm_t* lrm, const char * app_name);
static int lrm_signoff (ll_lrm_t*);
static int lrm_delete (ll_lrm_t*);
static int lrm_set_lrm_callback (ll_lrm_t* lrm,
                         lrm_op_done_callback_t op_done_callback_func);
static GList* lrm_get_rsc_class_supported (ll_lrm_t* lrm);
static GList* lrm_get_rsc_type_supported (ll_lrm_t* lrm, const char* class);
static GList* lrm_get_rsc_provider_supported (ll_lrm_t* lrm
                        ,const char* class, const char* type);
static char* lrm_get_rsc_type_metadata(ll_lrm_t* lrm, const char* class
                        ,const char* type, const char* provider);
static GHashTable* lrm_get_all_type_metadata(ll_lrm_t*, const char* class);
static GList* lrm_get_all_rscs (ll_lrm_t* lrm);
static lrm_rsc_t* lrm_get_rsc (ll_lrm_t* lrm, const char* rsc_id);
static int lrm_add_rsc (ll_lrm_t*, const char* id, const char* class
                  ,const char* type, const char* provider
                  ,GHashTable* parameter);
static int lrm_delete_rsc (ll_lrm_t*, const char* id);
static IPC_Channel* lrm_ipcchan (ll_lrm_t*);
static int lrm_msgready (ll_lrm_t*);
static int lrm_rcvmsg (ll_lrm_t*, int blocking);
static struct lrm_ops lrm_ops_instance =
{
      lrm_signon,
      lrm_signoff,
      lrm_delete,
      lrm_set_lrm_callback,
      lrm_get_rsc_class_supported,
      lrm_get_rsc_type_supported,
      lrm_get_rsc_provider_supported,
      lrm_get_rsc_type_metadata,
      lrm_get_all_type_metadata,
      lrm_get_all_rscs,
      lrm_get_rsc,
      lrm_add_rsc,
      lrm_delete_rsc,
      lrm_ipcchan,
      lrm_msgready,
      lrm_rcvmsg
};
/* declare the functions used by the lrm_rsc_ops structure*/
static int rsc_perform_op (lrm_rsc_t*, lrm_op_t* op);
static int rsc_cancel_op (lrm_rsc_t*, int call_id);
static int rsc_flush_ops (lrm_rsc_t*);
static GList* rsc_get_cur_state (lrm_rsc_t*, state_flag_t* cur_state);
static lrm_op_t* rsc_get_last_result (lrm_rsc_t*, const char* op_type);
static gint compare_call_id(gconstpointer a, gconstpointer b);

static struct rsc_ops rsc_ops_instance =
{
      rsc_perform_op,
      rsc_cancel_op,
      rsc_flush_ops,
      rsc_get_cur_state,
      rsc_get_last_result
};


/* define the internal data used by the client library*/
static int is_signed_on                         = FALSE;
static IPC_Channel* ch_cmd                      = NULL;
static IPC_Channel* ch_cbk                      = NULL;
static lrm_op_done_callback_t op_done_callback  = NULL;

/* define some utility functions*/
static int get_ret_from_ch(IPC_Channel* ch);
static int get_ret_from_msg(struct ha_msg* msg);
static struct ha_msg* op_to_msg (lrm_op_t* op);
static lrm_op_t* msg_to_op(struct ha_msg* msg);
static void free_op (lrm_op_t* op);

/* define of the api functions*/
ll_lrm_t*
ll_lrm_new (const char * llctype)
{
      ll_lrm_t* lrm;

      /* check the parameter*/
      if (0 != STRNCMP_CONST(llctype, LRM_ID)) {
            cl_log(LOG_ERR, "ll_lrm_new: wrong parameter");
            return NULL;
      }

      /* alloc memory for lrm*/
      if (NULL == (lrm = (ll_lrm_t*) g_new(ll_lrm_t,1))) {
            cl_log(LOG_ERR, "ll_lrm_new: can not allocate memory");
            return NULL;
      }
      /* assign the ops*/
      lrm->lrm_ops = &lrm_ops_instance;

      return lrm;
}

static int
lrm_signon (ll_lrm_t* lrm, const char * app_name)
{

      GHashTable* ch_cmd_attrs;
      GHashTable* ch_cbk_attrs;

      struct ha_msg* msg;

      char path[] = IPC_PATH_ATTR;
      char cmd_path[] = LRM_CMDPATH;
      char callback_path[] = LRM_CALLBACKPATH;

      /* check parameters*/
      if (NULL == lrm || NULL == app_name) {
            cl_log(LOG_ERR, "lrm_signon: wrong parameter");
            return HA_FAIL;
      }

      /* if already signed on, sign off first*/
      if (is_signed_on) {
            cl_log(LOG_WARNING,
                  "lrm_signon: the client is alreay signed on, re-sign");
            lrm_signoff(lrm);
      }

      /* create the command ipc channel to lrmd*/
      ch_cmd_attrs = g_hash_table_new(g_str_hash, g_str_equal);
      g_hash_table_insert(ch_cmd_attrs, path, cmd_path);
      ch_cmd = ipc_channel_constructor(IPC_ANYTYPE, ch_cmd_attrs);
      g_hash_table_destroy(ch_cmd_attrs);

      if (NULL == ch_cmd){
            lrm_signoff(lrm);
            cl_log(LOG_WARNING,
                  "lrm_signon: can not connect to lrmd for cmd channel");
            return HA_FAIL;
      }

      if (IPC_OK != ch_cmd->ops->initiate_connection(ch_cmd)) {
            lrm_signoff(lrm);
            cl_log(LOG_WARNING,
                  "lrm_signon: can not initiate connection");
            return HA_FAIL;
      }

      /* construct the reg msg*/
      if (NULL == (msg = create_lrm_reg_msg(app_name))) {
            lrm_signoff(lrm);
            cl_log(LOG_ERR,"lrm_signon: failed to create a register message");
            return HA_FAIL;
      }

      /* send the msg*/
      if (HA_OK != msg2ipcchan(msg,ch_cmd)) {
            lrm_signoff(lrm);
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(REGISTER, "ch_cmd");
            return HA_FAIL;
      }
      /* parse the return msg*/
      if (HA_OK != get_ret_from_ch(ch_cmd)) {
            ha_msg_del(msg);
            lrm_signoff(lrm);
            LOG_FAIL_receive_reply(REGISTER);
            return HA_FAIL;
      }

      /* create the callback ipc channel to lrmd*/
      ch_cbk_attrs = g_hash_table_new(g_str_hash, g_str_equal);
      g_hash_table_insert(ch_cbk_attrs, path, callback_path);
      ch_cbk = ipc_channel_constructor(IPC_ANYTYPE,ch_cbk_attrs);
      g_hash_table_destroy(ch_cbk_attrs);

      if (NULL == ch_cbk) {
            ha_msg_del(msg);
            lrm_signoff(lrm);
            cl_log(LOG_ERR, "lrm_signon: failed to construct a callback "
                  "channel to lrmd");
            return HA_FAIL;
      }

      if (IPC_OK != ch_cbk->ops->initiate_connection(ch_cbk)) {
            ha_msg_del(msg);
            lrm_signoff(lrm);
            cl_log(LOG_ERR,
                  "lrm_signon: failed to initiate the callback channel.");
            return HA_FAIL;
      }
      /* send the msg*/
      if (HA_OK != msg2ipcchan(msg,ch_cbk)) {
            lrm_signoff(lrm);
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(REGISTER, "ch_cbk");
            return HA_FAIL;
      }
      ha_msg_del(msg);
      /* parse the return msg*/
      if (HA_OK != get_ret_from_ch(ch_cbk)) {
            lrm_signoff(lrm);
            LOG_FAIL_receive_reply(REGISTER);
            return HA_FAIL;
      }
      /* ok, we sign on sucessfully now*/
      is_signed_on = TRUE;
      return HA_OK;
}

static int
lrm_signoff (ll_lrm_t* lrm)
{
      /* close channels */
      if (NULL != ch_cmd) {
            if (IPC_ISWCONN(ch_cmd)) {
                  ch_cmd->ops->destroy(ch_cmd);
            }
            ch_cmd = NULL;
      }
      if (NULL != ch_cbk) {
            if (IPC_ISWCONN(ch_cbk)) {
                  ch_cbk->ops->destroy(ch_cbk);
            }
            ch_cbk = NULL;
      }
      is_signed_on = FALSE;

      return HA_OK;
}

static int
lrm_delete (ll_lrm_t* lrm)
{
      /* check the parameter */
      if (NULL == lrm) {
            cl_log(LOG_ERR,"lrm_delete: the parameter is a null pointer.");
            return HA_FAIL;
      }
      g_free(lrm);
      
      return HA_OK;
}

static int
lrm_set_lrm_callback (ll_lrm_t* lrm,
                  lrm_op_done_callback_t op_done_callback_func)

{
      op_done_callback = op_done_callback_func;

      return HA_OK;
}

static GList*
lrm_get_rsc_class_supported (ll_lrm_t* lrm)
{
      struct ha_msg* msg;
      struct ha_msg* ret;
      GList* class_list = NULL;
      /* check whether the channel to lrmd is available */
      if (NULL == ch_cmd)
      {
            cl_log(LOG_ERR,
                  "lrm_get_rsc_class_supported: ch_cmd is a null pointer.");
            return NULL;
      }
      /* create the get ra type message */
      msg = create_lrm_msg(GETRSCCLASSES);
      if ( NULL == msg) {
            LOG_FAIL_create_lrm_msg(GETRSCCLASSES);
            return NULL;
      }

      /* send the msg to lrmd */
      if (HA_OK != msg2ipcchan(msg,ch_cmd)) {
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(GETRSCCLASSES, "ch_cmd");
            return NULL;
      }
      ha_msg_del(msg);
      /* get the return message */
      ret = msgfromIPC(ch_cmd, MSG_ALLOWINTR);
      if (NULL == ret) {
            LOG_FAIL_receive_reply(GETRSCCLASSES);
            return NULL;
      }
      /* get the return code of the message */
      if (HA_OK != get_ret_from_msg(ret)) {
            LOG_GOT_FAIL_RET(LOG_WARNING, GETRSCCLASSES);
            ha_msg_del(ret);
            return NULL;
      }
      /* get the ra type list from message */
      class_list = ha_msg_value_str_list(ret,F_LRM_RCLASS);

      ha_msg_del(ret);

      return class_list;
}
static GList*
lrm_get_rsc_type_supported (ll_lrm_t* lrm, const char* rclass)
{
      struct ha_msg* msg;
      struct ha_msg* ret;
      GList* type_list = NULL;
      /* check whether the channel to lrmd is available */
      if (NULL == ch_cmd)
      {
            cl_log(LOG_ERR, "%s(%d): ch_cmd is null."
            ,     __FUNCTION__, __LINE__);
            
            return NULL;
      }
      /* create the get ra type message */
      msg = create_lrm_msg(GETRSCTYPES);
      if ( NULL == msg) {
            LOG_FAIL_create_lrm_msg(GETRSCTYPES);
            return NULL;
      }
      if ( HA_OK != ha_msg_add(msg, F_LRM_RCLASS, rclass)) {
            ha_msg_del(msg);
            LOG_BASIC_ERROR("ha_msg_add");
            return NULL;
      }

      /* send the msg to lrmd */
      if (HA_OK != msg2ipcchan(msg,ch_cmd)) {
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(GETRSCTYPES, "ch_cmd");
            return NULL;
      }
      ha_msg_del(msg);
      /* get the return message */
      ret = msgfromIPC(ch_cmd, MSG_ALLOWINTR);
      if (NULL == ret) {
            LOG_FAIL_receive_reply(GETRSCTYPES);
            return NULL;
      }
      /* get the return code of the message */
      if (HA_OK != get_ret_from_msg(ret)) {
            LOG_GOT_FAIL_RET(LOG_ERR, GETRSCTYPES);
            ha_msg_del(ret);
            return NULL;
      }
      /* get the ra type list from message */
      type_list = ha_msg_value_str_list(ret,F_LRM_RTYPES);

      ha_msg_del(ret);

      return type_list;
}
static GList*
lrm_get_rsc_provider_supported (ll_lrm_t* lrm, const char* class, const char* type)
{
      struct ha_msg* msg;
      struct ha_msg* ret;
      GList* provider_list = NULL;
      /* check whether the channel to lrmd is available */
      if (NULL == ch_cmd)
      {
            cl_log(LOG_ERR,
                  "lrm_get_rsc_provider_supported: ch_mod is null.");
            return NULL;
      }
      /* create the get ra providers message */
      msg = create_lrm_msg(GETPROVIDERS);
      if ( NULL == msg) {
            LOG_FAIL_create_lrm_msg(GETPROVIDERS);
            return NULL;
      }
      if (HA_OK != ha_msg_add(msg, F_LRM_RCLASS, class)
      ||  HA_OK != ha_msg_add(msg, F_LRM_RTYPE, type)) {
            ha_msg_del(msg);
            LOG_BASIC_ERROR("ha_msg_add");
            return NULL;
      }

      /* send the msg to lrmd */
      if (HA_OK != msg2ipcchan(msg,ch_cmd)) {
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(GETPROVIDERS, "ch_cmd");
            return NULL;
      }
      ha_msg_del(msg);
      /* get the return message */
      ret = msgfromIPC(ch_cmd, MSG_ALLOWINTR);
      if (NULL == ret) {
            LOG_FAIL_receive_reply(GETPROVIDERS);
            return NULL;
      }
      /* get the return code of the message */
      if (HA_OK != get_ret_from_msg(ret)) {
            LOG_GOT_FAIL_RET(LOG_ERR, GETPROVIDERS);
            ha_msg_del(ret);
            return NULL;
      }
      /* get the ra provider list from message */
      provider_list = ha_msg_value_str_list(ret,F_LRM_RPROVIDERS);

      ha_msg_del(ret);

      return provider_list;
}
      
/*
 * lrm_get_all_type_metadatas():
 * For OCF RAs, they may have more than one providers so they may have more than
 * one metadata. The hash table is not suitable for this. Fix Me
 */
static GHashTable*
lrm_get_all_type_metadata (ll_lrm_t* lrm, const char* rclass)
{
      GHashTable* metas = g_hash_table_new(g_str_hash, g_str_equal);
      GList* types = lrm_get_rsc_type_supported (lrm, rclass);
      GList* node = NULL;
        const char* meta;

      for (node = g_list_first(types); NULL!=node; node=g_list_next(node)) {
            meta = lrm_get_rsc_type_metadata(lrm,rclass,node->data,NULL);
            if (NULL == meta) {
                  continue;
            }
            g_hash_table_insert(metas, node->data,g_strdup(meta));
      }
      g_list_free(types);
      
      return metas;
}

static char*
lrm_get_rsc_type_metadata (ll_lrm_t* lrm, const char* rclass, const char* rtype,
                        const char* provider)
{
      struct ha_msg* msg;
      struct ha_msg* ret;
      const char* tmp = NULL;
      char* metadata = NULL;
      
      /* check whether the channel to lrmd is available */
      if (NULL == ch_cmd)
      {
            cl_log(LOG_ERR,
                  "lrm_get_rsc_type_metadata: ch_mod is null.");
            return NULL;
      }
      /* create the get ra type message */
      msg = create_lrm_msg(GETRSCMETA);
      if (NULL == msg ) {
            LOG_FAIL_create_lrm_msg(GETRSCMETA);
            return NULL;
      }
      
      if (HA_OK != ha_msg_add(msg, F_LRM_RCLASS, rclass)
      ||  HA_OK != ha_msg_add(msg, F_LRM_RTYPE, rtype)){
            ha_msg_del(msg);
            LOG_BASIC_ERROR("ha_msg_add");
            return NULL;
      }

      if( provider ) {
            if (HA_OK != ha_msg_add(msg, F_LRM_RPROVIDER, provider)) {
                  LOG_BASIC_ERROR("ha_msg_add");      
                  ha_msg_del(msg);
                  return NULL;
            }
      }

      /* send the msg to lrmd */
      if (HA_OK != msg2ipcchan(msg,ch_cmd)) {
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(GETRSCMETA, "ch_cmd");
            return NULL;
      }
      ha_msg_del(msg);
      /* get the return message */
      ret = msgfromIPC(ch_cmd, MSG_ALLOWINTR);
      if (NULL == ret) {
            LOG_FAIL_receive_reply(GETRSCMETA);
            return NULL;
      }
      /* get the return code of the message */
      if (HA_OK != get_ret_from_msg(ret)) {
            LOG_GOT_FAIL_RET(LOG_ERR, GETRSCMETA);
            ha_msg_del(ret);
            return NULL;
      }

      /* get the metadata from message */
      tmp = cl_get_string(ret, F_LRM_METADATA);
      if (NULL!=tmp) {
            metadata = g_strdup(tmp);
      }
      ha_msg_del(ret);

      return metadata;
}

static GList*
lrm_get_all_rscs (ll_lrm_t* lrm)
{
      struct ha_msg* msg = NULL;
      struct ha_msg* ret = NULL;
      GList* rid_list = NULL;

      /* check whether the channel to lrmd is available */
      if (NULL == ch_cmd) {
            cl_log(LOG_ERR, "lrm_get_all_rscs: ch_mod is null.");
            return NULL;
      }
      /* create the msg of get all resource */
      msg = create_lrm_msg(GETALLRCSES);
      if ( NULL == msg) {
            LOG_FAIL_create_lrm_msg(GETALLRCSES);
            return NULL;
      }
      /* send the msg to lrmd */
      if (HA_OK != msg2ipcchan(msg,ch_cmd)) {
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(GETALLRCSES, "ch_cmd");
            return NULL;
      }
      ha_msg_del(msg);
      /* get the return msg */
      ret = msgfromIPC(ch_cmd, MSG_ALLOWINTR);
      if (NULL == ret) {
            LOG_FAIL_receive_reply(GETALLRCSES);
            return NULL;
      }
      /* get the return code of msg */
      if (HA_OK != get_ret_from_msg(ret)) {
            LOG_GOT_FAIL_RET(LOG_ERR, GETALLRCSES);
            ha_msg_del(ret);
            return NULL;
      }
      /* get the rsc_id list from msg */
      rid_list = ha_msg_value_str_list(ret,F_LRM_RID);

      ha_msg_del(ret);
      /* return the id list */
      return rid_list;

}

static lrm_rsc_t*
lrm_get_rsc (ll_lrm_t* lrm, const char* rsc_id)
{
      struct ha_msg* msg = NULL;
      struct ha_msg* ret = NULL;
      lrm_rsc_t* rsc     = NULL;

      /* check whether the rsc_id is available */
      if (strlen(rsc_id) >= RID_LEN)      {
            cl_log(LOG_ERR, "lrm_get_rsc: rsc_id is too long.");
            return NULL;
      }

      /* check whether the channel to lrmd is available */
      if (NULL == ch_cmd)     {
            cl_log(LOG_ERR, "lrm_get_rsc: ch_mod is null.");
            return NULL;
      }
      /* create the msg of get resource */
      msg = create_lrm_rsc_msg(rsc_id, GETRSC);
      if ( NULL == msg) {
            LOG_FAIL_create_lrm_rsc_msg(GETRSC);
            return NULL;
      }
      /* send the msg to lrmd */
      if (HA_OK != msg2ipcchan(msg,ch_cmd)) {
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(GETRSC, "ch_cmd");
            return NULL;
      }
      ha_msg_del(msg);
      /* get the return msg from lrmd */
      ret = msgfromIPC(ch_cmd, MSG_ALLOWINTR);
      if (NULL == ret) {
            LOG_FAIL_receive_reply(GETRSC);
            return NULL;
      }
      /* get the return code of return message */
      if (HA_OK != get_ret_from_msg(ret)) {
            LOG_GOT_FAIL_RET(LOG_WARNING, GETRSC);
            ha_msg_del(ret);
            return NULL;
      }
      /* create a new resource structure */
      rsc = g_new(lrm_rsc_t, 1);

      /* fill the field of resource with the data from msg */
      rsc->id = g_strdup(ha_msg_value(ret, F_LRM_RID));
      rsc->type = g_strdup(ha_msg_value(ret, F_LRM_RTYPE));
      rsc->class = g_strdup(ha_msg_value(ret, F_LRM_RCLASS));
      rsc->provider = g_strdup(ha_msg_value(ret, F_LRM_RPROVIDER));
      rsc->params = ha_msg_value_str_table(ret,F_LRM_PARAM);

      rsc->ops = &rsc_ops_instance;
      ha_msg_del(ret);
      /* return the new resource */
      return rsc;
}

static int
lrm_add_rsc (ll_lrm_t* lrm, const char* rsc_id, const char* class
,          const char* type, const char* provider, GHashTable* parameter)
{
      struct ha_msg* msg;

      /* check whether the rsc_id is available */
      if (NULL == rsc_id || RID_LEN <= strlen(rsc_id))      {
            cl_log(LOG_ERR, "lrm_add_rsc: wrong parameter rsc_id.");
            return HA_FAIL;
      }

      /* check whether the channel to lrmd is available */
      if (NULL == ch_cmd)     {
            cl_log(LOG_ERR, "lrm_add_rsc: ch_mod is null.");
            return HA_FAIL;
      }

      /* create the message of add resource */
      msg = create_lrm_addrsc_msg(rsc_id, class, type, provider, parameter);
      if ( NULL == msg) {
            cl_log(LOG_ERR, "%s(%d): failed to create a ADDSRC message "
                  "with function create_lrm_addrsc_msg"
            ,     __FUNCTION__, __LINE__);
            return HA_FAIL;
      }
      /* send to lrmd */
      if (HA_OK != msg2ipcchan(msg,ch_cmd)) {
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(ADDRSC, "ch_cmd");
            return HA_FAIL;
      }
      ha_msg_del(msg);
      /* check the result */
      if (HA_OK != get_ret_from_ch(ch_cmd)) {
            LOG_GOT_FAIL_RET(LOG_ERR, ADDRSC);
            return HA_FAIL;
      }

      return HA_OK;
}

static int
lrm_delete_rsc (ll_lrm_t* lrm, const char* rsc_id)
{
      struct ha_msg* msg = NULL;

      /* check whether the rsc_id is available */
      if (NULL == rsc_id || RID_LEN <= strlen(rsc_id))      {
            cl_log(LOG_ERR, "lrm_delete_rsc: wrong parameter rsc_id.");
            return HA_FAIL;
      }

      /* check whether the channel to lrmd is available */
      if (NULL == ch_cmd)     {
            cl_log(LOG_ERR, "lrm_delete_rsc: ch_mod is null.");
            return HA_FAIL;
      }

      /* create the msg of del resource */
      msg = create_lrm_rsc_msg(rsc_id, DELRSC);
      if ( NULL == msg) {
            LOG_FAIL_create_lrm_rsc_msg(DELRSC);
            return HA_FAIL;
      }
      /* send the msg to lrmd */
      if (HA_OK != msg2ipcchan(msg,ch_cmd)) {
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(DELRSC, "ch_cmd");
            return HA_FAIL;
      }
      ha_msg_del(msg);
      /* check the response of the msg */
      if (HA_OK != get_ret_from_ch(ch_cmd)) {
            LOG_GOT_FAIL_RET(LOG_ERR, DELRSC);
            return HA_FAIL;
      }

      return HA_OK;
}

static IPC_Channel*
lrm_ipcchan (ll_lrm_t* lrm)
{
      if (NULL == ch_cbk) {
            cl_log(LOG_ERR,
                  "lrm_inputfd: callback channel is null.");
            return NULL;
      }

      return ch_cbk;
}

static gboolean
lrm_msgready (ll_lrm_t* lrm)
{
      if (NULL == ch_cbk) {
            cl_log(LOG_ERR,
                  "lrm_msgready: callback channel is null.");
            return FALSE;
      }
      return ch_cbk->ops->is_message_pending(ch_cbk);
}

static int
lrm_rcvmsg (ll_lrm_t* lrm, int blocking)
{
      struct ha_msg* msg = NULL;
      lrm_op_t* op = NULL;
      int msg_count = 0;

      /* if it is not blocking mode and no message in the channel, return */
      if ((!lrm_msgready(lrm)) && (!blocking)) {
            cl_log(LOG_DEBUG,
                  "lrm_rcvmsg: no message and non-block.");
            return msg_count;
      }
      /* wait until message ready */
      if (!lrm_msgready(lrm)) {
            ch_cbk->ops->waitin(ch_cbk);
      }
      while (lrm_msgready(lrm)) {
            if (ch_cbk->ch_status == IPC_DISCONNECT) {
                  return msg_count;
            }
            /* get the message */
            msg = msgfromIPC(ch_cbk, MSG_ALLOWINTR);
            if (msg == NULL) {
                  cl_log(LOG_WARNING,
                        "%s(%d): receive a null message with msgfromIPC."
                  ,     __FUNCTION__, __LINE__);
                  return msg_count;
            }
            msg_count++;

            op = msg_to_op(msg);
            if (NULL!=op && NULL!=op_done_callback) {
                  (*op_done_callback)(op);
            }
            ha_msg_del(msg);
      }

      return msg_count;
}

/* following are the functions for rsc_ops */
static int
rsc_perform_op (lrm_rsc_t* rsc, lrm_op_t* op)
{
      int rc = 0;
      struct ha_msg* msg = NULL;

      /* check whether the channel to lrmd is available */
      if (NULL == ch_cmd
      ||  NULL == rsc
      ||  NULL == rsc->id
      ||  NULL == op
      ||  NULL == op->op_type) {
            cl_log(LOG_ERR,
                  "rsc_perform_op: wrong parameters.");
            return HA_FAIL;
      }
      /* create the msg of perform op */
      op->rsc_id = rsc->id;
      msg = op_to_msg(op);
      if ( NULL == msg) {
            cl_log(LOG_ERR, "rsc_perform_op: failed to create a message "
                  "with function op_to_msg");
            return HA_FAIL;
      }
      /* send it to lrmd */
      if (HA_OK != msg2ipcchan(msg,ch_cmd)) {
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(PERFORMOP, "ch_cmd");
            return HA_FAIL;
      }
      ha_msg_del(msg);

      /* check return code, the return code is the call_id of the op */
      rc = get_ret_from_ch(ch_cmd);
      op->rsc_id = NULL;
      return rc;
}

static int
rsc_cancel_op (lrm_rsc_t* rsc, int call_id)
{
      int rc;
      struct ha_msg* msg = NULL;

      /* check whether the channel to lrmd is available */
      if (NULL == ch_cmd)     {
            cl_log(LOG_ERR, "rsc_cancel_op: ch_mod is null.");
            return HA_FAIL;
      }
      /* check parameter */
      if (NULL == rsc) {
            cl_log(LOG_ERR, "rsc_cancel_op: parameter rsc is null.");
            return HA_FAIL;
      }
      /* create the msg of flush ops */
      msg = create_lrm_rsc_msg(rsc->id,CANCELOP);
      if (NULL == msg) {
            LOG_FAIL_create_lrm_rsc_msg(CANCELOP);
            return HA_FAIL;
      }
      if (HA_OK != ha_msg_add_int(msg, F_LRM_CALLID, call_id))    {
            LOG_BASIC_ERROR("ha_msg_add_int");
            ha_msg_del(msg);
            return HA_FAIL;
      }
      
      /* send the msg to lrmd */
      if (HA_OK != msg2ipcchan(msg,ch_cmd)) {
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(CANCELOP, "ch_cmd");
            return HA_FAIL;
      }
      ha_msg_del(msg);

      rc = get_ret_from_ch(ch_cmd);

      return rc;
}

static int
rsc_flush_ops (lrm_rsc_t* rsc)
{
      int rc;
      struct ha_msg* msg = NULL;

      /* check whether the channel to lrmd is available */
      if (NULL == ch_cmd)     {
            cl_log(LOG_ERR, "rsc_flush_ops: ch_mod is null.");
            return HA_FAIL;
      }
      /* check parameter */
      if (NULL == rsc) {
            cl_log(LOG_ERR, "rsc_flush_ops: parameter rsc is null.");
            return HA_FAIL;
      }
      /* create the msg of flush ops */
      msg = create_lrm_rsc_msg(rsc->id,FLUSHOPS);
      if ( NULL == msg) {
            LOG_FAIL_create_lrm_rsc_msg(CANCELOP);
            return HA_FAIL;
      }
      /* send the msg to lrmd */
      if (HA_OK != msg2ipcchan(msg,ch_cmd)) {
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(FLUSHOPS, "ch_cmd");
            return HA_FAIL;
      }
      ha_msg_del(msg);

      rc = get_ret_from_ch(ch_cmd);

      return rc>0?HA_OK:HA_FAIL;
}
static gint 
compare_call_id(gconstpointer a, gconstpointer b)
{
      const lrm_op_t* opa = (const lrm_op_t*)a;
      const lrm_op_t* opb = (const lrm_op_t*)b;
      return opa->call_id - opb->call_id;
}
static GList*
rsc_get_cur_state (lrm_rsc_t* rsc, state_flag_t* cur_state)
{
      GList* op_list = NULL;
      struct ha_msg* msg = NULL;
      struct ha_msg* ret = NULL;
      struct ha_msg* op_msg = NULL;
      lrm_op_t* op = NULL;
      int state;
      int op_count, i;

      /* check whether the channel to lrmd is available */
      if (NULL == ch_cmd)     {
            cl_log(LOG_ERR, "rsc_get_cur_state: ch_mod is null.");
            return NULL;
      }
      /* check paramter */
      if (NULL == rsc) {
            cl_log(LOG_ERR, "rsc_get_cur_state: parameter rsc is null.");
            return NULL;
      }
      /* create the msg of get current state of resource */
      msg = create_lrm_rsc_msg(rsc->id,GETRSCSTATE);
      if ( NULL == msg) {
            LOG_FAIL_create_lrm_rsc_msg(GETRSCSTATE);
            return NULL;
      }
      /* send the msg to lrmd */
      if (HA_OK != msg2ipcchan(msg,ch_cmd)) {
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(GETRSCSTATE, "ch_cmd");
            return NULL;
      }
      ha_msg_del(msg);

      /* get the return msg */
      ret = msgfromIPC(ch_cmd, MSG_ALLOWINTR);
      if (NULL == ret) {
            LOG_FAIL_receive_reply(GETRSCSTATE);
            return NULL;
      }

      /* get the state of the resource from the message */
      if (HA_OK != ha_msg_value_int(ret, F_LRM_STATE, &state)) {
            LOG_FAIL_GET_MSG_FIELD(LOG_ERR, F_LRM_STATE, ret);
            ha_msg_del(ret);
            return NULL;
      }
      *cur_state = (state_flag_t)state;
      /* the first msg includes the count of pending ops. */
      if (HA_OK != ha_msg_value_int(ret, F_LRM_OPCNT, &op_count)) {
            LOG_FAIL_GET_MSG_FIELD(LOG_WARNING, F_LRM_OPCNT, ret);
            ha_msg_del(ret);
            return NULL;
      }
      ha_msg_del(ret);
      for (i = 0; i < op_count; i++) {
            /* one msg for one op */
            op_msg = msgfromIPC(ch_cmd, MSG_ALLOWINTR);

            if (NULL == op_msg) {
                  cl_log(LOG_WARNING, "%s(%d): failed to receive a "
                        "(pending operation) message from lrmd."
                  ,     __FUNCTION__, __LINE__);
                  continue;
            }
            op = msg_to_op(op_msg);
            /* add msg to the return list */
            
            if (NULL != op) {
                  op_list = g_list_append(op_list, op);
            }
            else {
                  cl_log(LOG_WARNING, "%s(%d): failed to make a operation "
                        "from a message with function msg_to_op"
                  ,     __FUNCTION__, __LINE__);
            }
            ha_msg_del(op_msg);
      }
      g_list_sort(op_list, compare_call_id);
      return op_list;
}

static lrm_op_t*
rsc_get_last_result (lrm_rsc_t* rsc, const char* op_type)
{
      struct ha_msg* msg = NULL;
      struct ha_msg* ret = NULL;
      lrm_op_t* op = NULL;
      int opcount = 0;
      /* check whether the channel to lrmd is available */
      if (NULL == ch_cmd)     {
            cl_log(LOG_ERR, "rsc_get_last_result: ch_mod is null.");
            return NULL;
      }
      /* check parameter */
      if (NULL == rsc) {
            cl_log(LOG_ERR, "rsc_get_last_result: parameter rsc is null.");
            return NULL;
      }
      /* create the msg of get last op */
      msg = create_lrm_rsc_msg(rsc->id,GETLASTOP);
      if (NULL == msg) {
            LOG_FAIL_create_lrm_rsc_msg(GETLASTOP);
            return NULL;
      }
      if (HA_OK != ha_msg_add(msg, F_LRM_RID, rsc->id))     {
            LOG_BASIC_ERROR("ha_msg_add");
            ha_msg_del(msg);
            return NULL;
      }
      if (HA_OK != ha_msg_add(msg, F_LRM_OP, op_type))      {
            LOG_BASIC_ERROR("ha_msg_add");
            ha_msg_del(msg);
            return NULL;
      }
      
      /* send the msg to lrmd */
      if (HA_OK != msg2ipcchan(msg,ch_cmd)) {
            ha_msg_del(msg);
            LOG_FAIL_SEND_MSG(GETLASTOP, "ch_cmd");
            return NULL;
      }
      
      /* get the return msg */
      ret = msgfromIPC(ch_cmd, MSG_ALLOWINTR);
      if (NULL == ret) {
            LOG_FAIL_receive_reply(GETLASTOP);
            ha_msg_del(msg);
            return NULL;
      }
      if (HA_OK != ha_msg_value_int(ret,F_LRM_OPCNT, &opcount)) {
            op = NULL;
      } 
      else if ( 1 == opcount ) {
            op = msg_to_op(ret);
      }
      ha_msg_del(msg);
      ha_msg_del(ret);
      return op;
}
/* 
 * following are the implements of the utility functions
 */
lrm_op_t*
lrm_op_new(void)
{
      lrm_op_t* op;

      op = g_new0(lrm_op_t, 1);
      op->op_status = LRM_OP_PENDING;
      return op;
}

static lrm_op_t*
msg_to_op(struct ha_msg* msg)
{
      lrm_op_t* op;
      const char* op_type;
      const char* app_name;
      const char* rsc_id;
      const char* output;
      const void* user_data;

      op = lrm_op_new();

      /* op->timeout, op->interval, op->target_rc, op->call_id*/
      if (HA_OK != ha_msg_value_int(msg,F_LRM_TIMEOUT, &op->timeout)
      ||  HA_OK != ha_msg_value_int(msg,F_LRM_INTERVAL, &op->interval)
      ||  HA_OK != ha_msg_value_int(msg,F_LRM_TARGETRC, &op->target_rc)
      ||  HA_OK != ha_msg_value_int(msg,F_LRM_DELAY, &op->start_delay)
      ||  HA_OK != ha_msg_value_int(msg,F_LRM_CALLID, &op->call_id)) {
            LOG_BASIC_ERROR("ha_msg_value_int");
            free_op(op);
            return NULL;
      }

      /* op->op_status */
      if (HA_OK !=
            ha_msg_value_int(msg, F_LRM_OPSTATUS, (int*)&op->op_status)) {
            LOG_FAIL_GET_MSG_FIELD(LOG_WARNING, F_LRM_OPSTATUS, msg);
                op->op_status = LRM_OP_PENDING;
      }

      /* if it finished successfully */
      if (LRM_OP_DONE == op->op_status ) {
            /* op->rc */
            if (HA_OK != ha_msg_value_int(msg, F_LRM_RC, &op->rc)) {
                  free_op(op);
                  LOG_FAIL_GET_MSG_FIELD(LOG_ERR, F_LRM_RC, msg);
                  return NULL;
            }
            /* op->output */
            output = cl_get_string(msg, F_LRM_DATA);
            if (NULL != output){
                  op->output = g_strdup(output);
            }
            else {
                  op->output = NULL;
            }
            /* check the rc to revise the op_status */
            if (0 != op->rc) {
                  op->op_status = LRM_OP_ERROR;
            }
      } else if(op->op_status == LRM_OP_PENDING) {
            op->rc = EXECRA_STATUS_UNKNOWN;
            
      } else {
            op->rc = EXECRA_EXEC_UNKNOWN_ERROR;
      }


      /* op->app_name */
      app_name = ha_msg_value(msg, F_LRM_APP);
      if (NULL == app_name) {
            LOG_FAIL_GET_MSG_FIELD(LOG_ERR, F_LRM_APP, msg);
            free_op(op);
            return NULL;
      }
      op->app_name = g_strdup(app_name);
      
      
      /* op->op_type */
      op_type = ha_msg_value(msg, F_LRM_OP);
      if (NULL == op_type) {
            LOG_FAIL_GET_MSG_FIELD(LOG_ERR, F_LRM_OP, msg);
            free_op(op);
            return NULL;
      }
      op->op_type = g_strdup(op_type);

      /* op->rsc_id */
      rsc_id = ha_msg_value(msg, F_LRM_RID);
      if (NULL == rsc_id) {
            LOG_FAIL_GET_MSG_FIELD(LOG_ERR, F_LRM_RID, msg);
            free_op(op);
            return NULL;
      }

      /* op->user_data */
      user_data = cl_get_string(msg, F_LRM_USERDATA);
      
      if (NULL != user_data) {
            op->user_data = g_strdup(user_data);
      }
      
      op->rsc_id = g_strdup(rsc_id);

      /* op->params */
      op->params = ha_msg_value_str_table(msg, F_LRM_PARAM);

      return op;
}

static struct ha_msg*
op_to_msg (lrm_op_t* op)
{
      struct ha_msg* msg = ha_msg_new(5);
      if (NULL == msg) {
            LOG_BASIC_ERROR("ha_msg_new");
            return NULL;
      }
      
      if (HA_OK != ha_msg_add(msg, F_LRM_TYPE, PERFORMOP)
      ||  HA_OK != ha_msg_add(msg, F_LRM_RID, op->rsc_id)
      ||  HA_OK != ha_msg_add(msg, F_LRM_OP, op->op_type)
      ||  HA_OK != ha_msg_add_int(msg, F_LRM_TIMEOUT, op->timeout)
      ||  HA_OK != ha_msg_add_int(msg, F_LRM_INTERVAL, op->interval)
      ||  HA_OK != ha_msg_add_int(msg, F_LRM_DELAY, op->start_delay)
      ||  HA_OK != ha_msg_add_int(msg, F_LRM_TARGETRC, op->target_rc)) {
            ha_msg_del(msg);
            LOG_BASIC_ERROR("ha_msg_add*");
            return NULL;
      }

      if (NULL != op->app_name) {
            if (HA_OK != ha_msg_add(msg, F_LRM_APP, op->app_name)){
                  ha_msg_del(msg);
                  LOG_BASIC_ERROR("ha_mag_add");
                  return NULL;
            }
      }

      if (NULL != op->user_data) {
            if (HA_OK != ha_msg_add(msg,F_LRM_USERDATA,op->user_data)){
                  ha_msg_del(msg);
                  LOG_BASIC_ERROR("ha_msg_add");
                  return NULL;
            }
      }

      if (NULL != op->params) {
            if (HA_OK != ha_msg_add_str_table(msg,F_LRM_PARAM,op->params)){
                  ha_msg_del(msg);
                  LOG_BASIC_ERROR("ha_msg_add_str_table");
                  return NULL;
            }     
      }

      return msg;
}

static int
get_ret_from_ch(IPC_Channel* ch)
{
      int ret;
      struct ha_msg* msg;

      msg = msgfromIPC(ch, MSG_ALLOWINTR);

      if (NULL == msg) {
            cl_log(LOG_ERR
            , "%s(%d): failed to receive message with function msgfromIPC"
            , __FUNCTION__, __LINE__);
            return HA_FAIL;
      }
      if (HA_OK != ha_msg_value_int(msg, F_LRM_RET, &ret)) {
            LOG_FAIL_GET_MSG_FIELD(LOG_ERR, F_LRM_RET, msg);
            ha_msg_del(msg);
            return HA_FAIL;
      }
      ha_msg_del(msg);
      return ret;
}

static int
get_ret_from_msg(struct ha_msg* msg)
{
      int ret;

      if (NULL == msg) {
            cl_log(LOG_ERR, "%s(%d): the parameter is a NULL pointer."
            ,     __FUNCTION__, __LINE__);
            return HA_FAIL;
      }
      if (HA_OK != ha_msg_value_int(msg, F_LRM_RET, &ret)) {
            LOG_FAIL_GET_MSG_FIELD(LOG_ERR, F_LRM_RET, msg);
            return HA_FAIL;
      }
      return ret;
}
static void
free_op (lrm_op_t* op)
{
      if (NULL == op) {
            return;
      }
      if (NULL != op->op_type) {
            g_free(op->op_type);
      }
      if (NULL != op->output) {
            g_free(op->output);
      }
      if (NULL != op->rsc_id) {
            g_free(op->rsc_id);
      }
      if (NULL != op->app_name) {
            g_free(op->app_name);
      }
      if (NULL != op->params) {
            free_str_table(op->params);
      }
}

void lrm_free_op(lrm_op_t* op) {
      free_op(op);
}
void lrm_free_rsc(lrm_rsc_t* rsc) {
      if (NULL == rsc) {
            return;
      }
      if (NULL != rsc->id) {
            g_free(rsc->id);
      }
      if (NULL != rsc->type) {
            g_free(rsc->type);
      }
      if (NULL != rsc->class) {
            g_free(rsc->class);
      }
      if (NULL != rsc->provider) {
            g_free(rsc->provider);
      }
      if (NULL != rsc->params) {
            free_str_table(rsc->params);
      }
      g_free(rsc);
}
void lrm_free_str_list(GList* list) {
      GList* item;
      if (NULL == list) {
            return;
      }
      item = g_list_first(list);
      while (NULL != item) {
            if (NULL != item->data) {
                  g_free(item->data);
            }
            list = g_list_delete_link(list, item);
            item = g_list_first(list);
      }
}     
void lrm_free_op_list(GList* list) {
      GList* item;
      if (NULL == list) {
            return;
      }
      item = g_list_first(list);
      while (NULL != item) {
            if (NULL != item->data) {
                  free_op((lrm_op_t*)item->data);
            }
            list = g_list_delete_link(list, item);
            item = g_list_first(list);
      }
}     
void lrm_free_str_table(GHashTable* table) {
      if (NULL != table) {
            free_str_table(table);
      }
}

const char *
execra_code2string(uniform_ret_execra_t code)
{
      switch(code) {
            case EXECRA_EXEC_UNKNOWN_ERROR:
                  return "unknown exec error";
            case EXECRA_NO_RA:
                  return "no RA";
            case EXECRA_OK:
                  return "ok";
            case EXECRA_UNKNOWN_ERROR:
                  return "unknown error";
            case EXECRA_INVALID_PARAM:
                  return "invalid parameter";
            case EXECRA_UNIMPLEMENT_FEATURE:
                  return "unimplemented feature";
            case EXECRA_INSUFFICIENT_PRIV:
                  return "insufficient privileges";
            case EXECRA_NOT_INSTALLED:
                  return "not installed";
            case EXECRA_NOT_CONFIGURED:
                  return "not configured";
            case EXECRA_NOT_RUNNING:
                  return "not running";
            /* For status command only */
            case EXECRA_RA_DEAMON_DEAD1:
                  return "status: deamon dead";
            case EXECRA_RA_DEAMON_DEAD2:
                  return "status: deamon dead";
            case EXECRA_RA_DEAMON_STOPPED:
                  return "status: deamon stopped";
            case EXECRA_STATUS_UNKNOWN:
                  return "status: unknown";
            default:
            break;
      }

      return "<unknown>";
}

Generated by  Doxygen 1.6.0   Back to index