[Debian-ha-svn-commits] [SCM] corosync Debian packaging branch, master, updated. debian/1.2.0-1

Guido Günther agx at sigxcpu.org
Thu Jan 14 12:18:26 UTC 2010


The following commit has been merged in the master branch:
commit 0538e91de2d36b7d9f2b06674fc5a93fcc1b89dc
Author: Guido Günther <agx at sigxcpu.org>
Date:   Thu Jan 14 11:48:38 2010 +0100

    Imported Upstream version 1.2.0

diff --git a/AUTHORS b/AUTHORS
index b3257e3..fb540f2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,4 +1,4 @@
-Last Updated June 2009
+Last Updated Dec 2009
 
 Main Developers
 ---------------
@@ -9,13 +9,13 @@ Christine Caulfield	cpg, cfg, quorum, confdb, totem ipv6 support, totem NSS
 			support
 Fabien Thomas		OS portability, BSD port
 Hans Feldt		logging inspiration
-Angus Salkeld		objdb, static code analysis cleanup
+Angus Salkeld		objdb, static code analysis cleanup, statistics
 Lon Hohberger		logsys
 Fabio Di Nitto		automake, pkgconfig, logsys, config, distro release
 Jim Meyering		automake, sanitizing APIs, warnings removal
 Andrew Beekhof		automake, integration with Pacemaker
 Dave Teigland		cpg specification, integration with cluster3
-Jan Friesse		cpg
+Jan Friesse		cpg, sam
 Jérôme Flesch		BSD portability
 
 Significant credit belongs in our large vibrant community members, who are
diff --git a/CHANGELOG b/CHANGELOG
index 85729e9..6e8697b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,4 +1,520 @@
 ------------------------------------------------------------------------
