Cmap service is application developer interface to icmap and it is direct replacement for confdb. Signed-off-by: Jan Friesse <jfriesse@xxxxxxxxxx> --- include/corosync/cmap.h | 334 ++++++++++++++++++++++ include/corosync/corodefs.h | 3 +- include/corosync/ipc_cmap.h | 183 ++++++++++++ services/Makefile.am | 2 +- services/cmap.c | 645 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1165 insertions(+), 2 deletions(-) create mode 100644 include/corosync/cmap.h create mode 100644 include/corosync/ipc_cmap.h create mode 100644 services/cmap.c diff --git a/include/corosync/cmap.h b/include/corosync/cmap.h new file mode 100644 index 0000000..b43dcea --- /dev/null +++ b/include/corosync/cmap.h @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Jan Friesse (jfriesse@xxxxxxxxxx) + * + * This software licensed under BSD license, the text of which follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the Red Hat, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef COROSYNC_CMAP_H_DEFINED +#define COROSYNC_CMAP_H_DEFINED + +#include <corosync/corotypes.h> +#include <corosync/hdb.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup cmap_corosync + * + * @{ + */ + +/* + * Handle for cmap service connection + */ +typedef uint64_t cmap_handle_t; + +/* + * Handle for cmap iterator + */ +typedef uint64_t cmap_iter_handle_t; + +/* + * Handle for cmap tracking function + */ +typedef uint64_t cmap_track_handle_t; + +/* + * Maximum length of key in cmap + */ +#define CMAP_KEYNAME_MAXLEN 255 +/* + * Minumum length of key in cmap + */ +#define CMAP_KEYNAME_MINLEN 3 + +/* + * Tracking values. + */ +#define CMAP_TRACK_ADD 4 +#define CMAP_TRACK_DELETE 1 +#define CMAP_TRACK_MODIFY 2 +/* + * Whole prefix is tracked, instead of key only (so "totem." tracking means that + * "totem.nodeid", "totem.version", ... applies). This value is also never returned + * inside of callback and is used only in adding track + */ +#define CMAP_TRACK_PREFIX 8 + +/* + * Possible types of value. Binary is raw data without trailing zero with given length + */ +typedef enum { + CMAP_VALUETYPE_INT8 = 1, + CMAP_VALUETYPE_UINT8 = 2, + CMAP_VALUETYPE_INT16 = 3, + CMAP_VALUETYPE_UINT16 = 4, + CMAP_VALUETYPE_INT32 = 5, + CMAP_VALUETYPE_UINT32 = 6, + CMAP_VALUETYPE_INT64 = 7, + CMAP_VALUETYPE_UINT64 = 8, + CMAP_VALUETYPE_FLOAT = 9, + CMAP_VALUETYPE_DOUBLE = 10, + CMAP_VALUETYPE_STRING = 11, + CMAP_VALUETYPE_BINARY = 12, +} cmap_value_types_t; + +/* + * Structure passed as new_value and old_value in change callback. It contains type of + * key, length of key and pointer to value of key + */ +struct cmap_notify_value { + cmap_value_types_t type; + size_t len; + const void *data; +}; + +/* + * Prototype for notify callback function. Even is one of CMAP_TRACK_* event, key_name is + * changed key, new and old_value contains values or are zeroed (in other words, type is non + * existing 0 type) if there were no old (creating of key) or new (deleting of key) value. + * user_data are passed when adding tracking. + */ +typedef void (*cmap_notify_fn_t) ( + cmap_handle_t cmap_handle, + cmap_track_handle_t cmap_track_handle, + int32_t event, + const char *key_name, + struct cmap_notify_value new_value, + struct cmap_notify_value old_value, + void *user_data); + +/** + * Create a new cmap connection + * + * @param handle will be filled with handle to be used for all following + * operations with cht. + */ +extern cs_error_t cmap_initialize ( + cmap_handle_t *handle); + +/** + * Close the cmap handle + * @param handle cmap handle + */ +extern cs_error_t cmap_finalize ( + cmap_handle_t handle); + +/* + * Get a file descriptor on which to poll. cmap_handle_t is NOT a + * file descriptor and may not be used directly. + * @param handle cmap handle initialized by cmap_initialize + * @param fd file descriptor for poll + */ +extern cs_error_t cmap_fd_get ( + cmap_handle_t handle, + int *fd); + +/** + * Dispatch data from service. + * @param handle cmap handle initialized by cmap_initialize + * @param dispatch_types one of standard corosync dispatch values + */ +extern cs_error_t cmap_dispatch ( + cmap_handle_t handle, + cs_dispatch_flags_t dispatch_types); +/* + * Get/set context variable + */ +extern cs_error_t cmap_context_get ( + cmap_handle_t handle, + const void **context); + +extern cs_error_t cmap_context_set ( + cmap_handle_t handle, + const void *context); + + +/** + * Store value in cmap + * @param handle cmap handle + * @param key_name name of key where to store value + * @param value value to store + * @param value_len length of value to store + * @param type type to store + */ +extern cs_error_t cmap_set( + cmap_handle_t handle, + const char *key_name, + const void *value, + size_t value_len, + cmap_value_types_t type); + +/* + * Shortcuts for cmap_set with given type + */ +extern cs_error_t cmap_set_int8(cmap_handle_t handle, const char *key_name, int8_t value); +extern cs_error_t cmap_set_uint8(cmap_handle_t handle, const char *key_name, uint8_t value); +extern cs_error_t cmap_set_int16(cmap_handle_t handle, const char *key_name, int16_t value); +extern cs_error_t cmap_set_uint16(cmap_handle_t handle, const char *key_name, uint16_t value); +extern cs_error_t cmap_set_int32(cmap_handle_t handle, const char *key_name, int32_t value); +extern cs_error_t cmap_set_uint32(cmap_handle_t handle, const char *key_name, uint32_t value); +extern cs_error_t cmap_set_int64(cmap_handle_t handle, const char *key_name, int64_t value); +extern cs_error_t cmap_set_uint64(cmap_handle_t handle, const char *key_name, uint64_t value); +extern cs_error_t cmap_set_float(cmap_handle_t handle, const char *key_name, float value); +extern cs_error_t cmap_set_double(cmap_handle_t handle, const char *key_name, double value); +extern cs_error_t cmap_set_string(cmap_handle_t handle, const char *key_name, const char *value); + +/** + * Deletes key from cmap database + * @param handle cmap handle + * @param key_name name of key to delete + */ +extern cs_error_t cmap_delete(cmap_handle_t handle, const char *key_name); + +/** + * Retrieve value of key key_name and store it in user preallocated value pointer. + * value can be NULL, and then only value_len and/or type is returned (both of them + * can also be NULL). If value is not NULL, actual length of value in map is checked + * against value_len. If *value_len is shorter then length of value in map, error + * CS_ERR_INVALID_PARAM is returned. After successful copy of value, value_len is + * set to actual length of value in map. + * + * @param handle cmap handle + * @param key_name name of key where to get value + * @param value pointer to store data (or NULL) + * @param value_len pointer with length of value (value != NULL), or pointer where value length + * will be returned (value == NULL) or NULL. + * @param type type of value in cmap + */ +extern cs_error_t cmap_get( + cmap_handle_t handle, + const char *key_name, + void *value, + size_t *value_len, + cmap_value_types_t *type); + +/* + * Shortcuts for cmap_get. + */ +extern cs_error_t cmap_get_int8(cmap_handle_t handle, const char *key_name, int8_t *i8); +extern cs_error_t cmap_get_uint8(cmap_handle_t handle, const char *key_name, uint8_t *u8); +extern cs_error_t cmap_get_int16(cmap_handle_t handle, const char *key_name, int16_t *i16); +extern cs_error_t cmap_get_uint16(cmap_handle_t handle, const char *key_name, uint16_t *u16); +extern cs_error_t cmap_get_int32(cmap_handle_t handle, const char *key_name, int32_t *i32); +extern cs_error_t cmap_get_uint32(cmap_handle_t handle, const char *key_name, uint32_t *u32); +extern cs_error_t cmap_get_int64(cmap_handle_t handle, const char *key_name, int64_t *i64); +extern cs_error_t cmap_get_uint64(cmap_handle_t handle, const char *key_name, uint64_t *u64); +extern cs_error_t cmap_get_float(cmap_handle_t handle, const char *key_name, float *flt); +extern cs_error_t cmap_get_double(cmap_handle_t handle, const char *key_name, double *dbl); + +/** + * Shortcut for cmap_get for string type. Returned string is newly allocated and + * caller is responsible for freeing memory + * @param handle cmap handle + * @param key_name name of key to get value from + * @param str pointer where char pointer will be stored + */ +extern cs_error_t cmap_get_string(cmap_handle_t handle, const char *key_name, char **str); + +/** + * Increment value of key_name if it is [u]int* type + * @param handle cmap handle + * @param key_name key name + */ +extern cs_error_t cmap_inc(cmap_handle_t handle, const char *key_name); + +/** + * Decrement value of key_name if it is [u]int* type + * @param handle cmap handle + * @param key_name key name + */ +extern cs_error_t cmap_dec(cmap_handle_t handle, const char *key_name); + +/** + * Initialize iterator with given prefix + * @param handle cmap handle + * @param prefix prefix to iterate on + * @param cmap_iter_handle value used for getting next value of iterator and/or deleting iteration + */ +extern cs_error_t cmap_iter_init(cmap_handle_t handle, const char *prefix, cmap_iter_handle_t *cmap_iter_handle); + +/** + * Return next item in iterator iter. value_len and type are optional (= can be NULL), but if set, + * length of returned value and/or type is returned. + * + * @param handle cmap handle + * @param cmap_iter_handle handle of iteration returned by cmap_iter_init + * @param key_name place to store name of key. Maximum length is CMAP_KEYNAME_MAXLEN + * @param value_len length of value + * @param type type of value + * @return CS_NO_SECTION if there are no more sections to iterate + */ +extern cs_error_t cmap_iter_next( + cmap_handle_t handle, + cmap_iter_handle_t iter_handle, + char key_name[], + size_t *value_len, + cmap_value_types_t *type); + +/** + * Finalize iterator + */ +extern cs_error_t cmap_iter_finalize(cmap_handle_t handle, cmap_iter_handle_t iter_handle); + +/* + * Add tracking function for given key_name. Tracked changes (add|modify|delete) depend on track_type, + * which is bitwise or of CMAP_TRACK_* values. notify_fn is called on change, where user_data pointer + * is passed (unchanged). Value which can be used to delete tracking is passed as cmap_track. + * @param handle cmap handle + * @param key_name name of key to track changes on + * @param track_type bitwise-or of CMAP_TRACK_* values + * @param notify_fn function to be called on change of key + * @param user_data given pointer is unchanged passed to notify_fn + * @param cmap_track_handle handle used for removing of newly created track + */ +extern cs_error_t cmap_track_add( + cmap_handle_t handle, + const char *key_name, + int32_t track_type, + cmap_notify_fn_t notify_fn, + void *user_data, + cmap_track_handle_t *cmap_track_handle); + +/** + * Delete track created previously by cmap_track_add + * @param handle cmap handle + * @param track_handle Track handle + */ +extern cs_error_t cmap_track_delete(cmap_handle_t handle, cmap_track_handle_t track_handle); + +#ifdef __cplusplus +} +#endif + +#endif /* COROSYNC_CMAP_H_DEFINED */ diff --git a/include/corosync/corodefs.h b/include/corosync/corodefs.h index 7d03644..c43f6ca 100644 --- a/include/corosync/corodefs.h +++ b/include/corosync/corodefs.h @@ -59,7 +59,8 @@ enum corosync_service_types { TST_SV1_SERVICE = 18, TST_SV2_SERVICE = 19, MON_SERVICE = 20, - WD_SERVICE = 21 + WD_SERVICE = 21, + CMAP_SERVICE = 22, }; #ifdef HAVE_SMALL_MEMORY_FOOTPRINT diff --git a/include/corosync/ipc_cmap.h b/include/corosync/ipc_cmap.h new file mode 100644 index 0000000..5784410 --- /dev/null +++ b/include/corosync/ipc_cmap.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Jan Friesse (jfriesse@xxxxxxxxxx) + * + * This software licensed under BSD license, the text of which follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the Red Hat, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IPC_CMAP_H_DEFINED +#define IPC_CMAP_H_DEFINED + +#include <netinet/in.h> +#include <corosync/corotypes.h> +#include <corosync/mar_gen.h> + +enum req_cmap_types { + MESSAGE_REQ_CMAP_SET = 0, + MESSAGE_REQ_CMAP_DELETE = 1, + MESSAGE_REQ_CMAP_GET = 2, + MESSAGE_REQ_CMAP_ADJUST_INT = 3, + MESSAGE_REQ_CMAP_ITER_INIT = 4, + MESSAGE_REQ_CMAP_ITER_NEXT = 5, + MESSAGE_REQ_CMAP_ITER_FINALIZE = 6, + MESSAGE_REQ_CMAP_TRACK_ADD = 7, + MESSAGE_REQ_CMAP_TRACK_DELETE = 8, +}; + +enum res_cmap_types { + MESSAGE_RES_CMAP_SET = 0, + MESSAGE_RES_CMAP_DELETE = 1, + MESSAGE_RES_CMAP_GET = 2, + MESSAGE_RES_CMAP_ADJUST_INT = 3, + MESSAGE_RES_CMAP_ITER_INIT = 4, + MESSAGE_RES_CMAP_ITER_NEXT = 5, + MESSAGE_RES_CMAP_ITER_FINALIZE = 6, + MESSAGE_RES_CMAP_TRACK_ADD = 7, + MESSAGE_RES_CMAP_TRACK_DELETE = 8, + MESSAGE_RES_CMAP_NOTIFY_CALLBACK = 9, +}; + +struct req_lib_cmap_set { + struct qb_ipc_request_header header __attribute__((aligned(8))); + mar_name_t key_name __attribute__((aligned(8))); + mar_size_t value_len __attribute__((aligned(8))); + mar_uint8_t type __attribute__((aligned(8))); + mar_uint8_t value[] __attribute__((aligned(8))); +}; + +struct res_lib_cmap_set { + struct qb_ipc_response_header header __attribute__((aligned(8))); +}; + +struct req_lib_cmap_delete { + struct qb_ipc_request_header header __attribute__((aligned(8))); + mar_name_t key_name __attribute__((aligned(8))); +}; + +struct res_lib_cmap_delete { + struct qb_ipc_response_header header __attribute__((aligned(8))); +}; + +struct req_lib_cmap_get { + struct qb_ipc_request_header header __attribute__((aligned(8))); + mar_name_t key_name __attribute__((aligned(8))); + mar_size_t value_len __attribute__((aligned(8))); +}; + +struct res_lib_cmap_get { + struct qb_ipc_response_header header __attribute__((aligned(8))); + mar_size_t value_len __attribute__((aligned(8))); + mar_uint8_t type __attribute__((aligned(8))); + mar_uint8_t value[] __attribute__((aligned(8))); +}; + +struct req_lib_cmap_adjust_int { + struct qb_ipc_request_header header __attribute__((aligned(8))); + mar_name_t key_name __attribute__((aligned(8))); + mar_int32_t step __attribute__((aligned(8))); +}; + +struct res_lib_cmap_adjust_int { + struct qb_ipc_response_header header __attribute__((aligned(8))); +}; + +struct req_lib_cmap_iter_init { + struct qb_ipc_request_header header __attribute__((aligned(8))); + mar_name_t prefix __attribute__((aligned(8))); +}; + +struct res_lib_cmap_iter_init { + struct qb_ipc_response_header header __attribute__((aligned(8))); + mar_uint64_t iter_handle __attribute__((aligned(8))); +}; + +struct req_lib_cmap_iter_next { + struct qb_ipc_request_header header __attribute__((aligned(8))); + mar_uint64_t iter_handle __attribute__((aligned(8))); +}; + +struct res_lib_cmap_iter_next { + struct qb_ipc_response_header header __attribute__((aligned(8))); + mar_name_t key_name __attribute__((aligned(8))); + mar_size_t value_len __attribute__((aligned(8))); + mar_uint8_t type __attribute__((aligned(8))); +}; + +struct req_lib_cmap_iter_finalize { + struct qb_ipc_request_header header __attribute__((aligned(8))); + mar_uint64_t iter_handle __attribute__((aligned(8))); +}; + +struct res_lib_cmap_iter_finalize { + struct qb_ipc_response_header header __attribute__((aligned(8))); +}; + +struct req_lib_cmap_track_add { + struct qb_ipc_request_header header __attribute__((aligned(8))); + mar_name_t key_name __attribute__((aligned(8))); + mar_int32_t track_type __attribute__((aligned(8))); + mar_uint64_t track_inst_handle __attribute__((aligned(8))); +}; + +struct res_lib_cmap_track_add { + struct qb_ipc_response_header header __attribute__((aligned(8))); + mar_uint64_t track_handle __attribute__((aligned(8))); +}; + +struct req_lib_cmap_track_delete { + struct qb_ipc_request_header header __attribute__((aligned(8))); + mar_uint64_t track_handle __attribute__((aligned(8))); +}; + +struct res_lib_cmap_track_delete { + struct qb_ipc_response_header header __attribute__((aligned(8))); + mar_uint64_t track_inst_handle __attribute__((aligned(8))); +}; + +struct res_lib_cmap_notify_callback { + struct qb_ipc_response_header header __attribute__((aligned(8))); + mar_uint64_t track_inst_handle __attribute__((aligned(8))); + mar_name_t key_name __attribute__((aligned(8))); + mar_int32_t event __attribute__((aligned(8))); + mar_uint8_t new_value_type __attribute__((aligned(8))); + mar_uint8_t old_value_type __attribute__((aligned(8))); + mar_size_t new_value_len __attribute__((aligned(8))); + mar_size_t old_value_len __attribute__((aligned(8))); + /* + * After old_vale_len, there are two items with length of new_value_len + * and old_value_len, only first (as a pointer) is defined + * + * mar_uint8_t *new_value; + * mar_uint8_t *old_value; + */ + mar_uint8_t new_value[]; +}; + +#endif /* IPC_CMAP_H_DEFINED */ diff --git a/services/Makefile.am b/services/Makefile.am index f39adc3..376363d 100644 --- a/services/Makefile.am +++ b/services/Makefile.am @@ -37,7 +37,7 @@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ -I$(top_builddir)/include/corosync \ -I$(top_srcdir)/include/corosync -SERVICE_LCRSO = evs cfg cpg confdb pload +SERVICE_LCRSO = evs cfg cpg confdb pload cmap if BUILD_WATCHDOG SERVICE_LCRSO += wd endif diff --git a/services/cmap.c b/services/cmap.c new file mode 100644 index 0000000..92f0574 --- /dev/null +++ b/services/cmap.c @@ -0,0 +1,645 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Jan Friesse (jfriesse@xxxxxxxxxx) + * + * This software licensed under BSD license, the text of which follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the Red Hat, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <config.h> + +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <poll.h> +#include <assert.h> + +#include <qb/qbloop.h> +#include <qb/qbipc_common.h> + +#include <corosync/corotypes.h> +#include <corosync/corodefs.h> +#include <corosync/list.h> +#include <corosync/mar_gen.h> +#include <corosync/ipc_cmap.h> +#include <corosync/lcr/lcr_comp.h> +#include <corosync/engine/logsys.h> +#include <corosync/engine/coroapi.h> +#include <corosync/engine/icmap.h> + +#define hdb_error_to_cs(_result_) qb_to_cs_error(_result_) + +LOGSYS_DECLARE_SUBSYS ("CMAP"); + +struct cmap_conn_info { + struct hdb_handle_database iter_db; + struct hdb_handle_database track_db; +}; + +typedef uint64_t cmap_iter_handle_t; +typedef uint64_t cmap_track_handle_t; + +struct cmap_track_user_data { + void *conn; + cmap_track_handle_t track_handle; + uint64_t track_inst_handle; +}; + +static struct corosync_api_v1 *api; + +static int cmap_exec_init_fn (struct corosync_api_v1 *corosync_api); +static int cmap_exec_exit_fn(void); + +static int cmap_lib_init_fn (void *conn); +static int cmap_lib_exit_fn (void *conn); + +static void message_handler_req_lib_cmap_set(void *conn, const void *message); +static void message_handler_req_lib_cmap_delete(void *conn, const void *message); +static void message_handler_req_lib_cmap_get(void *conn, const void *message); +static void message_handler_req_lib_cmap_adjust_int(void *conn, const void *message); +static void message_handler_req_lib_cmap_iter_init(void *conn, const void *message); +static void message_handler_req_lib_cmap_iter_next(void *conn, const void *message); +static void message_handler_req_lib_cmap_iter_finalize(void *conn, const void *message); +static void message_handler_req_lib_cmap_track_add(void *conn, const void *message); +static void message_handler_req_lib_cmap_track_delete(void *conn, const void *message); + +static void cmap_notify_fn(int32_t event, + const char *key_name, + struct icmap_notify_value new_val, + struct icmap_notify_value old_val, + void *user_data); + +/* + * Library Handler Definition + */ +static struct corosync_lib_handler cmap_lib_engine[] = +{ + { /* 0 */ + .lib_handler_fn = message_handler_req_lib_cmap_set, + .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED + }, + { /* 1 */ + .lib_handler_fn = message_handler_req_lib_cmap_delete, + .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED + }, + { /* 2 */ + .lib_handler_fn = message_handler_req_lib_cmap_get, + .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED + }, + { /* 3 */ + .lib_handler_fn = message_handler_req_lib_cmap_adjust_int, + .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED + }, + { /* 4 */ + .lib_handler_fn = message_handler_req_lib_cmap_iter_init, + .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED + }, + { /* 5 */ + .lib_handler_fn = message_handler_req_lib_cmap_iter_next, + .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED + }, + { /* 6 */ + .lib_handler_fn = message_handler_req_lib_cmap_iter_finalize, + .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED + }, + { /* 7 */ + .lib_handler_fn = message_handler_req_lib_cmap_track_add, + .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED + }, + { /* 8 */ + .lib_handler_fn = message_handler_req_lib_cmap_track_delete, + .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED + }, +}; + + +struct corosync_service_engine cmap_service_engine = { + .name = "corosync configuration map access", + .id = CMAP_SERVICE, + .priority = 1, + .private_data_size = sizeof(struct cmap_conn_info), + .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED, + .allow_inquorate = CS_LIB_ALLOW_INQUORATE, + .lib_init_fn = cmap_lib_init_fn, + .lib_exit_fn = cmap_lib_exit_fn, + .lib_engine = cmap_lib_engine, + .lib_engine_count = sizeof (cmap_lib_engine) / sizeof (struct corosync_lib_handler), + .exec_init_fn = cmap_exec_init_fn, + .exec_exit_fn = cmap_exec_exit_fn, +}; + +/* + * Dynamic loader definition + */ +static struct corosync_service_engine *cmap_get_service_engine_ver0 (void); + +static struct corosync_service_engine_iface_ver0 cmap_service_engine_iface = { + .corosync_get_service_engine_ver0 = cmap_get_service_engine_ver0 +}; + +static struct lcr_iface corosync_cmap_ver0[1] = { + { + .name = "corosync_cmap", + .version = 0, + .versions_replace = 0, + .versions_replace_count = 0, + .dependencies = 0, + .dependency_count = 0, + .constructor = NULL, + .destructor = NULL, + .interfaces = NULL + } +}; + +static struct lcr_comp cmap_comp_ver0 = { + .iface_count = 1, + .ifaces = corosync_cmap_ver0 +}; + + +static struct corosync_service_engine *cmap_get_service_engine_ver0 (void) +{ + return (&cmap_service_engine); +} + +#ifdef COROSYNC_SOLARIS +void corosync_lcr_component_register (void); + +void corosync_lcr_component_register (void) { +#else +__attribute__ ((constructor)) static void corosync_lcr_component_register (void) { +#endif + lcr_interfaces_set (&corosync_cmap_ver0[0], &cmap_service_engine_iface); + + lcr_component_register (&cmap_comp_ver0); +} + +static int cmap_exec_exit_fn(void) +{ + return 0; +} + +static int cmap_exec_init_fn ( + struct corosync_api_v1 *corosync_api) +{ + +#ifdef COROSYNC_SOLARIS + logsys_subsys_init(); +#endif + api = corosync_api; + + return (0); +} + +static int cmap_lib_init_fn (void *conn) +{ + struct cmap_conn_info *conn_info = (struct cmap_conn_info *)api->ipc_private_data_get (conn); + + log_printf(LOGSYS_LEVEL_DEBUG, "lib_init_fn: conn=%p\n", conn); + + api->ipc_refcnt_inc(conn); + + memset(conn_info, 0, sizeof(*conn_info)); + hdb_create(&conn_info->iter_db); + hdb_create(&conn_info->track_db); + + return (0); +} + +static int cmap_lib_exit_fn (void *conn) +{ + struct cmap_conn_info *conn_info = (struct cmap_conn_info *)api->ipc_private_data_get (conn); + hdb_handle_t iter_handle = 0; + icmap_iter_t *iter; + hdb_handle_t track_handle = 0; + icmap_track_t *track; + + log_printf(LOGSYS_LEVEL_DEBUG, "exit_fn for conn=%p\n", conn); + + hdb_iterator_reset(&conn_info->iter_db); + while (hdb_iterator_next(&conn_info->iter_db, + (void*)&iter, &iter_handle) == 0) { + + icmap_iter_finalize(*iter); + + (void)hdb_handle_put (&conn_info->iter_db, iter_handle); + } + + hdb_destroy(&conn_info->iter_db); + + hdb_iterator_reset(&conn_info->track_db); + while (hdb_iterator_next(&conn_info->track_db, + (void*)&track, &track_handle) == 0) { + + free(icmap_track_get_user_data(*track)); + + icmap_track_delete(*track); + + (void)hdb_handle_put (&conn_info->track_db, track_handle); + } + hdb_destroy(&conn_info->track_db); + + api->ipc_refcnt_dec(conn); + + return (0); +} + +static void message_handler_req_lib_cmap_set(void *conn, const void *message) +{ + const struct req_lib_cmap_set *req_lib_cmap_set = message; + struct res_lib_cmap_set res_lib_cmap_set; + cs_error_t ret; + + if (icmap_is_key_ro((char *)req_lib_cmap_set->key_name.value)) { + ret = CS_ERR_ACCESS; + } else { + ret = icmap_set((char *)req_lib_cmap_set->key_name.value, &req_lib_cmap_set->value, + req_lib_cmap_set->value_len, req_lib_cmap_set->type); + } + + memset(&res_lib_cmap_set, 0, sizeof(res_lib_cmap_set)); + res_lib_cmap_set.header.size = sizeof(res_lib_cmap_set); + res_lib_cmap_set.header.id = MESSAGE_RES_CMAP_SET; + res_lib_cmap_set.header.error = ret; + + api->ipc_response_send(conn, &res_lib_cmap_set, sizeof(res_lib_cmap_set)); +} + +static void message_handler_req_lib_cmap_delete(void *conn, const void *message) +{ + const struct req_lib_cmap_set *req_lib_cmap_set = message; + struct res_lib_cmap_delete res_lib_cmap_delete; + cs_error_t ret; + + if (icmap_is_key_ro((char *)req_lib_cmap_set->key_name.value)) { + ret = CS_ERR_ACCESS; + } else { + ret = icmap_delete((char *)req_lib_cmap_set->key_name.value); + } + + memset(&res_lib_cmap_delete, 0, sizeof(res_lib_cmap_delete)); + res_lib_cmap_delete.header.size = sizeof(res_lib_cmap_delete); + res_lib_cmap_delete.header.id = MESSAGE_RES_CMAP_DELETE; + res_lib_cmap_delete.header.error = ret; + + api->ipc_response_send(conn, &res_lib_cmap_delete, sizeof(res_lib_cmap_delete)); +} + +static void message_handler_req_lib_cmap_get(void *conn, const void *message) +{ + const struct req_lib_cmap_get *req_lib_cmap_get = message; + struct res_lib_cmap_get *res_lib_cmap_get; + struct res_lib_cmap_get error_res_lib_cmap_get; + cs_error_t ret; + size_t value_len; + size_t res_lib_cmap_get_size; + icmap_value_types_t type; + void *value; + + value_len = req_lib_cmap_get->value_len; + + res_lib_cmap_get_size = sizeof(*res_lib_cmap_get) + value_len; + res_lib_cmap_get = malloc(res_lib_cmap_get_size); + if (res_lib_cmap_get == NULL) { + ret = CS_ERR_NO_MEMORY; + goto error_exit; + } + + memset(res_lib_cmap_get, 0, res_lib_cmap_get_size); + + if (value_len > 0) { + value = res_lib_cmap_get->value; + } else { + value = NULL; + } + + ret = icmap_get((char *)req_lib_cmap_get->key_name.value, + value, + &value_len, + &type); + + if (ret != CS_OK) { + free(res_lib_cmap_get); + goto error_exit; + } + + res_lib_cmap_get->header.size = res_lib_cmap_get_size; + res_lib_cmap_get->header.id = MESSAGE_RES_CMAP_GET; + res_lib_cmap_get->header.error = ret; + res_lib_cmap_get->type = type; + res_lib_cmap_get->value_len = value_len; + + api->ipc_response_send(conn, res_lib_cmap_get, res_lib_cmap_get_size); + free(res_lib_cmap_get); + + return ; + +error_exit: + memset(&error_res_lib_cmap_get, 0, sizeof(error_res_lib_cmap_get)); + error_res_lib_cmap_get.header.size = sizeof(error_res_lib_cmap_get); + error_res_lib_cmap_get.header.id = MESSAGE_RES_CMAP_GET; + error_res_lib_cmap_get.header.error = ret; + + api->ipc_response_send(conn, &error_res_lib_cmap_get, sizeof(error_res_lib_cmap_get)); +} + +static void message_handler_req_lib_cmap_adjust_int(void *conn, const void *message) +{ + const struct req_lib_cmap_adjust_int *req_lib_cmap_adjust_int = message; + struct res_lib_cmap_adjust_int res_lib_cmap_adjust_int; + cs_error_t ret; + + ret = icmap_adjust_int((char *)req_lib_cmap_adjust_int->key_name.value, req_lib_cmap_adjust_int->step); + + memset(&res_lib_cmap_adjust_int, 0, sizeof(res_lib_cmap_adjust_int)); + res_lib_cmap_adjust_int.header.size = sizeof(res_lib_cmap_adjust_int); + res_lib_cmap_adjust_int.header.id = MESSAGE_RES_CMAP_ADJUST_INT; + res_lib_cmap_adjust_int.header.error = ret; + + api->ipc_response_send(conn, &res_lib_cmap_adjust_int, sizeof(res_lib_cmap_adjust_int)); +} + +static void message_handler_req_lib_cmap_iter_init(void *conn, const void *message) +{ + const struct req_lib_cmap_iter_init *req_lib_cmap_iter_init = message; + struct res_lib_cmap_iter_init res_lib_cmap_iter_init; + cs_error_t ret; + icmap_iter_t iter; + icmap_iter_t *hdb_iter; + cmap_iter_handle_t handle; + const char *prefix; + struct cmap_conn_info *conn_info = (struct cmap_conn_info *)api->ipc_private_data_get (conn); + + if (req_lib_cmap_iter_init->prefix.length > 0) { + prefix = (char *)req_lib_cmap_iter_init->prefix.value; + } else { + prefix = NULL; + } + + iter = icmap_iter_init(prefix); + if (iter == NULL) { + ret = CS_ERR_NO_SECTIONS; + goto reply_send; + } + + ret = hdb_error_to_cs(hdb_handle_create(&conn_info->iter_db, sizeof(iter), &handle)); + if (ret != CS_OK) { + goto reply_send; + } + + ret = hdb_error_to_cs(hdb_handle_get(&conn_info->iter_db, handle, (void *)&hdb_iter)); + if (ret != CS_OK) { + goto reply_send; + } + + *hdb_iter = iter; + + (void)hdb_handle_put (&conn_info->iter_db, handle); + +reply_send: + memset(&res_lib_cmap_iter_init, 0, sizeof(res_lib_cmap_iter_init)); + res_lib_cmap_iter_init.header.size = sizeof(res_lib_cmap_iter_init); + res_lib_cmap_iter_init.header.id = MESSAGE_RES_CMAP_ITER_INIT; + res_lib_cmap_iter_init.header.error = ret; + res_lib_cmap_iter_init.iter_handle = handle; + + api->ipc_response_send(conn, &res_lib_cmap_iter_init, sizeof(res_lib_cmap_iter_init)); +} + +static void message_handler_req_lib_cmap_iter_next(void *conn, const void *message) +{ + const struct req_lib_cmap_iter_next *req_lib_cmap_iter_next = message; + struct res_lib_cmap_iter_next res_lib_cmap_iter_next; + cs_error_t ret; + icmap_iter_t *iter; + size_t value_len; + icmap_value_types_t type; + const char *res = NULL; + struct cmap_conn_info *conn_info = (struct cmap_conn_info *)api->ipc_private_data_get (conn); + + ret = hdb_error_to_cs(hdb_handle_get(&conn_info->iter_db, + req_lib_cmap_iter_next->iter_handle, (void *)&iter)); + if (ret != CS_OK) { + goto reply_send; + } + + res = icmap_iter_next(*iter, &value_len, &type); + if (res == NULL) { + ret = CS_ERR_NO_SECTIONS; + } + + (void)hdb_handle_put (&conn_info->iter_db, req_lib_cmap_iter_next->iter_handle); + +reply_send: + memset(&res_lib_cmap_iter_next, 0, sizeof(res_lib_cmap_iter_next)); + res_lib_cmap_iter_next.header.size = sizeof(res_lib_cmap_iter_next); + res_lib_cmap_iter_next.header.id = MESSAGE_RES_CMAP_ITER_NEXT; + res_lib_cmap_iter_next.header.error = ret; + + if (res != NULL) { + res_lib_cmap_iter_next.value_len = value_len; + res_lib_cmap_iter_next.type = type; + + memcpy(res_lib_cmap_iter_next.key_name.value, res, strlen(res)); + res_lib_cmap_iter_next.key_name.length = strlen(res); + } + + api->ipc_response_send(conn, &res_lib_cmap_iter_next, sizeof(res_lib_cmap_iter_next)); +} + +static void message_handler_req_lib_cmap_iter_finalize(void *conn, const void *message) +{ + const struct req_lib_cmap_iter_finalize *req_lib_cmap_iter_finalize = message; + struct res_lib_cmap_iter_finalize res_lib_cmap_iter_finalize; + cs_error_t ret; + icmap_iter_t *iter; + struct cmap_conn_info *conn_info = (struct cmap_conn_info *)api->ipc_private_data_get (conn); + + ret = hdb_error_to_cs(hdb_handle_get(&conn_info->iter_db, + req_lib_cmap_iter_finalize->iter_handle, (void *)&iter)); + if (ret != CS_OK) { + goto reply_send; + } + + icmap_iter_finalize(*iter); + + (void)hdb_handle_destroy(&conn_info->iter_db, req_lib_cmap_iter_finalize->iter_handle); + + (void)hdb_handle_put (&conn_info->iter_db, req_lib_cmap_iter_finalize->iter_handle); + +reply_send: + memset(&res_lib_cmap_iter_finalize, 0, sizeof(res_lib_cmap_iter_finalize)); + res_lib_cmap_iter_finalize.header.size = sizeof(res_lib_cmap_iter_finalize); + res_lib_cmap_iter_finalize.header.id = MESSAGE_RES_CMAP_ITER_FINALIZE; + res_lib_cmap_iter_finalize.header.error = ret; + + api->ipc_response_send(conn, &res_lib_cmap_iter_finalize, sizeof(res_lib_cmap_iter_finalize)); +} + +static void cmap_notify_fn(int32_t event, + const char *key_name, + struct icmap_notify_value new_val, + struct icmap_notify_value old_val, + void *user_data) +{ + struct cmap_track_user_data *cmap_track_user_data = (struct cmap_track_user_data *)user_data; + struct res_lib_cmap_notify_callback res_lib_cmap_notify_callback; + struct iovec iov[3]; + + memset(&res_lib_cmap_notify_callback, 0, sizeof(res_lib_cmap_notify_callback)); + + res_lib_cmap_notify_callback.header.size = sizeof(res_lib_cmap_notify_callback) + new_val.len + old_val.len; + res_lib_cmap_notify_callback.header.id = MESSAGE_RES_CMAP_NOTIFY_CALLBACK; + res_lib_cmap_notify_callback.header.error = CS_OK; + + res_lib_cmap_notify_callback.new_value_type = new_val.type; + res_lib_cmap_notify_callback.old_value_type = old_val.type; + res_lib_cmap_notify_callback.new_value_len = new_val.len; + res_lib_cmap_notify_callback.old_value_len = old_val.len; + res_lib_cmap_notify_callback.event = event; + res_lib_cmap_notify_callback.key_name.length = strlen(key_name); + res_lib_cmap_notify_callback.track_inst_handle = cmap_track_user_data->track_inst_handle; + + memcpy(res_lib_cmap_notify_callback.key_name.value, key_name, strlen(key_name)); + + iov[0].iov_base = (char *)&res_lib_cmap_notify_callback; + iov[0].iov_len = sizeof(res_lib_cmap_notify_callback); + iov[1].iov_base = (char *)new_val.data; + iov[1].iov_len = new_val.len; + iov[2].iov_base = (char *)old_val.data; + iov[2].iov_len = old_val.len; + + api->ipc_dispatch_iov_send(cmap_track_user_data->conn, iov, 3); +} + +static void message_handler_req_lib_cmap_track_add(void *conn, const void *message) +{ + const struct req_lib_cmap_track_add *req_lib_cmap_track_add = message; + struct res_lib_cmap_track_add res_lib_cmap_track_add; + cs_error_t ret; + cmap_track_handle_t handle; + icmap_track_t track; + icmap_track_t *hdb_track; + struct cmap_track_user_data *cmap_track_user_data; + const char *key_name; + + struct cmap_conn_info *conn_info = (struct cmap_conn_info *)api->ipc_private_data_get (conn); + + cmap_track_user_data = malloc(sizeof(*cmap_track_user_data)); + if (cmap_track_user_data == NULL) { + ret = CS_ERR_NO_MEMORY; + + goto reply_send; + } + memset(cmap_track_user_data, 0, sizeof(*cmap_track_user_data)); + + if (req_lib_cmap_track_add->key_name.length > 0) { + key_name = (char *)req_lib_cmap_track_add->key_name.value; + } else { + key_name = NULL; + } + + ret = icmap_track_add(key_name, + req_lib_cmap_track_add->track_type, + cmap_notify_fn, + cmap_track_user_data, + &track); + if (ret != CS_OK) { + free(cmap_track_user_data); + + goto reply_send; + } + + ret = hdb_error_to_cs(hdb_handle_create(&conn_info->track_db, sizeof(track), &handle)); + if (ret != CS_OK) { + free(cmap_track_user_data); + + goto reply_send; + } + + ret = hdb_error_to_cs(hdb_handle_get(&conn_info->track_db, handle, (void *)&hdb_track)); + if (ret != CS_OK) { + free(cmap_track_user_data); + + goto reply_send; + } + + *hdb_track = track; + cmap_track_user_data->conn = conn; + cmap_track_user_data->track_handle = handle; + cmap_track_user_data->track_inst_handle = req_lib_cmap_track_add->track_inst_handle; + + (void)hdb_handle_put (&conn_info->track_db, handle); + +reply_send: + memset(&res_lib_cmap_track_add, 0, sizeof(res_lib_cmap_track_add)); + res_lib_cmap_track_add.header.size = sizeof(res_lib_cmap_track_add); + res_lib_cmap_track_add.header.id = MESSAGE_RES_CMAP_TRACK_ADD; + res_lib_cmap_track_add.header.error = ret; + res_lib_cmap_track_add.track_handle = handle; + + api->ipc_response_send(conn, &res_lib_cmap_track_add, sizeof(res_lib_cmap_track_add)); +} + +static void message_handler_req_lib_cmap_track_delete(void *conn, const void *message) +{ + const struct req_lib_cmap_track_delete *req_lib_cmap_track_delete = message; + struct res_lib_cmap_track_delete res_lib_cmap_track_delete; + cs_error_t ret; + icmap_track_t *track; + struct cmap_conn_info *conn_info = (struct cmap_conn_info *)api->ipc_private_data_get (conn); + uint64_t track_inst_handle = 0; + + ret = hdb_error_to_cs(hdb_handle_get(&conn_info->track_db, + req_lib_cmap_track_delete->track_handle, (void *)&track)); + if (ret != CS_OK) { + goto reply_send; + } + + track_inst_handle = ((struct cmap_track_user_data *)icmap_track_get_user_data(*track))->track_inst_handle; + + free(icmap_track_get_user_data(*track)); + + ret = icmap_track_delete(*track); + + (void)hdb_handle_put (&conn_info->track_db, req_lib_cmap_track_delete->track_handle); + (void)hdb_handle_destroy(&conn_info->track_db, req_lib_cmap_track_delete->track_handle); + +reply_send: + memset(&res_lib_cmap_track_delete, 0, sizeof(res_lib_cmap_track_delete)); + res_lib_cmap_track_delete.header.size = sizeof(res_lib_cmap_track_delete); + res_lib_cmap_track_delete.header.id = MESSAGE_RES_CMAP_TRACK_DELETE; + res_lib_cmap_track_delete.header.error = ret; + res_lib_cmap_track_delete.track_inst_handle = track_inst_handle; + + api->ipc_response_send(conn, &res_lib_cmap_track_delete, sizeof(res_lib_cmap_track_delete)); +} -- 1.7.1 _______________________________________________ discuss mailing list discuss@xxxxxxxxxxxx http://lists.corosync.org/mailman/listinfo/discuss