diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-03 17:01:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-03 17:01:24 +0000 |
commit | 6dd3dfb79125cd02d02efbce435a6c82e5af92ef (patch) | |
tree | 45084fc83278586f6bbafcb935f92d53f71a6b03 /lib | |
parent | Initial commit. (diff) | |
download | corosync-6dd3dfb79125cd02d02efbce435a6c82e5af92ef.tar.xz corosync-6dd3dfb79125cd02d02efbce435a6c82e5af92ef.zip |
Adding upstream version 3.1.8.upstream/3.1.8upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.am | 66 | ||||
-rw-r--r-- | lib/Makefile.in | 786 | ||||
-rw-r--r-- | lib/cfg.c | 835 | ||||
-rw-r--r-- | lib/cmap.c | 1119 | ||||
-rw-r--r-- | lib/cpg.c | 1426 | ||||
-rw-r--r-- | lib/libcfg.versions | 18 | ||||
-rw-r--r-- | lib/libcfg.verso | 1 | ||||
-rw-r--r-- | lib/libcmap.versions | 6 | ||||
-rw-r--r-- | lib/libcmap.verso | 1 | ||||
-rw-r--r-- | lib/libcpg.versions | 17 | ||||
-rw-r--r-- | lib/libcpg.verso | 1 | ||||
-rw-r--r-- | lib/libquorum.versions | 11 | ||||
-rw-r--r-- | lib/libquorum.verso | 1 | ||||
-rw-r--r-- | lib/libsam.versions | 12 | ||||
-rw-r--r-- | lib/libsam.verso | 1 | ||||
-rw-r--r-- | lib/libvotequorum.versions | 17 | ||||
-rw-r--r-- | lib/libvotequorum.verso | 1 | ||||
-rw-r--r-- | lib/quorum.c | 588 | ||||
-rw-r--r-- | lib/sam.c | 1489 | ||||
-rw-r--r-- | lib/util.h | 54 | ||||
-rw-r--r-- | lib/votequorum.c | 811 |
21 files changed, 7261 insertions, 0 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000..002866a --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,66 @@ +# +# Copyright (c) 2009-2020 Red Hat, Inc. +# +# Authors: Andrew Beekhof +# Steven Dake (sdake@redhat.com) +# +# 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 MontaVista Software, 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. + +# Functions to be used at link time (target.lo) +get_libname=$(shell echo $1 | $(SED) -e "s/\.lo//") +uc=$(shell echo $(call get_libname,$1) | tr a-z A-Z) +get_soname=$(subst .,:,$(if $($(call uc,$1)_SONAME),$($(call uc,$1)_SONAME),$(SONAME))) +get_major=$(firstword $(subst :, ,$(call get_soname,$1))) + +MAINTAINERCLEANFILES = Makefile.in + +EXTRA_DIST = libcfg.versions libcfg.verso \ + libcmap.versions libcmap.verso \ + libcpg.versions libcpg.verso \ + libquorum.versions libquorum.verso \ + libsam.versions libsam.verso \ + libvotequorum.versions libvotequorum.verso + +noinst_HEADERS = util.h + +# override global LIBS that pulls in lots of craft we don't need here +LIBS = -version-number $(call get_soname,$<) \ + @VERSCRIPT_LDFLAGS@ \ + -lpthread \ + $(top_builddir)/common_lib/libcorosync_common.la \ + $(LIBQB_LIBS) + +lib_LTLIBRARIES = libcpg.la libquorum.la libcfg.la \ + libvotequorum.la libcmap.la libsam.la + +libcpg_la_SOURCES = cpg.c +libcfg_la_SOURCES = cfg.c +libquorum_la_SOURCES = quorum.c +libvotequorum_la_SOURCES= votequorum.c +libcmap_la_SOURCES = cmap.c +libsam_la_SOURCES = sam.c +libsam_la_LIBADD = libquorum.la libcmap.la diff --git a/lib/Makefile.in b/lib/Makefile.in new file mode 100644 index 0000000..2fa4309 --- /dev/null +++ b/lib/Makefile.in @@ -0,0 +1,786 @@ +# Makefile.in generated by automake 1.13.4 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Copyright (c) 2009-2020 Red Hat, Inc. +# +# Authors: Andrew Beekhof +# Steven Dake (sdake@redhat.com) +# +# 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 MontaVista Software, 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. + + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/depcomp $(noinst_HEADERS) +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/lib/libcfg.verso $(top_srcdir)/lib/libcpg.verso \ + $(top_srcdir)/lib/libquorum.verso \ + $(top_srcdir)/lib/libsam.verso \ + $(top_srcdir)/lib/libvotequorum.verso \ + $(top_srcdir)/lib/libcmap.verso $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/corosync/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libcfg_la_LIBADD = +am_libcfg_la_OBJECTS = cfg.lo +libcfg_la_OBJECTS = $(am_libcfg_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libcmap_la_LIBADD = +am_libcmap_la_OBJECTS = cmap.lo +libcmap_la_OBJECTS = $(am_libcmap_la_OBJECTS) +libcpg_la_LIBADD = +am_libcpg_la_OBJECTS = cpg.lo +libcpg_la_OBJECTS = $(am_libcpg_la_OBJECTS) +libquorum_la_LIBADD = +am_libquorum_la_OBJECTS = quorum.lo +libquorum_la_OBJECTS = $(am_libquorum_la_OBJECTS) +libsam_la_DEPENDENCIES = libquorum.la libcmap.la +am_libsam_la_OBJECTS = sam.lo +libsam_la_OBJECTS = $(am_libsam_la_OBJECTS) +libvotequorum_la_LIBADD = +am_libvotequorum_la_OBJECTS = votequorum.lo +libvotequorum_la_OBJECTS = $(am_libvotequorum_la_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include/corosync +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libcfg_la_SOURCES) $(libcmap_la_SOURCES) \ + $(libcpg_la_SOURCES) $(libquorum_la_SOURCES) \ + $(libsam_la_SOURCES) $(libvotequorum_la_SOURCES) +DIST_SOURCES = $(libcfg_la_SOURCES) $(libcmap_la_SOURCES) \ + $(libcpg_la_SOURCES) $(libquorum_la_SOURCES) \ + $(libsam_la_SOURCES) $(libvotequorum_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUGTOOL = @AUGTOOL@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASHPATH = @BASHPATH@ +BINDGEN = @BINDGEN@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFG_SONAME = @CFG_SONAME@ +CFLAGS = @CFLAGS@ +CLIPPY = @CLIPPY@ +CMAP_SONAME = @CMAP_SONAME@ +COROSYSCONFDIR = @COROSYSCONFDIR@ +CPG_SONAME = @CPG_SONAME@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DBUS_CFLAGS = @DBUS_CFLAGS@ +DBUS_LIBS = @DBUS_LIBS@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOT = @DOT@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +GROFF = @GROFF@ +INITCONFIGDIR = @INITCONFIGDIR@ +INITDDIR = @INITDDIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBQB_CFLAGS = @LIBQB_CFLAGS@ +LIBQB_LIBS = @LIBQB_LIBS@ + +# override global LIBS that pulls in lots of craft we don't need here +LIBS = -version-number $(call get_soname,$<) \ + @VERSCRIPT_LDFLAGS@ \ + -lpthread \ + $(top_builddir)/common_lib/libcorosync_common.la \ + $(LIBQB_LIBS) + +LIBTOOL = @LIBTOOL@ +LINT_FLAGS = @LINT_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOGDIR = @LOGDIR@ +LOGROTATEDIR = @LOGROTATEDIR@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +QUORUM_SONAME = @QUORUM_SONAME@ +RANLIB = @RANLIB@ +RUSTC = @RUSTC@ +RUSTDOC = @RUSTDOC@ +RUSTFMT = @RUSTFMT@ +RUST_FLAGS = @RUST_FLAGS@ +RUST_TARGET_DIR = @RUST_TARGET_DIR@ +SAM_SONAME = @SAM_SONAME@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SNMPCONFIG = @SNMPCONFIG@ +SNMP_LIBS = @SNMP_LIBS@ +SOMAJOR = @SOMAJOR@ +SOMICRO = @SOMICRO@ +SOMINOR = @SOMINOR@ +SONAME = @SONAME@ +STRIP = @STRIP@ +SYSTEMDDIR = @SYSTEMDDIR@ +VERSCRIPT_LDFLAGS = @VERSCRIPT_LDFLAGS@ +VERSION = @VERSION@ +VOTEQUORUM_SONAME = @VOTEQUORUM_SONAME@ +WITH_LIST = @WITH_LIST@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +corosyncrustver = @corosyncrustver@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +knet_CFLAGS = @knet_CFLAGS@ +knet_LIBS = @knet_LIBS@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libsystemd_CFLAGS = @libsystemd_CFLAGS@ +libsystemd_LIBS = @libsystemd_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +nozzle_CFLAGS = @nozzle_CFLAGS@ +nozzle_LIBS = @nozzle_LIBS@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +statgrab_CFLAGS = @statgrab_CFLAGS@ +statgrab_LIBS = @statgrab_LIBS@ +statgrabge090_CFLAGS = @statgrabge090_CFLAGS@ +statgrabge090_LIBS = @statgrabge090_LIBS@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# Functions to be used at link time (target.lo) +get_libname = $(shell echo $1 | $(SED) -e "s/\.lo//") +uc = $(shell echo $(call get_libname,$1) | tr a-z A-Z) +get_soname = $(subst .,:,$(if $($(call uc,$1)_SONAME),$($(call uc,$1)_SONAME),$(SONAME))) +get_major = $(firstword $(subst :, ,$(call get_soname,$1))) +MAINTAINERCLEANFILES = Makefile.in +EXTRA_DIST = libcfg.versions libcfg.verso \ + libcmap.versions libcmap.verso \ + libcpg.versions libcpg.verso \ + libquorum.versions libquorum.verso \ + libsam.versions libsam.verso \ + libvotequorum.versions libvotequorum.verso + +noinst_HEADERS = util.h +lib_LTLIBRARIES = libcpg.la libquorum.la libcfg.la \ + libvotequorum.la libcmap.la libsam.la + +libcpg_la_SOURCES = cpg.c +libcfg_la_SOURCES = cfg.c +libquorum_la_SOURCES = quorum.c +libvotequorum_la_SOURCES = votequorum.c +libcmap_la_SOURCES = cmap.c +libsam_la_SOURCES = sam.c +libsam_la_LIBADD = libquorum.la libcmap.la +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libcfg.la: $(libcfg_la_OBJECTS) $(libcfg_la_DEPENDENCIES) $(EXTRA_libcfg_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libcfg_la_OBJECTS) $(libcfg_la_LIBADD) $(LIBS) + +libcmap.la: $(libcmap_la_OBJECTS) $(libcmap_la_DEPENDENCIES) $(EXTRA_libcmap_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libcmap_la_OBJECTS) $(libcmap_la_LIBADD) $(LIBS) + +libcpg.la: $(libcpg_la_OBJECTS) $(libcpg_la_DEPENDENCIES) $(EXTRA_libcpg_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libcpg_la_OBJECTS) $(libcpg_la_LIBADD) $(LIBS) + +libquorum.la: $(libquorum_la_OBJECTS) $(libquorum_la_DEPENDENCIES) $(EXTRA_libquorum_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libquorum_la_OBJECTS) $(libquorum_la_LIBADD) $(LIBS) + +libsam.la: $(libsam_la_OBJECTS) $(libsam_la_DEPENDENCIES) $(EXTRA_libsam_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libsam_la_OBJECTS) $(libsam_la_LIBADD) $(LIBS) + +libvotequorum.la: $(libvotequorum_la_OBJECTS) $(libvotequorum_la_DEPENDENCIES) $(EXTRA_libvotequorum_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libvotequorum_la_OBJECTS) $(libvotequorum_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cfg.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpg.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/quorum.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sam.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/votequorum.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/cfg.c b/lib/cfg.c new file mode 100644 index 0000000..f0a3e9a --- /dev/null +++ b/lib/cfg.c @@ -0,0 +1,835 @@ +/* + * Copyright (c) 2002-2005 MontaVista Software, Inc. + * Copyright (c) 2006-2020 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Steven Dake (sdake@redhat.com) + * + * 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 MontaVista Software, 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 <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <pthread.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/un.h> +#include <sys/uio.h> + +#include <qb/qbipcc.h> + +#include <corosync/corotypes.h> +#include <corosync/corodefs.h> +#include <corosync/hdb.h> + +#include <corosync/cfg.h> +#include <corosync/ipc_cfg.h> + +#include "util.h" + +/* + * Data structure for instance data + */ +struct cfg_inst { + qb_ipcc_connection_t *c; + corosync_cfg_callbacks_t callbacks; + cs_name_t comp_name; + int comp_registered; + int finalize; +}; + +/* + * All instances in one database + */ +static void cfg_inst_free (void *inst); + +DECLARE_HDB_DATABASE (cfg_hdb, cfg_inst_free); + +/* + * Implementation + */ + +cs_error_t +corosync_cfg_initialize ( + corosync_cfg_handle_t *cfg_handle, + const corosync_cfg_callbacks_t *cfg_callbacks) +{ + struct cfg_inst *cfg_inst; + cs_error_t error = CS_OK; + + error = hdb_error_to_cs (hdb_handle_create (&cfg_hdb, sizeof (struct cfg_inst), cfg_handle)); + if (error != CS_OK) { + goto error_no_destroy; + } + + error = hdb_error_to_cs (hdb_handle_get (&cfg_hdb, *cfg_handle, (void *)&cfg_inst)); + if (error != CS_OK) { + goto error_destroy; + } + + cfg_inst->finalize = 0; + cfg_inst->c = qb_ipcc_connect ("cfg", IPC_REQUEST_SIZE); + if (cfg_inst->c == NULL) { + error = qb_to_cs_error(-errno); + goto error_put_destroy; + } + + if (cfg_callbacks) { + memcpy (&cfg_inst->callbacks, cfg_callbacks, sizeof (corosync_cfg_callbacks_t)); + } + + (void)hdb_handle_put (&cfg_hdb, *cfg_handle); + + return (CS_OK); + +error_put_destroy: + (void)hdb_handle_put (&cfg_hdb, *cfg_handle); +error_destroy: + (void)hdb_handle_destroy (&cfg_hdb, *cfg_handle); +error_no_destroy: + return (error); +} + +cs_error_t +corosync_cfg_fd_get ( + corosync_cfg_handle_t cfg_handle, + int32_t *selection_fd) +{ + struct cfg_inst *cfg_inst; + cs_error_t error; + + error = hdb_error_to_cs (hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + + error = qb_to_cs_error (qb_ipcc_fd_get (cfg_inst->c, selection_fd)); + + (void)hdb_handle_put (&cfg_hdb, cfg_handle); + return (error); +} + +cs_error_t +corosync_cfg_dispatch ( + corosync_cfg_handle_t cfg_handle, + cs_dispatch_flags_t dispatch_flags) +{ + int timeout = -1; + cs_error_t error; + int cont = 1; /* always continue do loop except when set to 0 */ + struct cfg_inst *cfg_inst; + struct res_lib_cfg_testshutdown *res_lib_cfg_testshutdown; + corosync_cfg_callbacks_t callbacks; + struct qb_ipc_response_header *dispatch_data; + char dispatch_buf[IPC_DISPATCH_SIZE]; + + error = hdb_error_to_cs (hdb_handle_get (&cfg_hdb, cfg_handle, + (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + + /* + * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and + * wait indefinately for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING + */ + if (dispatch_flags == CS_DISPATCH_ALL || dispatch_flags == CS_DISPATCH_ONE_NONBLOCKING) { + timeout = 0; + } + + dispatch_data = (struct qb_ipc_response_header *)dispatch_buf; + do { + error = qb_to_cs_error (qb_ipcc_event_recv ( + cfg_inst->c, + dispatch_buf, + IPC_DISPATCH_SIZE, + timeout)); + if (error == CS_ERR_BAD_HANDLE) { + error = CS_OK; + goto error_put; + } + if (error == CS_ERR_TRY_AGAIN) { + if (dispatch_flags == CS_DISPATCH_ONE_NONBLOCKING) { + /* + * Don't mask error + */ + goto error_put; + } + error = CS_OK; + if (dispatch_flags == CS_DISPATCH_ALL) { + break; /* exit do while cont is 1 loop */ + } else { + continue; /* next poll */ + } + } + if (error != CS_OK) { + goto error_put; + } + + /* + * Make copy of callbacks, message data, unlock instance, and call callback + * A risk of this dispatch method is that the callback routines may + * operate at the same time that cfgFinalize has been called in another thread. + */ + memcpy (&callbacks, &cfg_inst->callbacks, sizeof (corosync_cfg_callbacks_t)); + + /* + * Dispatch incoming response + */ + switch (dispatch_data->id) { + case MESSAGE_RES_CFG_TESTSHUTDOWN: + if (callbacks.corosync_cfg_shutdown_callback == NULL) { + break; + } + + res_lib_cfg_testshutdown = (struct res_lib_cfg_testshutdown *)dispatch_data; + callbacks.corosync_cfg_shutdown_callback(cfg_handle, res_lib_cfg_testshutdown->flags); + break; + default: + error = CS_ERR_LIBRARY; + goto error_nounlock; + break; + } + if (cfg_inst->finalize) { + /* + * If the finalize has been called then get out of the dispatch. + */ + error = CS_ERR_BAD_HANDLE; + goto error_put; + } + + /* + * Determine if more messages should be processed + */ + if (dispatch_flags == CS_DISPATCH_ONE || dispatch_flags == CS_DISPATCH_ONE_NONBLOCKING) { + cont = 0; + } + } while (cont); + +error_put: + (void)hdb_handle_put (&cfg_hdb, cfg_handle); +error_nounlock: + return (error); +} + +static void cfg_inst_free (void *inst) +{ + struct cfg_inst *cfg_inst = (struct cfg_inst *)inst; + qb_ipcc_disconnect(cfg_inst->c); +} + +cs_error_t +corosync_cfg_finalize ( + corosync_cfg_handle_t cfg_handle) +{ + struct cfg_inst *cfg_inst; + cs_error_t error; + + error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + + /* + * Another thread has already started finalizing + */ + if (cfg_inst->finalize) { + (void)hdb_handle_put (&cfg_hdb, cfg_handle); + return (CS_ERR_BAD_HANDLE); + } + + cfg_inst->finalize = 1; + + (void)hdb_handle_destroy (&cfg_hdb, cfg_handle); + + (void)hdb_handle_put (&cfg_hdb, cfg_handle); + + return (error); +} + +cs_error_t +corosync_cfg_ring_status_get ( + corosync_cfg_handle_t cfg_handle, + char ***interface_names, + char ***status, + unsigned int *interface_count) +{ + struct cfg_inst *cfg_inst; + struct req_lib_cfg_ringstatusget req_lib_cfg_ringstatusget; + struct res_lib_cfg_ringstatusget res_lib_cfg_ringstatusget; + unsigned int i, j; + cs_error_t error; + struct iovec iov; + + error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_cfg_ringstatusget.header.size = sizeof (struct req_lib_cfg_ringstatusget); + req_lib_cfg_ringstatusget.header.id = MESSAGE_REQ_CFG_RINGSTATUSGET; + + iov.iov_base = (void *)&req_lib_cfg_ringstatusget, + iov.iov_len = sizeof (struct req_lib_cfg_ringstatusget), + + error = qb_to_cs_error (qb_ipcc_sendv_recv(cfg_inst->c, + &iov, + 1, + &res_lib_cfg_ringstatusget, + sizeof (struct res_lib_cfg_ringstatusget), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto exit_handle_put; + } + + *interface_count = res_lib_cfg_ringstatusget.interface_count; + *interface_names = malloc (sizeof (char *) * *interface_count); + if (*interface_names == NULL) { + return (CS_ERR_NO_MEMORY); + } + memset (*interface_names, 0, sizeof (char *) * *interface_count); + + *status = malloc (sizeof (char *) * *interface_count); + if (*status == NULL) { + error = CS_ERR_NO_MEMORY; + goto error_free_interface_names_array; + } + memset (*status, 0, sizeof (char *) * *interface_count); + + for (i = 0; i < res_lib_cfg_ringstatusget.interface_count; i++) { + (*(interface_names))[i] = strdup (res_lib_cfg_ringstatusget.interface_name[i]); + if ((*(interface_names))[i] == NULL) { + error = CS_ERR_NO_MEMORY; + goto error_free_interface_names; + } + } + + for (i = 0; i < res_lib_cfg_ringstatusget.interface_count; i++) { + (*(status))[i] = strdup (res_lib_cfg_ringstatusget.interface_status[i]); + if ((*(status))[i] == NULL) { + error = CS_ERR_NO_MEMORY; + goto error_free_status; + } + } + goto exit_handle_put; + +error_free_status: + for (j = 0; j < i; j++) { + free ((*(status))[j]); + } + i = *interface_count; + +error_free_interface_names: + for (j = 0; j < i; j++) { + free ((*(interface_names))[j]); + } + + free (*status); + +error_free_interface_names_array: + free (*interface_names); + +exit_handle_put: + (void)hdb_handle_put (&cfg_hdb, cfg_handle); + + return (error); +} + +cs_error_t +corosync_cfg_node_status_get ( + corosync_cfg_handle_t cfg_handle, + unsigned int nodeid, + corosync_cfg_node_status_version_t version, + void *node_status) +{ + struct cfg_inst *cfg_inst; + struct req_lib_cfg_nodestatusget req_lib_cfg_nodestatusget; + cs_error_t error; + struct iovec iov; + size_t cfg_node_status_size; + void *res_lib_cfg_nodestatuget_ptr; + struct res_lib_cfg_nodestatusget_v1 res_lib_cfg_nodestatusget_v1; + struct res_lib_cfg_nodestatusget_version *res_lib_cfg_nodestatusget_version; + + if (!node_status) { + return (CS_ERR_INVALID_PARAM); + } + + switch (version) { + case CFG_NODE_STATUS_V1: + cfg_node_status_size = sizeof(struct res_lib_cfg_nodestatusget_v1); + res_lib_cfg_nodestatuget_ptr = &res_lib_cfg_nodestatusget_v1; + + break; + default: + return (CS_ERR_INVALID_PARAM); + break; + } + + error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_cfg_nodestatusget.header.size = sizeof (struct req_lib_cfg_nodestatusget); + req_lib_cfg_nodestatusget.header.id = MESSAGE_REQ_CFG_NODESTATUSGET; + req_lib_cfg_nodestatusget.nodeid = nodeid; + req_lib_cfg_nodestatusget.version = version; + + iov.iov_base = (void *)&req_lib_cfg_nodestatusget, + iov.iov_len = sizeof (struct req_lib_cfg_nodestatusget), + + error = qb_to_cs_error (qb_ipcc_sendv_recv(cfg_inst->c, + &iov, + 1, + res_lib_cfg_nodestatuget_ptr, + cfg_node_status_size, CS_IPC_TIMEOUT_MS)); + if (error != CS_OK) { + goto error_put; + } + + res_lib_cfg_nodestatusget_version = res_lib_cfg_nodestatuget_ptr; + error = res_lib_cfg_nodestatusget_version->header.error; + if (error != CS_OK) { + goto error_put; + } + + if (res_lib_cfg_nodestatusget_version->version != version) { + /* + * corosync sent us something we don't really understand. + */ + error = CS_ERR_NOT_SUPPORTED; + goto error_put; + } + + switch (version) { + case CFG_NODE_STATUS_V1: + memcpy(node_status, &res_lib_cfg_nodestatusget_v1.node_status, + sizeof(struct corosync_cfg_node_status_v1)); + break; + } + +error_put: + (void)hdb_handle_put (&cfg_hdb, cfg_handle); + + return (error); +} + + +cs_error_t +corosync_cfg_trackstart ( + corosync_cfg_handle_t cfg_handle, + uint8_t track_flags) +{ + struct cfg_inst *cfg_inst; + struct req_lib_cfg_trackstart req_lib_cfg_trackstart; + struct res_lib_cfg_trackstart res_lib_cfg_trackstart; + cs_error_t error; + struct iovec iov; + + req_lib_cfg_trackstart.header.size = sizeof (struct req_lib_cfg_trackstart); + req_lib_cfg_trackstart.header.id = MESSAGE_REQ_CFG_TRACKSTART; + req_lib_cfg_trackstart.track_flags = track_flags; + + error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, + (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + + iov.iov_base = (void *)&req_lib_cfg_trackstart, + iov.iov_len = sizeof (struct req_lib_cfg_trackstart), + + error = qb_to_cs_error (qb_ipcc_sendv_recv (cfg_inst->c, + &iov, + 1, + &res_lib_cfg_trackstart, + sizeof (struct res_lib_cfg_trackstart), CS_IPC_TIMEOUT_MS)); + + (void)hdb_handle_put (&cfg_hdb, cfg_handle); + + return (error == CS_OK ? res_lib_cfg_trackstart.header.error : error); +} + +cs_error_t +corosync_cfg_trackstop ( + corosync_cfg_handle_t cfg_handle) +{ + struct cfg_inst *cfg_inst; + struct req_lib_cfg_trackstop req_lib_cfg_trackstop; + struct res_lib_cfg_trackstop res_lib_cfg_trackstop; + cs_error_t error; + struct iovec iov; + + error = hdb_error_to_cs (hdb_handle_get (&cfg_hdb, cfg_handle, + (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_cfg_trackstop.header.size = sizeof (struct req_lib_cfg_trackstop); + req_lib_cfg_trackstop.header.id = MESSAGE_REQ_CFG_TRACKSTOP; + + iov.iov_base = (void *)&req_lib_cfg_trackstop, + iov.iov_len = sizeof (struct req_lib_cfg_trackstop), + + error = qb_to_cs_error (qb_ipcc_sendv_recv (cfg_inst->c, + &iov, + 1, + &res_lib_cfg_trackstop, + sizeof (struct res_lib_cfg_trackstop), CS_IPC_TIMEOUT_MS)); + + (void)hdb_handle_put (&cfg_hdb, cfg_handle); + + return (error == CS_OK ? res_lib_cfg_trackstop.header.error : error); +} + +cs_error_t +corosync_cfg_kill_node ( + corosync_cfg_handle_t cfg_handle, + unsigned int nodeid, + const char *reason) +{ + struct cfg_inst *cfg_inst; + struct req_lib_cfg_killnode req_lib_cfg_killnode; + struct res_lib_cfg_killnode res_lib_cfg_killnode; + cs_error_t error; + struct iovec iov; + + if (strlen(reason) >= CS_MAX_NAME_LENGTH) + return CS_ERR_NAME_TOO_LONG; + + error = hdb_error_to_cs (hdb_handle_get (&cfg_hdb, cfg_handle, + (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_cfg_killnode.header.id = MESSAGE_REQ_CFG_KILLNODE; + req_lib_cfg_killnode.header.size = sizeof (struct req_lib_cfg_killnode); + req_lib_cfg_killnode.nodeid = nodeid; + strcpy((char *)req_lib_cfg_killnode.reason.value, reason); + req_lib_cfg_killnode.reason.length = strlen(reason)+1; + + iov.iov_base = (void *)&req_lib_cfg_killnode; + iov.iov_len = sizeof (struct req_lib_cfg_killnode); + + error = qb_to_cs_error (qb_ipcc_sendv_recv (cfg_inst->c, + &iov, + 1, + &res_lib_cfg_killnode, + sizeof (struct res_lib_cfg_killnode), CS_IPC_TIMEOUT_MS)); + + error = res_lib_cfg_killnode.header.error; + + (void)hdb_handle_put (&cfg_hdb, cfg_handle); + + return (error == CS_OK ? res_lib_cfg_killnode.header.error : error); +} + +cs_error_t +corosync_cfg_try_shutdown ( + corosync_cfg_handle_t cfg_handle, + corosync_cfg_shutdown_flags_t flags) +{ + struct cfg_inst *cfg_inst; + struct req_lib_cfg_tryshutdown req_lib_cfg_tryshutdown; + struct res_lib_cfg_tryshutdown res_lib_cfg_tryshutdown; + cs_error_t error; + struct iovec iov; + + error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, + (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_cfg_tryshutdown.header.id = MESSAGE_REQ_CFG_TRYSHUTDOWN; + req_lib_cfg_tryshutdown.header.size = sizeof (struct req_lib_cfg_tryshutdown); + req_lib_cfg_tryshutdown.flags = flags; + + iov.iov_base = (void *)&req_lib_cfg_tryshutdown; + iov.iov_len = sizeof (req_lib_cfg_tryshutdown); + + error = qb_to_cs_error (qb_ipcc_sendv_recv (cfg_inst->c, + &iov, + 1, + &res_lib_cfg_tryshutdown, + sizeof (struct res_lib_cfg_tryshutdown), CS_IPC_TIMEOUT_MS)); + + (void)hdb_handle_put (&cfg_hdb, cfg_handle); + + return (error == CS_OK ? res_lib_cfg_tryshutdown.header.error : error); +} + +cs_error_t +corosync_cfg_replyto_shutdown ( + corosync_cfg_handle_t cfg_handle, + corosync_cfg_shutdown_reply_flags_t response) +{ + struct cfg_inst *cfg_inst; + struct req_lib_cfg_replytoshutdown req_lib_cfg_replytoshutdown; + struct res_lib_cfg_replytoshutdown res_lib_cfg_replytoshutdown; + struct iovec iov; + cs_error_t error; + + error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, + (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_cfg_replytoshutdown.header.id = MESSAGE_REQ_CFG_REPLYTOSHUTDOWN; + req_lib_cfg_replytoshutdown.header.size = sizeof (struct req_lib_cfg_replytoshutdown); + req_lib_cfg_replytoshutdown.response = response; + + iov.iov_base = (void *)&req_lib_cfg_replytoshutdown; + iov.iov_len = sizeof (struct req_lib_cfg_replytoshutdown); + + error = qb_to_cs_error (qb_ipcc_sendv_recv (cfg_inst->c, + &iov, + 1, + &res_lib_cfg_replytoshutdown, + sizeof (struct res_lib_cfg_replytoshutdown), CS_IPC_TIMEOUT_MS)); + + return (error); +} + +cs_error_t corosync_cfg_get_node_addrs ( + corosync_cfg_handle_t cfg_handle, + unsigned int nodeid, + size_t max_addrs, + int *num_addrs, + corosync_cfg_node_address_t *addrs) +{ + cs_error_t error; + struct req_lib_cfg_get_node_addrs req_lib_cfg_get_node_addrs; + struct res_lib_cfg_get_node_addrs *res_lib_cfg_get_node_addrs; + struct cfg_inst *cfg_inst; + int addrlen = 0; + int i; + struct iovec iov; + const char *addr_buf; + char response_buf[IPC_RESPONSE_SIZE]; + char zeroes[sizeof(struct sockaddr_storage)]; + + error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, + (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + memset(zeroes, 0, sizeof(zeroes)); + + req_lib_cfg_get_node_addrs.header.size = sizeof (req_lib_cfg_get_node_addrs); + req_lib_cfg_get_node_addrs.header.id = MESSAGE_REQ_CFG_GET_NODE_ADDRS; + req_lib_cfg_get_node_addrs.nodeid = nodeid; + + iov.iov_base = (char *)&req_lib_cfg_get_node_addrs; + iov.iov_len = sizeof (req_lib_cfg_get_node_addrs); + + error = qb_to_cs_error (qb_ipcc_sendv_recv ( + cfg_inst->c, + &iov, 1, + response_buf, IPC_RESPONSE_SIZE, CS_IPC_TIMEOUT_MS)); + res_lib_cfg_get_node_addrs = (struct res_lib_cfg_get_node_addrs *)response_buf; + + if (error != CS_OK) { + goto error_put; + } + + if (res_lib_cfg_get_node_addrs->family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + if (res_lib_cfg_get_node_addrs->family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + + for (i = 0, addr_buf = (char *)res_lib_cfg_get_node_addrs->addrs; + i < max_addrs && i<res_lib_cfg_get_node_addrs->num_addrs; + i++, addr_buf += TOTEMIP_ADDRLEN) { + struct sockaddr_in *in; + struct sockaddr_in6 *in6; + + addrs[i].address_length = addrlen; + + if (res_lib_cfg_get_node_addrs->family == AF_INET) { + in = (struct sockaddr_in *)addrs[i].address; + if (memcmp(addr_buf, zeroes, addrlen) == 0) { + in->sin_family = 0; + } else { + in->sin_family = AF_INET; + } + memcpy(&in->sin_addr, addr_buf, sizeof(struct in_addr)); + } + if (res_lib_cfg_get_node_addrs->family == AF_INET6) { + in6 = (struct sockaddr_in6 *)addrs[i].address; + + if (memcmp(addr_buf, zeroes, addrlen) == 0) { + in6->sin6_family = 0; + } else { + in6->sin6_family = AF_INET6; + } + memcpy(&in6->sin6_addr, addr_buf, sizeof(struct in6_addr)); + } + + /* Mark it as unused */ + + } + *num_addrs = res_lib_cfg_get_node_addrs->num_addrs; + errno = error = res_lib_cfg_get_node_addrs->header.error; + +error_put: + hdb_handle_put (&cfg_hdb, cfg_handle); + + return (error); +} + +cs_error_t corosync_cfg_local_get ( + corosync_cfg_handle_t handle, + unsigned int *local_nodeid) +{ + cs_error_t error; + struct cfg_inst *cfg_inst; + struct iovec iov; + struct req_lib_cfg_local_get req_lib_cfg_local_get; + struct res_lib_cfg_local_get res_lib_cfg_local_get; + + error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, handle, (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_cfg_local_get.header.size = sizeof (struct qb_ipc_request_header); + req_lib_cfg_local_get.header.id = MESSAGE_REQ_CFG_LOCAL_GET; + + iov.iov_base = (void *)&req_lib_cfg_local_get; + iov.iov_len = sizeof (struct req_lib_cfg_local_get); + + error = qb_to_cs_error (qb_ipcc_sendv_recv ( + cfg_inst->c, + &iov, + 1, + &res_lib_cfg_local_get, + sizeof (struct res_lib_cfg_local_get), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_cfg_local_get.header.error; + + *local_nodeid = res_lib_cfg_local_get.local_nodeid; + +error_exit: + (void)hdb_handle_put (&cfg_hdb, handle); + + return (error); +} + +cs_error_t corosync_cfg_reload_config ( + corosync_cfg_handle_t handle) +{ + cs_error_t error; + struct cfg_inst *cfg_inst; + struct iovec iov; + struct req_lib_cfg_reload_config req_lib_cfg_reload_config; + struct res_lib_cfg_reload_config res_lib_cfg_reload_config; + + error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, handle, (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_cfg_reload_config.header.size = sizeof (struct qb_ipc_request_header); + req_lib_cfg_reload_config.header.id = MESSAGE_REQ_CFG_RELOAD_CONFIG; + + iov.iov_base = (void *)&req_lib_cfg_reload_config; + iov.iov_len = sizeof (struct req_lib_cfg_reload_config); + + error = qb_to_cs_error (qb_ipcc_sendv_recv ( + cfg_inst->c, + &iov, + 1, + &res_lib_cfg_reload_config, + sizeof (struct res_lib_cfg_reload_config), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_cfg_reload_config.header.error; + +error_exit: + (void)hdb_handle_put (&cfg_hdb, handle); + + return (error); +} + +cs_error_t corosync_cfg_reopen_log_files ( + corosync_cfg_handle_t handle) +{ + cs_error_t error; + struct cfg_inst *cfg_inst; + struct iovec iov; + struct req_lib_cfg_reopen_log_files req_lib_cfg_reopen_log_files; + struct res_lib_cfg_reopen_log_files res_lib_cfg_reopen_log_files; + + error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, handle, (void *)&cfg_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_cfg_reopen_log_files.header.size = sizeof (struct qb_ipc_request_header); + req_lib_cfg_reopen_log_files.header.id = MESSAGE_REQ_CFG_REOPEN_LOG_FILES; + + iov.iov_base = (void *)&req_lib_cfg_reopen_log_files; + iov.iov_len = sizeof (struct req_lib_cfg_reopen_log_files); + + error = qb_to_cs_error (qb_ipcc_sendv_recv ( + cfg_inst->c, + &iov, + 1, + &res_lib_cfg_reopen_log_files, + sizeof (struct res_lib_cfg_reopen_log_files), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_cfg_reopen_log_files.header.error; + +error_exit: + (void)hdb_handle_put (&cfg_hdb, handle); + + return (error); +} diff --git a/lib/cmap.c b/lib/cmap.c new file mode 100644 index 0000000..ed9774a --- /dev/null +++ b/lib/cmap.c @@ -0,0 +1,1119 @@ +/* + * Copyright (c) 2011-2017 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Jan Friesse (jfriesse@redhat.com) + * + * 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 <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/uio.h> +#include <errno.h> + +#include <corosync/corotypes.h> +#include <corosync/corodefs.h> +#include <corosync/hdb.h> +#include <qb/qbipcc.h> + +#include <corosync/cmap.h> +#include <corosync/ipc_cmap.h> + +#include "util.h" +#include <stdio.h> + +struct cmap_inst { + int finalize; + qb_ipcc_connection_t *c; + const void *context; +}; + +struct cmap_track_inst { + void *user_data; + cmap_notify_fn_t notify_fn; + qb_ipcc_connection_t *c; + cmap_track_handle_t track_handle; +}; + +static void cmap_inst_free (void *inst); + +DECLARE_HDB_DATABASE(cmap_handle_t_db, cmap_inst_free); +DECLARE_HDB_DATABASE(cmap_track_handle_t_db,NULL); + +/* + * Function prototypes + */ +static cs_error_t cmap_get_int( + cmap_handle_t handle, + const char *key_name, + void *value, + size_t value_size, + cmap_value_types_t type); + +static cs_error_t cmap_adjust_int(cmap_handle_t handle, const char *key_name, int32_t step); + +/* + * Function implementations + */ +cs_error_t cmap_initialize (cmap_handle_t *handle) +{ + cs_error_t error; + struct cmap_inst *cmap_inst; + + error = hdb_error_to_cs(hdb_handle_create(&cmap_handle_t_db, sizeof(*cmap_inst), handle)); + if (error != CS_OK) { + goto error_no_destroy; + } + + error = hdb_error_to_cs(hdb_handle_get(&cmap_handle_t_db, *handle, (void *)&cmap_inst)); + if (error != CS_OK) { + goto error_destroy; + } + + error = CS_OK; + cmap_inst->finalize = 0; + cmap_inst->c = qb_ipcc_connect("cmap", IPC_REQUEST_SIZE); + if (cmap_inst->c == NULL) { + error = qb_to_cs_error(-errno); + goto error_put_destroy; + } + + (void)hdb_handle_put(&cmap_handle_t_db, *handle); + + return (CS_OK); + +error_put_destroy: + (void)hdb_handle_put(&cmap_handle_t_db, *handle); +error_destroy: + (void)hdb_handle_destroy(&cmap_handle_t_db, *handle); +error_no_destroy: + return (error); +} + +cs_error_t cmap_initialize_map (cmap_handle_t *handle, + cmap_map_t map) +{ + cs_error_t error; + struct iovec iov[1]; + struct cmap_inst *cmap_inst; + struct req_lib_cmap_set_current_map req_lib_cmap_set_current_map; + struct qb_ipc_response_header res_lib_cmap_set_current_map; + + error = cmap_initialize(handle); + + if (error == CS_OK) { + error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, *handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + memset(&req_lib_cmap_set_current_map, 0, sizeof(req_lib_cmap_set_current_map)); + req_lib_cmap_set_current_map.header.size = sizeof(req_lib_cmap_set_current_map); + req_lib_cmap_set_current_map.header.id = MESSAGE_REQ_CMAP_SET_CURRENT_MAP; + req_lib_cmap_set_current_map.map = map; + + iov[0].iov_base = (char *)&req_lib_cmap_set_current_map; + iov[0].iov_len = sizeof(req_lib_cmap_set_current_map); + + error = qb_to_cs_error(qb_ipcc_sendv_recv( + cmap_inst->c, + iov, + 1, + &res_lib_cmap_set_current_map, + sizeof (res_lib_cmap_set_current_map), CS_IPC_TIMEOUT_MS)); + + if (error == CS_OK) { + error = res_lib_cmap_set_current_map.error; + } + + (void)hdb_handle_put (&cmap_handle_t_db, *handle); + + return (error); + } + return (error); +} + +static void cmap_inst_free (void *inst) +{ + struct cmap_inst *cmap_inst = (struct cmap_inst *)inst; + qb_ipcc_disconnect(cmap_inst->c); +} + +cs_error_t cmap_finalize(cmap_handle_t handle) +{ + struct cmap_inst *cmap_inst; + cs_error_t error; + hdb_handle_t track_inst_handle = 0; + struct cmap_track_inst *cmap_track_inst; + + error = hdb_error_to_cs(hdb_handle_get(&cmap_handle_t_db, handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + if (cmap_inst->finalize) { + (void)hdb_handle_put (&cmap_handle_t_db, handle); + return (CS_ERR_BAD_HANDLE); + } + cmap_inst->finalize = 1; + + /* + * Destroy all track instances for given connection + */ + hdb_iterator_reset(&cmap_track_handle_t_db); + while (hdb_iterator_next(&cmap_track_handle_t_db, + (void*)&cmap_track_inst, &track_inst_handle) == 0) { + + if (cmap_track_inst->c == cmap_inst->c) { + (void)hdb_handle_destroy(&cmap_track_handle_t_db, track_inst_handle); + } + + (void)hdb_handle_put (&cmap_track_handle_t_db, track_inst_handle); + } + + (void)hdb_handle_destroy(&cmap_handle_t_db, handle); + + (void)hdb_handle_put(&cmap_handle_t_db, handle); + + return (CS_OK); +} + +cs_error_t cmap_fd_get(cmap_handle_t handle, int *fd) +{ + cs_error_t error; + struct cmap_inst *cmap_inst; + + error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + error = qb_to_cs_error (qb_ipcc_fd_get (cmap_inst->c, fd)); + + (void)hdb_handle_put (&cmap_handle_t_db, handle); + + return (error); +} + +cs_error_t cmap_dispatch ( + cmap_handle_t handle, + cs_dispatch_flags_t dispatch_types) +{ + int timeout = -1; + cs_error_t error; + int cont = 1; /* always continue do loop except when set to 0 */ + struct cmap_inst *cmap_inst; + struct qb_ipc_response_header *dispatch_data; + char dispatch_buf[IPC_DISPATCH_SIZE]; + struct res_lib_cmap_notify_callback *res_lib_cmap_notify_callback; + struct cmap_track_inst *cmap_track_inst; + struct cmap_notify_value old_val; + struct cmap_notify_value new_val; + + error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + /* + * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and + * wait indefinately for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING + */ + if (dispatch_types == CS_DISPATCH_ALL || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { + timeout = 0; + } + + dispatch_data = (struct qb_ipc_response_header *)dispatch_buf; + do { + error = qb_to_cs_error(qb_ipcc_event_recv ( + cmap_inst->c, + dispatch_buf, + IPC_DISPATCH_SIZE, + timeout)); + + if (error == CS_ERR_BAD_HANDLE) { + error = CS_OK; + goto error_put; + } + if (error == CS_ERR_TRY_AGAIN) { + if (dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { + /* + * Don't mask error + */ + goto error_put; + } + error = CS_OK; + if (dispatch_types == CS_DISPATCH_ALL) { + break; /* exit do while cont is 1 loop */ + } else { + continue; /* next poll */ + } + } + + if (error != CS_OK) { + goto error_put; + } + + /* + * Dispatch incoming message + */ + switch (dispatch_data->id) { + case MESSAGE_RES_CMAP_NOTIFY_CALLBACK: + res_lib_cmap_notify_callback = (struct res_lib_cmap_notify_callback *)dispatch_data; + + error = hdb_error_to_cs(hdb_handle_get(&cmap_track_handle_t_db, + res_lib_cmap_notify_callback->track_inst_handle, + (void *)&cmap_track_inst)); + if (error == CS_ERR_BAD_HANDLE) { + /* + * User deleted tracker -> ignore error + */ + break; + } + if (error != CS_OK) { + goto error_put; + } + + new_val.type = res_lib_cmap_notify_callback->new_value_type; + old_val.type = res_lib_cmap_notify_callback->old_value_type; + new_val.len = res_lib_cmap_notify_callback->new_value_len; + old_val.len = res_lib_cmap_notify_callback->old_value_len; + new_val.data = res_lib_cmap_notify_callback->new_value; + old_val.data = (((const char *)res_lib_cmap_notify_callback->new_value) + new_val.len); + + cmap_track_inst->notify_fn(handle, + cmap_track_inst->track_handle, + res_lib_cmap_notify_callback->event, + (char *)res_lib_cmap_notify_callback->key_name.value, + new_val, + old_val, + cmap_track_inst->user_data); + + (void)hdb_handle_put(&cmap_track_handle_t_db, res_lib_cmap_notify_callback->track_inst_handle); + break; + default: + error = CS_ERR_LIBRARY; + goto error_put; + break; + } + if (cmap_inst->finalize) { + /* + * If the finalize has been called then get out of the dispatch. + */ + error = CS_ERR_BAD_HANDLE; + goto error_put; + } + + /* + * Determine if more messages should be processed + */ + if (dispatch_types == CS_DISPATCH_ONE || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { + cont = 0; + } + } while (cont); + +error_put: + (void)hdb_handle_put (&cmap_handle_t_db, handle); + + return (error); +} + +cs_error_t cmap_context_get ( + cmap_handle_t handle, + const void **context) +{ + cs_error_t error; + struct cmap_inst *cmap_inst; + + error = hdb_error_to_cs(hdb_handle_get(&cmap_handle_t_db, handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + *context = cmap_inst->context; + + (void)hdb_handle_put (&cmap_handle_t_db, handle); + + return (CS_OK); +} + +cs_error_t cmap_context_set ( + cmap_handle_t handle, + const void *context) +{ + cs_error_t error; + struct cmap_inst *cmap_inst; + + error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + cmap_inst->context = context; + + (void)hdb_handle_put (&cmap_handle_t_db, handle); + + return (CS_OK); +} + +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) +{ + cs_error_t error; + struct iovec iov[2]; + struct cmap_inst *cmap_inst; + struct req_lib_cmap_set req_lib_cmap_set; + struct res_lib_cmap_set res_lib_cmap_set; + + if (key_name == NULL || value == NULL) { + return (CS_ERR_INVALID_PARAM); + } + + if (strlen(key_name) >= CS_MAX_NAME_LENGTH) { + return (CS_ERR_NAME_TOO_LONG); + } + + error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + memset(&req_lib_cmap_set, 0, sizeof(req_lib_cmap_set)); + req_lib_cmap_set.header.size = sizeof(req_lib_cmap_set) + value_len; + req_lib_cmap_set.header.id = MESSAGE_REQ_CMAP_SET; + + memcpy(req_lib_cmap_set.key_name.value, key_name, strlen(key_name)); + req_lib_cmap_set.key_name.length = strlen(key_name); + + req_lib_cmap_set.value_len = value_len; + req_lib_cmap_set.type = type; + + iov[0].iov_base = (char *)&req_lib_cmap_set; + iov[0].iov_len = sizeof(req_lib_cmap_set); + iov[1].iov_base = (void *)value; + iov[1].iov_len = value_len; + + error = qb_to_cs_error(qb_ipcc_sendv_recv( + cmap_inst->c, + iov, + 2, + &res_lib_cmap_set, + sizeof (struct res_lib_cmap_set), CS_IPC_TIMEOUT_MS)); + + if (error == CS_OK) { + error = res_lib_cmap_set.header.error; + } + + (void)hdb_handle_put (&cmap_handle_t_db, handle); + + return (error); +} + +cs_error_t cmap_set_int8(cmap_handle_t handle, const char *key_name, int8_t value) +{ + return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_INT8)); +} + +cs_error_t cmap_set_uint8(cmap_handle_t handle, const char *key_name, uint8_t value) +{ + return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_UINT8)); +} + +cs_error_t cmap_set_int16(cmap_handle_t handle, const char *key_name, int16_t value) +{ + return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_INT16)); +} + +cs_error_t cmap_set_uint16(cmap_handle_t handle, const char *key_name, uint16_t value) +{ + return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_UINT16)); +} + +cs_error_t cmap_set_int32(cmap_handle_t handle, const char *key_name, int32_t value) +{ + return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_INT32)); +} + +cs_error_t cmap_set_uint32(cmap_handle_t handle, const char *key_name, uint32_t value) +{ + return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_UINT32)); +} + +cs_error_t cmap_set_int64(cmap_handle_t handle, const char *key_name, int64_t value) +{ + return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_INT64)); +} + +cs_error_t cmap_set_uint64(cmap_handle_t handle, const char *key_name, uint64_t value) +{ + return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_UINT64)); +} + +cs_error_t cmap_set_float(cmap_handle_t handle, const char *key_name, float value) +{ + return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_FLOAT)); +} + +cs_error_t cmap_set_double(cmap_handle_t handle, const char *key_name, double value) +{ + return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_DOUBLE)); +} + +cs_error_t cmap_set_string(cmap_handle_t handle, const char *key_name, const char *value) +{ + + if (value == NULL) { + return (CS_ERR_INVALID_PARAM); + } + + return (cmap_set(handle, key_name, value, strlen(value), CMAP_VALUETYPE_STRING)); +} + +cs_error_t cmap_delete(cmap_handle_t handle, const char *key_name) +{ + cs_error_t error; + struct iovec iov; + struct cmap_inst *cmap_inst; + struct req_lib_cmap_delete req_lib_cmap_delete; + struct res_lib_cmap_delete res_lib_cmap_delete; + + if (key_name == NULL) { + return (CS_ERR_INVALID_PARAM); + } + if (strlen(key_name) >= CS_MAX_NAME_LENGTH) { + return (CS_ERR_NAME_TOO_LONG); + } + + error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + memset(&req_lib_cmap_delete, 0, sizeof(req_lib_cmap_delete)); + req_lib_cmap_delete.header.size = sizeof(req_lib_cmap_delete); + req_lib_cmap_delete.header.id = MESSAGE_REQ_CMAP_DELETE; + + memcpy(req_lib_cmap_delete.key_name.value, key_name, strlen(key_name)); + req_lib_cmap_delete.key_name.length = strlen(key_name); + + iov.iov_base = (char *)&req_lib_cmap_delete; + iov.iov_len = sizeof(req_lib_cmap_delete); + + error = qb_to_cs_error(qb_ipcc_sendv_recv( + cmap_inst->c, + &iov, + 1, + &res_lib_cmap_delete, + sizeof (struct res_lib_cmap_delete), CS_IPC_TIMEOUT_MS)); + + if (error == CS_OK) { + error = res_lib_cmap_delete.header.error; + } + + (void)hdb_handle_put (&cmap_handle_t_db, handle); + + return (error); +} + +cs_error_t cmap_get( + cmap_handle_t handle, + const char *key_name, + void *value, + size_t *value_len, + cmap_value_types_t *type) +{ + cs_error_t error; + struct cmap_inst *cmap_inst; + struct iovec iov; + struct req_lib_cmap_get req_lib_cmap_get; + struct res_lib_cmap_get *res_lib_cmap_get; + size_t res_size; + + if (key_name == NULL) { + return (CS_ERR_INVALID_PARAM); + } + if (strlen(key_name) >= CS_MAX_NAME_LENGTH) { + return (CS_ERR_NAME_TOO_LONG); + } + + if (value != NULL && value_len == NULL) { + return (CS_ERR_INVALID_PARAM); + } + + error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + memset(&req_lib_cmap_get, 0, sizeof(req_lib_cmap_get)); + req_lib_cmap_get.header.size = sizeof(req_lib_cmap_get); + req_lib_cmap_get.header.id = MESSAGE_REQ_CMAP_GET; + + memcpy(req_lib_cmap_get.key_name.value, key_name, strlen(key_name)); + req_lib_cmap_get.key_name.length = strlen(key_name); + + if (value != NULL && value_len != NULL) { + req_lib_cmap_get.value_len = *value_len; + } else { + req_lib_cmap_get.value_len = 0; + } + + iov.iov_base = (char *)&req_lib_cmap_get; + iov.iov_len = sizeof(req_lib_cmap_get); + + res_size = sizeof(struct res_lib_cmap_get) + req_lib_cmap_get.value_len; + + res_lib_cmap_get = malloc(res_size); + if (res_lib_cmap_get == NULL) { + return (CS_ERR_NO_MEMORY); + } + + error = qb_to_cs_error(qb_ipcc_sendv_recv( + cmap_inst->c, + &iov, + 1, + res_lib_cmap_get, + res_size, CS_IPC_TIMEOUT_MS)); + + if (error == CS_OK) { + error = res_lib_cmap_get->header.error; + } + + if (error == CS_OK) { + if (type != NULL) { + *type = res_lib_cmap_get->type; + } + + if (value_len != NULL) { + *value_len = res_lib_cmap_get->value_len; + } + + if (value != NULL && value_len != NULL) { + memcpy(value, res_lib_cmap_get->value, res_lib_cmap_get->value_len); + } + } + + free(res_lib_cmap_get); + + (void)hdb_handle_put (&cmap_handle_t_db, handle); + + return (error); +} + +static cs_error_t cmap_get_int( + cmap_handle_t handle, + const char *key_name, + void *value, + size_t value_size, + cmap_value_types_t type) +{ + char key_value[16]; + size_t key_size; + cs_error_t err; + + cmap_value_types_t key_type; + + key_size = sizeof(key_value); + memset(key_value, 0, key_size); + + err = cmap_get(handle, key_name, key_value, &key_size, &key_type); + if (err != CS_OK) + return (err); + + if (key_type != type) { + return (CS_ERR_INVALID_PARAM); + } + + memcpy(value, key_value, value_size); + + return (CS_OK); +} + +cs_error_t cmap_get_int8(cmap_handle_t handle, const char *key_name, int8_t *i8) +{ + + return (cmap_get_int(handle, key_name, i8, sizeof(*i8), CMAP_VALUETYPE_INT8)); +} + +cs_error_t cmap_get_uint8(cmap_handle_t handle, const char *key_name, uint8_t *u8) +{ + + return (cmap_get_int(handle, key_name, u8, sizeof(*u8), CMAP_VALUETYPE_UINT8)); +} + +cs_error_t cmap_get_int16(cmap_handle_t handle, const char *key_name, int16_t *i16) +{ + + return (cmap_get_int(handle, key_name, i16, sizeof(*i16), CMAP_VALUETYPE_INT16)); +} + +cs_error_t cmap_get_uint16(cmap_handle_t handle, const char *key_name, uint16_t *u16) +{ + + return (cmap_get_int(handle, key_name, u16, sizeof(*u16), CMAP_VALUETYPE_UINT16)); +} + +cs_error_t cmap_get_int32(cmap_handle_t handle, const char *key_name, int32_t *i32) +{ + + return (cmap_get_int(handle, key_name, i32, sizeof(*i32), CMAP_VALUETYPE_INT32)); +} + +cs_error_t cmap_get_uint32(cmap_handle_t handle, const char *key_name, uint32_t *u32) +{ + + return (cmap_get_int(handle, key_name, u32, sizeof(*u32), CMAP_VALUETYPE_UINT32)); +} + +cs_error_t cmap_get_int64(cmap_handle_t handle, const char *key_name, int64_t *i64) +{ + + return (cmap_get_int(handle, key_name, i64, sizeof(*i64), CMAP_VALUETYPE_INT64)); +} + +cs_error_t cmap_get_uint64(cmap_handle_t handle, const char *key_name, uint64_t *u64) +{ + + return (cmap_get_int(handle, key_name, u64, sizeof(*u64), CMAP_VALUETYPE_UINT64)); +} + +cs_error_t cmap_get_float(cmap_handle_t handle, const char *key_name, float *flt) +{ + + return (cmap_get_int(handle, key_name, flt, sizeof(*flt), CMAP_VALUETYPE_FLOAT)); +} + +cs_error_t cmap_get_double(cmap_handle_t handle, const char *key_name, double *dbl) +{ + + return (cmap_get_int(handle, key_name, dbl, sizeof(*dbl), CMAP_VALUETYPE_DOUBLE)); +} + +cs_error_t cmap_get_string(cmap_handle_t handle, const char *key_name, char **str) +{ + cs_error_t res; + size_t str_len; + cmap_value_types_t type; + + res = cmap_get(handle, key_name, NULL, &str_len, &type); + + if (res != CS_OK || type != CMAP_VALUETYPE_STRING) { + if (res == CS_OK) { + res = CS_ERR_INVALID_PARAM; + } + + goto return_error; + } + + *str = malloc(str_len); + if (*str == NULL) { + res = CS_ERR_NO_MEMORY; + + goto return_error; + } + + res = cmap_get(handle, key_name, *str, &str_len, &type); + if (res != CS_OK) { + free(*str); + + goto return_error; + } + + return (CS_OK); + +return_error: + return (res); +} + +static cs_error_t cmap_adjust_int(cmap_handle_t handle, const char *key_name, int32_t step) +{ + cs_error_t error; + struct iovec iov; + struct cmap_inst *cmap_inst; + struct req_lib_cmap_adjust_int req_lib_cmap_adjust_int; + struct res_lib_cmap_adjust_int res_lib_cmap_adjust_int; + + if (key_name == NULL) { + return (CS_ERR_INVALID_PARAM); + } + if (strlen(key_name) >= CS_MAX_NAME_LENGTH) { + return (CS_ERR_NAME_TOO_LONG); + } + + error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + memset(&req_lib_cmap_adjust_int, 0, sizeof(req_lib_cmap_adjust_int)); + req_lib_cmap_adjust_int.header.size = sizeof(req_lib_cmap_adjust_int); + req_lib_cmap_adjust_int.header.id = MESSAGE_REQ_CMAP_ADJUST_INT; + + memcpy(req_lib_cmap_adjust_int.key_name.value, key_name, strlen(key_name)); + req_lib_cmap_adjust_int.key_name.length = strlen(key_name); + + req_lib_cmap_adjust_int.step = step; + + iov.iov_base = (char *)&req_lib_cmap_adjust_int; + iov.iov_len = sizeof(req_lib_cmap_adjust_int); + + error = qb_to_cs_error(qb_ipcc_sendv_recv( + cmap_inst->c, + &iov, + 1, + &res_lib_cmap_adjust_int, + sizeof (struct res_lib_cmap_adjust_int), CS_IPC_TIMEOUT_MS)); + + if (error == CS_OK) { + error = res_lib_cmap_adjust_int.header.error; + } + + (void)hdb_handle_put (&cmap_handle_t_db, handle); + + return (error); +} + +cs_error_t cmap_inc(cmap_handle_t handle, const char *key_name) +{ + + return (cmap_adjust_int(handle, key_name, 1)); +} + +cs_error_t cmap_dec(cmap_handle_t handle, const char *key_name) +{ + + return (cmap_adjust_int(handle, key_name, -1)); +} + +cs_error_t cmap_iter_init( + cmap_handle_t handle, + const char *prefix, + cmap_iter_handle_t *cmap_iter_handle) +{ + cs_error_t error; + struct iovec iov; + struct cmap_inst *cmap_inst; + struct req_lib_cmap_iter_init req_lib_cmap_iter_init; + struct res_lib_cmap_iter_init res_lib_cmap_iter_init; + + if (cmap_iter_handle == NULL) { + return (CS_ERR_INVALID_PARAM); + } + + error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + memset(&req_lib_cmap_iter_init, 0, sizeof(req_lib_cmap_iter_init)); + req_lib_cmap_iter_init.header.size = sizeof(req_lib_cmap_iter_init); + req_lib_cmap_iter_init.header.id = MESSAGE_REQ_CMAP_ITER_INIT; + + if (prefix) { + if (strlen(prefix) >= CS_MAX_NAME_LENGTH) { + return (CS_ERR_NAME_TOO_LONG); + } + memcpy(req_lib_cmap_iter_init.prefix.value, prefix, strlen(prefix)); + req_lib_cmap_iter_init.prefix.length = strlen(prefix); + } + + iov.iov_base = (char *)&req_lib_cmap_iter_init; + iov.iov_len = sizeof(req_lib_cmap_iter_init); + + error = qb_to_cs_error(qb_ipcc_sendv_recv( + cmap_inst->c, + &iov, + 1, + &res_lib_cmap_iter_init, + sizeof (struct res_lib_cmap_iter_init), CS_IPC_TIMEOUT_MS)); + + if (error == CS_OK) { + error = res_lib_cmap_iter_init.header.error; + } + + if (error == CS_OK) { + *cmap_iter_handle = res_lib_cmap_iter_init.iter_handle; + } + + (void)hdb_handle_put (&cmap_handle_t_db, handle); + + return (error); +} + +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) +{ + cs_error_t error; + struct iovec iov; + struct cmap_inst *cmap_inst; + struct req_lib_cmap_iter_next req_lib_cmap_iter_next; + struct res_lib_cmap_iter_next res_lib_cmap_iter_next; + + if (key_name == NULL) { + return (CS_ERR_INVALID_PARAM); + } + + error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + memset(&req_lib_cmap_iter_next, 0, sizeof(req_lib_cmap_iter_next)); + req_lib_cmap_iter_next.header.size = sizeof(req_lib_cmap_iter_next); + req_lib_cmap_iter_next.header.id = MESSAGE_REQ_CMAP_ITER_NEXT; + req_lib_cmap_iter_next.iter_handle = iter_handle; + + iov.iov_base = (char *)&req_lib_cmap_iter_next; + iov.iov_len = sizeof(req_lib_cmap_iter_next); + + error = qb_to_cs_error(qb_ipcc_sendv_recv( + cmap_inst->c, + &iov, + 1, + &res_lib_cmap_iter_next, + sizeof (struct res_lib_cmap_iter_next), CS_IPC_TIMEOUT_MS)); + + if (error == CS_OK) { + error = res_lib_cmap_iter_next.header.error; + } + + if (error == CS_OK) { + memcpy(key_name, (const char *)res_lib_cmap_iter_next.key_name.value, + res_lib_cmap_iter_next.key_name.length); + key_name[res_lib_cmap_iter_next.key_name.length] = '\0'; + + if (value_len != NULL) { + *value_len = res_lib_cmap_iter_next.value_len; + } + + if (type != NULL) { + *type = res_lib_cmap_iter_next.type; + } + } + + (void)hdb_handle_put (&cmap_handle_t_db, handle); + + return (error); +} + +cs_error_t cmap_iter_finalize( + cmap_handle_t handle, + cmap_iter_handle_t iter_handle) +{ + cs_error_t error; + struct iovec iov; + struct cmap_inst *cmap_inst; + struct req_lib_cmap_iter_finalize req_lib_cmap_iter_finalize; + struct res_lib_cmap_iter_finalize res_lib_cmap_iter_finalize; + + error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + memset(&req_lib_cmap_iter_finalize, 0, sizeof(req_lib_cmap_iter_finalize)); + req_lib_cmap_iter_finalize.header.size = sizeof(req_lib_cmap_iter_finalize); + req_lib_cmap_iter_finalize.header.id = MESSAGE_REQ_CMAP_ITER_FINALIZE; + req_lib_cmap_iter_finalize.iter_handle = iter_handle; + + iov.iov_base = (char *)&req_lib_cmap_iter_finalize; + iov.iov_len = sizeof(req_lib_cmap_iter_finalize); + + error = qb_to_cs_error(qb_ipcc_sendv_recv( + cmap_inst->c, + &iov, + 1, + &res_lib_cmap_iter_finalize, + sizeof (struct res_lib_cmap_iter_finalize), CS_IPC_TIMEOUT_MS)); + + if (error == CS_OK) { + error = res_lib_cmap_iter_finalize.header.error; + } + + (void)hdb_handle_put (&cmap_handle_t_db, handle); + + return (error); +} + +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) +{ + cs_error_t error; + struct iovec iov; + struct cmap_inst *cmap_inst; + struct req_lib_cmap_track_add req_lib_cmap_track_add; + struct res_lib_cmap_track_add res_lib_cmap_track_add; + struct cmap_track_inst *cmap_track_inst; + cmap_track_handle_t cmap_track_inst_handle; + + if (cmap_track_handle == NULL || notify_fn == NULL) { + return (CS_ERR_INVALID_PARAM); + } + + error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + error = hdb_error_to_cs(hdb_handle_create(&cmap_track_handle_t_db, + sizeof(*cmap_track_inst), &cmap_track_inst_handle)); + if (error != CS_OK) { + goto error_put; + } + + error = hdb_error_to_cs(hdb_handle_get(&cmap_track_handle_t_db, + cmap_track_inst_handle, (void *)&cmap_track_inst)); + if (error != CS_OK) { + goto error_put_destroy; + } + + cmap_track_inst->user_data = user_data; + cmap_track_inst->notify_fn = notify_fn; + cmap_track_inst->c = cmap_inst->c; + + memset(&req_lib_cmap_track_add, 0, sizeof(req_lib_cmap_track_add)); + req_lib_cmap_track_add.header.size = sizeof(req_lib_cmap_track_add); + req_lib_cmap_track_add.header.id = MESSAGE_REQ_CMAP_TRACK_ADD; + + if (key_name) { + if (strlen(key_name) >= CS_MAX_NAME_LENGTH) { + return (CS_ERR_NAME_TOO_LONG); + } + memcpy(req_lib_cmap_track_add.key_name.value, key_name, strlen(key_name)); + req_lib_cmap_track_add.key_name.length = strlen(key_name); + } + + req_lib_cmap_track_add.track_type = track_type; + req_lib_cmap_track_add.track_inst_handle = cmap_track_inst_handle; + + iov.iov_base = (char *)&req_lib_cmap_track_add; + iov.iov_len = sizeof(req_lib_cmap_track_add); + + error = qb_to_cs_error(qb_ipcc_sendv_recv( + cmap_inst->c, + &iov, + 1, + &res_lib_cmap_track_add, + sizeof (struct res_lib_cmap_track_add), CS_IPC_TIMEOUT_MS)); + + if (error == CS_OK) { + error = res_lib_cmap_track_add.header.error; + } + + if (error == CS_OK) { + *cmap_track_handle = res_lib_cmap_track_add.track_handle; + cmap_track_inst->track_handle = *cmap_track_handle; + } + + (void)hdb_handle_put (&cmap_track_handle_t_db, cmap_track_inst_handle); + + (void)hdb_handle_put (&cmap_handle_t_db, handle); + + return (error); + +error_put_destroy: + (void)hdb_handle_put (&cmap_track_handle_t_db, cmap_track_inst_handle); + (void)hdb_handle_destroy (&cmap_track_handle_t_db, cmap_track_inst_handle); + +error_put: + (void)hdb_handle_put (&cmap_handle_t_db, handle); + + return (error); +} + +cs_error_t cmap_track_delete( + cmap_handle_t handle, + cmap_track_handle_t track_handle) +{ + cs_error_t error; + struct iovec iov; + struct cmap_inst *cmap_inst; + struct cmap_track_inst *cmap_track_inst; + struct req_lib_cmap_track_delete req_lib_cmap_track_delete; + struct res_lib_cmap_track_delete res_lib_cmap_track_delete; + + error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst)); + if (error != CS_OK) { + return (error); + } + + memset(&req_lib_cmap_track_delete, 0, sizeof(req_lib_cmap_track_delete)); + req_lib_cmap_track_delete.header.size = sizeof(req_lib_cmap_track_delete); + req_lib_cmap_track_delete.header.id = MESSAGE_REQ_CMAP_TRACK_DELETE; + req_lib_cmap_track_delete.track_handle = track_handle; + + iov.iov_base = (char *)&req_lib_cmap_track_delete; + iov.iov_len = sizeof(req_lib_cmap_track_delete); + + error = qb_to_cs_error(qb_ipcc_sendv_recv( + cmap_inst->c, + &iov, + 1, + &res_lib_cmap_track_delete, + sizeof (struct res_lib_cmap_track_delete), CS_IPC_TIMEOUT_MS)); + + if (error == CS_OK) { + error = res_lib_cmap_track_delete.header.error; + } + + if (error == CS_OK) { + error = hdb_error_to_cs(hdb_handle_get(&cmap_track_handle_t_db, + res_lib_cmap_track_delete.track_inst_handle, + (void *)&cmap_track_inst)); + if (error != CS_OK) { + goto error_put; + } + + (void)hdb_handle_put(&cmap_track_handle_t_db, res_lib_cmap_track_delete.track_inst_handle); + (void)hdb_handle_destroy(&cmap_track_handle_t_db, res_lib_cmap_track_delete.track_inst_handle); + } + +error_put: + (void)hdb_handle_put (&cmap_handle_t_db, handle); + + return (error); +} diff --git a/lib/cpg.c b/lib/cpg.c new file mode 100644 index 0000000..b41f31d --- /dev/null +++ b/lib/cpg.c @@ -0,0 +1,1426 @@ +/* + * vi: set autoindent tabstop=4 shiftwidth=4 : + * + * Copyright (c) 2006-2015 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Christine Caulfield (ccaulfi@redhat.com) + * Author: Jan Friesse (jfriesse@redhat.com) + * + * 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 MontaVista Software, 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. + */ +/* + * Provides a closed process group API using the coroipcc executive + */ + +#include <config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/mman.h> +#include <sys/uio.h> +#include <sys/stat.h> +#include <errno.h> +#include <limits.h> + +#include <qb/qblist.h> +#include <qb/qbdefs.h> +#include <qb/qbipcc.h> +#include <qb/qblog.h> + +#include <corosync/hdb.h> +#include <corosync/corotypes.h> +#include <corosync/corodefs.h> +#include <corosync/cpg.h> +#include <corosync/ipc_cpg.h> + +#include "util.h" + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +/* + * Maximum number of times to retry a send when transmitting + * a large message fragment + */ +#define MAX_RETRIES 100 + +/* + * ZCB files have following umask (umask is same as used in libqb) + */ +#define CPG_MEMORY_MAP_UMASK 077 + +struct cpg_assembly_data +{ + struct qb_list_head list; + uint32_t nodeid; + uint32_t pid; + char *assembly_buf; + uint32_t assembly_buf_ptr; +}; + +struct cpg_inst { + qb_ipcc_connection_t *c; + int finalize; + void *context; + union { + cpg_model_data_t model_data; + cpg_model_v1_data_t model_v1_data; + }; + struct qb_list_head iteration_list_head; + uint32_t max_msg_size; + struct qb_list_head assembly_list_head; +}; +static void cpg_inst_free (void *inst); + +DECLARE_HDB_DATABASE(cpg_handle_t_db, cpg_inst_free); + +struct cpg_iteration_instance_t { + cpg_iteration_handle_t cpg_iteration_handle; + qb_ipcc_connection_t *conn; + hdb_handle_t executive_iteration_handle; + struct qb_list_head list; +}; + +DECLARE_HDB_DATABASE(cpg_iteration_handle_t_db,NULL); + + +/* + * Internal (not visible by API) functions + */ + +static cs_error_t +coroipcc_msg_send_reply_receive ( + qb_ipcc_connection_t *c, + const struct iovec *iov, + unsigned int iov_len, + void *res_msg, + size_t res_len) +{ + return qb_to_cs_error(qb_ipcc_sendv_recv(c, iov, iov_len, res_msg, res_len, + CS_IPC_TIMEOUT_MS)); +} + +static void cpg_iteration_instance_finalize (struct cpg_iteration_instance_t *cpg_iteration_instance) +{ + qb_list_del (&cpg_iteration_instance->list); + hdb_handle_destroy (&cpg_iteration_handle_t_db, cpg_iteration_instance->cpg_iteration_handle); +} + +static void cpg_inst_free (void *inst) +{ + struct cpg_inst *cpg_inst = (struct cpg_inst *)inst; + qb_ipcc_disconnect(cpg_inst->c); +} + +static void cpg_inst_finalize (struct cpg_inst *cpg_inst, hdb_handle_t handle) +{ + struct qb_list_head *iter, *tmp_iter; + struct cpg_iteration_instance_t *cpg_iteration_instance; + + /* + * Traverse thru iteration instances and delete them + */ + qb_list_for_each_safe(iter, tmp_iter, &(cpg_inst->iteration_list_head)) { + cpg_iteration_instance = qb_list_entry (iter, struct cpg_iteration_instance_t, list); + + cpg_iteration_instance_finalize (cpg_iteration_instance); + } + hdb_handle_destroy (&cpg_handle_t_db, handle); +} + +/** + * @defgroup cpg_coroipcc The closed process group API + * @ingroup coroipcc + * + * @{ + */ + +cs_error_t cpg_initialize ( + cpg_handle_t *handle, + cpg_callbacks_t *callbacks) +{ + cpg_model_v1_data_t model_v1_data; + + memset (&model_v1_data, 0, sizeof (cpg_model_v1_data_t)); + + if (callbacks) { + model_v1_data.cpg_deliver_fn = callbacks->cpg_deliver_fn; + model_v1_data.cpg_confchg_fn = callbacks->cpg_confchg_fn; + } + + return (cpg_model_initialize (handle, CPG_MODEL_V1, (cpg_model_data_t *)&model_v1_data, NULL)); +} + +cs_error_t cpg_model_initialize ( + cpg_handle_t *handle, + cpg_model_t model, + cpg_model_data_t *model_data, + void *context) +{ + cs_error_t error; + struct cpg_inst *cpg_inst; + + if (model != CPG_MODEL_V1) { + error = CS_ERR_INVALID_PARAM; + goto error_no_destroy; + } + + error = hdb_error_to_cs (hdb_handle_create (&cpg_handle_t_db, sizeof (struct cpg_inst), handle)); + if (error != CS_OK) { + goto error_no_destroy; + } + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, *handle, (void *)&cpg_inst)); + if (error != CS_OK) { + goto error_destroy; + } + + cpg_inst->c = qb_ipcc_connect ("cpg", IPC_REQUEST_SIZE); + if (cpg_inst->c == NULL) { + error = qb_to_cs_error(-errno); + goto error_put_destroy; + } + + if (model_data != NULL) { + switch (model) { + case CPG_MODEL_V1: + memcpy (&cpg_inst->model_v1_data, model_data, sizeof (cpg_model_v1_data_t)); + if ((cpg_inst->model_v1_data.flags & ~(CPG_MODEL_V1_DELIVER_INITIAL_TOTEM_CONF)) != 0) { + error = CS_ERR_INVALID_PARAM; + + goto error_destroy; + } + break; + } + } + + /* Allow space for corosync internal headers */ + cpg_inst->max_msg_size = IPC_REQUEST_SIZE - 1024; + cpg_inst->model_data.model = model; + cpg_inst->context = context; + + qb_list_init(&cpg_inst->iteration_list_head); + + qb_list_init(&cpg_inst->assembly_list_head); + + hdb_handle_put (&cpg_handle_t_db, *handle); + + return (CS_OK); + +error_put_destroy: + hdb_handle_put (&cpg_handle_t_db, *handle); +error_destroy: + hdb_handle_destroy (&cpg_handle_t_db, *handle); +error_no_destroy: + return (error); +} + +cs_error_t cpg_finalize ( + cpg_handle_t handle) +{ + struct cpg_inst *cpg_inst; + struct iovec iov; + struct req_lib_cpg_finalize req_lib_cpg_finalize; + struct res_lib_cpg_finalize res_lib_cpg_finalize; + cs_error_t error; + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + /* + * Another thread has already started finalizing + */ + if (cpg_inst->finalize) { + hdb_handle_put (&cpg_handle_t_db, handle); + return (CS_ERR_BAD_HANDLE); + } + + cpg_inst->finalize = 1; + + /* + * Send service request + */ + req_lib_cpg_finalize.header.size = sizeof (struct req_lib_cpg_finalize); + req_lib_cpg_finalize.header.id = MESSAGE_REQ_CPG_FINALIZE; + + iov.iov_base = (void *)&req_lib_cpg_finalize; + iov.iov_len = sizeof (struct req_lib_cpg_finalize); + + error = coroipcc_msg_send_reply_receive (cpg_inst->c, + &iov, + 1, + &res_lib_cpg_finalize, + sizeof (struct res_lib_cpg_finalize)); + + cpg_inst_finalize (cpg_inst, handle); + hdb_handle_put (&cpg_handle_t_db, handle); + + return (error); +} + +cs_error_t cpg_fd_get ( + cpg_handle_t handle, + int *fd) +{ + cs_error_t error; + struct cpg_inst *cpg_inst; + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + error = qb_to_cs_error (qb_ipcc_fd_get (cpg_inst->c, fd)); + + hdb_handle_put (&cpg_handle_t_db, handle); + + return (error); +} + +cs_error_t cpg_max_atomic_msgsize_get ( + cpg_handle_t handle, + uint32_t *size) +{ + cs_error_t error; + struct cpg_inst *cpg_inst; + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + *size = cpg_inst->max_msg_size; + + hdb_handle_put (&cpg_handle_t_db, handle); + + return (error); +} + +cs_error_t cpg_context_get ( + cpg_handle_t handle, + void **context) +{ + cs_error_t error; + struct cpg_inst *cpg_inst; + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + *context = cpg_inst->context; + + hdb_handle_put (&cpg_handle_t_db, handle); + + return (CS_OK); +} + +cs_error_t cpg_context_set ( + cpg_handle_t handle, + void *context) +{ + cs_error_t error; + struct cpg_inst *cpg_inst; + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + cpg_inst->context = context; + + hdb_handle_put (&cpg_handle_t_db, handle); + + return (CS_OK); +} + +cs_error_t cpg_dispatch ( + cpg_handle_t handle, + cs_dispatch_flags_t dispatch_types) +{ + int timeout = -1; + cs_error_t error; + int cont = 1; /* always continue do loop except when set to 0 */ + struct cpg_inst *cpg_inst; + struct res_lib_cpg_confchg_callback *res_cpg_confchg_callback; + struct res_lib_cpg_deliver_callback *res_cpg_deliver_callback; + struct res_lib_cpg_partial_deliver_callback *res_cpg_partial_deliver_callback; + struct res_lib_cpg_totem_confchg_callback *res_cpg_totem_confchg_callback; + struct cpg_inst cpg_inst_copy; + struct qb_ipc_response_header *dispatch_data; + struct cpg_address member_list[CPG_MEMBERS_MAX]; + struct cpg_address left_list[CPG_MEMBERS_MAX]; + struct cpg_address joined_list[CPG_MEMBERS_MAX]; + struct cpg_name group_name; + struct cpg_assembly_data *assembly_data; + struct qb_list_head *iter, *tmp_iter; + mar_cpg_address_t *left_list_start; + mar_cpg_address_t *joined_list_start; + unsigned int i; + struct cpg_ring_id ring_id; + uint32_t totem_member_list[CPG_MEMBERS_MAX]; + int32_t errno_res; + char dispatch_buf[IPC_DISPATCH_SIZE]; + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + /* + * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and + * wait indefinitely for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING + */ + if (dispatch_types == CS_DISPATCH_ALL || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { + timeout = 0; + } + + dispatch_data = (struct qb_ipc_response_header *)dispatch_buf; + do { + errno_res = qb_ipcc_event_recv ( + cpg_inst->c, + dispatch_buf, + IPC_DISPATCH_SIZE, + timeout); + error = qb_to_cs_error (errno_res); + if (error == CS_ERR_BAD_HANDLE) { + error = CS_OK; + goto error_put; + } + if (error == CS_ERR_TRY_AGAIN) { + if (dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { + /* + * Don't mask error + */ + goto error_put; + } + error = CS_OK; + if (dispatch_types == CS_DISPATCH_ALL) { + break; /* exit do while cont is 1 loop */ + } else { + continue; /* next poll */ + } + } + if (error != CS_OK) { + goto error_put; + } + + /* + * Make copy of callbacks, message data, unlock instance, and call callback + * A risk of this dispatch method is that the callback routines may + * operate at the same time that cpgFinalize has been called. + */ + memcpy (&cpg_inst_copy, cpg_inst, sizeof (struct cpg_inst)); + switch (cpg_inst_copy.model_data.model) { + case CPG_MODEL_V1: + /* + * Dispatch incoming message + */ + switch (dispatch_data->id) { + case MESSAGE_RES_CPG_DELIVER_CALLBACK: + if (cpg_inst_copy.model_v1_data.cpg_deliver_fn == NULL) { + break; + } + + res_cpg_deliver_callback = (struct res_lib_cpg_deliver_callback *)dispatch_data; + + marshall_from_mar_cpg_name_t ( + &group_name, + &res_cpg_deliver_callback->group_name); + + cpg_inst_copy.model_v1_data.cpg_deliver_fn (handle, + &group_name, + res_cpg_deliver_callback->nodeid, + res_cpg_deliver_callback->pid, + &res_cpg_deliver_callback->message, + res_cpg_deliver_callback->msglen); + break; + + case MESSAGE_RES_CPG_PARTIAL_DELIVER_CALLBACK: + res_cpg_partial_deliver_callback = (struct res_lib_cpg_partial_deliver_callback *)dispatch_data; + + marshall_from_mar_cpg_name_t ( + &group_name, + &res_cpg_partial_deliver_callback->group_name); + + /* + * Search for assembly data for current messages (nodeid, pid) pair in list of assemblies + */ + assembly_data = NULL; + qb_list_for_each(iter, &(cpg_inst->assembly_list_head)) { + struct cpg_assembly_data *current_assembly_data = qb_list_entry (iter, struct cpg_assembly_data, list); + if (current_assembly_data->nodeid == res_cpg_partial_deliver_callback->nodeid && current_assembly_data->pid == res_cpg_partial_deliver_callback->pid) { + assembly_data = current_assembly_data; + break; + } + } + + if (res_cpg_partial_deliver_callback->type == LIBCPG_PARTIAL_FIRST) { + + /* + * As this is LIBCPG_PARTIAL_FIRST packet, check that there is no ongoing assembly. + * Otherwise the sending of packet must have been interrupted and error should have + * been reported to sending client. Therefore here last assembly will be dropped. + */ + if (assembly_data) { + qb_list_del (&assembly_data->list); + free(assembly_data->assembly_buf); + free(assembly_data); + assembly_data = NULL; + } + + assembly_data = malloc(sizeof(struct cpg_assembly_data)); + if (!assembly_data) { + error = CS_ERR_NO_MEMORY; + goto error_put; + } + + assembly_data->nodeid = res_cpg_partial_deliver_callback->nodeid; + assembly_data->pid = res_cpg_partial_deliver_callback->pid; + assembly_data->assembly_buf = malloc(res_cpg_partial_deliver_callback->msglen); + if (!assembly_data->assembly_buf) { + free(assembly_data); + error = CS_ERR_NO_MEMORY; + goto error_put; + } + assembly_data->assembly_buf_ptr = 0; + qb_list_init (&assembly_data->list); + + qb_list_add (&assembly_data->list, &cpg_inst->assembly_list_head); + } + if (assembly_data) { + memcpy(assembly_data->assembly_buf + assembly_data->assembly_buf_ptr, + res_cpg_partial_deliver_callback->message, res_cpg_partial_deliver_callback->fraglen); + assembly_data->assembly_buf_ptr += res_cpg_partial_deliver_callback->fraglen; + + if (res_cpg_partial_deliver_callback->type == LIBCPG_PARTIAL_LAST) { + cpg_inst_copy.model_v1_data.cpg_deliver_fn (handle, + &group_name, + res_cpg_partial_deliver_callback->nodeid, + res_cpg_partial_deliver_callback->pid, + assembly_data->assembly_buf, + res_cpg_partial_deliver_callback->msglen); + + qb_list_del (&assembly_data->list); + free(assembly_data->assembly_buf); + free(assembly_data); + } + } + break; + + case MESSAGE_RES_CPG_CONFCHG_CALLBACK: + if (cpg_inst_copy.model_v1_data.cpg_confchg_fn == NULL) { + break; + } + + res_cpg_confchg_callback = (struct res_lib_cpg_confchg_callback *)dispatch_data; + + for (i = 0; i < res_cpg_confchg_callback->member_list_entries; i++) { + marshall_from_mar_cpg_address_t (&member_list[i], + &res_cpg_confchg_callback->member_list[i]); + } + left_list_start = res_cpg_confchg_callback->member_list + + res_cpg_confchg_callback->member_list_entries; + for (i = 0; i < res_cpg_confchg_callback->left_list_entries; i++) { + marshall_from_mar_cpg_address_t (&left_list[i], + &left_list_start[i]); + } + joined_list_start = res_cpg_confchg_callback->member_list + + res_cpg_confchg_callback->member_list_entries + + res_cpg_confchg_callback->left_list_entries; + for (i = 0; i < res_cpg_confchg_callback->joined_list_entries; i++) { + marshall_from_mar_cpg_address_t (&joined_list[i], + &joined_list_start[i]); + } + marshall_from_mar_cpg_name_t ( + &group_name, + &res_cpg_confchg_callback->group_name); + + cpg_inst_copy.model_v1_data.cpg_confchg_fn (handle, + &group_name, + member_list, + res_cpg_confchg_callback->member_list_entries, + left_list, + res_cpg_confchg_callback->left_list_entries, + joined_list, + res_cpg_confchg_callback->joined_list_entries); + + /* + * If member left while his partial packet was being assembled, assembly data must be removed from list + */ + for (i = 0; i < res_cpg_confchg_callback->left_list_entries; i++) { + qb_list_for_each_safe(iter, tmp_iter, &(cpg_inst->assembly_list_head)) { + struct cpg_assembly_data *current_assembly_data = qb_list_entry (iter, struct cpg_assembly_data, list); + if (current_assembly_data->nodeid != left_list[i].nodeid || current_assembly_data->pid != left_list[i].pid) + continue; + + qb_list_del (¤t_assembly_data->list); + free(current_assembly_data->assembly_buf); + free(current_assembly_data); + } + } + + break; + case MESSAGE_RES_CPG_TOTEM_CONFCHG_CALLBACK: + if (cpg_inst_copy.model_v1_data.cpg_totem_confchg_fn == NULL) { + break; + } + + res_cpg_totem_confchg_callback = (struct res_lib_cpg_totem_confchg_callback *)dispatch_data; + + marshall_from_mar_cpg_ring_id_t (&ring_id, &res_cpg_totem_confchg_callback->ring_id); + for (i = 0; i < res_cpg_totem_confchg_callback->member_list_entries; i++) { + totem_member_list[i] = res_cpg_totem_confchg_callback->member_list[i]; + } + + cpg_inst_copy.model_v1_data.cpg_totem_confchg_fn (handle, + ring_id, + res_cpg_totem_confchg_callback->member_list_entries, + totem_member_list); + break; + default: + error = CS_ERR_LIBRARY; + goto error_put; + break; + } /* - switch (dispatch_data->id) */ + break; /* case CPG_MODEL_V1 */ + } /* - switch (cpg_inst_copy.model_data.model) */ + + if (cpg_inst_copy.finalize || cpg_inst->finalize) { + /* + * If the finalize has been called then get out of the dispatch. + */ + cpg_inst->finalize = 1; + error = CS_ERR_BAD_HANDLE; + goto error_put; + } + + /* + * Determine if more messages should be processed + */ + if (dispatch_types == CS_DISPATCH_ONE || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { + cont = 0; + } + } while (cont); + +error_put: + hdb_handle_put (&cpg_handle_t_db, handle); + return (error); +} + +cs_error_t cpg_join ( + cpg_handle_t handle, + const struct cpg_name *group) +{ + cs_error_t error; + struct cpg_inst *cpg_inst; + struct iovec iov[2]; + struct req_lib_cpg_join req_lib_cpg_join; + struct res_lib_cpg_join response; + + if (group->length > CPG_MAX_NAME_LENGTH) { + return (CS_ERR_NAME_TOO_LONG); + } + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + /* Now join */ + req_lib_cpg_join.header.size = sizeof (struct req_lib_cpg_join); + req_lib_cpg_join.header.id = MESSAGE_REQ_CPG_JOIN; + req_lib_cpg_join.pid = getpid(); + req_lib_cpg_join.flags = 0; + + switch (cpg_inst->model_data.model) { + case CPG_MODEL_V1: + req_lib_cpg_join.flags = cpg_inst->model_v1_data.flags; + break; + } + + marshall_to_mar_cpg_name_t (&req_lib_cpg_join.group_name, + group); + + iov[0].iov_base = (void *)&req_lib_cpg_join; + iov[0].iov_len = sizeof (struct req_lib_cpg_join); + + do { + error = coroipcc_msg_send_reply_receive (cpg_inst->c, iov, 1, + &response, sizeof (struct res_lib_cpg_join)); + + if (error != CS_OK) { + goto error_exit; + } + } while (response.header.error == CS_ERR_BUSY); + + error = response.header.error; + +error_exit: + hdb_handle_put (&cpg_handle_t_db, handle); + + return (error); +} + +cs_error_t cpg_leave ( + cpg_handle_t handle, + const struct cpg_name *group) +{ + cs_error_t error; + struct cpg_inst *cpg_inst; + struct iovec iov[2]; + struct req_lib_cpg_leave req_lib_cpg_leave; + struct res_lib_cpg_leave res_lib_cpg_leave; + + if (group->length > CPG_MAX_NAME_LENGTH) { + return (CS_ERR_NAME_TOO_LONG); + } + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_cpg_leave.header.size = sizeof (struct req_lib_cpg_leave); + req_lib_cpg_leave.header.id = MESSAGE_REQ_CPG_LEAVE; + req_lib_cpg_leave.pid = getpid(); + marshall_to_mar_cpg_name_t (&req_lib_cpg_leave.group_name, + group); + + iov[0].iov_base = (void *)&req_lib_cpg_leave; + iov[0].iov_len = sizeof (struct req_lib_cpg_leave); + + do { + error = coroipcc_msg_send_reply_receive (cpg_inst->c, iov, 1, + &res_lib_cpg_leave, sizeof (struct res_lib_cpg_leave)); + + if (error != CS_OK) { + goto error_exit; + } + } while (res_lib_cpg_leave.header.error == CS_ERR_BUSY); + + error = res_lib_cpg_leave.header.error; + +error_exit: + hdb_handle_put (&cpg_handle_t_db, handle); + + return (error); +} + +cs_error_t cpg_membership_get ( + cpg_handle_t handle, + struct cpg_name *group_name, + struct cpg_address *member_list, + int *member_list_entries) +{ + cs_error_t error; + struct cpg_inst *cpg_inst; + struct iovec iov; + struct req_lib_cpg_membership_get req_lib_cpg_membership_get; + struct res_lib_cpg_membership_get res_lib_cpg_membership_get; + unsigned int i; + + if (group_name->length > CPG_MAX_NAME_LENGTH) { + return (CS_ERR_NAME_TOO_LONG); + } + if (member_list == NULL) { + return (CS_ERR_INVALID_PARAM); + } + if (member_list_entries == NULL) { + return (CS_ERR_INVALID_PARAM); + } + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_cpg_membership_get.header.size = sizeof (struct req_lib_cpg_membership_get); + req_lib_cpg_membership_get.header.id = MESSAGE_REQ_CPG_MEMBERSHIP; + + marshall_to_mar_cpg_name_t (&req_lib_cpg_membership_get.group_name, + group_name); + + iov.iov_base = (void *)&req_lib_cpg_membership_get; + iov.iov_len = sizeof (struct req_lib_cpg_membership_get); + + error = coroipcc_msg_send_reply_receive (cpg_inst->c, &iov, 1, + &res_lib_cpg_membership_get, sizeof (res_lib_cpg_membership_get)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_cpg_membership_get.header.error; + + /* + * Copy results to caller + */ + *member_list_entries = res_lib_cpg_membership_get.member_count; + if (member_list) { + for (i = 0; i < res_lib_cpg_membership_get.member_count; i++) { + marshall_from_mar_cpg_address_t (&member_list[i], + &res_lib_cpg_membership_get.member_list[i]); + } + } + +error_exit: + hdb_handle_put (&cpg_handle_t_db, handle); + + return (error); +} + +cs_error_t cpg_local_get ( + cpg_handle_t handle, + unsigned int *local_nodeid) +{ + cs_error_t error; + struct cpg_inst *cpg_inst; + struct iovec iov; + struct req_lib_cpg_local_get req_lib_cpg_local_get; + struct res_lib_cpg_local_get res_lib_cpg_local_get; + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_cpg_local_get.header.size = sizeof (struct qb_ipc_request_header); + req_lib_cpg_local_get.header.id = MESSAGE_REQ_CPG_LOCAL_GET; + + iov.iov_base = (void *)&req_lib_cpg_local_get; + iov.iov_len = sizeof (struct req_lib_cpg_local_get); + + error = coroipcc_msg_send_reply_receive (cpg_inst->c, &iov, 1, + &res_lib_cpg_local_get, sizeof (res_lib_cpg_local_get)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_cpg_local_get.header.error; + + *local_nodeid = res_lib_cpg_local_get.local_nodeid; + +error_exit: + hdb_handle_put (&cpg_handle_t_db, handle); + + return (error); +} + +cs_error_t cpg_flow_control_state_get ( + cpg_handle_t handle, + cpg_flow_control_state_t *flow_control_state) +{ + cs_error_t error; + struct cpg_inst *cpg_inst; + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + *flow_control_state = CPG_FLOW_CONTROL_DISABLED; + error = CS_OK; + + hdb_handle_put (&cpg_handle_t_db, handle); + + return (error); +} + +static int +memory_map (char *path, const char *file, void **buf, size_t bytes) +{ + int32_t fd; + void *addr; + int32_t res; + char *buffer; + int32_t i; + size_t written; + size_t page_size; + long int sysconf_page_size; + mode_t old_umask; + + snprintf (path, PATH_MAX, "/dev/shm/%s", file); + + old_umask = umask(CPG_MEMORY_MAP_UMASK); + fd = mkstemp (path); + (void)umask(old_umask); + if (fd == -1) { + snprintf (path, PATH_MAX, LOCALSTATEDIR "/run/%s", file); + old_umask = umask(CPG_MEMORY_MAP_UMASK); + fd = mkstemp (path); + (void)umask(old_umask); + if (fd == -1) { + return (-1); + } + } + + res = ftruncate (fd, bytes); + if (res == -1) { + goto error_close_unlink; + } + sysconf_page_size = sysconf(_SC_PAGESIZE); + if (sysconf_page_size <= 0) { + goto error_close_unlink; + } + page_size = sysconf_page_size; + buffer = malloc (page_size); + if (buffer == NULL) { + goto error_close_unlink; + } + memset (buffer, 0, page_size); + for (i = 0; i < (bytes / page_size); i++) { +retry_write: + written = write (fd, buffer, page_size); + if (written == -1 && errno == EINTR) { + goto retry_write; + } + if (written != page_size) { + free (buffer); + goto error_close_unlink; + } + } + free (buffer); + + addr = mmap (NULL, bytes, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + + if (addr == MAP_FAILED) { + goto error_close_unlink; + } +#ifdef MADV_NOSYNC + madvise(addr, bytes, MADV_NOSYNC); +#endif + + res = close (fd); + if (res) { + munmap(addr, bytes); + + return (-1); + } + *buf = addr; + + return 0; + +error_close_unlink: + close (fd); + unlink(path); + return -1; +} + +cs_error_t cpg_zcb_alloc ( + cpg_handle_t handle, + size_t size, + void **buffer) +{ + void *buf = NULL; + char path[PATH_MAX]; + mar_req_coroipcc_zc_alloc_t req_coroipcc_zc_alloc; + struct qb_ipc_response_header res_coroipcs_zc_alloc; + size_t map_size; + struct iovec iovec; + struct coroipcs_zc_header *hdr; + cs_error_t error; + struct cpg_inst *cpg_inst; + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + map_size = size + sizeof (struct req_lib_cpg_mcast) + sizeof (struct coroipcs_zc_header); + assert(memory_map (path, "corosync_zerocopy-XXXXXX", &buf, map_size) != -1); + + if (strlen(path) >= CPG_ZC_PATH_LEN) { + unlink(path); + munmap (buf, map_size); + return (CS_ERR_NAME_TOO_LONG); + } + + req_coroipcc_zc_alloc.header.size = sizeof (mar_req_coroipcc_zc_alloc_t); + req_coroipcc_zc_alloc.header.id = MESSAGE_REQ_CPG_ZC_ALLOC; + req_coroipcc_zc_alloc.map_size = map_size; + strcpy (req_coroipcc_zc_alloc.path_to_file, path); + + iovec.iov_base = (void *)&req_coroipcc_zc_alloc; + iovec.iov_len = sizeof (mar_req_coroipcc_zc_alloc_t); + + error = coroipcc_msg_send_reply_receive ( + cpg_inst->c, + &iovec, + 1, + &res_coroipcs_zc_alloc, + sizeof (struct qb_ipc_response_header)); + + if (error != CS_OK) { + goto error_exit; + } + + hdr = (struct coroipcs_zc_header *)buf; + hdr->map_size = map_size; + *buffer = ((char *)buf) + sizeof (struct coroipcs_zc_header) + sizeof (struct req_lib_cpg_mcast); + +error_exit: + hdb_handle_put (&cpg_handle_t_db, handle); + return (error); +} + +cs_error_t cpg_zcb_free ( + cpg_handle_t handle, + void *buffer) +{ + cs_error_t error; + unsigned int res; + struct cpg_inst *cpg_inst; + mar_req_coroipcc_zc_free_t req_coroipcc_zc_free; + struct qb_ipc_response_header res_coroipcs_zc_free; + struct iovec iovec; + struct coroipcs_zc_header *header = (struct coroipcs_zc_header *)((char *)buffer - sizeof (struct coroipcs_zc_header) - sizeof (struct req_lib_cpg_mcast)); + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + req_coroipcc_zc_free.header.size = sizeof (mar_req_coroipcc_zc_free_t); + req_coroipcc_zc_free.header.id = MESSAGE_REQ_CPG_ZC_FREE; + req_coroipcc_zc_free.map_size = header->map_size; + req_coroipcc_zc_free.server_address = header->server_address; + + iovec.iov_base = (void *)&req_coroipcc_zc_free; + iovec.iov_len = sizeof (mar_req_coroipcc_zc_free_t); + + error = coroipcc_msg_send_reply_receive ( + cpg_inst->c, + &iovec, + 1, + &res_coroipcs_zc_free, + sizeof (struct qb_ipc_response_header)); + + if (error != CS_OK) { + goto error_exit; + } + + res = munmap ((void *)header, header->map_size); + if (res == -1) { + error = qb_to_cs_error(-errno); + + goto error_exit; + } + +error_exit: + hdb_handle_put (&cpg_handle_t_db, handle); + + return (error); +} + +cs_error_t cpg_zcb_mcast_joined ( + cpg_handle_t handle, + cpg_guarantee_t guarantee, + void *msg, + size_t msg_len) +{ + cs_error_t error; + struct cpg_inst *cpg_inst; + struct req_lib_cpg_mcast *req_lib_cpg_mcast; + struct res_lib_cpg_mcast res_lib_cpg_mcast; + mar_req_coroipcc_zc_execute_t req_coroipcc_zc_execute; + struct coroipcs_zc_header *hdr; + struct iovec iovec; + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + if (msg_len > IPC_REQUEST_SIZE) { + error = CS_ERR_TOO_BIG; + goto error_exit; + } + + req_lib_cpg_mcast = (struct req_lib_cpg_mcast *)(((char *)msg) - sizeof (struct req_lib_cpg_mcast)); + req_lib_cpg_mcast->header.size = sizeof (struct req_lib_cpg_mcast) + + msg_len; + + req_lib_cpg_mcast->header.id = MESSAGE_REQ_CPG_MCAST; + req_lib_cpg_mcast->guarantee = guarantee; + req_lib_cpg_mcast->msglen = msg_len; + + hdr = (struct coroipcs_zc_header *)(((char *)req_lib_cpg_mcast) - sizeof (struct coroipcs_zc_header)); + + req_coroipcc_zc_execute.header.size = sizeof (mar_req_coroipcc_zc_execute_t); + req_coroipcc_zc_execute.header.id = MESSAGE_REQ_CPG_ZC_EXECUTE; + req_coroipcc_zc_execute.server_address = hdr->server_address; + + iovec.iov_base = (void *)&req_coroipcc_zc_execute; + iovec.iov_len = sizeof (mar_req_coroipcc_zc_execute_t); + + error = coroipcc_msg_send_reply_receive ( + cpg_inst->c, + &iovec, + 1, + &res_lib_cpg_mcast, + sizeof(res_lib_cpg_mcast)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_cpg_mcast.header.error; + +error_exit: + hdb_handle_put (&cpg_handle_t_db, handle); + + return (error); +} + +static cs_error_t send_fragments ( + struct cpg_inst *cpg_inst, + cpg_guarantee_t guarantee, + size_t msg_len, + const struct iovec *iovec, + unsigned int iov_len) +{ + int i; + cs_error_t error = CS_OK; + struct iovec iov[2]; + struct req_lib_cpg_partial_mcast req_lib_cpg_mcast; + struct res_lib_cpg_partial_send res_lib_cpg_partial_send; + size_t sent = 0; + size_t iov_sent = 0; + int retry_count; + + req_lib_cpg_mcast.header.id = MESSAGE_REQ_CPG_PARTIAL_MCAST; + req_lib_cpg_mcast.guarantee = guarantee; + req_lib_cpg_mcast.msglen = msg_len; + + iov[0].iov_base = (void *)&req_lib_cpg_mcast; + iov[0].iov_len = sizeof (struct req_lib_cpg_partial_mcast); + + i=0; + iov_sent = 0 ; + qb_ipcc_fc_enable_max_set(cpg_inst->c, 2); + + while (error == CS_OK && sent < msg_len) { + + retry_count = 0; + if ( (iovec[i].iov_len - iov_sent) > cpg_inst->max_msg_size) { + iov[1].iov_len = cpg_inst->max_msg_size; + } + else { + iov[1].iov_len = iovec[i].iov_len - iov_sent; + } + + if (sent == 0) { + req_lib_cpg_mcast.type = LIBCPG_PARTIAL_FIRST; + } + else if ((sent + iov[1].iov_len) == msg_len) { + req_lib_cpg_mcast.type = LIBCPG_PARTIAL_LAST; + } + else { + req_lib_cpg_mcast.type = LIBCPG_PARTIAL_CONTINUED; + } + + req_lib_cpg_mcast.fraglen = iov[1].iov_len; + req_lib_cpg_mcast.header.size = sizeof (struct req_lib_cpg_partial_mcast) + iov[1].iov_len; + iov[1].iov_base = (char *)iovec[i].iov_base + iov_sent; + + resend: + error = coroipcc_msg_send_reply_receive (cpg_inst->c, iov, 2, + &res_lib_cpg_partial_send, + sizeof (res_lib_cpg_partial_send)); + + if (error == CS_ERR_TRY_AGAIN) { + fprintf(stderr, "sleep. counter=%d\n", retry_count); + if (++retry_count > MAX_RETRIES) { + goto error_exit; + } + usleep(10000); + goto resend; + } + + iov_sent += iov[1].iov_len; + sent += iov[1].iov_len; + + /* Next iovec */ + if (iov_sent >= iovec[i].iov_len) { + i++; + iov_sent = 0; + } + error = res_lib_cpg_partial_send.header.error; + } +error_exit: + qb_ipcc_fc_enable_max_set(cpg_inst->c, 1); + + return error; +} + + +cs_error_t cpg_mcast_joined ( + cpg_handle_t handle, + cpg_guarantee_t guarantee, + const struct iovec *iovec, + unsigned int iov_len) +{ + int i; + cs_error_t error; + struct cpg_inst *cpg_inst; + struct iovec iov[64]; + struct req_lib_cpg_mcast req_lib_cpg_mcast; + size_t msg_len = 0; + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + for (i = 0; i < iov_len; i++ ) { + msg_len += iovec[i].iov_len; + } + + if (msg_len > cpg_inst->max_msg_size) { + error = send_fragments(cpg_inst, guarantee, msg_len, iovec, iov_len); + goto error_exit; + } + + req_lib_cpg_mcast.header.size = sizeof (struct req_lib_cpg_mcast) + + msg_len; + + req_lib_cpg_mcast.header.id = MESSAGE_REQ_CPG_MCAST; + req_lib_cpg_mcast.guarantee = guarantee; + req_lib_cpg_mcast.msglen = msg_len; + + iov[0].iov_base = (void *)&req_lib_cpg_mcast; + iov[0].iov_len = sizeof (struct req_lib_cpg_mcast); + memcpy (&iov[1], iovec, iov_len * sizeof (struct iovec)); + + qb_ipcc_fc_enable_max_set(cpg_inst->c, 2); + error = qb_to_cs_error(qb_ipcc_sendv(cpg_inst->c, iov, iov_len + 1)); + qb_ipcc_fc_enable_max_set(cpg_inst->c, 1); + +error_exit: + hdb_handle_put (&cpg_handle_t_db, handle); + + return (error); +} + +cs_error_t cpg_iteration_initialize( + cpg_handle_t handle, + cpg_iteration_type_t iteration_type, + const struct cpg_name *group, + cpg_iteration_handle_t *cpg_iteration_handle) +{ + cs_error_t error; + struct iovec iov; + struct cpg_inst *cpg_inst; + struct cpg_iteration_instance_t *cpg_iteration_instance; + struct req_lib_cpg_iterationinitialize req_lib_cpg_iterationinitialize; + struct res_lib_cpg_iterationinitialize res_lib_cpg_iterationinitialize; + + if (group && group->length > CPG_MAX_NAME_LENGTH) { + return (CS_ERR_NAME_TOO_LONG); + } + if (cpg_iteration_handle == NULL) { + return (CS_ERR_INVALID_PARAM); + } + + if ((iteration_type == CPG_ITERATION_ONE_GROUP && group == NULL) || + (iteration_type != CPG_ITERATION_ONE_GROUP && group != NULL)) { + return (CS_ERR_INVALID_PARAM); + } + + if (iteration_type != CPG_ITERATION_NAME_ONLY && iteration_type != CPG_ITERATION_ONE_GROUP && + iteration_type != CPG_ITERATION_ALL) { + + return (CS_ERR_INVALID_PARAM); + } + + error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst)); + if (error != CS_OK) { + return (error); + } + + error = hdb_error_to_cs (hdb_handle_create (&cpg_iteration_handle_t_db, + sizeof (struct cpg_iteration_instance_t), cpg_iteration_handle)); + if (error != CS_OK) { + goto error_put_cpg_db; + } + + error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, *cpg_iteration_handle, + (void *)&cpg_iteration_instance)); + if (error != CS_OK) { + goto error_destroy; + } + + cpg_iteration_instance->conn = cpg_inst->c; + + qb_list_init (&cpg_iteration_instance->list); + + req_lib_cpg_iterationinitialize.header.size = sizeof (struct req_lib_cpg_iterationinitialize); + req_lib_cpg_iterationinitialize.header.id = MESSAGE_REQ_CPG_ITERATIONINITIALIZE; + req_lib_cpg_iterationinitialize.iteration_type = iteration_type; + if (group) { + marshall_to_mar_cpg_name_t (&req_lib_cpg_iterationinitialize.group_name, group); + } + + iov.iov_base = (void *)&req_lib_cpg_iterationinitialize; + iov.iov_len = sizeof (struct req_lib_cpg_iterationinitialize); + + error = coroipcc_msg_send_reply_receive (cpg_inst->c, + &iov, + 1, + &res_lib_cpg_iterationinitialize, + sizeof (struct res_lib_cpg_iterationinitialize)); + + if (error != CS_OK) { + goto error_put_destroy; + } + + cpg_iteration_instance->executive_iteration_handle = + res_lib_cpg_iterationinitialize.iteration_handle; + cpg_iteration_instance->cpg_iteration_handle = *cpg_iteration_handle; + + qb_list_add (&cpg_iteration_instance->list, &cpg_inst->iteration_list_head); + + hdb_handle_put (&cpg_iteration_handle_t_db, *cpg_iteration_handle); + hdb_handle_put (&cpg_handle_t_db, handle); + + return (res_lib_cpg_iterationinitialize.header.error); + +error_put_destroy: + hdb_handle_put (&cpg_iteration_handle_t_db, *cpg_iteration_handle); +error_destroy: + hdb_handle_destroy (&cpg_iteration_handle_t_db, *cpg_iteration_handle); +error_put_cpg_db: + hdb_handle_put (&cpg_handle_t_db, handle); + + return (error); +} + +cs_error_t cpg_iteration_next( + cpg_iteration_handle_t handle, + struct cpg_iteration_description_t *description) +{ + cs_error_t error; + struct cpg_iteration_instance_t *cpg_iteration_instance; + struct req_lib_cpg_iterationnext req_lib_cpg_iterationnext; + struct res_lib_cpg_iterationnext res_lib_cpg_iterationnext; + + if (description == NULL) { + return CS_ERR_INVALID_PARAM; + } + + error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, handle, + (void *)&cpg_iteration_instance)); + if (error != CS_OK) { + goto error_exit; + } + + req_lib_cpg_iterationnext.header.size = sizeof (struct req_lib_cpg_iterationnext); + req_lib_cpg_iterationnext.header.id = MESSAGE_REQ_CPG_ITERATIONNEXT; + req_lib_cpg_iterationnext.iteration_handle = cpg_iteration_instance->executive_iteration_handle; + + error = qb_to_cs_error (qb_ipcc_send (cpg_iteration_instance->conn, + &req_lib_cpg_iterationnext, + req_lib_cpg_iterationnext.header.size)); + if (error != CS_OK) { + goto error_put; + } + + error = qb_to_cs_error (qb_ipcc_recv (cpg_iteration_instance->conn, + &res_lib_cpg_iterationnext, + sizeof(struct res_lib_cpg_iterationnext), -1)); + if (error != CS_OK) { + goto error_put; + } + + marshall_from_mar_cpg_iteration_description_t( + description, + &res_lib_cpg_iterationnext.description); + + error = res_lib_cpg_iterationnext.header.error; + +error_put: + hdb_handle_put (&cpg_iteration_handle_t_db, handle); + +error_exit: + return (error); +} + +cs_error_t cpg_iteration_finalize ( + cpg_iteration_handle_t handle) +{ + cs_error_t error; + struct iovec iov; + struct cpg_iteration_instance_t *cpg_iteration_instance; + struct req_lib_cpg_iterationfinalize req_lib_cpg_iterationfinalize; + struct res_lib_cpg_iterationfinalize res_lib_cpg_iterationfinalize; + + error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, handle, + (void *)&cpg_iteration_instance)); + if (error != CS_OK) { + goto error_exit; + } + + req_lib_cpg_iterationfinalize.header.size = sizeof (struct req_lib_cpg_iterationfinalize); + req_lib_cpg_iterationfinalize.header.id = MESSAGE_REQ_CPG_ITERATIONFINALIZE; + req_lib_cpg_iterationfinalize.iteration_handle = cpg_iteration_instance->executive_iteration_handle; + + iov.iov_base = (void *)&req_lib_cpg_iterationfinalize; + iov.iov_len = sizeof (struct req_lib_cpg_iterationfinalize); + + error = coroipcc_msg_send_reply_receive (cpg_iteration_instance->conn, + &iov, + 1, + &res_lib_cpg_iterationfinalize, + sizeof (struct req_lib_cpg_iterationfinalize)); + + if (error != CS_OK) { + goto error_put; + } + + cpg_iteration_instance_finalize (cpg_iteration_instance); + hdb_handle_put (&cpg_iteration_handle_t_db, cpg_iteration_instance->cpg_iteration_handle); + + return (res_lib_cpg_iterationfinalize.header.error); + +error_put: + hdb_handle_put (&cpg_iteration_handle_t_db, handle); +error_exit: + return (error); +} + +/** @} */ diff --git a/lib/libcfg.versions b/lib/libcfg.versions new file mode 100644 index 0000000..18d18f7 --- /dev/null +++ b/lib/libcfg.versions @@ -0,0 +1,18 @@ +# Version and symbol export for libcfg.so + +COROSYNC_CFG_0.82 { + global: + corosync_cfg_initialize; + corosync_cfg_fd_get; + corosync_cfg_dispatch; + corosync_cfg_finalize; + corosync_cfg_administrative_state_get; + corosync_cfg_administrative_state_set; + corosync_cfg_track; + corosync_cfg_track_stop; + corosync_cfg_ring_status_get; + corosync_cfg_node_status_get; + corosync_cfg_ring_reenable; + corosync_cfg_trackstart; + corosync_cfg_trackstop; +}; diff --git a/lib/libcfg.verso b/lib/libcfg.verso new file mode 100644 index 0000000..1502020 --- /dev/null +++ b/lib/libcfg.verso @@ -0,0 +1 @@ +7.3.0 diff --git a/lib/libcmap.versions b/lib/libcmap.versions new file mode 100644 index 0000000..59c8778 --- /dev/null +++ b/lib/libcmap.versions @@ -0,0 +1,6 @@ +# Version and symbol export for libsam.so + +COROSYNC_CMAP_1.0 { + global: + cmap_initialize; +}; diff --git a/lib/libcmap.verso b/lib/libcmap.verso new file mode 100644 index 0000000..ee74734 --- /dev/null +++ b/lib/libcmap.verso @@ -0,0 +1 @@ +4.1.0 diff --git a/lib/libcpg.versions b/lib/libcpg.versions new file mode 100644 index 0000000..93eeb52 --- /dev/null +++ b/lib/libcpg.versions @@ -0,0 +1,17 @@ +# Version and symbol export for libcpg.so + +COROSYNC_CPG_1.0 { + global: + cpg_initialize; + cpg_finalize; + cpg_fd_get; + cpg_dispatch; + cpg_join; + cpg_leave; + cpg_mcast_joined; + cpg_membership_get; + cpg_context_get; + cpg_context_set; + cpg_zcb_alloc; + cpg_zcb_free; +}; diff --git a/lib/libcpg.verso b/lib/libcpg.verso new file mode 100644 index 0000000..ee74734 --- /dev/null +++ b/lib/libcpg.verso @@ -0,0 +1 @@ +4.1.0 diff --git a/lib/libquorum.versions b/lib/libquorum.versions new file mode 100644 index 0000000..b1f0a88 --- /dev/null +++ b/lib/libquorum.versions @@ -0,0 +1,11 @@ +# Version and symbol export for libquorum.so + +COROSYNC_QUORUM_1.0 { + global: + quorum_initialize; + quorum_finalize; + quorum_getquorate; + quorum_initialize; + quorum_finalize; + quorum_dispatch; +}; diff --git a/lib/libquorum.verso b/lib/libquorum.verso new file mode 100644 index 0000000..831446c --- /dev/null +++ b/lib/libquorum.verso @@ -0,0 +1 @@ +5.1.0 diff --git a/lib/libsam.versions b/lib/libsam.versions new file mode 100644 index 0000000..48fba2c --- /dev/null +++ b/lib/libsam.versions @@ -0,0 +1,12 @@ +# Version and symbol export for libsam.so + +COROSYNC_SAM_1.0 { + global: + sam_initialized; + sam_finalize; + sam_start; + sam_stop; + sam_register; + sam_hc_send; + sam_hc_callback_register; +}; diff --git a/lib/libsam.verso b/lib/libsam.verso new file mode 100644 index 0000000..fdc6698 --- /dev/null +++ b/lib/libsam.verso @@ -0,0 +1 @@ +4.4.0 diff --git a/lib/libvotequorum.versions b/lib/libvotequorum.versions new file mode 100644 index 0000000..7a37030 --- /dev/null +++ b/lib/libvotequorum.versions @@ -0,0 +1,17 @@ +# Version and symbol export for libvotequorum.so + +COROSYNC_VOTEQUORUM_1.0 { + global: + votequorum_initialize; + votequorum_finalize; + votequorum_getinfo; + votequorum_setexpected; + votequorum_setvotes; + votequorum_qdevice_register; + votequorum_qdevice_unregister; + votequorum_qdevice_poll; + votequorum_trackstart; + votequorum_trackstop; + votequorum_context_get; + votequorum_context_set; +}; diff --git a/lib/libvotequorum.verso b/lib/libvotequorum.verso new file mode 100644 index 0000000..ae9a76b --- /dev/null +++ b/lib/libvotequorum.verso @@ -0,0 +1 @@ +8.0.0 diff --git a/lib/quorum.c b/lib/quorum.c new file mode 100644 index 0000000..c1139c0 --- /dev/null +++ b/lib/quorum.c @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2008-2020 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Christine Caulfield (ccaulfie@redhat.com) + * + * 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 MontaVista Software, 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. + */ +/* + * Provides a quorum API using the corosync executive + */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <errno.h> + +#include <qb/qbipcc.h> +#include <corosync/corotypes.h> +#include <corosync/corodefs.h> +#include <corosync/hdb.h> + +#include <corosync/quorum.h> +#include <corosync/ipc_quorum.h> + +#include "util.h" + +struct quorum_inst { + qb_ipcc_connection_t *c; + int finalize; + const void *context; + union { + quorum_model_data_t model_data; + quorum_model_v0_data_t model_v0_data; + quorum_model_v1_data_t model_v1_data; + }; +}; + +static void quorum_inst_free (void *inst); + +DECLARE_HDB_DATABASE(quorum_handle_t_db, quorum_inst_free); + +cs_error_t quorum_initialize ( + quorum_handle_t *handle, + quorum_callbacks_t *callbacks, + uint32_t *quorum_type) +{ + quorum_model_v0_data_t model_v0_data; + + memset (&model_v0_data, 0, sizeof(quorum_model_v0_data_t)); + + if (callbacks) { + model_v0_data.quorum_notify_fn = callbacks->quorum_notify_fn; + } + + return (quorum_model_initialize(handle, QUORUM_MODEL_V0, + (quorum_model_data_t *)&model_v0_data, quorum_type, NULL)); +} + +cs_error_t quorum_model_initialize ( + quorum_handle_t *handle, + quorum_model_t model, + quorum_model_data_t *model_data, + uint32_t *quorum_type, + void *context) +{ + cs_error_t error; + struct quorum_inst *quorum_inst; + struct iovec iov; + struct qb_ipc_request_header quorum_gettype_req; + struct req_lib_quorum_model_gettype quorum_model_gettype_req; + struct res_lib_quorum_gettype res_lib_quorum_gettype; + struct res_lib_quorum_model_gettype res_lib_quorum_model_gettype; + uint32_t local_quorum_type; + + if (model != QUORUM_MODEL_V0 && model != QUORUM_MODEL_V1) { + error = CS_ERR_INVALID_PARAM; + goto error_no_destroy; + } + + error = hdb_error_to_cs(hdb_handle_create (&quorum_handle_t_db, sizeof (struct quorum_inst), handle)); + if (error != CS_OK) { + goto error_no_destroy; + } + + error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, *handle, (void *)&quorum_inst)); + if (error != CS_OK) { + goto error_destroy; + } + + error = CS_OK; + quorum_inst->finalize = 0; + quorum_inst->c = qb_ipcc_connect ("quorum", IPC_REQUEST_SIZE); + if (quorum_inst->c == NULL) { + error = qb_to_cs_error(-errno); + goto error_put_destroy; + } + + switch (model) { + case QUORUM_MODEL_V0: + quorum_gettype_req.size = sizeof (quorum_gettype_req); + quorum_gettype_req.id = MESSAGE_REQ_QUORUM_GETTYPE; + + iov.iov_base = (char *)&quorum_gettype_req; + iov.iov_len = sizeof (quorum_gettype_req); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + quorum_inst->c, + &iov, + 1, + &res_lib_quorum_gettype, + sizeof(res_lib_quorum_gettype), -1)); + + if (error != CS_OK) { + goto error_put_destroy; + } + error = res_lib_quorum_gettype.header.error; + local_quorum_type = res_lib_quorum_gettype.quorum_type; + break; + case QUORUM_MODEL_V1: + quorum_model_gettype_req.header.size = sizeof (quorum_model_gettype_req); + quorum_model_gettype_req.header.id = MESSAGE_REQ_QUORUM_MODEL_GETTYPE; + quorum_model_gettype_req.model = model; + + iov.iov_base = (char *)&quorum_model_gettype_req; + iov.iov_len = sizeof (quorum_model_gettype_req); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + quorum_inst->c, + &iov, + 1, + &res_lib_quorum_model_gettype, + sizeof(res_lib_quorum_model_gettype), -1)); + + if (error != CS_OK) { + goto error_put_destroy; + } + error = res_lib_quorum_model_gettype.header.error; + local_quorum_type = res_lib_quorum_model_gettype.quorum_type; + break; + } + + if (quorum_type != NULL) { + *quorum_type = local_quorum_type; + } + + if (model_data != NULL) { + switch (model) { + case QUORUM_MODEL_V0: + memcpy(&quorum_inst->model_v0_data, model_data, sizeof(quorum_model_v0_data_t)); + break; + case QUORUM_MODEL_V1: + memcpy(&quorum_inst->model_v1_data, model_data, sizeof(quorum_model_v1_data_t)); + break; + } + } + + quorum_inst->model_data.model = model; + quorum_inst->context = context; + + (void)hdb_handle_put (&quorum_handle_t_db, *handle); + + return (error); + +error_put_destroy: + (void)hdb_handle_put (&quorum_handle_t_db, *handle); +error_destroy: + (void)hdb_handle_destroy (&quorum_handle_t_db, *handle); +error_no_destroy: + return (error); +} + +static void quorum_inst_free (void *inst) +{ + struct quorum_inst *quorum_inst = (struct quorum_inst *)inst; + qb_ipcc_disconnect(quorum_inst->c); +} + +cs_error_t quorum_finalize ( + quorum_handle_t handle) +{ + struct quorum_inst *quorum_inst; + cs_error_t error; + + error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); + if (error != CS_OK) { + return (error); + } + + /* + * Another thread has already started finalizing + */ + if (quorum_inst->finalize) { + (void)hdb_handle_put (&quorum_handle_t_db, handle); + return (CS_ERR_BAD_HANDLE); + } + + quorum_inst->finalize = 1; + + (void)hdb_handle_destroy (&quorum_handle_t_db, handle); + + (void)hdb_handle_put (&quorum_handle_t_db, handle); + + return (CS_OK); +} + +cs_error_t quorum_getquorate ( + quorum_handle_t handle, + int *quorate) +{ + cs_error_t error; + struct quorum_inst *quorum_inst; + struct iovec iov; + struct qb_ipc_request_header req; + struct res_lib_quorum_getquorate res_lib_quorum_getquorate; + + error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); + if (error != CS_OK) { + return (error); + } + + req.size = sizeof (req); + req.id = MESSAGE_REQ_QUORUM_GETQUORATE; + + iov.iov_base = (char *)&req; + iov.iov_len = sizeof (req); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + quorum_inst->c, + &iov, + 1, + &res_lib_quorum_getquorate, + sizeof (struct res_lib_quorum_getquorate), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_quorum_getquorate.header.error; + + *quorate = res_lib_quorum_getquorate.quorate; + +error_exit: + (void)hdb_handle_put (&quorum_handle_t_db, handle); + + return (error); +} + +cs_error_t quorum_fd_get ( + quorum_handle_t handle, + int *fd) +{ + cs_error_t error; + struct quorum_inst *quorum_inst; + + error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); + if (error != CS_OK) { + return (error); + } + + error = qb_to_cs_error(qb_ipcc_fd_get (quorum_inst->c, fd)); + + (void)hdb_handle_put (&quorum_handle_t_db, handle); + + return (error); +} + + +cs_error_t quorum_context_get ( + quorum_handle_t handle, + const void **context) +{ + cs_error_t error; + struct quorum_inst *quorum_inst; + + error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); + if (error != CS_OK) { + return (error); + } + + *context = quorum_inst->context; + + (void)hdb_handle_put (&quorum_handle_t_db, handle); + + return (CS_OK); +} + +cs_error_t quorum_context_set ( + quorum_handle_t handle, + const void *context) +{ + cs_error_t error; + struct quorum_inst *quorum_inst; + + error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); + if (error != CS_OK) { + return (error); + } + + quorum_inst->context = context; + + (void)hdb_handle_put (&quorum_handle_t_db, handle); + + return (CS_OK); +} + + +cs_error_t quorum_trackstart ( + quorum_handle_t handle, + unsigned int flags ) +{ + cs_error_t error; + struct quorum_inst *quorum_inst; + struct iovec iov; + struct req_lib_quorum_trackstart req_lib_quorum_trackstart; + struct qb_ipc_response_header res; + + error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_quorum_trackstart.header.size = sizeof (struct req_lib_quorum_trackstart); + req_lib_quorum_trackstart.header.id = MESSAGE_REQ_QUORUM_TRACKSTART; + req_lib_quorum_trackstart.track_flags = flags; + + iov.iov_base = (char *)&req_lib_quorum_trackstart; + iov.iov_len = sizeof (struct req_lib_quorum_trackstart); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + quorum_inst->c, + &iov, + 1, + &res, + sizeof (res), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res.error; + +error_exit: + (void)hdb_handle_put (&quorum_handle_t_db, handle); + + return (error); +} + +cs_error_t quorum_trackstop ( + quorum_handle_t handle) +{ + cs_error_t error; + struct quorum_inst *quorum_inst; + struct iovec iov; + struct qb_ipc_request_header req; + struct qb_ipc_response_header res; + + error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst)); + if (error != CS_OK) { + return (error); + } + + req.size = sizeof (req); + req.id = MESSAGE_REQ_QUORUM_TRACKSTOP; + + iov.iov_base = (char *)&req; + iov.iov_len = sizeof (req); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + quorum_inst->c, + &iov, + 1, + &res, + sizeof (res), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res.error; + +error_exit: + (void)hdb_handle_put (&quorum_handle_t_db, handle); + + return (error); +} + +cs_error_t quorum_dispatch ( + quorum_handle_t handle, + cs_dispatch_flags_t dispatch_types) +{ + int timeout = -1; + cs_error_t error; + int cont = 1; /* always continue do loop except when set to 0 */ + struct quorum_inst *quorum_inst; + struct quorum_inst quorum_inst_copy; + struct qb_ipc_response_header *dispatch_data; + char dispatch_buf[IPC_DISPATCH_SIZE]; + struct res_lib_quorum_notification *res_lib_quorum_notification; + struct res_lib_quorum_v1_quorum_notification *res_lib_quorum_v1_quorum_notification; + struct res_lib_quorum_v1_nodelist_notification *res_lib_quorum_v1_nodelist_notification; + struct quorum_ring_id ring_id; + mar_uint32_t *joined_list; + mar_uint32_t *left_list; + + if (dispatch_types != CS_DISPATCH_ONE && + dispatch_types != CS_DISPATCH_ALL && + dispatch_types != CS_DISPATCH_BLOCKING && + dispatch_types != CS_DISPATCH_ONE_NONBLOCKING) { + + return (CS_ERR_INVALID_PARAM); + } + + error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, + (void *)&quorum_inst)); + if (error != CS_OK) { + return (error); + } + + /* + * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and + * wait indefinately for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING + */ + if (dispatch_types == CS_DISPATCH_ALL || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { + timeout = 0; + } + + dispatch_data = (struct qb_ipc_response_header *)dispatch_buf; + do { + error = qb_to_cs_error (qb_ipcc_event_recv ( + quorum_inst->c, + dispatch_buf, + IPC_DISPATCH_SIZE, + timeout)); + if (error == CS_ERR_BAD_HANDLE) { + error = CS_OK; + goto error_put; + } + if (error == CS_ERR_TRY_AGAIN) { + if (dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { + /* + * Don't mask error + */ + goto error_put; + } + error = CS_OK; + if (dispatch_types == CS_DISPATCH_ALL) { + break; /* exit do while cont is 1 loop */ + } else { + continue; /* next poll */ + } + } + if (error != CS_OK) { + goto error_put; + } + + /* + * Make copy of callbacks, message data, unlock instance, and call callback + * A risk of this dispatch method is that the callback routines may + * operate at the same time that quorum_finalize has been called in another thread. + */ + memcpy (&quorum_inst_copy, quorum_inst, sizeof(quorum_inst_copy)); + switch (quorum_inst_copy.model_data.model) { + case QUORUM_MODEL_V0: + /* + * Dispatch incoming message + */ + switch (dispatch_data->id) { + case MESSAGE_RES_QUORUM_NOTIFICATION: + if (quorum_inst_copy.model_v0_data.quorum_notify_fn == NULL) { + break; + } + res_lib_quorum_notification = (struct res_lib_quorum_notification *)dispatch_data; + + quorum_inst_copy.model_v0_data.quorum_notify_fn ( handle, + res_lib_quorum_notification->quorate, + res_lib_quorum_notification->ring_seq, + res_lib_quorum_notification->view_list_entries, + res_lib_quorum_notification->view_list); + break; + default: + error = CS_ERR_LIBRARY; + goto error_put; + break; + } /* switch (dispatch_data->id) */ + break; /* case QUORUM_MODEL_V0 */ + case QUORUM_MODEL_V1: + /* + * Dispatch incoming message + */ + switch (dispatch_data->id) { + case MESSAGE_RES_QUORUM_V1_QUORUM_NOTIFICATION: + if (quorum_inst_copy.model_v1_data.quorum_notify_fn == NULL) { + break; + } + res_lib_quorum_v1_quorum_notification = + (struct res_lib_quorum_v1_quorum_notification *)dispatch_data; + + ring_id.nodeid = res_lib_quorum_v1_quorum_notification->ring_id.nodeid; + ring_id.seq = res_lib_quorum_v1_quorum_notification->ring_id.seq; + + quorum_inst_copy.model_v1_data.quorum_notify_fn ( handle, + res_lib_quorum_v1_quorum_notification->quorate, + ring_id, + res_lib_quorum_v1_quorum_notification->view_list_entries, + res_lib_quorum_v1_quorum_notification->view_list); + break; + case MESSAGE_RES_QUORUM_V1_NODELIST_NOTIFICATION: + if (quorum_inst_copy.model_v1_data.nodelist_notify_fn == NULL) { + break; + } + res_lib_quorum_v1_nodelist_notification = + (struct res_lib_quorum_v1_nodelist_notification *)dispatch_data; + + ring_id.nodeid = res_lib_quorum_v1_nodelist_notification->ring_id.nodeid; + ring_id.seq = res_lib_quorum_v1_nodelist_notification->ring_id.seq; + + joined_list = res_lib_quorum_v1_nodelist_notification->member_list + + res_lib_quorum_v1_nodelist_notification->member_list_entries; + left_list = joined_list + + res_lib_quorum_v1_nodelist_notification->joined_list_entries; + + quorum_inst_copy.model_v1_data.nodelist_notify_fn ( handle, + ring_id, + res_lib_quorum_v1_nodelist_notification->member_list_entries, + res_lib_quorum_v1_nodelist_notification->member_list, + res_lib_quorum_v1_nodelist_notification->joined_list_entries, + joined_list, + res_lib_quorum_v1_nodelist_notification->left_list_entries, + left_list); + break; + default: + error = CS_ERR_LIBRARY; + goto error_put; + break; + } /* switch (dispatch_data->id) */ + break; /* case QUORUM_MODEL_V1 */ + } + if (quorum_inst->finalize) { + /* + * If the finalize has been called then get out of the dispatch. + */ + error = CS_ERR_BAD_HANDLE; + goto error_put; + } + + /* + * Determine if more messages should be processed + */ + if (dispatch_types == CS_DISPATCH_ONE || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { + cont = 0; + } + } while (cont); + +error_put: + (void)hdb_handle_put (&quorum_handle_t_db, handle); + return (error); +} diff --git a/lib/sam.c b/lib/sam.c new file mode 100644 index 0000000..94dbf2a --- /dev/null +++ b/lib/sam.c @@ -0,0 +1,1489 @@ +/* + * Copyright (c) 2009-2011 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Jan Friesse (jfriesse@redhat.com) + * + * 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. + */ + +/* + * Provides a SAM API + */ + +#include <config.h> + +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> +#include <poll.h> + +#include <corosync/corotypes.h> +#include <qb/qbipcc.h> +#include <corosync/corodefs.h> +#include <corosync/cmap.h> +#include <corosync/hdb.h> +#include <corosync/quorum.h> + +#include <corosync/sam.h> + +#include "util.h" + +#include <stdio.h> +#include <sys/wait.h> +#include <signal.h> + +#define SAM_CMAP_S_FAILED "failed" +#define SAM_CMAP_S_REGISTERED "stopped" +#define SAM_CMAP_S_STARTED "running" +#define SAM_CMAP_S_Q_WAIT "waiting for quorum" + +#define SAM_RP_MASK_Q(pol) (pol & (~SAM_RECOVERY_POLICY_QUORUM)) +#define SAM_RP_MASK_C(pol) (pol & (~SAM_RECOVERY_POLICY_CMAP)) +#define SAM_RP_MASK(pol) (pol & (~(SAM_RECOVERY_POLICY_QUORUM | SAM_RECOVERY_POLICY_CMAP))) + +enum sam_internal_status_t { + SAM_INTERNAL_STATUS_NOT_INITIALIZED = 0, + SAM_INTERNAL_STATUS_INITIALIZED, + SAM_INTERNAL_STATUS_REGISTERED, + SAM_INTERNAL_STATUS_STARTED, + SAM_INTERNAL_STATUS_FINALIZED +}; + +enum sam_command_t { + SAM_COMMAND_START, + SAM_COMMAND_STOP, + SAM_COMMAND_HB, + SAM_COMMAND_DATA_STORE, + SAM_COMMAND_WARN_SIGNAL_SET, + SAM_COMMAND_MARK_FAILED, +}; + +enum sam_reply_t { + SAM_REPLY_OK, + SAM_REPLY_ERROR, +}; + +enum sam_parent_action_t { + SAM_PARENT_ACTION_ERROR, + SAM_PARENT_ACTION_RECOVERY, + SAM_PARENT_ACTION_QUIT, + SAM_PARENT_ACTION_CONTINUE +}; + +enum sam_cmap_key_t { + SAM_CMAP_KEY_RECOVERY, + SAM_CMAP_KEY_HC_PERIOD, + SAM_CMAP_KEY_LAST_HC, + SAM_CMAP_KEY_STATE, +}; + +static struct { + int time_interval; + sam_recovery_policy_t recovery_policy; + enum sam_internal_status_t internal_status; + unsigned int instance_id; + int child_fd_out; + int child_fd_in; + int term_send; + int warn_signal; + int am_i_child; + + sam_hc_callback_t hc_callback; + pthread_t cb_thread; + int cb_rpipe_fd, cb_wpipe_fd; + int cb_registered; + + void *user_data; + size_t user_data_size; + size_t user_data_allocated; + + pthread_mutex_t lock; + + quorum_handle_t quorum_handle; + uint32_t quorate; + int quorum_fd; + + cmap_handle_t cmap_handle; + char cmap_pid_path[CMAP_KEYNAME_MAXLEN]; +} sam_internal_data; + +extern const char *__progname; + +static cs_error_t sam_cmap_update_key (enum sam_cmap_key_t key, const char *value) +{ + cs_error_t err; + const char *svalue; + uint64_t hc_period, last_hc; + + const char *ssvalue[] = { [SAM_RECOVERY_POLICY_QUIT] = "quit", [SAM_RECOVERY_POLICY_RESTART] = "restart" }; + char key_name[CMAP_KEYNAME_MAXLEN]; + + switch (key) { + case SAM_CMAP_KEY_RECOVERY: + svalue = ssvalue[SAM_RP_MASK (sam_internal_data.recovery_policy)]; + + if (snprintf(key_name, CMAP_KEYNAME_MAXLEN, "%s%s", sam_internal_data.cmap_pid_path, + "recovery") >= CMAP_KEYNAME_MAXLEN) { + + err = CS_ERR_NAME_TOO_LONG; + goto exit_error; + } + + if ((err = cmap_set_string(sam_internal_data.cmap_handle, key_name, svalue)) != CS_OK) { + goto exit_error; + } + break; + case SAM_CMAP_KEY_HC_PERIOD: + hc_period = sam_internal_data.time_interval; + + if (snprintf(key_name, CMAP_KEYNAME_MAXLEN, "%s%s", sam_internal_data.cmap_pid_path, + "poll_period") >= CMAP_KEYNAME_MAXLEN) { + + err = CS_ERR_NAME_TOO_LONG; + goto exit_error; + } + + if ((err = cmap_set_uint64(sam_internal_data.cmap_handle, key_name, hc_period)) != CS_OK) { + goto exit_error; + } + break; + case SAM_CMAP_KEY_LAST_HC: + last_hc = cs_timestamp_get(); + + if (snprintf(key_name, CMAP_KEYNAME_MAXLEN, "%s%s", sam_internal_data.cmap_pid_path, + "last_updated") >= CMAP_KEYNAME_MAXLEN) { + + err = CS_ERR_NAME_TOO_LONG; + goto exit_error; + } + if ((err = cmap_set_uint64(sam_internal_data.cmap_handle, key_name, last_hc)) != CS_OK) { + goto exit_error; + } + break; + case SAM_CMAP_KEY_STATE: + svalue = value; + if (snprintf(key_name, CMAP_KEYNAME_MAXLEN, "%s%s", sam_internal_data.cmap_pid_path, + "state") >= CMAP_KEYNAME_MAXLEN) { + + err = CS_ERR_NAME_TOO_LONG; + goto exit_error; + } + + if ((err = cmap_set_string(sam_internal_data.cmap_handle, key_name, svalue)) != CS_OK) { + goto exit_error; + } + break; + } + + return (CS_OK); + +exit_error: + return (err); +} + +static cs_error_t sam_cmap_destroy_pid_path (void) +{ + cmap_iter_handle_t iter; + cs_error_t err; + char key_name[CMAP_KEYNAME_MAXLEN + 1]; + + err = cmap_iter_init(sam_internal_data.cmap_handle, sam_internal_data.cmap_pid_path, &iter); + if (err != CS_OK) { + goto error_exit; + } + + while ((err = cmap_iter_next(sam_internal_data.cmap_handle, iter, key_name, NULL, NULL)) == CS_OK) { + cmap_delete(sam_internal_data.cmap_handle, key_name); + } + + err = cmap_iter_finalize(sam_internal_data.cmap_handle, iter); + +error_exit: + return (err); +} + +static cs_error_t sam_cmap_register (void) +{ + cs_error_t err; + cmap_handle_t cmap_handle; + + if ((err = cmap_initialize (&cmap_handle)) != CS_OK) { + return (err); + } + + snprintf(sam_internal_data.cmap_pid_path, CMAP_KEYNAME_MAXLEN, "resources.process.%d.", getpid()); + + sam_internal_data.cmap_handle = cmap_handle; + + if ((err = sam_cmap_update_key (SAM_CMAP_KEY_RECOVERY, NULL)) != CS_OK) { + goto destroy_finalize_error; + } + + if ((err = sam_cmap_update_key (SAM_CMAP_KEY_HC_PERIOD, NULL)) != CS_OK) { + goto destroy_finalize_error; + } + + return (CS_OK); + +destroy_finalize_error: + sam_cmap_destroy_pid_path (); + cmap_finalize (cmap_handle); + return (err); +} + +static void quorum_notification_fn ( + quorum_handle_t handle, + uint32_t quorate, + uint64_t ring_id, + uint32_t view_list_entries, + uint32_t *view_list) +{ + sam_internal_data.quorate = quorate; +} + +cs_error_t sam_initialize ( + int time_interval, + sam_recovery_policy_t recovery_policy) +{ + quorum_callbacks_t quorum_callbacks; + uint32_t quorum_type; + cs_error_t err; + + if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_NOT_INITIALIZED) { + return (CS_ERR_BAD_HANDLE); + } + + if (SAM_RP_MASK (recovery_policy) != SAM_RECOVERY_POLICY_QUIT && + SAM_RP_MASK (recovery_policy) != SAM_RECOVERY_POLICY_RESTART) { + return (CS_ERR_INVALID_PARAM); + } + + if (recovery_policy & SAM_RECOVERY_POLICY_QUORUM) { + /* + * Initialize quorum + */ + quorum_callbacks.quorum_notify_fn = quorum_notification_fn; + if ((err = quorum_initialize (&sam_internal_data.quorum_handle, &quorum_callbacks, &quorum_type)) != CS_OK) { + goto exit_error; + } + + if ((err = quorum_trackstart (sam_internal_data.quorum_handle, CS_TRACK_CHANGES)) != CS_OK) { + goto exit_error_quorum; + } + + if ((err = quorum_fd_get (sam_internal_data.quorum_handle, &sam_internal_data.quorum_fd)) != CS_OK) { + goto exit_error_quorum; + } + + /* + * Dispatch initial quorate state + */ + if ((err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ONE)) != CS_OK) { + goto exit_error_quorum; + } + } + sam_internal_data.recovery_policy = recovery_policy; + + sam_internal_data.time_interval = time_interval; + + sam_internal_data.internal_status = SAM_INTERNAL_STATUS_INITIALIZED; + + sam_internal_data.warn_signal = SIGTERM; + + sam_internal_data.am_i_child = 0; + + sam_internal_data.user_data = NULL; + sam_internal_data.user_data_size = 0; + sam_internal_data.user_data_allocated = 0; + + pthread_mutex_init (&sam_internal_data.lock, NULL); + + return (CS_OK); + +exit_error_quorum: + quorum_finalize (sam_internal_data.quorum_handle); +exit_error: + return (err); +} + +/* + * Wrapper on top of write(2) function. It handles EAGAIN and EINTR states and sends whole buffer if possible. + */ +static size_t sam_safe_write ( + int d, + const void *buf, + size_t nbyte) +{ + ssize_t bytes_write; + ssize_t tmp_bytes_write; + + bytes_write = 0; + + do { + tmp_bytes_write = write (d, (const char *)buf + bytes_write, + (nbyte - bytes_write > SSIZE_MAX) ? SSIZE_MAX : nbyte - bytes_write); + + if (tmp_bytes_write == -1) { + if (!(errno == EAGAIN || errno == EINTR)) + return -1; + } else { + bytes_write += tmp_bytes_write; + } + } while (bytes_write != nbyte); + + return (bytes_write); +} + +/* + * Wrapper on top of read(2) function. It handles EAGAIN and EINTR states and reads whole buffer if possible. + */ +static size_t sam_safe_read ( + int d, + void *buf, + size_t nbyte) +{ + ssize_t bytes_read; + ssize_t tmp_bytes_read; + + bytes_read = 0; + + do { + tmp_bytes_read = read (d, (char *)buf + bytes_read, + (nbyte - bytes_read > SSIZE_MAX) ? SSIZE_MAX : nbyte - bytes_read); + + if (tmp_bytes_read == -1) { + if (!(errno == EAGAIN || errno == EINTR)) + return -1; + } else { + bytes_read += tmp_bytes_read; + } + + } while (bytes_read != nbyte && tmp_bytes_read != 0); + + return (bytes_read); +} + +static cs_error_t sam_read_reply ( + int child_fd_in) +{ + char reply; + cs_error_t err; + + if (sam_safe_read (sam_internal_data.child_fd_in, &reply, sizeof (reply)) != sizeof (reply)) { + return (CS_ERR_LIBRARY); + } + + switch (reply) { + case SAM_REPLY_ERROR: + /* + * Read error and return that + */ + if (sam_safe_read (sam_internal_data.child_fd_in, &err, sizeof (err)) != sizeof (err)) { + return (CS_ERR_LIBRARY); + } + + return (err); + break; + case SAM_REPLY_OK: + /* + * Everything correct + */ + break; + default: + return (CS_ERR_LIBRARY); + break; + } + + return (CS_OK); +} + +cs_error_t sam_data_getsize (size_t *size) +{ + if (size == NULL) { + return (CS_ERR_INVALID_PARAM); + } + + if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED && + sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED && + sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) { + + return (CS_ERR_BAD_HANDLE); + } + + pthread_mutex_lock (&sam_internal_data.lock); + + *size = sam_internal_data.user_data_size; + + pthread_mutex_unlock (&sam_internal_data.lock); + + return (CS_OK); +} + +cs_error_t sam_data_restore ( + void *data, + size_t size) +{ + cs_error_t err; + + err = CS_OK; + + if (data == NULL) { + return (CS_ERR_INVALID_PARAM); + } + + if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED && + sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED && + sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) { + + return (CS_ERR_BAD_HANDLE); + } + + pthread_mutex_lock (&sam_internal_data.lock); + + if (sam_internal_data.user_data_size == 0) { + err = CS_OK; + + goto error_unlock; + } + + if (size < sam_internal_data.user_data_size) { + err = CS_ERR_INVALID_PARAM; + + goto error_unlock; + } + + memcpy (data, sam_internal_data.user_data, sam_internal_data.user_data_size); + + pthread_mutex_unlock (&sam_internal_data.lock); + + return (CS_OK); + +error_unlock: + pthread_mutex_unlock (&sam_internal_data.lock); + + return (err); +} + +cs_error_t sam_data_store ( + const void *data, + size_t size) +{ + cs_error_t err; + char command; + char *new_data; + + if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED && + sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED && + sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) { + + return (CS_ERR_BAD_HANDLE); + } + + + if (data == NULL) { + size = 0; + } + + pthread_mutex_lock (&sam_internal_data.lock); + + if (sam_internal_data.am_i_child) { + /* + * We are child so we must send data to parent + */ + command = SAM_COMMAND_DATA_STORE; + if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) { + err = CS_ERR_LIBRARY; + + goto error_unlock; + } + + if (sam_safe_write (sam_internal_data.child_fd_out, &size, sizeof (size)) != sizeof (size)) { + err = CS_ERR_LIBRARY; + + goto error_unlock; + } + + if (data != NULL && sam_safe_write (sam_internal_data.child_fd_out, data, size) != size) { + err = CS_ERR_LIBRARY; + + goto error_unlock; + } + + /* + * And wait for reply + */ + if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) { + goto error_unlock; + } + } + + /* + * We are parent or we received OK reply from parent -> do required action + */ + if (data == NULL) { + free (sam_internal_data.user_data); + sam_internal_data.user_data = NULL; + sam_internal_data.user_data_allocated = 0; + sam_internal_data.user_data_size = 0; + } else { + if (sam_internal_data.user_data_allocated < size) { + if ((new_data = realloc (sam_internal_data.user_data, size)) == NULL) { + err = CS_ERR_NO_MEMORY; + + goto error_unlock; + } + + sam_internal_data.user_data_allocated = size; + } else { + new_data = sam_internal_data.user_data; + } + sam_internal_data.user_data = new_data; + sam_internal_data.user_data_size = size; + + memcpy (sam_internal_data.user_data, data, size); + } + + pthread_mutex_unlock (&sam_internal_data.lock); + + return (CS_OK); + +error_unlock: + pthread_mutex_unlock (&sam_internal_data.lock); + + return (err); +} + +cs_error_t sam_start (void) +{ + char command; + cs_error_t err; + sam_recovery_policy_t recpol; + + if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED) { + return (CS_ERR_BAD_HANDLE); + } + + recpol = sam_internal_data.recovery_policy; + + if (recpol & SAM_RECOVERY_POLICY_QUORUM || recpol & SAM_RECOVERY_POLICY_CMAP) { + pthread_mutex_lock (&sam_internal_data.lock); + } + + command = SAM_COMMAND_START; + + if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) { + if (recpol & SAM_RECOVERY_POLICY_QUORUM || recpol & SAM_RECOVERY_POLICY_CMAP) { + pthread_mutex_unlock (&sam_internal_data.lock); + } + + return (CS_ERR_LIBRARY); + } + + if (recpol & SAM_RECOVERY_POLICY_QUORUM || recpol & SAM_RECOVERY_POLICY_CMAP) { + /* + * Wait for parent reply + */ + if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) { + pthread_mutex_unlock (&sam_internal_data.lock); + + return (err); + } + + pthread_mutex_unlock (&sam_internal_data.lock); + } + + if (sam_internal_data.hc_callback) + if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, sizeof (command)) != sizeof (command)) + return (CS_ERR_LIBRARY); + + sam_internal_data.internal_status = SAM_INTERNAL_STATUS_STARTED; + + return (CS_OK); +} + +cs_error_t sam_stop (void) +{ + char command; + cs_error_t err; + + if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) { + return (CS_ERR_BAD_HANDLE); + } + + command = SAM_COMMAND_STOP; + + if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) { + pthread_mutex_lock (&sam_internal_data.lock); + } + + if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) { + if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) { + pthread_mutex_unlock (&sam_internal_data.lock); + } + + return (CS_ERR_LIBRARY); + } + + if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) { + /* + * Wait for parent reply + */ + if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) { + pthread_mutex_unlock (&sam_internal_data.lock); + + return (err); + } + + pthread_mutex_unlock (&sam_internal_data.lock); + } + + if (sam_internal_data.hc_callback) + if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, sizeof (command)) != sizeof (command)) + return (CS_ERR_LIBRARY); + + sam_internal_data.internal_status = SAM_INTERNAL_STATUS_REGISTERED; + + return (CS_OK); +} + +cs_error_t sam_hc_send (void) +{ + char command; + + if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) { + return (CS_ERR_BAD_HANDLE); + } + + command = SAM_COMMAND_HB; + + if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) + return (CS_ERR_LIBRARY); + + return (CS_OK); +} + +cs_error_t sam_finalize (void) +{ + cs_error_t error; + + if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED && + sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED && + sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) { + return (CS_ERR_BAD_HANDLE); + } + + if (sam_internal_data.internal_status == SAM_INTERNAL_STATUS_STARTED) { + error = sam_stop (); + if (error != CS_OK) + goto exit_error; + } + + sam_internal_data.internal_status = SAM_INTERNAL_STATUS_FINALIZED; + + free (sam_internal_data.user_data); + +exit_error: + return (CS_OK); +} + +cs_error_t sam_mark_failed (void) +{ + char command; + + if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED && + sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED) { + return (CS_ERR_BAD_HANDLE); + } + + if (!(sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP)) { + return (CS_ERR_INVALID_PARAM); + } + + command = SAM_COMMAND_MARK_FAILED; + + if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) + return (CS_ERR_LIBRARY); + + return (CS_OK); +} + +cs_error_t sam_warn_signal_set (int warn_signal) +{ + char command; + cs_error_t err; + + if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED && + sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED && + sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) { + return (CS_ERR_BAD_HANDLE); + } + + pthread_mutex_lock (&sam_internal_data.lock); + + if (sam_internal_data.am_i_child) { + /* + * We are child so we must send data to parent + */ + command = SAM_COMMAND_WARN_SIGNAL_SET; + if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) { + err = CS_ERR_LIBRARY; + + goto error_unlock; + } + + if (sam_safe_write (sam_internal_data.child_fd_out, &warn_signal, sizeof (warn_signal)) != + sizeof (warn_signal)) { + err = CS_ERR_LIBRARY; + + goto error_unlock; + } + + /* + * And wait for reply + */ + if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) { + goto error_unlock; + } + } + + /* + * We are parent or we received OK reply from parent -> do required action + */ + sam_internal_data.warn_signal = warn_signal; + + pthread_mutex_unlock (&sam_internal_data.lock); + + return (CS_OK); + +error_unlock: + pthread_mutex_unlock (&sam_internal_data.lock); + + return (err); +} + +static cs_error_t sam_parent_reply_send ( + cs_error_t err, + int parent_fd_in, + int parent_fd_out) +{ + char reply; + + if (err == CS_OK) { + reply = SAM_REPLY_OK; + + if (sam_safe_write (parent_fd_out, &reply, sizeof (reply)) != sizeof (reply)) { + err = CS_ERR_LIBRARY; + goto error_reply; + } + + return (CS_OK); + } + +error_reply: + reply = SAM_REPLY_ERROR; + if (sam_safe_write (parent_fd_out, &reply, sizeof (reply)) != sizeof (reply)) { + return (CS_ERR_LIBRARY); + } + if (sam_safe_write (parent_fd_out, &err, sizeof (err)) != sizeof (err)) { + return (CS_ERR_LIBRARY); + } + + return (err); +} + + +static cs_error_t sam_parent_warn_signal_set ( + int parent_fd_in, + int parent_fd_out) +{ + int warn_signal; + cs_error_t err; + + err = CS_OK; + + if (sam_safe_read (parent_fd_in, &warn_signal, sizeof (warn_signal)) != sizeof (warn_signal)) { + err = CS_ERR_LIBRARY; + goto error_reply; + } + + err = sam_warn_signal_set (warn_signal); + if (err != CS_OK) { + goto error_reply; + } + + + return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out)); + +error_reply: + return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out)); +} + +static cs_error_t sam_parent_wait_for_quorum ( + int parent_fd_in, + int parent_fd_out) +{ + cs_error_t err; + struct pollfd pfds[2]; + int poll_err; + + if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) { + if ((err = sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_Q_WAIT)) != CS_OK) { + goto error_reply; + } + } + + /* + * Update current quorum + */ + if ((err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ALL)) != CS_OK) { + goto error_reply; + } + + /* + * Wait for quorum + */ + while (!sam_internal_data.quorate) { + pfds[0].fd = parent_fd_in; + pfds[0].events = 0; + pfds[0].revents = 0; + + pfds[1].fd = sam_internal_data.quorum_fd; + pfds[1].events = POLLIN; + pfds[1].revents = 0; + + poll_err = poll (pfds, 2, -1); + + if (poll_err == -1) { + /* + * Error in poll + * If it is EINTR, continue, otherwise QUIT + */ + if (errno != EINTR) { + err = CS_ERR_LIBRARY; + goto error_reply; + } + } + + if (pfds[0].revents != 0) { + if (pfds[0].revents == POLLERR || pfds[0].revents == POLLHUP ||pfds[0].revents == POLLNVAL) { + /* + * Child has exited + */ + return (CS_OK); + } + } + + if (pfds[1].revents != 0) { + if ((err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ONE)) != CS_OK) { + goto error_reply; + } + } + } + + if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) { + if ((err = sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_STARTED)) != CS_OK) { + goto error_reply; + } + } + + return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out)); + +error_reply: + if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) { + sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_REGISTERED); + } + + return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out)); +} + +static cs_error_t sam_parent_cmap_state_set ( + int parent_fd_in, + int parent_fd_out, + int state) +{ + cs_error_t err; + const char *state_s; + + if (state == 1) { + state_s = SAM_CMAP_S_STARTED; + } else { + state_s = SAM_CMAP_S_REGISTERED; + } + + if ((err = sam_cmap_update_key (SAM_CMAP_KEY_STATE, state_s)) != CS_OK) { + goto error_reply; + } + + return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out)); + +error_reply: + return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out)); +} + +static cs_error_t sam_parent_kill_child ( + int *action, + pid_t child_pid) +{ + /* + * Kill child process + */ + if (!sam_internal_data.term_send) { + /* + * We didn't send warn_signal yet. + */ + kill (child_pid, sam_internal_data.warn_signal); + + sam_internal_data.term_send = 1; + } else { + /* + * We sent child warning. Now, we will not be so nice + */ + kill (child_pid, SIGKILL); + *action = SAM_PARENT_ACTION_RECOVERY; + } + + return (CS_OK); +} + +static cs_error_t sam_parent_mark_child_failed ( + int *action, + pid_t child_pid) +{ + sam_recovery_policy_t recpol; + + recpol = sam_internal_data.recovery_policy; + + sam_internal_data.term_send = 1; + sam_internal_data.recovery_policy = SAM_RECOVERY_POLICY_QUIT | + (SAM_RP_MASK_C (recpol) ? SAM_RECOVERY_POLICY_CMAP : 0) | + (SAM_RP_MASK_Q (recpol) ? SAM_RECOVERY_POLICY_QUORUM : 0); + + return (sam_parent_kill_child (action, child_pid)); +} + +static cs_error_t sam_parent_data_store ( + int parent_fd_in, + int parent_fd_out) +{ + char *user_data; + ssize_t size; + cs_error_t err; + + err = CS_OK; + user_data = NULL; + + if (sam_safe_read (parent_fd_in, &size, sizeof (size)) != sizeof (size)) { + err = CS_ERR_LIBRARY; + goto error_reply; + } + + if (size > 0) { + user_data = malloc (size); + if (user_data == NULL) { + err = CS_ERR_NO_MEMORY; + goto error_reply; + } + + if (sam_safe_read (parent_fd_in, user_data, size) != size) { + err = CS_ERR_LIBRARY; + goto free_error_reply; + } + } + + err = sam_data_store (user_data, size); + if (err != CS_OK) { + goto free_error_reply; + } + + free (user_data); + + return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out)); + +free_error_reply: + free (user_data); +error_reply: + return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out)); +} + +static enum sam_parent_action_t sam_parent_handler ( + int parent_fd_in, + int parent_fd_out, + pid_t child_pid) +{ + int poll_error; + int action; + int status; + ssize_t bytes_read; + char command; + int time_interval; + struct pollfd pfds[2]; + nfds_t nfds; + cs_error_t err; + sam_recovery_policy_t recpol; + + status = 0; + + action = SAM_PARENT_ACTION_CONTINUE; + recpol = sam_internal_data.recovery_policy; + + while (action == SAM_PARENT_ACTION_CONTINUE) { + pfds[0].fd = parent_fd_in; + pfds[0].events = POLLIN; + pfds[0].revents = 0; + nfds = 1; + + if (status == 1 && sam_internal_data.time_interval != 0) { + time_interval = sam_internal_data.time_interval; + } else { + time_interval = -1; + } + + if (recpol & SAM_RECOVERY_POLICY_QUORUM) { + pfds[nfds].fd = sam_internal_data.quorum_fd; + pfds[nfds].events = POLLIN; + pfds[nfds].revents = 0; + nfds++; + } + + poll_error = poll (pfds, nfds, time_interval); + + if (poll_error == -1) { + /* + * Error in poll + * If it is EINTR, continue, otherwise QUIT + */ + if (errno != EINTR) { + action = SAM_PARENT_ACTION_ERROR; + } + } + + if (poll_error == 0) { + /* + * Time limit expires + */ + if (status == 0) { + action = SAM_PARENT_ACTION_QUIT; + } else { + sam_parent_kill_child (&action, child_pid); + } + } + + if (poll_error > 0) { + if (pfds[0].revents != 0) { + /* + * We have EOF or command in pipe + */ + bytes_read = sam_safe_read (parent_fd_in, &command, 1); + + if (bytes_read == 0) { + /* + * Handle EOF -> Take recovery action or quit if sam_start wasn't called + */ + if (status == 0) + action = SAM_PARENT_ACTION_QUIT; + else + action = SAM_PARENT_ACTION_RECOVERY; + + continue; + } + + if (bytes_read == -1) { + action = SAM_PARENT_ACTION_ERROR; + goto action_exit; + } + + if (recpol & SAM_RECOVERY_POLICY_CMAP) { + sam_cmap_update_key (SAM_CMAP_KEY_LAST_HC, NULL); + } + + /* + * We have read command + */ + switch (command) { + case SAM_COMMAND_START: + if (status == 0) { + /* + * Not started yet + */ + if (recpol & SAM_RECOVERY_POLICY_QUORUM) { + if (sam_parent_wait_for_quorum (parent_fd_in, + parent_fd_out) != CS_OK) { + continue; + } + } + + if (recpol & SAM_RECOVERY_POLICY_CMAP) { + if (sam_parent_cmap_state_set (parent_fd_in, + parent_fd_out, 1) != CS_OK) { + continue; + } + } + + status = 1; + } + break; + case SAM_COMMAND_STOP: + if (status == 1) { + /* + * Started + */ + if (recpol & SAM_RECOVERY_POLICY_CMAP) { + if (sam_parent_cmap_state_set (parent_fd_in, + parent_fd_out, 0) != CS_OK) { + continue; + } + } + + status = 0; + } + break; + case SAM_COMMAND_DATA_STORE: + sam_parent_data_store (parent_fd_in, parent_fd_out); + break; + case SAM_COMMAND_WARN_SIGNAL_SET: + sam_parent_warn_signal_set (parent_fd_in, parent_fd_out); + break; + case SAM_COMMAND_MARK_FAILED: + status = 1; + sam_parent_mark_child_failed (&action, child_pid); + break; + } + } /* if (pfds[0].revents != 0) */ + + if ((sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_QUORUM) && + pfds[1].revents != 0) { + /* + * Handle quorum change + */ + err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ALL); + + if (status == 1 && + (!sam_internal_data.quorate || (err != CS_ERR_TRY_AGAIN && err != CS_OK))) { + sam_parent_kill_child (&action, child_pid); + } + } + } /* select_error > 0 */ + } /* action == SAM_PARENT_ACTION_CONTINUE */ + +action_exit: + return action; +} + +cs_error_t sam_register ( + unsigned int *instance_id) +{ + cs_error_t error; + pid_t pid; + int pipe_error; + int pipe_fd_out[2], pipe_fd_in[2]; + enum sam_parent_action_t action, old_action; + int child_status; + sam_recovery_policy_t recpol; + + if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED) { + return (CS_ERR_BAD_HANDLE); + } + + recpol = sam_internal_data.recovery_policy; + + if (recpol & SAM_RECOVERY_POLICY_CMAP) { + /* + * Register to cmap + */ + if ((error = sam_cmap_register ()) != CS_OK) { + goto error_exit; + } + } + + error = CS_OK; + + while (1) { + if ((pipe_error = pipe (pipe_fd_out)) != 0) { + error = CS_ERR_LIBRARY; + goto error_exit; + } + + if ((pipe_error = pipe (pipe_fd_in)) != 0) { + close (pipe_fd_out[0]); + close (pipe_fd_out[1]); + + error = CS_ERR_LIBRARY; + goto error_exit; + } + + if (recpol & SAM_RECOVERY_POLICY_CMAP) { + if ((error = sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_REGISTERED)) != CS_OK) { + goto error_exit; + } + } + + sam_internal_data.instance_id++; + + sam_internal_data.term_send = 0; + + pid = fork (); + + if (pid == -1) { + /* + * Fork error + */ + sam_internal_data.instance_id--; + + error = CS_ERR_LIBRARY; + goto error_exit; + } + + if (pid == 0) { + /* + * Child process + */ + close (pipe_fd_out[0]); + close (pipe_fd_in[1]); + + sam_internal_data.child_fd_out = pipe_fd_out[1]; + sam_internal_data.child_fd_in = pipe_fd_in[0]; + + if (instance_id) + *instance_id = sam_internal_data.instance_id; + + sam_internal_data.am_i_child = 1; + sam_internal_data.internal_status = SAM_INTERNAL_STATUS_REGISTERED; + + pthread_mutex_init (&sam_internal_data.lock, NULL); + + goto error_exit; + } else { + /* + * Parent process + */ + close (pipe_fd_out[1]); + close (pipe_fd_in[0]); + + action = sam_parent_handler (pipe_fd_out[0], pipe_fd_in[1], pid); + + close (pipe_fd_out[0]); + close (pipe_fd_in[1]); + + if (action == SAM_PARENT_ACTION_ERROR) { + error = CS_ERR_LIBRARY; + goto error_exit; + } + + /* + * We really don't like zombies + */ + while (waitpid (pid, &child_status, 0) == -1 && errno == EINTR) + ; + + old_action = action; + + if (action == SAM_PARENT_ACTION_RECOVERY) { + if (SAM_RP_MASK (sam_internal_data.recovery_policy) == SAM_RECOVERY_POLICY_QUIT) + action = SAM_PARENT_ACTION_QUIT; + } + + + if (action == SAM_PARENT_ACTION_QUIT) { + if (recpol & SAM_RECOVERY_POLICY_QUORUM) { + quorum_finalize (sam_internal_data.quorum_handle); + } + + if (recpol & SAM_RECOVERY_POLICY_CMAP) { + if (old_action == SAM_PARENT_ACTION_RECOVERY) { + /* + * Mark as failed + */ + sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_FAILED); + } else { + sam_cmap_destroy_pid_path (); + } + } + + exit (WEXITSTATUS (child_status)); + } + + + } + } + +error_exit: + return (error); +} + +static void *hc_callback_thread (void *unused_param) +{ + int poll_error; + int status; + ssize_t bytes_readed; + char command; + int time_interval, tmp_time_interval; + int counter; + struct pollfd pfds; + + status = 0; + counter = 0; + + time_interval = sam_internal_data.time_interval >> 2; + + while (1) { + pfds.fd = sam_internal_data.cb_rpipe_fd; + pfds.events = POLLIN; + pfds.revents = 0; + + if (status == 1) { + tmp_time_interval = time_interval; + } else { + tmp_time_interval = -1; + } + + poll_error = poll (&pfds, 1, tmp_time_interval); + + if (poll_error == 0) { + if (sam_hc_send () == CS_OK) { + counter++; + } + + if (counter >= 4) { + if (sam_internal_data.hc_callback () != 0) { + status = 3; + } + + counter = 0; + } + } + + if (poll_error > 0) { + bytes_readed = sam_safe_read (sam_internal_data.cb_rpipe_fd, &command, 1); + + if (bytes_readed > 0) { + if (status == 0 && command == SAM_COMMAND_START) + status = 1; + + if (status == 1 && command == SAM_COMMAND_STOP) + status = 0; + + } + } + } + + /* + * This makes compiler happy, it's same as return (NULL); + */ + return (unused_param); +} + +cs_error_t sam_hc_callback_register (sam_hc_callback_t cb) +{ + cs_error_t error = CS_OK; + pthread_attr_t thread_attr; + int pipe_error; + int pipe_fd[2]; + + if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED) { + return (CS_ERR_BAD_HANDLE); + } + + if (sam_internal_data.time_interval == 0) { + return (CS_ERR_INVALID_PARAM); + } + + if (sam_internal_data.cb_registered) { + sam_internal_data.hc_callback = cb; + + return (CS_OK); + } + + /* + * We know, this is first registration + */ + + if (cb == NULL) { + return (CS_ERR_INVALID_PARAM); + } + + pipe_error = pipe (pipe_fd); + + if (pipe_error != 0) { + /* + * Pipe creation error + */ + error = CS_ERR_LIBRARY; + goto error_exit; + } + + sam_internal_data.cb_rpipe_fd = pipe_fd[0]; + sam_internal_data.cb_wpipe_fd = pipe_fd[1]; + + /* + * Create thread attributes + */ + error = pthread_attr_init (&thread_attr); + if (error != 0) { + error = CS_ERR_LIBRARY; + goto error_close_fd_exit; + } + + + pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setstacksize (&thread_attr, 32768); + + /* + * Create thread + */ + error = pthread_create (&sam_internal_data.cb_thread, &thread_attr, hc_callback_thread, NULL); + + if (error != 0) { + error = CS_ERR_LIBRARY; + goto error_attr_destroy_exit; + } + + /* + * Cleanup + */ + pthread_attr_destroy(&thread_attr); + + sam_internal_data.cb_registered = 1; + sam_internal_data.hc_callback = cb; + + return (CS_OK); + +error_attr_destroy_exit: + pthread_attr_destroy(&thread_attr); +error_close_fd_exit: + sam_internal_data.cb_rpipe_fd = sam_internal_data.cb_wpipe_fd = 0; + close (pipe_fd[0]); + close (pipe_fd[1]); +error_exit: + return (error); +} diff --git a/lib/util.h b/lib/util.h new file mode 100644 index 0000000..a1610a7 --- /dev/null +++ b/lib/util.h @@ -0,0 +1,54 @@ + +/* + * Copyright (c) 2002-2003 MontaVista Software, Inc. + * Copyright (c) 2012 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Steven Dake (sdake@redhat.com) + * + * 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 MontaVista Software, 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_UTIL_H_DEFINED +#define COROSYNC_UTIL_H_DEFINED + +#include <corosync/corotypes.h> + +cs_error_t hdb_error_to_cs (int res); + +#ifdef HAVE_SMALL_MEMORY_FOOTPRINT +#define IPC_REQUEST_SIZE 1024*64 +#define IPC_RESPONSE_SIZE 1024*64 +#define IPC_DISPATCH_SIZE 1024*64 +#else +#define IPC_REQUEST_SIZE 8192*128 +#define IPC_RESPONSE_SIZE 8192*128 +#define IPC_DISPATCH_SIZE 8192*128 +#endif /* HAVE_SMALL_MEMORY_FOOTPRINT */ + +#endif /* COROSYNC_UTIL_H_DEFINED */ diff --git a/lib/votequorum.c b/lib/votequorum.c new file mode 100644 index 0000000..4bcac22 --- /dev/null +++ b/lib/votequorum.c @@ -0,0 +1,811 @@ +/* + * Copyright (c) 2009-2012 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Christine Caulfield (ccaulfie@redhat.com) + * + * 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 MontaVista Software, 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 CONTIBUTORS "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. + */ + +/* + * Provides a quorum API using the corosync executive + */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <errno.h> + +#include <qb/qbdefs.h> +#include <qb/qbipcc.h> + +#include <corosync/corotypes.h> +#include <corosync/corodefs.h> +#include <corosync/hdb.h> + +#include <corosync/votequorum.h> +#include <corosync/ipc_votequorum.h> + +#include "util.h" + +struct votequorum_inst { + qb_ipcc_connection_t *c; + int finalize; + void *context; + votequorum_callbacks_t callbacks; +}; + +static void votequorum_inst_free (void *inst); + +DECLARE_HDB_DATABASE(votequorum_handle_t_db, votequorum_inst_free); + +cs_error_t votequorum_initialize ( + votequorum_handle_t *handle, + votequorum_callbacks_t *callbacks) +{ + cs_error_t error; + struct votequorum_inst *votequorum_inst; + + error = hdb_error_to_cs(hdb_handle_create (&votequorum_handle_t_db, sizeof (struct votequorum_inst), handle)); + if (error != CS_OK) { + goto error_no_destroy; + } + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, *handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + goto error_destroy; + } + + votequorum_inst->finalize = 0; + votequorum_inst->c = qb_ipcc_connect ("votequorum", IPC_REQUEST_SIZE); + if (votequorum_inst->c == NULL) { + error = qb_to_cs_error(-errno); + goto error_put_destroy; + } + + if (callbacks) + memcpy(&votequorum_inst->callbacks, callbacks, sizeof (*callbacks)); + else + memset(&votequorum_inst->callbacks, 0, sizeof (*callbacks)); + + hdb_handle_put (&votequorum_handle_t_db, *handle); + + return (CS_OK); + +error_put_destroy: + hdb_handle_put (&votequorum_handle_t_db, *handle); +error_destroy: + hdb_handle_destroy (&votequorum_handle_t_db, *handle); +error_no_destroy: + return (error); +} + +static void votequorum_inst_free (void *inst) +{ + struct votequorum_inst *vq_inst = (struct votequorum_inst *)inst; + qb_ipcc_disconnect(vq_inst->c); +} + +cs_error_t votequorum_finalize ( + votequorum_handle_t handle) +{ + struct votequorum_inst *votequorum_inst; + cs_error_t error; + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + /* + * Another thread has already started finalizing + */ + if (votequorum_inst->finalize) { + hdb_handle_put (&votequorum_handle_t_db, handle); + return (CS_ERR_BAD_HANDLE); + } + + votequorum_inst->finalize = 1; + + hdb_handle_destroy (&votequorum_handle_t_db, handle); + + hdb_handle_put (&votequorum_handle_t_db, handle); + + return (CS_OK); +} + + +cs_error_t votequorum_getinfo ( + votequorum_handle_t handle, + unsigned int nodeid, + struct votequorum_info *info) +{ + cs_error_t error; + struct votequorum_inst *votequorum_inst; + struct iovec iov; + struct req_lib_votequorum_getinfo req_lib_votequorum_getinfo; + struct res_lib_votequorum_getinfo res_lib_votequorum_getinfo; + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_votequorum_getinfo.header.size = sizeof (struct req_lib_votequorum_getinfo); + req_lib_votequorum_getinfo.header.id = MESSAGE_REQ_VOTEQUORUM_GETINFO; + req_lib_votequorum_getinfo.nodeid = nodeid; + + iov.iov_base = (char *)&req_lib_votequorum_getinfo; + iov.iov_len = sizeof (struct req_lib_votequorum_getinfo); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + votequorum_inst->c, + &iov, + 1, + &res_lib_votequorum_getinfo, + sizeof (struct res_lib_votequorum_getinfo), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_votequorum_getinfo.header.error; + + info->node_id = res_lib_votequorum_getinfo.nodeid; + info->node_state = res_lib_votequorum_getinfo.state; + info->node_votes = res_lib_votequorum_getinfo.votes; + info->node_expected_votes = res_lib_votequorum_getinfo.expected_votes; + info->highest_expected = res_lib_votequorum_getinfo.highest_expected; + info->total_votes = res_lib_votequorum_getinfo.total_votes; + info->quorum = res_lib_votequorum_getinfo.quorum; + info->flags = res_lib_votequorum_getinfo.flags; + info->qdevice_votes = res_lib_votequorum_getinfo.qdevice_votes; + memset(info->qdevice_name, 0, VOTEQUORUM_QDEVICE_MAX_NAME_LEN); + strcpy(info->qdevice_name, res_lib_votequorum_getinfo.qdevice_name); + +error_exit: + hdb_handle_put (&votequorum_handle_t_db, handle); + + return (error); +} + +cs_error_t votequorum_setexpected ( + votequorum_handle_t handle, + unsigned int expected_votes) +{ + cs_error_t error; + struct votequorum_inst *votequorum_inst; + struct iovec iov; + struct req_lib_votequorum_setexpected req_lib_votequorum_setexpected; + struct res_lib_votequorum_status res_lib_votequorum_status; + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + + req_lib_votequorum_setexpected.header.size = sizeof (struct req_lib_votequorum_setexpected); + req_lib_votequorum_setexpected.header.id = MESSAGE_REQ_VOTEQUORUM_SETEXPECTED; + req_lib_votequorum_setexpected.expected_votes = expected_votes; + + iov.iov_base = (char *)&req_lib_votequorum_setexpected; + iov.iov_len = sizeof (struct req_lib_votequorum_setexpected); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + votequorum_inst->c, + &iov, + 1, + &res_lib_votequorum_status, + sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_votequorum_status.header.error; + +error_exit: + hdb_handle_put (&votequorum_handle_t_db, handle); + + return (error); +} + +cs_error_t votequorum_setvotes ( + votequorum_handle_t handle, + unsigned int nodeid, + unsigned int votes) +{ + cs_error_t error; + struct votequorum_inst *votequorum_inst; + struct iovec iov; + struct req_lib_votequorum_setvotes req_lib_votequorum_setvotes; + struct res_lib_votequorum_status res_lib_votequorum_status; + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_votequorum_setvotes.header.size = sizeof (struct req_lib_votequorum_setvotes); + req_lib_votequorum_setvotes.header.id = MESSAGE_REQ_VOTEQUORUM_SETVOTES; + req_lib_votequorum_setvotes.nodeid = nodeid; + req_lib_votequorum_setvotes.votes = votes; + + iov.iov_base = (char *)&req_lib_votequorum_setvotes; + iov.iov_len = sizeof (struct req_lib_votequorum_setvotes); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + votequorum_inst->c, + &iov, + 1, + &res_lib_votequorum_status, + sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_votequorum_status.header.error; + +error_exit: + hdb_handle_put (&votequorum_handle_t_db, handle); + + return (error); +} + +cs_error_t votequorum_trackstart ( + votequorum_handle_t handle, + uint64_t context, + unsigned int flags) +{ + cs_error_t error; + struct votequorum_inst *votequorum_inst; + struct iovec iov; + struct req_lib_votequorum_trackstart req_lib_votequorum_trackstart; + struct res_lib_votequorum_status res_lib_votequorum_status; + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_votequorum_trackstart.header.size = sizeof (struct req_lib_votequorum_trackstart); + req_lib_votequorum_trackstart.header.id = MESSAGE_REQ_VOTEQUORUM_TRACKSTART; + req_lib_votequorum_trackstart.track_flags = flags; + req_lib_votequorum_trackstart.context = context; + + iov.iov_base = (char *)&req_lib_votequorum_trackstart; + iov.iov_len = sizeof (struct req_lib_votequorum_trackstart); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + votequorum_inst->c, + &iov, + 1, + &res_lib_votequorum_status, + sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_votequorum_status.header.error; + +error_exit: + hdb_handle_put (&votequorum_handle_t_db, handle); + + return (error); +} + +cs_error_t votequorum_trackstop ( + votequorum_handle_t handle) +{ + cs_error_t error; + struct votequorum_inst *votequorum_inst; + struct iovec iov; + struct req_lib_votequorum_general req_lib_votequorum_general; + struct res_lib_votequorum_status res_lib_votequorum_status; + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_votequorum_general.header.size = sizeof (struct req_lib_votequorum_general); + req_lib_votequorum_general.header.id = MESSAGE_REQ_VOTEQUORUM_TRACKSTOP; + + iov.iov_base = (char *)&req_lib_votequorum_general; + iov.iov_len = sizeof (struct req_lib_votequorum_general); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + votequorum_inst->c, + &iov, + 1, + &res_lib_votequorum_status, + sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_votequorum_status.header.error; + +error_exit: + hdb_handle_put (&votequorum_handle_t_db, handle); + + return (error); +} + + +cs_error_t votequorum_context_get ( + votequorum_handle_t handle, + void **context) +{ + cs_error_t error; + struct votequorum_inst *votequorum_inst; + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + *context = votequorum_inst->context; + + hdb_handle_put (&votequorum_handle_t_db, handle); + + return (CS_OK); +} + +cs_error_t votequorum_context_set ( + votequorum_handle_t handle, + void *context) +{ + cs_error_t error; + struct votequorum_inst *votequorum_inst; + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + votequorum_inst->context = context; + + hdb_handle_put (&votequorum_handle_t_db, handle); + + return (CS_OK); +} + + +cs_error_t votequorum_fd_get ( + votequorum_handle_t handle, + int *fd) +{ + cs_error_t error; + struct votequorum_inst *votequorum_inst; + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + error = qb_to_cs_error(qb_ipcc_fd_get (votequorum_inst->c, fd)); + + (void)hdb_handle_put (&votequorum_handle_t_db, handle); + + return (error); +} + +cs_error_t votequorum_dispatch ( + votequorum_handle_t handle, + cs_dispatch_flags_t dispatch_types) +{ + int timeout = -1; + cs_error_t error; + int cont = 1; /* always continue do loop except when set to 0 */ + struct votequorum_inst *votequorum_inst; + votequorum_callbacks_t callbacks; + struct qb_ipc_response_header *dispatch_data; + struct res_lib_votequorum_quorum_notification *res_lib_votequorum_quorum_notification; + struct res_lib_votequorum_nodelist_notification *res_lib_votequorum_nodelist_notification; + struct res_lib_votequorum_expectedvotes_notification *res_lib_votequorum_expectedvotes_notification; + char dispatch_buf[IPC_DISPATCH_SIZE]; + votequorum_ring_id_t ring_id; + + if (dispatch_types != CS_DISPATCH_ONE && + dispatch_types != CS_DISPATCH_ALL && + dispatch_types != CS_DISPATCH_BLOCKING && + dispatch_types != CS_DISPATCH_ONE_NONBLOCKING) { + + return (CS_ERR_INVALID_PARAM); + } + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, + (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + /* + * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and + * wait indefinately for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING + */ + if (dispatch_types == CS_DISPATCH_ALL || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { + timeout = 0; + } + + dispatch_data = (struct qb_ipc_response_header *)dispatch_buf; + do { + error = qb_to_cs_error (qb_ipcc_event_recv ( + votequorum_inst->c, + dispatch_buf, + IPC_DISPATCH_SIZE, + timeout)); + if (error == CS_ERR_BAD_HANDLE) { + error = CS_OK; + goto error_put; + } + if (error == CS_ERR_TRY_AGAIN) { + if (dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { + /* + * Don't mask error + */ + goto error_put; + } + error = CS_OK; + if (dispatch_types == CS_DISPATCH_ALL) { + break; /* exit do while cont is 1 loop */ + } else { + continue; /* next poll */ + } + } + if (error != CS_OK) { + goto error_put; + } + + /* + * Make copy of callbacks, message data, unlock instance, and call callback + * A risk of this dispatch method is that the callback routines may + * operate at the same time that votequorum_finalize has been called in another thread. + */ + memcpy (&callbacks, &votequorum_inst->callbacks, sizeof (votequorum_callbacks_t)); + + /* + * Dispatch incoming message + */ + switch (dispatch_data->id) { + + case MESSAGE_RES_VOTEQUORUM_QUORUM_NOTIFICATION: + if (callbacks.votequorum_quorum_notify_fn == NULL) { + break; + } + res_lib_votequorum_quorum_notification = (struct res_lib_votequorum_quorum_notification *)dispatch_data; + + callbacks.votequorum_quorum_notify_fn ( handle, + res_lib_votequorum_quorum_notification->context, + res_lib_votequorum_quorum_notification->quorate, + res_lib_votequorum_quorum_notification->node_list_entries, + (votequorum_node_t *)res_lib_votequorum_quorum_notification->node_list ); + break; + + case MESSAGE_RES_VOTEQUORUM_NODELIST_NOTIFICATION: + if (callbacks.votequorum_nodelist_notify_fn == NULL) { + break; + } + res_lib_votequorum_nodelist_notification = (struct res_lib_votequorum_nodelist_notification *)dispatch_data; + marshall_from_mar_votequorum_ring_id (&ring_id, &res_lib_votequorum_nodelist_notification->ring_id); + + callbacks.votequorum_nodelist_notify_fn ( handle, + res_lib_votequorum_nodelist_notification->context, + ring_id, + res_lib_votequorum_nodelist_notification->node_list_entries, + res_lib_votequorum_nodelist_notification->node_list ); + break; + + case MESSAGE_RES_VOTEQUORUM_EXPECTEDVOTES_NOTIFICATION: + if (callbacks.votequorum_expectedvotes_notify_fn == NULL) { + break; + } + res_lib_votequorum_expectedvotes_notification = (struct res_lib_votequorum_expectedvotes_notification *)dispatch_data; + + callbacks.votequorum_expectedvotes_notify_fn ( handle, + res_lib_votequorum_expectedvotes_notification->context, + res_lib_votequorum_expectedvotes_notification->expected_votes); + break; + + default: + error = CS_ERR_LIBRARY; + goto error_put; + break; + } + if (votequorum_inst->finalize) { + /* + * If the finalize has been called then get out of the dispatch. + */ + error = CS_ERR_BAD_HANDLE; + goto error_put; + } + + /* + * Determine if more messages should be processed + */ + if (dispatch_types == CS_DISPATCH_ONE || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) { + cont = 0; + } + } while (cont); + + +error_put: + hdb_handle_put (&votequorum_handle_t_db, handle); + return (error); +} + +cs_error_t votequorum_qdevice_register ( + votequorum_handle_t handle, + const char *name) +{ + cs_error_t error; + struct votequorum_inst *votequorum_inst; + struct iovec iov; + struct req_lib_votequorum_qdevice_register req_lib_votequorum_qdevice_register; + struct res_lib_votequorum_status res_lib_votequorum_status; + + if ((strlen(name) == 0) || + (strlen(name) >= VOTEQUORUM_QDEVICE_MAX_NAME_LEN)) { + return CS_ERR_INVALID_PARAM; + } + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + + req_lib_votequorum_qdevice_register.header.size = sizeof (struct req_lib_votequorum_qdevice_register); + req_lib_votequorum_qdevice_register.header.id = MESSAGE_REQ_VOTEQUORUM_QDEVICE_REGISTER; + strcpy(req_lib_votequorum_qdevice_register.name, name); + + iov.iov_base = (char *)&req_lib_votequorum_qdevice_register; + iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_register); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + votequorum_inst->c, + &iov, + 1, + &res_lib_votequorum_status, + sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_votequorum_status.header.error; + +error_exit: + hdb_handle_put (&votequorum_handle_t_db, handle); + + return (error); +} + +cs_error_t votequorum_qdevice_poll ( + votequorum_handle_t handle, + const char *name, + unsigned int cast_vote, + votequorum_ring_id_t ring_id) +{ + cs_error_t error; + struct votequorum_inst *votequorum_inst; + struct iovec iov; + struct req_lib_votequorum_qdevice_poll req_lib_votequorum_qdevice_poll; + struct res_lib_votequorum_status res_lib_votequorum_status; + + if ((strlen(name) == 0) || + (strlen(name) >= VOTEQUORUM_QDEVICE_MAX_NAME_LEN)) { + return CS_ERR_INVALID_PARAM; + } + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_votequorum_qdevice_poll.header.size = sizeof (struct req_lib_votequorum_qdevice_poll); + req_lib_votequorum_qdevice_poll.header.id = MESSAGE_REQ_VOTEQUORUM_QDEVICE_POLL; + strcpy(req_lib_votequorum_qdevice_poll.name, name); + req_lib_votequorum_qdevice_poll.cast_vote = cast_vote; + marshall_to_mar_votequorum_ring_id(&req_lib_votequorum_qdevice_poll.ring_id, &ring_id); + + iov.iov_base = (char *)&req_lib_votequorum_qdevice_poll; + iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_poll); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + votequorum_inst->c, + &iov, + 1, + &res_lib_votequorum_status, + sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_votequorum_status.header.error; + +error_exit: + hdb_handle_put (&votequorum_handle_t_db, handle); + + return (error); +} + +cs_error_t votequorum_qdevice_master_wins ( + votequorum_handle_t handle, + const char *name, + unsigned int allow) +{ + cs_error_t error; + struct votequorum_inst *votequorum_inst; + struct iovec iov; + struct req_lib_votequorum_qdevice_master_wins req_lib_votequorum_qdevice_master_wins; + struct res_lib_votequorum_status res_lib_votequorum_status; + + if ((strlen(name) == 0) || + (strlen(name) >= VOTEQUORUM_QDEVICE_MAX_NAME_LEN)) { + return CS_ERR_INVALID_PARAM; + } + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_votequorum_qdevice_master_wins.header.size = sizeof (struct req_lib_votequorum_qdevice_master_wins); + req_lib_votequorum_qdevice_master_wins.header.id = MESSAGE_REQ_VOTEQUORUM_QDEVICE_MASTER_WINS; + strcpy(req_lib_votequorum_qdevice_master_wins.name, name); + req_lib_votequorum_qdevice_master_wins.allow = allow; + + iov.iov_base = (char *)&req_lib_votequorum_qdevice_master_wins; + iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_master_wins); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + votequorum_inst->c, + &iov, + 1, + &res_lib_votequorum_status, + sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_votequorum_status.header.error; + +error_exit: + hdb_handle_put (&votequorum_handle_t_db, handle); + + return (error); +} + +cs_error_t votequorum_qdevice_update ( + votequorum_handle_t handle, + const char *oldname, + const char *newname) +{ + cs_error_t error; + struct votequorum_inst *votequorum_inst; + struct iovec iov; + struct req_lib_votequorum_qdevice_update req_lib_votequorum_qdevice_update; + struct res_lib_votequorum_status res_lib_votequorum_status; + + if ((strlen(oldname) == 0) || + (strlen(oldname) >= VOTEQUORUM_QDEVICE_MAX_NAME_LEN) || + (strlen(newname) == 0) || + (strlen(newname) >= VOTEQUORUM_QDEVICE_MAX_NAME_LEN)) { + return CS_ERR_INVALID_PARAM; + } + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_votequorum_qdevice_update.header.size = sizeof (struct req_lib_votequorum_qdevice_update); + req_lib_votequorum_qdevice_update.header.id = MESSAGE_REQ_VOTEQUORUM_QDEVICE_UPDATE; + strcpy(req_lib_votequorum_qdevice_update.oldname, oldname); + strcpy(req_lib_votequorum_qdevice_update.newname, newname); + + iov.iov_base = (char *)&req_lib_votequorum_qdevice_update; + iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_update); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + votequorum_inst->c, + &iov, + 1, + &res_lib_votequorum_status, + sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_votequorum_status.header.error; + +error_exit: + hdb_handle_put (&votequorum_handle_t_db, handle); + + return (error); +} + +cs_error_t votequorum_qdevice_unregister ( + votequorum_handle_t handle, + const char *name) +{ + cs_error_t error; + struct votequorum_inst *votequorum_inst; + struct iovec iov; + struct req_lib_votequorum_qdevice_unregister req_lib_votequorum_qdevice_unregister; + struct res_lib_votequorum_status res_lib_votequorum_status; + + if ((strlen(name) == 0) || + (strlen(name) >= VOTEQUORUM_QDEVICE_MAX_NAME_LEN)) { + return CS_ERR_INVALID_PARAM; + } + + error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst)); + if (error != CS_OK) { + return (error); + } + + req_lib_votequorum_qdevice_unregister.header.size = sizeof (struct req_lib_votequorum_qdevice_unregister); + req_lib_votequorum_qdevice_unregister.header.id = MESSAGE_REQ_VOTEQUORUM_QDEVICE_UNREGISTER; + strcpy(req_lib_votequorum_qdevice_unregister.name, name); + + iov.iov_base = (char *)&req_lib_votequorum_qdevice_unregister; + iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_unregister); + + error = qb_to_cs_error(qb_ipcc_sendv_recv ( + votequorum_inst->c, + &iov, + 1, + &res_lib_votequorum_status, + sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS)); + + if (error != CS_OK) { + goto error_exit; + } + + error = res_lib_votequorum_status.header.error; + +error_exit: + hdb_handle_put (&votequorum_handle_t_db, handle); + + return (error); +} |