+r2637 | sdake | 2009-12-07 18:09:51 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2581:
+r2581 | sdake | 2009-12-07 17:02:00 -0700 (Mon, 07 Dec 2009) | 2 lines
+
+Bump verion to 1.2.0.
+
+
+------------------------------------------------------------------------
+r2636 | sdake | 2009-12-07 18:04:57 -0700 (Mon, 07 Dec 2009) | 2 lines
+
+Fix merge conflicts.
+
+------------------------------------------------------------------------
+r2635 | sdake | 2009-12-07 17:42:25 -0700 (Mon, 07 Dec 2009) | 5 lines
+
+Merge trunk revision 2580:
+r2580 | sdake | 2009-12-07 17:01:39 -0700 (Mon, 07 Dec 2009) | 2 lines
+
+Remove string overwrite if many recovery messages are originated.
+
+------------------------------------------------------------------------
+r2634 | sdake | 2009-12-07 17:41:46 -0700 (Mon, 07 Dec 2009) | 5 lines
+
+Merge trunk revision 2579:
+r2579 | sdake | 2009-12-07 16:23:42 -0700 (Mon, 07 Dec 2009) | 2 lines
+
+Remove compiler warning in vsf_quorum.c.
+
+------------------------------------------------------------------------
+r2633 | sdake | 2009-12-07 17:41:18 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2578:
+r2578 | sdake | 2009-12-07 16:21:01 -0700 (Mon, 07 Dec 2009) | 2 lines
+
+Remove compiler warning in totemsrp.
+
+
+------------------------------------------------------------------------
+r2632 | sdake | 2009-12-07 17:40:53 -0700 (Mon, 07 Dec 2009) | 5 lines
+
+Merge trunk revision 2577:
+r2577 | sdake | 2009-12-07 16:18:44 -0700 (Mon, 07 Dec 2009) | 2 lines
+
+Update to AUTHORS file.
+
+------------------------------------------------------------------------
+r2631 | sdake | 2009-12-07 17:40:23 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2576:
+r2576 | fabbione | 2009-12-07 16:13:34 -0700 (Mon, 07 Dec 2009) | 2 lines
+
+Update spec file to deal with new libsam
+
+
+------------------------------------------------------------------------
+r2630 | sdake | 2009-12-07 17:39:52 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2575:
+r2575 | fabbione | 2009-12-07 16:13:14 -0700 (Mon, 07 Dec 2009) | 2 lines
+
+Generate .pc file for new libsam
+
+
+------------------------------------------------------------------------
+r2629 | sdake | 2009-12-07 17:39:25 -0700 (Mon, 07 Dec 2009) | 5 lines
+
+Merge trunk revision 2574:
+r2574 | sdake | 2009-12-07 15:40:49 -0700 (Mon, 07 Dec 2009) | 2 lines
+
+SAM man pages.
+
+------------------------------------------------------------------------
+r2628 | sdake | 2009-12-07 17:38:51 -0700 (Mon, 07 Dec 2009) | 7 lines
+
+Merge trunk revision 2573:
+r2573 | sdake | 2009-12-07 11:41:49 -0700 (Mon, 07 Dec 2009) | 3 lines
+
+Set boolean indicating the retrans flag was set to 1 to 0 when setting retrans
+flag in token to zero.
+
+
+------------------------------------------------------------------------
+r2627 | sdake | 2009-12-07 17:38:18 -0700 (Mon, 07 Dec 2009) | 7 lines
+
+Merge trunk revision 2572:
+r2572 | sdake | 2009-12-07 11:22:48 -0700 (Mon, 07 Dec 2009) | 3 lines
+
+Make assertions for range checking of message delivery check with the define
+instead of magic numbers that are not valid if the define changes.
+
+
+------------------------------------------------------------------------
+r2626 | sdake | 2009-12-07 17:37:43 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2571:
+r2571 | honzaf | 2009-12-07 10:14:44 -0700 (Mon, 07 Dec 2009) | 2 lines
+
+Remove potentially thread unsafe call of strftime
+
+
+------------------------------------------------------------------------
+r2625 | sdake | 2009-12-07 17:37:12 -0700 (Mon, 07 Dec 2009) | 11 lines
+
+Merge trunk revision 2570:
+r2570 | honzaf | 2009-12-07 10:06:53 -0700 (Mon, 07 Dec 2009) | 8 lines
+
+SAM implementation merge
+
+The SAM library provide a tool to check the health
+of an application. The main purpose of SAM is to restart
+a local process when it fails to respond to a healthcheck
+request in a configured time interval.
+
+
+------------------------------------------------------------------------
+r2624 | sdake | 2009-12-07 17:36:27 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2569:
+r2569 | sdake | 2009-12-06 22:03:25 -0700 (Sun, 06 Dec 2009) | 2 lines
+
+Prevent lockup in recovery state in totem after 206 messages are originated.
+
+
+------------------------------------------------------------------------
+r2623 | sdake | 2009-12-07 17:35:56 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+r2568 | sdake | 2009-12-06 22:02:28 -0700 (Sun, 06 Dec 2009) | 3 lines
+
+Fix recovery messages to be proper length to remove segfault that occurs during
+recovery.
+
+
+------------------------------------------------------------------------
+r2622 | sdake | 2009-12-07 17:35:35 -0700 (Mon, 07 Dec 2009) | 9 lines
+
+Merge trunk revision 2567:
+r2567 | sdake | 2009-12-05 18:35:05 -0700 (Sat, 05 Dec 2009) | 5 lines
+
+Force consensus timer to be at minimum 1.2 * token to prevent one group of
+nodes from executing a token timeout in the COMMIT state while another node
+executes a consensus timeout, showing to applications as a temporary network
+partition.
+
+
+------------------------------------------------------------------------
+r2621 | sdake | 2009-12-07 17:35:04 -0700 (Mon, 07 Dec 2009) | 5 lines
+
+Merge trunk revision 2566:
+r2566 | chrissie | 2009-12-04 09:11:49 -0700 (Fri, 04 Dec 2009) | 2 lines
+
+Make man page match reality of totem configuration values.
+
+------------------------------------------------------------------------
+r2620 | sdake | 2009-12-07 17:34:39 -0700 (Mon, 07 Dec 2009) | 11 lines
+
+Merge trunk revision 2565:
+r2565 | chrissie | 2009-12-04 09:10:59 -0700 (Fri, 04 Dec 2009) | 8 lines
+
+This puts multiple nodeids on each [QUORUM] Members line instead of
+putting each nodeid on a separate line.  With more than a few nodes the
+excessive lines become a real nuisance, and anyone up around 32 nodes
+may literally be scrolling through hundreds of those lines.
+
+from David teigland
+
+
+------------------------------------------------------------------------
+r2619 | sdake | 2009-12-07 17:34:07 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2564:
+r2564 | asalkeld | 2009-12-03 11:18:29 -0700 (Thu, 03 Dec 2009) | 2 lines
+
+stats: don't calloc the totemsrp stats struct.
+
+
+------------------------------------------------------------------------
+r2618 | sdake | 2009-12-07 17:33:10 -0700 (Mon, 07 Dec 2009) | 5 lines
+
+r2563 | asalkeld | 2009-12-03 11:13:52 -0700 (Thu, 03 Dec 2009) | 2 lines
+
+Correct some ugly indentation.
+
+
+------------------------------------------------------------------------
+r2617 | sdake | 2009-12-07 17:32:47 -0700 (Mon, 07 Dec 2009) | 5 lines
+
+Merge trunk revision 2562:
+r2562 | asalkeld | 2009-12-03 01:36:31 -0700 (Thu, 03 Dec 2009) | 2 lines
+
+objdb: fix memory leaks when objects are destroyed.
+
+------------------------------------------------------------------------
+r2616 | sdake | 2009-12-07 17:32:21 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2561:
+r2561 | asalkeld | 2009-12-02 15:14:00 -0700 (Wed, 02 Dec 2009) | 2 lines
+
+make sure key_names past from confdb are null terminated.
+
+
+------------------------------------------------------------------------
+r2615 | sdake | 2009-12-07 17:31:43 -0700 (Mon, 07 Dec 2009) | 11 lines
+
+r2560 | honzaf | 2009-12-02 08:09:18 -0700 (Wed, 02 Dec 2009) | 8 lines
+
+bsd: Fix mlockall on FreeBSD version >= 8.0
+
+FreeBSD version 8.0 and greater supports mlockall
+syscall correctly. So configure.ac is changed to detect
+FreeBSD version and main.c is changed to support it.
+
+Resolves: rhbz#513687
+
+
+------------------------------------------------------------------------
+r2614 | sdake | 2009-12-07 17:31:05 -0700 (Mon, 07 Dec 2009) | 5 lines
+
+r2559 | fabbione | 2009-12-01 23:30:27 -0700 (Tue, 01 Dec 2009) | 2 lines
+
+spec file cleanup
+
+
+------------------------------------------------------------------------
+r2613 | sdake | 2009-12-07 17:30:30 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2558:
+r2558 | fabbione | 2009-11-30 16:01:51 -0700 (Mon, 30 Nov 2009) | 3 lines
+
+Fix threads vs fork init order
+
+
+------------------------------------------------------------------------
+r2612 | sdake | 2009-12-07 17:29:57 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2557:
+r2557 | fabbione | 2009-11-30 14:28:30 -0700 (Mon, 30 Nov 2009) | 3 lines
+
+Fix stop regression
+
+
+------------------------------------------------------------------------
+r2611 | sdake | 2009-12-07 17:28:31 -0700 (Mon, 07 Dec 2009) | 5 lines
+
+r2556 | fabbione | 2009-11-30 13:18:48 -0700 (Mon, 30 Nov 2009) | 3 lines
+
+Expose service.d config directory
+
+
+------------------------------------------------------------------------
+r2610 | sdake | 2009-12-07 17:28:12 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+r2555 | sdake | 2009-11-30 12:11:20 -0700 (Mon, 30 Nov 2009) | 3 lines
+
+Start pause timer at initialization so first gather doesn't result in pause
+timeout operations.
+
+
+------------------------------------------------------------------------
+r2609 | sdake | 2009-12-07 17:27:38 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+merge trunk revision 2554:
+r2554 | fabbione | 2009-11-30 11:56:28 -0700 (Mon, 30 Nov 2009) | 3 lines
+
+Clean up init scripts and make a single generic one
+
+
+------------------------------------------------------------------------
+r2608 | sdake | 2009-12-07 17:27:08 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2553:
+r2553 | asalkeld | 2009-11-29 11:42:00 -0700 (Sun, 29 Nov 2009) | 3 lines
+
+Rename totem_new_msg_signal() to something more generic.
+
+
+------------------------------------------------------------------------
+r2607 | sdake | 2009-12-07 17:26:40 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2552:
+r2552 | asalkeld | 2009-11-29 11:28:39 -0700 (Sun, 29 Nov 2009) | 3 lines
+
+coroipcs: Add a queue_size stats counter to each ipc connection.
+
+
+------------------------------------------------------------------------
+r2606 | sdake | 2009-12-07 17:26:13 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2551:
+r2551 | asalkeld | 2009-11-29 11:25:51 -0700 (Sun, 29 Nov 2009) | 3 lines
+
+coroipcs: add logging for flow control state changes.
+
+
+------------------------------------------------------------------------
+r2605 | sdake | 2009-12-07 17:25:45 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+r2550 | sdake | 2009-11-27 15:59:48 -0700 (Fri, 27 Nov 2009) | 3 lines
+
+Patch to use proper IFA on Linux platforms to match interface addresses when
+netmask is not 255.255.255.0.
+
+
+------------------------------------------------------------------------
+r2604 | sdake | 2009-12-07 17:25:21 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2549:
+r2549 | asalkeld | 2009-11-22 17:32:31 -0700 (Sun, 22 Nov 2009) | 2 lines
+
+COVERITY 4: remove dead code in XYZ_dispatch().
+
+
+------------------------------------------------------------------------
+r2603 | sdake | 2009-12-07 17:24:38 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2548:
+r2548 | asalkeld | 2009-11-22 16:59:51 -0700 (Sun, 22 Nov 2009) | 2 lines
+
+COVERITY 17: fix exit handling in show_votes().
+
+
+------------------------------------------------------------------------
+r2602 | sdake | 2009-12-07 17:23:55 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2547:
+r2547 | asalkeld | 2009-11-22 16:19:41 -0700 (Sun, 22 Nov 2009) | 1 line
+
+COVERITY 12: prevent overrun of logsys output buffers.
+
+
+------------------------------------------------------------------------
+r2601 | sdake | 2009-12-07 17:23:26 -0700 (Mon, 07 Dec 2009) | 5 lines
+
+Merge trunk revision 2546:
+r2546 | asalkeld | 2009-11-21 23:34:11 -0700 (Sat, 21 Nov 2009) | 2 lines
+
+COVERITY 13: prevent buffer overrun in quorum-tool.
+
+------------------------------------------------------------------------
+r2600 | sdake | 2009-12-07 17:22:53 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2545:
+r2545 | asalkeld | 2009-11-21 23:29:46 -0700 (Sat, 21 Nov 2009) | 3 lines
+
+COVERITY 11: remove dead code from cpg_iteration_next().
+
+
+------------------------------------------------------------------------
+r2599 | sdake | 2009-12-07 17:22:19 -0700 (Mon, 07 Dec 2009) | 7 lines
+
+Merge trunk revision 2544:
+r2544 | asalkeld | 2009-11-21 23:27:09 -0700 (Sat, 21 Nov 2009) | 3 lines
+
+COVERITY 14: free zcb_mapped if memory_map() fails.
+
+
+
+------------------------------------------------------------------------
+r2598 | sdake | 2009-12-07 17:19:00 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2530:
+r2530 | asalkeld | 2009-10-18 11:15:24 -0700 (Sun, 18 Oct 2009) | 3 lines
+
+Add a log_printf function to coroipcs so we can pass the log level
+
+
+------------------------------------------------------------------------
+r2597 | sdake | 2009-12-07 17:18:04 -0700 (Mon, 07 Dec 2009) | 5 lines
+
+r2529 | asalkeld | 2009-10-14 16:05:18 -0700 (Wed, 14 Oct 2009) | 3 lines
+
+Avoid array out of bound error.
+
+
+------------------------------------------------------------------------
+r2596 | sdake | 2009-12-07 17:17:08 -0700 (Mon, 07 Dec 2009) | 8 lines
+
+Merge trunk revision 2522:
+r2522 | asalkeld | 2009-10-13 21:06:42 -0700 (Tue, 13 Oct 2009) | 5 lines
+
+stats: prevent a div by zero if totem_count is zero.
+
+patch by Chrissie
+
+
+------------------------------------------------------------------------
+r2595 | sdake | 2009-12-07 17:16:18 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2521:
+r2521 | asalkeld | 2009-10-13 01:13:53 -0700 (Tue, 13 Oct 2009) | 2 lines
+
+Fix the OSX build (broken by stats patches)
+
+
+------------------------------------------------------------------------
+r2594 | sdake | 2009-12-07 17:15:32 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2519:
+r2519 | asalkeld | 2009-10-12 14:56:23 -0700 (Mon, 12 Oct 2009) | 2 lines
+
+Add some missing calls to increment the relevant stats.
+
+
+------------------------------------------------------------------------
+r2593 | sdake | 2009-12-07 17:14:47 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2518:
+r2518 | asalkeld | 2009-10-12 14:50:10 -0700 (Mon, 12 Oct 2009) | 2 lines
+
+allow coroipcs to work without calling stats initialization.
+
+
+------------------------------------------------------------------------
+r2592 | sdake | 2009-12-07 17:14:10 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2517:
+r2517 | asalkeld | 2009-10-12 10:30:20 -0700 (Mon, 12 Oct 2009) | 3 lines
+
+Add totem stats to objdb.
+
+
+------------------------------------------------------------------------
+r2591 | sdake | 2009-12-07 17:12:32 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2516:
+r2516 | asalkeld | 2009-10-12 10:29:19 -0700 (Mon, 12 Oct 2009) | 3 lines
+
+Remove silly warning in corosync-objdb
+
+
+------------------------------------------------------------------------
+r2590 | sdake | 2009-12-07 17:11:42 -0700 (Mon, 07 Dec 2009) | 2 lines
+
+Fixup merge problem in trunk revision 2515.
+
+------------------------------------------------------------------------
+r2589 | sdake | 2009-12-07 17:11:03 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2515 (their's conflict):
+r2515 | asalkeld | 2009-10-11 17:39:39 -0700 (Sun, 11 Oct 2009) | 2 lines
+
+Add per service-function statistics.
+
+
+------------------------------------------------------------------------
+r2588 | sdake | 2009-12-07 17:09:15 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2514:
+r2514 | asalkeld | 2009-10-11 17:36:55 -0700 (Sun, 11 Oct 2009) | 2 lines
+
+Add connection related statistics to the object db.
+
+
+------------------------------------------------------------------------
+r2587 | sdake | 2009-12-07 17:08:38 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2513:
+r2513 | asalkeld | 2009-10-11 16:46:07 -0700 (Sun, 11 Oct 2009) | 2 lines
+
+Test the key value size for typed keys.
+
+
+------------------------------------------------------------------------
+r2586 | sdake | 2009-12-07 17:07:56 -0700 (Mon, 07 Dec 2009) | 9 lines
+
+Merge trunk revision 2512:
+r2512 | asalkeld | 2009-10-11 15:53:13 -0700 (Sun, 11 Oct 2009) | 4 lines
+
+teach object_key_increment() key types.
+
+This is so we can increment all integer types correctly.
+
+
+
+------------------------------------------------------------------------
+r2585 | sdake | 2009-12-07 17:07:23 -0700 (Mon, 07 Dec 2009) | 9 lines
+
+Merge trunk revision 2511:
+r2511 | asalkeld | 2009-10-09 20:20:38 -0700 (Fri, 09 Oct 2009) | 6 lines
+
+Add value types to objdb keys.
+
+This allows you to create a key with a know type.
+And then get the type with the key value.
+
+
+------------------------------------------------------------------------
+r2584 | sdake | 2009-12-07 17:04:24 -0700 (Mon, 07 Dec 2009) | 8 lines
+
+Merge trunk revision 2543:
+r2543 | asalkeld | 2009-11-21 23:22:49 -0700 (Sat, 21 Nov 2009) | 5 lines
+
+COVERITY 18: prevent deref after free.
+
+Event deref_after_free: Dereferencing freed pointer "pi".
+
+
+------------------------------------------------------------------------
+r2583 | sdake | 2009-12-07 17:03:48 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2542:
+r2542 | beekhof | 2009-11-05 06:01:25 -0700 (Thu, 05 Nov 2009) | 1 line
+
+Fix compilation on RHEL-4: If _GNU_SOURCE isn't defined, then neither is pthread_spinlock_t and compilation fails
+
+
+------------------------------------------------------------------------
+r2582 | sdake | 2009-12-07 17:03:18 -0700 (Mon, 07 Dec 2009) | 6 lines
+
+Merge trunk revision 2541:
+r2541 | beekhof | 2009-10-28 12:09:59 -0700 (Wed, 28 Oct 2009) | 1 line
+
+Prevent daemon from suppressing corefile generation
+
+
+------------------------------------------------------------------------
 r2539 | sdake | 2009-10-22 15:34:49 -0700 (Thu, 22 Oct 2009) | 6 lines
 
 Merge trunk revision 2537:
diff --git a/Makefile.am b/Makefile.am
index 7cfb511..5cb90b8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -52,11 +52,13 @@ SUBDIRS			= include lcr lib exec services tools test pkgconfig \
 			  man init
 
 install-exec-local:
+	$(INSTALL) -d $(DESTDIR)/${COROSYSCONFDIR}/service.d
 	$(INSTALL) -d $(DESTDIR)/${COROSYSCONFDIR}/uidgid.d
 	$(INSTALL) -d $(DESTDIR)/${localstatedir}/lib/corosync
 	$(INSTALL) -d $(DESTDIR)/${SOCKETDIR}
 
 uninstall-local:
+	rmdir $(DESTDIR)/${COROSYSCONFDIR}/service.d || :;
 	rmdir $(DESTDIR)/${COROSYSCONFDIR}/uidgid.d || :;
 	rmdir $(DESTDIR)/${localstatedir}/lib/corosync || :;
 	rmdir $(DESTDIR)/${SOCKETDIR} || :;
diff --git a/Makefile.in b/Makefile.in
index 6ab9ff8..d599f88 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -185,6 +185,7 @@ EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
 GROFF = @GROFF@
+INITDDIR = @INITDDIR@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -841,11 +842,13 @@ uninstall-am: uninstall-corosysconfDATA uninstall-dist_docDATA \
 
 
 install-exec-local:
+	$(INSTALL) -d $(DESTDIR)/${COROSYSCONFDIR}/service.d
 	$(INSTALL) -d $(DESTDIR)/${COROSYSCONFDIR}/uidgid.d
 	$(INSTALL) -d $(DESTDIR)/${localstatedir}/lib/corosync
 	$(INSTALL) -d $(DESTDIR)/${SOCKETDIR}
 
 uninstall-local:
+	rmdir $(DESTDIR)/${COROSYSCONFDIR}/service.d || :;
 	rmdir $(DESTDIR)/${COROSYSCONFDIR}/uidgid.d || :;
 	rmdir $(DESTDIR)/${localstatedir}/lib/corosync || :;
 	rmdir $(DESTDIR)/${SOCKETDIR} || :;
diff --git a/configure b/configure
index 1e4689a..4ebcf54 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.63 for corosync 1.1.2.
+# Generated by GNU Autoconf 2.63 for corosync 1.2.0.
 #
 # Report bugs to <openais at lists.osdl.org>.
 #
@@ -596,8 +596,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='corosync'
 PACKAGE_TARNAME='corosync'
-PACKAGE_VERSION='1.1.2'
-PACKAGE_STRING='corosync 1.1.2'
+PACKAGE_VERSION='1.2.0'
+PACKAGE_STRING='corosync 1.2.0'
 PACKAGE_BUGREPORT='openais at lists.osdl.org'
 
 ac_unique_file="lib/coroipcc.c"
@@ -660,6 +660,7 @@ SOMINOR
 SOMAJOR
 SOCKETDIR
 LCRSODIR
+INITDDIR
 ibverbs_LIBS
 ibverbs_CFLAGS
 rdmacm_LIBS
@@ -774,6 +775,7 @@ enable_coverage
 enable_small_memory_footprint
 enable_nss
 enable_rdma
+with_initddir
 with_lcrso_dir
 with_socket_dir
 '
@@ -1345,7 +1347,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures corosync 1.1.2 to adapt to many kinds of systems.
+\`configure' configures corosync 1.2.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1415,7 +1417,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of corosync 1.1.2:";;
+     short | recursive ) echo "Configuration of corosync 1.2.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1436,6 +1438,7 @@ Optional Features:
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-initddir=DIR     : path to init script directory.
   --with-lcrso-dir=DIR    : corosync lcrso files.
   --with-socket-dir=DIR   : corosync socket dir.
 
@@ -1525,7 +1528,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-corosync configure 1.1.2
+corosync configure 1.2.0
 generated by GNU Autoconf 2.63
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1539,7 +1542,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by corosync $as_me 1.1.2, which was
+It was created by corosync $as_me 1.2.0, which was
 generated by GNU Autoconf 2.63.  Invocation command line was
 
   $ $0 $@
@@ -2388,7 +2391,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='corosync'
- VERSION='1.1.2'
+ VERSION='1.2.0'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -2527,7 +2530,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 # Define SVN revision
 
 cat >>confdefs.h <<\_ACEOF
-#define SVN_REVISION "2539"
+#define SVN_REVISION "2637"
 _ACEOF
 
 
@@ -9543,182 +9546,6 @@ _ACEOF
 
 
 
-for ac_func in strftime
-do
-as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
-$as_echo_n "checking for $ac_func... " >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
-
-int
-main ()
-{
-return $ac_func ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-	 test -z "$ac_c_werror_flag" ||
-	 test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-	 test "$cross_compiling" = yes ||
-	 $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_var=yes"
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-	eval "$as_ac_var=no"
-fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-ac_res=`eval 'as_val=${'$as_ac_var'}
-		 $as_echo "$as_val"'`
-	       { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-as_val=`eval 'as_val=${'$as_ac_var'}
-		 $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
-
-else
-  # strftime is in -lintl on SCO UNIX.
-{ $as_echo "$as_me:$LINENO: checking for strftime in -lintl" >&5
-$as_echo_n "checking for strftime in -lintl... " >&6; }
-if test "${ac_cv_lib_intl_strftime+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lintl  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char strftime ();
-int
-main ()
-{
-return strftime ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-	 test -z "$ac_c_werror_flag" ||
-	 test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-	 test "$cross_compiling" = yes ||
-	 $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_lib_intl_strftime=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-	ac_cv_lib_intl_strftime=no
-fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_intl_strftime" >&5
-$as_echo "$ac_cv_lib_intl_strftime" >&6; }
-if test "x$ac_cv_lib_intl_strftime" = x""yes; then
-  cat >>confdefs.h <<\_ACEOF
-#define HAVE_STRFTIME 1
-_ACEOF
-
-LIBS="-lintl $LIBS"
-fi
-
-fi
-done
-
-
 for ac_func in vprintf
 do
 as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@@ -10184,6 +10011,15 @@ fi
 
 
 
+# Check whether --with-initddir was given.
+if test "${with_initddir+set}" = set; then
+  withval=$with_initddir;  INITDDIR="$withval"
+else
+   INITDDIR="$sysconfdir/init.d"
+fi
+
+
+
 # Check whether --with-lcrso-dir was given.
 if test "${with_lcrso_dir+set}" = set; then
   withval=$with_lcrso_dir;  LCRSODIR="$withval"
@@ -10265,6 +10101,17 @@ _ACEOF
 		OS_DYFLAGS="-export-dynamic"
 		DARWIN_OPTS=""
 		OS_LDL=""
+		case "$host_os" in
+			*freebsd[234567]*)
+			;;
+			*freebsd*)
+
+cat >>confdefs.h <<_ACEOF
+#define COROSYNC_FREEBSD_GE_8 1
+_ACEOF
+
+			;;
+		esac
 	;;
 	*solaris*)
 
@@ -10882,6 +10729,7 @@ LDFLAGS="$ENV_LDFLAGS $COVERAGE_LDFLAGS $OS_LDFLAGS"
 
 
 
+
  if test -n "${DARWIN_OPTS}"; then
   BUILD_DARWIN_TRUE=
   BUILD_DARWIN_FALSE='#'
@@ -11411,7 +11259,7 @@ exec 6>&1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by corosync $as_me 1.1.2, which was
+This file was extended by corosync $as_me 1.2.0, which was
 generated by GNU Autoconf 2.63.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -11478,7 +11326,7 @@ Report bugs to <bug-autoconf at gnu.org>."
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_version="\\
-corosync config.status 1.1.2
+corosync config.status 1.2.0
 configured by $0, generated by GNU Autoconf 2.63,
   with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 
@@ -12507,6 +12355,8 @@ $as_echo "  Arch-independent files   = ${datadir}" >&6; }
 $as_echo "  State information        = ${localstatedir}" >&6; }
 { $as_echo "$as_me:$LINENO: result:   System configuration     = ${sysconfdir}" >&5
 $as_echo "  System configuration     = ${sysconfdir}" >&6; }
+{ $as_echo "$as_me:$LINENO: result:   System init.d directory  = ${INITDDIR}" >&5
+$as_echo "  System init.d directory  = ${INITDDIR}" >&6; }
 { $as_echo "$as_me:$LINENO: result:   corosync config dir      = ${COROSYSCONFDIR}" >&5
 $as_echo "  corosync config dir      = ${COROSYSCONFDIR}" >&6; }
 { $as_echo "$as_me:$LINENO: result:   LCRSO                    = ${LCRSODIR}" >&5
diff --git a/configure.ac b/configure.ac
index 9487103..45a59d9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@
 # bootstrap / init
 AC_PREREQ([2.61])
 
-AC_INIT([corosync], [1.1.2], [openais at lists.osdl.org])
+AC_INIT([corosync], [1.2.0], [openais at lists.osdl.org])
 AM_INIT_AUTOMAKE([-Wno-portability])
 
 AC_CONFIG_SRCDIR([lib/coroipcc.c])
@@ -110,7 +110,6 @@ AC_FUNC_MEMCMP
 AC_FUNC_REALLOC
 AC_FUNC_SELECT_ARGTYPES
 AC_TYPE_SIGNAL
-AC_FUNC_STRFTIME
 AC_FUNC_VPRINTF
 AC_CHECK_FUNCS([alarm alphasort atexit bzero dup2 endgrent endpwent fcntl \
 		getcwd getpeerucred getpeereid gettimeofday inet_ntoa memmove \
@@ -205,6 +204,11 @@ AC_ARG_ENABLE([rdma],
 	[ enable_rdma="no" ])
 AM_CONDITIONAL(BUILD_RDMA, test x$enable_rdma = xyes)
 
+AC_ARG_WITH([initddir],
+	[  --with-initddir=DIR     : path to init script directory. ],
+	[ INITDDIR="$withval" ],
+	[ INITDDIR="$sysconfdir/init.d" ])
+
 AC_ARG_WITH([lcrso-dir],
 	[  --with-lcrso-dir=DIR    : corosync lcrso files. ],
 	[ LCRSODIR="$withval" ],
@@ -258,6 +262,14 @@ case "$host_os" in
 		OS_DYFLAGS="-export-dynamic"
 		DARWIN_OPTS=""
 		OS_LDL=""
+		case "$host_os" in
+			*freebsd[[234567]]*)
+			;;
+			*freebsd*)
+				AC_DEFINE_UNQUOTED([COROSYNC_FREEBSD_GE_8], [1],
+					   [Compiling for FreeBSD >= 8 platform])
+			;;
+		esac
 	;;
 	*solaris*)
 		AC_DEFINE_UNQUOTED([COROSYNC_SOLARIS], [1],
@@ -390,6 +402,7 @@ CPPFLAGS="$ENV_CPPFLAGS $ANSI_CPPFLAGS $OS_CPPFLAGS"
 LDFLAGS="$ENV_LDFLAGS $COVERAGE_LDFLAGS $OS_LDFLAGS"
 
 # substitute what we need:
+AC_SUBST([INITDDIR])
 AC_SUBST([LCRSODIR])
 AC_SUBST([SOCKETDIR])
 
@@ -438,6 +451,7 @@ AC_MSG_RESULT([  Header files             = ${includedir}])
 AC_MSG_RESULT([  Arch-independent files   = ${datadir}])
 AC_MSG_RESULT([  State information        = ${localstatedir}])
 AC_MSG_RESULT([  System configuration     = ${sysconfdir}])
+AC_MSG_RESULT([  System init.d directory  = ${INITDDIR}])
 AC_MSG_RESULT([  corosync config dir      = ${COROSYSCONFDIR}])
 AC_MSG_RESULT([  LCRSO                    = ${LCRSODIR}])
 AC_MSG_RESULT([  SOCKETDIR                = ${SOCKETDIR}])
diff --git a/corosync.spec.in b/corosync.spec.in
index 0b3435e..8e1687a 100644
--- a/corosync.spec.in
+++ b/corosync.spec.in
@@ -1,4 +1,4 @@
-%define alphatag @alphatag@
+%global alphatag @alphatag@
 
 Name: corosync
 Summary: The Corosync Cluster Engine and Application Programming Interfaces
@@ -7,7 +7,7 @@ Release: 1%{?alphatag:.%{alphatag}}%{?dist}
 License: BSD
 Group: System Environment/Base
 URL: http://www.openais.org
-Source0: http://developer.osdl.org/dev/openais/downloads/corosync-%{version}/corosync-%{version}.tar.gz
+Source0: http://developer.osdl.org/dev/openais/downloads/%{name}-%{version}/%{name}-%{version}.tar.gz
 
 # Runtime bits
 Requires: corosynclib = %{version}-%{release}
@@ -16,6 +16,8 @@ Requires(post): /sbin/chkconfig
 Requires(preun): /sbin/chkconfig
 Conflicts: openais <= 0.89, openais-devel <= 0.89
 
+# Build bits
+
 %define buildtrunk 0
 %{?_with_buildtrunk: %define buildtrunk 1}
 
@@ -28,7 +30,7 @@ BuildRequires: libibverbs-devel librdmacm-devel
 BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
 
 %prep
-%setup -q -n corosync-%{version}
+%setup -q -n %{name}-%{version}
 
 %if %{buildtrunk}
 ./autogen.sh
@@ -40,7 +42,8 @@ export rdmacm_CFLAGS=-I/usr/include/rdma \
 export rdmacm_LIBS=-lrdmacm \
 %{configure} \
 	--enable-nss \
-	--enable-rdma
+	--enable-rdma \
+	--with-initddir=%{_initddir}
 
 %build
 make %{_smp_mflags}
@@ -49,8 +52,6 @@ make %{_smp_mflags}
 rm -rf %{buildroot}
 
 make install DESTDIR=%{buildroot}
-install -d %{buildroot}%{_initddir}
-install -m 755 init/redhat %{buildroot}%{_initddir}/corosync
 
 ## tree fixup
 # drop static libs
@@ -74,9 +75,6 @@ if [ $1 -eq 0 ]; then
 	/sbin/chkconfig --del corosync || :
 fi
 
-%postun
-[ "$1" -ge "1" ] && /sbin/service corosync condrestart &>/dev/null || :
-
 %files
 %defattr(-,root,root,-)
 %doc LICENSE SECURITY
@@ -89,6 +87,7 @@ fi
 %{_sbindir}/corosync-cpgtool
 %{_sbindir}/corosync-quorumtool
 %dir %{_sysconfdir}/corosync
+%dir %{_sysconfdir}/corosync/service.d
 %dir %{_sysconfdir}/corosync/uidgid.d
 %config(noreplace) %{_sysconfdir}/corosync/corosync.conf.example
 %{_initddir}/corosync
@@ -112,7 +111,7 @@ fi
 %package -n corosynclib
 Summary: The Corosync Cluster Engine Libraries
 Group: System Environment/Libraries
-Conflicts: corosync < 0.92-7
+Requires: %{name} = %{version}-%{release}
 
 %description -n corosynclib
 This package contains corosync libraries.
@@ -131,6 +130,7 @@ This package contains corosync libraries.
 %{_libdir}/libquorum.so.*
 %{_libdir}/libvotequorum.so.*
 %{_libdir}/libpload.so.*
+%{_libdir}/libsam.so.*
 
 %post -n corosynclib -p /sbin/ldconfig
 
@@ -165,6 +165,7 @@ The Corosync Cluster Engine APIs.
 %{_includedir}/corosync/hdb.h
 %{_includedir}/corosync/list.h
 %{_includedir}/corosync/mar_gen.h
+%{_includedir}/corosync/sam.h
 %{_includedir}/corosync/swab.h
 %{_includedir}/corosync/quorum.h
 %{_includedir}/corosync/votequorum.h
@@ -194,17 +195,20 @@ The Corosync Cluster Engine APIs.
 %{_libdir}/libquorum.so
 %{_libdir}/libvotequorum.so
 %{_libdir}/libpload.so
+%{_libdir}/libsam.so
 %{_libdir}/pkgconfig/*.pc
 %{_mandir}/man3/cpg_*3*
 %{_mandir}/man3/evs_*3*
 %{_mandir}/man3/confdb_*3*
 %{_mandir}/man3/votequorum_*3*
+%{_mandir}/man3/sam_*3*
 %{_mandir}/man8/cpg_overview.8*
 %{_mandir}/man8/evs_overview.8*
 %{_mandir}/man8/confdb_overview.8*
 %{_mandir}/man8/logsys_overview.8*
 %{_mandir}/man8/votequorum_overview.8*
 %{_mandir}/man8/coroipc_overview.8*
+%{_mandir}/man8/sam_overview.8*
 
 %changelog
 * @date@ Autotools generated version <nobody at nowhere.org> - @version at -1.@alphatag@
diff --git a/exec/Makefile.in b/exec/Makefile.in
index 96bdc42..4724d66 100644
--- a/exec/Makefile.in
+++ b/exec/Makefile.in
@@ -179,6 +179,7 @@ EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
 GROFF = @GROFF@
+INITDDIR = @INITDDIR@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
diff --git a/exec/apidef.c b/exec/apidef.c
index a8ae751..5e1f178 100644
--- a/exec/apidef.c
+++ b/exec/apidef.c
@@ -49,11 +49,11 @@
 #include "timer.h"
 #include "sync.h"
 #include "quorum.h"
-#include "service.h"
 #include "schedwrk.h"
 #include "main.h"
-#include <corosync/engine/coroapi.h>
 #include "apidef.h"
+#include <corosync/engine/coroapi.h>
+#include "service.h"
 
 LOGSYS_DECLARE_SUBSYS ("APIDEF");
 
@@ -117,6 +117,7 @@ static struct corosync_api_v1 apidef_corosync_api_v1 = {
 	.totem_ip_print = totemip_print,
 	.totem_crypto_set = totempg_crypto_set,
 	.totem_callback_token_create = totempg_callback_token_create,
+	.totem_get_stats = totempg_get_stats,
 	.tpg_init = totempg_groups_initialize,
 	.tpg_exit = NULL, /* missing from totempg api */
 	.tpg_join = (typedef_tpg_join)totempg_groups_join,
@@ -172,6 +173,9 @@ void apidef_init (struct objdb_iface_ver0 *objdb) {
 	apidef_corosync_api_v1.object_reload_config = objdb->object_reload_config;
 	apidef_corosync_api_v1.object_key_increment = objdb->object_key_increment;
 	apidef_corosync_api_v1.object_key_decrement = objdb->object_key_decrement;
+	apidef_corosync_api_v1.object_key_create_typed = objdb->object_key_create_typed;
+	apidef_corosync_api_v1.object_key_get_typed = objdb->object_key_get_typed;
+	apidef_corosync_api_v1.object_key_iter_typed = objdb->object_key_iter_typed;
 }
 
 struct corosync_api_v1 *apidef_get (void)
diff --git a/exec/coroipcs.c b/exec/coroipcs.c
index 5f87bae..22643ee 100644
--- a/exec/coroipcs.c
+++ b/exec/coroipcs.c
@@ -72,9 +72,13 @@
 #include <corosync/list.h>
 
 #include <corosync/coroipc_types.h>
+#include <corosync/hdb.h>
 #include <corosync/coroipcs.h>
 #include <corosync/coroipc_ipc.h>
 
+#define LOGSYS_UTILS_ONLY 1
+#include <corosync/engine/logsys.h>
+
 #if _POSIX_THREAD_PROCESS_SHARED > 0
 #include <semaphore.h>
 #else
@@ -90,7 +94,7 @@
 #define MSG_SEND_LOCKED		0
 #define MSG_SEND_UNLOCKED	1
 
-static struct coroipcs_init_state *api;
+static struct coroipcs_init_state_v2 *api = NULL;
 
 DECLARE_LIST_INIT (conn_info_list_head);
 
@@ -130,11 +134,14 @@ enum conn_state {
 struct conn_info {
 	int fd;
 	pthread_t thread;
+	pid_t client_pid;
 	pthread_attr_t thread_attr;
 	unsigned int service;
 	enum conn_state state;
 	int notify_flow_control_enabled;
+	int flow_control_state;
 	int refcount;
+	hdb_handle_t stats_handle;
 #if _POSIX_THREAD_PROCESS_SHARED < 1
 	key_t semkey;
 	int semid;
@@ -169,6 +176,48 @@ static void ipc_disconnect (struct conn_info *conn_info);
 static void msg_send (void *conn, const struct iovec *iov, unsigned int iov_len,
 		      int locked);
 
+static void _corosync_ipc_init(void);
+
+#define log_printf(level, format, args...) \
+do { \
+	if (api->log_printf) \
+        api->log_printf ( \
+                LOGSYS_ENCODE_RECID(level, \
+                                    api->log_subsys_id, \
+                                    LOGSYS_RECID_LOG), \
+                __FUNCTION__, __FILE__, __LINE__, \
+                (const char *)format, ##args); \
+	else \
+        api->old_log_printf ((const char *)format, ##args); \
+} while (0)
+
+static hdb_handle_t dummy_stats_create_connection (
+	const char *name,
+	pid_t pid,
+	int fd)
+{
+	return (0ULL);
+}
+
+static void dummy_stats_destroy_connection (
+	hdb_handle_t handle)
+{
+}
+
+static void dummy_stats_update_value (
+	hdb_handle_t handle,
+	const char *name,
+	const void *value,
+	size_t value_size)
+{
+}
+
+static void dummy_stats_increment_value (
+	hdb_handle_t handle,
+	const char *name)
+{
+}
+
 static void sem_post_exit_thread (struct conn_info *conn_info)
 {
 #if _POSIX_THREAD_PROCESS_SHARED < 1
@@ -180,6 +229,7 @@ static void sem_post_exit_thread (struct conn_info *conn_info)
 retry_semop:
 	res = sem_post (&conn_info->control_buffer->sem0);
 	if (res == -1 && errno == EINTR) {
+		api->stats_increment_value (conn_info->stats_handle, "sem_retry_count");
 		goto retry_semop;
 	}
 #else
@@ -190,6 +240,7 @@ retry_semop:
 retry_semop:
 	res = semop (conn_info->semid, &sop, 1);
 	if ((res == -1) && (errno == EINTR || errno == EAGAIN)) {
+		api->stats_increment_value (conn_info->stats_handle, "sem_retry_count");
 		goto retry_semop;
 	}
 #endif
@@ -363,6 +414,7 @@ static inline int zcb_alloc (
 		size,
 		addr);
 	if (res == -1) {
+		free (zcb_mapped);
 		return (-1);
 	}
 
@@ -437,6 +489,7 @@ static inline int conn_info_destroy (struct conn_info *conn_info)
 	 * Retry library exit function if busy
 	 */
 	if (conn_info->state == CONN_STATE_THREAD_DESTROYED) {
+		api->stats_destroy_connection (conn_info->stats_handle);
 		res = api->exit_fn_get (conn_info->service) (conn_info);
 		if (res == -1) {
 			api->serialize_unlock ();
@@ -588,6 +641,7 @@ retry_semwait:
 			pthread_exit (0);
 		}
 		if ((res == -1) && (errno == EINTR)) {
+			api->stats_increment_value (conn_info->stats_handle, "sem_retry_count");
 			goto retry_semwait;
 		}
 #else
@@ -602,6 +656,7 @@ retry_semop:
 			pthread_exit (0);
 		}
 		if ((res == -1) && (errno == EINTR || errno == EAGAIN)) {
+			api->stats_increment_value (conn_info->stats_handle, "sem_retry_count");
 			goto retry_semop;
 		} else
 		if ((res == -1) && (errno == EINVAL || errno == EIDRM)) {
@@ -639,12 +694,14 @@ retry_semop:
 		} else 
 		if (send_ok) {
 			api->serialize_lock();
+			api->stats_increment_value (conn_info->stats_handle, "requests");
 			api->handler_fn_get (conn_info->service, header->id) (conn_info, header);
 			api->serialize_unlock();
 		} else {
 			/*
 			 * Overload, tell library to retry
 			 */
+			api->stats_increment_value (conn_info->stats_handle, "sem_retry_count");
 			coroipc_response_header.size = sizeof (coroipc_response_header_t);
 			coroipc_response_header.id = 0;
 			coroipc_response_header.error = CS_ERR_TRY_AGAIN;
@@ -672,9 +729,11 @@ req_setup_send (
 retry_send:
 	res = send (conn_info->fd, &res_setup, sizeof (mar_res_setup_t), MSG_WAITALL);
 	if (res == -1 && errno == EINTR) {
+		api->stats_increment_value (conn_info->stats_handle, "send_retry_count");
 		goto retry_send;
 	} else
 	if (res == -1 && errno == EAGAIN) {
+		api->stats_increment_value (conn_info->stats_handle, "send_retry_count");
 		goto retry_send;
 	}
 	return (0);
@@ -719,6 +778,7 @@ req_setup_recv (
 retry_recv:
 	res = recvmsg (conn_info->fd, &msg_recv, MSG_NOSIGNAL);
 	if (res == -1 && errno == EINTR) {
+		api->stats_increment_value (conn_info->stats_handle, "recv_retry_count");
 		goto retry_recv;
 	} else
 	if (res == -1 && errno != EAGAIN) {
@@ -753,6 +813,7 @@ retry_recv:
 		if (getpeerucred (conn_info->fd, &uc) == 0) {
 			euid = ucred_geteuid (uc);
 			egid = ucred_getegid (uc);
+			conn_info->client_pid = ucred_getpid (uc);
 			if (api->security_valid (euid, egid)) {
 				authenticated = 1;
 			}
@@ -768,6 +829,10 @@ retry_recv:
 		uid_t euid;
 		gid_t egid;
 
+		/*
+		 * TODO get the peer's pid.
+		 * conn_info->client_pid = ?;
+		 */
 		euid = -1;
 		egid = -1;
 		if (getpeereid (conn_info->fd, &euid, &egid) == 0) {
@@ -785,6 +850,7 @@ retry_recv:
 	assert (cmsg);
 	cred = (struct ucred *)CMSG_DATA (cmsg);
 	if (cred) {
+		conn_info->client_pid = cred->pid;
 		if (api->security_valid (cred->uid, cred->gid)) {
 			authenticated = 1;
 		}
@@ -792,11 +858,11 @@ retry_recv:
 
 #else /* no credentials */
 	authenticated = 1;
- 	api->log_printf ("Platform does not support IPC authentication.  Using no authentication\n");
+ 	log_printf (LOGSYS_LEVEL_ERROR, "Platform does not support IPC authentication.  Using no authentication\n");
 #endif /* no credentials */
 
 	if (authenticated == 0) {
-		api->log_printf ("Invalid IPC credentials.\n");
+		log_printf (LOGSYS_LEVEL_ERROR, "Invalid IPC credentials.\n");
 		ipc_disconnect (conn_info);
 		return (-1);
  	}
@@ -838,6 +904,7 @@ static int conn_info_create (int fd)
 	memset (conn_info, 0, sizeof (struct conn_info));
 
 	conn_info->fd = fd;
+	conn_info->client_pid = 0;
 	conn_info->service = SOCKET_SERVICE_INIT;
 	conn_info->state = CONN_STATE_THREAD_INACTIVE;
 	list_init (&conn_info->outq_head);
@@ -845,7 +912,7 @@ static int conn_info_create (int fd)
 	list_init (&conn_info->zcb_mapped_list_head);
 	list_add (&conn_info->list, &conn_info_list_head);
 
-        api->poll_dispatch_add (fd, conn_info);
+	api->poll_dispatch_add (fd, conn_info);
 
 	return (0);
 }
@@ -862,15 +929,59 @@ static int conn_info_create (int fd)
 /*
  * Exported functions
  */
+extern void coroipcs_ipc_init_v2 (
+	struct coroipcs_init_state_v2 *init_state_v2)
+{
+	api = init_state_v2;
+	api->old_log_printf	= NULL;
+
+	log_printf (LOGSYS_LEVEL_DEBUG, "you are using ipc api v2\n");
+	_corosync_ipc_init ();
+}
+
 extern void coroipcs_ipc_init (
         struct coroipcs_init_state *init_state)
 {
+	api = calloc (sizeof(struct coroipcs_init_state_v2), 1);
+	/* v2 api */
+	api->stats_create_connection	= dummy_stats_create_connection;
+	api->stats_destroy_connection	= dummy_stats_destroy_connection;
+	api->stats_update_value		= dummy_stats_update_value;
+	api->stats_increment_value	= dummy_stats_increment_value;
+	api->log_printf			= NULL;
+
+	/* v1 api */
+	api->socket_name		= init_state->socket_name;
+	api->sched_policy		= init_state->sched_policy;
+	api->sched_param		= init_state->sched_param;
+	api->malloc			= init_state->malloc;
+	api->free			= init_state->free;
+	api->old_log_printf		= init_state->log_printf;
+	api->fatal_error		= init_state->fatal_error;
+	api->security_valid		= init_state->security_valid;
+	api->service_available		= init_state->service_available;
+	api->private_data_size_get	= init_state->private_data_size_get;
+	api->serialize_lock		= init_state->serialize_lock;
+	api->serialize_unlock		= init_state->serialize_unlock;
+	api->sending_allowed		= init_state->sending_allowed;
+	api->sending_allowed_release	= init_state->sending_allowed_release;
+	api->poll_accept_add		= init_state->poll_accept_add;
+	api->poll_dispatch_add		= init_state->poll_dispatch_add;
+	api->poll_dispatch_modify	= init_state->poll_dispatch_modify;
+	api->init_fn_get		= init_state->init_fn_get;
+	api->exit_fn_get		= init_state->exit_fn_get;
+	api->handler_fn_get		= init_state->handler_fn_get;
+
+	log_printf (LOGSYS_LEVEL_DEBUG, "you are using ipc api v1\n");
+
+	_corosync_ipc_init ();
+}
+
+static void _corosync_ipc_init(void)
+{
 	int server_fd;
 	struct sockaddr_un un_addr;
 	int res;
-
-	api = init_state;
-
 	/*
 	 * Create socket for IPC clients, name socket, listen for connections
 	 */
@@ -880,13 +991,13 @@ extern void coroipcs_ipc_init (
 	server_fd = socket (PF_LOCAL, SOCK_STREAM, 0);
 #endif
 	if (server_fd == -1) {
-		api->log_printf ("Cannot create client connections socket.\n");
+		log_printf (LOGSYS_LEVEL_CRIT, "Cannot create client connections socket.\n");
 		api->fatal_error ("Can't create library listen socket");
 	};
 
 	res = fcntl (server_fd, F_SETFL, O_NONBLOCK);
 	if (res == -1) {
-		api->log_printf ("Could not set non-blocking operation on server socket: %s\n", strerror (errno));
+		log_printf (LOGSYS_LEVEL_CRIT, "Could not set non-blocking operation on server socket: %s\n", strerror (errno));
 		api->fatal_error ("Could not set non-blocking operation on server socket");
 	}
 
@@ -903,7 +1014,7 @@ extern void coroipcs_ipc_init (
 		struct stat stat_out;
 		res = stat (SOCKETDIR, &stat_out);
 		if (res == -1 || (res == 0 && !S_ISDIR(stat_out.st_mode))) {
-			api->log_printf ("Required directory not present %s\n", SOCKETDIR);
+			log_printf (LOGSYS_LEVEL_CRIT, "Required directory not present %s\n", SOCKETDIR);
 			api->fatal_error ("Please create required directory.");
 		}
 		sprintf (un_addr.sun_path, "%s/%s", SOCKETDIR, api->socket_name);
@@ -913,7 +1024,7 @@ extern void coroipcs_ipc_init (
 
 	res = bind (server_fd, (struct sockaddr *)&un_addr, COROSYNC_SUN_LEN(&un_addr));
 	if (res) {
-		api->log_printf ("Could not bind AF_UNIX (%s): %s.\n", un_addr.sun_path, strerror (errno));
+		log_printf (LOGSYS_LEVEL_CRIT, "Could not bind AF_UNIX (%s): %s.\n", un_addr.sun_path, strerror (errno));
 		api->fatal_error ("Could not bind to AF_UNIX socket\n");
 	}
 
@@ -926,10 +1037,10 @@ extern void coroipcs_ipc_init (
 #endif
 	listen (server_fd, SERVER_BACKLOG);
 
-        /*
-         * Setup connection dispatch routine
-         */
-        api->poll_accept_add (server_fd);
+	/*
+	 * Setup connection dispatch routine
+	 */
+	api->poll_accept_add (server_fd);
 }
 
 void coroipcs_ipc_exit (void)
@@ -1000,12 +1111,14 @@ int coroipcs_response_send (void *conn, const void *msg, size_t mlen)
 retry_semop:
 	res = semop (conn_info->semid, &sop, 1);
 	if ((res == -1) && (errno == EINTR || errno == EAGAIN)) {
+		api->stats_increment_value (conn_info->stats_handle, "sem_retry_count");
 		goto retry_semop;
 	} else
 	if ((res == -1) && (errno == EINVAL || errno == EIDRM)) {
 		return (0);
 	}
 #endif
+	api->stats_increment_value (conn_info->stats_handle, "responses");
 	return (0);
 }
 
@@ -1038,12 +1151,14 @@ int coroipcs_response_iov_send (void *conn, const struct iovec *iov, unsigned in
 retry_semop:
 	res = semop (conn_info->semid, &sop, 1);
 	if ((res == -1) && (errno == EINTR || errno == EAGAIN)) {
+		api->stats_increment_value (conn_info->stats_handle, "sem_retry_count");
 		goto retry_semop;
 	} else
 	if ((res == -1) && (errno == EINVAL || errno == EIDRM)) {
 		return (0);
 	}
 #endif
+	api->stats_increment_value (conn_info->stats_handle, "responses");
 	return (0);
 }
 
@@ -1074,6 +1189,36 @@ static void memcpy_dwrap (struct conn_info *conn_info, void *msg, unsigned int l
 	conn_info->control_buffer->write = (write_idx + len) % conn_info->dispatch_size;
 }
 
+/**
+ * simulate the behaviour in coroipcc.c
+ */
+static int flow_control_event_send (struct conn_info *conn_info, char event)
+{
+	int new_fc = 0;
+
+	if (event == MESSAGE_RES_OUTQ_NOT_EMPTY ||
+		event == MESSAGE_RES_ENABLE_FLOWCONTROL) {
+		new_fc = 1;
+	}
+
+	if (conn_info->flow_control_state != new_fc) {
+		if (new_fc == 1) {
+			log_printf (LOGSYS_LEVEL_INFO, "Enabling flow control for %d, event %d\n",
+				conn_info->client_pid, event);
+		} else {
+			log_printf (LOGSYS_LEVEL_INFO, "Disabling flow control for %d, event %d\n",
+				conn_info->client_pid, event);
+		}
+		conn_info->flow_control_state = new_fc;
+		api->stats_update_value (conn_info->stats_handle, "flow_control",
+			&conn_info->flow_control_state,
+			sizeof(conn_info->flow_control_state));
+		api->stats_increment_value (conn_info->stats_handle, "flow_control_count");
+	}
+
+	return send (conn_info->fd, &event, 1, MSG_NOSIGNAL);
+}
+
 static void msg_send (void *conn, const struct iovec *iov, unsigned int iov_len,
 		      int locked)
 {
@@ -1083,14 +1228,16 @@ static void msg_send (void *conn, const struct iovec *iov, unsigned int iov_len,
 #endif
 	int res;
 	int i;
-	char buf;
 
 	for (i = 0; i < iov_len; i++) {
 		memcpy_dwrap (conn_info, iov[i].iov_base, iov[i].iov_len);
 	}
 
-	buf = !list_empty (&conn_info->outq_head);
-	res = send (conn_info->fd, &buf, 1, MSG_NOSIGNAL);
+	if (list_empty (&conn_info->outq_head))
+		res = flow_control_event_send (conn_info, MESSAGE_RES_OUTQ_EMPTY);
+	else
+		res = flow_control_event_send (conn_info, MESSAGE_RES_OUTQ_NOT_EMPTY);
+
 	if (res == -1 && errno == EAGAIN) {
 		if (locked == 0) {
 			pthread_mutex_lock (&conn_info->mutex);
@@ -1115,12 +1262,14 @@ static void msg_send (void *conn, const struct iovec *iov, unsigned int iov_len,
 retry_semop:
 	res = semop (conn_info->semid, &sop, 1);
 	if ((res == -1) && (errno == EINTR || errno == EAGAIN)) {
+		api->stats_increment_value (conn_info->stats_handle, "sem_retry_count");
 		goto retry_semop;
 	} else
 	if ((res == -1) && (errno == EINVAL || errno == EIDRM)) {
 		return;
 	}
 #endif
+	api->stats_increment_value (conn_info->stats_handle, "dispatched");
 }
 
 static void outq_flush (struct conn_info *conn_info) {
@@ -1128,13 +1277,11 @@ static void outq_flush (struct conn_info *conn_info) {
 	struct outq_item *outq_item;
 	unsigned int bytes_left;
 	struct iovec iov;
-	char buf;
 	int res;
 
 	pthread_mutex_lock (&conn_info->mutex);
 	if (list_empty (&conn_info->outq_head)) {
-		buf = 3;
-		res = send (conn_info->fd, &buf, 1, MSG_NOSIGNAL);
+		res = flow_control_event_send (conn_info, MESSAGE_RES_OUTQ_FLUSH_NR);
 		pthread_mutex_unlock (&conn_info->mutex);
 		return;
 	}
@@ -1151,6 +1298,7 @@ static void outq_flush (struct conn_info *conn_info) {
 			list_del (list);
 			api->free (iov.iov_base);
 			api->free (outq_item);
+			api->stats_decrement_value (conn_info->stats_handle, "queue_size");
 		} else {
 			break;
 		}
@@ -1173,9 +1321,11 @@ retry_recv:
 		sizeof (mar_req_priv_change),
 		MSG_NOSIGNAL);
 	if (res == -1 && errno == EINTR) {
+		api->stats_increment_value (conn_info->stats_handle, "recv_retry_count");
 		goto retry_recv;
 	}
 	if (res == -1 && errno == EAGAIN) {
+		api->stats_increment_value (conn_info->stats_handle, "recv_retry_count");
 		goto retry_recv;
 	}
 	if (res == -1 && errno != EAGAIN) {
@@ -1254,6 +1404,7 @@ static void msg_send_or_queue (void *conn, const struct iovec *iov, unsigned int
 		}
 		list_add_tail (&outq_item->list, &conn_info->outq_head);
 		pthread_mutex_unlock (&conn_info->mutex);
+		api->stats_increment_value (conn_info->stats_handle, "queue_size");
 		return;
 	}
 	msg_send (conn, iov, iov_len, MSG_SEND_LOCKED);
@@ -1316,13 +1467,16 @@ retry_accept:
 	}
 
 	if (new_fd == -1) {
-		api->log_printf ("Could not accept Library connection: %s\n", strerror (errno));
+		log_printf (LOGSYS_LEVEL_ERROR,
+			"Could not accept Library connection: %s\n", strerror (errno));
 		return (0); /* This is an error, but -1 would indicate disconnect from poll loop */
 	}
 
 	res = fcntl (new_fd, F_SETFL, O_NONBLOCK);
 	if (res == -1) {
-		api->log_printf ("Could not set non-blocking operation on library connection: %s\n", strerror (errno));
+		log_printf (LOGSYS_LEVEL_ERROR,
+			"Could not set non-blocking operation on library connection: %s\n",
+			strerror (errno));
 		close (new_fd);
 		return (0); /* This is an error, but -1 would indicate disconnect from poll loop */
 	}
@@ -1346,6 +1500,69 @@ retry_accept:
 	return (0);
 }
 
+static char * pid_to_name (pid_t pid, char *out_name, size_t name_len)
+{
+	char *name;
+	char *rest;
+	FILE *fp;
+	char fname[32];
+	char buf[256];
+
+	snprintf (fname, 32, "/proc/%d/stat", pid);
+	fp = fopen (fname, "r");
+	if (!fp) {
+		return NULL;
+	}
+
+	if (fgets (buf, sizeof (buf), fp) == NULL) {
+		fclose (fp);
+		return NULL;
+	}
+	fclose (fp);
+
+	name = strrchr (buf, '(');
+	if (!name) {
+		return NULL;
+	}
+
+	/* move past the bracket */
+	name++;
+
+	rest = strrchr (buf, ')');
+
+	if (rest == NULL || rest[1] != ' ') {
+		return NULL;
+	}
+
+	*rest = '\0';
+	/* move past the NULL and space */
+	rest += 2;
+
+	/* copy the name */
+	strncpy (out_name, name, name_len);
+	out_name[name_len - 1] = '\0';
+	return out_name;
+}
+
+static void coroipcs_init_conn_stats (
+	struct conn_info *conn)
+{
+	char conn_name[42];
+	char proc_name[32];
+
+	if (conn->client_pid > 0) {
+		if (pid_to_name (conn->client_pid, proc_name, sizeof(proc_name)))
+			snprintf (conn_name, sizeof(conn_name), "%s:%d:%d", proc_name, conn->client_pid, conn->fd);
+		else
+			snprintf (conn_name, sizeof(conn_name), "%d:%d", conn->client_pid, conn->fd);
+	} else
+		snprintf (conn_name, sizeof(conn_name), "%d", conn->fd);
+
+	conn->stats_handle = api->stats_create_connection (conn_name, conn->client_pid, conn->fd);
+	api->stats_update_value (conn->stats_handle, "service_id",
+		&conn->service, sizeof(conn->service));
+}
+
 int coroipcs_handler_dispatch (
 	int fd,
 	int revent,
@@ -1447,6 +1664,9 @@ int coroipcs_handler_dispatch (
 
 		api->init_fn_get (conn_info->service) (conn_info);
 
+		/* create stats objects */
+		coroipcs_init_conn_stats (conn_info);
+
 		pthread_attr_init (&conn_info->thread_attr);
 		/*
 		* IA64 needs more stack space then other arches
@@ -1505,9 +1725,13 @@ int coroipcs_handler_dispatch (
 	coroipcs_refcount_inc (conn_info);
 	pthread_mutex_lock (&conn_info->mutex);
 	if ((conn_info->state == CONN_STATE_THREAD_ACTIVE) && (revent & POLLOUT)) {
-		buf = !list_empty (&conn_info->outq_head);
+		if (list_empty (&conn_info->outq_head))
+			buf = MESSAGE_RES_OUTQ_EMPTY;
+		else
+			buf = MESSAGE_RES_OUTQ_NOT_EMPTY;
+
 		for (; conn_info->pending_semops;) {
-			res = send (conn_info->fd, &buf, 1, MSG_NOSIGNAL);
+			res = flow_control_event_send (conn_info, buf);
 			if (res == 1) {
 				conn_info->pending_semops--;
 			} else {
@@ -1515,8 +1739,7 @@ int coroipcs_handler_dispatch (
 			}
 		}
 		if (conn_info->notify_flow_control_enabled) {
-			buf = 2;
-			res = send (conn_info->fd, &buf, 1, MSG_NOSIGNAL);
+			res = flow_control_event_send (conn_info, MESSAGE_RES_ENABLE_FLOWCONTROL);
 			if (res == 1) {
 				conn_info->notify_flow_control_enabled = 0;
 			}
@@ -1533,3 +1756,4 @@ int coroipcs_handler_dispatch (
 
 	return (0);
 }
+
diff --git a/exec/coroparse.c b/exec/coroparse.c
index 5c4b374..ba7e954 100644
--- a/exec/coroparse.c
+++ b/exec/coroparse.c
@@ -172,9 +172,8 @@ static int parse_section(FILE *fp,
 				    key, error_string))
 					    return -1;
 			}
-			objdb->object_key_create (parent_handle, key,
-				strlen (key),
-				value, strlen (value) + 1);
+			objdb->object_key_create_typed (parent_handle, key,
+				value, strlen (value) + 1, OBJDB_VALUETYPE_STRING);
 		}
 
 		if ((loc = strchr_rs (line, '}'))) {
diff --git a/exec/logsys.c b/exec/logsys.c
index 978c157..d43f983 100644
--- a/exec/logsys.c
+++ b/exec/logsys.c
@@ -410,6 +410,11 @@ static inline int strcpy_cutoff (char *dest, const char *src, size_t cutoff,
 	return (cutoff);
 }
 
+static const char log_month_name[][4] = {
+	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
 /*
  * %s SUBSYSTEM
  * %n FUNCTION NAME
@@ -441,6 +446,7 @@ static void log_printf_to_logs (
 	int subsysid;
 	unsigned int level;
 	int c;
+	struct tm tm_res;
 
 	if (LOGSYS_DECODE_RECID(rec_ident) != LOGSYS_RECID_LOG) {
 		return;
@@ -490,7 +496,10 @@ static void log_printf_to_logs (
 
 				case 't':
 					gettimeofday (&tv, NULL);
-					(void)strftime (char_time, sizeof (char_time), "%b %d %T", localtime ((time_t *)&tv.tv_sec));
+					(void)localtime_r ((time_t *)&tv.tv_sec, &tm_res);
+					snprintf (char_time, sizeof (char_time), "%s %02d %02d:%02d:%02d",
+					    log_month_name[tm_res.tm_mon], tm_res.tm_mday, tm_res.tm_hour,
+					    tm_res.tm_min, tm_res.tm_sec);
 					normal_p = char_time;
 
 					/*
@@ -527,8 +536,12 @@ static void log_printf_to_logs (
 			syslog_output_buffer_idx += syslog_len;
 			format_buffer_idx += 1;
 		}
-		if ((normal_output_buffer_idx == sizeof (normal_output_buffer)) ||
-		    (syslog_output_buffer_idx == sizeof (syslog_output_buffer))) {
+		if ((normal_output_buffer_idx >= sizeof (normal_output_buffer) - 2) ||
+		    (syslog_output_buffer_idx >= sizeof (syslog_output_buffer) - 1)) {
+			/* Note: we make allowance for '\0' at the end of
+			 * both of these arrays and normal_output_buffer also
+			 * needs a '\n'.
+			 */
 			break;
 		}
 	}
diff --git a/exec/main.c b/exec/main.c
index 33adacb..2a2fded 100644
--- a/exec/main.c
+++ b/exec/main.c
@@ -129,6 +129,10 @@ static hdb_handle_t corosync_poll_handle;
 
 struct sched_param global_sched_param;
 
+static hdb_handle_t object_connection_handle;
+
+static corosync_timer_handle_t corosync_stats_timer_handle;
+
 hdb_handle_t corosync_poll_handle_get (void)
 {
 	return (corosync_poll_handle);
@@ -400,7 +404,7 @@ static void corosync_tty_detach (void)
 
 static void corosync_mlockall (void)
 {
-#if !defined(COROSYNC_BSD)
+#if !defined(COROSYNC_BSD) || defined(COROSYNC_FREEBSD_GE_8)
 	int res;
 #endif
 	struct rlimit rlimit;
@@ -413,8 +417,8 @@ static void corosync_mlockall (void)
 	setrlimit (RLIMIT_VMEM, &rlimit);
 #endif
 
-#if defined(COROSYNC_BSD)
-	/* under FreeBSD a process with locked page cannot call dlopen
+#if defined(COROSYNC_BSD) && !defined(COROSYNC_FREEBSD_GE_8)
+	/* under FreeBSD < 8 a process with locked page cannot call dlopen
 	 * code disabled until FreeBSD bug i386/93396 was solved
 	 */
 	log_printf (LOGSYS_LEVEL_WARNING, "Could not lock memory of service to avoid page faults\n");
@@ -426,6 +430,254 @@ static void corosync_mlockall (void)
 #endif
 }
 
+
+static void corosync_totem_stats_updater (void *data)
+{
+	totempg_stats_t * stats;
+	uint32_t mtt_rx_token;
+	uint32_t total_mtt_rx_token;
+	uint32_t avg_backlog_calc;
+	uint32_t total_backlog_calc;
+	uint32_t avg_token_holdtime;
+	uint32_t total_token_holdtime;
+	int t, prev;
+	int32_t token_count;
+
+	stats = api->totem_get_stats();
+
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"orf_token_tx", strlen("orf_token_tx"),
+		&stats->mrp->srp->orf_token_tx, sizeof (stats->mrp->srp->orf_token_tx));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"orf_token_rx", strlen("orf_token_rx"),
+		&stats->mrp->srp->orf_token_rx, sizeof (stats->mrp->srp->orf_token_rx));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"memb_merge_detect_tx", strlen("memb_merge_detect_tx"),
+		&stats->mrp->srp->memb_merge_detect_tx, sizeof (stats->mrp->srp->memb_merge_detect_tx));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"memb_merge_detect_rx", strlen("memb_merge_detect_rx"),
+		&stats->mrp->srp->memb_merge_detect_rx, sizeof (stats->mrp->srp->memb_merge_detect_rx));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"memb_join_tx", strlen("memb_join_tx"),
+		&stats->mrp->srp->memb_join_tx, sizeof (stats->mrp->srp->memb_join_tx));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"memb_join_rx", strlen("memb_join_rx"),
+		&stats->mrp->srp->memb_join_rx, sizeof (stats->mrp->srp->memb_join_rx));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"mcast_tx", strlen("mcast_tx"),
+		&stats->mrp->srp->mcast_tx,	sizeof (stats->mrp->srp->mcast_tx));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"mcast_retx", strlen("mcast_retx"),
+		&stats->mrp->srp->mcast_retx, sizeof (stats->mrp->srp->mcast_retx));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"mcast_rx", strlen("mcast_rx"),
+		&stats->mrp->srp->mcast_rx, sizeof (stats->mrp->srp->mcast_rx));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"memb_commit_token_tx", strlen("memb_commit_token_tx"),
+		&stats->mrp->srp->memb_commit_token_tx, sizeof (stats->mrp->srp->memb_commit_token_tx));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"memb_commit_token_rx", strlen("memb_commit_token_rx"),
+		&stats->mrp->srp->memb_commit_token_rx, sizeof (stats->mrp->srp->memb_commit_token_rx));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"token_hold_cancel_tx", strlen("token_hold_cancel_tx"),
+		&stats->mrp->srp->token_hold_cancel_tx, sizeof (stats->mrp->srp->token_hold_cancel_tx));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"token_hold_cancel_rx", strlen("token_hold_cancel_rx"),
+		&stats->mrp->srp->token_hold_cancel_rx, sizeof (stats->mrp->srp->token_hold_cancel_rx));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"operational_entered", strlen("operational_entered"),
+		&stats->mrp->srp->operational_entered, sizeof (stats->mrp->srp->operational_entered));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"operational_token_lost", strlen("operational_token_lost"),
+		&stats->mrp->srp->operational_token_lost, sizeof (stats->mrp->srp->operational_token_lost));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"gather_entered", strlen("gather_entered"),
+		&stats->mrp->srp->gather_entered, sizeof (stats->mrp->srp->gather_entered));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"gather_token_lost", strlen("gather_token_lost"),
+		&stats->mrp->srp->gather_token_lost, sizeof (stats->mrp->srp->gather_token_lost));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"commit_entered", strlen("commit_entered"),
+		&stats->mrp->srp->commit_entered, sizeof (stats->mrp->srp->commit_entered));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"commit_token_lost", strlen("commit_token_lost"),
+		&stats->mrp->srp->commit_token_lost, sizeof (stats->mrp->srp->commit_token_lost));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"recovery_entered", strlen("recovery_entered"),
+		&stats->mrp->srp->recovery_entered, sizeof (stats->mrp->srp->recovery_entered));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"recovery_token_lost", strlen("recovery_token_lost"),
+		&stats->mrp->srp->recovery_token_lost, sizeof (stats->mrp->srp->recovery_token_lost));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"consensus_timeouts", strlen("consensus_timeouts"),
+		&stats->mrp->srp->consensus_timeouts, sizeof (stats->mrp->srp->consensus_timeouts));
+	objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+		"rx_msg_dropped", strlen("rx_msg_dropped"),
+		&stats->mrp->srp->rx_msg_dropped, sizeof (stats->mrp->srp->rx_msg_dropped));
+
+	total_mtt_rx_token = 0;
+	total_token_holdtime = 0;
+	total_backlog_calc = 0;
+	token_count = 0;
+	t = stats->mrp->srp->latest_token;
+	while (1) {
+		if (t == 0)
+			prev = TOTEM_TOKEN_STATS_MAX - 1;
+		else
+			prev = t - 1;
+		if (prev == stats->mrp->srp->earliest_token)
+			break;
+		/* if tx == 0, then dropped token (not ours) */
+		if (stats->mrp->srp->token[t].tx != 0 ||
+			(stats->mrp->srp->token[t].rx - stats->mrp->srp->token[prev].rx) > 0 ) {
+			total_mtt_rx_token += (stats->mrp->srp->token[t].rx - stats->mrp->srp->token[prev].rx);
+			total_token_holdtime += (stats->mrp->srp->token[t].tx - stats->mrp->srp->token[t].rx);
+			total_backlog_calc += stats->mrp->srp->token[t].backlog_calc;
+			token_count++;
+		}
+		t = prev;
+	}
+	if (token_count) {
+		mtt_rx_token = (total_mtt_rx_token / token_count);
+		avg_backlog_calc = (total_backlog_calc / token_count);
+		avg_token_holdtime = (total_token_holdtime / token_count);
+
+		objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+			"mtt_rx_token", strlen("mtt_rx_token"),
+			&mtt_rx_token, sizeof (mtt_rx_token));
+		objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+			"avg_token_workload", strlen("avg_token_workload"),
+			&avg_token_holdtime, sizeof (avg_backlog_calc));
+		objdb->object_key_replace (stats->mrp->srp->hdr.handle,
+			"avg_backlog_calc", strlen("avg_backlog_calc"),
+			&avg_backlog_calc, sizeof (avg_backlog_calc));
+	}
+	api->timer_add_duration (1500 * MILLI_2_NANO_SECONDS, NULL,
+		corosync_totem_stats_updater,
+		&corosync_stats_timer_handle);
+}
+
+static void corosync_totem_stats_init (void)
+{
+	totempg_stats_t * stats;
+	hdb_handle_t object_find_handle;
+	hdb_handle_t object_runtime_handle;
+	hdb_handle_t object_totem_handle;
+	uint32_t zero_32 = 0;
+	uint64_t zero_64 = 0;
+
+	stats = api->totem_get_stats();
+
+	objdb->object_find_create (
+		OBJECT_PARENT_HANDLE,
+		"runtime",
+		strlen ("runtime"),
+		&object_find_handle);
+
+	if (objdb->object_find_next (object_find_handle,
+			&object_runtime_handle) == 0) {
+
+		objdb->object_create (object_runtime_handle,
+			&object_totem_handle,
+			"totem", strlen ("totem"));
+		objdb->object_create (object_totem_handle,
+			&stats->hdr.handle,
+			"pg", strlen ("pg"));
+		objdb->object_create (stats->hdr.handle,
+			&stats->mrp->hdr.handle,
+			"mrp", strlen ("mrp"));
+		objdb->object_create (stats->mrp->hdr.handle,
+			&stats->mrp->srp->hdr.handle,
+			"srp", strlen ("srp"));
+
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"orf_token_tx",	&stats->mrp->srp->orf_token_tx,
+			sizeof (stats->mrp->srp->orf_token_tx),	OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"orf_token_rx", &stats->mrp->srp->orf_token_rx,
+			sizeof (stats->mrp->srp->orf_token_rx), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"memb_merge_detect_tx", &stats->mrp->srp->memb_merge_detect_tx,
+			sizeof (stats->mrp->srp->memb_merge_detect_tx), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"memb_merge_detect_rx", &stats->mrp->srp->memb_merge_detect_rx,
+			sizeof (stats->mrp->srp->memb_merge_detect_rx), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"memb_join_tx", &stats->mrp->srp->memb_join_tx,
+			sizeof (stats->mrp->srp->memb_join_tx), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"memb_join_rx", &stats->mrp->srp->memb_join_rx,
+			sizeof (stats->mrp->srp->memb_join_rx), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"mcast_tx", &stats->mrp->srp->mcast_tx,
+			sizeof (stats->mrp->srp->mcast_tx), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"mcast_retx", &stats->mrp->srp->mcast_retx,
+			sizeof (stats->mrp->srp->mcast_retx), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"mcast_rx", &stats->mrp->srp->mcast_rx,
+			sizeof (stats->mrp->srp->mcast_rx), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"memb_commit_token_tx", &stats->mrp->srp->memb_commit_token_tx,
+			sizeof (stats->mrp->srp->memb_commit_token_tx), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"memb_commit_token_rx", &stats->mrp->srp->memb_commit_token_rx,
+			sizeof (stats->mrp->srp->memb_commit_token_rx), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"token_hold_cancel_tx", &stats->mrp->srp->token_hold_cancel_tx,
+			sizeof (stats->mrp->srp->token_hold_cancel_tx), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"token_hold_cancel_rx", &stats->mrp->srp->token_hold_cancel_rx,
+			sizeof (stats->mrp->srp->token_hold_cancel_rx), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"operational_entered", &stats->mrp->srp->operational_entered,
+			sizeof (stats->mrp->srp->operational_entered), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"operational_token_lost", &stats->mrp->srp->operational_token_lost,
+			sizeof (stats->mrp->srp->operational_token_lost), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"gather_entered", &stats->mrp->srp->gather_entered,
+			sizeof (stats->mrp->srp->gather_entered), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"gather_token_lost", &stats->mrp->srp->gather_token_lost,
+			sizeof (stats->mrp->srp->gather_token_lost), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"commit_entered", &stats->mrp->srp->commit_entered,
+			sizeof (stats->mrp->srp->commit_entered), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"commit_token_lost", &stats->mrp->srp->commit_token_lost,
+			sizeof (stats->mrp->srp->commit_token_lost), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"recovery_entered", &stats->mrp->srp->recovery_entered,
+			sizeof (stats->mrp->srp->recovery_entered), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"recovery_token_lost", &stats->mrp->srp->recovery_token_lost,
+			sizeof (stats->mrp->srp->recovery_token_lost), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"consensus_timeouts", &stats->mrp->srp->consensus_timeouts,
+			sizeof (stats->mrp->srp->consensus_timeouts), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"mtt_rx_token", &zero_32,
+			sizeof (zero_32), OBJDB_VALUETYPE_UINT32);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"avg_token_workload", &zero_32,
+			sizeof (zero_32), OBJDB_VALUETYPE_UINT32);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"avg_backlog_calc", &zero_64,
+			sizeof (zero_64), OBJDB_VALUETYPE_UINT64);
+		objdb->object_key_create_typed (stats->mrp->srp->hdr.handle,
+			"rx_msg_dropped", &zero_64,
+			sizeof (zero_64), OBJDB_VALUETYPE_UINT64);
+
+	}
+	/* start stats timer */
+	api->timer_add_duration (1500 * MILLI_2_NANO_SECONDS, NULL,
+		corosync_totem_stats_updater,
+		&corosync_stats_timer_handle);
+
+}
+
+
 static void deliver_fn (
 	unsigned int nodeid,
 	const void *msg,
@@ -437,6 +689,7 @@ static void deliver_fn (
 	int fn_id;
 	unsigned int id;
 	unsigned int size;
+	unsigned int key_incr_dummy;
 
 	header = msg;
 	if (endian_conversion_required) {
@@ -465,6 +718,10 @@ static void deliver_fn (
 		return;
 	}
 
+	objdb->object_key_increment (service_stats_handle[service][fn_id],
+		"rx", strlen("rx"),
+		&key_incr_dummy);
+
 	if (endian_conversion_required) {
 		assert(ais_service[service]->exec_engine[fn_id].exec_endian_convert_fn != NULL);
 		ais_service[service]->exec_engine[fn_id].exec_endian_convert_fn
@@ -488,6 +745,19 @@ int main_mcast (
         unsigned int iov_len,
         unsigned int guarantee)
 {
+	const coroipc_request_header_t *req = iovec->iov_base;
+	int service;
+	int fn_id;
+	unsigned int key_incr_dummy;
+
+	service = req->id >> 16;
+	fn_id = req->id & 0xffff;
+
+	if (ais_service[service]) {
+		objdb->object_key_increment (service_stats_handle[service][fn_id],
+			"tx", strlen("tx"), &key_incr_dummy);
+	}
+
 	return (totempg_groups_mcast_joined (corosync_group_handle, iovec, iov_len, guarantee));
 }
 
@@ -611,21 +881,6 @@ static void corosync_sending_allowed_release (void *sending_allowed_private_data
 
 static int ipc_subsys_id = -1;
 
-static void ipc_log_printf (const char *format, ...) __attribute__((format(printf, 1, 2)));
-static void ipc_log_printf (const char *format, ...) {
-	va_list ap;
-
-	va_start (ap, format);
-
-	_logsys_log_vprintf (
-		LOGSYS_ENCODE_RECID(LOGSYS_LEVEL_ERROR,
-				    ipc_subsys_id,
-				    LOGSYS_RECID_LOG),
-		__FUNCTION__, __FILE__, __LINE__,
-		format, ap);
-
-	va_end (ap);
-}
 
 static void ipc_fatal_error(const char *error_msg) {
        _logsys_log_printf (
@@ -679,13 +934,132 @@ static void corosync_poll_dispatch_modify (
 		corosync_poll_handler_dispatch);
 }
 
-static struct coroipcs_init_state ipc_init_state = {
+
+static hdb_handle_t corosync_stats_create_connection (const char* name,
+                       const pid_t pid, const int fd)
+{
+	uint32_t zero_32 = 0;
+	uint64_t zero_64 = 0;
+	unsigned int key_incr_dummy;
+	hdb_handle_t object_handle;
+
+	objdb->object_key_increment (object_connection_handle,
+		"active", strlen("active"),
+		&key_incr_dummy);
+
+
+	objdb->object_create (object_connection_handle,
+		&object_handle,
+		name,
+		strlen (name));
+
+	objdb->object_key_create_typed (object_handle,
+		"service_id",
+		&zero_32, sizeof (zero_32),
+		OBJDB_VALUETYPE_UINT32);
+
+	objdb->object_key_create_typed (object_handle,
+		"client_pid",
+		&pid, sizeof (pid),
+		OBJDB_VALUETYPE_INT32);
+
+	objdb->object_key_create_typed (object_handle,
+		"responses",
+		&zero_64, sizeof (zero_64),
+		OBJDB_VALUETYPE_UINT64);
+
+	objdb->object_key_create_typed (object_handle,
+		"dispatched",
+		&zero_64, sizeof (zero_64),
+		OBJDB_VALUETYPE_UINT64);
+
+	objdb->object_key_create_typed (object_handle,
+		"requests",
+		&zero_64, sizeof (zero_64),
+		OBJDB_VALUETYPE_INT64);
+
+	objdb->object_key_create_typed (object_handle,
+		"sem_retry_count",
+		&zero_64, sizeof (zero_64),
+		OBJDB_VALUETYPE_UINT64);
+
+	objdb->object_key_create_typed (object_handle,
+		"send_retry_count",
+		&zero_64, sizeof (zero_64),
+		OBJDB_VALUETYPE_UINT64);
+
+	objdb->object_key_create_typed (object_handle,
+		"recv_retry_count",
+		&zero_64, sizeof (zero_64),
+		OBJDB_VALUETYPE_UINT64);
+
+	objdb->object_key_create_typed (object_handle,
+		"flow_control",
+		&zero_32, sizeof (zero_32),
+		OBJDB_VALUETYPE_UINT32);
+
+	objdb->object_key_create_typed (object_handle,
+		"flow_control_count",
+		&zero_64, sizeof (zero_64),
+		OBJDB_VALUETYPE_UINT64);
+
+	objdb->object_key_create_typed (object_handle,
+		"queue_size",
+		&zero_64, sizeof (zero_64),
+		OBJDB_VALUETYPE_UINT64);
+
+	return object_handle;
+}
+
+static void corosync_stats_destroy_connection (hdb_handle_t handle)
+{
+	unsigned int key_incr_dummy;
+
+	objdb->object_destroy (handle);
+
+	objdb->object_key_increment (object_connection_handle,
+		"closed", strlen("closed"),
+		&key_incr_dummy);
+	objdb->object_key_decrement (object_connection_handle,
+		"active", strlen("active"),
+		&key_incr_dummy);
+}
+
+static void corosync_stats_update_value (hdb_handle_t handle,
+	const char *name, const void *value,
+	size_t value_len)
+{
+	objdb->object_key_replace (handle,
+		name, strlen(name),
+		value, value_len);
+}
+
+static void corosync_stats_increment_value (hdb_handle_t handle,
+	const char* name)
+{
+	unsigned int key_incr_dummy;
+
+	objdb->object_key_increment (handle,
+		name, strlen(name),
+		&key_incr_dummy);
+}
+static void corosync_stats_decrement_value (hdb_handle_t handle,
+	const char* name)
+{
+	unsigned int key_incr_dummy;
+
+	objdb->object_key_decrement (handle,
+		name, strlen(name),
+		&key_incr_dummy);
+}
+
+static struct coroipcs_init_state_v2 ipc_init_state_v2 = {
 	.socket_name			= COROSYNC_SOCKET_NAME,
 	.sched_policy			= SCHED_OTHER,
 	.sched_param			= &global_sched_param,
 	.malloc				= malloc,
 	.free				= free,
-	.log_printf			= ipc_log_printf,
+	.log_printf			= _logsys_log_printf,
 	.fatal_error			= ipc_fatal_error,
 	.security_valid			= corosync_security_valid,
 	.service_available		= corosync_service_available,
@@ -699,7 +1073,12 @@ static struct coroipcs_init_state ipc_init_state = {
 	.poll_dispatch_modify		= corosync_poll_dispatch_modify,
 	.init_fn_get			= corosync_init_fn_get,
 	.exit_fn_get			= corosync_exit_fn_get,
-	.handler_fn_get			= corosync_handler_fn_get
+	.handler_fn_get			= corosync_handler_fn_get,
+	.stats_create_connection	= corosync_stats_create_connection,
+	.stats_destroy_connection	= corosync_stats_destroy_connection,
+	.stats_update_value		= corosync_stats_update_value,
+	.stats_increment_value		= corosync_stats_increment_value,
+	.stats_decrement_value		= corosync_stats_decrement_value,
 };
 
 static void corosync_setscheduler (void)
@@ -721,7 +1100,7 @@ static void corosync_setscheduler (void)
 			/*
 			 * Turn on SCHED_RR in ipc system
 			 */
-			ipc_init_state.sched_policy = SCHED_RR;
+			ipc_init_state_v2.sched_policy = SCHED_RR;
 
 			/*
 			 * Turn on SCHED_RR in logsys system
@@ -744,6 +1123,35 @@ static void corosync_setscheduler (void)
 #endif
 }
 
+static void corosync_stats_init (void)
+{
+	hdb_handle_t object_find_handle;
+	hdb_handle_t object_runtime_handle;
+	uint64_t zero_64 = 0;
+
+	objdb->object_find_create (OBJECT_PARENT_HANDLE,
+		"runtime", strlen ("runtime"),
+		&object_find_handle);
+
+	if (objdb->object_find_next (object_find_handle,
+			&object_runtime_handle) != 0) {
+		return;
+	}
+
+	/* Connection objects */
+	objdb->object_create (object_runtime_handle,
+		&object_connection_handle,
+		"connections", strlen ("connections"));
+
+	objdb->object_key_create_typed (object_connection_handle,
+		"active", &zero_64, sizeof (zero_64),
+		OBJDB_VALUETYPE_UINT64);
+	objdb->object_key_create_typed (object_connection_handle,
+		"closed", &zero_64, sizeof (zero_64),
+		OBJDB_VALUETYPE_UINT64);
+}
+
+
 static void main_service_ready (void)
 {
 	int res;
@@ -756,6 +1164,8 @@ static void main_service_ready (void)
 		corosync_exit_error (AIS_DONE_INIT_SERVICES);
 	}
 	evil_init (api);
+	corosync_stats_init ();
+	corosync_totem_stats_init ();
 }
 
 int main (int argc, char **argv)
@@ -775,6 +1185,7 @@ int main (int argc, char **argv)
 	int background, setprio;
 	struct stat stat_out;
 	char corosync_lib_dir[PATH_MAX];
+	hdb_handle_t object_runtime_handle;
 
 #if defined(HAVE_PTHREAD_SPIN_LOCK)
 	pthread_spin_init (&serialize_spin, 0);
@@ -835,13 +1246,6 @@ int main (int argc, char **argv)
 	(void)signal (SIGPIPE, SIG_IGN);
 #endif
 
-	corosync_timer_init (
-		serialize_lock,
-		serialize_unlock,
-		sched_priority);
-
-	corosync_poll_handle = poll_create ();
-
 	/*
 	 * Load the object database interface
 	 */
@@ -965,7 +1369,7 @@ int main (int argc, char **argv)
 		corosync_exit_error (AIS_DONE_MAINCONFIGREAD);
 	}
 
-  	totem_config.totem_logging_configuration.log_level_security = LOGSYS_LEVEL_WARNING;
+	totem_config.totem_logging_configuration.log_level_security = LOGSYS_LEVEL_WARNING;
 	totem_config.totem_logging_configuration.log_level_error = LOGSYS_LEVEL_ERROR;
 	totem_config.totem_logging_configuration.log_level_warning = LOGSYS_LEVEL_WARNING;
 	totem_config.totem_logging_configuration.log_level_notice = LOGSYS_LEVEL_NOTICE;
@@ -988,6 +1392,11 @@ int main (int argc, char **argv)
 		corosync_exit_error (AIS_DONE_MAINCONFIGREAD);
 	}
 
+	/* create the main runtime object */
+	objdb->object_create (OBJECT_PARENT_HANDLE,
+		&object_runtime_handle,
+		"runtime", strlen ("runtime"));
+
 	/*
 	 * Now we are fully initialized.
 	 */
@@ -996,6 +1405,13 @@ int main (int argc, char **argv)
 	}
 	logsys_fork_completed();
 
+	corosync_timer_init (
+		serialize_lock,
+		serialize_unlock,
+		sched_priority);
+
+	corosync_poll_handle = poll_create ();
+
 	/*
 	 * Sleep for a while to let other nodes in the cluster
 	 * understand that this node has been away (if it was
@@ -1061,9 +1477,9 @@ int main (int argc, char **argv)
 	 */
 	priv_drop ();
 
- 	schedwrk_init (
- 		serialize_lock,
- 		serialize_unlock);
+	schedwrk_init (
+		serialize_lock,
+		serialize_unlock);
 
 	ipc_subsys_id = _logsys_subsys_create ("IPC");
 	if (ipc_subsys_id < 0) {
@@ -1072,7 +1488,8 @@ int main (int argc, char **argv)
 		corosync_exit_error (AIS_DONE_INIT_SERVICES);
 	}
 
-	coroipcs_ipc_init (&ipc_init_state);
+	ipc_init_state_v2.log_subsys_id = ipc_subsys_id;
+	coroipcs_ipc_init_v2 (&ipc_init_state_v2);
 
 	/*
 	 * Start main processing loop
@@ -1081,3 +1498,4 @@ int main (int argc, char **argv)
 
 	return EXIT_SUCCESS;
 }
+
diff --git a/exec/objdb.c b/exec/objdb.c
index 33688cb..67acc39 100644
--- a/exec/objdb.c
+++ b/exec/objdb.c
@@ -53,6 +53,7 @@ struct object_key {
 	size_t key_len;
 	void *value;
 	size_t value_len;
+	objdb_value_types_t value_type;
 	struct list_head list;
 };
 
@@ -204,9 +205,9 @@ static int _object_notify_deleted_children(struct object_instance *parent_pt)
 			if ((tracker_pt != NULL) &&
 				(tracker_pt->object_destroy_notify_fn != NULL))
 				tracker_pt->object_destroy_notify_fn(parent_pt->object_handle,
-													 obj_pt->object_name,
-													 obj_pt->object_name_len,
-													 tracker_pt->data_pt);
+					obj_pt->object_name,
+					obj_pt->object_name_len,
+					tracker_pt->data_pt);
 		}
 	}
 
@@ -236,9 +237,10 @@ static void object_created_notification(
 			if (((obj_handle == parent_object_handle) ||
 				 (tracker_pt->depth == OBJECT_TRACK_DEPTH_RECURSIVE)) &&
 				(tracker_pt->object_create_notify_fn != NULL)) {
-				tracker_pt->object_create_notify_fn(object_handle, parent_object_handle,
-									 name_pt, name_len,
-									 tracker_pt->data_pt);
+				tracker_pt->object_create_notify_fn(object_handle,
+					parent_object_handle,
+					name_pt, name_len,
+					tracker_pt->data_pt);
 			}
 		}
 
@@ -452,9 +454,9 @@ static int object_create (
 
 	hdb_handle_put (&object_instance_database, parent_object_handle);
 	object_created_notification(object_instance->object_handle,
-								object_instance->parent_handle,
-								object_instance->object_name,
-								object_instance->object_name_len);
+		object_instance->parent_handle,
+		object_instance->object_name,
+		object_instance->object_name_len);
 	objdb_rdunlock();
 	return (0);
 
@@ -498,12 +500,12 @@ error_exit:
 	return (-1);
 }
 
-static int object_key_create (
+static int object_key_create_typed(
 	hdb_handle_t object_handle,
-	const void *key_name,
-	size_t key_len,
+	const char *key_name,
 	const void *value,
-	size_t value_len)
+	size_t value_len,
+	objdb_value_types_t value_type)
 {
 	struct object_instance *instance;
 	struct object_key *object_key;
@@ -511,15 +513,55 @@ static int object_key_create (
 	struct list_head *list;
 	int found = 0;
 	int i;
+	size_t key_len = strlen(key_name);
+	size_t expected_size;
+	int test_size_by_type = CS_TRUE;
 
 	objdb_rdlock();
 
 	res = hdb_handle_get (&object_instance_database,
-		object_handle, (void *)&instance);
+			  object_handle, (void *)&instance);
 	if (res != 0) {
 		goto error_exit;
 	}
 
+	switch (value_type) {
+	case OBJDB_VALUETYPE_INT16:
+		expected_size = sizeof (int16_t);
+		break;
+	case OBJDB_VALUETYPE_UINT16:
+		expected_size = sizeof (uint16_t);
+		break;
+	case OBJDB_VALUETYPE_INT32:
+		expected_size = sizeof (int32_t);
+		break;
+	case OBJDB_VALUETYPE_UINT32:
+		expected_size = sizeof (uint32_t);
+		break;
+	case OBJDB_VALUETYPE_INT64:
+		expected_size = sizeof (int64_t);
+		break;
+	case OBJDB_VALUETYPE_UINT64:
+		expected_size = sizeof (uint64_t);
+		break;
+	case OBJDB_VALUETYPE_FLOAT:
+		expected_size = sizeof (float);
+		break;
+	case OBJDB_VALUETYPE_DOUBLE:
+		expected_size = sizeof (double);
+		break;
+	case OBJDB_VALUETYPE_ANY:
+	default:
+		test_size_by_type = CS_FALSE;
+		break;
+	}
+	if (test_size_by_type) {
+		if (expected_size != value_len) {
+			//printf ("%s exp:%d != len:%d\n", key_name, expected_size, value_len);
+			goto error_put;
+		}
+	}
+
 	/*
 	 * Do validation check if validation is configured for the parent object
 	 */
@@ -574,11 +616,11 @@ static int object_key_create (
 		if (object_key == 0) {
 			goto error_put;
 		}
-		object_key->key_name = malloc (key_len);
+		object_key->key_name = malloc (key_len + 1);
 		if (object_key->key_name == 0) {
 			goto error_put_object;
 		}
-		memcpy (object_key->key_name, key_name, key_len);
+		memcpy (object_key->key_name, key_name, key_len + 1);
 		list_init (&object_key->list);
 		list_add_tail (&object_key->list, &instance->key_head);
 	}
@@ -590,9 +632,11 @@ static int object_key_create (
 
 	object_key->key_len = key_len;
 	object_key->value_len = value_len;
+	object_key->value_type = value_type;
 
 	object_key_changed_notification(object_handle, key_name, key_len,
-					value, value_len, OBJECT_KEY_CREATED);
+		value, value_len, OBJECT_KEY_CREATED);
+	hdb_handle_put (&object_instance_database, object_handle);
 	objdb_rdunlock();
 	return (0);
 
@@ -610,6 +654,32 @@ error_exit:
 	return (-1);
 }
 
+static int object_key_create (
+	hdb_handle_t object_handle,
+	const void *key_name,
+	size_t key_len,
+	const void *value,
+	size_t value_len)
+{
+	char *key_name_terminated = NULL;
+	char *key_name_str = (char*)key_name;
+	int ret;
+
+	if (key_name_str[key_len-1] != '\0') {
+		key_name_terminated = malloc (key_len + 1);
+		memcpy (key_name_terminated, key_name, key_len);
+		key_name_terminated[key_len] = '\0';
+		key_name_str = key_name_terminated;
+	}
+
+	ret = object_key_create_typed (object_handle, key_name_str,
+		value, value_len, OBJDB_VALUETYPE_ANY);
+	if (key_name_terminated) {
+		free (key_name_terminated);
+	}
+	return ret;
+}
+
 static int _clear_object(struct object_instance *instance)
 {
 	struct list_head *list;
@@ -628,6 +698,7 @@ static int _clear_object(struct object_instance *instance)
 		list_del(&object_key->list);
 		free(object_key->key_name);
 		free(object_key->value);
+		free(object_key);
 	}
 
 	for (list = instance->child_head.next;
@@ -674,7 +745,8 @@ static int object_destroy (
 
 	list_del(&instance->child_list);
 	free(instance->object_name);
-	free(instance);
+	hdb_handle_put (&object_instance_database, object_handle);
+	hdb_handle_destroy (&object_instance_database, object_handle);
 
 	objdb_rdunlock();
 	return (res);
@@ -861,18 +933,19 @@ error_exit:
 	return (-1);
 }
 
-static int object_key_get (
+static int object_key_get_typed (
 	hdb_handle_t object_handle,
-	const void *key_name,
-	size_t key_len,
+	const char *key_name,
 	void **value,
-	size_t *value_len)
+	size_t *value_len,
+	objdb_value_types_t * type)
 {
 	unsigned int res = 0;
 	struct object_instance *instance;
 	struct object_key *object_key = NULL;
 	struct list_head *list;
 	int found = 0;
+	size_t key_len = strlen(key_name);
 
 	objdb_rdlock();
 	res = hdb_handle_get (&object_instance_database,
@@ -896,6 +969,7 @@ static int object_key_get (
 		if (value_len) {
 			*value_len = object_key->value_len;
 		}
+		*type = object_key->value_type;
 	}
 	else {
 		res = -1;
@@ -910,6 +984,34 @@ error_exit:
 	return (-1);
 }
 
+static int object_key_get (
+	hdb_handle_t object_handle,
+	const void *key_name,
+	size_t key_len,
+	void **value,
+	size_t *value_len)
+{
+	objdb_value_types_t t;
+	int ret;
+	char *key_name_str = (char*)key_name;
+	char *key_name_terminated = NULL;
+
+	if (key_name_str[key_len-1] != '\0') {
+		key_name_terminated = malloc (key_len + 1);
+		memcpy (key_name_terminated, key_name, key_len);
+		key_name_terminated[key_len] = '\0';
+		key_name_str = key_name_terminated;
+	}
+
+	ret = object_key_get_typed(object_handle,
+		key_name_str,
+		value, value_len, &t);
+	if (key_name_terminated) {
+		free (key_name_terminated);
+	}
+	return ret;
+}
+
 static int object_key_increment (
 	hdb_handle_t object_handle,
 	const void *key_name,
@@ -939,9 +1041,45 @@ static int object_key_increment (
 			break;
 		}
 	}
-	if (found && object_key->value_len == sizeof(int)) {
-		(*(int *)object_key->value)++;
-		*value = *(int *)object_key->value;
+
+	if (found) {
+		switch (object_key->value_type) {
+		case OBJDB_VALUETYPE_INT16:
+			(*(int16_t *)object_key->value)++;
+			break;
+		case OBJDB_VALUETYPE_UINT16:
+			(*(uint16_t *)object_key->value)++;
+			break;
+		case OBJDB_VALUETYPE_INT32:
+			(*(int32_t *)object_key->value)++;
+			break;
+		case OBJDB_VALUETYPE_UINT32:
+			(*(uint32_t *)object_key->value)++;
+			break;
+		case OBJDB_VALUETYPE_INT64:
+			(*(int64_t *)object_key->value)++;
+			break;
+		case OBJDB_VALUETYPE_UINT64:
+			(*(uint64_t *)object_key->value)++;
+			break;
+		case OBJDB_VALUETYPE_ANY:
+			/* for backwards compatibilty */
+			if (object_key->value_len == sizeof(int)) {
+				(*(int *)object_key->value)++;
+			}
+			else {
+				res = -1;
+			}
+			break;
+		default:
+			res = -1;
+			break;
+		}
+		if (res == 0) {
+			/* nasty, not sure why we need to return this typed
+			 * instead of void* */
+			*value = *(int *)object_key->value;
+		}
 	}
 	else {
 		res = -1;
@@ -985,9 +1123,46 @@ static int object_key_decrement (
 			break;
 		}
 	}
-	if (found && object_key->value_len == sizeof(int)) {
-		(*(int *)object_key->value)--;
-		*value = *(int *)object_key->value;
+
+
+	if (found) {
+		switch (object_key->value_type) {
+		case OBJDB_VALUETYPE_INT16:
+			(*(int16_t *)object_key->value)--;
+			break;
+		case OBJDB_VALUETYPE_UINT16:
+			(*(uint16_t *)object_key->value)--;
+			break;
+		case OBJDB_VALUETYPE_INT32:
+			(*(int32_t *)object_key->value)--;
+			break;
+		case OBJDB_VALUETYPE_UINT32:
+			(*(uint32_t *)object_key->value)--;
+			break;
+		case OBJDB_VALUETYPE_INT64:
+			(*(int64_t *)object_key->value)--;
+			break;
+		case OBJDB_VALUETYPE_UINT64:
+			(*(uint64_t *)object_key->value)--;
+			break;
+		case OBJDB_VALUETYPE_ANY:
+			/* for backwards compatibilty */
+			if (object_key->value_len == sizeof(int)) {
+				(*(int *)object_key->value)--;
+			}
+			else {
+				res = -1;
+			}
+			break;
+		default:
+			res = -1;
+			break;
+		}
+		if (res == 0) {
+			/* nasty, not sure why we need to return this typed
+			 * instead of void* */
+			*value = *(int *)object_key->value;
+		}
 	}
 	else {
 		res = -1;
@@ -1043,9 +1218,10 @@ static int object_key_delete (
 	}
 
 	hdb_handle_put (&object_instance_database, object_handle);
-	if (ret == 0)
+	if (ret == 0) {
 		object_key_changed_notification(object_handle, key_name, key_len,
-										NULL, 0, OBJECT_KEY_DELETED);
+			NULL, 0, OBJECT_KEY_DELETED);
+	}
 	objdb_rdunlock();
 	return (ret);
 
@@ -1140,9 +1316,10 @@ static int object_key_replace (
 	}
 
 	hdb_handle_put (&object_instance_database, object_handle);
-	if (ret == 0)
-		object_key_changed_notification(object_handle, key_name, key_len,
-										new_value, new_value_len, OBJECT_KEY_REPLACED);
+	if (ret == 0) {
+		object_key_changed_notification (object_handle, key_name, key_len,
+			new_value, new_value_len, OBJECT_KEY_REPLACED);
+	}
 	objdb_rdunlock();
 	return (ret);
 
@@ -1205,8 +1382,39 @@ static int _dump_object(struct object_instance *instance, FILE *file, int depth)
 
 		memcpy(stringbuf1, object_key->key_name, object_key->key_len);
 		stringbuf1[object_key->key_len] = '\0';
-		memcpy(stringbuf2, object_key->value, object_key->value_len);
-		stringbuf2[object_key->value_len] = '\0';
+
+		switch (object_key->value_type) {
+		case OBJDB_VALUETYPE_INT16:
+			snprintf (stringbuf2, sizeof(int), "%hd",
+				*(unsigned int*)object_key->value);
+			break;
+		case OBJDB_VALUETYPE_UINT16:
+			snprintf (stringbuf2, sizeof(int), "%hu",
+				*(unsigned int*)object_key->value);
+			break;
+		case OBJDB_VALUETYPE_INT32:
+			snprintf (stringbuf2, sizeof(int), "%d",
+				*(int*)object_key->value);
+			break;
+		case OBJDB_VALUETYPE_UINT32:
+			snprintf (stringbuf2, sizeof(int), "%u",
+				*(unsigned int*)object_key->value);
+			break;
+		case OBJDB_VALUETYPE_INT64:
+			snprintf (stringbuf2, sizeof(int), "%ld",
+				*(long int*)object_key->value);
+			break;
+		case OBJDB_VALUETYPE_UINT64:
+			snprintf (stringbuf2, sizeof(int), "%lu",
+				*(unsigned long int*)object_key->value);
+			break;
+		default:
+		case OBJDB_VALUETYPE_STRING:
+		case OBJDB_VALUETYPE_ANY:
+			memcpy(stringbuf2, object_key->value, object_key->value_len);
+			stringbuf2[object_key->value_len] = '\0';
+			break;
+		}
 
 		for (i=0; i<depth+1; i++)
 			fprintf(file, "    ");
@@ -1255,12 +1463,11 @@ error_exit:
 	return (-1);
 }
 
-
-static int object_key_iter(hdb_handle_t parent_object_handle,
-			   void **key_name,
-			   size_t *key_len,
-			   void **value,
-			   size_t *value_len)
+static int object_key_iter_typed (hdb_handle_t parent_object_handle,
+	char **key_name,
+	void **value,
+	size_t *value_len,
+	objdb_value_types_t *type)
 {
 	unsigned int res;
 	struct object_instance *instance;
@@ -1284,9 +1491,8 @@ static int object_key_iter(hdb_handle_t parent_object_handle,
 	instance->iter_key_list = list;
 	if (found) {
 		*key_name = find_key->key_name;
-		if (key_len)
-			*key_len = find_key->key_len;
 		*value = find_key->value;
+		*type = find_key->value_type;
 		if (value_len)
 			*value_len = find_key->value_len;
 		res = 0;
@@ -1304,6 +1510,22 @@ error_exit:
 	return (-1);
 }
 
+static int object_key_iter(hdb_handle_t parent_object_handle,
+			   void **key_name,
+			   size_t *key_len,
+			   void **value,
+			   size_t *value_len)
+{
+	objdb_value_types_t t;
+	int ret;
+	char *str;
+	ret = object_key_iter_typed (parent_object_handle,
+		(char**)key_name, value, value_len, &t);
+	str = *key_name;
+	*key_len = strlen(str);
+	return ret;
+}
+
 static int object_key_iter_from(hdb_handle_t parent_object_handle,
 				hdb_handle_t start_pos,
 				void **key_name,
@@ -1599,6 +1821,9 @@ struct objdb_iface_ver0 objdb_iface = {
 	.object_reload_config   = object_reload_config,
 	.object_key_increment   = object_key_increment,
 	.object_key_decrement   = object_key_decrement,
+	.object_key_create_typed	= object_key_create_typed,
+	.object_key_get_typed		= object_key_get_typed,
+	.object_key_iter_typed		= object_key_iter_typed,
 };
 
 struct lcr_iface objdb_iface_ver0[1] = {
@@ -1631,3 +1856,4 @@ __attribute__ ((constructor)) static void corosync_lcr_component_register (void)
 
 	lcr_component_register (&objdb_comp_ver0);
 }
+
diff --git a/exec/service.c b/exec/service.c
index d2bcd0f..d99e7bf 100644
--- a/exec/service.c
+++ b/exec/service.c
@@ -91,8 +91,12 @@ static struct default_service default_services[] = {
 
 struct corosync_service_engine *ais_service[SERVICE_HANDLER_MAXIMUM_COUNT];
 
+hdb_handle_t service_stats_handle[SERVICE_HANDLER_MAXIMUM_COUNT][64];
+
 static hdb_handle_t object_internal_configuration_handle;
 
+static hdb_handle_t object_stats_services_handle;
+
 static void (*service_unlink_all_complete) (void) = NULL;
 
 static hdb_handle_t unlink_all_handle;
@@ -145,6 +149,11 @@ unsigned int corosync_service_link_and_init (
 	struct corosync_service_engine *service;
 	unsigned int res;
 	hdb_handle_t object_service_handle;
+	hdb_handle_t object_stats_handle;
+	int fn;
+	char object_name[32];
+	char *name_sufix;
+	uint64_t zero_64 = 0;
 
 	/*
 	 * reference the service interface
@@ -187,29 +196,58 @@ unsigned int corosync_service_link_and_init (
 		"service",
 		strlen ("service"));
 
-	corosync_api->object_key_create (object_service_handle,
+	corosync_api->object_key_create_typed (object_service_handle,
 		"name",
-		strlen ("name"),
 		service_name,
-		strlen (service_name) + 1);
+		strlen (service_name) + 1, OBJDB_VALUETYPE_STRING);
 
-	corosync_api->object_key_create (object_service_handle,
+	corosync_api->object_key_create_typed (object_service_handle,
 		"ver",
-		strlen ("ver"),
 		&service_ver,
-		sizeof (service_ver));
+		sizeof (service_ver), OBJDB_VALUETYPE_UINT32);
 
-	res = corosync_api->object_key_create (object_service_handle,
+	res = corosync_api->object_key_create_typed (object_service_handle,
 		"handle",
-		strlen ("handle"),
 		&handle,
-		sizeof (handle));
+		sizeof (handle), OBJDB_VALUETYPE_UINT64);
 
-	corosync_api->object_key_create (object_service_handle,
+	corosync_api->object_key_create_typed (object_service_handle,
 		"service_id",
-		strlen ("service_id"),
 		&service->id,
-		sizeof (service->id));
+		sizeof (service->id), OBJDB_VALUETYPE_UINT16);
+
+	name_sufix = strrchr (service_name, '_');
+	if (name_sufix)
+		name_sufix++;
+	else
+		name_sufix = (char*)service_name;
+
+	corosync_api->object_create (object_stats_services_handle,
+								 &object_stats_handle,
+								 name_sufix, strlen (name_sufix));
+
+	corosync_api->object_key_create_typed (object_stats_handle,
+										 "service_id",
+										 &service->id, sizeof (service->id),
+										 OBJDB_VALUETYPE_INT16);
+
+	for (fn = 0; fn < service->exec_engine_count; fn++) {
+
+		snprintf (object_name, 32, "%d", fn);
+		corosync_api->object_create (object_stats_handle,
+									 &service_stats_handle[service->id][fn],
+									 object_name, strlen (object_name));
+
+		corosync_api->object_key_create_typed (service_stats_handle[service->id][fn],
+											 "tx",
+											 &zero_64, sizeof (zero_64),
+											 OBJDB_VALUETYPE_UINT64);
+
+		corosync_api->object_key_create_typed (service_stats_handle[service->id][fn],
+											 "rx",
+											 &zero_64, sizeof (zero_64),
+											 OBJDB_VALUETYPE_UINT64);
+	}
 
 	log_printf (LOGSYS_LEVEL_NOTICE, "Service engine loaded: %s\n", service->name);
 	return (res);
@@ -317,8 +355,30 @@ static unsigned int service_unlink_and_exit (
 	unsigned int *found_service_ver;
 	hdb_handle_t object_find_handle;
 	hdb_handle_t *found_service_handle;
+	char *name_sufix;
 	int res;
 
+	name_sufix = strrchr (service_name, '_');
+	if (name_sufix)
+		name_sufix++;
+	else
+		name_sufix = (char*)service_name;
+
+	corosync_api->object_find_create (
+		object_stats_services_handle,
+		name_sufix, strlen (name_sufix),
+		&object_find_handle);
+
+	if (corosync_api->object_find_next (
+			object_find_handle,
+			&object_service_handle) == 0) {
+
+		corosync_api->object_destroy (object_service_handle);
+
+	}
+	corosync_api->object_find_destroy (object_find_handle);
+
+
 	corosync_api->object_find_create (
 		object_internal_configuration_handle,
 		"service",
@@ -406,7 +466,23 @@ unsigned int corosync_service_defaults_link_and_init (struct corosync_api_v1 *co
 	char *found_service_ver;
 	unsigned int found_service_ver_atoi;
 	hdb_handle_t object_find_handle;
+	hdb_handle_t object_find2_handle;
+	hdb_handle_t object_runtime_handle;
+
+	corosync_api->object_find_create (
+		OBJECT_PARENT_HANDLE,
+		"runtime",
+		strlen ("runtime"),
+		&object_find2_handle);
 
+	if (corosync_api->object_find_next (
+			object_find2_handle,
+			&object_runtime_handle) == 0) {
+
+		corosync_api->object_create (object_runtime_handle,
+									 &object_stats_services_handle,
+									 "services", strlen ("services"));
+	}
 	corosync_api->object_create (OBJECT_PARENT_HANDLE,
 		&object_internal_configuration_handle,
 		"internal_configuration",
diff --git a/exec/service.h b/exec/service.h
index 9f1b724..efb3e44 100644
--- a/exec/service.h
+++ b/exec/service.h
@@ -35,6 +35,7 @@
 #ifndef COROSYNC_SERVICE_H_DEFINED
 #define COROSYNC_SERVICE_H_DEFINED
 
+#include <corosync/hdb.h>
 /*
  * Link and initialize a service
  */
@@ -68,4 +69,6 @@ extern unsigned int corosync_service_defaults_link_and_init (
 
 extern struct corosync_service_engine *ais_service[];
 
+extern hdb_handle_t service_stats_handle[SERVICE_HANDLER_MAXIMUM_COUNT][64];
+
 #endif /* SERVICE_H_DEFINED */
diff --git a/exec/totemconfig.c b/exec/totemconfig.c
index f5ed516..de02c77 100644
--- a/exec/totemconfig.c
+++ b/exec/totemconfig.c
@@ -71,7 +71,6 @@
 #define TOKEN_RETRANSMIT_TIMEOUT		(int)(TOKEN_TIMEOUT / (TOKEN_RETRANSMITS_BEFORE_LOSS_CONST + 0.2))
 #define TOKEN_HOLD_TIMEOUT			(int)(TOKEN_RETRANSMIT_TIMEOUT * 0.8 - (1000/(int)HZ))
 #define JOIN_TIMEOUT				50
-#define CONSENSUS_TIMEOUT			800
 #define MERGE_TIMEOUT				200
 #define DOWNCHECK_TIMEOUT			1000
 #define FAIL_TO_RECV_CONST			50
@@ -550,7 +549,7 @@ int totem_config_validate (
 	}
 
 	if (totem_config->consensus_timeout == 0) {
-		totem_config->consensus_timeout = CONSENSUS_TIMEOUT;
+		totem_config->consensus_timeout = (int)(float)(1.2 * totem_config->token_timeout);
 	}
 
 	if (totem_config->consensus_timeout < MINIMUM_TIMEOUT) {
@@ -560,6 +559,13 @@ int totem_config_validate (
 		goto parse_error;
 	}
 
+	if (totem_config->consensus_timeout <= 1.2 * totem_config->token_timeout) {
+		snprintf (local_error_reason, sizeof(local_error_reason),
+			"The consensus timeout parameter (%d ms) must be atleast 1.2 * token (%d ms).",
+			totem_config->consensus_timeout, (int) ((float)1.2 * totem_config->token_timeout));
+		goto parse_error;
+	}
+
 	if (totem_config->merge_timeout == 0) {
 		totem_config->merge_timeout = MERGE_TIMEOUT;
 	}
diff --git a/exec/totemip.c b/exec/totemip.c
index 8a1fe42..9e1bc44 100644
--- a/exec/totemip.c
+++ b/exec/totemip.c
@@ -561,12 +561,12 @@ int totemip_iface_check(struct totem_ip_address *bindnet,
 
 				/* If the address we have is an IPv4 network address, then
 				   substitute the actual IP address of this interface */
-				if (!found_if && tb[IFA_BROADCAST] && ifa->ifa_family == AF_INET) {
+				if (!found_if && tb[IFA_LOCAL] && ifa->ifa_family == AF_INET) {
 					uint32_t network;
 					uint32_t addr;
 					uint32_t netmask = htonl(~((1<<(32-ifa->ifa_prefixlen))-1));
 
-					memcpy(&network, RTA_DATA(tb[IFA_BROADCAST]), sizeof(uint32_t));
+					memcpy(&network, RTA_DATA(tb[IFA_LOCAL]), sizeof(uint32_t));
 					memcpy(&addr, bindnet->addr, sizeof(uint32_t));
 
 					if ((addr & netmask) == (network & netmask)) {
diff --git a/exec/totemmrp.c b/exec/totemmrp.c
index d014300..dceb44a 100644
--- a/exec/totemmrp.c
+++ b/exec/totemmrp.c
@@ -57,7 +57,6 @@
 
 #include <corosync/totem/totem.h>
 #include <corosync/totem/coropoll.h>
-#include <corosync/hdb.h>
 
 #include "totemmrp.h"
 #include "totemsrp.h"
@@ -119,6 +118,7 @@ void totemmrp_confchg_fn (
 int totemmrp_initialize (
 	hdb_handle_t poll_handle,
 	struct totem_config *totem_config,
+	totempg_stats_t *stats,
 
 	void (*deliver_fn) (
 		unsigned int nodeid,
@@ -136,10 +136,12 @@ int totemmrp_initialize (
 	pg_deliver_fn = deliver_fn;
 	pg_confchg_fn = confchg_fn;
 
+	stats->mrp = calloc (sizeof(totemmrp_stats_t), 1);
 	result = totemsrp_initialize (
 		poll_handle,
 		&totemsrp_context,
 		totem_config,
+		stats->mrp,
 		totemmrp_deliver_fn,
 		totemmrp_confchg_fn);
 
@@ -186,8 +188,9 @@ void totemmrp_callback_token_destroy (
 	totemsrp_callback_token_destroy (totemsrp_context, handle_out);
 }
 
-void totemmrp_new_msg_signal (void) {
-	totemsrp_new_msg_signal (totemsrp_context);
+void totemmrp_event_signal (enum totem_event_type type, int value)
+{
+	totemsrp_event_signal (totemsrp_context, type, value);
 }
 
 int totemmrp_ifaces_get (
diff --git a/exec/totemmrp.h b/exec/totemmrp.h
index aa19c1b..f9b1911 100644
--- a/exec/totemmrp.h
+++ b/exec/totemmrp.h
@@ -58,6 +58,7 @@ extern void totemmrp_log_printf_init (
 extern int totemmrp_initialize (
 	hdb_handle_t poll_handle,
 	struct totem_config *totem_config,
+	totempg_stats_t *stats,
 
 	void (*deliver_fn) (
 		unsigned int nodeid,
@@ -96,7 +97,7 @@ extern int totemmrp_callback_token_create (
 extern void totemmrp_callback_token_destroy (
 	void *handle_out);
 
-extern void totemmrp_new_msg_signal (void);
+extern void totemmrp_event_signal (enum totem_event_type type, int value);
 
 extern int totemmrp_ifaces_get (
 	unsigned int nodeid,
diff --git a/exec/totempg.c b/exec/totempg.c
index ed4c286..10effc8 100644
--- a/exec/totempg.c
+++ b/exec/totempg.c
@@ -175,6 +175,8 @@ static void (*totempg_log_printf) (
 
 struct totem_config *totempg_totem_config;
 
+static totempg_stats_t totempg_stats;
+
 enum throw_away_mode {
 	THROW_AWAY_INACTIVE,
 	THROW_AWAY_ACTIVE
@@ -726,6 +728,7 @@ int totempg_initialize (
 	res = totemmrp_initialize (
 		poll_handle,
 		totem_config,
+		&totempg_stats,
 		totempg_deliver_fn,
 		totempg_confchg_fn);
 
@@ -770,7 +773,7 @@ static int mcast_msg (
 	int total_size = 0;
 
 	pthread_mutex_lock (&mcast_msg_mutex);
-	totemmrp_new_msg_signal ();
+	totemmrp_event_signal (TOTEM_EVENT_NEW_MSG, 1);
 
 	/*
 	 * Remove zero length iovectors from the list
@@ -1304,6 +1307,16 @@ int totempg_ifaces_get (
 	return (res);
 }
 
+void totempg_event_signal (enum totem_event_type type, int value)
+{
+	totemmrp_event_signal (type, value);
+}
+
+void* totempg_get_stats (void)
+{
+	return &totempg_stats;
+}
+
 int totempg_crypto_set (
 	unsigned int type)
 {
diff --git a/exec/totemsrp.c b/exec/totemsrp.c
index a7c1eac..a96a3e8 100644
--- a/exec/totemsrp.c
+++ b/exec/totemsrp.c
@@ -92,7 +92,7 @@
 #include "tlist.h"
 
 #define LOCALHOST_IP				inet_addr("127.0.0.1")
-#define QUEUE_RTR_ITEMS_SIZE_MAX		256 /* allow 256 retransmit items */
+#define QUEUE_RTR_ITEMS_SIZE_MAX		16384 /* allow 16384 retransmit items */
 #define RETRANS_MESSAGE_QUEUE_SIZE_MAX		500 /* allow 500 messages to be queued */
 #define RECEIVED_MESSAGE_QUEUE_SIZE_MAX		500 /* allow 500 messages to be queued */
 #define MAXIOVS					5
@@ -140,10 +140,10 @@
 #define ENDIAN_LOCAL					 0xff22
 
 enum message_type {
-	MESSAGE_TYPE_ORF_TOKEN = 0,		/* Ordering, Reliability, Flow (ORF) control Token */
-	MESSAGE_TYPE_MCAST = 1,			/* ring ordered multicast message */
+	MESSAGE_TYPE_ORF_TOKEN = 0,			/* Ordering, Reliability, Flow (ORF) control Token */
+	MESSAGE_TYPE_MCAST = 1,				/* ring ordered multicast message */
 	MESSAGE_TYPE_MEMB_MERGE_DETECT = 2,	/* merge rings if there are available rings */
-	MESSAGE_TYPE_MEMB_JOIN = 3, 		/* membership join message */
+	MESSAGE_TYPE_MEMB_JOIN = 3,			/* membership join message */
 	MESSAGE_TYPE_MEMB_COMMIT_TOKEN = 4,	/* membership commit token */
 	MESSAGE_TYPE_TOKEN_HOLD_CANCEL = 5,	/* cancel the holding of the token */
 };
@@ -268,7 +268,7 @@ struct memb_commit_token {
 /*
  * These parts of the data structure are dynamic:
  *
- * 	struct srp_addr addr[PROCESSOR_COUNT_MAX];
+ *	struct srp_addr addr[PROCESSOR_COUNT_MAX];
  *	struct memb_commit_token_memb_entry memb_list[PROCESSOR_COUNT_MAX];
  */
 }__attribute__((packed));
@@ -501,6 +501,9 @@ struct totemsrp_instance {
 
 	struct memb_commit_token *commit_token;
 
+	totemsrp_stats_t stats;
+	void * token_recv_event_handle;
+	void * token_sent_event_handle;
 	char commit_token_storage[9000];
 };
 
@@ -707,6 +710,41 @@ static int pause_flush (struct totemsrp_instance *instance)
 	return (res);
 }
 
+static int token_event_stats_collector (enum totem_callback_token_type type, const void *void_instance)
+{
+	struct totemsrp_instance *instance = (struct totemsrp_instance *)void_instance;
+	uint32_t time_now;
+	unsigned long long nano_secs = timerlist_nano_current_get ();
+
+	time_now = (nano_secs / TIMERLIST_NS_IN_MSEC);
+
+	if (type == TOTEM_CALLBACK_TOKEN_RECEIVED) {
+		/* incr latest token the index */
+		if (instance->stats.latest_token == (TOTEM_TOKEN_STATS_MAX - 1))
+			instance->stats.latest_token = 0;
+		else
+			instance->stats.latest_token++;
+
+		if (instance->stats.earliest_token == instance->stats.latest_token) {
+			/* we have filled up the array, start overwriting */
+			if (instance->stats.earliest_token == (TOTEM_TOKEN_STATS_MAX - 1))
+				instance->stats.earliest_token = 0;
+			else
+				instance->stats.earliest_token++;
+
+			instance->stats.token[instance->stats.earliest_token].rx = 0;
+			instance->stats.token[instance->stats.earliest_token].tx = 0;
+			instance->stats.token[instance->stats.earliest_token].backlog_calc = 0;
+		}
+
+		instance->stats.token[instance->stats.latest_token].rx = time_now;
+		instance->stats.token[instance->stats.latest_token].tx = 0; /* in case we drop the token */
+	} else {
+		instance->stats.token[instance->stats.latest_token].tx = time_now;
+	}
+	return 0;
+}
+
 /*
  * Exported interfaces
  */
@@ -714,6 +752,7 @@ int totemsrp_initialize (
 	hdb_handle_t poll_handle,
 	void **srp_context,
 	struct totem_config *totem_config,
+	totemmrp_stats_t *stats,
 
 	void (*deliver_fn) (
 		unsigned int nodeid,
@@ -753,6 +792,10 @@ int totemsrp_initialize (
 
 	totemsrp_instance_initialize (instance);
 
+	stats->srp = &instance->stats;
+	instance->stats.latest_token = 0;
+	instance->stats.earliest_token = 0;
+
 	instance->totem_config = totem_config;
 
 	/*
@@ -833,7 +876,7 @@ int totemsrp_initialize (
 	instance->totemsrp_confchg_fn = confchg_fn;
 	instance->use_heartbeat = 1;
 
-	instance->pause_timestamp = timerlist_nano_current_get ();
+	timer_function_pause_timeout (instance);
 
 	if ( totem_config->heartbeat_failures_allowed == 0 ) {
 		log_printf (instance->totemsrp_log_level_debug,
@@ -859,7 +902,7 @@ int totemsrp_initialize (
 		}
 		else {
 			log_printf (instance->totemsrp_log_level_debug,
-                		"total heartbeat_timeout (%d ms)\n", instance->heartbeat_timeout);
+				"total heartbeat_timeout (%d ms)\n", instance->heartbeat_timeout);
 		}
 	}
 
@@ -881,6 +924,18 @@ int totemsrp_initialize (
 		MESSAGE_QUEUE_MAX,
 		sizeof (struct message_item));
 
+	totemsrp_callback_token_create (instance,
+		&instance->token_recv_event_handle,
+		TOTEM_CALLBACK_TOKEN_RECEIVED,
+		0,
+		token_event_stats_collector,
+		instance);
+	totemsrp_callback_token_create (instance,
+		&instance->token_sent_event_handle,
+		TOTEM_CALLBACK_TOKEN_SENT,
+		0,
+		token_event_stats_collector,
+		instance);
 	*srp_context = instance;
 	return (0);
 
@@ -1432,6 +1487,7 @@ static void memb_state_consensus_timeout_expired (
         struct srp_addr no_consensus_list[PROCESSOR_COUNT_MAX];
 	int no_consensus_list_entries;
 
+	instance->stats.consensus_timeouts++;
 	if (memb_consensus_agreed (instance)) {
 		memb_consensus_reset (instance);
 
@@ -1479,6 +1535,7 @@ static void timer_function_orf_token_timeout (void *data)
 				"A processor failed, forming new configuration.\n");
 			totemrrp_iface_check (instance->totemrrp_context);
 			memb_state_gather_enter (instance, 2);
+			instance->stats.operational_token_lost++;
 			break;
 
 		case MEMB_STATE_GATHER:
@@ -1486,12 +1543,14 @@ static void timer_function_orf_token_timeout (void *data)
 				"The consensus timeout expired.\n");
 			memb_state_consensus_timeout_expired (instance);
 			memb_state_gather_enter (instance, 3);
+			instance->stats.gather_token_lost++;
 			break;
 
 		case MEMB_STATE_COMMIT:
 			log_printf (instance->totemsrp_log_level_debug,
 				"The token was lost in the COMMIT state.\n");
 			memb_state_gather_enter (instance, 4);
+			instance->stats.commit_token_lost++;
 			break;
 
 		case MEMB_STATE_RECOVERY:
@@ -1499,6 +1558,7 @@ static void timer_function_orf_token_timeout (void *data)
 				"The token was lost in the RECOVERY state.\n");
 			ring_state_restore (instance);
 			memb_state_gather_enter (instance, 5);
+			instance->stats.recovery_token_lost++;
 			break;
 	}
 }
@@ -1603,7 +1663,6 @@ static void deliver_messages_from_recovery_to_regular (struct totemsrp_instance
 		if (memcmp (&instance->my_old_ring_id, &mcast->ring_id,
 			sizeof (struct memb_ring_id)) == 0) {
 
-			regular_message_item.msg_len = recovery_message_item->msg_len;
 			res = sq_item_inuse (&instance->regular_sort_queue, mcast->seq);
 			if (res == 0) {
 				sq_item_add (&instance->regular_sort_queue,
@@ -1730,6 +1789,7 @@ static void memb_state_operational_enter (struct totemsrp_instance *instance)
 		"A processor joined or left the membership and a new membership was formed.\n");
 	instance->memb_state = MEMB_STATE_OPERATIONAL;
 
+	instance->stats.operational_entered++;
 	instance->my_received_flg = 1;
 
 	reset_pause_timeout (instance);
@@ -1786,6 +1846,7 @@ static void memb_state_gather_enter (
 		"entering GATHER state from %d.\n", gather_from);
 
 	instance->memb_state = MEMB_STATE_GATHER;
+	instance->stats.gather_entered++;
 
 	return;
 }
@@ -1831,6 +1892,7 @@ static void memb_state_commit_enter (
 	reset_token_retransmit_timeout (instance); // REVIEWED
 	reset_token_timeout (instance); // REVIEWED
 
+	instance->stats.commit_entered++;
 
 	/*
 	 * reset all flow control variables since we are starting a new ring
@@ -1852,9 +1914,6 @@ static void memb_state_recovery_enter (
 	unsigned int low_ring_aru;
 	unsigned int range = 0;
 	unsigned int messages_originated = 0;
-	char is_originated[4096];
-	char not_originated[4096];
-	char seqno_string_hex[10];
 	const struct srp_addr *addr;
 	struct memb_commit_token_memb_entry *memb_list;
 
@@ -1956,13 +2015,11 @@ static void memb_state_recovery_enter (
 		 */
 		goto no_originate;
 	}
-	assert (range < 1024);
+	assert (range < QUEUE_RTR_ITEMS_SIZE_MAX);
 
 	log_printf (instance->totemsrp_log_level_debug,
 		"copying all old ring messages from %x-%x.\n",
 		low_ring_aru + 1, instance->old_ring_state_high_seq_received);
-	strcpy (not_originated, "Not Originated for recovery: ");
-	strcpy (is_originated, "Originated for recovery: ");
 
 	for (i = 1; i <= range; i++) {
 		struct sort_queue_item *sort_queue_item;
@@ -1970,14 +2027,11 @@ static void memb_state_recovery_enter (
 		void *ptr;
 		int res;
 
-		sprintf (seqno_string_hex, "%x ", low_ring_aru + i);
 		res = sq_item_get (&instance->regular_sort_queue,
 			low_ring_aru + i, &ptr);
 		if (res != 0) {
-			strcat (not_originated, seqno_string_hex);
 			continue;
 		}
-		strcat (is_originated, seqno_string_hex);
 		sort_queue_item = ptr;
 		messages_originated++;
 		memset (&message_item, 0, sizeof (struct message_item));
@@ -2000,10 +2054,6 @@ static void memb_state_recovery_enter (
 	}
 	log_printf (instance->totemsrp_log_level_debug,
 		"Originated %d messages in RECOVERY.\n", messages_originated);
-	strcat (not_originated, "\n");
-	strcat (is_originated, "\n");
-	log_printf (instance->totemsrp_log_level_debug, "%s", is_originated);
-	log_printf (instance->totemsrp_log_level_debug, "%s", not_originated);
 	goto originated;
 
 no_originate:
@@ -2022,16 +2072,17 @@ originated:
 	reset_token_retransmit_timeout (instance); // REVIEWED
 
 	instance->memb_state = MEMB_STATE_RECOVERY;
+	instance->stats.recovery_entered++;
 	return;
 }
 
-int totemsrp_new_msg_signal (void *srp_context)
+void totemsrp_event_signal (void *srp_context, enum totem_event_type type, int value)
 {
 	struct totemsrp_instance *instance = (struct totemsrp_instance *)srp_context;
 
 	token_hold_cancel_send (instance);
 
-	return (0);
+	return;
 }
 
 int totemsrp_mcast (
@@ -2083,6 +2134,7 @@ int totemsrp_mcast (
 	message_item.msg_len = addr_idx;
 
 	log_printf (instance->totemsrp_log_level_debug, "mcasted message added to pending queue\n");
+	instance->stats.mcast_tx++;
 	cs_queue_item_add (&instance->new_message_queue, &message_item);
 
 	return (0);
@@ -2181,7 +2233,7 @@ static void messages_free (
 	}
 
 	range = release_to - instance->last_released;
-	assert (range < 1024);
+	assert (range < QUEUE_RTR_ITEMS_SIZE_MAX);
 
 	/*
 	 * Release retransmit list items if group aru indicates they are transmitted
@@ -2398,6 +2450,7 @@ static int orf_token_rtr (
 			memmove (&rtr_list[i], &rtr_list[i + 1],
 				sizeof (struct rtr_item) * (orf_token->rtr_list_entries));
 
+			instance->stats.mcast_retx++;
 			instance->fcc_remcast_current++;
 		} else {
 			i += 1;
@@ -2411,7 +2464,7 @@ static int orf_token_rtr (
 	 */
 
 	range = instance->my_high_seq_received - instance->my_aru;
-	assert (range < 100000);
+	assert (range < QUEUE_RTR_ITEMS_SIZE_MAX);
 
 	for (i = 1; (orf_token->rtr_list_entries < RETRANSMIT_ENTRIES_MAX) &&
 		(i <= range); i++) {
@@ -2567,6 +2620,8 @@ static int token_hold_cancel_send (struct totemsrp_instance *instance)
 		sizeof (struct memb_ring_id));
 	assert (token_hold_cancel.header.nodeid);
 
+	instance->stats.token_hold_cancel_tx++;
+
 	totemrrp_mcast_flush_send (instance->totemrrp_context, &token_hold_cancel,
 		sizeof (struct token_hold_cancel));
 
@@ -2587,6 +2642,7 @@ static int orf_token_send_initial (struct totemsrp_instance *instance)
 	orf_token.token_seq = SEQNO_START_TOKEN;
 	orf_token.retrans_flg = 1;
 	instance->my_set_retrans_flg = 1;
+	instance->stats.orf_token_tx++;
 
 	if (cs_queue_is_empty (&instance->retrans_message_queue) == 1) {
 		orf_token.retrans_flg = 0;
@@ -2717,6 +2773,8 @@ static int memb_state_commit_token_send_recovery (
 	memcpy (instance->orf_token_retransmit, commit_token, commit_token_size);
 	instance->orf_token_retransmit_size = commit_token_size;
 
+	instance->stats.memb_commit_token_tx++;
+
 	totemrrp_token_send (instance->totemrrp_context,
 		commit_token,
 		commit_token_size);
@@ -2748,6 +2806,8 @@ static int memb_state_commit_token_send (
 	memcpy (instance->orf_token_retransmit, instance->commit_token, commit_token_size);
 	instance->orf_token_retransmit_size = commit_token_size;
 
+	instance->stats.memb_commit_token_tx++;
+
 	totemrrp_token_send (instance->totemrrp_context,
 		instance->commit_token,
 		commit_token_size);
@@ -2882,6 +2942,8 @@ static void memb_join_message_send (struct totemsrp_instance *instance)
 		usleep (random() % (instance->totem_config->send_join_timeout * 1000));
 	}
 
+	instance->stats.memb_join_tx++;
+
 	totemrrp_mcast_flush_send (
 		instance->totemrrp_context,
 		memb_join,
@@ -2950,6 +3012,7 @@ static void memb_leave_message_send (struct totemsrp_instance *instance)
 	if (instance->totem_config->send_join_timeout) {
 		usleep (random() % (instance->totem_config->send_join_timeout * 1000));
 	}
+	instance->stats.memb_join_tx++;
 
 	totemrrp_mcast_flush_send (
 		instance->totemrrp_context,
@@ -2970,6 +3033,7 @@ static void memb_merge_detect_transmit (struct totemsrp_instance *instance)
 		sizeof (struct memb_ring_id));
 	assert (memb_merge_detect.header.nodeid);
 
+	instance->stats.memb_merge_detect_tx++;
 	totemrrp_mcast_flush_send (instance->totemrrp_context,
 		&memb_merge_detect,
 		sizeof (struct memb_merge_detect));
@@ -3152,6 +3216,7 @@ static unsigned int backlog_get (struct totemsrp_instance *instance)
 	if (instance->memb_state == MEMB_STATE_RECOVERY) {
 		backlog = cs_queue_used (&instance->retrans_message_queue);
 	}
+	instance->stats.token[instance->stats.latest_token].backlog_calc = backlog;
 	return (backlog);
 }
 
@@ -3444,6 +3509,7 @@ printf ("token seq %d\n", token->seq);
 				} else
 				if (token->retrans_flg == 1 && instance->my_set_retrans_flg) {
 					token->retrans_flg = 0;
+					instance->my_set_retrans_flg = 0;
 				}
 				log_printf (instance->totemsrp_log_level_debug,
 					"token retrans flag is %d my set retrans flag%d retrans queue empty %d count %d, aru %x\n",
@@ -3553,7 +3619,7 @@ static void messages_deliver_to_app (
 			"Delivering %x to %x\n", instance->my_high_delivered,
 			end_point);
 	}
-	assert (range < 10240);
+	assert (range < QUEUE_RTR_ITEMS_SIZE_MAX);
 	my_high_delivered_stored = instance->my_high_delivered;
 
 	/*
@@ -3704,10 +3770,12 @@ static int message_handler_mcast (
 
 		case MEMB_STATE_COMMIT:
 			/* discard message */
+			instance->stats.rx_msg_dropped++;
 			break;
 
 		case MEMB_STATE_RECOVERY:
 			/* discard message */
+			instance->stats.rx_msg_dropped++;
 			break;
 		}
 		return (0);
@@ -4203,9 +4271,32 @@ void main_deliver_fn (
 	if ((int)message_header->type >= totemsrp_message_handlers.count) {
 		log_printf (instance->totemsrp_log_level_security, "Type of received message is wrong...  ignoring %d.\n", (int)message_header->type);
 printf ("wrong message type\n");
+		instance->stats.rx_msg_dropped++;
 		return;
 	}
 
+	switch (message_header->type) {
+	case MESSAGE_TYPE_ORF_TOKEN:
+		instance->stats.orf_token_rx++;
+		break;
+	case MESSAGE_TYPE_MCAST:
+		instance->stats.mcast_rx++;
+		break;
+	case MESSAGE_TYPE_MEMB_MERGE_DETECT:
+		instance->stats.memb_merge_detect_rx++;
+		break;
+	case MESSAGE_TYPE_MEMB_JOIN:
+		instance->stats.memb_join_rx++;
+		break;
+	case MESSAGE_TYPE_MEMB_COMMIT_TOKEN:
+		instance->stats.memb_commit_token_rx++;
+		break;
+	case MESSAGE_TYPE_TOKEN_HOLD_CANCEL:
+		instance->stats.token_hold_cancel_rx++;
+		break;
+	default:
+		break;
+	}
 	/*
 	 * Handle incoming message
 	 */
diff --git a/exec/totemsrp.h b/exec/totemsrp.h
index 743aaad..37ef588 100644
--- a/exec/totemsrp.h
+++ b/exec/totemsrp.h
@@ -50,6 +50,7 @@ int totemsrp_initialize (
 	hdb_handle_t poll_handle,
 	void **srp_context,
 	struct totem_config *totem_config,
+	totemmrp_stats_t *stats,
 
 	void (*deliver_fn) (
 		unsigned int nodeid,
@@ -91,7 +92,7 @@ void totemsrp_callback_token_destroy (
 	void *srp_context,
 	void **handle_out);
 
-int totemsrp_new_msg_signal (void *srp_context);
+void totemsrp_event_signal (void *srp_context, enum totem_event_type type, int value);
 
 extern void totemsrp_net_mtu_adjust (struct totem_config *totem_config);
 
diff --git a/exec/vsf_quorum.c b/exec/vsf_quorum.c
index bc11d05..4d94ee9 100644
--- a/exec/vsf_quorum.c
+++ b/exec/vsf_quorum.c
@@ -103,14 +103,38 @@ static struct memb_ring_id quorum_ring_id;
 static size_t quorum_view_list_entries = 0;
 static int quorum_view_list[PROCESSOR_COUNT_MAX];
 struct quorum_services_api_ver1 *quorum_iface = NULL;
+static char view_buf[64];
+
+static void log_view_list(const unsigned int *view_list, size_t view_list_entries)
+{
+	int total = (int)view_list_entries;
+	int len, pos, ret;
+	int i = 0;
+
+	while (1) {
+		len = sizeof(view_buf);
+		pos = 0;
+		memset(view_buf, 0, len);
+
+		for (; i < total; i++) {
+			ret = snprintf(view_buf + pos, len - pos, " %d", view_list[i]);
+			if (ret >= len - pos)
+				break;
+			pos += ret;
+		}
+		log_printf (LOGSYS_LEVEL_NOTICE, "Members[%d]:%s%s",
+			    total, view_buf, i < total ? "\\" : "");
+
+		if (i == total)
+			break;
+	}
+}
 
 /* Internal quorum API function */
 static void quorum_api_set_quorum(const unsigned int *view_list,
 				  size_t view_list_entries,
 				  int quorum, struct memb_ring_id *ring_id)
 {
-	int i;
-
 	primary_designated = quorum;
 
 	if (primary_designated) {
@@ -123,9 +147,7 @@ static void quorum_api_set_quorum(const unsigned int *view_list,
 	memcpy(&quorum_ring_id, ring_id, sizeof (quorum_ring_id));
 	memcpy(quorum_view_list, view_list, sizeof(unsigned int)*view_list_entries);
 
-	log_printf (LOGSYS_LEVEL_NOTICE, "Members[%d]: ", (int)view_list_entries);
-	for (i=0; i<view_list_entries; i++)
-		log_printf (LOGSYS_LEVEL_NOTICE, "    %d ", view_list[i]);
+	log_view_list(view_list, view_list_entries);
 
 	/* Tell internal listeners */
 	send_internal_notification();
diff --git a/include/Makefile.am b/include/Makefile.am
index bafe545..3f15cf5 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -32,7 +32,8 @@
 MAINTAINERCLEANFILES    = Makefile.in corosync/config.h.in
 
 CS_H			= hdb.h cs_config.h cpg.h cfg.h evs.h mar_gen.h swab.h 	\
-		  	coroipcc.h coroipcs.h coroipc_types.h corodefs.h confdb.h list.h corotypes.h quorum.h votequorum.h
+			coroipcc.h coroipcs.h coroipc_types.h corodefs.h \
+			confdb.h list.h corotypes.h quorum.h votequorum.h sam.h
 
 CS_INTERNAL_H		= ipc_cfg.h ipc_confdb.h ipc_cpg.h ipc_evs.h ipc_pload.h ipc_quorum.h 	\
 			jhash.h pload.h cs_queue.h quorum.h sq.h ipc_votequorum.h coroipc_ipc.h
diff --git a/include/Makefile.in b/include/Makefile.in
index b439f81..aca9d0a 100644
--- a/include/Makefile.in
+++ b/include/Makefile.in
@@ -131,6 +131,7 @@ EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
 GROFF = @GROFF@
+INITDDIR = @INITDDIR@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -227,7 +228,8 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 MAINTAINERCLEANFILES = Makefile.in corosync/config.h.in
 CS_H = hdb.h cs_config.h cpg.h cfg.h evs.h mar_gen.h swab.h 	\
-		  	coroipcc.h coroipcs.h coroipc_types.h corodefs.h confdb.h list.h corotypes.h quorum.h votequorum.h
+			coroipcc.h coroipcs.h coroipc_types.h corodefs.h \
+			confdb.h list.h corotypes.h quorum.h votequorum.h sam.h
 
 CS_INTERNAL_H = ipc_cfg.h ipc_confdb.h ipc_cpg.h ipc_evs.h ipc_pload.h ipc_quorum.h 	\
 			jhash.h pload.h cs_queue.h quorum.h sq.h ipc_votequorum.h coroipc_ipc.h
diff --git a/include/corosync/confdb.h b/include/corosync/confdb.h
index e0797bb..bb4f890 100644
--- a/include/corosync/confdb.h
+++ b/include/corosync/confdb.h
@@ -51,6 +51,19 @@ typedef uint64_t confdb_handle_t;
 #define OBJECT_PARENT_HANDLE 0xFFFFFFFF00000000ULL
 
 typedef enum {
+	CONFDB_VALUETYPE_INT16,
+	CONFDB_VALUETYPE_UINT16,
+	CONFDB_VALUETYPE_INT32,
+	CONFDB_VALUETYPE_UINT32,
+	CONFDB_VALUETYPE_INT64,
+	CONFDB_VALUETYPE_UINT64,
+	CONFDB_VALUETYPE_FLOAT,
+	CONFDB_VALUETYPE_DOUBLE,
+	CONFDB_VALUETYPE_STRING,
+	CONFDB_VALUETYPE_ANY,
+} confdb_value_types_t;
+
+typedef enum {
 	CONFDB_TRACK_DEPTH_ONE,
 	CONFDB_TRACK_DEPTH_RECURSIVE
 } confdb_track_depth_t;
@@ -181,6 +194,14 @@ cs_error_t confdb_key_create (
 	const void *value,
 	size_t value_len);
 
+cs_error_t confdb_key_create_typed (
+	confdb_handle_t handle,
+	hdb_handle_t parent_object_handle,
+	const char *key_name,
+	const void *value,
+	size_t value_len,
+	confdb_value_types_t type);
+
 cs_error_t confdb_key_delete (
 	confdb_handle_t handle,
 	hdb_handle_t parent_object_handle,
@@ -200,6 +221,14 @@ cs_error_t confdb_key_get (
 	void *value,
 	size_t *value_len);
 
+cs_error_t confdb_key_get_typed (
+	confdb_handle_t handle,
+	hdb_handle_t parent_object_handle,
+	const char *key_name,
+	void *value,
+	size_t *value_len,
+	confdb_value_types_t *type);
+
 cs_error_t confdb_key_replace (
 	confdb_handle_t handle,
 	hdb_handle_t parent_object_handle,
@@ -275,6 +304,14 @@ cs_error_t confdb_key_iter (
 	void *value,
 	size_t *value_len);
 
+cs_error_t confdb_key_iter_typed (
+	confdb_handle_t handle,
+	hdb_handle_t parent_object_handle,
+	char *key_name,
+	void *value,
+	size_t *value_len,
+	confdb_value_types_t *type);
+
 /*
  * Get/set context variable
  */
diff --git a/include/corosync/config.h.in b/include/corosync/config.h.in
index 2ae4e69..b4eba59 100644
--- a/include/corosync/config.h.in
+++ b/include/corosync/config.h.in
@@ -12,6 +12,9 @@
 /* Compiling for Darwin platform */
 #undef COROSYNC_DARWIN
 
+/* Compiling for FreeBSD >= 8 platform */
+#undef COROSYNC_FREEBSD_GE_8
+
 /* Compiling for Linux platform */
 #undef COROSYNC_LINUX
 
@@ -217,9 +220,6 @@
 /* Define to 1 if you have the `strerror' function. */
 #undef HAVE_STRERROR
 
-/* Define to 1 if you have the `strftime' function. */
-#undef HAVE_STRFTIME
-
 /* Define to 1 if you have the <strings.h> header file. */
 #undef HAVE_STRINGS_H
 
diff --git a/include/corosync/coroipc_ipc.h b/include/corosync/coroipc_ipc.h
index de25e48..5126faa 100644
--- a/include/corosync/coroipc_ipc.h
+++ b/include/corosync/coroipc_ipc.h
@@ -62,6 +62,11 @@ enum req_init_types {
 #define MESSAGE_REQ_CHANGE_EUID		1
 #define MESSAGE_REQ_OUTQ_FLUSH		2
 
+#define MESSAGE_RES_OUTQ_EMPTY         0
+#define MESSAGE_RES_OUTQ_NOT_EMPTY     1
+#define MESSAGE_RES_ENABLE_FLOWCONTROL 2
+#define MESSAGE_RES_OUTQ_FLUSH_NR      3
+
 struct control_buffer {
 	unsigned int read;
 	unsigned int write;
diff --git a/include/corosync/coroipcs.h b/include/corosync/coroipcs.h
index 946b66d..3838af8 100644
--- a/include/corosync/coroipcs.h
+++ b/include/corosync/coroipcs.h
@@ -36,6 +36,7 @@
 #define COROIPCS_H_DEFINED
 
 #include <stdlib.h>
+#include <corosync/engine/objdb.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -74,9 +75,55 @@ struct coroipcs_init_state {
 	coroipcs_handler_fn_lvalue (*handler_fn_get)(unsigned int service, unsigned int id);
 };
 
+struct coroipcs_init_state_v2 {
+	const char *socket_name;
+	int sched_policy;
+	const struct sched_param *sched_param;
+	void *(*malloc) (size_t size);
+	void (*free) (void *ptr);
+        void (*old_log_printf) (
+                const char *format,
+                ...) __attribute__((format(printf, 1, 2)));
+	int (*service_available)(unsigned int service);
+	int (*private_data_size_get)(unsigned int service);
+	int (*security_valid)(int uid, int gid);
+	void (*serialize_lock)(void);
+	void (*serialize_unlock)(void);
+	int (*sending_allowed)(unsigned int service, unsigned int id,
+		const void *msg, void *sending_allowed_private_data);
+	void (*sending_allowed_release)(void *sending_allowed_private_data);
+	void (*poll_accept_add)(int fd);
+	void (*poll_dispatch_add)(int fd, void *context);
+	void (*poll_dispatch_modify)(int fd, int events);
+	void (*poll_dispatch_destroy)(int fd, void *context);
+	void (*fatal_error)(const char *error_msg);
+	coroipcs_init_fn_lvalue (*init_fn_get)(unsigned int service);
+	coroipcs_exit_fn_lvalue (*exit_fn_get)(unsigned int service);
+	coroipcs_handler_fn_lvalue (*handler_fn_get)(unsigned int service, unsigned int id);
+	/* v2 functions */
+	hdb_handle_t (*stats_create_connection) (const char* name,
+		pid_t pid, int fd);
+	void (*stats_destroy_connection) (hdb_handle_t handle);
+	void (*stats_update_value) (hdb_handle_t handle,
+		const char *name, const void *value, size_t value_len);
+	void (*stats_increment_value) (hdb_handle_t handle, const char* name);
+	void (*log_printf) (
+		unsigned int rec_ident,
+		const char *function_name,
+		const char *file_name,
+		int file_line,
+		const char *format,
+		...) __attribute__((format(printf, 5, 6)));
+	int log_subsys_id;
+	void (*stats_decrement_value) (hdb_handle_t handle, const char* name);
+};
+
 extern void coroipcs_ipc_init (
 	struct coroipcs_init_state *init_state);
 
+extern void coroipcs_ipc_init_v2 (
+        struct coroipcs_init_state_v2 *init_state_v2);
+
 extern void *coroipcs_private_data_get (void *conn);
 
 extern int coroipcs_response_send (
diff --git a/include/corosync/engine/coroapi.h b/include/corosync/engine/coroapi.h
index e0d800b..0c487ca 100644
--- a/include/corosync/engine/coroapi.h
+++ b/include/corosync/engine/coroapi.h
@@ -170,6 +170,19 @@ struct object_key_valid {
 /* deprecated */
 
 typedef enum {
+	OBJDB_VALUETYPE_INT16,
+	OBJDB_VALUETYPE_UINT16,
+	OBJDB_VALUETYPE_INT32,
+	OBJDB_VALUETYPE_UINT32,
+	OBJDB_VALUETYPE_INT64,
+	OBJDB_VALUETYPE_UINT64,
+	OBJDB_VALUETYPE_FLOAT,
+	OBJDB_VALUETYPE_DOUBLE,
+	OBJDB_VALUETYPE_STRING,
+	OBJDB_VALUETYPE_ANY,
+} objdb_value_types_t;
+
+typedef enum {
 	OBJECT_TRACK_DEPTH_ONE,
 	OBJECT_TRACK_DEPTH_RECURSIVE
 } object_track_depth_t;
@@ -590,6 +603,30 @@ struct corosync_api_v1 {
 	 * Please avoid using any of coropoll apis in your service engines.
 	 */
 	hdb_handle_t (*poll_handle_get) (void);
+
+
+	int (*object_key_create_typed) (
+		hdb_handle_t object_handle,
+		const char *key_name,
+		const void *value,
+		size_t value_len,
+		objdb_value_types_t type);
+
+	int (*object_key_get_typed) (
+		hdb_handle_t object_handle,
+		const char *key_name,
+		void **value,
+		size_t *value_len,
+		objdb_value_types_t *type);
+
+	int (*object_key_iter_typed) (
+		hdb_handle_t parent_object_handle,
+		char **key_name,
+		void **value,
+		size_t *value_len,
+		objdb_value_types_t *type);
+
+	void *(*totem_get_stats)(void);
 };
 
 #define SERVICE_ID_MAKE(a,b) ( ((a)<<16) | (b) )
diff --git a/include/corosync/engine/objdb.h b/include/corosync/engine/objdb.h
index d26b6f7..140753a 100644
--- a/include/corosync/engine/objdb.h
+++ b/include/corosync/engine/objdb.h
@@ -42,6 +42,19 @@
 #include <corosync/hdb.h>
 
 typedef enum {
+	OBJDB_VALUETYPE_INT16,
+	OBJDB_VALUETYPE_UINT16,
+	OBJDB_VALUETYPE_INT32,
+	OBJDB_VALUETYPE_UINT32,
+	OBJDB_VALUETYPE_INT64,
+	OBJDB_VALUETYPE_UINT64,
+	OBJDB_VALUETYPE_FLOAT,
+	OBJDB_VALUETYPE_DOUBLE,
+	OBJDB_VALUETYPE_STRING,
+	OBJDB_VALUETYPE_ANY,
+} objdb_value_types_t;
+
+typedef enum {
 	OBJECT_TRACK_DEPTH_ONE,
 	OBJECT_TRACK_DEPTH_RECURSIVE
 } object_track_depth_t;
@@ -235,6 +248,27 @@ struct objdb_iface_ver0 {
 		const void *key_name,
 		size_t key_len,
 		unsigned int *value);
+
+	int (*object_key_create_typed) (
+		hdb_handle_t object_handle,
+		const char *key_name,
+		const void *value,
+		size_t value_len,
+		objdb_value_types_t type);
+
+	int (*object_key_get_typed) (
+		hdb_handle_t object_handle,
+		const char *key_name,
+		void **value,
+		size_t *value_len,
+		objdb_value_types_t *type);
+
+	int (*object_key_iter_typed) (
+		hdb_handle_t parent_object_handle,
+		char **key_name,
+		void **value,
+		size_t *value_len,
+		objdb_value_types_t *type);
 };
 
 #endif /* OBJDB_H_DEFINED */
diff --git a/include/corosync/hdb.h b/include/corosync/hdb.h
index ec85257..860738f 100644
--- a/include/corosync/hdb.h
+++ b/include/corosync/hdb.h
@@ -36,6 +36,10 @@
 #ifndef HDB_H_DEFINED
 #define HDB_H_DEFINED
 
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
 #include <errno.h>
 #include <assert.h>
 #include <stdlib.h>
diff --git a/include/corosync/ipc_confdb.h b/include/corosync/ipc_confdb.h
index c5c7c9b..454d01e 100644
--- a/include/corosync/ipc_confdb.h
+++ b/include/corosync/ipc_confdb.h
@@ -55,7 +55,10 @@ enum req_confdb_types {
 	MESSAGE_REQ_CONFDB_RELOAD = 13,
 	MESSAGE_REQ_CONFDB_OBJECT_FIND_DESTROY = 14,
 	MESSAGE_REQ_CONFDB_KEY_INCREMENT = 15,
-	MESSAGE_REQ_CONFDB_KEY_DECREMENT = 16
+	MESSAGE_REQ_CONFDB_KEY_DECREMENT = 16,
+	MESSAGE_REQ_CONFDB_KEY_CREATE_TYPED = 17,
+	MESSAGE_REQ_CONFDB_KEY_GET_TYPED = 18,
+	MESSAGE_REQ_CONFDB_KEY_ITER_TYPED = 19,
 };
 
 enum res_confdb_types {
@@ -78,7 +81,9 @@ enum res_confdb_types {
 	MESSAGE_RES_CONFDB_RELOAD = 16,
 	MESSAGE_RES_CONFDB_OBJECT_FIND_DESTROY = 17,
 	MESSAGE_RES_CONFDB_KEY_INCREMENT = 18,
-	MESSAGE_RES_CONFDB_KEY_DECREMENT = 19
+	MESSAGE_RES_CONFDB_KEY_DECREMENT = 19,
+	MESSAGE_RES_CONFDB_KEY_GET_TYPED = 20,
+	MESSAGE_RES_CONFDB_KEY_ITER_TYPED = 21,
 };
 
 
@@ -116,6 +121,14 @@ struct req_lib_confdb_key_create {
 	mar_name_t value __attribute__((aligned(8)));
 };
 
+struct req_lib_confdb_key_create_typed {
+	coroipc_request_header_t header __attribute__((aligned(8)));
+	mar_uint64_t object_handle __attribute__((aligned(8)));
+	mar_name_t key_name __attribute__((aligned(8)));
+	mar_name_t value __attribute__((aligned(8)));
+	mar_int32_t type __attribute__((aligned(8)));
+};
+
 struct req_lib_confdb_key_delete {
 	coroipc_request_header_t header __attribute__((aligned(8)));
 	mar_uint64_t object_handle __attribute__((aligned(8)));
@@ -168,6 +181,12 @@ struct res_lib_confdb_key_iter {
 	mar_name_t key_name __attribute__((aligned(8)));
 	mar_name_t value __attribute__((aligned(8)));
 };
+struct res_lib_confdb_key_iter_typed {
+	coroipc_response_header_t header __attribute__((aligned(8)));
+	mar_name_t key_name __attribute__((aligned(8)));
+	mar_name_t value __attribute__((aligned(8)));
+	mar_int32_t type __attribute__((aligned(8)));
+};
 
 struct req_lib_confdb_key_get {
 	coroipc_request_header_t header __attribute__((aligned(8)));
@@ -184,6 +203,11 @@ struct res_lib_confdb_key_get {
 	coroipc_response_header_t header __attribute__((aligned(8)));
 	mar_name_t value __attribute__((aligned(8)));
 };
+struct res_lib_confdb_key_get_typed {
+	coroipc_response_header_t header __attribute__((aligned(8)));
+	mar_name_t value __attribute__((aligned(8)));
+	mar_int32_t type __attribute__((aligned(8)));
+};
 
 struct res_lib_confdb_key_incdec {
 	coroipc_response_header_t header __attribute__((aligned(8)));
diff --git a/include/corosync/sam.h b/include/corosync/sam.h
new file mode 100644
index 0000000..50d7d8b
--- /dev/null
+++ b/include/corosync/sam.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Jan Friesse (jfriesse at 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.
+ */
+#ifndef COROSYNC_SAM_H_DEFINED
+#define COROSYNC_SAM_H_DEFINED
+
+#include <corosync/corotypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+	SAM_RECOVERY_POLICY_QUIT = 1,
+	SAM_RECOVERY_POLICY_RESTART = 2,
+} sam_recovery_policy_t;
+
+/*
+ * Callback definition for event driven checking
+ */
+typedef int (*sam_hc_callback_t)(void);
+
+/*
+ * Create a new SAM connection. This function must be called before any other.
+ * It is recommended to call it as one of first in application.
+ *
+ * @param time_interval Time interval in miliseconds of healthcheck. After this time, application
+ * will be killed and recovery policy will be taken. This can be zero, which means,
+ * that there is no time limit (only fall of application is checked and only then
+ * recovery action is taken)
+ * @param recovery_policy One of SAM_RECOVERY_POLICY_RESTART, which means, that after
+ * timeout application will be killed and new instance will be started.
+ * SAM_RECOVERY_POLICY_QUIT will just stop application
+ * @return
+ * - CS_OK in case no problem appeared
+ * - CS_ERR_BAD_HANDLE in case user is trying to initialize initialized instance
+ * - CS_ERR_INVALID_PARAM in case recovery_policy had bad value
+ */
+cs_error_t sam_initialize (
+        int time_interval,
+        sam_recovery_policy_t recovery_policy);
+
+/*
+ * Close the SAM handle. This function should be called as late as possible
+ * (in reality, if you plan just quit, and checking is stopped, there is no need
+ * to call it). Function will stop healtchecking and put library to state, where
+ * no new start is possible.
+ *
+ * @return
+ * - CS_OK in case no problem appeared
+ * - CS_ERR_BAD_HANDLE library was not initialized by #sam_initialize
+ */
+cs_error_t sam_finalize (void);
+
+/*
+ * Start healthchecking. From this time, you should call every time_interval
+ * sam_hc_send, otherwise, recovery action will be taken.
+ * @return
+ * - CS_OK in case no problem appeared
+ * - CS_ERR_BAD_HANDLE component was not registered by #sam_register
+ */
+cs_error_t sam_start (void);
+
+/*
+ * Stop healthchecking. Oposite of #sam_start. You can call sam_start and
+ * sam_stop how many times you want.
+ *
+ * @return
+ * - CS_OK in case no problem appeared
+ * - CS_ERR_BAD_HANDLE healthchecking is not in running state (no sam_start
+ *   was called)
+ */
+cs_error_t sam_stop (void);
+
+/*
+ * Register application. This is one of most crucial function. In case, your
+ * application will be restarted, you will always return to point after calling
+ * this function. This function can be called only once, and SAM must be initialized
+ * by sam_initialize. You can choose any place in your application, where to call
+ * this function.
+ *
+ * @param instance_id NULL or pointer to int memory, where current instance
+ * of application will be returned. It's always safe to suppose, that first instance
+ * (this means, no recovery action was taken yet) will be always 1 and instance_id
+ * will be raising up to MAX_INT (after this, it will fall to 0).
+ * @return
+ * - CS_OK in case no problem appeared
+ * - CS_ERR_BAD_HANDLE in case, you call this function twice, or before sam_init
+ * - CS_ERR_LIBRARY internal library call failed. This can be one of pipe or fork
+ *   creation. You can get more information from errno
+ */
+cs_error_t sam_register (
+	unsigned int *instance_id);
+
+/*
+ * Send healthcheck confirmation. This should be called after #sam_start
+ *
+ * - CS_OK in case no problem appeared
+ * - CS_ERR_BAD_HANDLE healthchecking is not in running state (no sam_start was
+ *   called, or called after sam_stop/sam_finalize)
+ */
+cs_error_t sam_hc_send (void);
+
+/*
+ * Register healtcheck callback. After you will call this function, and set
+ * cb to something else then NULL, SAM is automatically switched from
+ * application driven healtchecking to event driven healtchecking. In other
+ * words, is not longer needed to call sam_hc_send, but your callback function
+ * must return 0 in case of healtchecking is correct, or value different then
+ * 0, in case something happend. After next hc iteration, warning signal and
+ * after that kill signal is sent back to your application.
+ * @param cb Pointer to healtcheck function, or NULL to switch back to application driven hc
+ * @return
+ * - CS_OK in case no problem appeared
+ * - CS_ERR_BAD_HANDLE in case, you call this function before sam_init or after sam_start
+ * - CS_ERR_LIBRARY internal library call failed. This can be one of pipe or pthread
+ *   creation.
+ */
+cs_error_t sam_hc_callback_register (sam_hc_callback_t cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* COROSYNC_SAM_H_DEFINED */
diff --git a/include/corosync/totem/totem.h b/include/corosync/totem/totem.h
index 521a497..80bbf5c 100644
--- a/include/corosync/totem/totem.h
+++ b/include/corosync/totem/totem.h
@@ -35,6 +35,7 @@
 #ifndef TOTEM_H_DEFINED
 #define TOTEM_H_DEFINED
 #include "totemip.h"
+#include <corosync/hdb.h>
 
 #ifdef HAVE_SMALL_MEMORY_FOOTPRINT
 #define PROCESSOR_COUNT_MAX	16
@@ -178,11 +179,83 @@ enum totem_callback_token_type {
 	TOTEM_CALLBACK_TOKEN_SENT = 2
 };
 
+enum totem_event_type {
+	TOTEM_EVENT_DELIVERY_CONGESTED,
+	TOTEM_EVENT_NEW_MSG,
+};
+
 #define MEMB_RING_ID
 struct memb_ring_id {
 	struct totem_ip_address rep;
 	unsigned long long seq;
 } __attribute__((packed));
 
+typedef struct {
+	hdb_handle_t handle;
+	int is_dirty;
+	time_t last_updated;
+} totem_stats_header_t;
+
+typedef struct {
+	totem_stats_header_t hdr;
+	uint32_t iface_changes;
+} totemnet_stats_t;
+
+typedef struct {
+	totem_stats_header_t hdr;
+	totemnet_stats_t *net;
+	char *algo_name;
+} totemrrp_stats_t;
+
+
+typedef struct {
+	uint32_t rx;
+	uint32_t tx;
+	int backlog_calc;
+} totemsrp_token_stats_t;
+
+typedef struct {
+	totem_stats_header_t hdr;
+	totemrrp_stats_t *rrp;
+	uint64_t orf_token_tx;
+	uint64_t orf_token_rx;
+	uint64_t memb_merge_detect_tx;
+	uint64_t memb_merge_detect_rx;
+	uint64_t memb_join_tx;
+	uint64_t memb_join_rx;
+	uint64_t mcast_tx;
+	uint64_t mcast_retx;
+	uint64_t mcast_rx;
+	uint64_t memb_commit_token_tx;
+	uint64_t memb_commit_token_rx;
+	uint64_t token_hold_cancel_tx;
+	uint64_t token_hold_cancel_rx;
+	uint64_t operational_entered;
+	uint64_t operational_token_lost;
+	uint64_t gather_entered;
+	uint64_t gather_token_lost;
+	uint64_t commit_entered;
+	uint64_t commit_token_lost;
+	uint64_t recovery_entered;
+	uint64_t recovery_token_lost;
+	uint64_t consensus_timeouts;
+	uint64_t rx_msg_dropped;
+
+	int earliest_token;
+	int latest_token;
+#define TOTEM_TOKEN_STATS_MAX 100
+	totemsrp_token_stats_t token[TOTEM_TOKEN_STATS_MAX];
+
+} totemsrp_stats_t;
+
+typedef struct {
+	totem_stats_header_t hdr;
+	totemsrp_stats_t *srp;
+} totemmrp_stats_t;
+
+typedef struct {
+	totem_stats_header_t hdr;
+	totemmrp_stats_t *mrp;
+} totempg_stats_t;
 
 #endif /* TOTEM_H_DEFINED */
diff --git a/include/corosync/totem/totempg.h b/include/corosync/totem/totempg.h
index 4609092..fbf71fb 100644
--- a/include/corosync/totem/totempg.h
+++ b/include/corosync/totem/totempg.h
@@ -143,6 +143,10 @@ extern int totempg_ifaces_get (
 	char ***status,
         unsigned int *iface_count);
 
+extern void* totempg_get_stats (void);
+
+void totempg_event_signal (enum totem_event_type type, int value);
+
 extern const char *totempg_ifaces_print (unsigned int nodeid);
 
 extern unsigned int totempg_my_nodeid_get (void);
diff --git a/init/Makefile.am b/init/Makefile.am
index d495c13..2d079d1 100644
--- a/init/Makefile.am
+++ b/init/Makefile.am
@@ -34,4 +34,30 @@
 
 MAINTAINERCLEANFILES	= Makefile.in
 
-EXTRA_DIST		= generic mvlcge README redhat
+EXTRA_DIST		= generic.in
+
+target_INIT		= generic
+
+%: %.in Makefile
+	rm -f $@-t $@
+	sed \
+		-e 's#@''SBINDIR@#$(sbindir)#g' \
+		-e 's#@''SYSCONFDIR@#$(sysconfdir)#g' \
+		-e 's#@''INITDDIR@#$(INITDDIR)#g' \
+		-e 's#@''LOCALSTATEDIR@#$(localstatedir)#g' \
+	    $< > $@-t
+	chmod 0755 $@-t
+	mv $@-t $@
+
+all-local: $(target_INIT)
+
+clean-local:
+	rm -rf $(target_INIT)
+
+install-exec-local:
+	$(INSTALL) -d $(DESTDIR)/$(INITDDIR)
+	$(INSTALL) -m 755 generic $(DESTDIR)/$(INITDDIR)/corosync
+
+uninstall-local:
+	cd $(DESTDIR)/$(INITDDIR) && \
+		rm -f corosync
diff --git a/init/Makefile.in b/init/Makefile.in
index 2a80af2..05f0306 100644
--- a/init/Makefile.in
+++ b/init/Makefile.in
@@ -68,7 +68,7 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = init
-DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
@@ -107,6 +107,7 @@ EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
 GROFF = @GROFF@
+INITDDIR = @INITDDIR@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -202,7 +203,8 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 MAINTAINERCLEANFILES = Makefile.in
-EXTRA_DIST = generic mvlcge README redhat
+EXTRA_DIST = generic.in
+target_INIT = generic
 all: all-am
 
 .SUFFIXES:
@@ -275,7 +277,7 @@ distdir: $(DISTFILES)
 	done
 check-am: all-am
 check: check-am
-all-am: Makefile
+all-am: Makefile all-local
 installdirs:
 install: install-am
 install-exec: install-exec-am
@@ -305,7 +307,7 @@ maintainer-clean-generic:
 	-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
 clean: clean-am
 
-clean-am: clean-generic mostlyclean-am
+clean-am: clean-generic clean-local mostlyclean-am
 
 distclean: distclean-am
 	-rm -f Makefile
@@ -329,7 +331,7 @@ install-dvi: install-dvi-am
 
 install-dvi-am:
 
-install-exec-am:
+install-exec-am: install-exec-local
 
 install-html: install-html-am
 
@@ -367,21 +369,47 @@ ps: ps-am
 
 ps-am:
 
-uninstall-am:
+uninstall-am: uninstall-local
 
 .MAKE: install-am install-strip
 
-.PHONY: all all-am check check-am clean clean-generic distclean \
-	distclean-generic 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 \
+.PHONY: all all-am all-local check check-am clean clean-generic \
+	clean-local distclean distclean-generic 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-exec-local install-html \
 	install-html-am install-info install-info-am 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-generic pdf pdf-am ps ps-am uninstall uninstall-am
+	mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \
+	uninstall-local
 
 
+%: %.in Makefile
+	rm -f $@-t $@
+	sed \
+		-e 's#@''SBINDIR@#$(sbindir)#g' \
+		-e 's#@''SYSCONFDIR@#$(sysconfdir)#g' \
+		-e 's#@''INITDDIR@#$(INITDDIR)#g' \
+		-e 's#@''LOCALSTATEDIR@#$(localstatedir)#g' \
+	    $< > $@-t
+	chmod 0755 $@-t
+	mv $@-t $@
+
+all-local: $(target_INIT)
+
+clean-local:
+	rm -rf $(target_INIT)
+
+install-exec-local:
+	$(INSTALL) -d $(DESTDIR)/$(INITDDIR)
+	$(INSTALL) -m 755 generic $(DESTDIR)/$(INITDDIR)/corosync
+
+uninstall-local:
+	cd $(DESTDIR)/$(INITDDIR) && \
+		rm -f corosync
+
 # 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/init/README b/init/README
deleted file mode 100644
index ef0d408..0000000
--- a/init/README
+++ /dev/null
@@ -1,6 +0,0 @@
-This directory contains init scripts used to start and stop the Corosync Cluster
-Engine.
-
-redhat contains an init script for Red Hat systems.
-mvlcge contains an init script for MontaVista Linux systems.
-generic contains an init script for Generic Systems.
diff --git a/init/generic b/init/generic
deleted file mode 100755
index f13be6b..0000000
--- a/init/generic
+++ /dev/null
@@ -1,145 +0,0 @@
-#!/bin/sh
-#
-# corosync       Start the Corosync Cluster Engine
-#
-# Author:       Andrew Beekhof <abeekhof at suse.de>
-# License:      Revised BSD
-#
-# chkconfig: - 20 20
-# processname:  corosync
-# description:  Corosync Cluster Engine
-#
-### BEGIN INIT INFO
-# Description: corosync....
-#
-# Short-Description: Corosync Cluster Engine.
-# Provides: corosync
-# Required-Start: $network
-# Should-Start: $syslog
-# Required-Stop: $network
-# Default-Start: 3 5
-# Default-Stop: 0 6
-### END INIT INFO
-
-do_force=0
-prog="corosync"
-lockfile="/var/lock/subsys/$prog"
-
-internal_status() {
-    killall -0 corosync > /dev/null 2>&1
-    return $?
-}
-
-status() {
-    if
-	! internal_status
-    then
-	echo "Stopped"
-	return 7
-    fi
-
-    echo "Running"
-    return 0
-}
-
-start() {
-    echo -n $"Starting Corosync Cluster Engine ($prog): "
-    if
-	! internal_status
-    then
-	echo -n "starting... "
-	$prog 2>&1 > /dev/null 2>&1
-	echo -n "rc=$?: "
-    fi
-
-    sleep 2 # give it time to fail... $? isn't definitive
-
-    if
-	internal_status
-    then
-	echo "OK"
-	return 0
-    fi
-
-    echo "Failed"
-    return 1
-}
-
-do_force=0
-do_forever=1
-
-stop() {
-    echo -n $"Stopping Corosync Cluster Engine ($prog): "
-
-    killall -QUIT corosync
-
-    if [ $do_forever = 0 ]; then
-	for i in 1 2 3 4 5 6 7 8 9 10 12 13 14 15 16 17 18 19 20; do
-	    if
-		internal_status
-	    then
-		sleep 2
-		echo -n "."
-	    else
-		rm -f "$lockfile"
-		echo "OK"
-		return 0
-	    fi
-	done
-
-	if [ $do_force = 1 ]; then
-	    echo -n "Escalating... "
-	    killall -KILL corosync
-	    sleep 5
-
-	    if
-		! internal_status
-	    then
-		rm -f "$lockfile"
-		echo "OK"
-		return 0
-	    fi
-	fi
-
-	echo "Failed"
-	return 1
-    fi
-
-    while
-        internal_status
-    do
-	sleep 1
-	echo -n "."
-    done
-
-    rm -f "$lockfile"
-    echo "OK"
-    return 0
-}
-
-restart() {
-    stop
-    start
-}
-
-case "$1" in
-    start|stop|restart)
-        $1
-        ;;
-    force-stop)
-	do_force=1
-        stop
-        ;;
-    reload|force-reload)
-        restart
-        ;;
-    condrestart|try-restart)
-        [ ! -f "$lockfile" ] || restart
-        ;;
-    status)
-        status $prog
-        ;;
-    *)
-        echo $"Usage: $0 {start|stop|restart|try-restart|condrestart|reload|force-reload|force-stop|status}"
-        exit 2
-esac
diff --git a/init/generic.in b/init/generic.in
new file mode 100755
index 0000000..12236c1
--- /dev/null
+++ b/init/generic.in
@@ -0,0 +1,148 @@
+#!/bin/bash
+
+# Authors:
+#  Andrew Beekhof <abeekhof at redhat.com>
+#  Fabio M. Di Nitto <fdinitto at redhat.com>
+#
+# License: Revised BSD
+
+# chkconfig: - 20 20
+# description: Corosync Cluster Engine
+# processname: corosync
+#
+### BEGIN INIT INFO
+# Provides:		corosync
+# Required-Start:	$network
+# Should-Start:		$syslog
+# Required-Stop:	$network
+# Default-Start:
+# Default-Stop:
+# Short-Description:	Starts and stops Corosync Cluster Engine.
+# Description:		Starts and stops Corosync Cluster Engine.
+### END INIT INFO
+
+desc="Corosync Cluster Engine"
+prog="corosync"
+
+# set secure PATH
+PATH="/sbin:/bin:/usr/sbin:/usr/bin:@SBINDIR@"
+
+success()
+{
+	echo -ne "[  OK  ]\r"
+}
+
+failure()
+{
+	echo -ne "[FAILED]\r"
+}
+
+status()
+{
+	pid=$(pidof $1 2>/dev/null)
+	rtrn=$?
+	if [ $rtrn -ne 0 ]; then
+		echo "$1 is stopped"
+	else
+		echo "$1 (pid $pid) is running..."
+	fi
+	return $rtrn
+}
+
+# rpm based distros
+if [ -d @SYSCONFDIR@/sysconfig ]; then
+	[ -f @INITDDIR@/functions ] && . @INITDDIR@/functions
+	[ -f @SYSCONFDIR@/sysconfig/$prog ] && . @SYSCONFDIR@/sysconfig/$prog
+	[ -z "$LOCK_FILE" ] && LOCK_FILE="@LOCALSTATEDIR@/lock/subsys/$prog"
+fi
+
+# deb based distros
+if [ -d @SYSCONFDIR@/default ]; then
+	[ -f @SYSCONFDIR@/default/$prog ] && . @SYSCONFDIR@/default/$prog
+	[ -z "$LOCK_FILE" ] && LOCK_FILE="@LOCALSTATEDIR@/lock/$prog"
+fi
+
+start()
+{
+	echo -n "Starting $desc ($prog): "
+
+	# most recent distributions use tmpfs for @LOCALSTATEDIR@/run
+	# to avoid to clean it up on every boot.
+	# they also assume that init scripts will create
+	# required subdirectories for proper operations
+	mkdir -p @LOCALSTATEDIR@/run
+
+	if status $prog > /dev/null 2>&1; then
+		success
+	else
+		$prog > /dev/null 2>&1
+
+		# give it time to fail
+		sleep 2
+		if status $prog > /dev/null 2>&1; then
+			touch $LOCK_FILE
+			pidof $prog > @LOCALSTATEDIR@/run/$prog.pid
+			success
+		else
+			failure
+			rtrn=1
+		fi
+	fi
+	echo
+}
+
+stop()
+{
+	! status $prog > /dev/null 2>&1 && return
+
+	echo -n "Signaling $desc ($prog) to terminate: "
+	kill -TERM $(pidof $prog) > /dev/null 2>&1
+	success
+	echo
+
+	echo -n "Waiting for $prog services to unload:"
+	while status $prog > /dev/null 2>&1; do
+		sleep 1
+		echo -n "."
+	done
+
+	rm -f $LOCK_FILE
+	rm -f @LOCALSTATEDIR@/run/$prog.pid
+	success
+	echo
+}
+
+restart()
+{
+	stop
+	start
+}
+
+rtrn=0
+
+case "$1" in
+start)
+	start
+;;
+restart|reload|force-reload)
+	restart
+;;
+condrestart|try-restart)
+	if status $prog > /dev/null 2>&1; then
+		restart
+	fi
+;;
+status)
+	status $prog
+	rtrn=$?
+;;
+stop)
+	stop
+;;
+*)
+	echo "usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}"
+	rtrn=2
+;;
+esac
+
+exit $rtrn
diff --git a/init/mvlcge b/init/mvlcge
deleted file mode 100755
index 45fa240..0000000
--- a/init/mvlcge
+++ /dev/null
@@ -1,26 +0,0 @@
-#! /bin/sh
-#
-# Application Interface Specification Startup
-# chkconfig: 2345 20 20
-
-PATH=/bin:/usr/bin:/sbin:/usr/sbin
-
-test -f /usr/sbin/corosync | exit 0
-
-case "$1" in
-	start)
- 		echo -n "Starting Corosync Cluster Engine: "
-		start-stop-daemon --start --quiet --exec /usr/sbin/corosync
-		echo "."
-
-		;;
-       	stop)
-		echo -n "Stopping Corosync Cluster Engine: "
-		start-stop-daemon --stop --quiet --exec /usr/sbin/corosync
-		echo "."
-               	;;
-       	*)
-               echo "Usage: /etc/init.d/corosync {start|stop}" >&2
-               exit 1
-               ;;
-esac
diff --git a/init/redhat b/init/redhat
deleted file mode 100755
index dc516e3..0000000
--- a/init/redhat
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/bin/sh
-#
-# Corosync daemon init script for Red Hat Linux and compatibles.
-#
-# chkconfig: - 20 20
-# processname:  corosync
-# pidfile:      /var/run/corosync.pid
-# description:  Corosync Cluster Engine
-
-# Source function library
-. /etc/rc.d/init.d/functions
-
-prog="corosync"
-exec="/usr/sbin/corosync"
-lockfile="/var/lock/subsys/corosync"
-
-[ -x "$exec" ] || exit 0
-
-start() {
-    echo -n $"Starting Corosync Cluster Engine ($prog): "
-    daemon $exec
-    retval=$?
-    [ "$retval" -eq 0 ] && touch "$lockfile"
-    echo
-    return $retval
-}
-
-stop() {
-    echo -n $"Stopping Corosync Cluster Engine ($prog): "
-    # If no signal is specified, -TERM is used but _also_ -KILL 3s later
-    # This is far too aggressive for a cluster resource manager running on top of Corosync
-    killproc $prog -TERM
-    echo
-
-    echo -n $"Waiting for services to unload:"
-    while
-        pidofproc $prog > /dev/null 2>&1
-    do
-        sleep 2
-    done
-
-    success $"$base shutdown"
-    echo
-
-    rm -f "$lockfile"
-    return 0
-}
-
-restart() {
-    stop
-    start
-}
-
-case "$1" in
-    start|stop|restart)
-        $1
-        ;;
-    reload|force-reload)
-        restart
-        ;;
-    condrestart|try-restart)
-        [ ! -f "$lockfile" ] || restart
-        ;;
-    status)
-        status $prog
-        ;;
-    *)
-        echo $"Usage: $0 {start|stop|restart|try-restart|condrestart|reload|force-reload|status}"
-        exit 2
-esac
diff --git a/lcr/Makefile.in b/lcr/Makefile.in
index 9338a81..1ee179f 100644
--- a/lcr/Makefile.in
+++ b/lcr/Makefile.in
@@ -128,6 +128,7 @@ EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
 GROFF = @GROFF@
+INITDDIR = @INITDDIR@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 164aa07..cc2d642 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -39,7 +39,7 @@ AM_LDFLAGS		= -lpthread
 INCLUDES		= -I$(top_builddir)/include -I$(top_srcdir)/include
 
 lib_LIBRARIES		= libcpg.a libconfdb.a libevs.a libcfg.a libquorum.a \
-			  libvotequorum.a libpload.a libcoroipcc.a
+			  libvotequorum.a libpload.a libcoroipcc.a libsam.a
 SHARED_LIBS		= $(filter-out libcpg.so.$(SONAME), $(lib_LIBRARIES:%.a=%.so.$(SONAME))) libcpg.so.$(CPG_SONAME)
 SHARED_LIBS_SO		= $(lib_LIBRARIES:%.a=%.so)
 SHARED_LIBS_SO_TWO	= $(lib_LIBRARIES:%.a=%.so.$(SOMAJOR))
@@ -52,12 +52,14 @@ libquorum_a_SOURCES	= quorum.c
 libvotequorum_a_SOURCES	= votequorum.c
 libconfdb_a_SOURCES	= confdb.c sa-confdb.c
 libcoroipcc_a_SOURCES	= coroipcc.c
+libsam_a_SOURCES	= sam.c
 
 noinst_HEADERS		= sa-confdb.h util.h \
 			  libcfg.versions libconfdb.versions \
 			  libcoroipcc.versions libcpg.versions \
 			  libevs.versions libpload.versions \
-			  libquorum.versions libvotequorum.versions
+			  libquorum.versions libvotequorum.versions \
+			  libsam.versions
 
 ../lcr/lcr_ifact.o:
 	$(MAKE) -C ../lcr lcr_ifact.o
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 3438ff2..de86ea9 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -132,6 +132,10 @@ libquorum_a_AR = $(AR) $(ARFLAGS)
 libquorum_a_LIBADD =
 am_libquorum_a_OBJECTS = quorum.$(OBJEXT)
 libquorum_a_OBJECTS = $(am_libquorum_a_OBJECTS)
+libsam_a_AR = $(AR) $(ARFLAGS)
+libsam_a_LIBADD =
+am_libsam_a_OBJECTS = sam.$(OBJEXT)
+libsam_a_OBJECTS = $(am_libsam_a_OBJECTS)
 libvotequorum_a_AR = $(AR) $(ARFLAGS)
 libvotequorum_a_LIBADD =
 am_libvotequorum_a_OBJECTS = votequorum.$(OBJEXT)
@@ -147,11 +151,13 @@ LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
 SOURCES = $(libcfg_a_SOURCES) $(libconfdb_a_SOURCES) \
 	$(libcoroipcc_a_SOURCES) $(libcpg_a_SOURCES) \
 	$(libevs_a_SOURCES) $(libpload_a_SOURCES) \
-	$(libquorum_a_SOURCES) $(libvotequorum_a_SOURCES)
+	$(libquorum_a_SOURCES) $(libsam_a_SOURCES) \
+	$(libvotequorum_a_SOURCES)
 DIST_SOURCES = $(libcfg_a_SOURCES) $(libconfdb_a_SOURCES) \
 	$(libcoroipcc_a_SOURCES) $(libcpg_a_SOURCES) \
 	$(libevs_a_SOURCES) $(libpload_a_SOURCES) \
-	$(libquorum_a_SOURCES) $(libvotequorum_a_SOURCES)
+	$(libquorum_a_SOURCES) $(libsam_a_SOURCES) \
+	$(libvotequorum_a_SOURCES)
 HEADERS = $(noinst_HEADERS)
 ETAGS = etags
 CTAGS = ctags
@@ -182,6 +188,7 @@ EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
 GROFF = @GROFF@
+INITDDIR = @INITDDIR@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -281,7 +288,7 @@ AM_CFLAGS = -fPIC
 AM_LDFLAGS = -lpthread
 INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
 lib_LIBRARIES = libcpg.a libconfdb.a libevs.a libcfg.a libquorum.a \
-			  libvotequorum.a libpload.a libcoroipcc.a
+			  libvotequorum.a libpload.a libcoroipcc.a libsam.a
 
 SHARED_LIBS = $(filter-out libcpg.so.$(SONAME), $(lib_LIBRARIES:%.a=%.so.$(SONAME))) libcpg.so.$(CPG_SONAME)
 SHARED_LIBS_SO = $(lib_LIBRARIES:%.a=%.so)
@@ -294,11 +301,13 @@ libquorum_a_SOURCES = quorum.c
 libvotequorum_a_SOURCES = votequorum.c
 libconfdb_a_SOURCES = confdb.c sa-confdb.c
 libcoroipcc_a_SOURCES = coroipcc.c
+libsam_a_SOURCES = sam.c
 noinst_HEADERS = sa-confdb.h util.h \
 			  libcfg.versions libconfdb.versions \
 			  libcoroipcc.versions libcpg.versions \
 			  libevs.versions libpload.versions \
-			  libquorum.versions libvotequorum.versions
+			  libquorum.versions libvotequorum.versions \
+			  libsam.versions
 
 all: all-am
 
@@ -394,6 +403,10 @@ libquorum.a: $(libquorum_a_OBJECTS) $(libquorum_a_DEPENDENCIES)
 	-rm -f libquorum.a
 	$(libquorum_a_AR) libquorum.a $(libquorum_a_OBJECTS) $(libquorum_a_LIBADD)
 	$(RANLIB) libquorum.a
+libsam.a: $(libsam_a_OBJECTS) $(libsam_a_DEPENDENCIES) 
+	-rm -f libsam.a
+	$(libsam_a_AR) libsam.a $(libsam_a_OBJECTS) $(libsam_a_LIBADD)
+	$(RANLIB) libsam.a
 libvotequorum.a: $(libvotequorum_a_OBJECTS) $(libvotequorum_a_DEPENDENCIES) 
 	-rm -f libvotequorum.a
 	$(libvotequorum_a_AR) libvotequorum.a $(libvotequorum_a_OBJECTS) $(libvotequorum_a_LIBADD)
@@ -413,6 +426,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/pload.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/quorum.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sa-confdb.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sam.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/votequorum.Po at am__quote@
 
 .c.o:
diff --git a/lib/cfg.c b/lib/cfg.c
index 17d2591..19edb88 100644
--- a/lib/cfg.c
+++ b/lib/cfg.c
@@ -220,14 +220,8 @@ corosync_cfg_dispatch (
 		/*
 		 * Determine if more messages should be processed
 		 */
-		switch (dispatch_flags) {
-		case CS_DISPATCH_ONE:
+		if (dispatch_flags == CS_DISPATCH_ONE) {
 			cont = 0;
-			break;
-		case CS_DISPATCH_ALL:
-			break;
-		case CS_DISPATCH_BLOCKING:
-			break;
 		}
 	} while (cont);
 
diff --git a/lib/confdb.c b/lib/confdb.c
index 8a0d159..1d8bd8b 100644
--- a/lib/confdb.c
+++ b/lib/confdb.c
@@ -297,8 +297,8 @@ cs_error_t confdb_dispatch (
 	}
 
 	/*
-	 * Timeout instantly for SA_DISPATCH_ONE or SA_DISPATCH_ALL and
-	 * wait indefinately for SA_DISPATCH_BLOCKING
+	 * Timeout instantly for CS_DISPATCH_ONE or CS_DISPATCH_ALL and
+	 * wait indefinately for CS_DISPATCH_BLOCKING
 	 */
 	if (dispatch_types == CONFDB_DISPATCH_ALL) {
 		timeout = 0;
@@ -394,15 +394,9 @@ cs_error_t confdb_dispatch (
 
 		/*
 		 * Determine if more messages should be processed
-		 * */
-		switch (dispatch_types) {
-		case CONFDB_DISPATCH_ONE:
+		 */
+		if (dispatch_types == CS_DISPATCH_ONE) {
 			cont = 0;
-			break;
-		case CONFDB_DISPATCH_ALL:
-			break;
-		case CONFDB_DISPATCH_BLOCKING:
-			break;
 		}
 	} while (cont);
 
@@ -722,6 +716,68 @@ error_exit:
 	return (error);
 }
 
+
+cs_error_t confdb_key_create_typed (
+	confdb_handle_t handle,
+	hdb_handle_t parent_object_handle,
+	const char *key_name,
+	const void *value,
+	size_t value_len,
+	confdb_value_types_t type)
+{
+	cs_error_t error;
+	struct confdb_inst *confdb_inst;
+	struct iovec iov;
+	struct req_lib_confdb_key_create_typed request;
+	coroipc_response_header_t res;
+
+	error = hdb_error_to_cs(hdb_handle_get (&confdb_handle_t_db, handle, (void *)&confdb_inst));
+	if (error != CS_OK) {
+		return (error);
+	}
+
+	if (confdb_inst->standalone) {
+		error = CS_OK;
+
+		if (confdb_sa_key_create_typed(parent_object_handle,
+					 key_name, value, value_len, type))
+			error = CS_ERR_ACCESS;
+		goto error_exit;
+	}
+
+	request.header.size = sizeof (struct req_lib_confdb_key_create_typed);
+	request.header.id = MESSAGE_REQ_CONFDB_KEY_CREATE_TYPED;
+	request.object_handle = parent_object_handle;
+	request.key_name.length = strlen(key_name)+1;
+	memcpy(request.key_name.value, key_name, request.key_name.length);
+	memcpy(request.value.value, value, value_len);
+	request.value.length = value_len;
+	request.type = type;
+
+	iov.iov_base = (char *)&request;
+	iov.iov_len = sizeof (struct req_lib_confdb_key_create_typed);
+
+	error = coroipcc_msg_send_reply_receive (
+		confdb_inst->handle,
+		&iov,
+		1,
+		&res,
+		sizeof (res));
+
+	if (error != CS_OK) {
+		goto error_exit;
+	}
+
+	error = res.error;
+
+error_exit:
+	(void)hdb_handle_put (&confdb_handle_t_db, handle);
+
+	return (error);
+}
+
+
+
 cs_error_t confdb_key_delete (
 	confdb_handle_t handle,
 	hdb_handle_t parent_object_handle,
@@ -842,6 +898,69 @@ error_exit:
 	return (error);
 }
 
+
+cs_error_t confdb_key_get_typed (
+	confdb_handle_t handle,
+	hdb_handle_t parent_object_handle,
+	const char *key_name,
+	void *value,
+	size_t *value_len,
+	confdb_value_types_t *type)
+{
+	cs_error_t error;
+	struct confdb_inst *confdb_inst;
+	struct iovec iov;
+	struct req_lib_confdb_key_get req_lib_confdb_key_get;
+	struct res_lib_confdb_key_get_typed response;
+
+	error = hdb_error_to_cs(hdb_handle_get (&confdb_handle_t_db, handle, (void *)&confdb_inst));
+	if (error != CS_OK) {
+		return (error);
+	}
+
+	if (confdb_inst->standalone) {
+		error = CS_OK;
+
+		if (confdb_sa_key_get_typed(parent_object_handle,
+				      key_name, value, value_len, (int*)type))
+			error = CS_ERR_ACCESS;
+		goto error_exit;
+	}
+
+	req_lib_confdb_key_get.header.size = sizeof (struct req_lib_confdb_key_get);
+	req_lib_confdb_key_get.header.id = MESSAGE_REQ_CONFDB_KEY_GET_TYPED;
+	req_lib_confdb_key_get.parent_object_handle = parent_object_handle;
+	req_lib_confdb_key_get.key_name.length = strlen(key_name) + 1;
+	memcpy(req_lib_confdb_key_get.key_name.value, key_name, req_lib_confdb_key_get.key_name.length);
+
+	iov.iov_base = (char *)&req_lib_confdb_key_get;
+	iov.iov_len = sizeof (struct req_lib_confdb_key_get);
+
+        error = coroipcc_msg_send_reply_receive (
+		confdb_inst->handle,
+		&iov,
+		1,
+		&response,
+		sizeof (struct res_lib_confdb_key_get_typed));
+
+	if (error != CS_OK) {
+		goto error_exit;
+	}
+
+	error = response.header.error;
+	if (error == CS_OK) {
+		*value_len = response.value.length;
+		*type = response.type;
+		memcpy(value, response.value.value, *value_len);
+	}
+
+error_exit:
+	(void)hdb_handle_put (&confdb_handle_t_db, handle);
+
+	return (error);
+}
+
+
 cs_error_t confdb_key_increment (
 	confdb_handle_t handle,
 	hdb_handle_t parent_object_handle,
@@ -1330,8 +1449,10 @@ cs_error_t confdb_key_iter (
 
 	error = res_lib_confdb_key_iter.header.error;
 	if (error == CS_OK) {
+		char* key_name_str = (char*)key_name;
 		*key_name_len = res_lib_confdb_key_iter.key_name.length;
 		memcpy(key_name, res_lib_confdb_key_iter.key_name.value, *key_name_len);
+		key_name_str[res_lib_confdb_key_iter.key_name.length] = '\0';
 		*value_len = res_lib_confdb_key_iter.value.length;
 		memcpy(value, res_lib_confdb_key_iter.value.value, *value_len);
 	}
@@ -1345,6 +1466,81 @@ error_exit:
 	return (error);
 }
 
+cs_error_t confdb_key_iter_typed (
+	confdb_handle_t handle,
+	hdb_handle_t parent_object_handle,
+	char *key_name,
+	void *value,
+	size_t *value_len,
+	confdb_value_types_t *type)
+{
+	cs_error_t error;
+	struct confdb_inst *confdb_inst;
+	struct iovec iov;
+	struct iter_context *context;
+	struct req_lib_confdb_key_iter req_lib_confdb_key_iter;
+	struct res_lib_confdb_key_iter_typed response;
+
+	error = hdb_error_to_cs(hdb_handle_get (&confdb_handle_t_db, handle, (void *)&confdb_inst));
+	if (error != CS_OK) {
+		return (error);
+	}
+
+	/* You MUST call confdb_key_iter_start first */
+	context = find_iter_context(&confdb_inst->key_iter_head, parent_object_handle);
+	if (!context) {
+		error =	CS_ERR_CONTEXT_NOT_FOUND;
+		goto error_exit;
+	}
+
+	if (confdb_inst->standalone) {
+		error = CS_OK;
+
+		if (confdb_sa_key_iter_typed(parent_object_handle,
+				       context->next_entry,
+				       key_name,
+				       value, value_len, (int*)type))
+			error = CS_ERR_ACCESS;
+		goto sa_exit;
+	}
+
+	req_lib_confdb_key_iter.header.size = sizeof (struct req_lib_confdb_key_iter);
+	req_lib_confdb_key_iter.header.id = MESSAGE_REQ_CONFDB_KEY_ITER_TYPED;
+	req_lib_confdb_key_iter.parent_object_handle = parent_object_handle;
+	req_lib_confdb_key_iter.next_entry= context->next_entry;
+
+	iov.iov_base = (char *)&req_lib_confdb_key_iter;
+	iov.iov_len = sizeof (struct req_lib_confdb_key_iter);
+
+	error = coroipcc_msg_send_reply_receive (
+		confdb_inst->handle,
+		&iov,
+		1,
+		&response,
+		sizeof (struct res_lib_confdb_key_iter_typed));
+
+	if (error != CS_OK) {
+		goto error_exit;
+	}
+
+	error = response.header.error;
+	if (error == CS_OK) {
+		memcpy(key_name, response.key_name.value, response.key_name.length);
+		key_name[response.key_name.length] = '\0';
+		*value_len = response.value.length;
+		memcpy(value, response.value.value, *value_len);
+		*type = response.type;
+	}
+
+sa_exit:
+	context->next_entry++;
+
+error_exit:
+	(void)hdb_handle_put (&confdb_handle_t_db, handle);
+
+	return (error);
+}
+
 cs_error_t confdb_write (
 	confdb_handle_t handle,
 	char *error_text,
diff --git a/lib/coroipcc.c b/lib/coroipcc.c
index c0861a5..aa9546c 100644
--- a/lib/coroipcc.c
+++ b/lib/coroipcc.c
@@ -849,7 +849,7 @@ coroipcc_dispatch_get (
 		goto error_put;
 	}
 	ipc_instance->flow_control_state = 0;
-	if (buf == 1 || buf == 2) {
+	if (buf == MESSAGE_RES_OUTQ_NOT_EMPTY || buf == MESSAGE_RES_ENABLE_FLOWCONTROL) {
 		ipc_instance->flow_control_state = 1;
 	}
 	/*
@@ -864,11 +864,11 @@ coroipcc_dispatch_get (
 	 * This is just a notification of flow control starting at the addition
 	 * of a new pending message, not a message to dispatch
 	 */
-	if (buf == 2) {
+	if (buf == MESSAGE_RES_ENABLE_FLOWCONTROL) {
 		error = CS_ERR_TRY_AGAIN;
 		goto error_put;
 	}
-	if (buf == 3) {
+	if (buf == MESSAGE_RES_OUTQ_FLUSH_NR) {
 		error = CS_ERR_TRY_AGAIN;
 		goto error_put;
 	}
diff --git a/lib/cpg.c b/lib/cpg.c
index f031a95..780e79f 100644
--- a/lib/cpg.c
+++ b/lib/cpg.c
@@ -258,7 +258,6 @@ cs_error_t cpg_dispatch (
 	struct res_lib_cpg_deliver_callback *res_cpg_deliver_callback;
 	cpg_callbacks_t callbacks;
 	coroipc_response_header_t *dispatch_data;
-	int ignore_dispatch = 0;
 	struct cpg_address member_list[CPG_MEMBERS_MAX];
 	struct cpg_address left_list[CPG_MEMBERS_MAX];
 	struct cpg_address joined_list[CPG_MEMBERS_MAX];
@@ -273,8 +272,8 @@ cs_error_t cpg_dispatch (
 	}
 
 	/*
-	 * Timeout instantly for SA_DISPATCH_ONE or SA_DISPATCH_ALL and
-	 * wait indefinately for SA_DISPATCH_BLOCKING
+	 * Timeout instantly for CS_DISPATCH_ONE or CS_DISPATCH_ALL and
+	 * wait indefinately for CS_DISPATCH_BLOCKING
 	 */
 	if (dispatch_types == CPG_DISPATCH_ALL) {
 		timeout = 0;
@@ -378,22 +377,9 @@ cs_error_t cpg_dispatch (
 
 		/*
 		 * Determine if more messages should be processed
-		 * */
-		switch (dispatch_types) {
-		case CPG_DISPATCH_ONE:
-			if (ignore_dispatch) {
-				ignore_dispatch = 0;
-			} else {
-				cont = 0;
-			}
-			break;
-		case CPG_DISPATCH_ALL:
-			if (ignore_dispatch) {
-				ignore_dispatch = 0;
-			}
-			break;
-		case CPG_DISPATCH_BLOCKING:
-			break;
+		 */
+		if (dispatch_types == CS_DISPATCH_ONE) {
+			cont = 0;
 		}
 	} while (cont);
 
@@ -860,7 +846,7 @@ cs_error_t cpg_iteration_next(
 			description,
 			&res_lib_cpg_iterationnext->description);
 
-	error = (error == CS_OK ? res_lib_cpg_iterationnext->header.error : error);
+	error = res_lib_cpg_iterationnext->header.error;
 
 	coroipcc_msg_send_reply_receive_in_buf_put(
 			cpg_iteration_instance->conn_handle);
diff --git a/lib/evs.c b/lib/evs.c
index bb18e65..46985ff 100644
--- a/lib/evs.c
+++ b/lib/evs.c
@@ -231,7 +231,6 @@ evs_error_t evs_dispatch (
 	struct res_evs_deliver_callback *res_evs_deliver_callback;
 	evs_callbacks_t callbacks;
 	coroipc_response_header_t *dispatch_data;
-	int ignore_dispatch = 0;
 
 	error = hdb_error_to_cs(hdb_handle_get (&evs_handle_t_db, handle, (void *)&evs_inst));
 	if (error != CS_OK) {
@@ -239,8 +238,8 @@ evs_error_t evs_dispatch (
 	}
 
 	/*
-	 * Timeout instantly for SA_DISPATCH_ONE or SA_DISPATCH_ALL and
-	 * wait indefinately for SA_DISPATCH_BLOCKING
+	 * Timeout instantly for CS_DISPATCH_ONE or CS_DISPATCH_ALL and
+	 * wait indefinately for CS_DISPATCH_BLOCKING
 	 */
 	if (dispatch_types == EVS_DISPATCH_ALL) {
 		timeout = 0;
@@ -318,22 +317,9 @@ evs_error_t evs_dispatch (
 
 		/*
 		 * Determine if more messages should be processed
-		 * */
-		switch (dispatch_types) {
-		case EVS_DISPATCH_ONE:
-			if (ignore_dispatch) {
-				ignore_dispatch = 0;
-			} else {
-				cont = 0;
-			}
-			break;
-		case EVS_DISPATCH_ALL:
-			if (ignore_dispatch) {
-				ignore_dispatch = 0;
-			}
-			break;
-		case EVS_DISPATCH_BLOCKING:
-			break;
+		 */
+		if (dispatch_types == CS_DISPATCH_ONE) {
+			cont = 0;
 		}
 	} while (cont);
 
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/quorum.c b/lib/quorum.c
index d334269..11dbf5c 100644
--- a/lib/quorum.c
+++ b/lib/quorum.c
@@ -408,15 +408,9 @@ cs_error_t quorum_dispatch (
 
 		/*
 		 * Determine if more messages should be processed
-		 * */
-		switch (dispatch_types) {
-		case CS_DISPATCH_ONE:
+		 */
+		if (dispatch_types == CS_DISPATCH_ONE) {
 			cont = 0;
-			break;
-		case CS_DISPATCH_ALL:
-			break;
-		case CS_DISPATCH_BLOCKING:
-			break;
 		}
 	} while (cont);
 
diff --git a/lib/sa-confdb.c b/lib/sa-confdb.c
index 1178cff..712df9d 100644
--- a/lib/sa-confdb.c
+++ b/lib/sa-confdb.c
@@ -197,6 +197,18 @@ int confdb_sa_key_create (
 					value, value_len);
 }
 
+int confdb_sa_key_create_typed (
+	hdb_handle_t parent_object_handle,
+	const char *key_name,
+	const void *value,
+	size_t value_len,
+	int type)
+{
+	return objdb->object_key_create_typed(parent_object_handle,
+					key_name,
+					value, value_len, type);
+}
+
 int confdb_sa_key_delete (
 	hdb_handle_t parent_object_handle,
 	const void *key_name,
@@ -227,6 +239,25 @@ int confdb_sa_key_get (
 	return res;
 }
 
+int confdb_sa_key_get_typed (
+	hdb_handle_t parent_object_handle,
+	const char *key_name,
+	void *value,
+	size_t *value_len,
+	int *type)
+{
+	int res;
+	void *kvalue;
+
+	res = objdb->object_key_get_typed(parent_object_handle,
+				    key_name,
+				    &kvalue, value_len, (objdb_value_types_t*)type);
+	if (!res) {
+		memcpy(value, kvalue, *value_len);
+	}
+	return res;
+}
+
 int confdb_sa_key_increment (
 	hdb_handle_t parent_object_handle,
 	const void *key_name,
@@ -373,6 +404,36 @@ int confdb_sa_key_iter (
 	return res;
 }
 
+int confdb_sa_key_iter_typed (
+	hdb_handle_t parent_object_handle,
+	hdb_handle_t start_pos,
+	char *key_name,
+	void *value,
+	size_t *value_len,
+	int *type)
+{
+	int res;
+	void *kname;
+	void *kvalue;
+	size_t key_name_len;
+
+	res = objdb->object_key_iter_from(parent_object_handle,
+					  start_pos,
+					  &kname, &key_name_len,
+					  &kvalue, value_len);
+
+	if (!res) {
+		memcpy(key_name, kname, key_name_len);
+		key_name[key_name_len] = '\0';
+		memcpy(value, kvalue, *value_len);
+
+		objdb->object_key_get_typed(parent_object_handle,
+					  key_name,
+					  &kvalue, value_len, (objdb_value_types_t*)type);
+	}
+	return res;
+}
+
 int confdb_sa_find_destroy(hdb_handle_t find_handle)
 {
 	return objdb->object_find_destroy(find_handle);
diff --git a/lib/sa-confdb.h b/lib/sa-confdb.h
index 102eaf5..d9ea906 100644
--- a/lib/sa-confdb.h
+++ b/lib/sa-confdb.h
@@ -45,6 +45,11 @@ extern int confdb_sa_key_create(hdb_handle_t parent_object_handle,
 				size_t key_name_len,
 				const void *value,
 				size_t value_len);
+extern int confdb_sa_key_create_typed (hdb_handle_t parent_object_handle,
+				const char *key_name,
+				const void *value,
+				size_t value_len,
+				int type);
 extern int confdb_sa_key_delete(hdb_handle_t parent_object_handle,
 				const void *key_name,
 				size_t key_name_len,
@@ -55,6 +60,11 @@ extern int confdb_sa_key_get(hdb_handle_t parent_object_handle,
 			     size_t key_name_len,
 			     void *value,
 			     size_t *value_len);
+extern int confdb_sa_key_get_typed(hdb_handle_t parent_object_handle,
+			     const char *key_name,
+			     void *value,
+			     size_t *value_len,
+			     int *type);
 extern int confdb_sa_key_replace(hdb_handle_t parent_object_handle,
 				 const void *key_name,
 				 size_t key_name_len,
@@ -80,6 +90,12 @@ extern int confdb_sa_key_iter(hdb_handle_t parent_object_handle,
 			      size_t *key_name_len,
 			      void *value,
 			      size_t *value_len);
+extern int confdb_sa_key_iter_typed (hdb_handle_t parent_object_handle,
+				hdb_handle_t start_pos,
+				char *key_name,
+				void *value,
+				size_t *value_len,
+				int *type);
 extern int confdb_sa_key_increment(hdb_handle_t parent_object_handle,
 				   const void *key_name,
 				   size_t key_name_len,
diff --git a/lib/sam.c b/lib/sam.c
new file mode 100644
index 0000000..f6f6449
--- /dev/null
+++ b/lib/sam.c
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Jan Friesse (jfriesse at 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 <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#include <corosync/corotypes.h>
+#include <corosync/coroipc_types.h>
+#include <corosync/coroipcc.h>
+#include <corosync/corodefs.h>
+#include <corosync/hdb.h>
+
+#include <corosync/sam.h>
+
+#include "util.h"
+
+#include <stdio.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+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
+};
+
+enum sam_parent_action_t {
+	SAM_PARENT_ACTION_ERROR,
+	SAM_PARENT_ACTION_RECOVERY,
+	SAM_PARENT_ACTION_QUIT,
+	SAM_PARENT_ACTION_CONTINUE
+};
+
+static struct {
+	int time_interval;
+	sam_recovery_policy_t recovery_policy;
+	enum sam_internal_status_t internal_status;
+	unsigned int instance_id;
+	int parent_fd;
+	int term_send;
+
+	sam_hc_callback_t hc_callback;
+	pthread_t cb_thread;
+	int cb_rpipe_fd, cb_wpipe_fd;
+	int cb_registered;
+} sam_internal_data;
+
+cs_error_t sam_initialize (
+	int time_interval,
+	sam_recovery_policy_t recovery_policy)
+{
+	if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_NOT_INITIALIZED) {
+		return (CS_ERR_BAD_HANDLE);
+	}
+
+	if (recovery_policy != SAM_RECOVERY_POLICY_QUIT && recovery_policy != SAM_RECOVERY_POLICY_RESTART) {
+		return (CS_ERR_INVALID_PARAM);
+	}
+
+	sam_internal_data.recovery_policy = recovery_policy;
+
+	sam_internal_data.time_interval = time_interval;
+
+	sam_internal_data.internal_status = SAM_INTERNAL_STATUS_INITIALIZED;
+
+	return (CS_OK);
+}
+
+/*
+ * 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);
+
+		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;
+}
+
+cs_error_t sam_start (void)
+{
+	char command;
+
+	if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED) {
+		return (CS_ERR_BAD_HANDLE);
+	}
+
+	command = SAM_COMMAND_START;
+
+	if (sam_safe_write (sam_internal_data.parent_fd, &command, 1) == -1)
+		return (CS_ERR_LIBRARY);
+
+	if (sam_internal_data.hc_callback)
+		if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, 1) == -1)
+			return (CS_ERR_LIBRARY);
+
+	sam_internal_data.internal_status = SAM_INTERNAL_STATUS_STARTED;
+
+	return (CS_OK);
+}
+
+cs_error_t sam_stop (void)
+{
+	char command;
+
+	if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
+		return (CS_ERR_BAD_HANDLE);
+	}
+
+	command = SAM_COMMAND_STOP;
+
+	if (sam_safe_write (sam_internal_data.parent_fd, &command, 1) == -1)
+		return (CS_ERR_LIBRARY);
+
+	if (sam_internal_data.hc_callback)
+		if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, 1) == -1)
+			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.parent_fd, &command, 1) == -1)
+		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;
+
+exit_error:
+	return (CS_OK);
+}
+
+
+
+static enum sam_parent_action_t sam_parent_handler (int pipe_fd, pid_t child_pid)
+{
+	int poll_error;
+	int action;
+	int status;
+	ssize_t bytes_read;
+	char command;
+	int time_interval;
+	struct pollfd pfds;
+
+	status = 0;
+
+	action = SAM_PARENT_ACTION_CONTINUE;
+
+	while (action == SAM_PARENT_ACTION_CONTINUE) {
+		pfds.fd = pipe_fd;
+		pfds.events = POLLIN;
+		pfds.revents = 0;
+
+		if (status == 1 && sam_internal_data.time_interval != 0) {
+			time_interval = sam_internal_data.time_interval;
+		} else {
+			time_interval = -1;
+		}
+
+		poll_error = poll (&pfds, 1, 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 {
+				/*
+				 *  Kill child process
+				 */
+				if (!sam_internal_data.term_send) {
+					/*
+					 * We didn't send SIGTERM (warning) yet.
+					 */
+
+					kill (child_pid, SIGTERM);
+
+					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;
+				}
+			}
+		}
+
+		if (poll_error > 0) {
+			/*
+			 *  We have EOF or command in pipe
+			 */
+			bytes_read = read (pipe_fd, &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) {
+				/*
+				 * Something really bad happened in read side
+				 */
+				if (errno == EAGAIN || errno == EINTR) {
+					continue;
+				}
+
+				action = SAM_PARENT_ACTION_ERROR;
+				goto action_exit;
+			}
+
+			/*
+			 * We have read command -> take status
+			 */
+			switch (status) {
+			case 0:
+				/*
+				 *  Not started yet
+				 */
+				if (command == SAM_COMMAND_START)
+					status = 1;
+			break;
+
+			case 1:
+				/*
+				 *  Started
+				 */
+				if (command == SAM_COMMAND_STOP)
+					status = 0;
+			break;
+
+			}
+		} /* 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[2];
+	enum sam_parent_action_t action;
+	int child_status;
+
+	if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED) {
+		return (CS_ERR_BAD_HANDLE);
+	}
+
+	error = CS_OK;
+
+	while (1) {
+		pipe_error = pipe (pipe_fd);
+
+		if (pipe_error != 0) {
+			/*
+			 *  Pipe creation error
+			 */
+			error = CS_ERR_LIBRARY;
+			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[0]);
+
+			sam_internal_data.parent_fd = pipe_fd[1];
+			if (instance_id)
+				*instance_id = sam_internal_data.instance_id;
+
+			sam_internal_data.internal_status = SAM_INTERNAL_STATUS_REGISTERED;
+
+			goto error_exit;
+		} else {
+			/*
+			 *  Parent process
+			 */
+			close (pipe_fd[1]);
+
+			action = sam_parent_handler (pipe_fd[0], pid);
+
+			close (pipe_fd[0]);
+
+			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)
+				;
+
+			if (action == SAM_PARENT_ACTION_RECOVERY) {
+				if (sam_internal_data.recovery_policy == SAM_RECOVERY_POLICY_QUIT)
+					action = SAM_PARENT_ACTION_QUIT;
+			}
+
+			if (action == SAM_PARENT_ACTION_QUIT) {
+				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) {
+			sam_hc_send ();
+			counter++;
+
+			if (counter >= 4) {
+				if (sam_internal_data.hc_callback () != 0) {
+					status = 3;
+				}
+
+				counter = 0;
+			}
+		}
+
+		if (poll_error > 0) {
+			bytes_readed = 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/votequorum.c b/lib/votequorum.c
index 2731f7f..8cf400b 100644
--- a/lib/votequorum.c
+++ b/lib/votequorum.c
@@ -775,15 +775,9 @@ cs_error_t votequorum_dispatch (
 
 		/*
 		 * Determine if more messages should be processed
-		 * */
-		switch (dispatch_types) {
-		case CS_DISPATCH_ONE:
+		 */
+		if (dispatch_types == CS_DISPATCH_ONE) {
 			cont = 0;
-			break;
-		case CS_DISPATCH_ALL:
-			break;
-		case CS_DISPATCH_BLOCKING:
-			break;
 		}
 	} while (cont);
 
diff --git a/man/Makefile.am b/man/Makefile.am
index 3885452..348bc5b 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -99,8 +99,16 @@ dist_man_MANS = \
 	votequorum_qdisk_register.3 \
 	votequorum_qdisk_unregister.3 \
 	votequorum_setexpected.3 \
-	votequorum_setvotes.3
-
+	votequorum_setvotes.3 \
+	sam_finalize.3 \
+	sam_hc_callback_register.3 \
+	sam_hc_send.3 \
+	sam_initialize.3 \
+	sam_overview.8 \
+	sam_register.3 \
+	sam_start.3 \
+	sam_stop.3
+	
 if BUILD_HTML_DOCS
 
 HTML_DOCS = $(dist_man_MANS:%=%.html)
diff --git a/man/Makefile.in b/man/Makefile.in
index f62ec50..815c553 100644
--- a/man/Makefile.in
+++ b/man/Makefile.in
@@ -136,6 +136,7 @@ EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
 GROFF = @GROFF@
+INITDDIR = @INITDDIR@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -295,7 +296,15 @@ dist_man_MANS = \
 	votequorum_qdisk_register.3 \
 	votequorum_qdisk_unregister.3 \
 	votequorum_setexpected.3 \
-	votequorum_setvotes.3
+	votequorum_setvotes.3 \
+	sam_finalize.3 \
+	sam_hc_callback_register.3 \
+	sam_hc_send.3 \
+	sam_initialize.3 \
+	sam_overview.8 \
+	sam_register.3 \
+	sam_start.3 \
+	sam_stop.3
 
 @BUILD_HTML_DOCS_TRUE at HTML_DOCS = $(dist_man_MANS:%=%.html)
 @BUILD_HTML_DOCS_TRUE at INDEX_HTML = index.html
diff --git a/man/corosync.conf.5 b/man/corosync.conf.5
index c066dc0..6abe5c4 100644
--- a/man/corosync.conf.5
+++ b/man/corosync.conf.5
@@ -296,7 +296,7 @@ recommended to alter this value without guidance from the corosync community.
 The default is 180 milliseconds.
 
 .TP
-retransmits_before_loss
+token_retransmits_before_loss_const
 This value identifies how many token retransmits should be attempted before
 forming a new configuration.  If this value is set, retransmit and hold will
 be automatically calculated from retransmits_before_loss and token.
@@ -308,7 +308,7 @@ join
 This timeout specifies in milliseconds how long to wait for join messages in
 the membership protocol.
 
-The default is 100 milliseconds.
+The default is 50 milliseconds.
 
 .TP
 send_join
@@ -325,9 +325,11 @@ The default is 0 milliseconds.
 .TP
 consensus
 This timeout specifies in milliseconds how long to wait for consensus to be
-achieved before starting a new round of membership configuration.
+achieved before starting a new round of membership configuration.  The minimum
+value for consensus must be 1.2 * token.  This value will be automatically
+calculated at 1.2 * token if the user doesn't specify a consensus value.
 
-The default is 200 milliseconds.
+The default is 1200 milliseconds.
 
 .TP
 merge
@@ -415,7 +417,7 @@ This specifies the time in milliseconds to wait before decrementing the
 problem count by 1 for a particular ring to ensure a link is not marked
 faulty for transient network failures.
 
-The default is 1000 milliseconds.
+The default is 2000 milliseconds.
 
 .TP
 rrp_problem_count_threshold
@@ -430,7 +432,7 @@ rrp_problem_count_threshold * rrp_token_expired_timeout should be atleast 50
 milliseconds less then the token timeout, or a complete reconfiguration
 may occur.
 
-The default is 20 problem counts.
+The default is 10 problem counts.
 
 .TP
 rrp_token_expired_timeout
diff --git a/man/votequorum_setvotes.3 b/man/sam_finalize.3
similarity index 67%
copy from man/votequorum_setvotes.3
copy to man/sam_finalize.3
index 4fed319..c633a70 100644
--- a/man/votequorum_setvotes.3
+++ b/man/sam_finalize.3
@@ -3,7 +3,7 @@
 .\" *
 .\" * All rights reserved.
 .\" *
-.\" * Author: Christine Caulfield <ccaulfie at redhat.com>
+.\" * Author: Jan Friesse (jfriesse at redhat.com)
 .\" *
 .\" * This software licensed under BSD license, the text of which follows:
 .\" *
@@ -15,7 +15,7 @@
 .\" * - 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
+.\" * - 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.
 .\" *
@@ -31,27 +31,33 @@
 .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 .\" * THE POSSIBILITY OF SUCH DAMAGE.
 .\" */
-.TH VOTEQUORUM_VOTES 3 2009-01-26 "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+.TH "SAM_FINALIZE" 3 "12/01/2009" "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+
 .SH NAME
-votequorum_setvotes \- Sets the number of votes for a node
+.P
+sam_finalize \- Terminate SAM service
+
 .SH SYNOPSIS
-.B #include <corosync/votequorum.h>
-.sp
-.BI "int votequorum_setexpected(votequorum_handle_t " handle ", unsigned int " nodeid ", int " votes ");"
+.P
+\fB#include <corosync/sam.h>\fR
+
+.P
+\fBcs_error_t sam_finalize (void);\fR
+
 .SH DESCRIPTION
-The
-.B votequorum_setvotes
-is used to change the number of votes that a node has. Note that it is not possible, using this function,
-to change the number of node votes such that the cluster goes inquorate.
+.P
+The \fBsam_finalize\fR function is used to terminate SAM API. Once the connection is finalized,
+the SAM may not be used again by application. Whole functionality (health checking) will be
+stopped and after application fail, recovery action will not be taken.
+
 .SH RETURN VALUE
-This call returns the CS_OK value if successful, otherwise an error is returned.
-.PP
+.P
+This call return CS_OK value if successful, otherwise and error is returned.
+
 .SH ERRORS
-The errors are undocumented.
+.TP
+CS_ERR_BAD_HANDLE
+library was not initialized by \fBsam_init(3)\fR function or was finished already.
+
 .SH "SEE ALSO"
-.BR votequorum_overview (8),
-.BR votequorum_initialize (3),
-.BR votequorum_finalize (3),
-.BR votequorum_dispatch (3),
-.BR votequorum_fd_get (3),
-.PP
+.BR sam_initialize (3)
diff --git a/man/votequorum_getinfo.3 b/man/sam_hc_callback_register.3
similarity index 52%
copy from man/votequorum_getinfo.3
copy to man/sam_hc_callback_register.3
index 99517e1..91be22d 100644
--- a/man/votequorum_getinfo.3
+++ b/man/sam_hc_callback_register.3
@@ -3,7 +3,7 @@
 .\" *
 .\" * All rights reserved.
 .\" *
-.\" * Author: Christine Caulfield <ccaulfie at redhat.com>
+.\" * Author: Jan Friesse (jfriesse at redhat.com)
 .\" *
 .\" * This software licensed under BSD license, the text of which follows:
 .\" *
@@ -15,7 +15,7 @@
 .\" * - 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
+.\" * - 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.
 .\" *
@@ -31,61 +31,59 @@
 .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 .\" * THE POSSIBILITY OF SUCH DAMAGE.
 .\" */
-.TH VOTEQUORUM_GETINFO 3 2009-01-26 "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+.TH "SAM_HC_CALLBACK_REGISTER" 3 "12/01/2009" "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+
 .SH NAME
-votequorum_getinfo \- Get information about the VoteQuorum service
+.P
+sam_hc_callback_register \- Register health check callback
+
 .SH SYNOPSIS
-.B #include <corosync/votequorum.h>
-.sp
-.BI "int votequorum_getinfo(votequorum_handle_t *" handle ", unsigned int " nodeid ", struct votequorum_info *" info ");
+.P
+\fB#include <corosync/sam.h>\fR
+
+.P
+\fBcs_error_t sam_hc_callback_register (sam_hc_callback_t cb);\fR
+
 .SH DESCRIPTION
-The
-.B votequorum_getinfo
-function is used to get information about the voteing system and its nodes.
+.P
+The \fBsam_hc_callback_register\fR function is used to register a user provided
+healthcheck callback.  After calling of this function, the SAM is switched
+from application driven healthchecking to event driven healthchecking.  In this
+mode, \fBsam_hc_send(3)\fR does not need to be executed.
+
+.P
+The parameter \fIcb\fR is callback function of type \fIsam_hc_callback_t\fR
+defined as:
 
-The votequorum_info structure is defined as follows:
-.PP
-.PP
-.IP
-.RS
-.ne 18
 .nf
-.ta 4n 20n 32n
+  typedef int (*sam_hc_callback_t)(void);
+.fi
 
-struct votequorum_info {
-	unsigned int node_id;
-	unsigned int node_votes;
-	unsigned int node_expected_votes;
-	unsigned int highest_expected;
-	unsigned int total_votes;
-	unsigned int quorum;
-	unsigned int flags;
-};
+.P
+This function will be regulargly called and must return 0 if the process is
+functioning normally, or -1 if the process is executing abnormally.  When -1 is
+returned, the SAM server execute the registered recovery policy.
 
-#define VOTEQUORUM_INFO_FLAG_DIRTY      1
-#define VOTEQUORUM_INFO_FLAG_DISALLOWED 2
-#define VOTEQUORUM_INFO_FLAG_TWONODE    4
-#define VOTEQUORUM_INFO_FLAG_QUORATE    8
+.P
+A value of NULL can be passed into this function to switch into application
+driven healthchecking.
+\fIcb\fR to NULL.
 
-.ta
-.fi
-.RE
-.IP
-.PP
-.PP
-The members starting node_ hold information specific to the requested nodeid, the other are
-general to the voting system.
 .SH RETURN VALUE
-This call returns the CS_OK value if successful, otherwise an error is returned.
-.PP
-.SH BUGS
-Callbacks are not support at the moment.
-.PP
+.P
+This call return CS_OK value if successful, otherwise and error is returned.
+
 .SH ERRORS
-The errors are undocumented.
+.TP
+CS_ERR_BAD_HANDLE
+SAM was not initialized and registered or health checking is in running state
+.TP
+CS_ERR_LIBRARY
+internal library call failed. This can occur during fork() or pipe () system
+calls and the errno variable can be read to retrieve more information.
+
 .SH "SEE ALSO"
-.BR votequorum_overview (8),
-.BR votequorum_finalize (3),
-.BR votequorum_fd_get (3),
-.BR votequorum_dispatch (3),
-.PP
+.BR sam_start (3),
+.BR sam_stop (3),
+.BR sam_hc_send (3),
+.BR sam_register (3),
diff --git a/man/votequorum_finalize.3 b/man/sam_hc_send.3
similarity index 64%
copy from man/votequorum_finalize.3
copy to man/sam_hc_send.3
index c58aa89..c8e9131 100644
--- a/man/votequorum_finalize.3
+++ b/man/sam_hc_send.3
@@ -3,7 +3,7 @@
 .\" *
 .\" * All rights reserved.
 .\" *
-.\" * Author: Christine Caulfield <ccaulfie at redhat.com>
+.\" * Author: Jan Friesse (jfriesse at redhat.com)
 .\" *
 .\" * This software licensed under BSD license, the text of which follows:
 .\" *
@@ -15,7 +15,7 @@
 .\" * - 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
+.\" * - 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.
 .\" *
@@ -31,31 +31,38 @@
 .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 .\" * THE POSSIBILITY OF SUCH DAMAGE.
 .\" */
-.TH VOTEQUORUM_FINALIZE 3 2009-01-26 "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+.TH "SAM_HC_SEND" 3 "12/01/2009" "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+
 .SH NAME
-votequorum_finalize \- Terminate a connection to the votequorum service
+.P
+sam_hc_send \- Send health check confirmation
+
 .SH SYNOPSIS
-.B #include <corosync/votequorum.h>
-.sp
-.BI "int votequorum_finalize(votequorum_handle_t " handle ");"
+.P
+\fB#include <corosync/sam.h>\fR
+
+.P
+\fBcs_error_t sam_hc_send (void);\fR
+
 .SH DESCRIPTION
-The
-.B votequorum_finalize
-function is used to close a connection to the configuration dabatase API.
-Once the connection is finalized, the handle may not be used again by applications.
-No more callbacks will be dispatched from the
-.B votequorum_dispatch function.
-.PP
+.P
+The \fBsam_hc_send\fR function is used to send healthcheck confirmation from
+the applicatoin.  This function should be called reguarly when configured for
+application driven healthchecking, otherwise recovery actoin will be taken.
+
+When using event driven healthchecking, this function should not be used.
+
 .SH RETURN VALUE
-This call returns the CS_OK value if successful, otherwise an error is returned.
-.PP
+.P
+This call return CS_OK value if successful, otherwise and error is returned.
+
 .SH ERRORS
-The errors are undocumented.
-.SH "SEE ALSO"
-.BR votequorum_overview (8),
-.BR votequorum_initialize (3),
-.BR votequorum_finalize (3),
-.BR votequorum_dispatch (3),
-.BR votequorum_fd_get (3),
+.TP
+CS_ERR_BAD_HANDLE
+health checking is not in running state (\fBsam_start(3)\fR has not been
+executed) or function is called after stop/finalization of SAM.
 
-.PP
+.SH "SEE ALSO"
+.BR sam_start (3),
+.BR sam_stop (3),
+.BR sam_hc_callback_register (3)
diff --git a/man/sam_initialize.3 b/man/sam_initialize.3
new file mode 100644
index 0000000..fc771df
--- /dev/null
+++ b/man/sam_initialize.3
@@ -0,0 +1,105 @@
+.\"/*
+.\" * Copyright (c) 2009 Red Hat, Inc.
+.\" *
+.\" * All rights reserved.
+.\" *
+.\" * Author: Jan Friesse (jfriesse at 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.
+.\" */
+.TH "SAM_INITIALIZE" 3 "12/01/2009" "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+
+.SH NAME
+.P
+sam_initialize \- Initialize health checking
+
+.SH SYNOPSIS
+.P
+\fB#include <corosync/sam.h>\fR
+
+.P
+\fBcs_error_t sam_initialize (int\fR \fItime_interval\fR\fB, sam_recovery_policy_t \fIrecovery_policy\fR);\fR
+
+.SH DESCRIPTION
+.P
+The \fBsam_initialize\fR function is used to initialize health checking of a process.
+
+.P
+Application can have only one instance of SAM. This function must be called
+before any other of SAM functions.  It is recommended to initialize before the
+process begins any process initialization.
+
+.P
+The \fItime_interval\fR parameter is a timeout in milliseconds before taking
+recovery action after having not received a healthcheck.
+
+If \fItime_interval\fR parameter is zero, there is no time limit and no
+healthcheck must be sent by the process.  In this operational mode, a process
+failure will continue to execute the recovery policy.
+
+.P
+The \fIrecovery_policy\fR is defined as type:
+
+.nf
+  typedef enum {
+  	SAM_RECOVERY_POLICY_QUIT = 1,
+  	SAM_RECOVERY_POLICY_RESTART = 2,
+  } sam_recovery_policy_t;
+.fi
+
+.P
+where
+
+.TP
+SAM_RECOVERY_POLICY_QUIT
+on failure, the process will terminate.
+.TP
+SAM_RECOVERY_POLICY_RESTART
+on failure, the process will restart.
+
+.P
+To perform event driven healthchecking, \fBsam_register(3)\fR and
+\fBsam_start(3)\fR functions must called.  Event driven healthchecking causes
+the duplicate standby process running the SAM serve rto periodically request
+healthchecks from the active process.
+
+.SH RETURN VALUE
+.P
+This call return CS_OK value if successful, otherwise and error is returned.
+
+.SH ERRORS
+.TP
+CS_ERR_BAD_HANDLE
+can happened in case of double initialization.
+.TP
+CS_ERR_INVALID_PARAM
+\fIrecovery_policy\fR has invalid value.
+
+.SH "SEE ALSO"
+.BR sam_register (3),
+.BR sam_start (3),
+.BR sam_hc_callback_register (3)
diff --git a/man/sam_overview.8 b/man/sam_overview.8
new file mode 100644
index 0000000..09e84fd
--- /dev/null
+++ b/man/sam_overview.8
@@ -0,0 +1,126 @@
+.\"/*
+.\" * Copyright (c) 2009 Red Hat, Inc.
+.\" *
+.\" * All rights reserved.
+.\" *
+.\" * Author: Jan Friesse (jfriesse at redhat.com)
+.\" * Author: Steven Dake (sdake at 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.
+.\" */
+.TH "SAM_OVERVIEW" 8 "12/01/2009" "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+
+.SH NAME
+.P
+sam_overview \- Overview of the Simple Availability Manager
+
+.SH OVERVIEW
+.P
+The SAM library provide a tool to check the health of an application.
+The main purpose of SAM is to restart a local process when it fails to respond
+to a healthcheck request in a configured time interval.
+
+.P
+During \fBsam_initialize(3)\fR, a duplicate copy of the process is created using
+the \fBfork(3)\fR system call.  This duplicate process copy contains the logic
+for executing the SAM server.  The SAM server is responsible for requesting
+healthchecks from the active process, and controlling the lifecycle of the
+active process when it fails.  If the active process fails to respond to the
+healthcheck request sent by the SAM server, it will be sent a SIGTERM signal
+to request shutdown of the application.  After a configured time interval, the
+process will be forcibly killed by being sent a SIGKILL signal.  Once the
+active process terminates, the SAM server will create a new active process.
+
+.P
+The Simple Availability Manager is meant to be used in conjunction with the 
+cpg service.  Used together, it is possible to restart a cpg process that fails
+healthchecking during operation.
+
+.P
+The main features of SAM include:
+
+.RS
+.IP \(bu 3
+A configurable recovery policy.
+.IP \(bu 3
+A configurable time interval for health check operations.
+.IP \(bu 3
+A notification via signal before recovery action is taken.
+.IP \(bu 3
+A mechanism to indicate to the application the number of times an active
+process has been created by the SAM server.
+.IP \(bu 3
+Both application driven health checking and event driven health checking.
+.RE
+
+.SH Initializing SAM
+.P
+The SAM library is initialized by \fBsam_initialize(3)\fR.
+\fBsam_initalize(3)\fR may only be called once per process.  Calling it more 
+then once has undefined results and is not recommended or tested.
+
+.SH Setting warning callback
+.P
+A \fISIGTERM\fR signal is sent to the application when a recovery action is
+planned.  The application can use the \fBsignal(3)\fR system call to monitor
+for this signal.
+
+.P
+There are no special constraints on what SAM apis may be called in a warning
+callback.  After \fItime_interval\fR expires, a SIGKILL signal is sent to the
+active process to force its termination.
+
+.SH Registering the active process
+.P
+The active process is registered with SAM by calling \fBsam_register(3)\fR.
+This function should only be called one time in a process.  After a recovery
+action is taken, the new active process will begin execution at the next line 
+of code in a user process after \fBsam_register(3)\fR.
+
+.SH Enabling event driven healthchecking
+.P
+Two types of healthchecking are available to the user.  The first model is one
+where the user application healthchecks during its normal operation.  It is
+never requested to healtcheck, and if the active process doesn't respond within
+the time interval, the process will be restarted.
+
+.P
+A more useful mechanism for healthchecking is event driven healthchecking.
+Because this model is directed by the SAM server, It isn't necessary to guess
+or add timers to the active process to signal a healthcheck operation is
+successful.  To use event driven healthchecking,
+the \fBsam_hc_callback_register(3)\fR function should be executed.
+
+.SH BUGS
+.SH "SEE ALSO"
+.BR sam_initialize (3),
+.BR sam_finalize (3),
+.BR sam_start (3),
+.BR sam_stop (3),
+.BR sam_register (3),
+.BR sam_hc_send (3),
+.BR sam_hc_callback_register (3)
diff --git a/man/votequorum_setvotes.3 b/man/sam_register.3
similarity index 51%
copy from man/votequorum_setvotes.3
copy to man/sam_register.3
index 4fed319..2af86d2 100644
--- a/man/votequorum_setvotes.3
+++ b/man/sam_register.3
@@ -3,7 +3,7 @@
 .\" *
 .\" * All rights reserved.
 .\" *
-.\" * Author: Christine Caulfield <ccaulfie at redhat.com>
+.\" * Author: Jan Friesse (jfriesse at redhat.com)
 .\" *
 .\" * This software licensed under BSD license, the text of which follows:
 .\" *
@@ -15,7 +15,7 @@
 .\" * - 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
+.\" * - 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.
 .\" *
@@ -31,27 +31,58 @@
 .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 .\" * THE POSSIBILITY OF SUCH DAMAGE.
 .\" */
-.TH VOTEQUORUM_VOTES 3 2009-01-26 "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+.TH "SAM_REGISTER" 3 "12/01/2009" "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+
 .SH NAME
-votequorum_setvotes \- Sets the number of votes for a node
+.P
+sam_rehister \- Register component for health checking
+
 .SH SYNOPSIS
-.B #include <corosync/votequorum.h>
-.sp
-.BI "int votequorum_setexpected(votequorum_handle_t " handle ", unsigned int " nodeid ", int " votes ");"
+.P
+\fB#include <corosync/sam.h>\fR
+
+.P
+\fBcs_error_t sam_register (unsigned int *\fIinstance_id\fR);\fR
+
 .SH DESCRIPTION
-The
-.B votequorum_setvotes
-is used to change the number of votes that a node has. Note that it is not possible, using this function,
-to change the number of node votes such that the cluster goes inquorate.
+.P
+The \fBsam_register\fR function is used to register a process for healthchecking.
+If recovery policy is set to \fISAM_RECOVERY_POLICY_RESTART\fR and recovery
+action will be taken, the new process instance will begin execution at the next
+code line after this function is called.
+
+.P
+This function can be called only once and SAM must be initialized by
+\fBsam_initialize(3)\fR function.
+
+.P
+The \fIinstance_id\fR argument is a pointer to a value storing the current
+iteration instance.  If this parameter is NULL, no \fIinstance_id\fR is returned.
+and then, no \fIinstance_id\fR will be returned. This value starts at 0 for the 
+first iteration instance, and increases by 1 each time a recovery restart is
+executed.  After reaching MAX_INT, the instance_id will reset to 0.
+
+.P
+The placement of this function is important because after it is called, the
+process id will change.
+
+.P
+After registration, event driven health checking is not running.
+
 .SH RETURN VALUE
-This call returns the CS_OK value if successful, otherwise an error is returned.
-.PP
+.P
+This call return CS_OK value if successful, otherwise and error is returned.
+
 .SH ERRORS
-The errors are undocumented.
+.TP
+CS_ERR_BAD_HANDLE
+health checking was not started by calling \fBsam_start(3)\fR function.
+.TP
+CS_ERR_LIBRARY
+internal library call failed. This can be one of pipe creation or fork.
+It's possible to get more information from errno.
+
 .SH "SEE ALSO"
-.BR votequorum_overview (8),
-.BR votequorum_initialize (3),
-.BR votequorum_finalize (3),
-.BR votequorum_dispatch (3),
-.BR votequorum_fd_get (3),
-.PP
+.BR sam_start (3),
+.BR sam_initialize (3),
+.BR sam_hc_callback_register (3)
diff --git a/man/votequorum_qdisk_getinfo.3 b/man/sam_start.3
similarity index 59%
copy from man/votequorum_qdisk_getinfo.3
copy to man/sam_start.3
index c3f1c53..1ed6c04 100644
--- a/man/votequorum_qdisk_getinfo.3
+++ b/man/sam_start.3
@@ -3,7 +3,7 @@
 .\" *
 .\" * All rights reserved.
 .\" *
-.\" * Author: Christine Caulfield <ccaulfie at redhat.com>
+.\" * Author: Jan Friesse (jfriesse at redhat.com)
 .\" *
 .\" * This software licensed under BSD license, the text of which follows:
 .\" *
@@ -15,7 +15,7 @@
 .\" * - 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
+.\" * - 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.
 .\" *
@@ -31,50 +31,47 @@
 .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 .\" * THE POSSIBILITY OF SUCH DAMAGE.
 .\" */
-.TH VOTEQUORUM_QDISK_GETINFO 3 2009-01-26 "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+.TH "SAM_START" 3 "12/01/2009" "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+
 .SH NAME
-votequorum_qdisk_getinfo \- Get details of the quorum device
+.P
+sam_start \- Start health checking
+
 .SH SYNOPSIS
-.B #include <corosync/votequorum.h>
-.sp
-.BI "int votequorum_qdisk_getinfo(votequorum_handle_t " handle ", struct votequorum_qdisk_info " *info ");"
+.P
+\fB#include <corosync/sam.h>\fR
+
+.P
+\fBcs_error_t sam_start (void);\fR
+
 .SH DESCRIPTION
-The
-.B votequorum_qdisk_getinfo
-Returns information about the quorum device in the following structure:
-.PP
-.PP
-.IP
-.RS
-.ne 18
-.nf
-.ta 4n 20n 32n
+.P
+The \fBsam_start\fR function is used to start health checking of application.
+After calling this function, the active process needs to send healthchecks
+within the registered time interval by calling \fBsam_hc_send(3)\fR.  If
+event driven healthchecking is configured by calling \fBsam_register(3)\fR,
+an internal thread will be created and send health check confirmations four
+times per \fItime_interval\fR.
 
-struct votequorum_qdisk_info {
-	unsigned int votes;
-	unsigned int state;
-	char name[VOTEQUORUM_MAX_QDISK_NAME_LEN];
-};
+.P
+Application must be registered by calling \fBsam_register(3)\fR before this
+function can be called.
 
-.ta
-.fi
-.RE
-.IP
-.PP
-.PP
+.P
+An application can always stop health checking by calling the \fBsam_stop(3)\fR
+function.
 
 .SH RETURN VALUE
-This call returns the CS_OK value if successful, otherwise an error is returned.
-.PP
+.P
+This call return CS_OK value if successful, otherwise and error is returned.
+
 .SH ERRORS
-The errors are undocumented.
+.TP
+CS_ERR_BAD_HANDLE
+component was not registered by calling \fBsam_register(3)\fR function.
+
 .SH "SEE ALSO"
-.BR votequorum_overview (8),
-.BR votequorum_initialize (3),
-.BR votequorum_finalize (3),
-.BR votequorum_dispatch (3),
-.BR votequorum_fd_get (3),
-.BR votequorum_qdisk_poll (3),
-.BR votequorum_qdisk_unregister (3),
-.BR votequorum_qdisk_getinfo (3),
-.PP
+.BR sam_hc_send (3),
+.BR sam_stop (3),
+.BR sam_register (3),
+.BR sam_hc_callback_register (3)
diff --git a/man/votequorum_setvotes.3 b/man/sam_stop.3
similarity index 65%
copy from man/votequorum_setvotes.3
copy to man/sam_stop.3
index 4fed319..708d079 100644
--- a/man/votequorum_setvotes.3
+++ b/man/sam_stop.3
@@ -3,7 +3,7 @@
 .\" *
 .\" * All rights reserved.
 .\" *
-.\" * Author: Christine Caulfield <ccaulfie at redhat.com>
+.\" * Author: Jan Friesse (jfriesse at redhat.com)
 .\" *
 .\" * This software licensed under BSD license, the text of which follows:
 .\" *
@@ -15,7 +15,7 @@
 .\" * - 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
+.\" * - 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.
 .\" *
@@ -31,27 +31,37 @@
 .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 .\" * THE POSSIBILITY OF SUCH DAMAGE.
 .\" */
-.TH VOTEQUORUM_VOTES 3 2009-01-26 "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+.TH "SAM_STOP" 3 "12/01/2009" "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+
 .SH NAME
-votequorum_setvotes \- Sets the number of votes for a node
+.P
+sam_stop \- Stop health checking
+
 .SH SYNOPSIS
-.B #include <corosync/votequorum.h>
-.sp
-.BI "int votequorum_setexpected(votequorum_handle_t " handle ", unsigned int " nodeid ", int " votes ");"
+.P
+\fB#include <corosync/sam.h>\fR
+
+.P
+\fBcs_error_t sam_stop (void);\fR
+
 .SH DESCRIPTION
-The
-.B votequorum_setvotes
-is used to change the number of votes that a node has. Note that it is not possible, using this function,
-to change the number of node votes such that the cluster goes inquorate.
+.P
+The \fBsam_stop\fR function is used to stop health checking of an active
+process.  After calling this function, the application no longer should send
+helathchecks.  In the case of event driven healthchecking, the healthchecking
+thread will be stopped.
+
+.P
+A process can always start health checking again by calling \fBsam_start(3)\fR function.
+
 .SH RETURN VALUE
-This call returns the CS_OK value if successful, otherwise an error is returned.
-.PP
+.P
+This call return CS_OK value if successful, otherwise and error is returned.
+
 .SH ERRORS
-The errors are undocumented.
+.TP
+CS_ERR_BAD_HANDLE
+health checking was not started by calling \fBsam_start(3)\fR function.
+
 .SH "SEE ALSO"
-.BR votequorum_overview (8),
-.BR votequorum_initialize (3),
-.BR votequorum_finalize (3),
-.BR votequorum_dispatch (3),
-.BR votequorum_fd_get (3),
-.PP
+.BR sam_start (3)
diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am
index 3400370..cc9abf1 100644
--- a/pkgconfig/Makefile.am
+++ b/pkgconfig/Makefile.am
@@ -33,7 +33,7 @@ MAINTAINERCLEANFILES	= Makefile.in
 EXTRA_DIST		= libtemplate.pc.in corosync.pc.in
 
 LIBS	= cfg confdb coroipcc coroipcs cpg evs logsys pload quorum \
-	  totem_pg votequorum
+	  totem_pg votequorum sam
 
 target_LIBS = $(LIBS:%=lib%.pc)
 
diff --git a/pkgconfig/Makefile.in b/pkgconfig/Makefile.in
index 8443d60..0c9cbb9 100644
--- a/pkgconfig/Makefile.in
+++ b/pkgconfig/Makefile.in
@@ -103,6 +103,7 @@ EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
 GROFF = @GROFF@
+INITDDIR = @INITDDIR@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -112,7 +113,7 @@ LCRSODIR = @LCRSODIR@
 LDFLAGS = @LDFLAGS@
 LIBOBJS = @LIBOBJS@
 LIBS = cfg confdb coroipcc coroipcs cpg evs logsys pload quorum \
-	  totem_pg votequorum
+	  totem_pg votequorum sam
 
 LINT_FLAGS = @LINT_FLAGS@
 LN_S = @LN_S@
diff --git a/services/Makefile.in b/services/Makefile.in
index 96fc586..fd31582 100644
--- a/services/Makefile.in
+++ b/services/Makefile.in
@@ -103,6 +103,7 @@ EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
 GROFF = @GROFF@
+INITDDIR = @INITDDIR@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
diff --git a/services/confdb.c b/services/confdb.c
index c7c7808..64675f0 100644
--- a/services/confdb.c
+++ b/services/confdb.c
@@ -79,14 +79,20 @@ static void message_handler_req_lib_confdb_object_find_destroy (void *conn,
 								const void *message);
 
 static void message_handler_req_lib_confdb_key_create (void *conn,
-						       const void *message);
+								const void *message);
+static void message_handler_req_lib_confdb_key_create_typed (void *conn,
+								const void *message);
 static void message_handler_req_lib_confdb_key_get (void *conn,
+								const void *message);
+static void message_handler_req_lib_confdb_key_get_typed (void *conn,
 						    const void *message);
 static void message_handler_req_lib_confdb_key_replace (void *conn,
 							const void *message);
 static void message_handler_req_lib_confdb_key_delete (void *conn,
 						       const void *message);
 static void message_handler_req_lib_confdb_key_iter (void *conn,
+								const void *message);
+static void message_handler_req_lib_confdb_key_iter_typed (void *conn,
 						     const void *message);
 
 static void message_handler_req_lib_confdb_key_increment (void *conn,
@@ -204,6 +210,18 @@ static struct corosync_lib_handler confdb_lib_engine[] =
 		.lib_handler_fn				= message_handler_req_lib_confdb_key_decrement,
 		.flow_control				= CS_LIB_FLOW_CONTROL_NOT_REQUIRED
 	},
+	{ /* 17 */
+		.lib_handler_fn				= message_handler_req_lib_confdb_key_create_typed,
+		.flow_control				= CS_LIB_FLOW_CONTROL_NOT_REQUIRED
+	},
+	{ /* 18 */
+		.lib_handler_fn				= message_handler_req_lib_confdb_key_get_typed,
+		.flow_control				= CS_LIB_FLOW_CONTROL_NOT_REQUIRED
+	},
+	{ /* 19 */
+		.lib_handler_fn				= message_handler_req_lib_confdb_key_iter_typed,
+		.flow_control				= CS_LIB_FLOW_CONTROL_NOT_REQUIRED
+	},
 };
 
 
@@ -373,6 +391,27 @@ static void message_handler_req_lib_confdb_key_create (void *conn,
 	api->ipc_response_send(conn, &res, sizeof(res));
 }
 
+static void message_handler_req_lib_confdb_key_create_typed (void *conn,
+						       const void *message)
+{
+	const struct req_lib_confdb_key_create_typed *req_lib_confdb_key_create
+	  = message;
+	coroipc_response_header_t res;
+	int ret = CS_OK;
+
+	if (api->object_key_create_typed(req_lib_confdb_key_create->object_handle,
+					    (char*)req_lib_confdb_key_create->key_name.value,
+					    req_lib_confdb_key_create->value.value,
+					    req_lib_confdb_key_create->value.length,
+					    req_lib_confdb_key_create->type))
+		ret = CS_ERR_ACCESS;
+
+	res.size = sizeof(res);
+	res.id = MESSAGE_RES_CONFDB_KEY_CREATE;
+	res.error = ret;
+	api->ipc_response_send(conn, &res, sizeof(res));
+}
+
 static void message_handler_req_lib_confdb_key_get (void *conn,
 						    const void *message)
 {
@@ -399,6 +438,35 @@ static void message_handler_req_lib_confdb_key_get (void *conn,
 	api->ipc_response_send(conn, &res_lib_confdb_key_get, sizeof(res_lib_confdb_key_get));
 }
 
+static void message_handler_req_lib_confdb_key_get_typed (void *conn,
+						    const void *message)
+{
+	const struct req_lib_confdb_key_get *req_lib_confdb_key_get = message;
+	struct res_lib_confdb_key_get_typed res_lib_confdb_key_get;
+	size_t value_len;
+	void *value;
+	int ret = CS_OK;
+	objdb_value_types_t type;
+	char * key_name = (char*)req_lib_confdb_key_get->key_name.value;
+	key_name[req_lib_confdb_key_get->key_name.length] = '\0';
+
+	if (api->object_key_get_typed(req_lib_confdb_key_get->parent_object_handle,
+					 key_name,
+					 &value,
+					 &value_len, &type))
+		ret = CS_ERR_ACCESS;
+	else {
+		memcpy(res_lib_confdb_key_get.value.value, value, value_len);
+		res_lib_confdb_key_get.value.length = value_len;
+		res_lib_confdb_key_get.type = type;
+
+	}
+	res_lib_confdb_key_get.header.size = sizeof(res_lib_confdb_key_get);
+	res_lib_confdb_key_get.header.id = MESSAGE_RES_CONFDB_KEY_GET_TYPED;
+	res_lib_confdb_key_get.header.error = ret;
+	api->ipc_response_send(conn, &res_lib_confdb_key_get, sizeof(res_lib_confdb_key_get));
+}
+
 static void message_handler_req_lib_confdb_key_increment (void *conn,
 							  const void *message)
 {
@@ -529,6 +597,45 @@ static void message_handler_req_lib_confdb_key_iter (void *conn,
 	api->ipc_response_send(conn, &res_lib_confdb_key_iter, sizeof(res_lib_confdb_key_iter));
 }
 
+static void message_handler_req_lib_confdb_key_iter_typed (void *conn,
+						     const void *message)
+{
+	const struct req_lib_confdb_key_iter *req_lib_confdb_key_iter = message;
+	struct res_lib_confdb_key_iter_typed res_lib_confdb_key_iter;
+	void *key_name;
+	size_t key_name_len;
+	void *value;
+	size_t value_len;
+	int ret = CS_OK;
+	objdb_value_types_t my_type;
+
+	if (api->object_key_iter_from(req_lib_confdb_key_iter->parent_object_handle,
+					       req_lib_confdb_key_iter->next_entry,
+					       &key_name,
+					       &key_name_len,
+					       &value,
+					       &value_len))
+		ret = CS_ERR_ACCESS;
+	else {
+		memcpy(res_lib_confdb_key_iter.key_name.value, key_name, key_name_len);
+		memcpy(res_lib_confdb_key_iter.value.value, value, value_len);
+		res_lib_confdb_key_iter.key_name.length = key_name_len;
+		res_lib_confdb_key_iter.key_name.value[key_name_len] = '\0';
+		res_lib_confdb_key_iter.value.length = value_len;
+		api->object_key_get_typed(req_lib_confdb_key_iter->parent_object_handle,
+								(const char*)res_lib_confdb_key_iter.key_name.value,
+								&value,
+								&value_len,
+								&my_type);
+		res_lib_confdb_key_iter.type = my_type;
+	}
+	res_lib_confdb_key_iter.header.size = sizeof(res_lib_confdb_key_iter);
+	res_lib_confdb_key_iter.header.id = MESSAGE_RES_CONFDB_KEY_ITER_TYPED;
+	res_lib_confdb_key_iter.header.error = ret;
+
+	api->ipc_response_send(conn, &res_lib_confdb_key_iter, sizeof(res_lib_confdb_key_iter));
+}
+
 static void message_handler_req_lib_confdb_object_iter (void *conn,
 							const void *message)
 {
diff --git a/services/cpg.c b/services/cpg.c
index b15c253..59d59b2 100644
--- a/services/cpg.c
+++ b/services/cpg.c
@@ -830,6 +830,7 @@ static void message_handler_req_exec_cpg_downlist (
 	                                            MESSAGE_RES_CPG_CONFCHG_CALLBACK);
 				list_del (&pi->list);
 				free (pi);
+				break;
 			}
 		}
 	}
diff --git a/test/Makefile.am b/test/Makefile.am
index 3789385..2a88908 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -36,7 +36,7 @@ INCLUDES       		= -I$(top_builddir)/include -I$(top_srcdir)/include
 noinst_PROGRAMS		= testevs evsbench evsverify cpgverify testcpg testcpg2 cpgbench testconfdb	\
 			logsysbench logsysrec testquorum testvotequorum1 testvotequorum2	\
 			logsys_s logsys_t1 logsys_t2 testcpgzc cpgbenchzc testzcgc \
-			stress_cpgzc stress_cpgfdget stress_cpgcontext cpgbound
+			stress_cpgzc stress_cpgfdget stress_cpgcontext cpgbound testsam
 
 testevs_LDADD		= -levs -lcoroipcc
 testevs_LDFLAGS		= -L../lib
@@ -85,6 +85,8 @@ logsys_t1_LDADD		= -llogsys
 logsys_t1_LDFLAGS	= -L../exec
 logsys_t2_LDADD		= -llogsys
 logsys_t2_LDFLAGS	= -L../exec
+testsam_LDADD		= -lsam
+testsam_LDFLAGS		= -L../lib
 
 lint:
 	-splint $(LINT_FLAGS) $(CFLAGS) *.c
diff --git a/test/Makefile.in b/test/Makefile.in
index 684592e..027a80b 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -74,7 +74,7 @@ noinst_PROGRAMS = testevs$(EXEEXT) evsbench$(EXEEXT) \
 	logsys_s$(EXEEXT) logsys_t1$(EXEEXT) logsys_t2$(EXEEXT) \
 	testcpgzc$(EXEEXT) cpgbenchzc$(EXEEXT) testzcgc$(EXEEXT) \
 	stress_cpgzc$(EXEEXT) stress_cpgfdget$(EXEEXT) \
-	stress_cpgcontext$(EXEEXT) cpgbound$(EXEEXT)
+	stress_cpgcontext$(EXEEXT) cpgbound$(EXEEXT) testsam$(EXEEXT)
 subdir = test
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -188,6 +188,11 @@ testquorum_OBJECTS = testquorum.$(OBJEXT)
 testquorum_DEPENDENCIES =
 testquorum_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(testquorum_LDFLAGS) \
 	$(LDFLAGS) -o $@
+testsam_SOURCES = testsam.c
+testsam_OBJECTS = testsam.$(OBJEXT)
+testsam_DEPENDENCIES =
+testsam_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(testsam_LDFLAGS) \
+	$(LDFLAGS) -o $@
 testvotequorum1_SOURCES = testvotequorum1.c
 testvotequorum1_OBJECTS = testvotequorum1.$(OBJEXT)
 testvotequorum1_DEPENDENCIES =
@@ -215,13 +220,13 @@ SOURCES = cpgbench.c cpgbenchzc.c cpgbound.c cpgverify.c evsbench.c \
 	evsverify.c $(logsys_s_SOURCES) logsys_t1.c logsys_t2.c \
 	logsysbench.c logsysrec.c stress_cpgcontext.c \
 	stress_cpgfdget.c stress_cpgzc.c testconfdb.c testcpg.c \
-	testcpg2.c testcpgzc.c testevs.c testquorum.c \
+	testcpg2.c testcpgzc.c testevs.c testquorum.c testsam.c \
 	testvotequorum1.c testvotequorum2.c testzcgc.c
 DIST_SOURCES = cpgbench.c cpgbenchzc.c cpgbound.c cpgverify.c \
 	evsbench.c evsverify.c $(logsys_s_SOURCES) logsys_t1.c \
 	logsys_t2.c logsysbench.c logsysrec.c stress_cpgcontext.c \
 	stress_cpgfdget.c stress_cpgzc.c testconfdb.c testcpg.c \
-	testcpg2.c testcpgzc.c testevs.c testquorum.c \
+	testcpg2.c testcpgzc.c testevs.c testquorum.c testsam.c \
 	testvotequorum1.c testvotequorum2.c testzcgc.c
 ETAGS = etags
 CTAGS = ctags
@@ -252,6 +257,7 @@ EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
 GROFF = @GROFF@
+INITDDIR = @INITDDIR@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -395,6 +401,8 @@ logsys_t1_LDADD = -llogsys
 logsys_t1_LDFLAGS = -L../exec
 logsys_t2_LDADD = -llogsys
 logsys_t2_LDFLAGS = -L../exec
+testsam_LDADD = -lsam
+testsam_LDFLAGS = -L../lib
 all: all-am
 
 .SUFFIXES:
@@ -492,6 +500,9 @@ testevs$(EXEEXT): $(testevs_OBJECTS) $(testevs_DEPENDENCIES)
 testquorum$(EXEEXT): $(testquorum_OBJECTS) $(testquorum_DEPENDENCIES) 
 	@rm -f testquorum$(EXEEXT)
 	$(testquorum_LINK) $(testquorum_OBJECTS) $(testquorum_LDADD) $(LIBS)
+testsam$(EXEEXT): $(testsam_OBJECTS) $(testsam_DEPENDENCIES) 
+	@rm -f testsam$(EXEEXT)
+	$(testsam_LINK) $(testsam_OBJECTS) $(testsam_LDADD) $(LIBS)
 testvotequorum1$(EXEEXT): $(testvotequorum1_OBJECTS) $(testvotequorum1_DEPENDENCIES) 
 	@rm -f testvotequorum1$(EXEEXT)
 	$(testvotequorum1_LINK) $(testvotequorum1_OBJECTS) $(testvotequorum1_LDADD) $(LIBS)
@@ -530,6 +541,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/testcpgzc.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/testevs.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/testquorum.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/testsam.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/testvotequorum1.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/testvotequorum2.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/testzcgc.Po at am__quote@
diff --git a/test/testsam.c b/test/testsam.c
new file mode 100644
index 0000000..ae9a4cf
--- /dev/null
+++ b/test/testsam.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2009 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Jan Friesse (jfriesse at 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 test of SAM API
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <corosync/corotypes.h>
+#include <corosync/sam.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+static int test2_sig_delivered = 0;
+static int test4_hc_cb_count = 0;
+
+/*
+ * First test will just register SAM, with policy restart. First instance will
+ * sleep one second, send hc and sleep another 3 seconds. This should force restart.
+ * Second instance will sleep one second, send hc, stop hc and sleep 3 seconds.
+ * Then start hc again and sleep 3 seconds. This should force restart again.
+ * Last instance just calls initialize again. This should end with error.
+ * Then call start, followed by stop and start again. Finally, we will call finalize
+ * twice. One should succeed, second should fail. After this, we will call every function
+ * (none should succeed).
+ */
+static int test1 (void)
+{
+	cs_error_t error;
+	unsigned int instance_id;
+	int i;
+
+	printf ("%s: initialize\n", __FUNCTION__);
+	error = sam_initialize (2000, SAM_RECOVERY_POLICY_RESTART);
+	if (error != CS_OK) {
+		fprintf (stderr, "Can't initialize SAM API. Error %d\n", error);
+		return 1;
+	}
+	printf ("%s: register\n", __FUNCTION__);
+	error = sam_register (&instance_id);
+	if (error != CS_OK) {
+		fprintf (stderr, "Can't register. Error %d\n", error);
+		return 1;
+	}
+
+	if (instance_id == 1 || instance_id == 2) {
+		printf ("%s iid %d: start\n", __FUNCTION__, instance_id);
+		error = sam_start ();
+		if (error != CS_OK) {
+			fprintf (stderr, "Can't start hc. Error %d\n", error);
+			return 1;
+		}
+
+		for (i = 0; i < 10; i++) {
+			printf ("%s iid %d: sleep 1\n", __FUNCTION__, instance_id);
+			sleep (1);
+
+			printf ("%s iid %d: hc send\n", __FUNCTION__, instance_id);
+			error = sam_hc_send ();
+			if (error != CS_OK) {
+				fprintf (stderr, "Can't send hc. Error %d\n", error);
+				return 1;
+			}
+		}
+
+		if (instance_id == 2) {
+			printf ("%s iid %d: stop\n", __FUNCTION__, instance_id);
+			error = sam_stop ();
+
+			if (error != CS_OK) {
+				fprintf (stderr, "Can't send hc. Error %d\n", error);
+				return 1;
+			}
+		}
+
+		printf ("%s iid %d: sleep 3\n", __FUNCTION__, instance_id);
+		sleep (3);
+
+		printf ("%s iid %d: start\n", __FUNCTION__, instance_id);
+		error = sam_start ();
+		if (error != CS_OK) {
+			fprintf (stderr, "Can't start hc. Error %d\n", error);
+			return 1;
+		}
+
+		printf ("%s iid %d: sleep 3\n", __FUNCTION__, instance_id);
+		sleep (3);
+		return 0;
+	}
+
+	if (instance_id == 3) {
+		error = sam_initialize (2000, SAM_RECOVERY_POLICY_RESTART);
+		if (error == CS_OK) {
+			fprintf (stderr, "Can initialize SAM API after initialization");
+			return 1;
+		}
+
+		error = sam_start ();
+		if (error != CS_OK) {
+			fprintf (stderr, "Can't start hc. Error %d\n", error);
+			return 1;
+		}
+		error = sam_stop ();
+		if (error != CS_OK) {
+			fprintf (stderr, "Can't stop hc. Error %d\n", error);
+			return 1;
+		}
+		error = sam_finalize ();
+		if (error != CS_OK) {
+			fprintf (stderr, "Can't finalize sam. Error %d\n", error);
+			return 1;
+		}
+		error = sam_finalize ();
+		if (error == CS_OK) {
+			fprintf (stderr, "Can finalize sam after finalization!\n");
+			return 1;
+		}
+
+		if (sam_initialize (2, SAM_RECOVERY_POLICY_RESTART) == CS_OK ||
+			sam_start () == CS_OK || sam_stop () == CS_OK ||
+			sam_register (NULL) == CS_OK || sam_hc_send () == CS_OK ||
+			sam_hc_callback_register (NULL) == CS_OK) {
+
+			fprintf (stderr, "Can call one of function after finalization!\n");
+
+			return 1;
+		}
+
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static void test2_signal (int sig) {
+	printf ("%s\n", __FUNCTION__);
+
+	test2_sig_delivered = 1;
+}
+
+/*
+ * This tests recovery policy quit and callback.
+ */
+static int test2 (void) {
+	cs_error_t error;
+	unsigned int instance_id;
+
+	printf ("%s: initialize\n", __FUNCTION__);
+	error = sam_initialize (2000, SAM_RECOVERY_POLICY_QUIT);
+	if (error != CS_OK) {
+		fprintf (stderr, "Can't initialize SAM API. Error %d\n", error);
+		return 1;
+	}
+	printf ("%s: register\n", __FUNCTION__);
+	error = sam_register (&instance_id);
+	if (error != CS_OK) {
+		fprintf (stderr, "Can't register. Error %d\n", error);
+		return 1;
+	}
+
+	if (instance_id == 1) {
+		signal (SIGTERM, test2_signal);
+
+		printf ("%s iid %d: start\n", __FUNCTION__, instance_id);
+		error = sam_start ();
+		if (error != CS_OK) {
+			fprintf (stderr, "Can't start hc. Error %d\n", error);
+			return 1;
+		}
+
+		printf ("%s iid %d: sleep 1\n", __FUNCTION__, instance_id);
+		sleep (1);
+
+		printf ("%s iid %d: hc send\n", __FUNCTION__, instance_id);
+		error = sam_hc_send ();
+		if (error != CS_OK) {
+			fprintf (stderr, "Can't send hc. Error %d\n", error);
+			return 1;
+		}
+
+
+		printf ("%s iid %d: wait for delivery of signal\n", __FUNCTION__, instance_id);
+		while (!test2_sig_delivered) {
+			sleep (1);
+		}
+
+		printf ("%s iid %d: wait for real kill\n", __FUNCTION__, instance_id);
+
+		sleep (3);
+	}
+
+	return 1;
+
+}
+
+/*
+ * Smoke test. Better to turn off coredump ;) This has no time limit, just restart process
+ * when it dies.
+ */
+static int test3 (void) {
+	cs_error_t error;
+	unsigned int instance_id;
+	int tmp1, tmp2, tmp3;
+
+	printf ("%s: initialize\n", __FUNCTION__);
+	error = sam_initialize (0, SAM_RECOVERY_POLICY_RESTART);
+	if (error != CS_OK) {
+		fprintf (stderr, "Can't initialize SAM API. Error %d\n", error);
+		return 1;
+	}
+	printf ("%s: register\n", __FUNCTION__);
+	error = sam_register (&instance_id);
+	if (error != CS_OK) {
+		fprintf (stderr, "Can't register. Error %d\n", error);
+		return 1;
+	}
+
+	if (instance_id < 100) {
+		printf ("%s iid %d: start\n", __FUNCTION__, instance_id);
+		error = sam_start ();
+		if (error != CS_OK) {
+			fprintf (stderr, "Can't start hc. Error %d\n", error);
+			return 1;
+		}
+
+		printf ("%s iid %d: divide by zero\n", __FUNCTION__, instance_id);
+		tmp2 = rand ();
+		tmp3 = 0;
+		tmp1 = tmp2 / tmp3;
+
+		return 1;
+	}
+
+	return 0;
+
+}
+
+static int test4_hc_cb (void)
+{
+	printf ("%s %d\n", __FUNCTION__, ++test4_hc_cb_count);
+
+	if (test4_hc_cb_count > 10)
+		return 1;
+
+	return 0;
+}
+/*
+ * Test event driven healtchecking.
+ */
+static int test4 (void)
+{
+	cs_error_t error;
+	unsigned int instance_id;
+
+	printf ("%s: initialize\n", __FUNCTION__);
+	error = sam_initialize (100, SAM_RECOVERY_POLICY_RESTART);
+	if (error != CS_OK) {
+		fprintf (stderr, "Can't initialize SAM API. Error %d\n", error);
+		return 1;
+	}
+	printf ("%s: register\n", __FUNCTION__);
+	error = sam_register (&instance_id);
+	if (error != CS_OK) {
+		fprintf (stderr, "Can't register. Error %d\n", error);
+		return 1;
+	}
+
+	if (instance_id == 1) {
+		printf ("%s iid %d: hc callback register\n", __FUNCTION__, instance_id);
+		error = sam_hc_callback_register (test4_hc_cb);
+		if (error != CS_OK) {
+			fprintf (stderr, "Can't register hc cb. Error %d\n", error);
+			return 1;
+		}
+
+
+		printf ("%s iid %d: start\n", __FUNCTION__, instance_id);
+		error = sam_start ();
+		if (error != CS_OK) {
+			fprintf (stderr, "Can't start hc. Error %d\n", error);
+			return 1;
+		}
+
+		sleep (2);
+
+		printf ("%s iid %d: Failed. Wasn't killed.\n", __FUNCTION__, instance_id);
+		return 1;
+	}
+
+	if (instance_id == 2) {
+		return 0;
+	}
+
+	return 1;
+}
+
+int main(int argc, char *argv[])
+{
+	pid_t pid;
+	int err;
+	int stat;
+	int all_passed = 1;
+
+	pid = fork ();
+
+	if (pid == -1) {
+		fprintf (stderr, "Can't fork\n");
+		return 1;
+	}
+
+	if (pid == 0) {
+		err = test1 ();
+
+		fprintf (stderr, "test1 %s\n", (err == 0 ? "passed" : "failed"));
+		if (err != 0)
+			all_passed = 0;
+
+		return err;
+	}
+
+	waitpid (pid, NULL, 0);
+
+
+	pid = fork ();
+
+	if (pid == -1) {
+		fprintf (stderr, "Can't fork\n");
+		return 1;
+	}
+
+	if (pid == 0) {
+		err = test2 ();
+
+		return err;
+	}
+
+	waitpid (pid, &stat, 0);
+
+	fprintf (stderr, "test2 %s\n", (WEXITSTATUS (stat) == 0 ? "passed" : "failed"));
+	if (WEXITSTATUS (stat) != 0)
+		all_passed = 0;
+
+	pid = fork ();
+
+	if (pid == -1) {
+		fprintf (stderr, "Can't fork\n");
+		return 1;
+	}
+
+	if (pid == 0) {
+		err = test3 ();
+
+		fprintf (stderr, "test3 %s\n", (err == 0 ? "passed" : "failed"));
+		if (err != 0)
+			all_passed = 0;
+		return err;
+	}
+
+	waitpid (pid, NULL, 0);
+
+	pid = fork ();
+
+	if (pid == -1) {
+		fprintf (stderr, "Can't fork\n");
+		return 1;
+	}
+
+	if (pid == 0) {
+		err = test4 ();
+
+		fprintf (stderr, "test4 %s\n", (err == 0 ? "passed" : "failed"));
+		if (err != 0)
+			all_passed = 0;
+		return err;
+	}
+
+	waitpid (pid, NULL, 0);
+
+	if (all_passed)
+		fprintf (stderr, "All tests passed\n");
+
+	return (all_passed ? 0 : 1);
+}
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 163fcff..1118345 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -42,7 +42,8 @@ corosync_objctl_LDADD	= -lconfdb ../lcr/liblcr.a -lcoroipcc
 corosync_objctl_LDFLAGS	= -L../lib
 corosync_cfgtool_LDADD	= -lcfg -lcoroipcc
 corosync_cfgtool_LDFLAGS= -L../lib
-corosync_cpgtool_LDADD	= ../lib/libcfg.a ../lib/libcpg.a ../lib/libcoroipcc.a
+corosync_cpgtool_LDADD	= -lcfg -lcpg -lcoroipcc
+corosync_cpgtool_LDFLAGS= -L../lib
 corosync_quorumtool_LDADD = -lconfdb -lcfg -lquorum \
 			    -lvotequorum -lcoroipcc ../lcr/liblcr.a
 corosync_quorumtool_LDFLAGS = -L../lib
diff --git a/tools/Makefile.in b/tools/Makefile.in
index 4c56d5a..69415ee 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -89,8 +89,9 @@ corosync_cfgtool_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
 	$(corosync_cfgtool_LDFLAGS) $(LDFLAGS) -o $@
 corosync_cpgtool_SOURCES = corosync-cpgtool.c
 corosync_cpgtool_OBJECTS = corosync-cpgtool.$(OBJEXT)
-corosync_cpgtool_DEPENDENCIES = ../lib/libcfg.a ../lib/libcpg.a \
-	../lib/libcoroipcc.a
+corosync_cpgtool_DEPENDENCIES =
+corosync_cpgtool_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(corosync_cpgtool_LDFLAGS) $(LDFLAGS) -o $@
 corosync_fplay_SOURCES = corosync-fplay.c
 corosync_fplay_OBJECTS = corosync-fplay.$(OBJEXT)
 corosync_fplay_LDADD = $(LDADD)
@@ -155,6 +156,7 @@ EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
 GROFF = @GROFF@
+INITDDIR = @INITDDIR@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -257,7 +259,8 @@ corosync_objctl_LDADD = -lconfdb ../lcr/liblcr.a -lcoroipcc
 corosync_objctl_LDFLAGS = -L../lib
 corosync_cfgtool_LDADD = -lcfg -lcoroipcc
 corosync_cfgtool_LDFLAGS = -L../lib
-corosync_cpgtool_LDADD = ../lib/libcfg.a ../lib/libcpg.a ../lib/libcoroipcc.a
+corosync_cpgtool_LDADD = -lcfg -lcpg -lcoroipcc
+corosync_cpgtool_LDFLAGS = -L../lib
 corosync_quorumtool_LDADD = -lconfdb -lcfg -lquorum \
 			    -lvotequorum -lcoroipcc ../lcr/liblcr.a
 
@@ -338,7 +341,7 @@ corosync-cfgtool$(EXEEXT): $(corosync_cfgtool_OBJECTS) $(corosync_cfgtool_DEPEND
 	$(corosync_cfgtool_LINK) $(corosync_cfgtool_OBJECTS) $(corosync_cfgtool_LDADD) $(LIBS)
 corosync-cpgtool$(EXEEXT): $(corosync_cpgtool_OBJECTS) $(corosync_cpgtool_DEPENDENCIES) 
 	@rm -f corosync-cpgtool$(EXEEXT)
-	$(LINK) $(corosync_cpgtool_OBJECTS) $(corosync_cpgtool_LDADD) $(LIBS)
+	$(corosync_cpgtool_LINK) $(corosync_cpgtool_OBJECTS) $(corosync_cpgtool_LDADD) $(LIBS)
 corosync-fplay$(EXEEXT): $(corosync_fplay_OBJECTS) $(corosync_fplay_DEPENDENCIES) 
 	@rm -f corosync-fplay$(EXEEXT)
 	$(LINK) $(corosync_fplay_OBJECTS) $(corosync_fplay_LDADD) $(LIBS)
diff --git a/tools/corosync-objctl.c b/tools/corosync-objctl.c
index 88098f3..8e2d754 100644
--- a/tools/corosync-objctl.c
+++ b/tools/corosync-objctl.c
@@ -51,6 +51,7 @@
 #define SEPERATOR_STR "."
 #define OBJ_NAME_SIZE 512
 
+
 typedef enum {
 	ACTION_READ,
 	ACTION_WRITE,
@@ -102,6 +103,43 @@ static confdb_callbacks_t callbacks = {
 static int debug = 0;
 static int action;
 
+static void print_key (char *key_name, void *value, size_t value_len, confdb_value_types_t type)
+{
+	switch (type) {
+		case CONFDB_VALUETYPE_INT16:
+			printf ("%s=%hd\n", key_name,
+					  *(int16_t*)value);
+			break;
+		case CONFDB_VALUETYPE_UINT16:
+			printf ("%s=%hu\n", key_name,
+					  *(uint16_t*)value);
+			break;
+		case CONFDB_VALUETYPE_INT32:
+			printf ("%s=%d\n", key_name,
+					  *(int32_t*)value);
+			break;
+		case CONFDB_VALUETYPE_UINT32:
+			printf ("%s=%u\n", key_name,
+					  *(uint32_t*)value);
+			break;
+		case CONFDB_VALUETYPE_INT64:
+			printf ("%s=%lld\n", key_name,
+					  *(int64_t*)value);
+			break;
+		case CONFDB_VALUETYPE_UINT64:
+			printf ("%s=%llu\n", key_name,
+					  *(uint64_t*)value);
+			break;
+		case CONFDB_VALUETYPE_STRING:
+			printf ("%s=%s\n", key_name, (char*)value);
+			break;
+		default:
+		case CONFDB_VALUETYPE_ANY:
+			printf ("%s=**binary**(%d)\n", key_name, type);
+			break;
+	}
+}
+
 /* Recursively dump the object tree */
 static void print_config_tree(confdb_handle_t handle, hdb_handle_t parent_object_handle, char * parent_name)
 {
@@ -109,11 +147,11 @@ static void print_config_tree(confdb_handle_t handle, hdb_handle_t parent_object
 	char object_name[OBJ_NAME_SIZE];
 	size_t object_name_len;
 	char key_name[OBJ_NAME_SIZE];
-	size_t key_name_len;
 	char key_value[OBJ_NAME_SIZE];
 	size_t key_value_len;
 	cs_error_t res;
 	int children_printed;
+	confdb_value_types_t type;
 
 	/* Show the keys */
 	res = confdb_key_iter_start(handle, parent_object_handle);
@@ -123,18 +161,17 @@ static void print_config_tree(confdb_handle_t handle, hdb_handle_t parent_object
 	}
 	children_printed = 0;
 
-	while ( (res = confdb_key_iter(handle,
+	while ( (res = confdb_key_iter_typed(handle,
 								   parent_object_handle,
 								   key_name,
-								   &key_name_len,
 								   key_value,
-								   &key_value_len)) == CS_OK) {
-		key_name[key_name_len] = '\0';
+								   &key_value_len,
+								   &type)) == CS_OK) {
 		key_value[key_value_len] = '\0';
 		if (parent_name != NULL)
-			printf("%s%c%s=%s\n", parent_name, SEPERATOR,key_name, key_value);
-		else
-			printf("%s=%s\n", key_name, key_value);
+			printf("%s%c", parent_name, SEPERATOR);
+
+		print_key(key_name, key_value, key_value_len, type);
 
 		children_printed++;
 	}
@@ -404,6 +441,7 @@ static void write_key(confdb_handle_t handle, char * path_pt)
 	char old_key_value[OBJ_NAME_SIZE];
 	size_t old_key_value_len;
 	cs_error_t res;
+	confdb_value_types_t type;
 
 	/* find the parent object */
 	get_parent_name(path_pt, parent_name);
@@ -425,12 +463,11 @@ static void write_key(confdb_handle_t handle, char * path_pt)
 	}
 
 	/* get the current key */
-	res = confdb_key_get (handle,
+	res = confdb_key_get_typed (handle,
 						  obj_handle,
 						  key_name,
-						  strlen(key_name),
 						  old_key_value,
-						  &old_key_value_len);
+						  &old_key_value_len, &type);
 
 	if (res == CS_OK) {
 		/* replace the current value */
@@ -447,12 +484,12 @@ static void write_key(confdb_handle_t handle, char * path_pt)
 			fprintf(stderr, "Failed to replace the key %s=%s. Error %d\n", key_name, key_value, res);
 	} else {
 		/* not there, create a new key */
-		res = confdb_key_create (handle,
+		res = confdb_key_create_typed (handle,
 								 obj_handle,
 								 key_name,
-								 strlen(key_name),
 								 key_value,
-								 strlen(key_value));
+								 strlen(key_value),
+								 CONFDB_VALUETYPE_STRING);
 		if (res != CS_OK)
 			fprintf(stderr, "Failed to create the key %s=%s. Error %d\n", key_name, key_value, res);
 	}
diff --git a/tools/corosync-quorumtool.c b/tools/corosync-quorumtool.c
index a1ee3ac..47a5686 100644
--- a/tools/corosync-quorumtool.c
+++ b/tools/corosync-quorumtool.c
@@ -113,6 +113,9 @@ static const char *get_quorum_type(void)
         if (result != CS_OK)
 		goto out;
 
+	if (namelen >= sizeof(buf)) {
+		namelen = sizeof(buf) - 1;
+	}
 	buf[namelen] = '\0';
 
 	/* If strdup returns NULL then we just assume no quorum provider ?? */
@@ -326,23 +329,24 @@ static void show_status(void)
 	return;
 }
 
-static void show_nodes(nodeid_format_t nodeid_format, name_format_t name_format)
+static int show_nodes(nodeid_format_t nodeid_format, name_format_t name_format)
 {
-	quorum_handle_t q_handle;
-	votequorum_handle_t v_handle;
-	corosync_cfg_handle_t c_handle;
+	quorum_handle_t q_handle = 0;
+	votequorum_handle_t v_handle = 0;
+	corosync_cfg_handle_t c_handle = 0;
 	corosync_cfg_callbacks_t c_callbacks;
 	int i;
 	int using_vq = 0;
 	quorum_callbacks_t q_callbacks;
 	votequorum_callbacks_t v_callbacks;
 	int err;
+	int result = EXIT_FAILURE;
 
 	q_callbacks.quorum_notify_fn = quorum_notification_fn;
 	err=quorum_initialize(&q_handle, &q_callbacks);
 	if (err != CS_OK) {
 		fprintf(stderr, "Cannot connect to quorum service, is it loaded?\n");
-		return;
+		return result;
 	}
 
 	v_callbacks.votequorum_notify_fn = NULL;
@@ -352,6 +356,7 @@ static void show_nodes(nodeid_format_t nodeid_format, name_format_t name_format)
 	if (using_vq) {
 		if ( (err=votequorum_initialize(&v_handle, &v_callbacks)) != CS_OK) {
 			fprintf(stderr, "votequorum_initialize FAILED: %d, this is probably a configuration error\n", err);
+			v_handle = 0;
 			goto err_exit;
 		}
 	}
@@ -359,7 +364,7 @@ static void show_nodes(nodeid_format_t nodeid_format, name_format_t name_format)
 	err = quorum_trackstart(q_handle, CS_TRACK_CURRENT);
 	if (err != CS_OK) {
 		fprintf(stderr, "quorum_trackstart FAILED: %d\n", err);
-		return;
+		goto err_exit;
 	}
 
 	g_called = 0;
@@ -367,10 +372,12 @@ static void show_nodes(nodeid_format_t nodeid_format, name_format_t name_format)
 		quorum_dispatch(q_handle, CS_DISPATCH_ONE);
 
 	quorum_finalize(q_handle);
+	q_handle = 0;
 
 	err = corosync_cfg_initialize(&c_handle, &c_callbacks);
 	if (err != CS_OK) {
 		fprintf(stderr, "Cannot initialise CFG service\n");
+		c_handle = 0;
 		goto err_exit;
 	}
 
@@ -394,10 +401,18 @@ static void show_nodes(nodeid_format_t nodeid_format, name_format_t name_format)
 		}
 	}
 
-	if (using_vq)
-		votequorum_finalize(v_handle);
+	result = EXIT_SUCCESS;
 err_exit:
-	corosync_cfg_finalize(c_handle);
+	if (q_handle != 0) {
+		quorum_finalize (q_handle);
+	}
+	if (using_vq && v_handle != 0) {
+		votequorum_finalize (v_handle);
+	}
+	if (c_handle != 0) {
+		corosync_cfg_finalize (c_handle);
+	}
+	return result;
 }
 
 int main (int argc, char *argv[]) {
@@ -477,7 +492,7 @@ int main (int argc, char *argv[]) {
 		show_usage(argv[0]);
 		break;
 	case CMD_SHOWNODES:
-		show_nodes(nodeid_format, address_format);
+		ret = show_nodes(nodeid_format, address_format);
 		break;
 	case CMD_SHOWSTATUS:
 		show_status();

-- 
corosync Debian packaging



More information about the Debian-ha-svn-commits mailing list