Browse Source

(Logical change 1.3)

git-svn-id: http://svn.fedorahosted.org/svn/corosync/trunk@5 fd59a12c-fef9-0310-b244-a6a79926bd2f
John Cherry 21 years ago
parent
commit
95f17845c6
66 changed files with 21664 additions and 0 deletions
  1. 232 0
      CHANGELOG
  2. 29 0
      LICENSE
  3. 51 0
      Makefile
  4. 63 0
      Makefile.samples
  5. 107 0
      QUICKSTART
  6. 169 0
      README.devmap
  7. 67 0
      TODO
  8. 58 0
      conf/groups.conf
  9. 3 0
      conf/network.conf
  10. 55 0
      exec/Makefile
  11. 2176 0
      exec/amf.c
  12. 56 0
      exec/amf.h
  13. 1638 0
      exec/ckpt.c
  14. 81 0
      exec/ckpt.h
  15. 456 0
      exec/clm.c
  16. 51 0
      exec/clm.h
  17. 2861 0
      exec/gmi.c
  18. 85 0
      exec/gmi.h
  19. 59 0
      exec/handlers.h
  20. 90 0
      exec/log/print.c
  21. 64 0
      exec/log/print.h
  22. 722 0
      exec/main.c
  23. 113 0
      exec/main.h
  24. 224 0
      exec/mempool.c
  25. 57 0
      exec/mempool.h
  26. 444 0
      exec/parse.c
  27. 161 0
      exec/parse.h
  28. 477 0
      exec/poll.c
  29. 78 0
      exec/poll.h
  30. 171 0
      exec/print.c
  31. 65 0
      exec/print.h
  32. 560 0
      exec/profile
  33. 247 0
      exec/tlist.c
  34. 62 0
      exec/tlist.h
  35. 221 0
      include/ais_amf.h
  36. 174 0
      include/ais_ckpt.h
  37. 100 0
      include/ais_clm.h
  38. 728 0
      include/ais_msg.h
  39. 394 0
      include/ais_types.h
  40. 75 0
      include/list.h
  41. 163 0
      include/queue.h
  42. 185 0
      include/sq.h
  43. 28 0
      init/ais
  44. 56 0
      lib/Makefile
  45. 938 0
      lib/amf.c
  46. 1251 0
      lib/ckpt.c
  47. 476 0
      lib/clm.c
  48. 564 0
      lib/util.c
  49. 186 0
      lib/util.h
  50. 14 0
      loc
  51. 92 0
      test/Makefile
  52. 200 0
      test/ckptstress.c
  53. 999 0
      test/scripts/spam
  54. 82 0
      test/scripts/spam2
  55. 315 0
      test/testamf.c
  56. 276 0
      test/testamf1.c
  57. 305 0
      test/testamf2.c
  58. 266 0
      test/testamf3.c
  59. 265 0
      test/testamf4.c
  60. 266 0
      test/testamf5.c
  61. 266 0
      test/testamf6.c
  62. 280 0
      test/testamfth.c
  63. 347 0
      test/testckpt.c
  64. 191 0
      test/testclm.c
  65. 54 0
      test/testparse.c
  66. 75 0
      test/testtimer.c

+ 232 - 0
CHANGELOG

@@ -0,0 +1,232 @@
+Application Interface Specification Implementation
+--------------------------------------------------
+0.30
+* Add GMI & sort queues to build environment.
+* Changed queue.h to be more consistent with naming conventions used in tree.
+* Simplified cluster membmership service by modifying to use GMI.
+* Modified availability management framework to use GMI.
+* Modified method services connect to main executive to make services standalone
+  objects.  This could facilitate plugin services in the future.
+* Modified checkpointing for multinode using GMI.  
+* healthcheck timeouts were being caused by slow access to the filesystem for
+  sockets and deleted sockets.  This was fixed by using the abstract namespace
+  which is memory based.
+* Generic logging facility added to get rid of numerous #ifdef DEBUGs and avoid
+  the SIGPIPE and signal changes created by the libc's version of syslog.
+* Authentication for API<->executive added.  Only uid=0 or gid=ais processes can
+  connect to the executive via the libraries to provide service.
+* This release has alot of cleanups!
+* Removed all point-to-point authentication since using GMI now.
+
+* GMI provides extended virtual synchrony semantics with:
+*	- agreed message ordering (all processors agree on message order)
+*	- using available hardware multicast
+*	- group membership algorithm that currently supports 16 processors
+*	- message fragmentation to fit MTU that avoids UDP fragmentation
+*	- full recovery of messages during configuration change
+*	- 512kb message support
+*	- 3 priority levels
+
+0.29
+* Changed all send/recv functions to sendmsg/recvmsg.
+
+0.28
+* Remove current poll code and replace with poll abstraction.
+
+0.27
+* Add CKPT service to AIS Executive for single node checkpointing.
+
+0.26
+* Added support for pthreads to clm and amf interfaces.  Critical
+  sections and shared data now protected by mutex.  If Dispatch in
+  one thread, Finalize in another thread will cause Dispatch to behave
+  per spec.
+* Moved global receive buffer for APIs into handles or stack.
+* Allocate and free instance memory in handle manager instead of in each API.
+* Merge defect fixes from 0.22.1-0.22.8 into development tree.
+* CkptCheckpointHandleT and CkptSectionIteratorT functions created a new
+  connection each time any APIs using those types were called.  Now these
+  types have been encapsulated into their own handle database which doesn't
+  create (expensive) connections for each API call.
+* Changed named types such as MESSAGE_CKPT_REQ* to MESSAGE_REQ_CKPT* to match
+  structure names.
+
+0.25
+* Added ability for authentication to use none, password, or DSA depending on
+  settings in file /etc/ais/authtype.  The values are no authentication, password
+  authentication, or dsa authentication.
+* Added DSA authentication to node-to-node communication.
+	Server generates 16 byte random number, sends random number to connecting
+	client, client signs random number message with DSA private key, server
+	verifies signature with public key of client for random number message.
+* Added DSA key generator.
+* Added password authentication.  File /etc/ais/aiskeys/password is used by the
+  server to compare the client's password.  If they match, the connection is
+  authenticated.
+* Added no authentication option.
+* Fixed PPC compile to compile cleanly with -Wall.
+* Added version checking to APIs.
+
+0.24
+* Fixed problem if outbound queues have messages queued, they are not
+  sent during the poll loop because poll isn't passed the correct events flag.
+  This problem introduced in the select to poll conversion in 0.23.
+* Healthchecks for CLM service intra-node now run on seperate timers per connection.
+* Fixed problem connections intra-node were completely broken as a result
+  of the change from select to poll in 0.23.
+* Fixed bug in AMF timer_del on NULL timer.
+* Fixed few bugs in AMF intra-node communications would result in segfault.
+* Made pollfd_table global to reduce variable passing and simplify code.
+* Cleaned up with compile of -Wall which found several bugs.
+* Some minor cleanups of makefiles from major reorg in 0.23.
+* Replaced memory malloc/free/realloc with memory pool versions to avoid
+  failed memory allocation requests and improve realtime response.
+* Implemented the library portion of all checkpointing (Ckpt) APIs.
+
+0.23
+* Reorganized executive into exec directory and split executive components
+  into seperate files.
+* Placed library interfaces into lib directory.
+* Placed test components into test directory.
+* Abstracted some of the service setup and teardown code that was
+  integrated into the main loops and disconnect function call to call
+  generic functions {amf|clm}InitializeExecutive, and {amf|clm}FinalizeApi.
+* Cleaned up connection (ci) datatypes.
+* Removed old timers, replaced with generic timer implementation.
+* replaced select with poll in executive.
+* lock memory of process and set RR prio 99 to avoid priority inversions.
+* Fixed problem where accept couldn't connect because resource exhaustion,
+  executive would crash.
+
+0.22
+* Fix defect in HA state and operational state machines where states are not
+  always determined correctly.
+* Fix defect invalid argument to saAmfErrorReport will crash executive.
+* Fix defect no /var/run/aisexec.pid created for service.
+
+0.21
+* Fix defect testclm doesn't exit if no connection to AIS executive possible.
+* Fix defect aisexec crashes if no /etc/groups.conf file present.
+* Fix defect aisexec opens "groups.conf" instead of "/etc/groups.conf" file.
+* Fix defect aisexec doesn't set SaClmClusterNodeT data structure if local interface
+  not defined in /etc/clusterips, or empty/no /etc/clusterips file present.
+* Fixed some basic error reporting in aisexec to use syslog's LOG_ERR instead
+  of LOG_NOTICE.
+* Fixed SEGV if component not found for componentcapabilitymodelget API.
+
+0.20
+* Correctly parse model values in configuration file for both service
+  groups and components.
+* Changed variables with text nodeexec to aisexec.
+* Fixed a bug select wouldn't retry because errno checked for -EINTR
+  when it should be checking for EINTR.
+* Correctly determine startup HA state and send appropriate ha state
+  changes to registered receivers.
+
+0.19
+* Implemented saAmfCSISetCallback.
+* Implemented saAmfCSIRemoveCallback.
+* Implemented saAmfProtectionGroupTrackStart.
+* Implemented saAmfProtectionGroupTrackCallback.
+* Implemented saAmfProtectionGroupTrackStop.
+* Implemented saAmfErrorReport.
+* Implemented saAmfErrorCancelAll.
+* Implemented saAmfResponse.
+* Implemented saAmfComponentCapabilityModelGet.
+* Implemented saAmfPendingOperationGet dummy function.
+	This function will have to be rewritten to be
+	correct, but completes the API for now.
+* Fixed problem where queued messages would not cause select
+  to be triggered.  Occured in component register, unregister,
+  track start, track stop functions.
+
+0.18
+* Implemented saAmfReadinessStateSetCallback.
+* Implemented saAmfStoppingComplete.
+* Implemented saAmfComponentTerminateCallback.
+* Implemented saAmfHAStateGet.
+
+0.17
+* Implemented saAmfHealthcheckCallback.
+* Implemented saAmfResponse.
+* Implemented saAmfReadinessStateGet.
+* Made connect non-blocking to fix bug where blocking connects
+  could cause timeout on heartbeating.
+* Made recv's non-blocking by adding small buffer to each connection
+  and recving and processing as needed.
+* Integrated message dispatch for libais and nodeexec connections.
+* Fixed bug where SA_TRACK_CURRENT does not return current state of 
+  cluster membership after second invocation of the testclm application.
+* Seperated several functions from main.
+* Fixed bug where outqs were not flushed when data present within them
+  at end of processing loop before next select.  Previously they would
+  only flush when new data was sent on the queues.
+* Fixed bug where CLM and AMF always processed dispatch functions in
+  SA_DISPATCH_BLOCKING mode.
+
+0.16
+* zero out component data structure during parse.
+* make component register/unregister update state in the group list.
+* return ERR_NOT_EXIST and ERR_EXIST and BAD_OPERATION error codes for
+  register and unregister as per spec.
+* renamed executive message handlers to include exec in name of handler
+  function.
+* Handle null proxyCompName to register and unregister as per spec.
+* Fixed off-by-one in handle database that resulted in badness when
+  allocating memory after creating any handle (ie: create two handles).
+* Added component enumerator which enumerates all components and executes
+  a function on the component.
+* Added component enumerator to unregister all library and nodeexec
+  connections that are disconnected.
+
+0.15
+* Added correct time stamping for SaClmClusterNodeT structure.
+* Made nodeexec message handlers use the message_handler structure.
+* Made nodeexec_process_receive handle messages made of only headers
+  with no payloads.  Previously, nodeexec would lock.
+* Seperated heartbeat into two shorter messages one request and one response.
+* Changed names of some structures to be more consistent.
+
+0.14
+* Added simple linked list implementation list.h.
+* Modified parser to read data into linked lists.  This makes processing
+  register/unregister/healthchecks/management of HAState easier.
+* Exported queue implementation from nodeexec.c to queue.h.
+* Seperated parser and parser testing code to seperate source files.
+* Modified makefile to build parser test code.
+* Modified parser test code to display new linked-list implementation.
+* Partially implemented register/unregister/get component name commands
+  in AMF spec.
+
+0.13
+* Genericized nodeexec handler so it could run any type of service
+  and each service has its own set of handler functions as not to crash
+  the node executive.  This allows a set of messages to be designed
+  to not be crashable, vs trying to figure out all of the interactions
+  between a flat message name space.
+* Added size field for messages stored into the outq so 
+  two send_messages in the nodeexec wouldn't crash.  The send_message
+  function requires the size on messages, and the size was retrieved from
+  the message header.  In a two-part send, there is no message header in
+  the second message.  This was resulting in junk data and possible
+  crashes on messages that must be queued waiting for the libais to
+  recv on the other end.
+  This also fixes the MESSAGE_MAGIC value being displayed in some
+  NodeId fields of the testclm application.
+* Changed lots of type names to something more consistent.
+* Changed lots of enumerated types names to something more consistent.
+
+0.12
+* Abstracted some of the networking functions for EINTR and other errors
+  Added library handle verification and generic handle database mechanism
+  available for all services.
+* Implemented database mechanism and all abstracted functions on cluster
+  membership service.
+
+0.11
+* Defined AMF configuration file.
+* Added configuration parser for AMF service.
+* Defined inital AMF header/c files.
+
+0.1
+* Initial release of cluster membership service.

+ 29 - 0
LICENSE

@@ -0,0 +1,29 @@
+Copyright (c) 2002-2004 MontaVista Software, Inc.
+
+All rights reserved.
+
+This software licensed under BSD license, the text of which follows:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice,
+  this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+- Neither the name of the MontaVista Software, Inc. nor the names of its
+  contributors may be used to endorse or promote products derived from this
+  software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.

+ 51 - 0
Makefile

@@ -0,0 +1,51 @@
+# Copyright (c) 2002-2004 MontaVista Software, Inc.
+# 
+# All rights reserved.
+# 
+# This software licensed under BSD license, the text of which follows:
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+# - Redistributions of source code must retain the above copyright notice,
+#   this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright notice,
+#   this list of conditions and the following disclaimer in the documentation
+#   and/or other materials provided with the distribution.
+# - Neither the name of the MontaVista Software, Inc. nor the names of its
+#   contributors may be used to endorse or promote products derived from this
+#   software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+# Production mode flags
+CFLAGS = -O3 -Wall
+LDFLAGS =
+
+# Debug mode flags
+#CFLAGS = -g -DDEBUG
+#LDFLAGS = -g
+
+# Profile mode flags
+#CFLAGS = -O3 -pg -DDEBUG
+#LDFLAGS = -pg
+
+all:
+	(cd lib; echo ==== `pwd` ===; $(MAKE) all CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)");
+	(cd exec; echo ==== `pwd` ===; $(MAKE) all CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)");
+	(cd test; echo ==== `pwd` ===; $(MAKE) all CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)");
+
+clean:
+	(cd lib; echo ==== `pwd` ===; $(MAKE) clean);
+	(cd exec; echo ==== `pwd` ===; $(MAKE) clean);
+	(cd test; echo ==== `pwd` ===; $(MAKE) clean);

+ 63 - 0
Makefile.samples

@@ -0,0 +1,63 @@
+# Copyright (c) 2002-2004 MontaVista Software, Inc.
+# 
+# All rights reserved.
+# 
+# This software licensed under BSD license, the text of which follows:
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+# - Redistributions of source code must retain the above copyright notice,
+#   this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright notice,
+#   this list of conditions and the following disclaimer in the documentation
+#   and/or other materials provided with the distribution.
+# - Neither the name of the MontaVista Software, Inc. nor the names of its
+#   contributors may be used to endorse or promote products derived from this
+#   software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+CFLAGS = -c -O2 -I/usr/include/ais
+LDFLAGS = 
+
+all:clean testclm testamf testamf1 testamf2 testamf3 testamf4 testamf5 testamf6
+
+cleanup:
+	rm -f testclm testamf
+
+testclm: testclm.o
+	$(CC) $(LDFLAGS) -o testclm testclm.o -lais
+
+testamf: testamf.o 
+	$(CC) $(LDFLAGS) -o testamf testamf.o -lais
+
+testamf1: testamf1.o libais.a
+	$(CC) $(LDFLAGS) -o testamf1 testamf1.o libais.a
+
+testamf2: testamf2.o libais.a
+	$(CC) $(LDFLAGS) -o testamf2 testamf2.o libais.a
+
+testamf3: testamf3.o libais.a
+	$(CC) $(LDFLAGS) -o testamf3 testamf3.o libais.a
+
+testamf4: testamf4.o libais.a
+	$(CC) $(LDFLAGS) -o testamf4 testamf4.o libais.a
+
+testamf5: testamf5.o libais.a
+	$(CC) $(LDFLAGS) -o testamf5 testamf5.o libais.a
+
+testamf6: testamf6.o libais.a
+	$(CC) $(LDFLAGS) -o testamf6 testamf6.o libais.a
+
+clean:
+	rm -f *.o testclm testamf testamf1 testamf2 testamf3 testamf4 testamf5 testamf6

+ 107 - 0
QUICKSTART

@@ -0,0 +1,107 @@
+Application Interface Specification Quckstart Guide
+---------------------------------------------------
+This AIS package is broken into four parts.  The exec directory contains
+all of the code responsible for serving the APIs.  The api directory contains
+APIs the user can link to.  The test directory contains some simple test
+programs which exercise the APIs.  The directory conf contains example
+configuration files which can be copied directly onto the target system.
+
+The API implements the Cluster Membership (CLM), Availabilty Management
+Framework (AMF) and the Checkpointing (CKPT) APIs.
+
+Configuring the AIS Executive:
+-----------------------------
+The AIS Executive will automatically determine cluster membership by
+communicating on a specified multicast address and port.
+
+The directory conf contains the file network.conf
+
+bindnetaddr:192.168.1.0
+mcastaddr:226.94.1.1
+mcastport:6000
+
+bindnetaddr specifies the address which the AIS Executive should bind to.
+This address should always end in zero.  If the local interface taffic
+traffic should routed over is 192.168.5.92, set bindnetaddr to 192.168.1.0.
+
+mcastaddr is a multicast address.  The default should work but you may have
+a different network configuration.  Avoid 225.X.X.X because this is a "config"
+multicast address which every multicast capable host joins on system start.
+
+mcastport specifies the UDP port number.  It is possible to use the same
+multicast address on a network with the AIS services configured for multiple
+UDP ports.
+
+The directory conf contains the file groups.conf which specifies the failover
+groups, service units, components, and policies to be used by the AMF.  The
+configuration file matches the testamf1-6 programs in the test directory and
+can be copied directly.
+
+These two files should be placed in the /etc/ais directory.
+
+Building AIS
+------------
+AIS requires GCC, LD, and a Linux 2.4 kernel.  AIS has been tested on
+Debian Sarge, MontaVista Carrier Grade Edition 3.1, and Redhat 9.
+
+Compile AIS by running make in the root directory.  Make can also be run
+in the individual directories.  Nothing is installed by make.  If install
+is desired, the files must be copied manually.
+
+Setup network
+-------------
+Some networks do not automatically configure the default route.  Ensure
+the default route is configured or AIS wont be able to communicate with
+other nodes.
+
+[sdake@slickdeal checkpointd]$ /sbin/route
+Kernel IP routing table
+Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
+10.0.0.6        *               255.255.255.255 UH    0      0        0 tun0
+127.0.0.0       *               255.0.0.0       U     0      0        0 lo
+default         192.168.1.1     0.0.0.0         UG    0      0        0 eth0
+
+the word default above specifies the default route.  If the default route
+is missing, specify one by
+
+unix# /sbin/route add default gw 192.168.1.1
+
+where 192.168.1.1 is the gateway.  It is possible to specify an invalid 
+route which will also make AIS work properly.
+
+Run AIS Executive
+-----------------
+Get 2 or more nodes and run the AIS executive on each node.  A list of
+node IPs should be displayed on stdout when the nodes join a configuration.
+Run the aisexec program (after the default route is setup and the config
+files are in place).
+
+Try out the CLM functionality
+-----------------------------
+Run test/testclm on one node.  Then kill and add nodes.  This will cause
+callbacks to be called in the testclm application which will print out
+the node state changes.
+
+Try out the AIS AMF functionality
+---------------------------------
+After aisexec is running
+
+Run testamf1 on one node, testamf3 testamf4 on another node.
+One will become active one standby.  testamf2 is special in that it shows
+reporting and canceling an error.  Run testamf2 on the node testamf1
+was run from.  The ha states and readiness states will be shown.
+
+Try out the AIS CKPT functionality
+----------------------------------
+run ckptstress.  This will write checkpoint data as quickly as possible to
+the cluster.
+
+Write your own applications
+---------------------------
+Without real applications, finding the hard bugs will be difficult.  Please
+port or write apps and let us know of the progress!
+
+Contribute!
+-----------
+Code, examples, documentation, bug reports, testing are all appreciated.
+Read the TODO or the ask on the mailing lists for ways to contribute.

+ 169 - 0
README.devmap

@@ -0,0 +1,169 @@
+Copyright (c) 2002-2004 MontaVista Software, Inc.
+
+All rights reserved.
+
+This software licensed under BSD license, the text of which follows:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice,
+  this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+- Neither the name of the MontaVista Software, Inc. nor the names of its
+  contributors may be used to endorse or promote products derived from this
+  software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------------------
+Files, purpose, and dependencies.
+-------------------------------------------------------------------------------
+
+*----------------*
+*- AIS INCLUDES -*
+*----------------*
+
+include/ais_amf.h
+-----------------
+	Definitions for AMF interface.
+
+include/ais_ckpt.h
+------------------
+	Definitions for CKPT interface.
+
+include/ais_clm.h
+-----------------
+	Definitions for CLM interface.
+
+include/ais_msg.h
+-----------------
+	All the stuff that is used to specify how lib and executive communicate
+	including message identifiers, message request data, and mesage response
+	data.
+
+include/ais_types.h
+-------------------
+	Base type definitions for AIS interface.
+
+include/list.h
+-------------
+	Doubly linked list inline implementation.
+
+include/queue.h
+---------------
+	FIFO queue inline implementation.
+
+	depends on list.
+
+include/sq.h
+------------
+	Sort queue where items are sorted according to a sequence number.  Avoids
+	Sort, hence, install of a new element takes is O(1).  Inline implementation.
+
+	depends on list.
+
+*---------------*
+* AIS LIBRARIES *
+*---------------*
+lib/amf.c
+---------
+	AMF user library linked into user application.
+
+lib/ckpt.c
+----------
+	CKPT user library linked into user application.
+
+lib/clm.c
+---------
+	CLM user library linked into user application.
+
+lib/util.c
+----------
+	Utility functions used by all libraries.
+
+*-----------------*
+*- AIS EXECUTIVE -*
+*-----------------*
+
+exec/amf.{h|c}
+-------------
+	Server side implementation of Availability Management Framework (AMF API).
+
+exec/ckpt.{h|c}
+	Server side implementation of Checkpointing (CKPT API).
+
+exec/clm.{h|c}
+	Server side implementation of Cluster Membership (CLM API).
+
+
+exec/gmi.{h|c}
+--------------
+	group messaging interface supporting reliable totally ordered group multicast
+	using ring topology.  Supports extended virtual synchrony delivery semantics
+	with strong membership guarantees.
+
+	depends on cglpoll.
+	depends on queue.
+	depends on sq.
+	depends on list.
+
+exec/handlers.h
+---------------
+	Functional specification of a service that connects into AIS executive.
+	If all functions are implemented, new services can easily be added.
+
+exec/main.{h|c}
+--------------
+	Main dispatch functionality and global data types used to connect AIS
+	services into one component.
+
+exec/mempool.{h|c}
+------------------
+	Memory pool implementation that supports preallocated memory blocks to
+	avoid OOM errors.
+
+exec/parse.{h|c}
+----------------
+	Parsing functions for parsing /etc/ais/groups.conf and
+	/etc/ais/network.conf into internally used data structures.
+
+exec/poll.{h|c}
+---------------
+	poll abstraction with support for nearly unlimited large poll handlers
+	and timer handlers.
+
+	depends on tlist.
+
+exec/print.{h|c}
+----------------
+	Logging implementation meant to replace syslog.  syslog has nasty side
+	effect of causing a signal every time a message is logged.
+
+exec/tlist.{h|c}
+-----------------
+	Timer list interface for supporting timer addition, removal, expiry, and 
+	determination of timeout period left for next timer to expire.
+
+	depends on list.
+
+exec/log/print.{h|c}
+--------------------
+	Prototype implementation of logging to syslog without using syslog C
+	library call.
+
+loc
+---
+Counts the lines of code in the AIS implementation.

+ 67 - 0
TODO

@@ -0,0 +1,67 @@
+Application Interface Specification TODO list
+
+Generic Items
+-------------
+* EVT, DLOCK, MSG APIs functionality need to be developed.
+* Error checking on parameters could use improvement.
+* Allow AIS Executive to configure cluster name.
+* Compliance testing of return values would be helpful.
+* Support B.01.01 version of spec (currently support A.01.01 version).
+* Consider implementing SOCK_SEQPACKET for the AF_UNIX family of sockets on
+  Linux.  This would save an extra system call every time an operation must
+  be done from the API.
+* There are lots of TODO's in the code that need attention.
+
+Group Messaging Interface
+-------------------------
+* Very important: single node may not work too well.  Debug this
+  mode of operation.
+* Very important: implement full EVS semantics when holes occur in
+  delivery messages after a configuration change but before the new
+  configuration is delivered.
+* Very important: block new messages from being multicast until recovery
+  of each service has completed after a configuration change.  This could be 
+  done with a "plug" in the token which "stops" any GMI_PRIO_MED or GMI_PRIO_LOW
+  messages from being multicast until all members of the configuration have 
+  unplugged the token.  Then queued messages in MED or LOW priority can be
+  sent, ensuring correct partition operation.
+* Implement error creation config file to test GMI since all my lossy
+  hardware has been fixed.
+* Add secrecy/authentication to group messaging interface.
+* Add support for multiple rings with gateway ring to ring for added scalability
+  in LANs.
+* Add support for multiple rings with gateway tuned to long haul networks for
+  added scalability in WANs.  Look at spread.org as a design.
+* Add support for low delivery-time delay FIFO messages.
+* Add support for SAFE ordering.
+* Add support for encryption/authentication using Helix.  nonce will start
+  at zero and increment for every message sent or rotation on the ring.  Group
+  key produced using group key generation protocol.
+  
+Cluster Membership
+------------------
+* Make timeout on SaClmClusterNodeGet work.  Currently the timeout is 5
+  seconds, but the spec requires the timeout to be specified in the API call.
+
+Availability Management Framework
+---------------------------------
+* Very Important: Implement configuration change support.  This includes partitions.
+* Currently the executive can record and manage only one component service
+  instance per component.  As a result, one component cannot act as standby/active
+  for two other components in the system (AIS Spec page 74 Figure 16. Example of
+  n+1 redundancy model).
+  - Fix to follow spec.
+* If a user of the AMF library doesn't respond with saAmfResponse, the state
+  of the application will never change.  Fix by adding timeouts to readiness state
+  and ha state changes to force saAmfResponse state changes triggered.
+* Create array namespace for each invocation id per connection to avoid
+  cross file descriptor contamination.
+* Implement resource proxy functions. (currently dummy functions)
+* Implement pending operations. (currently dummy functions)
+* Implement NWAY and NWAYACTIVE redundancy models.
+
+Checkpointing
+-------------
+* Very Important: Implement configuration change support.  This includes partitions.
+* Implement thread support for checkpointing library.
+* Implement expiration times on checkpoints.

+ 58 - 0
conf/groups.conf

@@ -0,0 +1,58 @@
+# Test configuration file
+  
+group {
+	name=raid
+	model=nplusm
+	active-units=1
+	backup-units=2
+		
+	unit {  
+		name=raidA
+		component {
+			name=comp_a_in_su_x
+			model=x_active
+		}
+		component {
+			name=comp_b_in_su_x
+			model = x_active	
+		}
+	}
+	unit {
+		name=raidB
+		component {
+			name=comp_a_in_su_y
+			model=x_active
+		}
+		component {
+			name=comp_b_in_su_y
+			model = x_active	
+		}
+	}
+	unit {
+		name=raidC
+		component {
+			name=comp_a_in_su_z
+			model=x_active
+		}
+		component {
+			name=comp_b_in_su_z
+			model = x_active	
+		}
+	}
+# protection group has the same name as a component service instance
+# if one entity of a component service instance fails, the entire
+# service unit fails over to another service unit in the service 
+# instance
+	protection {
+		name = pgA
+		member = comp_a_in_su_x
+		member = comp_a_in_su_y
+		member = comp_a_in_su_z
+	}
+	protection {
+		name = pgB
+		member = comp_b_in_su_x
+		member = comp_b_in_su_y
+		member = comp_b_in_su_z
+	}
+}

+ 3 - 0
conf/network.conf

@@ -0,0 +1,3 @@
+bindnetaddr:192.168.1.0
+mcastaddr:226.94.1.1
+mcastport:6000

+ 55 - 0
exec/Makefile

@@ -0,0 +1,55 @@
+# Copyright (c) 2002-2004 MontaVista Software, Inc.
+# 
+# All rights reserved.
+# 
+# This software licensed under BSD license, the text of which follows:
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+# - Redistributions of source code must retain the above copyright notice,
+#   this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright notice,
+#   this list of conditions and the following disclaimer in the documentation
+#   and/or other materials provided with the distribution.
+# - Neither the name of the MontaVista Software, Inc. nor the names of its
+#   contributors may be used to endorse or promote products derived from this
+#   software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+# Production mode flags
+#CFLAGS = -O3 -Wall
+#LDFLAGS = 
+
+# Debug mode flags
+CFLAGS = -g -Wall
+# -DDEBUG
+LDFLAGS = -g
+
+# Profile mode flags
+#CFLAGS = -O3 -pg
+#LDFLAGS = -pg
+
+OBJS = main.o parse.o tlist.o mempool.o poll.o gmi.o clm.o amf.o ckpt.o print.o
+
+all:aisexec
+
+aisexec: $(OBJS)
+	$(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o aisexec
+
+clean:
+	rm -f *.o aisexec gmon.out
+
+%.o: %.c
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<

+ 2176 - 0
exec/amf.c

@@ -0,0 +1,2176 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/sysinfo.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+
+#include "../include/ais_types.h"
+#include "../include/ais_msg.h"
+#include "../include/list.h"
+#include "../include/queue.h"
+#include "gmi.h"
+#include "poll.h"
+#include "mempool.h"
+#include "parse.h"
+#include "main.h"
+#include "print.h"
+#include "handlers.h"
+
+#ifdef INPARSEDOTH
+enum amfOperationalState {
+	AMF_OPER_DISABLED,
+	AMF_OPER_ENABLED
+};
+
+enum amfAdministrativeState {
+	AMF_ADMIN_UNLOCKED,
+	AMF_ADMIN_LOCKED,
+	AMF_ADMIN_STOPPING
+};
+
+enum amfOperationalAdministrativeState {
+	AMF_ENABLED_UNLOCKED,
+	AMF_DISABLED_UNLOCKED,
+	AMF_DISABLED_LOCKED,
+	AMF_ENABLED_STOPPING
+};
+
+
+/*
+ * State machines for states in AMF
+ */
+enum amfEnabledUnlockedState {
+	AMF_ENABLED_UNLOCKED_INITIAL,
+	AMF_ENABLED_UNLOCKED_IN_SERVICE_REQUESTED,
+	AMF_ENABLED_UNLOCKED_IN_SERVICE_COMPLETED,
+	AMF_ENABLED_UNLOCKED_ACTIVE_REQUESTED,
+	AMF_ENABLED_UNLOCKED_ACTIVE_COMPLETED,
+	AMF_ENABLED_UNLOCKED_STANDBY_REQUESTED,
+	AMF_ENABLED_UNLOCKED_STANDBY_COMPLETED,
+};
+
+enum amfDisabledUnlockedState {
+	AMF_DISABLED_UNLOCKED_INITIAL,
+	AMF_DISABLED_UNLOCKED_QUIESCED_REQUESTED,
+	AMF_DISABLED_UNLOCKED_QUIESCED_COMPLETED,
+	AMF_DISABLED_UNLOCKED_OUT_OF_SERVICE_REQUESTED,
+	AMF_DISABLED_UNLOCKED_OUT_OF_SERVICE_COMPLETED
+};
+	
+enum amfDisabledLockedState {
+	AMF_DISABLED_LOCKED_INITIAL,
+	AMF_DISABLED_LOCKED_QUIESCED_REQUESTED,
+	AMF_DISABLED_LOCKED_QUIESCED_COMPLETED,
+	AMF_DISABLED_LOCKED_OUT_OF_SERVICE_REQUESTED
+	AMF_DISABLED_LOCKED_OUT_OF_SERVICE_COMPLETED,
+};
+
+enum amfEnabledStoppingState {
+	AMF_ENABLED_STOPPING_INITIAL,
+	AMF_ENABLED_STOPPING_STOPPING_REQUESTED,
+	AMF_ENABLED_STOPPING_STOPPING_COMPLETED,
+};
+
+/*
+ * Internal Functions
+ */
+static void componentOutOfServiceSetNoApi (
+	struct saAmfComponent *component);
+
+#endif
+static void grow_amf_track_table (
+	int fd,
+	int growby);
+
+static void sendProtectionGroupNotification (
+	int fd,
+	SaAmfProtectionGroupNotificationT *notificationBufferAddress,
+	struct saAmfProtectionGroup *amfProtectionGroup,
+	struct saAmfComponent *changedComponent,
+	SaAmfProtectionGroupChangesT changeToComponent,
+	SaUint8T trackFlags);
+
+static int activeServiceUnitsCount (
+	struct saAmfGroup *saAmfGroup);
+
+#ifdef COMPILE_OUT
+static void enumerateComponents (
+	void (*function)(struct saAmfComponent *, void *data),
+	void *data);
+
+
+static void CSIRemove (
+	int fd);
+
+static void haStateSetClusterInit (
+	int fd,
+	struct saAmfComponent *saAmfComponent);
+#endif
+
+static void haStateSetCluster (
+	struct saAmfComponent *saAmfComponent,
+	SaAmfHAStateT haState);
+
+static void readinessStateSetApi (
+	struct saAmfComponent *component,
+	SaAmfReadinessStateT readinessState);
+
+#ifdef COMPILE_OUT
+static void readinessStateSetClusterInit (
+	int fd,
+	struct saAmfComponent *saAmfComponent);
+#endif
+
+static void readinessStateSetCluster (
+	struct saAmfComponent *saAmfComponent,
+	SaAmfReadinessStateT readinessState);
+
+#ifdef COMPILE_OUT
+static void enumerateComponentsClusterInit (
+	struct saAmfComponent *component,
+	void *data);
+#endif
+
+static void dsm (
+	struct saAmfComponent *saAmfComponent);
+
+#if 0 /* NOT IMPLEMENTED */
+static void componentTerminate (
+	int fd);
+#endif
+
+static void timer_function_libamf_healthcheck (
+	void *data);
+
+static struct saAmfProtectionGroup *findProtectionGroup (
+	SaNameT *csiName);
+
+static struct saAmfComponent *findComponentInProtectionGroup (
+	SaNameT *csiName,
+	SaNameT *compName);
+
+static void sendProtectionGroupNotifications (
+	struct saAmfComponent *changedComponent,
+	SaAmfProtectionGroupChangesT changeToComponent);
+
+static void sendProtectionGroupNotification (
+	int fd,
+	SaAmfProtectionGroupNotificationT *notificationBufferAddress,
+	struct saAmfProtectionGroup *amfProtectionGroup,
+	struct saAmfComponent *changedComponent,
+	SaAmfProtectionGroupChangesT changeToComponent,
+	SaUint8T trackFlags);
+
+static void response_handler_readinessstatesetcallback (
+	int connection,
+        struct req_amf_response *req_amf_response);
+
+static void response_handler_csisetcallback (
+	int connection,
+        struct req_amf_response *req_amf_response);
+
+
+static int amfApiFinalize (int fd);
+
+static int amfExecutiveInitialize (void);
+
+static int message_handler_req_exec_amf_componentregister (int fd, void *message);
+
+static int message_handler_req_exec_amf_componentunregister (int fd, void *message);
+
+static int message_handler_req_exec_amf_errorreport (int fd, void *message);
+
+static int message_handler_req_exec_amf_errorcancelall (int fd, void *message);
+
+static int message_handler_req_exec_amf_readinessstateset (int fd, void *message);
+
+static int message_handler_req_exec_amf_hastateset (int fd, void *message);
+
+static int message_handler_req_amf_init (int fd, void *message);
+
+static int message_handler_req_amf_activatepoll (int fd, void *message);
+
+static int message_handler_req_amf_componentregister (int fd, void *message);
+
+static int message_handler_req_amf_componentunregister (int fd, void *message);
+
+static int message_handler_req_amf_readinessstateget (int fd, void *message);
+
+static int message_handler_req_amf_hastateget (int fd, void *message);
+
+static int message_handler_req_amf_protectiongrouptrackstart (int fd, void *message);
+
+static int message_handler_req_amf_protectiongrouptrackstop (int fd, void *message);
+
+static int message_handler_req_amf_errorreport (int fd, void *message);
+
+static int message_handler_req_amf_errorcancelall (int fd, void *message);
+
+static int message_handler_req_amf_stoppingcomplete (int fd, void *message);
+
+static int message_handler_req_amf_response (int fd, void *message);
+
+static int message_handler_req_amf_componentcapabilitymodelget (int fd, void *message);
+
+int (*amf_libais_handler_fns[]) (int fd, void *) = {
+	message_handler_req_amf_activatepoll,
+	message_handler_req_amf_componentregister,
+	message_handler_req_amf_componentunregister,
+	message_handler_req_amf_readinessstateget,
+	message_handler_req_amf_hastateget,
+	message_handler_req_amf_protectiongrouptrackstart,
+	message_handler_req_amf_protectiongrouptrackstop,
+	message_handler_req_amf_errorreport,
+	message_handler_req_amf_errorcancelall,
+	message_handler_req_amf_stoppingcomplete,
+	message_handler_req_amf_response,
+	message_handler_req_amf_componentcapabilitymodelget
+};
+
+int (*amf_aisexec_handler_fns[]) (int fd, void *) = {
+	message_handler_req_exec_amf_componentregister,
+	message_handler_req_exec_amf_componentunregister,
+	message_handler_req_exec_amf_errorreport,
+	message_handler_req_exec_amf_errorcancelall,
+	message_handler_req_exec_amf_readinessstateset,
+	message_handler_req_exec_amf_hastateset,
+};
+
+/*
+ * Exports the interface for the service
+ */
+struct service_handler amf_service_handler = {
+	libais_handler_fns:			amf_libais_handler_fns,
+	libais_handler_fns_count:	sizeof (amf_libais_handler_fns) / sizeof (int (*)),
+	aisexec_handler_fns:		amf_aisexec_handler_fns,
+	aisexec_handler_fns_count:	sizeof (amf_aisexec_handler_fns) / sizeof (int (*)),
+	confchg_fn:					0,
+	libais_init_fn:				message_handler_req_amf_init,
+	libais_exit_fn:				amfApiFinalize,
+	aisexec_init_fn:			amfExecutiveInitialize
+};
+
+static void grow_amf_track_table (int fd, int growby)
+{
+	struct libamf_ci_trackentry *tracks;
+	int newsize;
+	int currsize = connections[fd].ais_ci.u.libamf_ci.trackEntries;
+
+	
+	newsize = growby + currsize;
+
+	if (newsize > currsize) {
+		tracks = (struct libamf_ci_trackentry *)mempool_realloc (connections[fd].ais_ci.u.libamf_ci.tracks,
+			(newsize) * sizeof (struct libamf_ci_trackentry));
+		if (tracks == 0) {
+#ifdef DEBUG
+			printf ("grow_amf_track_table: out of memory, woops\n");
+#endif
+// TODO
+			exit (1);
+		}
+		memset (&tracks[currsize], 0, growby * sizeof (struct libamf_ci_trackentry));
+		connections[fd].ais_ci.u.libamf_ci.trackEntries = newsize;
+		connections[fd].ais_ci.u.libamf_ci.tracks = tracks;
+	}
+}
+
+void componentUnregister (
+	struct saAmfComponent *component)
+{
+	struct req_exec_amf_componentunregister req_exec_amf_componentunregister;
+	struct iovec iovecs[2];
+
+	/*
+	 * This only works on local components
+	 */
+	if (component == 0 || component->local != 1) {
+		return;
+	}
+	log_printf (LOG_LEVEL_DEBUG, "componentUnregister: unregistering component %s\n",
+		getSaNameT (&component->name));
+	component->probableCause = SA_AMF_NOT_RESPONDING;
+
+	req_exec_amf_componentunregister.header.magic = MESSAGE_MAGIC;
+	req_exec_amf_componentunregister.header.size = sizeof (struct req_exec_amf_componentunregister);
+	req_exec_amf_componentunregister.header.id = MESSAGE_REQ_EXEC_AMF_COMPONENTUNREGISTER;
+
+	req_exec_amf_componentunregister.source.fd = 0;
+	req_exec_amf_componentunregister.source.in_addr.s_addr = 0;
+
+	memset (&req_exec_amf_componentunregister.req_lib_amf_componentunregister,
+		0, sizeof (struct req_lib_amf_componentunregister));
+	memcpy (&req_exec_amf_componentunregister.req_lib_amf_componentunregister.compName,
+		&component->name,
+		sizeof (SaNameT));
+
+	iovecs[0].iov_base = &req_exec_amf_componentunregister;
+	iovecs[0].iov_len = sizeof (req_exec_amf_componentunregister);
+
+	gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+}
+
+#ifdef COMPILE_OUT
+This should be used for a partition I think
+// This should be used for partition changes
+void enumerateComponents (
+	void (*function)(struct saAmfComponent *, void *data),
+	void *data)
+{
+	struct list_head *AmfGroupList;
+	struct list_head *AmfUnitList;
+	struct list_head *AmfComponentList;
+
+	struct saAmfGroup *saAmfGroup;
+	struct saAmfUnit *AmfUnit;
+	struct saAmfComponent *AmfComponent;
+
+
+	/*
+	 * Search all groups
+	 */
+	for (AmfGroupList = saAmfGroupHead.next;
+		AmfGroupList != &saAmfGroupHead;
+		AmfGroupList = AmfGroupList->next) {
+
+		saAmfGroup = list_entry (AmfGroupList,
+			struct saAmfGroup, saAmfGroupList);
+
+		/*
+		 * Search all units
+		 */
+		for (AmfUnitList = saAmfGroup->saAmfUnitHead.next;
+			AmfUnitList != &saAmfGroup->saAmfUnitHead;
+			AmfUnitList = AmfUnitList->next) {
+
+			AmfUnit = list_entry (AmfUnitList,
+				struct saAmfUnit, saAmfUnitList);
+
+			/*
+			 * Search all components
+			 */
+			for (AmfComponentList = AmfUnit->saAmfComponentHead.next;
+				AmfComponentList != &AmfUnit->saAmfComponentHead;
+				AmfComponentList = AmfComponentList->next) {
+
+				AmfComponent = list_entry (AmfComponentList,
+					struct saAmfComponent, saAmfComponentList);
+
+				function (AmfComponent, data);
+			}
+		}
+	}
+}
+#endif
+
+int activeServiceUnitsCount (struct saAmfGroup *saAmfGroup) {
+	struct saAmfUnit *saAmfUnit;
+	struct saAmfComponent *saAmfComponent;
+	struct list_head *saAmfComponentList;
+	struct list_head *saAmfUnitList;
+	int activeServiceUnits = 0;
+	int thisServiceUnitActive;
+
+	/*
+	 * Search all units
+	 */
+	for (activeServiceUnits = 0, saAmfUnitList = saAmfGroup->saAmfUnitHead.next;
+		saAmfUnitList != &saAmfGroup->saAmfUnitHead;
+		saAmfUnitList = saAmfUnitList->next) {
+
+		saAmfUnit = list_entry (saAmfUnitList,
+			struct saAmfUnit, saAmfUnitList);
+
+		/*
+		 * Search all components
+		 */
+		for (thisServiceUnitActive = 1, saAmfComponentList = saAmfUnit->saAmfComponentHead.next;
+			saAmfComponentList != &saAmfUnit->saAmfComponentHead;
+			saAmfComponentList = saAmfComponentList->next) {
+
+			saAmfComponent = list_entry (saAmfComponentList,
+				struct saAmfComponent, saAmfComponentList);
+
+			if (saAmfComponent->currentHAState != SA_AMF_ACTIVE) {
+				thisServiceUnitActive = 0;
+			}
+		}
+		/*
+		 * If all components are active in service unit, count service unit as active
+	 	 */
+		if (thisServiceUnitActive) {
+			activeServiceUnits += 1;
+		}
+	}
+
+	return (activeServiceUnits);
+}
+
+#ifdef CONFIG_TODO
+This should be sent after a service unit is made out of service
+
+void CSIRemove (int fd)
+{
+	struct res_amf_csiremovecallback res_amf_csiremovecallback;
+		
+	if (connections[fd].active == 0 ||
+		connections[fd].service != SOCKET_SERVICE_AMF) {
+
+		return;
+	}
+
+	log_printf (LOG_NOTICE_DEBUG, "executing CSI remove callback into API\n");
+
+	res_amf_csiremovecallback.header.magic = MESSAGE_MAGIC;
+	res_amf_csiremovecallback.header.id = MESSAGE_RES_AMF_CSIREMOVECALLBACK;
+	res_amf_csiremovecallback.header.size = sizeof (struct res_amf_csiremovecallback);
+	res_amf_csiremovecallback.invocation =
+		req_amf_response_set (
+		MESSAGE_REQ_AMF_RESPONSE_SAAMFCSIREMOVECALLBACK,
+		fd);
+
+	memcpy (&res_amf_csiremovecallback.compName,
+		&connections[fd].component->name, sizeof (SaNameT));
+	memcpy (&res_amf_csiremovecallback.csiName,
+		&connections[fd].component->saAmfProtectionGroup->name, sizeof (SaNameT));
+
+	res_amf_csiremovecallback.csiFlags = SA_AMF_CSI_ALL_INSTANCES;
+	libais_send_response (fd, &res_amf_csiremovecallback,
+		sizeof (struct res_amf_csiremovecallback));
+}
+#endif
+
+void haStateSetApi (struct saAmfComponent *component, SaAmfHAStateT haState)
+{
+	struct res_amf_csisetcallback res_amf_csisetcallback;
+
+	log_printf (LOG_LEVEL_DEBUG, "sending ha state to API\n");
+
+	if (component->local != 1) {
+		return;
+	}
+	if (component->probableCause == SA_AMF_NOT_RESPONDING) {
+		return;
+	}
+	/*
+	 * this should be an assertion
+	 */
+	if (connections[component->fd].active == 0 ||
+		connections[component->fd].service != SOCKET_SERVICE_AMF) {
+		return;
+	}
+
+	res_amf_csisetcallback.header.magic = MESSAGE_MAGIC;
+	res_amf_csisetcallback.header.id = MESSAGE_RES_AMF_CSISETCALLBACK;
+	res_amf_csisetcallback.header.size = sizeof (struct res_amf_csisetcallback);
+	res_amf_csisetcallback.invocation =
+		req_amf_response_set (
+		MESSAGE_REQ_AMF_RESPONSE_SAAMFCSISETCALLBACK,
+		component->fd);
+	memcpy (&res_amf_csisetcallback.compName,
+		&component->name, sizeof (SaNameT));
+	memcpy (&res_amf_csisetcallback.csiName,
+		&component->saAmfProtectionGroup->name, sizeof (SaNameT));
+	res_amf_csisetcallback.csiFlags = SA_AMF_CSI_ALL_INSTANCES;
+	res_amf_csisetcallback.haState = haState;
+	// TODO set activeCompName to correct component name
+	memcpy (&res_amf_csisetcallback.activeCompName,
+		&component->name, sizeof (SaNameT));
+	res_amf_csisetcallback.transitionDescriptor = SA_AMF_CSI_NEW_ASSIGN;
+
+	component->newHAState = haState;
+
+	libais_send_response (component->fd, &res_amf_csisetcallback,
+		sizeof (struct res_amf_csisetcallback));
+}
+
+#ifdef COMPILE_OUT
+
+void haStateSetClusterInit (
+	int fd,
+	struct saAmfComponent *saAmfComponent)
+{
+	struct req_exec_amf_hastatesetcluster req_exec_amf_hastatesetcluster;
+
+	return;
+	req_exec_amf_hastatesetcluster.header.magic = MESSAGE_MAGIC;
+	req_exec_amf_hastatesetcluster.header.id = MESSAGE_REQ_EXEC_AMF_HASTATESET;
+	req_exec_amf_hastatesetcluster.header.size = sizeof (struct req_exec_amf_hastatesetcluster);
+	memcpy (&req_exec_amf_hastatesetcluster.compName,
+		&saAmfComponent->name, sizeof (SaNameT));
+	req_exec_amf_hastatesetcluster.haState = saAmfComponent->currentHAState;
+
+	log_printf (LOG_LEVEL_DEBUG, "Sending init ha state message to cluster node to set ha state of component %s\n", getSaNameT (&saAmfComponent->name));
+	log_printf (LOG_LEVEL_DEBUG, "ha state is %d\n", saAmfComponent->currentHAState);
+
+	libais_send_response (fd, &req_exec_amf_hastatesetcluster,
+		sizeof (struct req_exec_amf_hastatesetcluster));
+}
+#endif
+
+void haStateSetCluster (
+	struct saAmfComponent *component,
+	SaAmfHAStateT haState)
+{
+
+	struct req_exec_amf_hastateset req_exec_amf_hastateset;
+	struct iovec iovecs[2];
+
+	req_exec_amf_hastateset.header.magic = MESSAGE_MAGIC;
+	req_exec_amf_hastateset.header.id = MESSAGE_REQ_EXEC_AMF_HASTATESET;
+	req_exec_amf_hastateset.header.size = sizeof (struct req_exec_amf_hastateset);
+	memcpy (&req_exec_amf_hastateset.compName, &component->name, sizeof (SaNameT));
+	req_exec_amf_hastateset.haState = haState;
+
+	log_printf (LOG_LEVEL_DEBUG, "Sending ha state to cluster for component %s\n", getSaNameT (&component->name));
+	log_printf (LOG_LEVEL_DEBUG, "ha state is %d\n", haState);
+
+	iovecs[0].iov_base = &req_exec_amf_hastateset;
+	iovecs[0].iov_len = sizeof (req_exec_amf_hastateset);
+
+	gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+}
+
+void readinessStateSetApi (struct saAmfComponent *component,
+	SaAmfReadinessStateT readinessState)
+{
+	struct res_amf_readinessstatesetcallback res_amf_readinessstatesetcallback;
+
+	/*
+	 * If component is local, don't request service from API
+	 */
+	if (component->local != 1) {
+		return;
+	}
+	if (component->probableCause == SA_AMF_NOT_RESPONDING) {
+		return;
+	}
+		
+	/*
+	 * this should be an assertion
+	 */
+	if (connections[component->fd].active == 0 ||
+		connections[component->fd].service != SOCKET_SERVICE_AMF) {
+
+		return;
+	}
+
+	res_amf_readinessstatesetcallback.header.magic = MESSAGE_MAGIC;
+	res_amf_readinessstatesetcallback.header.id = MESSAGE_RES_AMF_READINESSSTATESETCALLBACK;
+	res_amf_readinessstatesetcallback.header.size = sizeof (struct res_amf_readinessstatesetcallback);
+	res_amf_readinessstatesetcallback.invocation =
+		req_amf_response_set (
+		MESSAGE_REQ_AMF_RESPONSE_SAAMFREADINESSSTATESETCALLBACK,
+		component->fd);
+	memcpy (&res_amf_readinessstatesetcallback.compName,
+		&connections[component->fd].component->name, sizeof (SaNameT));
+	res_amf_readinessstatesetcallback.readinessState = readinessState;
+	connections[component->fd].component->newReadinessState = readinessState;
+
+	log_printf (LOG_LEVEL_DEBUG, "Setting component->fd %d to readiness state %d\n", component->fd, readinessState);
+
+	libais_send_response (component->fd, &res_amf_readinessstatesetcallback,
+		sizeof (struct res_amf_readinessstatesetcallback));
+}
+
+#ifdef COMPILE_OUT
+void readinessStateSetClusterInit (
+	int fd,
+	struct saAmfComponent *saAmfComponent)
+{
+
+	struct req_exec_amf_readinessstatesetcluster req_exec_amf_readinessstatesetcluster;
+
+	return;
+	req_exec_amf_readinessstatesetcluster.header.magic = MESSAGE_MAGIC;
+	req_exec_amf_readinessstatesetcluster.header.id = MESSAGE_REQ_EXEC_AMF_READINESSSTATESET;
+	req_exec_amf_readinessstatesetcluster.header.size = sizeof (struct req_exec_amf_readinessstateset);
+	memcpy (&req_exec_amf_readinessstatesetcluster.compName,
+		&saAmfComponent->name, sizeof (SaNameT));
+	req_exec_amf_readinessstatesetcluster.readinessState = saAmfComponent->currentReadinessState;
+
+	log_printf (LOG_LEVEL_DEBUG, "Sending init message to one cluster node to set readiness state of component %s\n", getSaNameT (&saAmfComponent->name));
+	log_printf (LOG_LEVEL_DEBUG, "readiness state is %d\n", saAmfComponent->currentReadinessState);
+
+	libais_send_response (fd, &req_exec_amf_readinessstatesetcluster,
+		sizeof (struct req_exec_amf_readinessstatesetcluster));
+}
+#endif
+
+void readinessStateSetCluster (
+	struct saAmfComponent *component,
+	SaAmfReadinessStateT readinessState)
+{
+
+	struct req_exec_amf_readinessstateset req_exec_amf_readinessstateset;
+	struct iovec iovecs[2];
+
+	req_exec_amf_readinessstateset.header.magic = MESSAGE_MAGIC;
+	req_exec_amf_readinessstateset.header.id = MESSAGE_REQ_EXEC_AMF_READINESSSTATESET;
+	req_exec_amf_readinessstateset.header.size = sizeof (struct req_exec_amf_readinessstateset);
+	memcpy (&req_exec_amf_readinessstateset.compName, &component->name, sizeof (SaNameT));
+	req_exec_amf_readinessstateset.readinessState = readinessState;
+
+	log_printf (LOG_LEVEL_DEBUG, "Sending message to all cluster nodes to set readiness state of component %s\n",
+		getSaNameT (&component->name));
+	log_printf (LOG_LEVEL_DEBUG, "readiness state is %d\n", readinessState);
+
+	iovecs[0].iov_base = &req_exec_amf_readinessstateset;
+	iovecs[0].iov_len = sizeof (req_exec_amf_readinessstateset);
+
+	gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+}
+
+#ifdef CMOPILE_OUT
+void enumerateComponentsClusterInit (
+	struct saAmfComponent *component,
+	void *data)
+{
+	int fd = (int)data;
+
+	return;
+	readinessStateSetClusterInit (fd, component);
+	haStateSetClusterInit (fd, component);
+}
+#endif
+
+static void dsmDisabledUnlockedRegisteredOrErrorCancel (
+	struct saAmfComponent *component)
+{
+	struct saAmfUnit *unit;
+	struct list_head *list;
+	int serviceUnitEnabled;
+	
+	log_printf (LOG_LEVEL_DEBUG, "dsmDisabledUnlockedRegisteredOrErrorCancel for %s\n",
+		getSaNameT (&component->name));
+
+	unit = component->saAmfUnit;
+	for (serviceUnitEnabled = 1, list = unit->saAmfComponentHead.next;
+		list != &unit->saAmfComponentHead;
+		list = list->next) {
+
+		component = list_entry (list,
+			struct saAmfComponent, saAmfComponentList);
+
+		if (component->registered == 0 ||
+			component->probableCause) {
+			log_printf (LOG_LEVEL_DEBUG, "dsm: Can't transition states, found component not registered or failed.\n", getSaNameT (&component->name));
+			serviceUnitEnabled = 0;
+			break;
+		}
+	}
+	if (serviceUnitEnabled == 1) {
+		log_printf (LOG_LEVEL_DEBUG, "dsm entering AMF_ENABLED_UNLOCKED state.\n");
+		component->saAmfUnit->operationalAdministrativeState = AMF_ENABLED_UNLOCKED;
+		component->disabledUnlockedState = -1; // SHOULD BE INVALID
+		component->enabledUnlockedState = AMF_ENABLED_UNLOCKED_INITIAL;
+		dsm (component);
+	}
+}
+
+static void dsmDisabledUnlockedFailed (
+	struct saAmfComponent *component)
+{
+	struct saAmfUnit *unit;
+	struct list_head *list;
+
+	unit = component->saAmfUnit;
+
+	for (list = unit->saAmfComponentHead.next;
+		list != &unit->saAmfComponentHead;
+		list = list->next) {
+
+		component = list_entry (list, struct saAmfComponent, saAmfComponentList);
+
+		log_printf (LOG_LEVEL_DEBUG, "dsmDisabledUnlockedFailed: for %s.\n",
+			getSaNameT (&component->name));
+		switch (component->enabledUnlockedState) {
+    	case AMF_ENABLED_UNLOCKED_IN_SERVICE_REQUESTED:
+    	case AMF_ENABLED_UNLOCKED_IN_SERVICE_COMPLETED:
+			component->disabledUnlockedState = AMF_DISABLED_UNLOCKED_OUT_OF_SERVICE_REQUESTED;
+			if (component->probableCause == SA_AMF_NOT_RESPONDING) {
+				readinessStateSetCluster (component, SA_AMF_OUT_OF_SERVICE);
+			} else {
+				readinessStateSetApi (component, SA_AMF_OUT_OF_SERVICE);
+			}
+			break;
+
+    	case AMF_ENABLED_UNLOCKED_ACTIVE_REQUESTED:
+    	case AMF_ENABLED_UNLOCKED_ACTIVE_COMPLETED:
+    	case AMF_ENABLED_UNLOCKED_STANDBY_REQUESTED:
+    	case AMF_ENABLED_UNLOCKED_STANDBY_COMPLETED:
+			component->disabledUnlockedState = AMF_DISABLED_UNLOCKED_QUIESCED_REQUESTED;
+			if (component->probableCause == SA_AMF_NOT_RESPONDING) {
+				haStateSetCluster (component, SA_AMF_QUIESCED);
+			} else {
+				haStateSetApi (component, SA_AMF_QUIESCED);
+			}
+			poll_timer_delete (aisexec_poll_handle,
+				component->timer_healthcheck);
+			component->timer_healthcheck = 0;
+			break;
+
+		default:
+			log_printf (LOG_LEVEL_DEBUG, "invalid case 5 %d\n", component->enabledUnlockedState);
+			break;
+		}
+	}
+}
+
+static void dsmDisabledUnlockedQuiescedRequested (
+	struct saAmfComponent *component)
+{
+	component->disabledUnlockedState = AMF_DISABLED_UNLOCKED_QUIESCED_COMPLETED;
+	dsm (component);
+}
+
+static void dsmDisabledUnlockedQuiescedCompleted (
+	struct saAmfComponent *component)
+{
+	struct saAmfUnit *unit;
+	struct list_head *list;
+	int serviceUnitQuiesced;
+	
+	unit = component->saAmfUnit;
+	for (serviceUnitQuiesced = 1, list = unit->saAmfComponentHead.next;
+		list != &unit->saAmfComponentHead;
+		list = list->next) {
+
+		component = list_entry (list, struct saAmfComponent, saAmfComponentList);
+
+		if (component->probableCause != SA_AMF_NOT_RESPONDING && component->registered) {
+			if (component->currentHAState != SA_AMF_QUIESCED) {
+				log_printf (LOG_LEVEL_DEBUG, "dsm: Can't transition states, found component not quiesced.\n", getSaNameT (&component->name));
+				serviceUnitQuiesced = 0;
+				break;
+			}
+		}
+	}
+	if (serviceUnitQuiesced == 1) {
+		log_printf (LOG_LEVEL_DEBUG, "All components have quiesced, Quiescing completed\n");
+		for (list = unit->saAmfComponentHead.next;
+			list != &unit->saAmfComponentHead;
+			list = list->next) {
+
+			component = list_entry (list, struct saAmfComponent, saAmfComponentList);
+
+			log_printf (LOG_LEVEL_DEBUG, "dsm: Sending readiness state set to OUTOFSERVICE for comp %s.\n",
+				getSaNameT (&component->name));
+			readinessStateSetApi (component, SA_AMF_OUT_OF_SERVICE);
+			component->disabledUnlockedState = AMF_DISABLED_UNLOCKED_OUT_OF_SERVICE_REQUESTED;
+		}
+	}
+}
+
+static void dsmDisabledUnlockedOutOfServiceRequested (
+	struct saAmfComponent *component)
+{
+	component->disabledUnlockedState = AMF_DISABLED_UNLOCKED_OUT_OF_SERVICE_COMPLETED;
+	dsm (component);
+}
+
+static void dsmDisabledUnlockedOutOfServiceCompleted (
+	struct saAmfComponent *component)
+{
+	struct saAmfUnit *unit;
+	struct list_head *list;
+	int serviceUnitOutOfService;
+	struct saAmfGroup *group = 0;
+	struct list_head *comp_list = 0;
+	struct list_head *unit_list = 0;
+	int serviceUnitInStandby = 0;
+
+	/*
+	 * Once all components of a service unit are out of service,
+	 * activate another service unit in standby
+	 */
+	log_printf (LOG_LEVEL_DEBUG, "dsmDisabledUnlockedOutOfServiceCompleted: component out of service %s\n", getSaNameT (&component->name));
+	/*
+	 * Determine if all components have responded to going out of service
+	 */
+	
+	unit = component->saAmfUnit;
+	for (serviceUnitOutOfService = 1, list = unit->saAmfComponentHead.next;
+		list != &unit->saAmfComponentHead;
+		list = list->next) {
+
+		component = list_entry (list, struct saAmfComponent, saAmfComponentList);
+
+		if (component->probableCause != SA_AMF_NOT_RESPONDING && component->registered) {
+			if (component->currentReadinessState != SA_AMF_OUT_OF_SERVICE) {
+				log_printf (LOG_LEVEL_DEBUG, "dsm: Can't transition states, found component not quiesced.\n", getSaNameT (&component->name));
+				serviceUnitOutOfService = 0;
+				break;
+			}
+		}
+	}
+
+	group = unit->saAmfGroup;
+	if (serviceUnitOutOfService == 1) {
+		log_printf (LOG_LEVEL_DEBUG, "SU has gone out of service.\n");
+		/*
+		 * Search all units
+		 */
+		for (unit_list = group->saAmfUnitHead.next;
+			unit_list != &group->saAmfUnitHead;
+			unit_list = unit_list->next) {
+
+			unit = list_entry (unit_list,
+				struct saAmfUnit, saAmfUnitList);
+
+			log_printf (LOG_LEVEL_DEBUG, "Checking if service unit is in standby %s\n", getSaNameT (&unit->name));
+			/*
+			 * Search all components
+			 */
+			for (serviceUnitInStandby = 1,
+				comp_list = unit->saAmfComponentHead.next;
+				comp_list != &unit->saAmfComponentHead;
+				comp_list = comp_list->next) {
+	
+				component = list_entry (comp_list,
+					struct saAmfComponent, saAmfComponentList);
+	
+				if (component->currentHAState != SA_AMF_STANDBY) {
+					serviceUnitInStandby = 0;
+					break; /* for iteration of service unit components */
+				}
+			}
+			if (serviceUnitInStandby) {
+				break; /* for iteration of service group's service units */
+			}
+		}
+
+		/*
+		 * All components in service unit are standby, activate standby service unit
+		 */
+		if (serviceUnitInStandby) {
+			log_printf (LOG_LEVEL_DEBUG, "unit in standby\n");
+			for (list = unit->saAmfComponentHead.next;
+				list != &unit->saAmfComponentHead;
+				list = list->next) {
+	
+				component = list_entry (list,
+				struct saAmfComponent, saAmfComponentList);
+	
+				haStateSetApi (component, SA_AMF_ACTIVE);
+			}
+		} else {
+			log_printf (LOG_LEVEL_DEBUG, "Can't activate standby service unit because no standby is available.\n");
+		}
+	}
+}
+
+static void dsmEnabledUnlockedInitial (
+	struct saAmfComponent *component)
+{ 
+	struct saAmfUnit *unit;
+	struct list_head *list;
+
+	unit = component->saAmfUnit;
+	for (list = unit->saAmfComponentHead.next;
+		list != &unit->saAmfComponentHead;
+		list = list->next) {
+
+		component = list_entry (list, struct saAmfComponent, saAmfComponentList);
+
+		readinessStateSetApi (component, SA_AMF_IN_SERVICE);
+		log_printf (LOG_LEVEL_DEBUG, "dsm: telling component %s to enter SA_AMF_IN_SERVICE.\n",
+			getSaNameT (&component->name));
+		component->enabledUnlockedState = AMF_ENABLED_UNLOCKED_IN_SERVICE_REQUESTED;
+	}
+}
+static void dsmEnabledUnlockedInServiceRequested (
+	struct saAmfComponent *component)
+{
+	struct saAmfUnit *unit;
+	struct list_head *list;
+	int in_service;
+
+	log_printf (LOG_LEVEL_DEBUG, "dsmEnabledUnlockedInServiceRequested %s.\n", getSaNameT (&component->name));
+	
+	unit = component->saAmfUnit;
+	for (in_service = 1, list = unit->saAmfComponentHead.next;
+		list != &unit->saAmfComponentHead;
+		list = list->next) {
+
+		component = list_entry (list, struct saAmfComponent, saAmfComponentList);
+
+		if (component->currentReadinessState != SA_AMF_IN_SERVICE) {
+			log_printf (LOG_LEVEL_DEBUG, "dsm: Found atleast one component not in service\n");
+			in_service = 0;
+			break;
+		}
+	}
+	if (in_service) {
+		log_printf (LOG_LEVEL_DEBUG, "DSM determined component is in service\n");
+		
+		component->enabledUnlockedState = AMF_ENABLED_UNLOCKED_IN_SERVICE_COMPLETED;
+		dsm (component);
+	}
+}
+
+static void dsmEnabledUnlockedInServiceCompleted (
+	struct saAmfComponent *component)
+{
+	struct saAmfUnit *unit;
+	struct list_head *list;
+	SaAmfHAStateT newHaState;
+	int activeServiceUnits;
+
+	log_printf (LOG_LEVEL_DEBUG, "dsmEnabledUnlockedInServiceCompleted %s.\n", getSaNameT (&component->name));
+
+	unit = component->saAmfUnit;
+	for (list = unit->saAmfComponentHead.next;
+		list != &unit->saAmfComponentHead;
+		list = list->next) {
+
+		component = list_entry (list,
+			struct saAmfComponent, saAmfComponentList);
+
+		log_printf (LOG_LEVEL_DEBUG, "Requesting component go active.\n", getSaNameT (&component->name));
+
+		/*
+		 * Count number of active service units
+		 */
+		activeServiceUnits = activeServiceUnitsCount (component->saAmfUnit->saAmfGroup);
+		if (activeServiceUnits < component->saAmfUnit->saAmfGroup->saAmfActiveUnitsDesired) {
+
+			newHaState = SA_AMF_ACTIVE;
+			log_printf (LOG_LEVEL_DEBUG, "Setting ha state of component %s to SA_AMF_ACTIVE\n", getSaNameT (&component->name));
+			component->enabledUnlockedState = AMF_ENABLED_UNLOCKED_ACTIVE_REQUESTED;
+		} else {
+			newHaState = SA_AMF_STANDBY;
+			log_printf (LOG_LEVEL_DEBUG, "Setting ha state of component %s to SA_AMF_STANDBY\n", getSaNameT (&component->name));
+			component->enabledUnlockedState = AMF_ENABLED_UNLOCKED_STANDBY_REQUESTED;
+		}
+		haStateSetApi (component, newHaState);
+	}
+}
+	
+void dsmEnabledUnlockedActiveRequested (
+	struct saAmfComponent *component)
+{
+	if (component->local == 1) {
+		log_printf (LOG_LEVEL_DEBUG, "Adding healthcheck timer\n");
+		poll_timer_add (aisexec_poll_handle,
+			component->healthcheckInterval,
+			(void *)component->fd,
+			timer_function_libamf_healthcheck,
+			&component->timer_healthcheck);
+	}
+
+	component->enabledUnlockedState = AMF_ENABLED_UNLOCKED_ACTIVE_COMPLETED;
+}
+
+void dsmEnabledUnlockedStandbyRequested (
+	struct saAmfComponent *component)
+{
+	if (component->local == 1) {
+
+		log_printf (LOG_LEVEL_DEBUG, "Adding healthcheck timer\n");
+
+		poll_timer_add (aisexec_poll_handle,
+			component->healthcheckInterval,
+			(void *)component->fd,
+			timer_function_libamf_healthcheck,
+			&component->timer_healthcheck);
+	}
+
+	component->enabledUnlockedState = AMF_ENABLED_UNLOCKED_STANDBY_COMPLETED;
+}
+
+void dsmEnabledUnlockedTransitionDisabledUnlocked (
+	struct saAmfComponent *component)
+{
+	struct saAmfUnit *unit;
+	struct list_head *list;
+
+	unit = component->saAmfUnit;
+	for (list = unit->saAmfComponentHead.next;
+		list != &unit->saAmfComponentHead;
+		list = list->next) {
+
+		component = list_entry (list, struct saAmfComponent, saAmfComponentList);
+
+		log_printf (LOG_LEVEL_DEBUG,  "Requesting component %s transition to disabled.\n",
+			getSaNameT (&component->name));
+
+		component->saAmfUnit->operationalAdministrativeState = AMF_DISABLED_UNLOCKED;
+		component->disabledUnlockedState = AMF_DISABLED_UNLOCKED_FAILED;
+	}
+	dsm (component);
+}
+	
+static void dsmEnabledUnlocked (
+	struct saAmfComponent *component)
+{
+	switch (component->enabledUnlockedState) {
+		case AMF_ENABLED_UNLOCKED_INITIAL:
+			dsmEnabledUnlockedInitial (component);
+			break;
+		case AMF_ENABLED_UNLOCKED_IN_SERVICE_REQUESTED:
+			dsmEnabledUnlockedInServiceRequested (component);
+			break;
+		case AMF_ENABLED_UNLOCKED_IN_SERVICE_COMPLETED:
+			dsmEnabledUnlockedInServiceCompleted (component);
+			break;
+		case AMF_ENABLED_UNLOCKED_ACTIVE_REQUESTED:
+			dsmEnabledUnlockedActiveRequested (component);
+			break;
+		case AMF_ENABLED_UNLOCKED_ACTIVE_COMPLETED:
+			/* noop - operational state */
+			break;
+		case AMF_ENABLED_UNLOCKED_STANDBY_REQUESTED:
+			dsmEnabledUnlockedActiveRequested (component);
+			break;
+		case AMF_ENABLED_UNLOCKED_STANDBY_COMPLETED:
+			/* noop - operational state */
+			break;
+			
+		default:
+			log_printf (LOG_LEVEL_DEBUG, "dsmEnabledUnlocked: unkown state machine value.\n");
+	}
+}
+
+static void dsmDisabledUnlocked (
+	struct saAmfComponent *component)
+{
+	log_printf (LOG_LEVEL_DEBUG, "dsmDisabledUnlocked for %s state %d\n",
+		getSaNameT (&component->name),
+		component->disabledUnlockedState);
+
+	switch (component->disabledUnlockedState) {
+		case AMF_DISABLED_UNLOCKED_REGISTEREDORERRORCANCEL:
+			dsmDisabledUnlockedRegisteredOrErrorCancel (component);
+			break;
+
+		case AMF_DISABLED_UNLOCKED_FAILED:
+			dsmDisabledUnlockedFailed (component);
+			break;
+
+		case AMF_DISABLED_UNLOCKED_QUIESCED_REQUESTED:
+			dsmDisabledUnlockedQuiescedRequested (component);
+			break;
+
+		case AMF_DISABLED_UNLOCKED_QUIESCED_COMPLETED:
+			dsmDisabledUnlockedQuiescedCompleted (component);
+			break;
+
+		case AMF_DISABLED_UNLOCKED_OUT_OF_SERVICE_REQUESTED:
+			dsmDisabledUnlockedOutOfServiceRequested (component);
+			break;
+
+		case AMF_DISABLED_UNLOCKED_OUT_OF_SERVICE_COMPLETED:
+			dsmDisabledUnlockedOutOfServiceCompleted (component);
+			break;
+
+		default:
+			log_printf (LOG_LEVEL_DEBUG, "dsmDisabledUnlocked: unkown state machine value %d.\n", component->disabledUnlockedState);
+	}
+}
+
+static void dsm (
+	struct saAmfComponent *component)
+{
+	log_printf (LOG_LEVEL_DEBUG, "dsm for component %s\n", getSaNameT (&component->name));
+
+	switch (component->saAmfUnit->operationalAdministrativeState) {
+		case AMF_DISABLED_UNLOCKED:
+			dsmDisabledUnlocked (component);
+			break;
+		case AMF_ENABLED_UNLOCKED:
+			dsmEnabledUnlocked (component);
+			break;
+/*
+	AMF_DISABLED_LOCKED,
+	AMF_ENABLED_STOPPING
+*/
+		default:
+			log_printf (LOG_LEVEL_DEBUG, "dsm: unknown state machine value.\n");
+	}
+}
+
+#if 0
+/*
+ * This is currently unused, but executes the componentterminatecallback
+ * callback in the AMF api.
+ */
+void componentTerminate (int fd)
+{
+	struct res_amf_componentterminatecallback res_amf_componentterminatecallback;
+
+	res_amf_componentterminatecallback.header.magic = MESSAGE_MAGIC;
+	res_amf_componentterminatecallback.header.id = MESSAGE_RES_AMF_COMPONENTTERMINATECALLBACK;
+	res_amf_componentterminatecallback.header.size = sizeof (struct res_amf_componentterminatecallback);
+	res_amf_componentterminatecallback.invocation =
+		req_amf_response_set (
+		MESSAGE_REQ_AMF_RESPONSE_SAAMFCOMPONENTTERMINATECALLBACK,
+		fd);
+	memcpy (&res_amf_componentterminatecallback.compName,
+		&connections[fd].component->name, sizeof (SaNameT));
+	connections[fd].component->newReadinessState = SA_AMF_OUT_OF_SERVICE;
+
+	log_printf (LOG_LEVEL_DEBUG, "terminating component on fd %d\n", fd);
+	libais_send_response (fd, &res_amf_componentterminatecallback,
+		sizeof (struct res_amf_componentterminatecallback));
+}
+#endif /* Not currently implemented */
+
+void errorReport (
+	struct saAmfComponent *component,
+	SaAmfProbableCauseT probableCause)
+{
+	struct req_exec_amf_errorreport req_exec_amf_errorreport;
+	struct iovec iovecs[2];
+
+	req_exec_amf_errorreport.header.magic = MESSAGE_MAGIC;
+	req_exec_amf_errorreport.header.size = sizeof (struct req_exec_amf_errorreport);
+	req_exec_amf_errorreport.header.id = MESSAGE_REQ_EXEC_AMF_ERRORREPORT;
+
+	req_exec_amf_errorreport.source.fd = 0;
+	req_exec_amf_errorreport.source.in_addr.s_addr = 0;
+	memcpy (&req_exec_amf_errorreport.req_lib_amf_errorreport.erroneousComponent,
+		&component->name,
+		sizeof (SaNameT));
+	req_exec_amf_errorreport.req_lib_amf_errorreport.errorDescriptor.probableCause = probableCause;
+
+	iovecs[0].iov_base = &req_exec_amf_errorreport;
+	iovecs[0].iov_len = sizeof (req_exec_amf_errorreport);
+
+	gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+}
+
+int healthcheck_instance = 0;
+void timer_function_libamf_healthcheck (void *data) {
+	struct res_amf_healthcheckcallback res_amf_healthcheckcallback;
+	int connection = (int)data;
+
+	res_amf_healthcheckcallback.header.magic = MESSAGE_MAGIC;
+	res_amf_healthcheckcallback.header.id = MESSAGE_RES_AMF_HEALTHCHECKCALLBACK;
+	res_amf_healthcheckcallback.header.size = sizeof (struct res_amf_healthcheckcallback);
+
+	log_printf (LOG_LEVEL_DEBUG, "checking healthcheck on component %s\n",
+		getSaNameT (&connections[connection].component->name));
+	if (connections[connection].component->healthcheck_outstanding == 1) {
+
+		log_printf (LOG_LEVEL_DEBUG, "Healthcheck timed out on component %s\n",
+			getSaNameT (&connections[connection].component->name));
+
+		/*
+		 * Report the error to the rest of the cluster using the normal state machine
+		 */
+		errorReport (connections[connection].component, SA_AMF_NOT_RESPONDING);
+
+		connections[connection].component->healthcheck_outstanding = 2;
+	} else
+	if (connections[connection].component->healthcheck_outstanding == 0) {
+		connections[connection].component->healthcheck_outstanding = 1;
+		/*
+		 * Send healthcheck message
+		 */
+		res_amf_healthcheckcallback.invocation =
+			req_amf_response_set (
+			MESSAGE_REQ_AMF_RESPONSE_SAAMFHEALTHCHECKCALLBACK,
+			connection);
+		memcpy (&res_amf_healthcheckcallback.compName,
+			&connections[connection].component->name,
+			sizeof (SaNameT));
+		res_amf_healthcheckcallback.checkType = SA_AMF_HEARTBEAT;
+
+	log_printf (LOG_LEVEL_DEBUG, "Sending instance %d\n", healthcheck_instance);
+	res_amf_healthcheckcallback.instance = healthcheck_instance++;
+		libais_send_response (connection,
+			&res_amf_healthcheckcallback,
+			sizeof (struct res_amf_healthcheckcallback));
+
+		poll_timer_add (aisexec_poll_handle,
+			connections[connection].component->healthcheckInterval,
+			(void *)connection,
+			timer_function_libamf_healthcheck,
+			&connections[connection].component->timer_healthcheck);
+	}
+}
+
+struct saAmfProtectionGroup *findProtectionGroup (
+	SaNameT *csiName)
+{
+	struct list_head *AmfGroupList;
+	struct list_head *AmfProtectionGroupList;
+
+	struct saAmfGroup *saAmfGroup;
+	struct saAmfProtectionGroup *AmfProtectionGroup;
+
+	/*
+	 * Search all groups
+	 */
+	for (AmfGroupList = saAmfGroupHead.next;
+		AmfGroupList != &saAmfGroupHead;
+		AmfGroupList = AmfGroupList->next) {
+
+		saAmfGroup = list_entry (AmfGroupList,
+			struct saAmfGroup, saAmfGroupList);
+
+		/*
+		 * Search all protection groups
+		 */
+		for (AmfProtectionGroupList = saAmfGroup->saAmfProtectionGroupHead.next;
+			AmfProtectionGroupList != &saAmfGroup->saAmfProtectionGroupHead;
+			AmfProtectionGroupList = AmfProtectionGroupList->next) {
+
+			AmfProtectionGroup = list_entry (AmfProtectionGroupList,
+				struct saAmfProtectionGroup, saAmfProtectionGroupList);
+
+			if (SaNameTisNameT (csiName, &AmfProtectionGroup->name)) {
+				return (AmfProtectionGroup);
+			}
+		}
+	}
+	return (0);
+}
+
+struct saAmfComponent *findComponentInProtectionGroup (
+	SaNameT *csiName,
+	SaNameT *compName)
+{
+
+	struct list_head *AmfGroupList = 0;
+	struct list_head *AmfProtectionGroupList = 0;
+	struct list_head *AmfComponentList = 0;
+
+	struct saAmfGroup *saAmfGroup = 0;
+	struct saAmfProtectionGroup *AmfProtectionGroup = 0;
+	struct saAmfComponent *AmfComponent = 0;
+	int found = 0;
+
+	/*
+	 * Search all groups
+	 */
+	for (AmfGroupList = saAmfGroupHead.next;
+		AmfGroupList != &saAmfGroupHead;
+		AmfGroupList = AmfGroupList->next) {
+
+		saAmfGroup = list_entry (AmfGroupList,
+			struct saAmfGroup, saAmfGroupList);
+
+		/*
+		 * Search all protection groups
+		 */
+		for (AmfProtectionGroupList = saAmfGroup->saAmfProtectionGroupHead.next;
+			AmfProtectionGroupList != &saAmfGroup->saAmfProtectionGroupHead;
+			AmfProtectionGroupList = AmfProtectionGroupList->next) {
+
+			AmfProtectionGroup = list_entry (AmfProtectionGroupList,
+				struct saAmfProtectionGroup, saAmfProtectionGroupList);
+
+			if (SaNameTisNameT (csiName, &AmfProtectionGroup->name)) {
+				/*
+				 * Search all components
+				 */
+				for (AmfComponentList = AmfProtectionGroup->saAmfMembersHead.next;
+					AmfComponentList != &AmfProtectionGroup->saAmfMembersHead;
+					AmfComponentList = AmfComponentList->next) {
+
+					AmfComponent = list_entry (AmfComponentList,
+						struct saAmfComponent, saAmfProtectionGroupList);
+
+					if (SaNameTisNameT (compName, &AmfComponent->name)) {
+						found = 1;
+					}
+				}
+			}
+		}
+	}
+
+	if (found) {
+		return (AmfComponent);
+	} else {
+		return (0);
+	}
+}
+
+void sendProtectionGroupNotifications (
+	struct saAmfComponent *changedComponent,
+	SaAmfProtectionGroupChangesT changeToComponent)
+{
+	int fd;
+	int i;
+
+	log_printf (LOG_LEVEL_DEBUG, "sendProtectionGroupNotifications: sending PGs to API.\n");
+
+	for (fd = 0; fd < connection_entries; fd++) {
+		if (connections[fd].active &&
+			connections[fd].service == SOCKET_SERVICE_AMF) {
+
+			for (i = 0; i < connections[fd].ais_ci.u.libamf_ci.trackEntries; i++) {
+				if (connections[fd].ais_ci.u.libamf_ci.tracks[i].active) {
+
+					sendProtectionGroupNotification (fd,
+						connections[fd].ais_ci.u.libamf_ci.tracks[i].notificationBufferAddress, 
+						changedComponent->saAmfProtectionGroup,
+						changedComponent,
+						changeToComponent,
+						connections[fd].ais_ci.u.libamf_ci.tracks[i].trackFlags);
+				} /* if active */
+			} /* for all track entries */
+		} /* if connection active and service is AMF */
+	} /* for all connection entries */
+
+}
+
+void sendProtectionGroupNotification (int fd,
+	SaAmfProtectionGroupNotificationT *notificationBufferAddress,
+	struct saAmfProtectionGroup *amfProtectionGroup,
+	struct saAmfComponent *changedComponent,
+	SaAmfProtectionGroupChangesT changeToComponent,
+	SaUint8T trackFlags)
+{
+	struct res_amf_protectiongrouptrackcallback res_amf_protectiongrouptrackcallback;
+	SaAmfProtectionGroupNotificationT *protectionGroupNotification = 0;
+	int notifyEntries = 0;
+	struct saAmfComponent *component;
+	struct list_head *componentList;
+
+	/*
+	 * Step through all components and generate protection group list for csi
+	 */
+
+	for (componentList = amfProtectionGroup->saAmfMembersHead.next;
+		componentList != &amfProtectionGroup->saAmfMembersHead;
+		componentList = componentList->next) {
+
+		component = list_entry (componentList,
+			struct saAmfComponent, saAmfProtectionGroupList);
+
+		/*
+		 * Generate new track entry for following cases:
+		 * 1. If this component is the changed component and
+		 *    SA_TRACK_CHANGES_ONLY is set
+		 * 2. If track flags indicate SA_TRACK_CURRENT or SA_TRACK_CHANGES
+		 */
+		if (component == changedComponent ||
+			(trackFlags & (SA_TRACK_CURRENT | SA_TRACK_CHANGES))) {
+
+			protectionGroupNotification = (SaAmfProtectionGroupNotificationT *)mempool_realloc (protectionGroupNotification,
+				sizeof (SaAmfProtectionGroupNotificationT) * (notifyEntries + 1));
+			memcpy (&protectionGroupNotification[notifyEntries].member.compName, 
+				&component->name, sizeof (SaNameT));
+			memcpy (&protectionGroupNotification[notifyEntries].member.readinessState, 
+				&component->currentReadinessState, sizeof (SaAmfReadinessStateT));
+			memcpy (&protectionGroupNotification[notifyEntries].member.haState, 
+				&component->currentHAState, sizeof (SaAmfHAStateT));
+			if (component == changedComponent) {
+				protectionGroupNotification[notifyEntries].change = changeToComponent;
+			} else {
+				protectionGroupNotification[notifyEntries].change = SA_AMF_PROTECTION_GROUP_NO_CHANGE;
+			}
+			notifyEntries += 1;
+		}
+	} /* for */
+
+	/*
+	 * Send track callback
+	 */
+	if (notifyEntries) {
+		res_amf_protectiongrouptrackcallback.header.magic = MESSAGE_MAGIC;
+		res_amf_protectiongrouptrackcallback.header.size =
+			sizeof (struct res_amf_protectiongrouptrackcallback) +
+			(notifyEntries * sizeof (SaAmfProtectionGroupNotificationT));
+		res_amf_protectiongrouptrackcallback.header.id = MESSAGE_RES_AMF_PROTECTIONGROUPTRACKCALLBACK;
+		res_amf_protectiongrouptrackcallback.numberOfItems = notifyEntries;
+		res_amf_protectiongrouptrackcallback.numberOfMembers = notifyEntries;
+		memcpy (&res_amf_protectiongrouptrackcallback.csiName,
+			&amfProtectionGroup->name, sizeof (SaNameT));
+
+		res_amf_protectiongrouptrackcallback.notificationBufferAddress = notificationBufferAddress;
+		libais_send_response (fd, &res_amf_protectiongrouptrackcallback,
+			sizeof (struct res_amf_protectiongrouptrackcallback));
+
+		libais_send_response (fd, protectionGroupNotification,
+			sizeof (SaAmfProtectionGroupNotificationT) * notifyEntries);
+
+		mempool_free (protectionGroupNotification);
+	}
+}
+
+/*
+ * The response handler for readiness state set callback
+ */
+static void response_handler_readinessstatesetcallback (int connection,
+	struct req_amf_response *req_amf_response)
+{
+
+	if (req_amf_response->error == SA_OK && connections[connection].component) {
+	log_printf (LOG_LEVEL_DEBUG, "CALLBACK sending readiness state to %s\n", 
+		getSaNameT (&connections[connection].component->name));
+		readinessStateSetCluster (connections[connection].component,
+			connections[connection].component->newReadinessState);
+	}
+}
+
+/* 
+ *	iterate service unit components
+ *		telling all components not already QUIESCING to enter SA_AMF_QUIESCED state
+ */
+static void response_handler_csisetcallback (int connection,
+	struct req_amf_response *req_amf_response)
+{
+
+	if (req_amf_response->error == SA_OK && connections[connection].component) {
+		haStateSetCluster (connections[connection].component,
+			connections[connection].component->newHAState);
+	}
+}
+
+int amfExecutiveInitialize (void)
+{
+	return (0);
+}
+
+int amfApiFinalize (int fd)
+{
+	/*
+	 * Unregister all components registered to this file descriptor
+	 */
+	if (connections[fd].service == SOCKET_SERVICE_AMF) {
+		componentUnregister (connections[fd].component);
+
+	if (connections[fd].component && connections[fd].component->timer_healthcheck) {
+		poll_timer_delete (aisexec_poll_handle,
+			connections[fd].component->timer_healthcheck);
+
+		connections[fd].component->timer_healthcheck = 0;
+	}
+
+		if (connections[fd].ais_ci.u.libamf_ci.tracks) {
+			mempool_free (connections[fd].ais_ci.u.libamf_ci.tracks);
+			connections[fd].ais_ci.u.libamf_ci.tracks = 0;
+		}
+	}
+
+	return (0);
+}
+
+
+static int message_handler_req_exec_amf_componentregister (int fd, void *message)
+{
+	struct req_exec_amf_componentregister *req_exec_amf_componentregister = (struct req_exec_amf_componentregister *)message;
+	struct res_lib_amf_componentregister res_lib_amf_componentregister;
+	struct saAmfComponent *component;
+	struct saAmfComponent *amfProxyComponent;
+	SaErrorT error;
+
+	log_printf (LOG_LEVEL_DEBUG, "Executive: ComponentRegister for component %s\n",
+		getSaNameT (&req_exec_amf_componentregister->req_lib_amf_componentregister.compName));
+
+	/*
+	 * Determine if proxy isn't registered
+	 */
+	error = SA_OK;
+	component = findComponent (&req_exec_amf_componentregister->req_lib_amf_componentregister.compName);
+	amfProxyComponent = findComponent (&req_exec_amf_componentregister->req_lib_amf_componentregister.proxyCompName);
+
+	/*
+	 * If component not in configuration files, return error
+	 */
+	if (component == 0) {
+		error = SA_ERR_NOT_EXIST;
+	}
+
+	/*
+	 * If proxy doesn't exist and isn't registered, return error
+	 */
+	if ((amfProxyComponent == 0 &&
+		req_exec_amf_componentregister->req_lib_amf_componentregister.proxyCompName.length > 0) || 
+		(amfProxyComponent && amfProxyComponent->registered == 0)) {
+
+		error = SA_ERR_NOT_EXIST;
+	}
+
+	/*
+	 * If component already registered, return error
+	 */
+	if (error == SA_OK) {
+		if (component->registered) {
+			error = SA_ERR_EXIST;
+		}
+	}
+
+	/*
+	 * Finally register component and setup links for proxy if
+	 * proxy present
+	 */
+	if (error == SA_OK) {
+		component->local = 0;
+		component->registered = 1;
+		component->fd = req_exec_amf_componentregister->source.fd;
+		component->currentReadinessState = SA_AMF_OUT_OF_SERVICE;
+		component->newReadinessState = SA_AMF_OUT_OF_SERVICE;
+		component->currentHAState = SA_AMF_QUIESCED;
+		component->newHAState = SA_AMF_QUIESCED;
+		component->probableCause = 0;
+		component->enabledUnlockedState = 0;
+		component->disabledUnlockedState = 0;
+
+		if (req_exec_amf_componentregister->req_lib_amf_componentregister.proxyCompName.length > 0) {
+			component->saAmfProxyComponent = amfProxyComponent;
+		}
+	}
+
+	/*
+	 * If this node originated the request to the cluster, respond back
+	 * to the AMF library
+	 */
+	if (req_exec_amf_componentregister->source.in_addr.s_addr == this_ip.sin_addr.s_addr) {
+		if (error == SA_OK) {
+			component->local = 1;
+			connections[req_exec_amf_componentregister->source.fd].component = component;
+		}
+
+		log_printf (LOG_LEVEL_DEBUG, "sending component register response to fd %d\n", req_exec_amf_componentregister->source.fd);
+
+		res_lib_amf_componentregister.header.magic = MESSAGE_MAGIC;
+		res_lib_amf_componentregister.header.size = sizeof (struct res_lib_amf_componentregister);
+		res_lib_amf_componentregister.header.id = MESSAGE_RES_AMF_COMPONENTREGISTER;
+		res_lib_amf_componentregister.error = error;
+
+		libais_send_response (req_exec_amf_componentregister->source.fd, &res_lib_amf_componentregister,
+			sizeof (struct res_lib_amf_componentregister));
+	}
+
+	
+	/*
+	 * If no error on registration, determine if we should enter new state
+	 */
+	if (error == SA_OK) {
+		dsm (component);
+	}
+
+	return (0);
+}
+
+static int message_handler_req_exec_amf_componentunregister (int fd, void *message)
+{
+	struct req_exec_amf_componentunregister *req_exec_amf_componentunregister = (struct req_exec_amf_componentunregister *)message;
+	struct res_lib_amf_componentunregister res_lib_amf_componentunregister;
+	struct saAmfComponent *component;
+	struct saAmfComponent *amfProxyComponent;
+	SaErrorT error;
+
+	log_printf (LOG_LEVEL_DEBUG, "Executive: ComponentUnregister for %s\n",
+		getSaNameT (&req_exec_amf_componentunregister->req_lib_amf_componentunregister.compName));
+
+	component = findComponent (&req_exec_amf_componentunregister->req_lib_amf_componentunregister.compName);
+	amfProxyComponent = findComponent (&req_exec_amf_componentunregister->req_lib_amf_componentunregister.proxyCompName);
+
+	/*
+	 * Check for proxy and component not existing in system
+	 */
+	error = SA_OK;
+	if (component == 0) {
+		error = SA_ERR_NOT_EXIST;
+	}
+	if (req_exec_amf_componentunregister->req_lib_amf_componentunregister.proxyCompName.length > 0) {
+		if (amfProxyComponent) {
+			if (amfProxyComponent->registered == 0) {
+				error = SA_ERR_NOT_EXIST;
+			}
+		} else {
+			error = SA_ERR_NOT_EXIST;
+		}
+	}
+
+	/*
+	 * If there is a proxycompname, make sure it is the proxy
+	 * of compName
+	 */
+	if (error == SA_OK && amfProxyComponent) {
+		if (component->saAmfProxyComponent != amfProxyComponent) {
+			error = SA_ERR_BAD_OPERATION;
+		}
+	}
+
+	/*
+	 * Finally unregister the component
+	 */
+	if (error == SA_OK) {
+		component->registered = 0;
+		dsmEnabledUnlockedTransitionDisabledUnlocked (component);
+	}
+	
+	/*
+	 * If this node originated the request to the cluster, respond back
+	 * to the AMF library
+	 */
+	if (req_exec_amf_componentunregister->source.in_addr.s_addr == this_ip.sin_addr.s_addr) {
+		log_printf (LOG_LEVEL_DEBUG, "sending component unregister response to fd %d\n",
+			req_exec_amf_componentunregister->source.fd);
+
+		res_lib_amf_componentunregister.header.magic = MESSAGE_MAGIC;
+		res_lib_amf_componentunregister.header.size = sizeof (struct res_lib_amf_componentunregister);
+		res_lib_amf_componentunregister.header.id = MESSAGE_RES_AMF_COMPONENTUNREGISTER;
+		res_lib_amf_componentunregister.error = error;
+
+		libais_send_response (req_exec_amf_componentunregister->source.fd,
+			&res_lib_amf_componentunregister, sizeof (struct res_lib_amf_componentunregister));
+	}
+
+	return (0);
+}
+
+static int message_handler_req_exec_amf_errorreport (int fd, void *message)
+{
+	struct req_exec_amf_errorreport *req_exec_amf_errorreport = (struct req_exec_amf_errorreport *)message;
+	struct res_lib_amf_errorreport res_lib_amf_errorreport;
+	struct saAmfComponent *component;
+	SaErrorT error = SA_ERR_BAD_OPERATION;
+
+	log_printf (LOG_LEVEL_DEBUG, "Executive: ErrorReport for %s\n", 
+		getSaNameT (&req_exec_amf_errorreport->req_lib_amf_errorreport.erroneousComponent));
+
+	component = findComponent (&req_exec_amf_errorreport->req_lib_amf_errorreport.erroneousComponent);
+	if (component && component->registered) {
+		component->probableCause = req_exec_amf_errorreport->req_lib_amf_errorreport.errorDescriptor.probableCause;
+
+		/*
+		 * One registered component left, so transition
+		 * SU to failed operational state
+		 */
+		dsmEnabledUnlockedTransitionDisabledUnlocked (component);
+		error = SA_OK;
+	}
+
+	/*
+	 * If this node originated the request to the cluster, respond back
+	 * to the AMF library
+	 */
+	if (req_exec_amf_errorreport->source.in_addr.s_addr == this_ip.sin_addr.s_addr) {
+		log_printf (LOG_LEVEL_DEBUG, "sending error report response to fd %d\n",
+			req_exec_amf_errorreport->source.fd);
+
+		res_lib_amf_errorreport.header.magic = MESSAGE_MAGIC;
+		res_lib_amf_errorreport.header.size = sizeof (struct res_lib_amf_errorreport);
+		res_lib_amf_errorreport.header.id = MESSAGE_RES_AMF_ERRORREPORT;
+		res_lib_amf_errorreport.error = error;
+
+		libais_send_response (req_exec_amf_errorreport->source.fd,
+			&res_lib_amf_errorreport, sizeof (struct res_lib_amf_errorreport));
+	}
+
+	return (0);
+}
+
+static int message_handler_req_exec_amf_errorcancelall (int fd, void *message)
+{
+	struct req_exec_amf_errorcancelall *req_exec_amf_errorcancelall = (struct req_exec_amf_errorcancelall *)message;
+	struct res_lib_amf_errorcancelall res_lib_amf_errorcancelall;
+	struct saAmfComponent *component;
+	SaErrorT error = SA_ERR_BAD_OPERATION;
+
+	log_printf (LOG_LEVEL_DEBUG, "Executive: ErrorCancelAll for %s\n", 
+		getSaNameT (&req_exec_amf_errorcancelall->req_lib_amf_errorcancelall.compName));
+
+	component = findComponent (&req_exec_amf_errorcancelall->req_lib_amf_errorcancelall.compName);
+	if (component && component->registered) {
+		/*
+		 * Mark component in service if its a AMF service
+		 * connected to this aisexec
+		 */
+		if (component->probableCause) {
+			component->probableCause = 0;
+			component->disabledUnlockedState = AMF_DISABLED_UNLOCKED_REGISTEREDORERRORCANCEL;
+			dsm (component);
+		}
+		error = SA_OK;
+	}
+	
+	/*
+	 * If this node originated the request to the cluster, respond back
+	 * to the AMF library
+	 */
+	if (req_exec_amf_errorcancelall->source.in_addr.s_addr == this_ip.sin_addr.s_addr) {
+		log_printf (LOG_LEVEL_DEBUG, "sending error report response to fd %d\n",
+			req_exec_amf_errorcancelall->source.fd);
+
+		res_lib_amf_errorcancelall.header.magic = MESSAGE_MAGIC;
+		res_lib_amf_errorcancelall.header.size = sizeof (struct res_lib_amf_errorcancelall);
+		res_lib_amf_errorcancelall.header.id = MESSAGE_RES_AMF_ERRORCANCELALL;
+		res_lib_amf_errorcancelall.error = error;
+
+		libais_send_response (req_exec_amf_errorcancelall->source.fd,
+			&res_lib_amf_errorcancelall, sizeof (struct res_lib_amf_errorcancelall));
+	}
+
+	return (0);
+}
+
+/*
+ * If receiving this message from another cluster node, another cluster node
+ * has selected a readiness state for a component connected to _that_ cluster
+ * node.  That cluster node API has verified the readiness state, so its time to let
+ * the rest of the cluster nodes know about the readiness state change.
+ */
+static int message_handler_req_exec_amf_readinessstateset (int fd, void *message)
+{
+	struct req_exec_amf_readinessstateset *req_exec_amf_readinessstateset = (struct req_exec_amf_readinessstateset *)message;
+	struct saAmfComponent *component;
+
+	component = findComponent (&req_exec_amf_readinessstateset->compName);
+	if (component) {
+		log_printf (LOG_LEVEL_DEBUG, "found component %s, setting current readiness state to %d\n",
+			getSaNameT (&component->name),
+			req_exec_amf_readinessstateset->readinessState);
+
+		component->currentReadinessState = req_exec_amf_readinessstateset->readinessState;
+		dsm (component);
+	}
+	
+	return (0);
+}
+
+/*
+ * If receiving this message from another cluster node, another cluster node
+ * has selected a ha state for a component connected to _that_ cluster
+ * node.  That cluster node API has verified the ha state, so its time to let
+ * the rest of the cluster nodes know about the HA state change.
+ */
+static int message_handler_req_exec_amf_hastateset (int fd, void *message)
+{
+	struct req_exec_amf_hastateset *req_exec_amf_hastateset = (struct req_exec_amf_hastateset *)message;
+	struct saAmfComponent *component;
+
+	component = findComponent (&req_exec_amf_hastateset->compName);
+	if (component) {
+		log_printf (LOG_LEVEL_DEBUG, "found component %s, setting current HA state to %d\n",
+			getSaNameT (&component->name),
+			req_exec_amf_hastateset->haState);
+		component->currentHAState = req_exec_amf_hastateset->haState;
+		dsm (component);
+	}
+	
+	return (0);
+}
+
+static int message_handler_req_amf_init (int fd, void *message)
+{
+	struct res_lib_init res_lib_init;
+	SaErrorT error = SA_ERR_SECURITY;
+
+	log_printf (LOG_LEVEL_DEBUG, "Got AMF request to initalize availability management framework service.\n");
+
+	if (connections[fd].authenticated) {
+		connections[fd].service = SOCKET_SERVICE_AMF;
+		error = SA_OK;
+	}
+
+	res_lib_init.header.magic = MESSAGE_MAGIC;
+	res_lib_init.header.size = sizeof (struct res_lib_init);
+	res_lib_init.header.id = MESSAGE_RES_INIT;
+	res_lib_init.error = error;
+
+	libais_send_response (fd, &res_lib_init, sizeof (res_lib_init));
+
+	if (connections[fd].authenticated) {
+		return (0);
+	}
+	return (-1);
+}
+
+static int message_handler_req_amf_activatepoll (int fd, void *message)
+{
+	struct res_amf_activatepoll res_amf_activatepoll;
+
+	res_amf_activatepoll.header.magic = MESSAGE_MAGIC;
+	res_amf_activatepoll.header.size = sizeof (struct res_amf_activatepoll);
+	res_amf_activatepoll.header.id = MESSAGE_RES_AMF_ACTIVATEPOLL;
+	libais_send_response (fd, &res_amf_activatepoll, sizeof (struct res_amf_activatepoll));
+
+	return (0);
+}
+
+static int message_handler_req_amf_componentregister (int fd, void *message)
+{
+	struct req_amf_componentregister *req_lib_amf_componentregister = (struct req_amf_componentregister *)message;
+	struct req_exec_amf_componentregister req_exec_amf_componentregister;
+	struct iovec iovecs[2];
+	int result;
+
+	req_exec_amf_componentregister.header.magic = MESSAGE_MAGIC;
+	req_exec_amf_componentregister.header.size = sizeof (struct req_exec_amf_componentregister);
+	req_exec_amf_componentregister.header.id = MESSAGE_REQ_EXEC_AMF_COMPONENTREGISTER;
+
+	req_exec_amf_componentregister.source.fd = fd;
+	req_exec_amf_componentregister.source.in_addr.s_addr = this_ip.sin_addr.s_addr;
+	memcpy (&req_exec_amf_componentregister.req_lib_amf_componentregister,
+		req_lib_amf_componentregister,
+		sizeof (struct req_lib_amf_componentregister));
+
+	iovecs[0].iov_base = &req_exec_amf_componentregister;
+	iovecs[0].iov_len = sizeof (req_exec_amf_componentregister);
+
+	result = gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+
+	return (0);
+}
+
+static int message_handler_req_amf_componentunregister (int fd, void *message)
+{
+	struct req_lib_amf_componentunregister *req_lib_amf_componentunregister = (struct req_lib_amf_componentunregister *)message;
+	struct req_exec_amf_componentunregister req_exec_amf_componentunregister;
+	struct iovec iovecs[2];
+	int result;
+	struct saAmfComponent *component;
+
+	req_exec_amf_componentunregister.header.magic = MESSAGE_MAGIC;
+	req_exec_amf_componentunregister.header.size = sizeof (struct req_exec_amf_componentunregister);
+	req_exec_amf_componentunregister.header.id = MESSAGE_REQ_EXEC_AMF_COMPONENTUNREGISTER;
+
+	req_exec_amf_componentunregister.source.fd = fd;
+	req_exec_amf_componentunregister.source.in_addr.s_addr = this_ip.sin_addr.s_addr;
+	memcpy (&req_exec_amf_componentunregister.req_lib_amf_componentunregister,
+		req_lib_amf_componentunregister,
+		sizeof (struct req_lib_amf_componentunregister));
+
+	component = findComponent (&req_lib_amf_componentunregister->compName);
+	if (component && component->registered && component->local) {
+		component->probableCause = SA_AMF_NOT_RESPONDING;
+	}
+	iovecs[0].iov_base = &req_exec_amf_componentunregister;
+	iovecs[0].iov_len = sizeof (req_exec_amf_componentunregister);
+
+	result = gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+
+	return (0);
+}
+
+static int message_handler_req_amf_readinessstateget (int fd, void *message)
+{
+	struct req_amf_readinessstateget *req_amf_readinessstateget = (struct req_amf_readinessstateget *)message;
+	struct res_amf_readinessstateget res_amf_readinessstateget;
+	struct saAmfComponent *component;
+
+	log_printf (LOG_LEVEL_DEBUG, "got request to return readiness state\n");
+	res_amf_readinessstateget.header.magic = MESSAGE_MAGIC;
+	res_amf_readinessstateget.header.id = MESSAGE_RES_AMF_READINESSSTATEGET;
+	res_amf_readinessstateget.header.size = sizeof (struct res_amf_readinessstateget);
+	res_amf_readinessstateget.error = SA_ERR_NOT_EXIST;
+
+	component = findComponent (&req_amf_readinessstateget->compName);
+	log_printf (LOG_LEVEL_DEBUG, "readinessstateget: found component %p\n", component);
+	if (component) {
+		memcpy (&res_amf_readinessstateget.readinessState, 
+			&component->currentReadinessState, sizeof (SaAmfReadinessStateT));
+		res_amf_readinessstateget.error = SA_OK;
+	}
+	libais_send_response (fd, &res_amf_readinessstateget, sizeof (struct res_amf_readinessstateget));
+	return (0);
+}
+
+static int message_handler_req_amf_hastateget (int fd, void *message)
+{
+	struct req_amf_hastateget *req_amf_hastateget = (struct req_amf_hastateget *)message;
+	struct res_amf_hastateget res_amf_hastateget;
+	struct saAmfComponent *component;
+
+	res_amf_hastateget.header.magic = MESSAGE_MAGIC;
+	res_amf_hastateget.header.id = MESSAGE_RES_AMF_HASTATEGET;
+	res_amf_hastateget.header.size = sizeof (struct res_amf_hastateget);
+	res_amf_hastateget.error = SA_ERR_NOT_EXIST;
+
+	component = findComponentInProtectionGroup (&req_amf_hastateget->csiName, &req_amf_hastateget->compName);
+
+	if (component) {
+		memcpy (&res_amf_hastateget.haState, 
+			&component->currentHAState, sizeof (SaAmfHAStateT));
+		res_amf_hastateget.error = SA_OK;
+	}
+	libais_send_response (fd, &res_amf_hastateget, sizeof (struct res_amf_hastateget));
+	return (0);
+}
+
+static int message_handler_req_amf_protectiongrouptrackstart (int fd, void *message)
+{
+	struct req_amf_protectiongrouptrackstart *req_amf_protectiongrouptrackstart = (struct req_amf_protectiongrouptrackstart *)message;
+	struct res_amf_protectiongrouptrackstart res_amf_protectiongrouptrackstart;
+	struct libamf_ci_trackentry *track = 0;
+	int i;
+	struct saAmfProtectionGroup *amfProtectionGroup;
+
+	amfProtectionGroup = findProtectionGroup (&req_amf_protectiongrouptrackstart->csiName);
+
+	if (amfProtectionGroup) {
+		log_printf (LOG_LEVEL_DEBUG, "protectiongrouptrackstart: Got valid track start on CSI: %s.\n", getSaNameT (&req_amf_protectiongrouptrackstart->csiName));
+		for (i = 0; i < connections[fd].ais_ci.u.libamf_ci.trackEntries; i++) {
+			if (connections[fd].ais_ci.u.libamf_ci.tracks[i].active == 0) {
+				track = &connections[fd].ais_ci.u.libamf_ci.tracks[i];
+				break;
+			}
+		}
+		if (track == 0) {
+			grow_amf_track_table (fd, 1);
+			track = &connections[fd].ais_ci.u.libamf_ci.tracks[i];
+		}
+
+		track->active = 1;
+		track->trackFlags = req_amf_protectiongrouptrackstart->trackFlags;
+		track->notificationBufferAddress = req_amf_protectiongrouptrackstart->notificationBufferAddress;
+		memcpy (&track->csiName,
+			&req_amf_protectiongrouptrackstart->csiName, sizeof (SaNameT));
+	
+		/*
+		 * If SA_TRACK_CURRENT is specified, write out all current connections
+		 */
+	} else {
+		log_printf (LOG_LEVEL_DEBUG, "invalid track start, csi not registered with system.\n");
+	}
+
+	res_amf_protectiongrouptrackstart.header.magic = MESSAGE_MAGIC;
+	res_amf_protectiongrouptrackstart.header.id = MESSAGE_RES_AMF_PROTECTIONGROUPTRACKSTART;
+	res_amf_protectiongrouptrackstart.header.size = sizeof (struct res_amf_protectiongrouptrackstart);
+	res_amf_protectiongrouptrackstart.error = SA_ERR_NOT_EXIST;
+
+	if (amfProtectionGroup) {
+		res_amf_protectiongrouptrackstart.error = SA_OK;
+	}
+	libais_send_response (fd, &res_amf_protectiongrouptrackstart,
+		sizeof (struct res_amf_protectiongrouptrackstart));
+
+	if (amfProtectionGroup &&
+		req_amf_protectiongrouptrackstart->trackFlags & SA_TRACK_CURRENT) {
+
+		sendProtectionGroupNotification (fd,
+			track->notificationBufferAddress,
+			amfProtectionGroup,
+			0, 
+			0,
+			track->trackFlags);
+
+		track->trackFlags &= ~SA_TRACK_CURRENT;
+	}
+	return (0);
+}
+
+static int message_handler_req_amf_protectiongrouptrackstop (int fd, void *message)
+{
+	struct req_amf_protectiongrouptrackstop *req_amf_protectiongrouptrackstop = (struct req_amf_protectiongrouptrackstop *)message;
+	struct res_amf_protectiongrouptrackstop res_amf_protectiongrouptrackstop;
+	struct libamf_ci_trackentry *track = 0;
+	int i;
+
+	for (i = 0; i < connections[fd].ais_ci.u.libamf_ci.trackEntries; i++) {
+		if (SaNameTisNameT (&req_amf_protectiongrouptrackstop->csiName,
+			&connections[fd].ais_ci.u.libamf_ci.tracks[i].csiName)) {
+
+			track = &connections[fd].ais_ci.u.libamf_ci.tracks[i];
+		}
+	}
+
+	if (track) {
+		log_printf (LOG_LEVEL_DEBUG, "protectiongrouptrackstop: Trackstop on CSI: %s\n", getSaNameT (&req_amf_protectiongrouptrackstop->csiName));
+		memset (track, 0, sizeof (struct libamf_ci_trackentry));
+	}
+
+	res_amf_protectiongrouptrackstop.header.magic = MESSAGE_MAGIC;
+	res_amf_protectiongrouptrackstop.header.id = MESSAGE_RES_AMF_PROTECTIONGROUPTRACKSTOP;
+	res_amf_protectiongrouptrackstop.header.size = sizeof (struct res_amf_protectiongrouptrackstop);
+	res_amf_protectiongrouptrackstop.error = SA_ERR_NOT_EXIST;
+
+	if (track) {
+		res_amf_protectiongrouptrackstop.error = SA_OK;
+	}
+	libais_send_response (fd, &res_amf_protectiongrouptrackstop,
+		sizeof (struct res_amf_protectiongrouptrackstop));
+
+	return (0);
+}
+
+static int message_handler_req_amf_errorreport (int fd, void *message)
+{
+	struct req_lib_amf_errorreport *req_lib_amf_errorreport = (struct req_lib_amf_errorreport *)message;
+	struct req_exec_amf_errorreport req_exec_amf_errorreport;
+
+	struct iovec iovecs[2];
+	int result;
+
+	req_exec_amf_errorreport.header.magic = MESSAGE_MAGIC;
+	req_exec_amf_errorreport.header.size = sizeof (struct req_exec_amf_errorreport);
+	req_exec_amf_errorreport.header.id = MESSAGE_REQ_EXEC_AMF_ERRORREPORT;
+
+	req_exec_amf_errorreport.source.fd = fd;
+	req_exec_amf_errorreport.source.in_addr.s_addr = this_ip.sin_addr.s_addr;
+	memcpy (&req_exec_amf_errorreport.req_lib_amf_errorreport,
+		req_lib_amf_errorreport,
+		sizeof (struct req_lib_amf_errorreport));
+
+	iovecs[0].iov_base = &req_exec_amf_errorreport;
+	iovecs[0].iov_len = sizeof (req_exec_amf_errorreport);
+//	iovecs[0].iov_len = sizeof (req_exec_amf_errorreport) - sizeof (req_lib_amf_errorreport);
+
+//	iovecs[1].iov_base = &req_lib_amf_errorreport;
+//	iovecs[1].iov_len = sizeof (req_lib_amf_errorreport);
+
+	result = gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+
+	return (0);
+}
+
+static int message_handler_req_amf_errorcancelall (int fd, void *message)
+{
+	struct req_lib_amf_errorcancelall *req_lib_amf_errorcancelall = (struct req_lib_amf_errorcancelall *)message;
+	struct req_exec_amf_errorcancelall req_exec_amf_errorcancelall;
+
+	struct iovec iovecs[2];
+	int result;
+
+	req_exec_amf_errorcancelall.header.magic = MESSAGE_MAGIC;
+	req_exec_amf_errorcancelall.header.size = sizeof (struct req_exec_amf_errorcancelall);
+	req_exec_amf_errorcancelall.header.id = MESSAGE_REQ_EXEC_AMF_ERRORCANCELALL;
+
+	req_exec_amf_errorcancelall.source.fd = fd;
+	req_exec_amf_errorcancelall.source.in_addr.s_addr = this_ip.sin_addr.s_addr;
+	memcpy (&req_exec_amf_errorcancelall.req_lib_amf_errorcancelall,
+		req_lib_amf_errorcancelall,
+		sizeof (struct req_lib_amf_errorcancelall));
+
+	iovecs[0].iov_base = &req_exec_amf_errorcancelall;
+	iovecs[0].iov_len = sizeof (req_exec_amf_errorcancelall);
+//	iovecs[0].iov_len = sizeof (req_exec_amf_errorcancelall) - sizeof (req_lib_amf_errorcancelall);
+
+//	iovecs[1].iov_base = &req_lib_amf_errorcancelall;
+//	iovecs[1].iov_len = sizeof (req_lib_amf_errorcancelall);
+
+	result = gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+
+	return (0);
+}
+
+static int message_handler_req_amf_stoppingcomplete (int fd, void *message)
+{
+	struct req_amf_stoppingcomplete *req_amf_stoppingcomplete = (struct req_amf_stoppingcomplete *)message;
+
+	int connection;
+
+	log_printf (LOG_LEVEL_DEBUG, "handling stopping complete\n");
+	connection = req_amf_response_get_connection (req_amf_stoppingcomplete->invocation);
+	connections[connection].component->currentReadinessState = connections[connection].component->newReadinessState;
+
+	readinessStateSetCluster (connections[connection].component, SA_AMF_STOPPING);
+
+	sendProtectionGroupNotifications (connections[connection].component,
+		SA_AMF_PROTECTION_GROUP_STATE_CHANGE);
+
+// This is part of dsm now
+//	readinessStateSetApi (connections[connection].component, SA_AMF_OUT_OF_SERVICE);
+
+	return (0);
+}
+
+void response_handler_healthcheckcallback (int connection,
+	struct req_amf_response *req_amf_response) {
+
+	if (req_amf_response->error == SA_OK) {
+		log_printf (LOG_LEVEL_DEBUG, "setting healthcheck ok\n");
+		connections[connection].component->healthcheck_outstanding = 0;
+	}
+}
+
+static int message_handler_req_amf_response (int fd, void *message)
+{
+	struct req_amf_response *req_amf_response = (struct req_amf_response *)message;
+	int connection;
+	int interface;
+
+	connection = req_amf_response_get_connection (req_amf_response->invocation);
+	interface = req_amf_response_get_interface (req_amf_response->invocation);
+	log_printf (LOG_LEVEL_DEBUG, "handling response connection %d interface %x\n", connection, interface);
+	switch (interface) {
+	case MESSAGE_REQ_AMF_RESPONSE_SAAMFHEALTHCHECKCALLBACK:
+		response_handler_healthcheckcallback (connection, req_amf_response);
+		break;
+
+	case MESSAGE_REQ_AMF_RESPONSE_SAAMFREADINESSSTATESETCALLBACK:
+		response_handler_readinessstatesetcallback (connection, req_amf_response);
+		break;
+
+	case MESSAGE_REQ_AMF_RESPONSE_SAAMFCSISETCALLBACK:
+		response_handler_csisetcallback (connection, req_amf_response);
+		break;
+
+	case MESSAGE_REQ_AMF_RESPONSE_SAAMFCSIREMOVECALLBACK:
+		break;
+
+	default:
+		// TODO
+		log_printf (LOG_LEVEL_ERROR, "invalid invocation value %x\n", req_amf_response->invocation);
+		break;
+	}
+
+	return (0);
+}
+
+static int message_handler_req_amf_componentcapabilitymodelget (int fd, void *message)
+{
+	struct req_amf_componentcapabilitymodelget *req_amf_componentcapabilitymodelget = (struct req_amf_componentcapabilitymodelget *)message;
+	struct res_amf_componentcapabilitymodelget res_amf_componentcapabilitymodelget;
+	struct saAmfComponent *component;
+	SaErrorT error = SA_OK;
+
+	log_printf (LOG_LEVEL_DEBUG, "componentcapabilitymodelget: Retrieve name %s.\n", getSaNameT (&req_amf_componentcapabilitymodelget->compName));
+	component = findComponent (&req_amf_componentcapabilitymodelget->compName);
+	if (component && component->registered) {
+		memcpy (&res_amf_componentcapabilitymodelget.componentCapabilityModel,
+			&component->componentCapabilityModel, sizeof (SaAmfComponentCapabilityModelT));
+	} else {
+		error = SA_ERR_NOT_EXIST;
+	}
+
+	res_amf_componentcapabilitymodelget.header.magic = MESSAGE_MAGIC;
+	res_amf_componentcapabilitymodelget.header.size = sizeof (struct res_amf_componentcapabilitymodelget);
+	res_amf_componentcapabilitymodelget.header.id = MESSAGE_RES_AMF_COMPONENTCAPABILITYMODELGET;
+	res_amf_componentcapabilitymodelget.error = error;
+	libais_send_response (fd, &res_amf_componentcapabilitymodelget, sizeof (struct res_amf_componentcapabilitymodelget));
+
+	return (0);
+}
+

+ 56 - 0
exec/amf.h

@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "../include/ais_msg.h"
+#include "poll.h"
+#include "parse.h"
+#include "handlers.h"
+
+#ifndef AMF_H_DEFINED
+#define AMF_H_DEFINED
+
+struct libamf_ci_trackentry {
+	int active;
+	SaUint8T trackFlags;
+	SaAmfProtectionGroupNotificationT *notificationBufferAddress;
+	SaNameT csiName;
+};
+
+struct libamf_ci {
+	struct libamf_ci_trackentry *tracks;
+	int trackEntries;
+};
+
+extern struct service_handler amf_service_handler;
+
+#endif /* AMF_H_DEFINED */

+ 1638 - 0
exec/ckpt.c

@@ -0,0 +1,1638 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/sysinfo.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+
+#include "../include/ais_types.h"
+#include "../include/ais_msg.h"
+#include "../include/list.h"
+#include "../include/queue.h"
+#include "poll.h"
+#include "mempool.h"
+#include "parse.h"
+#include "main.h"
+#include "print.h"
+#include "gmi.h"
+
+DECLARE_LIST_INIT(checkpointListHead);
+
+DECLARE_LIST_INIT(checkpointIteratorListHead);
+
+static int ckptCheckpointApiFinalize (int fd);
+static int ckptSectionIteratorApiFinalize (int fd);
+
+static int message_handler_req_exec_ckpt_checkpointopen (int fd, void *message);
+
+static int message_handler_req_exec_ckpt_checkpointclose (int fd, void *message);
+
+static int message_handler_req_exec_ckpt_checkpointunlink (int fd, void *message);
+
+static int message_handler_req_exec_ckpt_checkpointretentiondurationset (int fd, void *message);
+
+static int message_handler_req_exec_ckpt_sectioncreate (int fd, void *message);
+
+static int message_handler_req_exec_ckpt_sectiondelete (int fd, void *message);
+
+static int message_handler_req_exec_ckpt_sectionexpirationtimeset (int fd, void *message);
+
+static int message_handler_req_exec_ckpt_sectionwrite (int fd, void *message);
+
+static int message_handler_req_exec_ckpt_sectionoverwrite (int fd, void *message);
+
+static int message_handler_req_exec_ckpt_sectionread (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_init (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_checkpoint_init (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_sectioniterator_init (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_checkpointopen (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_checkpointopenasync (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_checkpointunlink (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_checkpointretentiondurationset (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_activecheckpointset (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_checkpointstatusget (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_sectioncreate (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_sectiondelete (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_sectionexpirationtimeset (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_sectionwrite (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_sectionoverwrite (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_sectionread (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_checkpointsynchronize (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_checkpointsyncronizeasync (int fd, void *message);
+
+static int message_handler_req_lib_ckpt_sectioniteratorinitialize (int fd, void *message);
+static int message_handler_req_lib_ckpt_sectioniteratornext (int fd, void *message);
+
+static int ckptConfChg (
+	struct sockaddr_in *member_list, int member_list_entries,
+	struct sockaddr_in *left_list, int left_list_entries,
+	struct sockaddr_in *joined_list, int joined_list_entries) {
+
+	return (0);
+}
+
+int (*ckpt_libais_handler_fns[]) (int fd, void *) = {
+};
+
+/*
+ * TODO multinode not yet implemented
+ */
+int (*ckpt_aisexec_handler_fns[]) (int fd, void *) = {
+};
+
+/*
+ * exported service
+ */
+struct service_handler ckpt_service_handler = {
+	libais_handler_fns:			ckpt_libais_handler_fns,
+	libais_handler_fns_count:	sizeof (ckpt_libais_handler_fns) / sizeof (int (*)),
+	aisexec_handler_fns:		ckpt_aisexec_handler_fns ,
+	aisexec_handler_fns_count:	sizeof (ckpt_aisexec_handler_fns) / sizeof (int (*)),
+	confchg_fn:					0, /* ckpt service handler is not distributed */
+	libais_init_fn:				message_handler_req_lib_ckpt_init,
+	libais_exit_fn:				0,
+	aisexec_init_fn:			0
+};
+
+static int (*ckpt_checkpoint_libais_handler_fns[]) (int fd, void *) = {
+	message_handler_req_lib_ckpt_checkpointopen,
+	message_handler_req_lib_ckpt_checkpointopenasync,
+	message_handler_req_lib_ckpt_checkpointunlink,
+	message_handler_req_lib_ckpt_checkpointretentiondurationset,
+	message_handler_req_lib_ckpt_activecheckpointset,
+	message_handler_req_lib_ckpt_checkpointstatusget,
+	message_handler_req_lib_ckpt_sectioncreate,
+	message_handler_req_lib_ckpt_sectiondelete,
+	message_handler_req_lib_ckpt_sectionexpirationtimeset,
+	message_handler_req_lib_ckpt_sectionwrite,
+	message_handler_req_lib_ckpt_sectionoverwrite,
+	message_handler_req_lib_ckpt_sectionread,
+	message_handler_req_lib_ckpt_checkpointsynchronize,
+	message_handler_req_lib_ckpt_checkpointsyncronizeasync
+};
+ 
+static int (*ckpt_checkpoint_aisexec_handler_fns[]) (int fd, void *) = {
+	message_handler_req_exec_ckpt_checkpointopen,
+	message_handler_req_exec_ckpt_checkpointclose,
+	message_handler_req_exec_ckpt_checkpointunlink,
+	message_handler_req_exec_ckpt_checkpointretentiondurationset,
+	message_handler_req_exec_ckpt_sectioncreate,
+	message_handler_req_exec_ckpt_sectiondelete,
+	message_handler_req_exec_ckpt_sectionexpirationtimeset,
+	message_handler_req_exec_ckpt_sectionwrite,
+	message_handler_req_exec_ckpt_sectionoverwrite,
+	message_handler_req_exec_ckpt_sectionread
+};
+
+struct service_handler ckpt_checkpoint_service_handler = {
+	libais_handler_fns:			ckpt_checkpoint_libais_handler_fns,
+	libais_handler_fns_count:	sizeof (ckpt_checkpoint_libais_handler_fns) / sizeof (int (*)),
+	aisexec_handler_fns:		ckpt_checkpoint_aisexec_handler_fns ,
+	aisexec_handler_fns_count:	sizeof (ckpt_checkpoint_aisexec_handler_fns) / sizeof (int (*)),
+	confchg_fn:					ckptConfChg,
+	libais_init_fn:				message_handler_req_lib_ckpt_checkpoint_init,
+	libais_exit_fn:				ckptCheckpointApiFinalize,
+	aisexec_init_fn:			0
+};
+
+static int (*ckpt_sectioniterator_libais_handler_fns[]) (int fd, void *) = {
+    message_handler_req_lib_ckpt_sectioniteratorinitialize,
+    message_handler_req_lib_ckpt_sectioniteratornext
+};
+
+static int (*ckpt_sectioniterator_aisexec_handler_fns[]) (int fd, void *) = {
+};
+
+struct service_handler ckpt_sectioniterator_service_handler = {
+	libais_handler_fns:			ckpt_sectioniterator_libais_handler_fns,
+	libais_handler_fns_count:	sizeof (ckpt_sectioniterator_libais_handler_fns) / sizeof (int (*)),
+	aisexec_handler_fns:		ckpt_sectioniterator_aisexec_handler_fns ,
+	aisexec_handler_fns_count:	sizeof (ckpt_sectioniterator_aisexec_handler_fns) / sizeof (int (*)),
+	confchg_fn:					0, /* Section Iterators are not distributed */
+	libais_init_fn:				message_handler_req_lib_ckpt_sectioniterator_init,
+	libais_exit_fn:				ckptSectionIteratorApiFinalize,
+	aisexec_init_fn:			0
+};
+
+static struct saCkptCheckpoint *findCheckpoint (SaNameT *name)
+{
+	struct list_head *checkpointList;
+	struct saCkptCheckpoint *checkpoint;
+
+   for (checkpointList = checkpointListHead.next;
+        checkpointList != &checkpointListHead;
+        checkpointList = checkpointList->next) {
+
+        checkpoint = list_entry (checkpointList,
+            struct saCkptCheckpoint, list);
+
+		if (SaNameTisNameT (name, &checkpoint->name)) {
+			return (checkpoint);
+		}
+	}
+	return (0);
+}
+
+static struct saCkptCheckpointSection *findCheckpointSection (
+	struct saCkptCheckpoint *ckptCheckpoint,
+	char *id,
+	int idLen)
+{
+	struct list_head *checkpointSectionList;
+	struct saCkptCheckpointSection *ckptCheckpointSection;
+
+	log_printf (LOG_LEVEL_DEBUG, "Finding checkpoint section id %s %d\n", id, idLen);
+	for (checkpointSectionList = ckptCheckpoint->checkpointSectionsListHead.next;
+		checkpointSectionList != &ckptCheckpoint->checkpointSectionsListHead;
+		checkpointSectionList = checkpointSectionList->next) {
+
+		ckptCheckpointSection = list_entry (checkpointSectionList,
+			struct saCkptCheckpointSection, list);
+	
+		log_printf (LOG_LEVEL_DEBUG, "Checking section id %s %d\n", 
+			ckptCheckpointSection->sectionDescriptor.sectionId.id,
+			ckptCheckpointSection->sectionDescriptor.sectionId.idLen);
+
+		if (ckptCheckpointSection->sectionDescriptor.sectionId.idLen == idLen &&
+			(memcmp (ckptCheckpointSection->sectionDescriptor.sectionId.id, 
+			id, idLen) == 0)) {
+
+			return (ckptCheckpointSection);
+		}
+	}
+	return 0;
+}
+
+void sendCkptCheckpointClose (struct saCkptCheckpoint *checkpoint) {
+	struct req_exec_ckpt_checkpointclose req_exec_ckpt_checkpointclose;
+	struct iovec iovecs[2];
+	int result;
+
+	req_exec_ckpt_checkpointclose.header.magic = MESSAGE_MAGIC;
+	req_exec_ckpt_checkpointclose.header.size =
+		sizeof (struct req_exec_ckpt_checkpointclose);
+	req_exec_ckpt_checkpointclose.header.id = MESSAGE_REQ_EXEC_CKPT_CHECKPOINTCLOSE;
+
+	memcpy (&req_exec_ckpt_checkpointclose.checkpointName,
+		&checkpoint->name,
+		sizeof (SaNameT));
+
+	iovecs[0].iov_base = &req_exec_ckpt_checkpointclose;
+	iovecs[0].iov_len = sizeof (req_exec_ckpt_checkpointclose);
+
+	result = gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+}
+
+static int ckptCheckpointApiFinalize (int fd)
+{
+	/*
+	 * close checkpoint opened from this fd
+	 */
+	if (connections[fd].service == SOCKET_SERVICE_CKPT_CHECKPOINT &&
+		connections[fd].ais_ci.u.libckpt_ci.checkpoint) {
+log_printf (LOG_LEVEL_DEBUG, "APIFinalize fd is %d %s\n", fd, getSaNameT (&connections[fd].ais_ci.u.libckpt_ci.checkpoint->name));
+
+		sendCkptCheckpointClose (connections[fd].ais_ci.u.libckpt_ci.checkpoint);
+	}
+	return (0);
+}
+
+static int ckptSectionIteratorApiFinalize (int fd) {
+	/*
+	 * If section iterator connection, unlink from list and free section iterator data
+	 */
+	if (connections[fd].service == SOCKET_SERVICE_CKPT_SECTIONITERATOR) {
+		log_printf (LOG_LEVEL_DEBUG, "freeing section iterator\n");
+		if (connections[fd].ais_ci.u.libckpt_ci.sectionIterator.sectionIteratorEntries) {
+			free (connections[fd].ais_ci.u.libckpt_ci.sectionIterator.sectionIteratorEntries);
+		}
+		list_del (&connections[fd].ais_ci.u.libckpt_ci.sectionIterator.list);
+	}
+
+	return (0);
+}
+
+static int message_handler_req_exec_ckpt_checkpointopen (int fd, void *message)
+{
+	struct req_exec_ckpt_checkpointopen *req_exec_ckpt_checkpointopen = (struct req_exec_ckpt_checkpointopen *)message;
+	struct req_lib_ckpt_checkpointopen *req_lib_ckpt_checkpointopen = (struct req_lib_ckpt_checkpointopen *)&req_exec_ckpt_checkpointopen->req_lib_ckpt_checkpointopen;
+	struct res_lib_ckpt_checkpointopen res_lib_ckpt_checkpointopen;
+
+	struct saCkptCheckpoint *ckptCheckpoint = 0;
+	struct saCkptCheckpointSection *ckptCheckpointSection = 0;
+	SaErrorT error = SA_OK;
+
+	log_printf (LOG_LEVEL_DEBUG, "Executive request to open checkpoint %p\n", req_exec_ckpt_checkpointopen);
+	
+	ckptCheckpoint = findCheckpoint (&req_lib_ckpt_checkpointopen->checkpointName);
+
+	/*
+	 * If checkpoint doesn't exist, create one
+	 */
+	if (ckptCheckpoint == 0) {
+		ckptCheckpoint = malloc (sizeof (struct saCkptCheckpoint));
+		if (ckptCheckpoint == 0) {
+			error = SA_ERR_NO_MEMORY;
+			goto error_exit;
+		}
+
+		ckptCheckpointSection = malloc (sizeof (struct saCkptCheckpointSection));
+		if (ckptCheckpointSection == 0) {
+			free (ckptCheckpoint);
+			error = SA_ERR_NO_MEMORY;
+			goto error_exit;
+		}
+
+		memcpy (&ckptCheckpoint->name,
+			&req_lib_ckpt_checkpointopen->checkpointName,
+			sizeof (SaNameT));
+		memcpy (&ckptCheckpoint->checkpointCreationAttributes,
+			&req_lib_ckpt_checkpointopen->checkpointCreationAttributes,
+			sizeof (SaCkptCheckpointCreationAttributesT));
+		ckptCheckpoint->unlinked = 0;
+		list_init (&ckptCheckpoint->list);
+		list_init (&ckptCheckpoint->checkpointSectionsListHead);
+		list_add (&ckptCheckpoint->list, &checkpointListHead);
+		ckptCheckpoint->referenceCount = 0;
+
+		/*
+		 * Add in default checkpoint section
+		 */
+		list_init (&ckptCheckpointSection->list);
+		list_add (&ckptCheckpointSection->list, &ckptCheckpoint->checkpointSectionsListHead);
+		ckptCheckpointSection->sectionDescriptor.expirationTime = 0xFFFFFFFF; //SA_END_TIME;
+		
+		/*
+		 * Default section id
+		 */
+		ckptCheckpointSection->sectionDescriptor.sectionId.id = 0;
+		ckptCheckpointSection->sectionDescriptor.sectionId.idLen = 0;
+		ckptCheckpointSection->sectionDescriptor.sectionSize = 0;
+		ckptCheckpointSection->sectionDescriptor.expirationTime = 0xffffffff; /* SA_END_TIME */
+		ckptCheckpointSection->sectionDescriptor.sectionState = SA_CKPT_SECTION_VALID;
+		ckptCheckpointSection->sectionDescriptor.lastUpdate = 0; // current time
+		ckptCheckpointSection->sectionData = 0;
+	}
+
+	/*
+	 * If the checkpoint has been unlinked, it is an invalid name
+	 */
+	if (ckptCheckpoint->unlinked) {
+		error = SA_ERR_INVALID_PARAM; /* Is this the correct return ? */
+		goto error_exit;
+	}
+
+	/*
+	 * Setup connection information and mark checkpoint as referenced
+	 */
+	log_printf (LOG_LEVEL_DEBUG, "CHECKPOINT opened fd %d is %p\n", fd, ckptCheckpoint);
+	ckptCheckpoint->referenceCount += 1;
+
+	/*
+	 * Send error result to CKPT library
+	 */
+error_exit:
+	/*
+	 * If this node was the source of the message, respond to this node
+	 */
+	if (req_exec_ckpt_checkpointopen->source.in_addr.s_addr == this_ip.sin_addr.s_addr) {
+		connections[req_exec_ckpt_checkpointopen->source.fd].ais_ci.u.libckpt_ci.checkpoint = ckptCheckpoint;
+		connections[req_exec_ckpt_checkpointopen->source.fd].ais_ci.u.libckpt_ci.checkpointOpenFlags = req_lib_ckpt_checkpointopen->checkpointOpenFlags;
+		res_lib_ckpt_checkpointopen.header.magic = MESSAGE_MAGIC;
+		res_lib_ckpt_checkpointopen.header.size = sizeof (struct res_lib_ckpt_checkpointopen);
+		res_lib_ckpt_checkpointopen.header.id = MESSAGE_RES_CKPT_CHECKPOINT_CHECKPOINTOPEN;
+		res_lib_ckpt_checkpointopen.error = error;
+
+		libais_send_response (req_exec_ckpt_checkpointopen->source.fd, &res_lib_ckpt_checkpointopen,
+			sizeof (struct res_lib_ckpt_checkpointopen));
+	}
+
+//	return (error == SA_OK ? 0 : -1);
+	return (0);
+}
+
+extern int message_handler_req_exec_ckpt_checkpointclose (int fd, void *message)
+{
+	struct req_exec_ckpt_checkpointclose *req_exec_ckpt_checkpointclose = (struct req_exec_ckpt_checkpointclose *)message;
+	struct saCkptCheckpoint *checkpoint = 0;
+
+	log_printf (LOG_LEVEL_DEBUG, "Got EXEC request to close checkpoint %s\n", getSaNameT (&req_exec_ckpt_checkpointclose->checkpointName));
+
+	checkpoint = findCheckpoint (&req_exec_ckpt_checkpointclose->checkpointName);
+	if (checkpoint == 0) {
+		return (0);
+	}
+
+	checkpoint->referenceCount--;
+	log_printf (LOG_LEVEL_DEBUG, "disconnect called, new CKPT ref count is %d\n", 
+		checkpoint->referenceCount);
+
+	/*
+	 * If checkpoint has been unlinked and this is the last reference, delete it
+	 */
+	if (checkpoint->unlinked && checkpoint->referenceCount == 0) {
+		log_printf (LOG_LEVEL_DEBUG, "Unlinking checkpoint.\n");
+		list_del (&checkpoint->list);
+		free (checkpoint);
+	} else
+	if (checkpoint->referenceCount == 0) {
+		// TODO Start retention duration timer if reference count is 0
+		// and checkpoint has not been unlinked
+	}
+	
+	return (0);
+}
+
+static int message_handler_req_exec_ckpt_checkpointunlink (int fd, void *message)
+{
+	struct req_exec_ckpt_checkpointunlink *req_exec_ckpt_checkpointunlink = (struct req_exec_ckpt_checkpointunlink *)message;
+
+	struct req_lib_ckpt_checkpointunlink *req_lib_ckpt_checkpointunlink = (struct req_lib_ckpt_checkpointunlink *)&req_exec_ckpt_checkpointunlink->req_lib_ckpt_checkpointunlink;
+	struct res_lib_ckpt_checkpointunlink res_lib_ckpt_checkpointunlink;
+	struct saCkptCheckpoint *ckptCheckpoint = 0;
+	SaErrorT error = SA_OK;
+	
+	log_printf (LOG_LEVEL_DEBUG, "Got EXEC request to unlink checkpoint %p\n", req_exec_ckpt_checkpointunlink);
+	ckptCheckpoint = findCheckpoint (&req_lib_ckpt_checkpointunlink->checkpointName);
+	if (ckptCheckpoint == 0) {
+printf ("invalid checkpoint name\n");
+		error = SA_ERR_NOT_EXIST;
+		goto error_exit;
+	}
+	if (ckptCheckpoint->unlinked) {
+		error = SA_ERR_INVALID_PARAM;
+		goto error_exit;
+	}
+	ckptCheckpoint->unlinked = 1;
+	/*
+	 * Immediately delete entry if reference count is zero
+	 */
+	if (ckptCheckpoint->referenceCount == 0) {
+		list_del (&ckptCheckpoint->list);
+		free (ckptCheckpoint);
+	}
+
+error_exit:
+	/*
+	 * If this node was the source of the message, respond to this node
+	 */
+	if (req_exec_ckpt_checkpointunlink->source.in_addr.s_addr == this_ip.sin_addr.s_addr) {
+		res_lib_ckpt_checkpointunlink.header.magic = MESSAGE_MAGIC;
+		res_lib_ckpt_checkpointunlink.header.size = sizeof (struct res_lib_ckpt_checkpointunlink);
+		res_lib_ckpt_checkpointunlink.header.id = MESSAGE_RES_CKPT_CHECKPOINT_CHECKPOINTUNLINK;
+		res_lib_ckpt_checkpointunlink.error = error;
+		libais_send_response (req_exec_ckpt_checkpointunlink->source.fd, &res_lib_ckpt_checkpointunlink,
+			sizeof (struct res_lib_ckpt_checkpointunlink));
+	}
+	return (0);
+}
+
+static int message_handler_req_exec_ckpt_checkpointretentiondurationset (int fd, void *message)
+{
+	struct req_exec_ckpt_checkpointretentiondurationset *req_exec_ckpt_checkpointretentiondurationset = (struct req_exec_ckpt_checkpointretentiondurationset *)message;
+	struct saCkptCheckpoint *checkpoint;
+
+	log_printf (LOG_LEVEL_DEBUG, "Got EXEC request to set retention duratione checkpoint %p\n", req_exec_ckpt_checkpointretentiondurationset);
+
+	checkpoint = findCheckpoint (&req_exec_ckpt_checkpointretentiondurationset->checkpointName);
+	if (checkpoint) {
+		log_printf (LOG_LEVEL_DEBUG, "setting retention duration\n");
+		checkpoint->checkpointCreationAttributes.retentionDuration = req_exec_ckpt_checkpointretentiondurationset->retentionDuration;
+	}
+
+	return (0);
+}
+
+static int message_handler_req_exec_ckpt_sectioncreate (int fd, void *message) {
+	struct req_exec_ckpt_sectioncreate *req_exec_ckpt_sectioncreate = (struct req_exec_ckpt_sectioncreate *)message;
+	struct req_lib_ckpt_sectioncreate *req_lib_ckpt_sectioncreate = (struct req_lib_ckpt_sectioncreate *)&req_exec_ckpt_sectioncreate->req_lib_ckpt_sectioncreate;
+	struct res_lib_ckpt_sectioncreate res_lib_ckpt_sectioncreate;
+	struct saCkptCheckpoint *ckptCheckpoint;
+	struct saCkptCheckpointSection *ckptCheckpointSection;
+	void *initialData;
+	void *sectionId;
+	SaErrorT error = SA_OK;
+
+	log_printf (LOG_LEVEL_DEBUG, "Executive request to create a checkpoint section.\n");
+	ckptCheckpoint = findCheckpoint (&req_exec_ckpt_sectioncreate->checkpointName);
+	if (ckptCheckpoint == 0) {
+		error = SA_ERR_SYSTEM; // TODO find the right error for this
+		goto error_exit;
+	}
+
+	/*
+	 * Determine if user-specified checkpoint ID already exists
+	 */
+	ckptCheckpointSection = findCheckpointSection (ckptCheckpoint,
+		((char *)req_lib_ckpt_sectioncreate) + sizeof (struct req_lib_ckpt_sectioncreate),
+		req_lib_ckpt_sectioncreate->idLen);
+	if (ckptCheckpointSection) {
+		error = SA_ERR_EXIST;
+		goto error_exit;
+	}
+
+	/*
+	 * Allocate checkpoint section
+	 */
+	ckptCheckpointSection = malloc (sizeof (struct saCkptCheckpointSection));
+	if (ckptCheckpointSection == 0) {
+		error = SA_ERR_NO_MEMORY;
+		goto error_exit;
+	}
+	/*
+	 * Allocate checkpoint section data
+	 */
+	initialData = malloc (req_lib_ckpt_sectioncreate->initialDataSize);
+	if (initialData == 0) {
+		free (ckptCheckpointSection);
+		error = SA_ERR_NO_MEMORY;
+		goto error_exit;
+	}
+	/*
+	 * Allocate checkpoint section id
+	 */
+	sectionId = malloc (req_lib_ckpt_sectioncreate->idLen);
+	if (sectionId == 0) {
+		free (ckptCheckpointSection);
+		free (initialData);
+		error = SA_ERR_NO_MEMORY;
+		goto error_exit;
+	}
+		
+	/*
+	 * Copy checkpoint section and section ID
+	 */
+	memcpy (sectionId, ((char *)req_lib_ckpt_sectioncreate) + sizeof (struct req_lib_ckpt_sectioncreate),
+		req_lib_ckpt_sectioncreate->idLen);
+	
+	memcpy (initialData,
+		((char *)req_lib_ckpt_sectioncreate) +
+			sizeof (struct req_lib_ckpt_sectioncreate) +
+			req_lib_ckpt_sectioncreate->idLen,
+		req_lib_ckpt_sectioncreate->initialDataSize);
+
+	/*
+	 * Configure checkpoint section
+	 */
+	ckptCheckpointSection->sectionDescriptor.expirationTime = req_lib_ckpt_sectioncreate->expirationTime;
+	ckptCheckpointSection->sectionDescriptor.sectionId.id = sectionId;
+	ckptCheckpointSection->sectionDescriptor.sectionId.idLen = req_lib_ckpt_sectioncreate->idLen;
+	ckptCheckpointSection->sectionDescriptor.sectionSize = req_lib_ckpt_sectioncreate->initialDataSize;
+	ckptCheckpointSection->sectionDescriptor.sectionState = SA_CKPT_SECTION_VALID;
+	ckptCheckpointSection->sectionDescriptor.lastUpdate = 0; // TODO current time
+	ckptCheckpointSection->sectionData = initialData;
+
+	/*
+	 * Add checkpoint section to checkpoint
+	 */
+	list_init (&ckptCheckpointSection->list);
+	list_add (&ckptCheckpointSection->list, &ckptCheckpoint->checkpointSectionsListHead);
+
+error_exit:
+	if (req_exec_ckpt_sectioncreate->source.in_addr.s_addr == this_ip.sin_addr.s_addr) {
+		res_lib_ckpt_sectioncreate.header.magic = MESSAGE_MAGIC;
+		res_lib_ckpt_sectioncreate.header.size = sizeof (struct res_lib_ckpt_sectioncreate);
+		res_lib_ckpt_sectioncreate.header.id = MESSAGE_RES_CKPT_CHECKPOINT_SECTIONCREATE;
+		res_lib_ckpt_sectioncreate.error = error;
+
+		libais_send_response (req_exec_ckpt_sectioncreate->source.fd,
+			&res_lib_ckpt_sectioncreate,
+			sizeof (struct res_lib_ckpt_sectioncreate));
+	}
+	return (0);
+}
+
+static int message_handler_req_exec_ckpt_sectiondelete (int fd, void *message) {
+	struct req_exec_ckpt_sectiondelete *req_exec_ckpt_sectiondelete = (struct req_exec_ckpt_sectiondelete *)message;
+	struct req_lib_ckpt_sectiondelete *req_lib_ckpt_sectiondelete = (struct req_lib_ckpt_sectiondelete *)&req_exec_ckpt_sectiondelete->req_lib_ckpt_sectiondelete;
+	struct res_lib_ckpt_sectiondelete res_lib_ckpt_sectiondelete;
+	struct saCkptCheckpoint *ckptCheckpoint;
+	struct saCkptCheckpointSection *ckptCheckpointSection;
+	SaErrorT error = SA_OK;
+
+	ckptCheckpoint = findCheckpoint (&req_exec_ckpt_sectiondelete->checkpointName);
+	if (ckptCheckpoint == 0) {
+		error = SA_ERR_NOT_EXIST;
+		goto error_exit;
+	}
+
+	/*
+	 * Determine if the user is trying to delete the default section
+	 */
+	if (req_lib_ckpt_sectiondelete->idLen == 0) {
+		error = SA_ERR_INVALID_PARAM;
+		goto error_exit;
+	}
+
+	/*
+	 * Find checkpoint section to be deleted
+	 */
+	ckptCheckpointSection = findCheckpointSection (ckptCheckpoint,
+		((char *)(req_lib_ckpt_sectiondelete) + sizeof (struct req_lib_ckpt_sectiondelete)),
+		req_lib_ckpt_sectiondelete->idLen);
+	if (ckptCheckpointSection == 0) {
+printf ("section not found\n");
+		error = SA_ERR_NOT_EXIST;
+		goto error_exit;
+	}
+
+	/*
+	 * Delete checkpoint section
+	 */
+	list_del (&ckptCheckpointSection->list);
+	free (ckptCheckpointSection->sectionDescriptor.sectionId.id); 
+	free (ckptCheckpointSection->sectionData);
+	free (ckptCheckpointSection);
+
+	/*
+	 * return result to CKPT library
+	 */
+error_exit:
+	if (req_exec_ckpt_sectiondelete->source.in_addr.s_addr == this_ip.sin_addr.s_addr) {
+		res_lib_ckpt_sectiondelete.header.magic = MESSAGE_MAGIC;
+		res_lib_ckpt_sectiondelete.header.size = sizeof (struct res_lib_ckpt_sectiondelete);
+		res_lib_ckpt_sectiondelete.header.id = MESSAGE_RES_CKPT_CHECKPOINT_SECTIONDELETE;
+		res_lib_ckpt_sectiondelete.error = error;
+
+		libais_send_response (req_exec_ckpt_sectiondelete->source.fd,
+			&res_lib_ckpt_sectiondelete,
+			sizeof (struct res_lib_ckpt_sectiondelete));
+	}
+	return (0);
+}
+
+static int message_handler_req_exec_ckpt_sectionexpirationtimeset (int fd, void *message) {
+	struct req_exec_ckpt_sectionexpirationtimeset *req_exec_ckpt_sectionexpirationtimeset = (struct req_exec_ckpt_sectionexpirationtimeset *)message;
+	struct req_lib_ckpt_sectionexpirationtimeset *req_lib_ckpt_sectionexpirationtimeset = (struct req_lib_ckpt_sectionexpirationtimeset *)&req_exec_ckpt_sectionexpirationtimeset->req_lib_ckpt_sectionexpirationtimeset;
+	struct res_lib_ckpt_sectionexpirationtimeset res_lib_ckpt_sectionexpirationtimeset;
+	struct saCkptCheckpoint *ckptCheckpoint;
+	struct saCkptCheckpointSection *ckptCheckpointSection;
+	SaErrorT error = SA_OK;
+
+	log_printf (LOG_LEVEL_DEBUG, "Executive request to set section expiratoin time\n");
+	ckptCheckpoint = findCheckpoint (&req_exec_ckpt_sectionexpirationtimeset->checkpointName);
+	if (ckptCheckpoint == 0) {
+		error = SA_ERR_NOT_EXIST;
+		goto error_exit;
+	}
+
+	/*
+	 * Determine if the user is trying to set expiration time for the default section
+	 */
+	if (req_lib_ckpt_sectionexpirationtimeset->idLen == 0) {
+		error = SA_ERR_INVALID_PARAM;
+		goto error_exit;
+	}
+
+	/*
+	 * Find checkpoint section that expiration time should be set for
+	 */
+	ckptCheckpointSection = findCheckpointSection (ckptCheckpoint,
+		((char *)req_lib_ckpt_sectionexpirationtimeset) +
+			sizeof (struct req_lib_ckpt_sectionexpirationtimeset),
+		req_lib_ckpt_sectionexpirationtimeset->idLen);
+
+	if (ckptCheckpointSection == 0) {
+		error = SA_ERR_NOT_EXIST;
+		goto error_exit;
+	}
+
+	ckptCheckpointSection->sectionDescriptor.expirationTime = req_lib_ckpt_sectionexpirationtimeset->expirationTime;
+
+error_exit:
+	if (req_exec_ckpt_sectionexpirationtimeset->source.in_addr.s_addr == this_ip.sin_addr.s_addr) {
+		res_lib_ckpt_sectionexpirationtimeset.header.magic = MESSAGE_MAGIC;
+		res_lib_ckpt_sectionexpirationtimeset.header.size = sizeof (struct res_lib_ckpt_sectionexpirationtimeset);
+		res_lib_ckpt_sectionexpirationtimeset.header.id = MESSAGE_RES_CKPT_CHECKPOINT_SECTIONEXPIRATIONTIMESET;
+		res_lib_ckpt_sectionexpirationtimeset.error = error;
+
+		libais_send_response (req_exec_ckpt_sectionexpirationtimeset->source.fd,
+			&res_lib_ckpt_sectionexpirationtimeset,
+			sizeof (struct res_lib_ckpt_sectionexpirationtimeset));
+	}
+	return (0);
+}
+
+int exec_section_write = 0;
+static int message_handler_req_exec_ckpt_sectionwrite (int fd, void *message) {
+	struct req_exec_ckpt_sectionwrite *req_exec_ckpt_sectionwrite = (struct req_exec_ckpt_sectionwrite *)message;
+	struct req_lib_ckpt_sectionwrite *req_lib_ckpt_sectionwrite = (struct req_lib_ckpt_sectionwrite *)&req_exec_ckpt_sectionwrite->req_lib_ckpt_sectionwrite;
+	struct res_lib_ckpt_sectionwrite res_lib_ckpt_sectionwrite;
+	struct saCkptCheckpoint *ckptCheckpoint;
+	struct saCkptCheckpointSection *ckptCheckpointSection;
+	int sizeRequired;
+	void *sectionData;
+	SaErrorT error = SA_OK;
+
+	log_printf (LOG_LEVEL_DEBUG, "Executive request to section write. %d\n", exec_section_write++);
+	ckptCheckpoint = findCheckpoint (&req_exec_ckpt_sectionwrite->checkpointName);
+	if (ckptCheckpoint == 0) {
+printf ("can't find checkpoint\n"); // TODO
+		error = SA_ERR_NOT_EXIST;
+		goto error_exit;
+	}
+
+//printf ("writing checkpoint section is %s\n", ((char *)req_lib_ckpt_sectionwrite) + sizeof (struct req_lib_ckpt_sectionwrite));
+	/*
+	 * Find checkpoint section to be written
+	 */
+	ckptCheckpointSection = findCheckpointSection (ckptCheckpoint,
+		((char *)req_lib_ckpt_sectionwrite) + sizeof (struct req_lib_ckpt_sectionwrite),
+		req_lib_ckpt_sectionwrite->idLen);
+	if (ckptCheckpointSection == 0) {
+printf ("CANT FIND SECTION '%s'\n",
+		((char *)req_lib_ckpt_sectionwrite) + sizeof (struct req_lib_ckpt_sectionwrite));
+		error = SA_ERR_NOT_EXIST;
+		goto error_exit;
+	}
+
+	/*
+	 * If write would extend past end of section data, enlarge section
+	 */
+	sizeRequired = req_lib_ckpt_sectionwrite->dataOffset + req_lib_ckpt_sectionwrite->dataSize;
+	if (sizeRequired > ckptCheckpointSection->sectionDescriptor.sectionSize) {
+printf ("reallocating data\n");
+		sectionData = realloc (ckptCheckpointSection->sectionData, sizeRequired);
+		if (sectionData == 0) {
+			error = SA_ERR_NO_MEMORY;
+			goto error_exit;
+		}
+
+		/*
+		 * Install new section data
+		 */
+		ckptCheckpointSection->sectionData = sectionData;
+		ckptCheckpointSection->sectionDescriptor.sectionSize = sizeRequired;
+	}
+
+	/*
+	 * Write checkpoint section to section data
+	 */
+	if (req_lib_ckpt_sectionwrite->dataSize > 0) {
+		char *sd;
+		int *val;
+		val = ckptCheckpointSection->sectionData;
+		sd = (char *)ckptCheckpointSection->sectionData;
+		memcpy (&sd[req_lib_ckpt_sectionwrite->dataOffset],
+			((char *)req_exec_ckpt_sectionwrite) + sizeof (struct req_exec_ckpt_sectionwrite) + 
+				req_lib_ckpt_sectionwrite->idLen,
+			req_lib_ckpt_sectionwrite->dataSize);
+	}
+	/*
+	 * Write write response to CKPT library
+	 */
+error_exit:
+	if (req_exec_ckpt_sectionwrite->source.in_addr.s_addr == this_ip.sin_addr.s_addr) {
+		res_lib_ckpt_sectionwrite.header.magic = MESSAGE_MAGIC;
+		res_lib_ckpt_sectionwrite.header.size = sizeof (struct res_lib_ckpt_sectionwrite);
+		res_lib_ckpt_sectionwrite.header.id = MESSAGE_RES_CKPT_CHECKPOINT_SECTIONWRITE;
+		res_lib_ckpt_sectionwrite.error = error;
+
+		libais_send_response (req_exec_ckpt_sectionwrite->source.fd,
+			&res_lib_ckpt_sectionwrite,
+			sizeof (struct res_lib_ckpt_sectionwrite));
+	}
+
+	return (0);
+}
+
+static int message_handler_req_exec_ckpt_sectionoverwrite (int fd, void *message) {
+	struct req_exec_ckpt_sectionoverwrite *req_exec_ckpt_sectionoverwrite = (struct req_exec_ckpt_sectionoverwrite *)message;
+	struct req_lib_ckpt_sectionoverwrite *req_lib_ckpt_sectionoverwrite = (struct req_lib_ckpt_sectionoverwrite *)&req_exec_ckpt_sectionoverwrite->req_lib_ckpt_sectionoverwrite;
+	struct res_lib_ckpt_sectionoverwrite res_lib_ckpt_sectionoverwrite;
+	struct saCkptCheckpoint *ckptCheckpoint;
+	struct saCkptCheckpointSection *ckptCheckpointSection;
+	void *sectionData;
+	SaErrorT error = SA_OK;
+
+	log_printf (LOG_LEVEL_DEBUG, "Executive request to section overwrite.\n");
+	ckptCheckpoint = findCheckpoint (&req_exec_ckpt_sectionoverwrite->checkpointName);
+	if (ckptCheckpoint == 0) {
+		error = SA_ERR_NOT_EXIST;
+		goto error_exit;
+	}
+
+	/*
+	 * Find checkpoint section to be overwritten
+	 */
+	ckptCheckpointSection = findCheckpointSection (ckptCheckpoint,
+		((char *)req_lib_ckpt_sectionoverwrite) +
+			sizeof (struct req_lib_ckpt_sectionoverwrite),
+		req_lib_ckpt_sectionoverwrite->idLen);
+	if (ckptCheckpointSection == 0) {
+		error = SA_ERR_NOT_EXIST;
+		goto error_exit;
+	}
+
+	/*
+	 * Allocate checkpoint section data
+	 */
+	sectionData = malloc (req_lib_ckpt_sectionoverwrite->dataSize);
+	if (sectionData == 0) {
+		error = SA_ERR_NO_MEMORY;
+		goto error_exit;
+	}
+
+	memcpy (sectionData,
+		((char *)req_lib_ckpt_sectionoverwrite) +
+			sizeof (struct req_lib_ckpt_sectionoverwrite) +
+			req_lib_ckpt_sectionoverwrite->idLen,
+		req_lib_ckpt_sectionoverwrite->dataSize);
+
+	/*
+	 * release old checkpoint section data
+	 */
+	free (ckptCheckpointSection->sectionData);
+
+	/*
+	 * Install overwritten checkpoint section data
+	 */
+	ckptCheckpointSection->sectionDescriptor.sectionSize = req_lib_ckpt_sectionoverwrite->dataSize;
+	ckptCheckpointSection->sectionDescriptor.sectionState = SA_CKPT_SECTION_VALID;
+	ckptCheckpointSection->sectionDescriptor.lastUpdate = 0; // TODO current time
+	ckptCheckpointSection->sectionData = sectionData;
+
+	/*
+	 * return result to CKPT library
+	 */
+error_exit:
+	if (req_exec_ckpt_sectionoverwrite->source.in_addr.s_addr == this_ip.sin_addr.s_addr) {
+		res_lib_ckpt_sectionoverwrite.header.magic = MESSAGE_MAGIC;
+		res_lib_ckpt_sectionoverwrite.header.size = sizeof (struct res_lib_ckpt_sectionoverwrite);
+		res_lib_ckpt_sectionoverwrite.header.id = MESSAGE_RES_CKPT_CHECKPOINT_SECTIONOVERWRITE;
+		res_lib_ckpt_sectionoverwrite.error = error;
+
+		libais_send_response (req_exec_ckpt_sectionoverwrite->source.fd,
+			&res_lib_ckpt_sectionoverwrite,
+			sizeof (struct res_lib_ckpt_sectionoverwrite));
+	}
+	return (0);
+}
+static int message_handler_req_exec_ckpt_sectionread (int fd, void *message) {
+	struct req_exec_ckpt_sectionread *req_exec_ckpt_sectionread = (struct req_exec_ckpt_sectionread *)message;
+	struct req_lib_ckpt_sectionread *req_lib_ckpt_sectionread = (struct req_lib_ckpt_sectionread *)&req_exec_ckpt_sectionread->req_lib_ckpt_sectionread;
+	struct res_lib_ckpt_sectionread res_lib_ckpt_sectionread;
+	struct saCkptCheckpoint *ckptCheckpoint;
+	struct saCkptCheckpointSection *ckptCheckpointSection = 0;
+	int sectionSize = 0;
+	SaErrorT error = SA_OK;
+
+	log_printf (LOG_LEVEL_DEBUG, "Executive request for section read.\n");
+
+	ckptCheckpoint = findCheckpoint (&req_exec_ckpt_sectionread->checkpointName);
+	if (ckptCheckpoint == 0) {
+		error = SA_ERR_SYSTEM; // TODO find the right error for this
+		goto error_exit;
+	}
+
+	/*
+	 * Find checkpoint section to be read
+	 */
+	ckptCheckpointSection = findCheckpointSection (ckptCheckpoint,
+		((char *)req_lib_ckpt_sectionread) +
+			sizeof (struct req_lib_ckpt_sectionread),
+		req_lib_ckpt_sectionread->idLen);
+	if (ckptCheckpointSection == 0) {
+		error = SA_ERR_NOT_EXIST;
+		goto error_exit;
+	}
+
+	/*
+	 * Determine the section size
+	 */
+	sectionSize = ckptCheckpointSection->sectionDescriptor.sectionSize -
+		req_lib_ckpt_sectionread->dataOffset;
+
+	/*
+	 * If the library has less space available then can be sent from the
+	 * section, reduce bytes sent to library to max requested
+	 */
+	if (sectionSize > req_lib_ckpt_sectionread->dataSize) {
+		sectionSize = req_lib_ckpt_sectionread->dataSize;
+	}
+
+	/*
+	 * If dataOffset is past end of data, return INVALID PARAM
+	 */
+	if (req_lib_ckpt_sectionread->dataOffset > sectionSize) {
+		sectionSize = 0;
+		error = SA_ERR_INVALID_PARAM;
+		goto error_exit;
+	}
+
+	/*
+	 * Write read response to CKPT library
+	 */
+error_exit:
+	if (req_exec_ckpt_sectionread->source.in_addr.s_addr == this_ip.sin_addr.s_addr) {
+		res_lib_ckpt_sectionread.header.magic = MESSAGE_MAGIC;
+		res_lib_ckpt_sectionread.header.size = sizeof (struct res_lib_ckpt_sectionread) + sectionSize;
+		res_lib_ckpt_sectionread.header.id = MESSAGE_RES_CKPT_CHECKPOINT_SECTIONREAD;
+		res_lib_ckpt_sectionread.error = error;
+	
+		libais_send_response (req_exec_ckpt_sectionread->source.fd,
+			&res_lib_ckpt_sectionread,
+			sizeof (struct res_lib_ckpt_sectionread));
+
+		/*
+		 * Write checkpoint to CKPT library section if section has data
+		 */
+		if (sectionSize) {
+			char *sd;
+			sd = (char *)ckptCheckpointSection->sectionData;
+			libais_send_response (req_exec_ckpt_sectionread->source.fd,
+				&sd[req_lib_ckpt_sectionread->dataOffset],
+				sectionSize);
+		}
+	}
+	return (0);
+}
+
+static int message_handler_req_lib_ckpt_init (int fd, void *message)
+{
+	struct res_lib_init res_lib_init;
+	SaErrorT error = SA_ERR_SECURITY;
+
+	log_printf (LOG_LEVEL_DEBUG, "Got request to initialize CKPT.\n");
+
+	if (connections[fd].authenticated) {
+		connections[fd].service = SOCKET_SERVICE_CKPT;
+		error = SA_OK;
+	}
+
+	res_lib_init.header.magic = MESSAGE_MAGIC;
+	res_lib_init.header.size = sizeof (struct res_lib_init);
+	res_lib_init.header.id = MESSAGE_RES_INIT;
+	res_lib_init.error = error;
+
+	libais_send_response (fd, &res_lib_init, sizeof (res_lib_init));
+
+	if (connections[fd].authenticated) {
+		return (0);
+	}
+	return (-1);
+}
+
+static int message_handler_req_lib_ckpt_checkpoint_init (int fd, void *message)
+{
+	struct res_lib_init res_lib_init;
+	SaErrorT error = SA_ERR_SECURITY;
+
+	log_printf (LOG_LEVEL_DEBUG, "Got request to initialize CKPT checkpoint.\n");
+
+	if (connections[fd].authenticated) {
+    	connections[fd].service = SOCKET_SERVICE_CKPT_CHECKPOINT;
+		connections[fd].ais_ci.u.libckpt_ci.checkpoint = 0;
+		connections[fd].ais_ci.u.libckpt_ci.checkpointOpenFlags = 0;
+		error = SA_OK;
+	}
+
+	res_lib_init.header.magic = MESSAGE_MAGIC;
+	res_lib_init.header.size = sizeof (struct res_lib_init);
+	res_lib_init.header.id = MESSAGE_RES_INIT;
+	res_lib_init.error = error;
+
+	libais_send_response (fd, &res_lib_init, sizeof (res_lib_init));
+
+	if (connections[fd].authenticated) {
+		return (0);
+	}
+	return (-1);
+}
+
+static int message_handler_req_lib_ckpt_sectioniterator_init (int fd, void *message)
+{
+	struct res_lib_init res_lib_init;
+	SaErrorT error = SA_ERR_SECURITY;
+
+	log_printf (LOG_LEVEL_DEBUG, "Got request to initialize CKPT section iterator.\n");
+
+	if (connections[fd].authenticated) {
+		connections[fd].service = SOCKET_SERVICE_CKPT_SECTIONITERATOR;
+		list_init (&connections[fd].ais_ci.u.libckpt_ci.sectionIterator.list);
+		connections[fd].ais_ci.u.libckpt_ci.sectionIterator.sectionIteratorEntries = 0;
+		connections[fd].ais_ci.u.libckpt_ci.sectionIterator.iteratorCount = 0;
+		connections[fd].ais_ci.u.libckpt_ci.sectionIterator.iteratorPos = 0;
+		list_add (&connections[fd].ais_ci.u.libckpt_ci.sectionIterator.list,
+			&checkpointIteratorListHead);
+		error = SA_OK;
+	}
+
+	res_lib_init.header.magic = MESSAGE_MAGIC;
+	res_lib_init.header.size = sizeof (struct res_lib_init);
+	res_lib_init.header.id = MESSAGE_RES_INIT;
+	res_lib_init.error = error;
+
+	libais_send_response (fd, &res_lib_init, sizeof (res_lib_init));
+
+	if (connections[fd].authenticated) {
+		return (0);
+	}
+	return (-1);
+}
+
+static int message_handler_req_lib_ckpt_checkpointopen (int fd, void *message)
+{
+	struct req_lib_ckpt_checkpointopen *req_lib_ckpt_checkpointopen = (struct req_lib_ckpt_checkpointopen *)message;
+	struct req_exec_ckpt_checkpointopen req_exec_ckpt_checkpointopen;
+	struct iovec iovecs[2];
+	int result;
+
+	log_printf (LOG_LEVEL_DEBUG, "Library request to open checkpoint.\n");
+	req_exec_ckpt_checkpointopen.header.magic = MESSAGE_MAGIC;
+	req_exec_ckpt_checkpointopen.header.size =
+		sizeof (struct req_exec_ckpt_checkpointopen);
+	req_exec_ckpt_checkpointopen.header.id = MESSAGE_REQ_EXEC_CKPT_CHECKPOINTOPEN;
+
+	req_exec_ckpt_checkpointopen.source.fd = fd;
+	req_exec_ckpt_checkpointopen.source.in_addr.s_addr = this_ip.sin_addr.s_addr;
+
+	memcpy (&req_exec_ckpt_checkpointopen.req_lib_ckpt_checkpointopen,
+		req_lib_ckpt_checkpointopen,
+		sizeof (struct req_lib_ckpt_checkpointopen));
+
+	iovecs[0].iov_base = &req_exec_ckpt_checkpointopen;
+	iovecs[0].iov_len = sizeof (req_exec_ckpt_checkpointopen);
+
+	result = gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+
+	return (0);
+}
+
+static int message_handler_req_lib_ckpt_checkpointopenasync (int fd, void *message)
+{
+	return (0);
+}
+
+
+static int message_handler_req_lib_ckpt_checkpointunlink (int fd, void *message)
+{
+	struct req_lib_ckpt_checkpointunlink *req_lib_ckpt_checkpointunlink = (struct req_lib_ckpt_checkpointunlink *)message;
+	struct req_exec_ckpt_checkpointunlink req_exec_ckpt_checkpointunlink;
+	struct iovec iovecs[2];
+	int result;
+
+	req_exec_ckpt_checkpointunlink.header.magic = MESSAGE_MAGIC;
+	req_exec_ckpt_checkpointunlink.header.size =
+		sizeof (struct req_exec_ckpt_checkpointunlink);
+	req_exec_ckpt_checkpointunlink.header.id = MESSAGE_REQ_EXEC_CKPT_CHECKPOINTUNLINK;
+
+	req_exec_ckpt_checkpointunlink.source.fd = fd;
+	req_exec_ckpt_checkpointunlink.source.in_addr.s_addr = this_ip.sin_addr.s_addr;
+
+	memcpy (&req_exec_ckpt_checkpointunlink.req_lib_ckpt_checkpointunlink,
+		req_lib_ckpt_checkpointunlink,
+		sizeof (struct req_lib_ckpt_checkpointunlink));
+
+	iovecs[0].iov_base = &req_exec_ckpt_checkpointunlink;
+	iovecs[0].iov_len = sizeof (req_exec_ckpt_checkpointunlink);
+
+	result = gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+
+	return (0);
+}
+
+static int message_handler_req_lib_ckpt_checkpointretentiondurationset (int fd, void *message)
+{
+	struct req_lib_ckpt_checkpointretentiondurationset *req_lib_ckpt_checkpointretentiondurationset = (struct req_lib_ckpt_checkpointretentiondurationset *)message;
+	struct req_exec_ckpt_checkpointretentiondurationset req_exec_ckpt_checkpointretentiondurationset;
+	struct iovec iovecs[2];
+
+	log_printf (LOG_LEVEL_DEBUG, "DURATION SET FROM API fd %d\n", fd);
+	req_exec_ckpt_checkpointretentiondurationset.header.magic = MESSAGE_MAGIC;
+	req_exec_ckpt_checkpointretentiondurationset.header.id = MESSAGE_REQ_EXEC_CKPT_CHECKPOINTRETENTIONDURATIONSET;
+	req_exec_ckpt_checkpointretentiondurationset.header.size = sizeof (struct req_exec_ckpt_checkpointretentiondurationset);
+	memcpy (&req_exec_ckpt_checkpointretentiondurationset.checkpointName,
+		&connections[fd].ais_ci.u.libckpt_ci.checkpoint->name,
+		sizeof (SaNameT));
+	req_exec_ckpt_checkpointretentiondurationset.retentionDuration = req_lib_ckpt_checkpointretentiondurationset->retentionDuration;
+
+	iovecs[0].iov_base = &req_exec_ckpt_checkpointretentiondurationset;
+	iovecs[0].iov_len = sizeof (req_exec_ckpt_checkpointretentiondurationset);
+
+	gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+
+	return (0);
+}
+
+static int message_handler_req_lib_ckpt_activecheckpointset (int fd, void *message)
+{
+	return (0);
+}
+
+static int message_handler_req_lib_ckpt_checkpointstatusget (int fd, void *message)
+{
+	struct req_lib_ckpt_checkpointstatusget *req_lib_ckpt_checkpointstatusget = (struct req_lib_ckpt_checkpointstatusget *)message;
+	struct res_lib_ckpt_checkpointstatusget res_lib_ckpt_checkpointstatusget;
+	struct saCkptCheckpoint *checkpoint;
+	int memoryUsed = 0;
+	int numberOfSections = 0;
+	struct list_head *checkpointSectionList;
+	struct saCkptCheckpointSection *checkpointSection;
+
+	req_lib_ckpt_checkpointstatusget = 0; /* The request info isn't used */
+	log_printf (LOG_LEVEL_DEBUG, "in status get\n");
+
+	/*
+	 * Count memory used by checkpoint sections
+	 */
+	checkpoint = connections[fd].ais_ci.u.libckpt_ci.checkpoint;
+	for (checkpointSectionList = checkpoint->checkpointSectionsListHead.next;
+		checkpointSectionList != &checkpoint->checkpointSectionsListHead;
+		checkpointSectionList = checkpointSectionList->next) {
+
+		checkpointSection = list_entry (checkpointSectionList,
+			struct saCkptCheckpointSection, list);
+
+		memoryUsed += checkpointSection->sectionDescriptor.sectionSize;
+		numberOfSections += 1;
+	}
+
+	/*
+	 * Build checkpoint status get response
+	 */
+	res_lib_ckpt_checkpointstatusget.header.magic = MESSAGE_MAGIC;
+	res_lib_ckpt_checkpointstatusget.header.size = sizeof (struct res_lib_ckpt_checkpointstatusget);
+	res_lib_ckpt_checkpointstatusget.header.id = MESSAGE_RES_CKPT_CHECKPOINT_CHECKPOINTSTATUSGET;
+
+	memcpy (&res_lib_ckpt_checkpointstatusget.checkpointStatus.checkpointCreationAttributes,
+		&checkpoint->checkpointCreationAttributes,
+		sizeof (SaCkptCheckpointCreationAttributesT));
+	res_lib_ckpt_checkpointstatusget.checkpointStatus.numberOfSections = numberOfSections;
+	res_lib_ckpt_checkpointstatusget.checkpointStatus.memoryUsed = memoryUsed;
+
+	log_printf (LOG_LEVEL_DEBUG, "before sending message\n");
+	libais_send_response (fd, &res_lib_ckpt_checkpointstatusget,
+		sizeof (struct res_lib_ckpt_checkpointstatusget));
+	return (0);
+}
+
+static int message_handler_req_lib_ckpt_sectioncreate (int fd, void *message)
+{
+	struct req_lib_ckpt_sectioncreate *req_lib_ckpt_sectioncreate = (struct req_lib_ckpt_sectioncreate *)message;
+	struct req_exec_ckpt_sectioncreate req_exec_ckpt_sectioncreate;
+	struct res_lib_ckpt_sectioncreate res_lib_ckpt_sectioncreate;
+	struct iovec iovecs[2];
+
+	log_printf (LOG_LEVEL_DEBUG, "Section create from API fd %d\n", fd);
+	/*
+	 * Determine if checkpoint is opened in write mode If not, send error to api
+	 */
+	if ((connections[fd].ais_ci.u.libckpt_ci.checkpointOpenFlags & SA_CKPT_CHECKPOINT_WRITE) == 0) {
+		res_lib_ckpt_sectioncreate.header.magic = MESSAGE_MAGIC;
+		res_lib_ckpt_sectioncreate.header.size = sizeof (struct res_lib_ckpt_sectioncreate);
+		res_lib_ckpt_sectioncreate.header.id = MESSAGE_RES_CKPT_CHECKPOINT_SECTIONCREATE;
+		res_lib_ckpt_sectioncreate.error = SA_ERR_ACCESS;
+
+		libais_send_response (fd, &res_lib_ckpt_sectioncreate,
+			sizeof (struct res_lib_ckpt_sectioncreate));
+		return (0);
+	}
+
+	/*
+	 * checkpoint opened is writeable mode so send message to cluster
+	 */
+	req_exec_ckpt_sectioncreate.header.magic = MESSAGE_MAGIC;
+	req_exec_ckpt_sectioncreate.header.id = MESSAGE_REQ_EXEC_CKPT_SECTIONCREATE;
+	req_exec_ckpt_sectioncreate.header.size = sizeof (struct req_exec_ckpt_sectioncreate);
+
+	memcpy (&req_exec_ckpt_sectioncreate.req_lib_ckpt_sectioncreate,
+		req_lib_ckpt_sectioncreate,
+		sizeof (struct req_lib_ckpt_sectioncreate));
+
+	memcpy (&req_exec_ckpt_sectioncreate.checkpointName,
+		&connections[fd].ais_ci.u.libckpt_ci.checkpoint->name,
+		sizeof (SaNameT));
+
+	req_exec_ckpt_sectioncreate.source.fd = fd;
+	req_exec_ckpt_sectioncreate.source.in_addr.s_addr = this_ip.sin_addr.s_addr;
+
+	iovecs[0].iov_base = &req_exec_ckpt_sectioncreate;
+	iovecs[0].iov_len = sizeof (req_exec_ckpt_sectioncreate);
+	/*
+	 * Send section name and initial data in message
+	 */
+	iovecs[1].iov_base = ((char *)req_lib_ckpt_sectioncreate) + sizeof (struct req_lib_ckpt_sectioncreate);
+	iovecs[1].iov_len = req_lib_ckpt_sectioncreate->header.size - sizeof (struct req_lib_ckpt_sectioncreate);
+
+#ifdef DEBUG
+printf ("LIBRARY SECTIONCREATE string is %s len is %d\n", iovecs[1].iov_base, iovecs[1].iov_len);
+printf ("|\n");
+{ int i;
+	char *suck = iovecs[1].iov_base;
+for (i = 0; i < 14;i++) {
+
+	printf ("%c ", suck[i]);
+}
+}
+printf ("|\n");
+#endif
+	if (iovecs[1].iov_len > 0) {
+		log_printf (LOG_LEVEL_DEBUG, "IOV_BASE is %s\n", iovecs[1].iov_base);
+		gmi_mcast (&aisexec_groupname, iovecs, 2, GMI_PRIO_MED);
+	} else {
+		gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+	}
+
+	return (0);
+}
+
+static int message_handler_req_lib_ckpt_sectiondelete (int fd, void *message)
+{
+	struct req_lib_ckpt_sectiondelete *req_lib_ckpt_sectiondelete = (struct req_lib_ckpt_sectiondelete *)message;
+	struct req_exec_ckpt_sectiondelete req_exec_ckpt_sectiondelete;
+	struct iovec iovecs[2];
+
+	log_printf (LOG_LEVEL_DEBUG, "section delete from API fd %d\n", fd);
+
+	req_exec_ckpt_sectiondelete.header.magic = MESSAGE_MAGIC;
+	req_exec_ckpt_sectiondelete.header.id = MESSAGE_REQ_EXEC_CKPT_SECTIONDELETE;
+	req_exec_ckpt_sectiondelete.header.size = sizeof (struct req_exec_ckpt_sectiondelete);
+
+	memcpy (&req_exec_ckpt_sectiondelete.checkpointName,
+		&connections[fd].ais_ci.u.libckpt_ci.checkpoint->name,
+		sizeof (SaNameT));
+
+	memcpy (&req_exec_ckpt_sectiondelete.req_lib_ckpt_sectiondelete,
+		req_lib_ckpt_sectiondelete,
+		sizeof (struct req_lib_ckpt_sectiondelete));
+
+	req_exec_ckpt_sectiondelete.source.fd = fd;
+	req_exec_ckpt_sectiondelete.source.in_addr.s_addr = this_ip.sin_addr.s_addr;
+
+	iovecs[0].iov_base = &req_exec_ckpt_sectiondelete;
+	iovecs[0].iov_len = sizeof (req_exec_ckpt_sectiondelete);
+
+	/*
+	 * Send section name
+	 */
+	iovecs[1].iov_base = ((char *)req_lib_ckpt_sectiondelete) + sizeof (struct req_lib_ckpt_sectiondelete);
+	iovecs[1].iov_len = req_lib_ckpt_sectiondelete->header.size - sizeof (struct req_lib_ckpt_sectiondelete);
+
+	if (iovecs[1].iov_len > 0) {
+		log_printf (LOG_LEVEL_DEBUG, "IOV_BASE is %s\n", iovecs[1].iov_base);
+		gmi_mcast (&aisexec_groupname, iovecs, 2, GMI_PRIO_MED);
+	} else {
+		gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+	}
+
+	return (0);
+}
+
+static int message_handler_req_lib_ckpt_sectionexpirationtimeset (int fd, void *message)
+{
+	struct req_lib_ckpt_sectionexpirationtimeset *req_lib_ckpt_sectionexpirationtimeset = (struct req_lib_ckpt_sectionexpirationtimeset *)message;
+	struct req_exec_ckpt_sectionexpirationtimeset req_exec_ckpt_sectionexpirationtimeset;
+	struct iovec iovecs[2];
+
+	log_printf (LOG_LEVEL_DEBUG, "section expiration time set fd=%d\n", fd);
+	req_exec_ckpt_sectionexpirationtimeset.header.magic = MESSAGE_MAGIC;
+	req_exec_ckpt_sectionexpirationtimeset.header.id = MESSAGE_REQ_EXEC_CKPT_SECTIONEXPIRATIONTIMESET;
+	req_exec_ckpt_sectionexpirationtimeset.header.size = sizeof (struct req_exec_ckpt_sectionexpirationtimeset);
+
+	memcpy (&req_exec_ckpt_sectionexpirationtimeset.checkpointName,
+		&connections[fd].ais_ci.u.libckpt_ci.checkpoint->name,
+		sizeof (SaNameT));
+
+	memcpy (&req_exec_ckpt_sectionexpirationtimeset.req_lib_ckpt_sectionexpirationtimeset,
+		req_lib_ckpt_sectionexpirationtimeset,
+		sizeof (struct req_lib_ckpt_sectionexpirationtimeset));
+
+	req_exec_ckpt_sectionexpirationtimeset.source.fd = fd;
+	req_exec_ckpt_sectionexpirationtimeset.source.in_addr.s_addr = this_ip.sin_addr.s_addr;
+
+	iovecs[0].iov_base = &req_exec_ckpt_sectionexpirationtimeset;
+	iovecs[0].iov_len = sizeof (req_exec_ckpt_sectionexpirationtimeset);
+
+	/*
+	 * Send section name
+	 */
+	iovecs[1].iov_base = ((char *)req_lib_ckpt_sectionexpirationtimeset) + sizeof (struct req_lib_ckpt_sectionexpirationtimeset);
+	iovecs[1].iov_len = req_lib_ckpt_sectionexpirationtimeset->header.size - sizeof (struct req_lib_ckpt_sectionexpirationtimeset);
+
+	if (iovecs[1].iov_len > 0) {
+		log_printf (LOG_LEVEL_DEBUG, "IOV_BASE is %s\n", iovecs[1].iov_base);
+		gmi_mcast (&aisexec_groupname, iovecs, 2, GMI_PRIO_MED);
+	} else {
+		gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+	}
+
+	return (0);
+}
+
+int write_inv = 0;
+static int message_handler_req_lib_ckpt_sectionwrite (int fd, void *message)
+{
+	struct req_lib_ckpt_sectionwrite *req_lib_ckpt_sectionwrite = (struct req_lib_ckpt_sectionwrite *)message;
+	struct req_exec_ckpt_sectionwrite req_exec_ckpt_sectionwrite;
+	struct res_lib_ckpt_sectionwrite res_lib_ckpt_sectionwrite;
+	struct iovec iovecs[2];
+
+	log_printf (LOG_LEVEL_DEBUG, "Section write from API fd %d\n", fd);
+// UNDO printf ("section write %d\n", write_inv++);
+	/*
+	 * Determine if checkpoint is opened in write mode If not, send error to api
+	 */
+	if ((connections[fd].ais_ci.u.libckpt_ci.checkpointOpenFlags & SA_CKPT_CHECKPOINT_WRITE) == 0) {
+		res_lib_ckpt_sectionwrite.header.magic = MESSAGE_MAGIC;
+		res_lib_ckpt_sectionwrite.header.size = sizeof (struct res_lib_ckpt_sectionwrite);
+		res_lib_ckpt_sectionwrite.header.id = MESSAGE_RES_CKPT_CHECKPOINT_SECTIONWRITE;
+		res_lib_ckpt_sectionwrite.error = SA_ERR_ACCESS;
+
+		libais_send_response (fd, &res_lib_ckpt_sectionwrite,
+			sizeof (struct res_lib_ckpt_sectionwrite));
+		return (0);
+	}
+
+	/*
+	 * checkpoint opened is writeable mode so send message to cluster
+	 */
+	req_exec_ckpt_sectionwrite.header.magic = MESSAGE_MAGIC;
+	req_exec_ckpt_sectionwrite.header.id = MESSAGE_REQ_EXEC_CKPT_SECTIONWRITE;
+	req_exec_ckpt_sectionwrite.header.size = sizeof (struct req_exec_ckpt_sectionwrite);
+
+	memcpy (&req_exec_ckpt_sectionwrite.req_lib_ckpt_sectionwrite,
+		req_lib_ckpt_sectionwrite,
+		sizeof (struct req_lib_ckpt_sectionwrite));
+
+	memcpy (&req_exec_ckpt_sectionwrite.checkpointName,
+		&connections[fd].ais_ci.u.libckpt_ci.checkpoint->name,
+		sizeof (SaNameT));
+
+	req_exec_ckpt_sectionwrite.source.fd = fd;
+	req_exec_ckpt_sectionwrite.source.in_addr.s_addr = this_ip.sin_addr.s_addr;
+
+	iovecs[0].iov_base = &req_exec_ckpt_sectionwrite;
+	iovecs[0].iov_len = sizeof (req_exec_ckpt_sectionwrite);
+	/*
+	 * Send section name and data to write in message
+	 */
+	iovecs[1].iov_base = ((char *)req_lib_ckpt_sectionwrite) + sizeof (struct req_lib_ckpt_sectionwrite);
+	iovecs[1].iov_len = req_lib_ckpt_sectionwrite->header.size - sizeof (struct req_lib_ckpt_sectionwrite);
+
+//printf ("LIB writing checkpoint section is %s\n", ((char *)req_lib_ckpt_sectionwrite) + sizeof (struct req_lib_ckpt_sectionwrite));
+	if (iovecs[1].iov_len > 0) {
+		gmi_mcast (&aisexec_groupname, iovecs, 2, GMI_PRIO_MED);
+	} else {
+		gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+	}
+
+	return (0);
+}
+
+static int message_handler_req_lib_ckpt_sectionoverwrite (int fd, void *message)
+{
+	struct req_lib_ckpt_sectionoverwrite *req_lib_ckpt_sectionoverwrite = (struct req_lib_ckpt_sectionoverwrite *)message;
+	struct req_exec_ckpt_sectionoverwrite req_exec_ckpt_sectionoverwrite;
+	struct res_lib_ckpt_sectionoverwrite res_lib_ckpt_sectionoverwrite;
+	struct iovec iovecs[2];
+
+	log_printf (LOG_LEVEL_DEBUG, "Section overwrite from API fd %d\n", fd);
+	/*
+	 * Determine if checkpoint is opened in write mode If not, send error to api
+	 */
+	if ((connections[fd].ais_ci.u.libckpt_ci.checkpointOpenFlags & SA_CKPT_CHECKPOINT_WRITE) == 0) {
+		res_lib_ckpt_sectionoverwrite.header.magic = MESSAGE_MAGIC;
+		res_lib_ckpt_sectionoverwrite.header.size = sizeof (struct res_lib_ckpt_sectionoverwrite);
+		res_lib_ckpt_sectionoverwrite.header.id = MESSAGE_RES_CKPT_CHECKPOINT_SECTIONOVERWRITE;
+		res_lib_ckpt_sectionoverwrite.error = SA_ERR_ACCESS;
+
+		libais_send_response (fd, &res_lib_ckpt_sectionoverwrite,
+			sizeof (struct res_lib_ckpt_sectionoverwrite));
+		return (0);
+	}
+
+	/*
+	 * checkpoint opened is writeable mode so send message to cluster
+	 */
+	req_exec_ckpt_sectionoverwrite.header.magic = MESSAGE_MAGIC;
+	req_exec_ckpt_sectionoverwrite.header.id = MESSAGE_REQ_EXEC_CKPT_SECTIONOVERWRITE;
+	req_exec_ckpt_sectionoverwrite.header.size = sizeof (struct req_exec_ckpt_sectionoverwrite);
+
+	memcpy (&req_exec_ckpt_sectionoverwrite.req_lib_ckpt_sectionoverwrite,
+		req_lib_ckpt_sectionoverwrite,
+		sizeof (struct req_lib_ckpt_sectionoverwrite));
+
+	memcpy (&req_exec_ckpt_sectionoverwrite.checkpointName,
+		&connections[fd].ais_ci.u.libckpt_ci.checkpoint->name,
+		sizeof (SaNameT));
+
+	req_exec_ckpt_sectionoverwrite.source.fd = fd;
+	req_exec_ckpt_sectionoverwrite.source.in_addr.s_addr = this_ip.sin_addr.s_addr;
+
+	iovecs[0].iov_base = &req_exec_ckpt_sectionoverwrite;
+	iovecs[0].iov_len = sizeof (req_exec_ckpt_sectionoverwrite);
+	/*
+	 * Send section name and data to overwrite in message
+	 */
+	iovecs[1].iov_base = ((char *)req_lib_ckpt_sectionoverwrite) + sizeof (struct req_lib_ckpt_sectionoverwrite);
+	iovecs[1].iov_len = req_lib_ckpt_sectionoverwrite->header.size - sizeof (struct req_lib_ckpt_sectionoverwrite);
+
+	if (iovecs[1].iov_len > 0) {
+		gmi_mcast (&aisexec_groupname, iovecs, 2, GMI_PRIO_MED);
+	} else {
+		gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+	}
+
+	return (0);
+}
+
+static int message_handler_req_lib_ckpt_sectionread (int fd, void *message)
+{
+	struct req_lib_ckpt_sectionread *req_lib_ckpt_sectionread = (struct req_lib_ckpt_sectionread *)message;
+	struct req_exec_ckpt_sectionread req_exec_ckpt_sectionread;
+	struct res_lib_ckpt_sectionread res_lib_ckpt_sectionread;
+	struct iovec iovecs[2];
+
+	log_printf (LOG_LEVEL_DEBUG, "Section overwrite from API fd %d\n", fd);
+	/*
+	 * Determine if checkpoint is opened in write mode If not, send error to api
+	 */
+	if ((connections[fd].ais_ci.u.libckpt_ci.checkpointOpenFlags & SA_CKPT_CHECKPOINT_READ) == 0) {
+		res_lib_ckpt_sectionread.header.magic = MESSAGE_MAGIC;
+		res_lib_ckpt_sectionread.header.size = sizeof (struct res_lib_ckpt_sectionread);
+		res_lib_ckpt_sectionread.header.id = MESSAGE_RES_CKPT_CHECKPOINT_SECTIONREAD;
+		res_lib_ckpt_sectionread.error = SA_ERR_ACCESS;
+
+		libais_send_response (fd, &res_lib_ckpt_sectionread,
+			sizeof (struct res_lib_ckpt_sectionread));
+		return (0);
+	}
+
+	/*
+	 * checkpoint opened is writeable mode so send message to cluster
+	 */
+	req_exec_ckpt_sectionread.header.magic = MESSAGE_MAGIC;
+	req_exec_ckpt_sectionread.header.id = MESSAGE_REQ_EXEC_CKPT_SECTIONREAD;
+	req_exec_ckpt_sectionread.header.size = sizeof (struct req_exec_ckpt_sectionread);
+
+	memcpy (&req_exec_ckpt_sectionread.req_lib_ckpt_sectionread,
+		req_lib_ckpt_sectionread,
+		sizeof (struct req_lib_ckpt_sectionread));
+
+	memcpy (&req_exec_ckpt_sectionread.checkpointName,
+		&connections[fd].ais_ci.u.libckpt_ci.checkpoint->name,
+		sizeof (SaNameT));
+
+	req_exec_ckpt_sectionread.source.fd = fd;
+	req_exec_ckpt_sectionread.source.in_addr.s_addr = this_ip.sin_addr.s_addr;
+
+	iovecs[0].iov_base = &req_exec_ckpt_sectionread;
+	iovecs[0].iov_len = sizeof (req_exec_ckpt_sectionread);
+	/*
+	 * Send section name and data to overwrite in message
+	 */
+	iovecs[1].iov_base = ((char *)req_lib_ckpt_sectionread) + sizeof (struct req_lib_ckpt_sectionread);
+	iovecs[1].iov_len = req_lib_ckpt_sectionread->header.size - sizeof (struct req_lib_ckpt_sectionread);
+
+	if (iovecs[1].iov_len > 0) {
+		gmi_mcast (&aisexec_groupname, iovecs, 2, GMI_PRIO_MED);
+	} else {
+		gmi_mcast (&aisexec_groupname, iovecs, 1, GMI_PRIO_MED);
+	}
+
+	return (0);
+}
+
+static int message_handler_req_lib_ckpt_checkpointsynchronize (int fd, void *message)
+{
+	return (0);
+}
+
+static int message_handler_req_lib_ckpt_checkpointsyncronizeasync (int fd, void *message)
+{
+	return (0);
+}
+
+static int message_handler_req_lib_ckpt_sectioniteratorinitialize (int fd, void *message)
+{
+	struct req_lib_ckpt_sectioniteratorinitialize *req_lib_ckpt_sectioniteratorinitialize = (struct req_lib_ckpt_sectioniteratorinitialize *)message;
+	struct res_lib_ckpt_sectioniteratorinitialize res_lib_ckpt_sectioniteratorinitialize;
+	struct saCkptCheckpoint *ckptCheckpoint;
+	struct saCkptCheckpointSection *ckptCheckpointSection;
+	struct saCkptSectionIteratorEntry *ckptSectionIteratorEntries;
+	struct saCkptSectionIterator *ckptSectionIterator;
+	struct list_head *checkpointSectionList;
+	int addEntry = 0;
+	int iteratorEntries = 0;
+	SaErrorT error = SA_OK;
+
+	log_printf (LOG_LEVEL_DEBUG, "section iterator initialize\n");
+	ckptSectionIterator = &connections[fd].ais_ci.u.libckpt_ci.sectionIterator;
+
+	ckptCheckpoint = findCheckpoint (&req_lib_ckpt_sectioniteratorinitialize->checkpointName);
+	if (ckptCheckpoint == 0) {
+		error = SA_ERR_NOT_EXIST;
+		goto error_exit;
+	}
+
+	/*
+	 * Iterate list of checkpoint sections
+	 */
+	for (checkpointSectionList = ckptCheckpoint->checkpointSectionsListHead.next;
+		checkpointSectionList != &ckptCheckpoint->checkpointSectionsListHead;
+		checkpointSectionList = checkpointSectionList->next) {
+
+		ckptCheckpointSection = list_entry (checkpointSectionList,
+			struct saCkptCheckpointSection, list);
+
+		addEntry = 1;
+
+		/*
+		 * Item should be added to iterator list
+		 */
+		if (addEntry) {
+			iteratorEntries += 1;
+			ckptSectionIteratorEntries =
+				realloc (ckptSectionIterator->sectionIteratorEntries,
+				sizeof (struct saCkptSectionIteratorEntry) * iteratorEntries);
+			if (ckptSectionIteratorEntries == 0) {
+				if (ckptSectionIterator->sectionIteratorEntries) {
+					free (ckptSectionIterator->sectionIteratorEntries);
+				}
+				error = SA_ERR_NO_MEMORY;
+				goto error_exit;
+			}
+			ckptSectionIteratorEntries[iteratorEntries - 1].active = 1;
+			ckptSectionIteratorEntries[iteratorEntries - 1].checkpointSection = ckptCheckpointSection;
+			ckptSectionIterator->sectionIteratorEntries = ckptSectionIteratorEntries;
+		}
+	}
+	ckptSectionIterator->iteratorCount = iteratorEntries;
+
+error_exit:
+	res_lib_ckpt_sectioniteratorinitialize.header.magic = MESSAGE_MAGIC;
+	res_lib_ckpt_sectioniteratorinitialize.header.size = sizeof (struct res_lib_ckpt_sectioniteratorinitialize);
+	res_lib_ckpt_sectioniteratorinitialize.header.id = MESSAGE_RES_CKPT_SECTIONITERATOR_SECTIONITERATORINITIALIZE;
+	res_lib_ckpt_sectioniteratorinitialize.error = error;
+
+	libais_send_response (fd, &res_lib_ckpt_sectioniteratorinitialize,
+		sizeof (struct res_lib_ckpt_sectioniteratorinitialize));
+
+	return (0);
+}
+
+static int message_handler_req_lib_ckpt_sectioniteratornext (int fd, void *message)
+{
+	struct req_lib_ckpt_sectioniteratornext *req_lib_ckpt_sectioniteratornext = (struct req_lib_ckpt_sectioniteratornext *)message;
+	struct res_lib_ckpt_sectioniteratornext res_lib_ckpt_sectioniteratornext;
+	struct saCkptSectionIterator *ckptSectionIterator;
+	SaErrorT error = SA_OK;
+	int sectionIdSize = 0;
+	int iteratorPos = 0;
+
+	req_lib_ckpt_sectioniteratornext = 0; /* this variable not used */
+
+	log_printf (LOG_LEVEL_DEBUG, "section iterator next\n");
+	ckptSectionIterator = &connections[fd].ais_ci.u.libckpt_ci.sectionIterator;
+
+	/*
+	 * Find active iterator entry
+	 */
+	for (;;) {
+		/*
+		 * No more sections in iterator
+		 */
+		if (ckptSectionIterator->iteratorPos + 1 >= ckptSectionIterator->iteratorCount) {
+			error = SA_ERR_NOT_EXIST;
+			goto error_exit;
+		}
+
+		/*
+		 * active iterator entry
+		 */
+		if (ckptSectionIterator->sectionIteratorEntries[ckptSectionIterator->iteratorPos].active == 1) {
+			break;
+		}
+
+		ckptSectionIterator->iteratorPos += 1;
+	}
+
+	/*
+	 * Prepare response to API
+	 */
+	iteratorPos = ckptSectionIterator->iteratorPos;
+
+	sectionIdSize = ckptSectionIterator->sectionIteratorEntries[iteratorPos].checkpointSection->sectionDescriptor.sectionId.idLen;
+
+	memcpy (&res_lib_ckpt_sectioniteratornext.sectionDescriptor, 
+		&ckptSectionIterator->sectionIteratorEntries[iteratorPos].checkpointSection->sectionDescriptor,
+		sizeof (SaCkptSectionDescriptorT));
+
+	/*
+	 * Get to next iterator entry
+	 */
+	ckptSectionIterator->iteratorPos += 1;
+
+error_exit:
+	res_lib_ckpt_sectioniteratornext.header.magic = MESSAGE_MAGIC;
+	res_lib_ckpt_sectioniteratornext.header.size = sizeof (struct res_lib_ckpt_sectioniteratornext) + sectionIdSize;
+	res_lib_ckpt_sectioniteratornext.header.id = MESSAGE_RES_CKPT_SECTIONITERATOR_SECTIONITERATORNEXT;
+	res_lib_ckpt_sectioniteratornext.error = error;
+
+	libais_send_response (fd, &res_lib_ckpt_sectioniteratornext,
+		sizeof (struct res_lib_ckpt_sectioniteratornext));
+
+	libais_send_response (fd,
+		ckptSectionIterator->sectionIteratorEntries[iteratorPos].checkpointSection->sectionDescriptor.sectionId.id,
+		sectionIdSize);
+	return (0);
+}

+ 81 - 0
exec/ckpt.h

@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "../include/ais_types.h"
+#include "../include/ais_msg.h"
+#include "poll.h"
+#include "parse.h"
+
+#ifndef CKPT_H_DEFINED
+#define CKPT_H_DEFINED
+
+struct saCkptCheckpointSection {
+	struct list_head list;
+	SaCkptSectionDescriptorT sectionDescriptor;
+	void *sectionData;
+};
+
+struct saCkptCheckpoint {
+	struct list_head list;
+	SaNameT name;
+	SaCkptCheckpointCreationAttributesT checkpointCreationAttributes;
+	struct list_head checkpointSectionsListHead;
+	int referenceCount;
+	int unlinked;
+};
+
+struct saCkptSectionIteratorEntry {
+	int active;
+	struct saCkptCheckpointSection *checkpointSection;
+};
+
+struct saCkptSectionIterator {
+	struct list_head list;
+	struct saCkptSectionIteratorEntry *sectionIteratorEntries;
+	int iteratorCount;
+	int iteratorPos;
+};
+
+struct libckpt_ci {
+	struct saCkptCheckpoint *checkpoint;
+	SaCkptCheckpointOpenFlagsT checkpointOpenFlags;
+	struct saCkptSectionIterator sectionIterator;
+};
+
+extern struct service_handler ckpt_service_handler;
+
+extern struct service_handler ckpt_checkpoint_service_handler;
+
+extern struct service_handler ckpt_sectioniterator_service_handler;
+
+#endif /* CKPT_H_DEFINED */

+ 456 - 0
exec/clm.c

@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/sysinfo.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <time.h>
+
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "../include/ais_types.h"
+#include "../include/ais_msg.h"
+#include "../include/list.h"
+#include "../include/queue.h"
+#include "poll.h"
+#include "gmi.h"
+#include "parse.h"
+#include "main.h"
+#include "print.h"
+#include "mempool.h"
+#include "handlers.h"
+
+SaClmClusterChangesT thisClusterNodeLastChange = SA_CLM_NODE_JOINED;
+SaClmClusterNodeT thisClusterNode;
+
+#define NODE_MAX 16
+
+SaClmClusterNodeT clusterNodes[NODE_MAX];
+
+int clusterNodeEntries = 0;
+
+/*
+ * Service Interfaces required by service_message_handler struct
+ */
+static int clmExecutiveInitialize (void);
+
+static int clmConfChg (
+    struct sockaddr_in *member_list, int member_list_entries,
+    struct sockaddr_in *left_list, int left_list_entries,
+    struct sockaddr_in *joined_list, int joined_list_entries);
+
+static int message_handler_req_exec_clm_nodejoin (int fd, void *message);
+
+static int message_handler_req_clm_init (int fd, void *message);
+
+static int message_handler_req_clm_trackstart (int fd, void *message);
+
+static int message_handler_req_clm_trackstop (int fd, void *message);
+
+static int message_handler_req_clm_nodeget (int fd, void *message);
+
+static int (*clm_libais_handler_fns[]) (int fd, void *) = {
+	message_handler_req_clm_trackstart,
+	message_handler_req_clm_trackstop,
+	message_handler_req_clm_nodeget
+};
+
+static int (*clm_aisexec_handler_fns[]) (int fd, void *) = {
+	message_handler_req_exec_clm_nodejoin
+};
+	
+struct service_handler clm_service_handler = {
+	libais_handler_fns:			clm_libais_handler_fns,
+	libais_handler_fns_count:	sizeof (clm_libais_handler_fns) / sizeof (int (*)),
+	aisexec_handler_fns:		clm_aisexec_handler_fns ,
+	aisexec_handler_fns_count:	sizeof (clm_aisexec_handler_fns) / sizeof (int (*)),
+	confchg_fn:					clmConfChg,
+	libais_init_fn:				message_handler_req_clm_init,
+	libais_exit_fn:				0,
+	aisexec_init_fn:			clmExecutiveInitialize
+};
+
+static int clmExecutiveInitialize (void)
+{
+	
+	memset (clusterNodes, 0, sizeof (SaClmClusterNodeT) * NODE_MAX);
+
+	/*
+	 * Build local cluster node data structure
+	 */
+	thisClusterNode.nodeId = this_ip.sin_addr.s_addr;
+	memcpy (&thisClusterNode.nodeAddress.value, &this_ip.sin_addr, sizeof (struct in_addr));
+	thisClusterNode.nodeAddress.length = sizeof (struct in_addr);
+	strcpy (thisClusterNode.nodeName.value, (char *)inet_ntoa (this_ip.sin_addr));
+	thisClusterNode.nodeName.length = strlen (thisClusterNode.nodeName.value);
+	strcpy (thisClusterNode.clusterName.value, "mvlcge");
+	thisClusterNode.clusterName.length = strlen ("mvlcge");
+	thisClusterNode.member = 1;
+	{
+		struct sysinfo s_info;
+		time_t current_time;
+		sysinfo (&s_info);
+		current_time = time (NULL);
+		 /* (currenttime (s) - uptime (s)) * 1 billion (ns) / 1 (s) */
+		thisClusterNode.bootTimestamp = ((SaTimeT)(current_time - s_info.uptime)) * 1000000000;
+	}
+
+#ifdef DEBUG
+    printSaClmClusterNodeT ("this cluster node", &thisClusterNode);
+#endif
+
+	memcpy (&clusterNodes[0], &thisClusterNode, sizeof (SaClmClusterNodeT));
+	clusterNodeEntries = 1;
+
+	return (0);
+}
+
+static void libraryNotificationCurrentState (int fd)
+{
+	struct res_clm_trackcallback res_clm_trackcallback;
+	SaClmClusterNotificationT clusterNotification[NODE_MAX];
+	int i;
+
+	if ((connections[fd].ais_ci.u.libclm_ci.trackFlags & SA_TRACK_CURRENT) == 0) {
+		return;
+	}
+	/*
+	 * Turn off track current
+	 */
+	connections[fd].ais_ci.u.libclm_ci.trackFlags &= ~SA_TRACK_CURRENT;
+
+	/*
+	 * Build notification list
+	 */
+	for (i = 0; i < clusterNodeEntries; i++) {
+		clusterNotification[i].clusterChanges = SA_CLM_NODE_NO_CHANGE;
+
+		memcpy (&clusterNotification[i].clusterNode, &clusterNodes[i],
+			sizeof (SaClmClusterNodeT));
+	}
+
+	/*
+	 * Send track response
+	 */
+	res_clm_trackcallback.header.magic = MESSAGE_MAGIC;
+	res_clm_trackcallback.header.size = sizeof (struct res_clm_trackcallback) +
+		sizeof (SaClmClusterNotificationT) * i;
+	res_clm_trackcallback.header.id = MESSAGE_RES_CLM_TRACKCALLBACK;
+	res_clm_trackcallback.viewNumber = 0;
+	res_clm_trackcallback.numberOfItems = i;
+	res_clm_trackcallback.numberOfMembers = i;
+	res_clm_trackcallback.notificationBufferAddress = 
+		connections[fd].ais_ci.u.libclm_ci.notificationBufferAddress;
+	libais_send_response (fd, &res_clm_trackcallback, sizeof (struct res_clm_trackcallback));
+	libais_send_response (fd, clusterNotification, sizeof (SaClmClusterNotificationT) * i);
+}
+
+static void libraryNotificationJoin (SaClmNodeIdT node)
+{
+	struct res_clm_trackcallback res_clm_trackcallback;
+	SaClmClusterNotificationT clusterNotification;
+	int fd;
+	int i;
+
+	/*
+	 * Generate notification element
+	 */
+	clusterNotification.clusterChanges = SA_CLM_NODE_JOINED;
+	for (i = 0; i < clusterNodeEntries; i++) {
+		if (node == clusterNodes[i].nodeId) {
+			memcpy (&clusterNotification.clusterNode, &clusterNodes[i],
+				sizeof (SaClmClusterNodeT));
+		}
+	}
+
+	/*
+	 * Send notifications to all listeners
+	 */
+	for (fd = 0; fd < connection_entries; fd++) {
+		if (connections[fd].service == SOCKET_SERVICE_CLM &&
+			connections[fd].active &&
+			connections[fd].ais_ci.u.libclm_ci.trackFlags) {
+
+			res_clm_trackcallback.header.magic = MESSAGE_MAGIC;
+			res_clm_trackcallback.header.size = sizeof (struct res_clm_trackcallback) +
+				sizeof (SaClmClusterNotificationT);
+			res_clm_trackcallback.header.id = MESSAGE_RES_CLM_TRACKCALLBACK;
+			res_clm_trackcallback.viewNumber = 0;
+			res_clm_trackcallback.numberOfItems = 1;
+			res_clm_trackcallback.numberOfMembers = 1;
+			res_clm_trackcallback.notificationBufferAddress = 
+				connections[fd].ais_ci.u.libclm_ci.notificationBufferAddress;
+			libais_send_response (fd, &res_clm_trackcallback, sizeof (struct res_clm_trackcallback));
+			libais_send_response (fd, &clusterNotification, sizeof (SaClmClusterNotificationT));
+		}
+	}
+}
+
+static void libraryNotificationLeave (SaClmNodeIdT *nodes, int nodes_entries)
+{
+	struct res_clm_trackcallback res_clm_trackcallback;
+	SaClmClusterNotificationT clusterNotification[NODE_MAX];
+	int fd;
+	int i, j;
+	int notifyEntries;
+
+	/*
+	 * Determine notification list
+	 */
+	for (notifyEntries = 0, i = 0; i < clusterNodeEntries; i++) {
+		for (j = 0; j < nodes_entries; j++) {
+			if (clusterNodes[i].nodeId == nodes[j]) {
+				memcpy (&clusterNotification[notifyEntries].clusterNode, 
+					&clusterNodes[i],
+					sizeof (SaClmClusterNodeT));
+				clusterNotification[notifyEntries].clusterChanges = SA_CLM_NODE_LEFT;
+				notifyEntries += 1;
+				break;
+			}
+		}
+	}
+
+	/*
+	 * Send notifications to all listeners
+	 */
+	for (fd = 0; fd < connection_entries; fd++) {
+		if (connections[fd].service == SOCKET_SERVICE_CLM &&
+			connections[fd].active &&
+			connections[fd].ais_ci.u.libclm_ci.trackFlags) {
+
+			if (notifyEntries) {
+				res_clm_trackcallback.header.magic = MESSAGE_MAGIC;
+				res_clm_trackcallback.header.size = sizeof (struct res_clm_trackcallback) +
+					(notifyEntries * sizeof (SaClmClusterNotificationT));
+				res_clm_trackcallback.header.id = MESSAGE_RES_CLM_TRACKCALLBACK;
+				res_clm_trackcallback.viewNumber = 0;
+				res_clm_trackcallback.numberOfItems = notifyEntries;
+				res_clm_trackcallback.numberOfMembers = notifyEntries;
+				res_clm_trackcallback.notificationBufferAddress = 
+					connections[fd].ais_ci.u.libclm_ci.notificationBufferAddress;
+				libais_send_response (fd, &res_clm_trackcallback, sizeof (struct res_clm_trackcallback));
+				libais_send_response (fd, clusterNotification, sizeof (SaClmClusterNotificationT) * notifyEntries);
+			}
+		}
+	}
+
+	/*
+	 * Remove entries from clusterNodes array
+	 */
+	for (i = 0; i < nodes_entries; i++) {
+		for (j = 0; j < clusterNodeEntries;) {
+			if (nodes[i] == clusterNodes[j].nodeId) {
+				clusterNodeEntries -= 1;
+				memcpy (&clusterNodes[j], &clusterNodes[j + 1],
+					(clusterNodeEntries - i) * sizeof (SaClmClusterNodeT));
+			} else {
+				/*
+				 * next clusterNode entry
+				 */
+				j++;
+			}
+		}
+	}
+}
+
+static int clmNodeJoinSend (void)
+{
+	struct req_exec_clm_nodejoin req_exec_clm_nodejoin;
+	struct iovec req_exec_clm_iovec;
+	int result;
+	req_exec_clm_nodejoin.header.magic = MESSAGE_MAGIC;
+	req_exec_clm_nodejoin.header.size = sizeof (struct req_exec_clm_nodejoin);
+	req_exec_clm_nodejoin.header.id = MESSAGE_REQ_EXEC_CLM_NODEJOIN;
+// TODO dont use memcpy, use iovecs !!
+	memcpy (&req_exec_clm_nodejoin.clusterNode, &thisClusterNode,
+		sizeof (SaClmClusterNodeT));
+	
+	req_exec_clm_iovec.iov_base = &req_exec_clm_nodejoin;
+	req_exec_clm_iovec.iov_len = sizeof (req_exec_clm_nodejoin);
+
+	result = gmi_mcast (&aisexec_groupname, &req_exec_clm_iovec, 1, GMI_PRIO_HIGH);
+
+	return (result);
+}
+
+static int clmConfChg (
+    struct sockaddr_in *member_list, int member_list_entries,
+    struct sockaddr_in *left_list, int left_list_entries,
+    struct sockaddr_in *joined_list, int joined_list_entries) {
+
+	int i;
+	SaClmNodeIdT nodes[NODE_MAX];
+
+	log_printf (LOG_LEVEL_NOTICE, "CLM CONFIGURATION CHANGE\n");
+	log_printf (LOG_LEVEL_NOTICE, "New Configuration:\n");
+	for (i = 0; i < member_list_entries; i++) {
+		log_printf (LOG_LEVEL_NOTICE, "\t%s\n", inet_ntoa (member_list[i].sin_addr));
+	}
+	log_printf (LOG_LEVEL_NOTICE, "Members Left:\n");
+	for (i = 0; i < left_list_entries; i++) {
+		log_printf (LOG_LEVEL_NOTICE, "\t%s\n", inet_ntoa (left_list[i].sin_addr));
+	}
+
+	log_printf (LOG_LEVEL_NOTICE, "Members Joined:\n");
+	for (i = 0; i < joined_list_entries; i++) {
+		log_printf (LOG_LEVEL_NOTICE, "\t%s\n", inet_ntoa (joined_list[i].sin_addr));
+	}
+
+	/*
+	 * Send node information to other nodes
+	 */
+	if (joined_list_entries) {
+		clmNodeJoinSend ();
+	}
+	for (i = 0; i < left_list_entries; i++) {
+		nodes[i] = left_list[i].sin_addr.s_addr;
+	}
+
+	libraryNotificationLeave (nodes, i);
+
+	return (0);
+}
+
+static int message_handler_req_exec_clm_nodejoin (int fd, void *message)
+{
+	struct req_exec_clm_nodejoin *req_exec_clm_nodejoin = (struct req_exec_clm_nodejoin *)message;
+	int found;
+	int i;
+
+	log_printf (LOG_LEVEL_NOTICE, "got nodejoin message %s\n", req_exec_clm_nodejoin->clusterNode.nodeName.value);
+	
+	/*
+	 * Determine if nodejoin already received
+	 */
+	for (found = 0, i = 0; i < clusterNodeEntries; i++) {
+		if (memcmp (&clusterNodes[i], &req_exec_clm_nodejoin->clusterNode, 
+			sizeof (SaClmClusterNodeT)) == 0) {
+
+			found = 1;
+		}
+	}
+
+	/*
+	 * If not received, add to internal list
+	 */
+	if (found == 0) {
+		memcpy (&clusterNodes[clusterNodeEntries],
+			&req_exec_clm_nodejoin->clusterNode,
+			sizeof (SaClmClusterNodeT));
+
+		clusterNodeEntries += 1;
+		libraryNotificationJoin (req_exec_clm_nodejoin->clusterNode.nodeId);
+	}
+
+	return (0);
+}
+
+static int message_handler_req_clm_init (int fd, void *message)
+{
+	log_printf (LOG_LEVEL_DEBUG, "Got request to initalize cluster membership service.\n");
+	connections[fd].service = SOCKET_SERVICE_CLM;
+
+	return (0);
+}
+
+int message_handler_req_clm_trackstart (int fd, void *message)
+{
+	struct req_clm_trackstart *req_clm_trackstart = (struct req_clm_trackstart *)message;
+
+
+	connections[fd].ais_ci.u.libclm_ci.trackFlags = req_clm_trackstart->trackFlags;
+	connections[fd].ais_ci.u.libclm_ci.notificationBufferAddress = req_clm_trackstart->notificationBufferAddress;
+
+	libraryNotificationCurrentState (fd);
+
+	return (0);
+}
+
+static int message_handler_req_clm_trackstop (int fd, void *message)
+{
+	connections[fd].ais_ci.u.libclm_ci.trackFlags = 0;
+	connections[fd].ais_ci.u.libclm_ci.notificationBufferAddress = 0;
+
+	return (0);
+}
+
+static int message_handler_req_clm_nodeget (int fd, void *message)
+{
+	struct req_clm_nodeget *req_clm_nodeget = (struct req_clm_nodeget *)message;
+	struct res_clm_nodeget res_clm_nodeget;
+	SaClmClusterNodeT *clusterNode = 0;
+	int valid = 0;
+	int i;
+
+	log_printf (LOG_LEVEL_DEBUG, "nodeget: trying to find node %x\n", (int)req_clm_nodeget->nodeId);
+
+	if (req_clm_nodeget->nodeId == SA_CLM_LOCAL_NODE_ID) {
+		clusterNode = &clusterNodes[0];
+		valid = 1;
+	} else 
+	for (i = 0; i < clusterNodeEntries; i++) {
+		if (clusterNodes[i].nodeId == req_clm_nodeget->nodeId) {
+			log_printf (LOG_LEVEL_DEBUG, "found host that matches one desired in nodeget.\n");
+			clusterNode = &clusterNodes[i];
+			valid = 1;
+			break;
+		}
+	}
+
+	res_clm_nodeget.header.magic = MESSAGE_MAGIC;
+	res_clm_nodeget.header.size = sizeof (struct res_clm_nodeget);
+	res_clm_nodeget.header.id = MESSAGE_RES_CLM_NODEGET;
+	res_clm_nodeget.invocation = req_clm_nodeget->invocation;
+	res_clm_nodeget.clusterNodeAddress = req_clm_nodeget->clusterNodeAddress;
+	res_clm_nodeget.valid = valid;
+	if (valid) {
+		memcpy (&res_clm_nodeget.clusterNode, clusterNode, sizeof (SaClmClusterNodeT));
+	}
+	libais_send_response (fd, &res_clm_nodeget, sizeof (struct res_clm_nodeget));
+
+	return (0);
+}

+ 51 - 0
exec/clm.h

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "../include/ais_types.h"
+
+#ifndef CLM_H_DEFINED
+#define CLM_H_DEFINED
+
+#include <netinet/in.h>
+
+struct libclm_ci {
+	SaUint8T trackFlags;
+	SaClmClusterNotificationT *notificationBufferAddress;
+};
+
+extern SaClmClusterNodeT thisClusterNode;
+
+extern struct service_handler clm_service_handler;
+
+#endif /* CLM_H_DEFINED */

+ 2861 - 0
exec/gmi.c

@@ -0,0 +1,2861 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code implements the ring protocol specified in Yair Amir's PhD thesis:
+ *	http://www.cs.jhu.edu/~yairamir/phd.ps) (ch4,5). 
+ *
+ * Some changes have been made to the design to support things like fragmentation,
+ * multiple I/O queues, and other things.
+ */
+
+#include <assert.h>
+#include <sys/poll.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <sys/un.h>
+#include <sys/sysinfo.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <sched.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "poll.h"
+#include "gmi.h"
+#include "../include/queue.h"
+#include "../include/sq.h"
+#include "print.h"
+
+extern struct sockaddr_in this_ip;
+
+#define LOCALHOST_IP				inet_addr("127.0.0.1")
+#define QUEUE_PEND_DELV_SIZE_MAX	((MESSAGE_SIZE_MAX / 1472) + 1) * 2
+#define QUEUE_RTR_ITEMS_SIZE_MAX	512
+#define QUEUE_PEND_TRANS_SIZE_MAX	((MESSAGE_SIZE_MAX / 1472) + 1) * 500
+#define MAXIOVS						8
+#define RTR_TOKEN_SIZE_MAX			32
+#define MISSING_MCAST_WINDOW		64
+#define TIMEOUT_STATE_GATHER		300
+#define TIMEOUT_TOKEN				300
+#define TIMEOUT_STATE_COMMIT		300
+#define MAX_MEMBERS					16
+#define HOLE_LIST_MAX				MISSING_MCAST_WINDOW
+#define PRIORITY_MAX				3
+
+int stats_sent = 0;
+int stats_recv = 0;
+int stats_delv = 0;
+int stats_remcasts = 0;
+int stats_orf_token = 0;
+int stats_form_token = 0;
+struct timeval stats_tv_start = { 0, 0 };
+
+/*
+ * Flow control mcasts and remcasts on last and current orf_token
+ */
+int fcc_remcast_last = 0;
+int fcc_mcast_last = 0;
+int fcc_mcast_current = 0;
+int fcc_remcast_current = 0;
+
+enum message_type {
+	MESSAGE_TYPE_ORF_TOKEN = 0,			/* Ordering, Reliability, Flow (ORF) control Token */
+	MESSAGE_TYPE_MCAST = 1,				/* ring ordered multicast message */
+	MESSAGE_TYPE_MEMB_ATTEMPT_JOIN = 2, /* membership join attempt message */
+	MESSAGE_TYPE_MEMB_JOIN = 3, 		/* membership join message */
+	MESSAGE_TYPE_MEMB_FORM_TOKEN = 4	/* membership FORM token */
+};
+
+/*
+ * In-order pending transmit queue
+ */
+struct queue queues_pend_trans[PRIORITY_MAX];
+
+/*
+ * In-order pending delivery queue
+ */
+struct pend_delv {
+	struct in_addr ip;
+	int seqid;
+	int first_delivery;
+	struct queue queue;
+};
+
+struct pend_delv queues_pend_delv[MAX_MEMBERS];
+
+/*
+ * Sorted delivery/retransmit queue
+ */
+struct sq queue_rtr_items;
+
+/*
+ * Multicast address
+ */
+struct sockaddr_in sockaddr_in_mcast;
+
+/*
+ * Multicast file descriptor
+ */
+int gmi_fd;
+
+/*
+ * Received up to and including
+ */
+int gmi_arut = 0;
+
+/*
+ * Delivered up to and including
+ */
+int gmi_adut = 0;
+
+int gmi_adut_old = 0;
+
+int gmi_original_arut = 0;
+
+int gmi_highest_seq = 0;
+
+int gmi_highest_seq_old = 0;
+
+int gmi_barrier_seq = 0;
+
+int gmi_last_seqid = 0;
+
+int gmi_fragment = 0;
+
+int gmi_pend_queue_priority = 0;
+
+/*
+ * Timers
+ */
+poll_timer_handle timer_orf_token_timeout = 0;
+
+poll_timer_handle timer_form_token_timeout = 0;
+
+poll_timer_handle timer_memb_state_gather_timeout = 0;
+
+poll_timer_handle timer_memb_state_commit_timeout = 0;
+
+poll_timer_handle timer_single_member = 0;
+
+/*
+ * Function called when new message received
+ */
+int (*gmi_recv) (char *group, struct iovec *iovec, int iov_len);
+
+struct message_header {
+	int type;
+	int seqid;
+};
+
+struct memb_conf_id {
+	struct in_addr rep;	
+	struct timeval tv;
+};
+
+struct mcast {
+	struct message_header header;
+	char priority;
+	struct memb_conf_id memb_conf_id;
+	short packet_number;
+	short packet_count;
+	int packet_seq;
+	struct in_addr source;
+	struct gmi_groupname groupname;
+};
+
+struct rtr_item  {
+	struct memb_conf_id conf_id;
+	int seqid;
+};
+
+struct orf_token {
+	struct message_header header;
+	int group_arut;
+	struct in_addr addr_arut;
+	short int fcc;
+	short int brake;
+	struct in_addr brake_addr;
+	struct rtr_item rtr_list[RTR_TOKEN_SIZE_MAX];
+	int rtr_list_entries;
+};
+
+struct conf_desc {
+	struct memb_conf_id conf_id;
+	int highest_seq;
+	int arut;
+#ifdef COMPLIE_OUT
+	int hole_list[HOLE_LIST_MAX];
+	int hole_list_entries;
+#endif
+};
+
+struct memb_form_token {
+	struct message_header header;
+	struct memb_conf_id conf_id;
+	struct conf_desc conf_desc_list[MAX_MEMBERS]; /* SHOULD BE MAX_MEMBERS */
+	int conf_desc_list_entries;
+	struct in_addr member_list[MAX_MEMBERS];
+	int member_list_entries;
+	struct in_addr rep_list[MAX_MEMBERS];
+	int rep_list_entries;
+};
+	
+
+struct memb_attempt_join {
+	struct message_header header;
+};
+
+struct memb_join {
+	struct message_header header;
+	struct in_addr active_rep_list[MAX_MEMBERS];
+	int active_rep_list_entries;
+	struct in_addr failed_rep_list[MAX_MEMBERS];
+	int failed_rep_list_entries;
+};
+
+struct gmi_pend_trans_item {
+	struct mcast *mcast;
+
+	struct iovec iovec[MAXIOVS];
+	int iov_len;
+};
+
+struct gmi_pend_delv_item {
+	struct iovec iovec[MAXIOVS];
+	int iov_len;
+};
+
+struct gmi_rtr_item {
+	struct iovec iovec[MAXIOVS+2]; /* +2 is for mcast msg + group name  TODO is this right */
+	int iov_len;
+};
+
+enum memb_state {
+	MEMB_STATE_OPERATIONAL,
+	MEMB_STATE_GATHER,
+	MEMB_STATE_COMMIT,
+	MEMB_STATE_FORM,
+	MEMB_STATE_EVS
+};
+
+static enum memb_state memb_state = MEMB_STATE_GATHER;
+
+static struct sockaddr_in memb_list[MAX_MEMBERS];
+static int memb_list_entries = 1;
+static int memb_list_entries_confchg = 1;
+
+struct sockaddr_in memb_next;
+
+struct in_addr memb_gather_set[MAX_MEMBERS];
+int memb_gather_set_entries = 0;
+
+struct memb_commit_set {
+	struct sockaddr_in rep;
+	struct in_addr join_rep_list[MAX_MEMBERS];
+	int join_rep_list_entries;
+	struct in_addr member_list[MAX_MEMBERS];
+	int member_list_entries;
+};
+
+static struct memb_commit_set memb_commit_set[MAX_MEMBERS];
+
+static int memb_commit_set_entries = 0;
+
+static struct in_addr memb_failed_list[MAX_MEMBERS];
+
+static int memb_failed_list_entries = 0;
+
+static struct sockaddr_in memb_local_sockaddr_in;
+
+static struct memb_conf_id memb_conf_id;
+
+static struct memb_conf_id memb_form_token_conf_id;
+
+static struct memb_join memb_join;
+
+static struct memb_form_token memb_form_token;
+
+char iov_buffer[MESSAGE_SIZE_MAX];
+
+static struct iovec gmi_iov_recv = {
+	iov_base:	iov_buffer,
+	iov_len:	sizeof (iov_buffer)
+};
+
+struct message_handlers {
+	int count;
+	int (*handler_functions[5]) (struct sockaddr_in *, struct iovec *, int, int);
+};
+
+poll_handle *gmi_poll_handle;
+
+void (*gmi_deliver_fn) (
+	struct gmi_groupname *groupname,
+	struct iovec *iovec,
+	int iov_len) = 0;
+
+void (*gmi_confchg_fn) (
+	struct sockaddr_in *member_list, int member_list_entries,
+	struct sockaddr_in *left_list, int left_list_entries,
+	struct sockaddr_in *joined_list, int joined_list_entries) = 0;
+
+/*
+ * forward decls
+ */
+static int message_handler_orf_token (struct sockaddr_in *, struct iovec *, int, int);
+static int message_handler_mcast (struct sockaddr_in *, struct iovec *, int, int);
+static int message_handler_memb_attempt_join (struct sockaddr_in *, struct iovec *, int, int);
+static int message_handler_memb_join (struct sockaddr_in *, struct iovec *, int, int);
+static int message_handler_memb_form_token (struct sockaddr_in *, struct iovec *, int, int);
+static void memb_conf_id_build (struct memb_conf_id *, struct in_addr);
+static int recv_handler (poll_handle handle, int fd, int revents, void *data);
+static int local_netif_determine (struct sockaddr_in *bindnet, struct sockaddr_in *bound_to);
+static int memb_state_gather_enter (void);
+static void pending_queues_deliver (void);
+static int orf_token_mcast (struct orf_token *orf_token,
+	int fcc_mcasts_allowed, struct sockaddr_in *system_from);
+static void queues_pend_delv_memb_new (void);
+static void calculate_group_arut (struct orf_token *orf_token);
+static int messages_free (int group_arut);
+
+struct message_handlers gmi_message_handlers = {
+	5,
+	{
+		message_handler_orf_token,
+		message_handler_mcast,
+		message_handler_memb_attempt_join,
+		message_handler_memb_join,
+		message_handler_memb_form_token
+	}
+};
+
+/*
+ * Exported interfaces
+ */
+int gmi_init (
+	struct sockaddr_in *sockaddr_mcast,
+	struct sockaddr_in *sockaddr_bindnet,
+	poll_handle *poll_handle,
+	struct sockaddr_in *bound_to)
+{
+	int res;
+	struct ip_mreqn mreqn;
+	struct sockaddr_in sockaddr_in;
+	char flag;
+	int i;
+	int index;
+
+	memcpy (&sockaddr_in_mcast, sockaddr_mcast, sizeof (struct sockaddr_in));
+
+	for (i = 0; i < PRIORITY_MAX; i++) {
+		queue_init (&queues_pend_trans[i], QUEUE_PEND_TRANS_SIZE_MAX,
+			sizeof (struct gmi_pend_trans_item));
+	}
+	sq_init (&queue_rtr_items, QUEUE_RTR_ITEMS_SIZE_MAX, sizeof (struct gmi_rtr_item), 0);
+	index = local_netif_determine (sockaddr_bindnet, bound_to);
+	if (index == -1) {
+		return (-1);
+	}
+	memcpy (&memb_list[0], &memb_local_sockaddr_in, sizeof (struct sockaddr_in));
+	memb_conf_id_build (&memb_conf_id, memb_local_sockaddr_in.sin_addr);
+	memcpy (&memb_form_token_conf_id, &memb_conf_id, sizeof (struct memb_conf_id));
+
+	/*
+	 * Set local sock addr for new socket
+	 */
+	sockaddr_in.sin_family = AF_INET;
+	sockaddr_in.sin_addr.s_addr = htonl (INADDR_ANY);
+	sockaddr_in.sin_port = sockaddr_in_mcast.sin_port;
+
+	/*
+	 * Join group membership on socket
+	 */
+	mreqn.imr_multiaddr.s_addr = sockaddr_mcast->sin_addr.s_addr;
+	mreqn.imr_ifindex = index + 1;
+
+	gmi_fd = socket (AF_INET, SOCK_DGRAM, 0);
+	if (gmi_fd == -1) {
+		perror ("socket");
+		return (-1);
+	}
+
+	res = bind (gmi_fd, (struct sockaddr *)&sockaddr_in,
+		sizeof (struct sockaddr_in));
+	if (res == -1) {
+		perror ("bind failed");
+		return (-1);
+	}
+#ifdef BROADCAST_CODE_TAKEN_OUT
+this code is the broadcast socket option vs multicast socket option
+	setsockopt (gmi_fd, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof (on));
+#endif
+	res = setsockopt (gmi_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+		&mreqn, sizeof (mreqn));
+	if (res == -1) {
+		perror ("join multicast group failed");
+		return (-1);
+	}
+
+	flag = 0;
+	res = setsockopt (gmi_fd, IPPROTO_IP, IP_MULTICAST_LOOP,
+		&flag, sizeof (flag));
+	if (res == -1) {
+		perror ("turn off loopback");
+		return (-1);
+	}
+
+	gmi_poll_handle = poll_handle;
+
+	poll_dispatch_add (*gmi_poll_handle, gmi_fd, POLLIN, 0, recv_handler);
+
+	memb_state_gather_enter ();
+
+	memset (&memb_next, 0, sizeof (struct sockaddr_in));
+
+	queues_pend_delv_memb_new ();
+
+	return (0);
+}
+
+int gmi_join (
+	struct gmi_groupname *groupname,
+	void (*deliver_fn) (
+		struct gmi_groupname *groupname,
+		struct iovec *iovec,
+		int iov_len),
+	void (*confchg_fn) (
+		struct sockaddr_in *member_list, int member_list_entries,
+		struct sockaddr_in *left_list, int left_list_entries,
+		struct sockaddr_in *joined_list, int joined_list_entries),
+	gmi_join_handle *handle_out) {
+
+	gmi_deliver_fn = deliver_fn;
+	gmi_confchg_fn = confchg_fn;
+	*handle_out = 0;
+
+	return (0);
+}
+
+int local_host_seq_count = 0;
+
+int gmi_leave (
+	gmi_join_handle handle_join);
+
+static int gmi_pend_trans_item_store (
+    struct gmi_groupname *groupname,
+	struct iovec *iovec,
+	int iov_len,
+	int priority,
+	 short packet_number, short packet_count)
+{
+	int i, j;
+	struct gmi_pend_trans_item gmi_pend_trans_item;
+	/*
+	 * Store pending item
+	 */
+	gmi_pend_trans_item.mcast = malloc (sizeof (struct mcast));
+	if (gmi_pend_trans_item.mcast == 0) {
+		goto error_mcast;
+	}
+
+	/*
+	 * Set mcast header
+	 */
+	gmi_pend_trans_item.mcast->header.type = MESSAGE_TYPE_MCAST;
+	gmi_pend_trans_item.mcast->priority = priority;
+	gmi_pend_trans_item.mcast->packet_number = packet_number;
+	gmi_pend_trans_item.mcast->packet_count = packet_count;
+	gmi_pend_trans_item.mcast->packet_seq = local_host_seq_count++;
+	gmi_pend_trans_item.mcast->source.s_addr = this_ip.sin_addr.s_addr;
+
+	memcpy (&gmi_pend_trans_item.mcast->groupname, groupname,
+		sizeof (struct gmi_groupname));
+
+	for (i = 0; i < iov_len; i++) {
+		gmi_pend_trans_item.iovec[i].iov_base = malloc (iovec[i].iov_len);
+		if (gmi_pend_trans_item.iovec[i].iov_base == 0) {
+			goto error_iovec;
+		}
+		memcpy (gmi_pend_trans_item.iovec[i].iov_base, iovec[i].iov_base,
+			iovec[i].iov_len);
+		gmi_pend_trans_item.iovec[i].iov_len = iovec[i].iov_len;
+	}
+	gmi_pend_trans_item.iov_len = iov_len;
+
+	log_printf (LOG_LEVEL_DEBUG, "mcasted message added to pending queue\n");
+	queue_item_add (&queues_pend_trans[priority], &gmi_pend_trans_item);
+
+	return (0);
+error_iovec:
+	for (j = 0; j < i; j++) {
+		free (gmi_pend_trans_item.iovec[j].iov_base);
+	}
+	return (-1);
+error_mcast:
+	return (0);
+}
+
+/*
+ * MTU - multicast message header - IP header - UDP header
+ *
+ * On lossy switches, making use of the DF UDP flag can lead to loss of
+ * forward progress.  So the packets must be fragmented by the algorithm
+ * and reassembled at the receiver.
+ */
+#define FRAGMENT_SIZE (1500 - sizeof (struct mcast) - 20 - 8)
+
+static void timer_function_single_member (void *data);
+
+static void single_member_deliver (void)
+{
+	struct orf_token orf_token;
+
+	memset (&orf_token, 0, sizeof (struct orf_token));
+	orf_token.header.seqid = gmi_arut;
+	orf_token.header.type = MESSAGE_TYPE_ORF_TOKEN;
+	orf_token.group_arut = gmi_arut;
+	orf_token.rtr_list_entries = 0;
+	orf_token_mcast (&orf_token, 99, &memb_local_sockaddr_in);
+	calculate_group_arut (&orf_token);
+	messages_free (gmi_arut);
+	poll_timer_delete (*gmi_poll_handle, timer_single_member);
+	timer_form_token_timeout = 0;
+	poll_timer_add (*gmi_poll_handle, 1, 0,
+		timer_function_single_member, &timer_single_member);
+}
+
+static void timer_function_single_member (void *data)
+{
+	single_member_deliver ();
+}
+
+int gmi_mcast (
+    struct gmi_groupname *groupname,
+    struct iovec *iovec,
+    int iov_len,
+	int priority)
+{
+	int res;
+	struct iovec copied_iovec;
+	struct iovec pending_iovecs[MAXIOVS];
+	int pending_iovec_entries = 0;
+	int iovec_entry = 0;
+	int total_size;
+	int packet_size;
+	int i;
+	int packet_number = 0;
+	int packet_count = 0;
+
+	packet_size = FRAGMENT_SIZE;
+
+	log_printf (LOG_LEVEL_DEBUG, "MCASTING MESSAGE\n");
+
+	/*
+	 * Determine size of total message
+	 */
+	total_size = 0;
+	for (i = 0; i < iov_len; i++) {
+		total_size += iovec[i].iov_len;
+		assert (iovec[i].iov_len < MESSAGE_SIZE_MAX);
+	}
+
+	packet_count = (total_size / packet_size);
+
+	log_printf (LOG_LEVEL_DEBUG, "Message size is %d\n", total_size);
+
+	/*
+	 * Break message up into individual packets and publish them
+	 */
+	copied_iovec.iov_base = iovec[0].iov_base;
+	copied_iovec.iov_len = iovec[0].iov_len;
+	packet_size = 0;
+	pending_iovec_entries = 0;
+	iovec_entry = 0;
+	do {
+		if (copied_iovec.iov_len + packet_size > FRAGMENT_SIZE) {
+			pending_iovecs[pending_iovec_entries].iov_base = copied_iovec.iov_base;
+			pending_iovecs[pending_iovec_entries].iov_len = FRAGMENT_SIZE - packet_size;
+			copied_iovec.iov_base += FRAGMENT_SIZE - packet_size;
+			copied_iovec.iov_len -= FRAGMENT_SIZE - packet_size;
+			packet_size += pending_iovecs[pending_iovec_entries].iov_len;
+		} else {
+			pending_iovecs[pending_iovec_entries].iov_base = copied_iovec.iov_base;
+			pending_iovecs[pending_iovec_entries].iov_len = copied_iovec.iov_len;
+			packet_size += copied_iovec.iov_len;
+			iovec_entry += 1; /* this must be before copied_iovec */
+			copied_iovec.iov_base = iovec[iovec_entry].iov_base;
+			copied_iovec.iov_len = iovec[iovec_entry].iov_len;
+		}
+		pending_iovec_entries += 1;
+		if (packet_size >= FRAGMENT_SIZE || packet_size == total_size) {
+#ifdef DEBUG
+for (i = 0; i < pending_iovec_entries; i++) {
+	assert (pending_iovecs[i].iov_len < MESSAGE_SIZE_MAX);
+	assert (pending_iovecs[i].iov_len >= 0);
+	printf ("iovecs[%d] %x %d\n", i, pending_iovecs[i].iov_base, pending_iovecs[i].iov_len);
+calced_total += pending_iovecs[i].iov_len;
+}
+printf ("CALCULATED TOTAL is %d\n", calced_total);
+#endif
+			total_size -= packet_size;
+			assert (total_size >= 0);
+			res = gmi_pend_trans_item_store (groupname, pending_iovecs,
+				pending_iovec_entries, priority, packet_number, packet_count);
+			pending_iovec_entries = 0;
+			iovec_entry = 0;
+			packet_size = 0;
+			packet_number += 1;
+		}
+	} while (total_size > 0);
+
+	/*
+	 * The queued messages are sent in orf_token_mcast, not this function
+	 * But if this processor is the only node, it must deliver the messages
+	 * for self-delivery requirements because orf_token_mcast is only called
+	 * on reception of a token
+	 */
+	if (memb_list_entries == 1) {
+		single_member_deliver ();
+	}
+
+	return (0);
+}
+
+static int local_netif_determine (struct sockaddr_in *bindnet, struct sockaddr_in *bound_to)
+{
+	struct sockaddr_in *sockaddr_in;
+	int id_fd;
+	struct ifconf ifc;
+	int numreqs = 0;
+	int res;
+	int i;
+
+	/*
+	 * Generate list of local interfaces in ifc.ifc_req structure
+	 */
+	id_fd = socket (AF_INET, SOCK_DGRAM, 0);
+	ifc.ifc_buf = 0;
+	do {
+		numreqs += 8;
+		ifc.ifc_len = sizeof (struct ifreq) * numreqs;
+		ifc.ifc_buf = (void *)realloc(ifc.ifc_buf, ifc.ifc_len);
+		res = ioctl (id_fd, SIOCGIFCONF, &ifc);
+		if (res < 0) {
+			close (id_fd);
+			return -1;
+		}
+	} while (ifc.ifc_len == sizeof (struct ifreq) * numreqs);
+
+	res = -1;
+
+	/*
+	 * Find interface to bind to
+	 */
+	for (i = 0; i < ifc.ifc_len / sizeof (struct ifreq); i++) {
+	sockaddr_in = (struct sockaddr_in *)&ifc.ifc_ifcu.ifcu_req[i].ifr_ifru.ifru_addr;
+		if ((sockaddr_in->sin_addr.s_addr & 0x00ffffff) == (bindnet->sin_addr.s_addr & 0x00ffffff)) {
+			memb_local_sockaddr_in.sin_addr.s_addr = sockaddr_in->sin_addr.s_addr;
+			memb_local_sockaddr_in.sin_family = AF_INET;
+			memb_local_sockaddr_in.sin_port = sockaddr_in_mcast.sin_port;
+			memcpy (bound_to, &memb_local_sockaddr_in, sizeof (struct sockaddr_in));
+			res = i;
+			break; /* for */
+		}
+	}
+	free (ifc.ifc_buf);
+	close (id_fd);
+	
+	return (res);
+}
+
+/*
+ * Misc Management
+ */
+int in_addr_compare (const void *a, const void *b) {
+	struct in_addr *in_addr_a = (struct in_addr *)a;
+	struct in_addr *in_addr_b = (struct in_addr *)b;
+
+	return (in_addr_a->s_addr > in_addr_b->s_addr);
+}
+
+/*
+ * ORF Token Management
+ */
+/* 
+ * Recast message to mcast group if it is available
+ */
+int orf_token_remcast (int seqid) {
+	struct msghdr msg_mcast;
+	struct gmi_rtr_item *gmi_rtr_item;
+	int res;
+	struct mcast *mcast;
+
+//printf ("remulticasting %d\n", seqid);
+	/*
+	 * Get RTR item at seqid, if not available, return
+	 */
+	res = sq_item_get (&queue_rtr_items, seqid, (void **)&gmi_rtr_item);
+	if (res != 0) {
+		return -1;
+	}
+	mcast = gmi_rtr_item->iovec[0].iov_base;
+
+	/*
+	 * Build multicast message
+	 */
+	msg_mcast.msg_name = &sockaddr_in_mcast;
+	msg_mcast.msg_namelen = sizeof (struct sockaddr_in);
+	msg_mcast.msg_iov = gmi_rtr_item->iovec;
+	msg_mcast.msg_iovlen = gmi_rtr_item->iov_len;
+	msg_mcast.msg_control = 0;
+	msg_mcast.msg_controllen = 0;
+	msg_mcast.msg_flags = 0;
+
+	/*
+	 * Multicast message
+	 */
+	res = sendmsg (gmi_fd, &msg_mcast, MSG_NOSIGNAL | MSG_DONTWAIT);
+	if (res == -1) {
+printf ("error during remulticast %d %d %d\n", seqid, errno, gmi_rtr_item->iov_len);
+		return (-1);
+	}
+	stats_sent += res;
+	return (0);
+}
+
+int last_group_arut = 0;
+int last_released = 0;
+int set_arut = -1;
+
+/*
+ * Brake output multicasts if the missing window is too large
+ */
+int gmi_brake;
+		
+static int messages_free (int group_arut)
+{
+	struct gmi_rtr_item *gmi_rtr_item_p;
+	int i, j;
+	int res;
+	int lesser;
+
+// TODO printf ("group arut %d last_group-arut  %d gmi_dut %d barrier %d\n", group_arut, last_group_arut, gmi_dut, gmi_barrier_seq);
+	/*
+	 * Determine braking value (when messages + MISSING_MCAST_WINDOW, stop sending messages)
+	 */
+	gmi_brake = group_arut;
+	if (gmi_brake > last_group_arut) {
+		gmi_brake = last_group_arut;
+	}
+	
+	/*
+	 * Determine low water mark for messages to be freed
+	 */
+	lesser = gmi_brake;
+	if (lesser > gmi_adut) {
+		lesser = gmi_adut;
+	}
+
+//printf ("Freeing lesser %d %d %d\n", lesser, group_arut, last_group_arut);
+//printf ("lesser %d gropu arut %d last group arut %d\n", lesser, group_arut, last_group_arut);
+		
+	/*
+	 * return early if no messages can be freed
+	 */
+/*
+	if (last_released + 1 == lesser) {
+		return (0);
+	}
+*/
+
+	/*
+	 * Release retransmit list items if group arut indicates they are transmitted
+	 */
+	for (i = last_released; i <= lesser; i++) {
+		res = sq_item_get (&queue_rtr_items, i, (void **)&gmi_rtr_item_p);
+		if (res == 0) {
+			for (j = 0; j < gmi_rtr_item_p->iov_len; j++) {
+				free (gmi_rtr_item_p->iovec[j].iov_base);
+				gmi_rtr_item_p->iovec[j].iov_base = (void *)0xdeadbeef;
+				gmi_rtr_item_p->iovec[j].iov_len = i;
+			}
+		}
+		last_released = i + 1;
+	}
+
+	sq_items_release (&queue_rtr_items, lesser);
+	log_printf (LOG_LEVEL_DEBUG, "releasing messages up to and including %d\n", lesser);
+	return (0);
+}
+
+/*
+ * Multicasts pending messages onto the ring (requires orf_token possession)
+ */
+static int orf_token_mcast (
+	struct orf_token *orf_token,
+	int fcc_mcasts_allowed,
+	struct sockaddr_in *system_from)
+{
+	struct msghdr msg_mcast;
+	struct gmi_rtr_item gmi_rtr_item;
+	struct gmi_pend_trans_item *gmi_pend_trans_item = 0;
+	int res = 0;
+	int orf_token_seqid;
+	struct mcast *mcast;
+	int last_packet = 1;
+	struct queue *queue_pend_trans;
+
+	/*
+	 * Disallow multicasts unless state is operational
+	 */
+	if (memb_state != MEMB_STATE_OPERATIONAL) {
+		return (0);
+	}
+
+	/*
+	 * If received a token with a higher sequence number,
+	 * set highest seq so retransmits can happen at end of 
+	 * message stream
+	 */
+	if (orf_token->header.seqid > gmi_highest_seq) {
+		gmi_highest_seq = orf_token->header.seqid;
+	}
+
+	orf_token_seqid = orf_token->header.seqid;
+
+	queue_pend_trans = &queues_pend_trans[gmi_pend_queue_priority];
+
+	for (fcc_mcast_current = 0; fcc_mcast_current < fcc_mcasts_allowed; fcc_mcast_current++) {
+		/*
+		 * determine which pending queue to take message
+		 * from if this is not a message fragment
+		 */
+		if (gmi_fragment == 0) {
+			gmi_pend_queue_priority = 0;
+			do {
+				queue_pend_trans = &queues_pend_trans[gmi_pend_queue_priority];
+
+				if (queue_is_empty (queue_pend_trans)) {
+					gmi_pend_queue_priority++;
+				} else {
+					break; /* from do - found first queue with data */
+				}
+			} while (gmi_pend_queue_priority < PRIORITY_MAX);
+		}
+
+		if (gmi_pend_queue_priority == PRIORITY_MAX) {
+			break; /* all queues are empty, break from for */
+		}
+//		printf ("selecting pending queue %d\n", gmi_pend_queue_priority);
+
+		gmi_pend_trans_item = (struct gmi_pend_trans_item *)queue_item_get (queue_pend_trans);
+		/* preincrement required by algo */
+		gmi_pend_trans_item->mcast->header.seqid = ++orf_token->header.seqid;
+// UNDO printf ("multicasting seqid %d\n", gmi_pend_trans_item->mcast->header.seqid);
+		
+		last_packet = (gmi_pend_trans_item->mcast->packet_number ==
+			gmi_pend_trans_item->mcast->packet_count);
+//printf ("last packet is %d current mcast %d\n", last_packet, fcc_mcast_current);
+
+		/*
+		 * Build IO vector
+		 */
+		gmi_rtr_item.iovec[0].iov_base = gmi_pend_trans_item->mcast;
+		gmi_rtr_item.iovec[0].iov_len = sizeof (struct mcast);
+
+		mcast = gmi_rtr_item.iovec[0].iov_base;
+
+		/*
+		 * Is this a fragment of a message
+		 */
+		if (mcast->packet_number == mcast->packet_count) {
+			gmi_fragment = 0;
+		} else {
+			gmi_fragment = 1;
+		}
+
+		memcpy (&mcast->memb_conf_id, &memb_form_token_conf_id,
+			sizeof (struct memb_conf_id));
+
+		memcpy (&gmi_rtr_item.iovec[1], gmi_pend_trans_item->iovec,
+			gmi_pend_trans_item->iov_len * sizeof (struct iovec));
+
+		gmi_rtr_item.iov_len = gmi_pend_trans_item->iov_len + 1;
+
+		assert (gmi_rtr_item.iov_len < 16);
+
+		/*
+		 * Add message to retransmit queue
+		 */
+		sq_item_add (&queue_rtr_items,
+			&gmi_rtr_item, gmi_pend_trans_item->mcast->header.seqid);
+
+		/*
+		 * Delete item from pending queue
+		 */
+		queue_item_remove (queue_pend_trans);
+
+		/*
+		 * Build multicast message
+		 */
+		msg_mcast.msg_name = &sockaddr_in_mcast;
+		msg_mcast.msg_namelen = sizeof (struct sockaddr_in);
+		msg_mcast.msg_iov = gmi_rtr_item.iovec;
+		msg_mcast.msg_iovlen = gmi_rtr_item.iov_len;
+		msg_mcast.msg_control = 0;
+		msg_mcast.msg_controllen = 0;
+		msg_mcast.msg_flags = 0;
+
+		/*
+		 * Multicast message
+		 */
+		res = sendmsg (gmi_fd, &msg_mcast, MSG_NOSIGNAL | MSG_DONTWAIT);
+		/*
+		 * An error here is recovered by the multicast algorithm
+	 	 */
+
+// TODO stats_sent isn't right below
+		stats_sent += res;
+	}
+	assert (fcc_mcast_current < 100);
+#ifdef OUTA
+	if (fcc_mcast_current > fcc_mcasts_allowed) {
+		fcc_mcast_current = fcc_mcasts_allowed;
+	}
+#endif
+	/*
+	 * If messages mcasted, deliver any new messages to pending queues
+	 */
+	if (fcc_mcast_current) {
+		if (gmi_pend_trans_item->mcast->header.seqid > gmi_highest_seq) {
+			gmi_highest_seq = gmi_pend_trans_item->mcast->header.seqid;
+		}
+		pending_queues_deliver ();
+//printf ("orf Token seqid is %d group %d\n", orf_token_seqid, orf_token->group_arut);
+#ifdef COMPILE_OUT
+		if (orf_token_seqid == orf_token->group_arut) {
+//printf ("previous group arut #1 %d\n", orf_token->group_arut);
+			orf_token->group_arut = orf_token_seqid + fcc_mcast_current;
+			orf_token->addr_arut.s_addr = 0;
+}
+//printf ("reasing group arut to %d\n", orf_token->group_arut);
+#endif
+	}
+		
+	return (res);
+}
+
+/*
+ * Remulticasts messages in orf_token's retransmit list (requires orf_token)
+ * Modify's orf_token's rtr to include retransmits required by this process
+ */
+static void orf_token_rtr (
+	struct orf_token *orf_token,
+	int *fcc_allowed)
+{
+	int res;
+	int i, j;
+	int found;
+
+#ifdef COMPLE_OUT
+printf ("Retransmit List %d\n", orf_token->rtr_list_entries);
+for (i = 0; i < orf_token->rtr_list_entries; i++) {
+	printf ("%d ", orf_token->rtr_list[i].seqid);
+}
+printf ("\n");
+#endif
+
+	/*
+	 * Retransmit messages on orf_token's RTR list from RTR queue
+	 */
+	for (fcc_remcast_current = 0, i = 0;
+		fcc_remcast_current <= *fcc_allowed && i < orf_token->rtr_list_entries;) {
+#ifdef COMPILE_OUT
+printf ("%d.%d.%d vs %d.%d.%d\n",
+	orf_token->rtr_list[i].conf_id.rep.s_addr,
+	orf_token->rtr_list[i].conf_id.tv.tv_sec,
+	orf_token->rtr_list[i].conf_id.tv.tv_usec,
+	memb_form_token_conf_id.rep.s_addr,
+	memb_form_token_conf_id.tv.tv_sec,
+	memb_form_token_conf_id.tv.tv_usec);
+#endif
+		/*
+		 * If this retransmit request isn't from this configuration,
+		 * try next rtr entry
+		 */
+ 		if (memcmp (&orf_token->rtr_list[i].conf_id, &memb_form_token_conf_id,
+			sizeof (struct memb_conf_id)) != 0) {
+
+			i++;
+			continue;
+		}
+		assert (orf_token->rtr_list[i].seqid > 0);
+		res = orf_token_remcast (orf_token->rtr_list[i].seqid);
+		if (res == 0) {
+			orf_token->rtr_list_entries -= 1;
+			assert (orf_token->rtr_list_entries >= 0);
+			memmove (&orf_token->rtr_list[i],
+				&orf_token->rtr_list[i + 1],
+				sizeof (struct rtr_item) * (orf_token->rtr_list_entries));
+			fcc_remcast_current++;
+			stats_remcasts++;
+		} else {
+			i++;
+//printf ("couldn't remcast %d\n", i);
+		}
+	}
+	*fcc_allowed = *fcc_allowed - fcc_remcast_current - 1;
+
+#ifdef COMPILE_OUT
+for (i = 0; i < orf_token->rtr_list_entries; i++) {
+	assert (orf_token->rtr_list[i].seqid != -1);
+}
+#endif
+
+	/*
+	 * Add messages to retransmit to RTR list
+	 * but only retry if there is room in the retransmit list
+	 */
+	for (i = gmi_arut + 1;
+			orf_token->rtr_list_entries < RTR_TOKEN_SIZE_MAX &&
+		//	i <= orf_token->header.seqid; /* TODO this worked previously but not correct for EVS */
+			i <= gmi_highest_seq;
+			i++) {
+
+		res = sq_item_inuse (&queue_rtr_items, i);
+		if (res == 0) {
+			found = 0;
+			for (j = 0; j < orf_token->rtr_list_entries; j++) {
+				if (i == orf_token->rtr_list[j].seqid) {
+					found = 1;
+				}
+			}
+			if (found == 0) {
+				memcpy (&orf_token->rtr_list[orf_token->rtr_list_entries].conf_id,
+					&memb_form_token_conf_id, sizeof (struct memb_conf_id));
+				orf_token->rtr_list[orf_token->rtr_list_entries].seqid = i;
+				orf_token->rtr_list_entries++;
+//printf ("adding to retransmit list %d\n", i);
+			}
+		}
+	}
+}
+
+/*
+ * Calculate flow control count
+ */
+static void orf_token_fcc (
+	struct orf_token *orf_token)
+{
+	orf_token->fcc = orf_token->fcc - fcc_mcast_last - fcc_remcast_last
+		+ fcc_mcast_current + fcc_remcast_current;
+
+	fcc_mcast_last = fcc_mcast_current;
+	fcc_remcast_last = fcc_remcast_current;
+}
+
+static void queues_pend_delv_memb_new (void)
+{
+	struct pend_delv pend_delv_new[MAX_MEMBERS];
+	int item_index = 0;
+	int i, j;
+	int found;
+
+	memset (pend_delv_new, 0, sizeof (struct pend_delv) * MAX_MEMBERS);
+
+	/*
+	 * Build new pending list
+	 */
+	for (i = 0; i < memb_list_entries_confchg; i++) {
+		found = 0;
+		for (j = 0; j < MAX_MEMBERS; j++) {
+			/*
+			 * If membership item in queues pending delivery list, copy it
+			 */
+			if (memb_list[i].sin_addr.s_addr == queues_pend_delv[j].ip.s_addr) {
+				memcpy (&pend_delv_new[item_index], &queues_pend_delv[j],
+					sizeof (struct pend_delv));
+				item_index += 1;
+				found = 1;
+				break; /* for j = */
+			}
+		}
+		/*
+		 * If membership item not found in pending delivery list, make new entry
+		 */
+		if (found == 0) {
+			queue_init (&pend_delv_new[item_index].queue, QUEUE_PEND_DELV_SIZE_MAX,
+				sizeof (struct gmi_pend_delv_item));
+			pend_delv_new[item_index].seqid = 0;
+			pend_delv_new[item_index].ip.s_addr = memb_list[i].sin_addr.s_addr;
+			item_index += 1;
+		}
+	}
+
+	/*
+	 * Copy new list into system list
+	 */
+	memcpy (queues_pend_delv, pend_delv_new,
+		sizeof (struct pend_delv) * MAX_MEMBERS);
+
+	for (i = 0; i < memb_list_entries_confchg; i++) {
+		/*
+		 * If queue not empty, mark it for first delivery
+		 * otherwise reset seqno
+		 */
+		if (queue_is_empty (&queues_pend_delv[i].queue) == 0) {
+			queues_pend_delv[i].first_delivery = 1;
+		} else {
+			queues_pend_delv[i].seqid = 0;
+		}
+	}
+}
+
+static int orf_token_evs (
+	struct orf_token *orf_token,
+	int starting_group_arut)
+{
+	int i, j;
+	struct sockaddr_in trans_memb_list[MAX_MEMBERS];
+	struct sockaddr_in left_list[MAX_MEMBERS];
+	struct sockaddr_in joined_list[MAX_MEMBERS];
+	int trans_memb_list_entries = 0;
+	int left_list_entries = 0;
+	int joined_list_entries = 0;
+	int found;
+
+//printf ("group arut is %d %d %d %d\n", orf_token->header.seqid, orf_token->group_arut, gmi_arut, gmi_highest_seq);
+	/*
+	 * We should only execute this function if we are in EVS membership state
+	 */
+	if (memb_state != MEMB_STATE_EVS) {
+		return (0);
+	}
+
+	/*
+	 * Delete form token timer since the token has been swallowed
+	 */
+	poll_timer_delete (*gmi_poll_handle, timer_form_token_timeout);
+	timer_form_token_timeout = 0;
+
+printf ("EVS STATE group arut %d gmi arut %d highest %d barrier %d starting group arut %d\n", orf_token->group_arut, gmi_arut, gmi_highest_seq, gmi_barrier_seq, starting_group_arut);
+
+	/*
+	 * This node has reached highest seq, set local arut to barrier
+	 */
+	if (gmi_arut == gmi_highest_seq) {
+//printf ("setting arut to barrier %d\n", gmi_barrier_seq);
+		gmi_arut = gmi_barrier_seq;
+	}
+
+	/*
+	 * Determine when EVS recovery has completed
+	 */
+//printf ("group arut is %d %d %d\n", orf_token->group_arut, gmi_arut, gmi_highest_seq);
+// TODO
+	if (memb_state == MEMB_STATE_EVS && gmi_arut == gmi_barrier_seq && orf_token->group_arut == gmi_barrier_seq) {
+		log_printf (LOG_LEVEL_NOTICE, "EVS recovery of messages complete, transitioning to operational.\n");
+		/*
+		 * EVS recovery complete, reset local variables
+		 */
+		gmi_arut = 0;
+
+		gmi_adut_old = gmi_adut;
+		gmi_adut = 0;
+
+		gmi_highest_seq_old = gmi_highest_seq;
+		gmi_highest_seq = 0;
+		last_group_arut = 0;
+		sq_reinit (&queue_rtr_items, 0);
+
+		memb_failed_list_entries = 0;
+
+		memb_state = MEMB_STATE_OPERATIONAL;
+		qsort (memb_form_token.member_list, memb_form_token.member_list_entries,
+			sizeof (struct in_addr), in_addr_compare);
+
+
+		/*
+		 * Determine transitional configuration
+		 */
+		for (i = 0; i < memb_list_entries_confchg; i++) {
+			for (found = 0, j = 0; j < memb_form_token.member_list_entries; j++) {
+				if (memb_list[i].sin_addr.s_addr == memb_form_token.member_list[j].s_addr) {
+					found = 1;
+					break;
+				}
+			}
+			if (found == 1) {
+				trans_memb_list[trans_memb_list_entries].sin_addr.s_addr = memb_list[i].sin_addr.s_addr;
+				trans_memb_list[trans_memb_list_entries].sin_family = AF_INET;
+				trans_memb_list[trans_memb_list_entries].sin_port = sockaddr_in_mcast.sin_port;
+				trans_memb_list_entries += 1;
+			}
+		}
+
+		/*
+		 * Determine nodes that left the configuration
+		 */
+		for (i = 0; i < memb_list_entries_confchg; i++) {
+			for (found = 0, j = 0; j < memb_form_token.member_list_entries; j++) {
+				if (memb_list[i].sin_addr.s_addr == memb_form_token.member_list[j].s_addr) {
+					found = 1;
+					break; /* for j = 0 */
+				}
+			}
+			/*
+			 * Node left membership, add it to list
+			 */
+			if (found == 0) {
+				left_list[left_list_entries].sin_addr.s_addr = memb_list[i].sin_addr.s_addr;
+				left_list[left_list_entries].sin_family = AF_INET;
+				left_list[left_list_entries].sin_port = sockaddr_in_mcast.sin_port;
+				left_list_entries += 1;
+			}
+		}
+
+		/*
+		 * MAIN STEP:
+		 * Deliver transitional configuration
+		 */
+		if (gmi_confchg_fn &&
+			(trans_memb_list_entries != memb_list_entries ||
+			(memcmp (trans_memb_list, memb_list, sizeof (struct sockaddr_in) * memb_list_entries) != 0))) {
+			gmi_confchg_fn (trans_memb_list, trans_memb_list_entries,
+				left_list, left_list_entries,
+				0, 0);
+		}
+
+		
+		/*
+		 * Determine nodes that joined the configuration
+		 */
+		for (i = 0; i < memb_form_token.member_list_entries; i++) {
+			for (found = 0, j = 0; j < memb_list_entries_confchg; j++) {
+				if (memb_form_token.member_list[i].s_addr == memb_list[j].sin_addr.s_addr) {
+					found = 1;
+					break; /* for j = 0 */
+				}
+			}
+
+			/*
+			 * Node joined membership, add it to list
+			 */
+			if (found == 0) {
+				joined_list[joined_list_entries].sin_addr.s_addr = memb_form_token.member_list[i].s_addr;
+				joined_list[joined_list_entries].sin_family = AF_INET;
+				joined_list[joined_list_entries].sin_port = sockaddr_in_mcast.sin_port;
+				joined_list_entries += 1;
+			}
+		}
+
+		/*
+		 * Install the form token's configuration into the local membership
+		 */
+		for (i = 0; i < memb_form_token.member_list_entries; i++) {
+			memb_list[i].sin_addr.s_addr = memb_form_token.member_list[i].s_addr;
+			memb_list[i].sin_family = AF_INET;
+			memb_list[i].sin_port = sockaddr_in_mcast.sin_port;
+		}
+
+		/*
+		 * Install pending delivery queues
+		 */
+		memb_list_entries = memb_form_token.member_list_entries;
+		memb_list_entries_confchg = memb_list_entries;
+		queues_pend_delv_memb_new ();
+
+		/*
+		 * Install new conf id
+		 */
+		memcpy (&memb_conf_id, &memb_form_token.conf_id,
+			sizeof (struct memb_conf_id));
+		memcpy (&memb_form_token_conf_id, &memb_form_token.conf_id,
+			sizeof (struct memb_conf_id));
+
+		/*
+		 * Deliver regular configuration
+		 */
+		if (gmi_confchg_fn) {
+			gmi_confchg_fn (memb_list, memb_list_entries,
+				left_list, 0,
+				joined_list, joined_list_entries);
+		}
+	}
+
+	return (0);
+}
+
+int gwin = 90;
+int pwin = 40;
+
+
+static int orf_fcc_allowed (struct orf_token *token)
+{
+	int allowed;
+
+	if (memb_state != MEMB_STATE_OPERATIONAL) {
+		return (0);
+	}
+	allowed = gwin + pwin - token->fcc;
+	if (allowed < 0)  {
+		allowed = 0;
+	}
+	if (allowed > gwin) {
+		allowed = gwin;
+	}
+	if (allowed > pwin) {
+		allowed = pwin;
+	}
+	return (allowed);
+}
+
+void timer_function_form_token_timeout (void *data)
+{
+	log_printf (LOG_LEVEL_WARNING, "Token loss in FORM state\n");
+	memb_list_entries = 1;
+
+	/*
+	 * Add highest rep to failed list to ensure termination
+	 */
+	memb_failed_list[memb_failed_list_entries++].s_addr =
+		memb_form_token.rep_list[memb_form_token.rep_list_entries].s_addr;
+
+	memb_state_gather_enter ();
+}
+
+void orf_timer_function_token_timeout (void *data)
+{
+	switch (memb_state) {
+	case MEMB_STATE_OPERATIONAL:
+		log_printf (LOG_LEVEL_WARNING, "Token loss in OPERATIONAL.\n");
+		memb_conf_id.rep.s_addr = memb_local_sockaddr_in.sin_addr.s_addr;
+		memb_list_entries = 1;
+
+		memb_state_gather_enter ();
+		break;
+
+	case MEMB_STATE_GATHER:
+	case MEMB_STATE_COMMIT:
+		log_printf (LOG_LEVEL_WARNING, "Token loss in GATHER or COMMIT.\n");
+		memb_list_entries = 1;
+		break;
+
+	case MEMB_STATE_EVS:
+		log_printf (LOG_LEVEL_WARNING, "Token loss in EVS state\n");
+		memb_list_entries = 1;
+		memb_state_gather_enter ();
+		break;
+
+	default:
+		printf ("token loss in form state doesn't make sense here\n");
+		break;
+	}
+}
+
+/*
+ * Send orf_token to next member (requires orf_token)
+ */
+static int orf_token_send (
+	struct orf_token *orf_token)
+{
+	struct msghdr msg_orf_token;
+	struct iovec iovec_orf_token;
+	int res;
+
+	poll_timer_delete (*gmi_poll_handle, timer_orf_token_timeout);
+
+	poll_timer_add (*gmi_poll_handle, TIMEOUT_TOKEN, 0,
+		orf_timer_function_token_timeout, &timer_orf_token_timeout);
+
+	iovec_orf_token.iov_base = orf_token;
+	iovec_orf_token.iov_len = sizeof (struct orf_token);
+
+	msg_orf_token.msg_name = &memb_next;
+	msg_orf_token.msg_namelen = sizeof (struct sockaddr_in);
+	msg_orf_token.msg_iov = &iovec_orf_token;
+	msg_orf_token.msg_iovlen = 1;
+	msg_orf_token.msg_control = 0;
+	msg_orf_token.msg_controllen = 0;
+	msg_orf_token.msg_flags = 0;
+	
+// THIS IS FOR TESTING ERRORS IN THE EVS STATE
+//if ((memb_state == MEMB_STATE_EVS) && ((random () % 3) == 0)) {
+//log_printf (LOG_LEVEL_DEBUG, "CAUSING TOKEN LOSS AT EVS STATE\n");
+//	return (1);
+//}
+
+	res = sendmsg (gmi_fd, &msg_orf_token, MSG_NOSIGNAL);
+	assert (res != -1);
+	
+	/*
+	 * res not used here errors are handled by algorithm
+	 */
+	gmi_last_seqid = orf_token->header.seqid;
+	stats_sent += res;
+
+	return (res);
+}
+
+int orf_token_send_initial (void)
+{
+	struct orf_token orf_token;
+	int res;
+
+	orf_token.header.seqid = 0;
+	orf_token.header.type = MESSAGE_TYPE_ORF_TOKEN;
+	orf_token.group_arut = gmi_highest_seq;
+	orf_token.addr_arut.s_addr = this_ip.sin_addr.s_addr;
+	orf_token.fcc = 0;
+
+	orf_token.rtr_list_entries = 0;
+	memset (orf_token.rtr_list, 0, sizeof (struct rtr_item) * RTR_TOKEN_SIZE_MAX);
+
+	res = orf_token_send (&orf_token);
+
+	return (res);
+}
+
+/*
+ * Membership Management
+ */
+static int memb_join_send (void)
+{
+	struct msghdr msghdr_join;
+	struct iovec iovec_join;
+	int res;
+
+	memb_join.header.seqid = 0;
+	memb_join.header.type = MESSAGE_TYPE_MEMB_JOIN;
+	/*
+	 * copy current gather list to representatives list
+	 */
+	if ((memb_gather_set_entries == memb_join.active_rep_list_entries) &&
+		(memcmp (memb_join.active_rep_list, memb_gather_set,
+			sizeof (struct in_addr) * memb_gather_set_entries) == 0) &&
+		(memb_failed_list_entries == memb_join.failed_rep_list_entries) &&
+		(memcmp (memb_join.failed_rep_list, memb_failed_list,
+			sizeof (struct in_addr) * memb_failed_list_entries) == 0)) {
+
+		return (0);
+	}
+	
+	/*
+	 * Copy active reps
+	 */
+	memcpy (memb_join.active_rep_list, memb_gather_set,
+		sizeof (struct in_addr) * memb_gather_set_entries);
+	memb_join.active_rep_list_entries = memb_gather_set_entries;
+
+	/*
+	 * Copy failed reps
+	 */
+	memcpy (memb_join.failed_rep_list, memb_failed_list,
+		sizeof (struct in_addr) * memb_failed_list_entries);
+	memb_join.failed_rep_list_entries = memb_failed_list_entries;
+
+	iovec_join.iov_base = &memb_join;
+	iovec_join.iov_len = sizeof (struct memb_join);
+
+	msghdr_join.msg_name = &sockaddr_in_mcast;
+	msghdr_join.msg_namelen = sizeof (struct sockaddr_in);
+	msghdr_join.msg_iov = &iovec_join;
+	msghdr_join.msg_iovlen = 1;
+	msghdr_join.msg_control = 0;
+	msghdr_join.msg_controllen = 0;
+	msghdr_join.msg_flags = 0;
+
+	res = sendmsg (gmi_fd, &msghdr_join, MSG_NOSIGNAL | MSG_DONTWAIT);
+
+	return (res);
+}
+
+static int memb_state_commit_enter (void);
+
+/*
+ * Update gather_set[0].join_reps with list of failed members
+ */
+void memb_gather_set_update_failed (struct in_addr *list, int list_entries)
+{
+	int i;
+	int j;
+
+	/*
+	 * Remove failed members from gather set
+	 */
+	for (i = 0; i < list_entries; i++) {
+		for (j = 0; j < memb_gather_set_entries; j++) {
+			if (list[i].s_addr == memb_gather_set[j].s_addr) {
+				memb_gather_set_entries -= 1;
+				memcpy (&memb_gather_set[j],
+					&memb_gather_set[j + 1],
+					memb_gather_set_entries * sizeof (struct in_addr));
+				break; /* for j = 0 */
+			}
+		}
+	}
+}
+
+static void memb_timer_function_state_commit_timeout (void *data)
+{
+	int i;
+	int j;
+	int k;
+	int found;
+	int add_to_failed = 1;
+	struct sockaddr_in left_list[MAX_MEMBERS];
+	int left_list_entries = 0;
+
+	memb_failed_list_entries = 0;
+
+	/*
+	 * No entries responded in commit timeout period
+	 */
+	if (memb_commit_set_entries == 0) {
+		/*
+		 * memb_list_entries only set to 0 when token times out, in which case
+		 * send a configuration change because no messages can be recovered in EVS
+		 */
+		if (memb_list_entries == 0) {
+			log_printf (LOG_LEVEL_NOTICE, "I am the only member.\n");
+			if (gmi_confchg_fn) {
+				/*
+				 * Determine nodes that left the configuration
+				 */
+				for (i = 0; i < memb_list_entries_confchg; i++) {
+					if (memb_local_sockaddr_in.sin_addr.s_addr != memb_list[i].sin_addr.s_addr) {
+						left_list[left_list_entries].sin_addr.s_addr = memb_list[i].sin_addr.s_addr;
+						left_list[left_list_entries].sin_family = AF_INET;
+						left_list[left_list_entries].sin_port = sockaddr_in_mcast.sin_port;
+						left_list_entries += 1;
+						
+					}
+				}
+
+				gmi_confchg_fn (&memb_local_sockaddr_in, 1,
+					left_list, left_list_entries,
+					0, 0);
+			}
+		} else {
+			log_printf (LOG_LEVEL_NOTICE, "No members sent join, keeping old ring and transitioning to operational.\n");
+		}
+		memb_state = MEMB_STATE_OPERATIONAL;
+		return;
+	}
+	/*
+	 * Find all failed members
+	 */
+	for (i = 0; i < memb_gather_set_entries; i++) {
+		add_to_failed = 1;
+		for (j = 0; j < memb_commit_set_entries; j++) {
+			/*
+			 * If gather entry not in commit rep list, add to failed
+			 */
+			if (memb_gather_set[i].s_addr == memb_commit_set[j].rep.sin_addr.s_addr) {
+				add_to_failed = 0;
+				break; /* for found = 0 */
+			}
+		}
+		/*
+		 * If gather entry not in commit set, add to failed set
+		 */
+		for (found = 0, j = 0; j < memb_commit_set_entries; j++) {
+			for (k = 0; k < memb_commit_set[j].join_rep_list_entries; k++) {
+				if (memb_gather_set[i].s_addr == memb_commit_set[j].join_rep_list[k].s_addr) {
+					found = 1;
+					break;
+				}
+			}
+			if (found == 0) {
+				add_to_failed = 1;
+				break;
+			}
+		}
+
+		/*
+		 * If local address, item found
+		 */
+		if (memb_gather_set[i].s_addr == memb_local_sockaddr_in.sin_addr.s_addr) {
+			add_to_failed = 0;
+		}
+
+		if (add_to_failed == 1) {
+			memb_failed_list[memb_failed_list_entries++].s_addr =
+				memb_gather_set[i].s_addr;
+		}
+	}
+
+	memb_gather_set_update_failed (memb_failed_list, memb_failed_list_entries);
+
+	memb_state_commit_enter ();
+}
+
+static int memb_state_commit_enter (void)
+{
+	int res;
+
+	memb_state = MEMB_STATE_COMMIT;
+	memb_commit_set_entries = 0;
+	res = memb_join_send();
+
+    poll_timer_delete (*gmi_poll_handle, timer_memb_state_gather_timeout);
+
+	timer_memb_state_gather_timeout = 0;
+
+	poll_timer_add (*gmi_poll_handle, TIMEOUT_STATE_COMMIT, 0,
+		memb_timer_function_state_commit_timeout, &timer_memb_state_commit_timeout);
+
+	return (res);
+}
+
+static void memb_timer_function_state_gather (void *data)
+{
+	int i;
+	/*
+	 * GATHER period expired, sort gather sets and send JOIN
+	 */
+	memb_state_commit_enter ();
+	log_printf (LOG_LEVEL_DEBUG, "GATHER timeout:\n");
+	for (i = 0; i < memb_gather_set_entries; i++) {
+		log_printf (LOG_LEVEL_DEBUG, "host %d attempted to join %s\n", i, inet_ntoa (memb_gather_set[i]));
+	}
+}
+
+static void memb_print_commit_set (void)
+{
+	int i, j;
+
+	log_printf (LOG_LEVEL_DEBUG, "Gather list\n");
+	for (i = 0; i < memb_gather_set_entries; i++) {
+		log_printf (LOG_LEVEL_DEBUG, "\tmember %d %s\n", i, inet_ntoa (memb_gather_set[i]));
+	}
+	for (i = 0; i < memb_commit_set_entries; i++) {
+		log_printf (LOG_LEVEL_DEBUG, "Join from rep %d %s\n", i, inet_ntoa (memb_commit_set[i].rep.sin_addr));
+		for (j = 0; j < memb_commit_set[i].join_rep_list_entries; j++) {
+			log_printf (LOG_LEVEL_DEBUG, "\tmember %d %s\n", j, inet_ntoa (memb_commit_set[i].join_rep_list[j]));
+		}
+	}
+}
+
+/*
+ * Determine if the commit phase has reached consensus
+ */
+static int memb_state_consensus_commit (void)
+{
+	int found;
+	int res;
+	int i, j;
+
+	/*
+	 * Determine consensus
+	 */
+
+	/*
+	 * If all commit sets don't match gather set, no consensus
+	 */
+	for (i = 0; i < memb_commit_set_entries; i++) {
+		/*
+		 * If not same number of entries, no consensus
+		 */
+		res = memb_gather_set_entries - memb_commit_set[i].join_rep_list_entries;
+		if (res != 0) {
+			return (0); /* no consensus */
+		}
+
+		/*
+		 * If entries dont match, no consensus
+		 */
+		res = memcmp (memb_gather_set, memb_commit_set[i].join_rep_list,
+			memb_gather_set_entries * sizeof (struct in_addr));
+		
+		if (res != 0) {
+			return (0); /* no consensus */
+		}
+	}
+
+	/*
+	 * If all reps from gather set represented in commit set, consensus
+	 */
+	for (i = 0; i < memb_gather_set_entries; i++) {
+		found = 0;
+		for (j = 0; j < memb_commit_set_entries; j++) {
+			if (memb_gather_set[i].s_addr == memb_local_sockaddr_in.sin_addr.s_addr) {
+				found = 1;
+				break;
+			}
+			if (memb_gather_set[i].s_addr == memb_commit_set[j].rep.sin_addr.s_addr) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (found == 0) {
+			return (0); /* no consensus, rep not found from gather set */
+		}
+	}
+
+	return (1); /* got consensus! */
+}
+
+/*
+ * Union commit_set_entry into gather set
+ */
+static void memb_state_commit_union (int commit_set_entry)
+{
+int found;
+int i, j;
+
+	for (i = 0; i < memb_commit_set[commit_set_entry].join_rep_list_entries; i++) {
+		for (found = 0, j = 0; j < memb_gather_set_entries; j++) {
+			if (memb_commit_set[commit_set_entry].join_rep_list[i].s_addr ==
+				memb_gather_set[j].s_addr) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (found == 0) {
+			memb_gather_set[memb_gather_set_entries++].s_addr =
+				memb_commit_set[commit_set_entry].join_rep_list[i].s_addr;
+			/*
+			 * Sort gather set
+			 */
+			qsort (memb_gather_set, memb_gather_set_entries,
+				sizeof (struct in_addr), in_addr_compare);
+		}
+	}
+}
+
+static void memb_conf_id_build (
+	struct memb_conf_id *memb_conf_id,
+	struct in_addr memb_local_rep)
+{
+	gettimeofday (&memb_conf_id->tv, NULL);
+	memb_conf_id->rep.s_addr = memb_local_rep.s_addr;
+}
+
+static void memb_form_token_update_highest_seq (
+	struct memb_form_token *form_token)
+{
+	struct conf_desc *conf_desc;
+	int entry;
+	int found = 0;
+
+	for (entry = 0; entry < form_token->conf_desc_list_entries; entry++) {
+		if (memcmp (&form_token->conf_desc_list[entry].conf_id,
+			&memb_form_token_conf_id, sizeof (struct memb_conf_id)) == 0) {
+
+			found = 1;
+			break;
+		}
+	}
+	conf_desc = &form_token->conf_desc_list[entry];
+	if (found && gmi_highest_seq < conf_desc->highest_seq) {
+		gmi_highest_seq = conf_desc->highest_seq;
+	}
+}
+
+static void memb_form_token_conf_desc_build (
+	struct memb_form_token *form_token)
+{
+	struct conf_desc *conf_desc;
+	int found = 0;
+	int entry = 0;
+
+	/*
+	 * Determine if local configuration id is already present in form token
+	 */
+	for (entry = 0; entry < form_token->conf_desc_list_entries; entry++) {
+		if (memcmp (&form_token->conf_desc_list[entry].conf_id,
+			&memb_form_token_conf_id, sizeof (struct memb_conf_id)) == 0) {
+
+			found = 1;
+			break;
+		}
+	}
+	conf_desc = &form_token->conf_desc_list[entry];
+
+	if (found == 0) {
+		/*
+		 * Item not present, add item
+		 */
+		conf_desc->highest_seq = gmi_highest_seq;
+		conf_desc->arut = gmi_arut;
+// TODO holes not currently implemented conf_desc->hole_list_entries = 0;
+		memcpy (&conf_desc->conf_id,
+			&memb_form_token_conf_id, sizeof (struct memb_conf_id));
+
+		form_token->conf_desc_list_entries += 1;
+	} else {
+		/*
+		 * Item already present, update arut, highest seq
+		 */
+		if (conf_desc->arut > gmi_arut) {
+			conf_desc->arut = gmi_arut;
+		}
+		if (gmi_highest_seq > conf_desc->highest_seq) {
+			conf_desc->highest_seq = gmi_highest_seq;
+		}
+	}
+	
+#ifdef COMPILE_OUT
+	/*
+	 * Build conf_desc->hole_list
+	 */
+printf ("conf desc build %d %d\n", gmi_arut, gmi_highest_seq);
+	conf_desc->hole_list_entries = 0;
+	for (i = gmi_arut; i < gmi_highest_seq; i++) {
+		assert (conf_desc->hole_list_entries < HOLE_LIST_MAX);
+		res = sq_item_get (&queue_rtr_items, i, (void **)&gmi_rtr_item_p);
+		if (res == 0) {
+			/*
+			 * If item present, delete from hole list if it exists
+			 */
+			for (j = 0; j < conf_desc->hole_list_entries; j++) {
+				if (conf_desc->hole_list[j] == i) {
+					memmove (&conf_desc->hole_list[j], &conf_desc->hole_list[j + 1],
+						sizeof (int) * (conf_desc->hole_list_entries - j - 1));
+					conf_desc->hole_list_entries -= 1;
+printf ("reducing setting desc entries to %d\n", conf_desc->hole_list_entries);
+					break; /* from for (j = ... ) */
+				}
+			}
+		} else {
+			/*
+			 * If item not present, add to hole list
+			 */
+			conf_desc->hole_list[conf_desc->hole_list_entries] = i;
+			conf_desc->hole_list_entries += 1;
+printf ("increasing setting desc entries to %d %d\n", conf_desc->hole_list_entries, i);
+		}
+	}
+printf ("Conf desc build done\n");
+#endif
+}
+
+static int memb_form_token_send (
+	struct memb_form_token *form_token)
+{
+	struct msghdr msg_form_token;
+	struct iovec iovec_form_token;
+	int res;
+
+	/*
+	 * Build message for sendmsg
+	 */
+	iovec_form_token.iov_base = form_token;
+	iovec_form_token.iov_len = sizeof (struct memb_form_token);
+
+	msg_form_token.msg_name = &memb_next;
+	msg_form_token.msg_namelen = sizeof (struct sockaddr_in);
+	msg_form_token.msg_iov = &iovec_form_token;
+	msg_form_token.msg_iovlen = 1;
+	msg_form_token.msg_control = 0;
+	msg_form_token.msg_controllen = 0;
+	msg_form_token.msg_flags = 0;
+	
+	res = sendmsg (gmi_fd, &msg_form_token, MSG_NOSIGNAL | MSG_DONTWAIT);
+
+	/*
+	 * res not used here, because orf token errors are handled by algorithm
+	 */
+	stats_sent += res;
+
+	poll_timer_delete (*gmi_poll_handle, timer_orf_token_timeout);
+	timer_orf_token_timeout = 0;
+
+	poll_timer_delete (*gmi_poll_handle, timer_form_token_timeout);
+
+	poll_timer_add (*gmi_poll_handle, TIMEOUT_TOKEN, 0,
+		timer_function_form_token_timeout, &timer_form_token_timeout);
+
+	return (res);
+}
+
+int memb_form_token_send_initial (void)
+{
+	struct memb_form_token form_token;
+	int res;
+
+	memset (&form_token, 0x00, sizeof (struct memb_form_token));
+	memb_state = MEMB_STATE_FORM;
+
+	/*
+	 * Build form token
+	 */
+	form_token.header.type = MESSAGE_TYPE_MEMB_FORM_TOKEN;
+	memcpy (form_token.rep_list,
+		memb_gather_set,
+		memb_gather_set_entries * sizeof (struct in_addr));
+	form_token.rep_list_entries = memb_gather_set_entries;
+
+	/*
+	 * Add local member to entry
+	 */
+	form_token.member_list[0].s_addr =
+		memb_local_sockaddr_in.sin_addr.s_addr;
+	form_token.member_list_entries = 1;
+
+	memb_conf_id_build (&form_token.conf_id, memb_local_sockaddr_in.sin_addr);
+
+	form_token.conf_desc_list_entries = 0;
+	memb_form_token_conf_desc_build (&form_token);
+	
+	/*
+	 * Send FORM to next member, or if no members in this configuration
+	 * to next representative
+	 */
+
+	if (memb_list_entries <= 1) {
+		memb_next.sin_addr.s_addr = memb_gather_set[1].s_addr;
+	}
+
+// TODO assertion here about the 1 value
+	memb_next.sin_family = AF_INET;
+	memb_next.sin_port = sockaddr_in_mcast.sin_port;
+
+	res = memb_form_token_send (&form_token);
+
+	return (res);
+}
+
+void print_stats (void)
+{
+	struct timeval tv_end;
+	gettimeofday (&tv_end, NULL);
+	
+	log_printf (LOG_LEVEL_NOTICE, "Bytes recv %d\n", stats_recv);
+	log_printf (LOG_LEVEL_NOTICE, "Bytes sent %d\n", stats_sent);
+	log_printf (LOG_LEVEL_NOTICE, "Messages delivered %d\n", stats_delv);
+	log_printf (LOG_LEVEL_NOTICE, "Re-Mcasts %d\n", stats_remcasts);
+	log_printf (LOG_LEVEL_NOTICE, "Tokens process %d\n", stats_orf_token);
+}
+
+/*
+ * Authenticates message using nonce, mac, and message body
+ */
+static int gmi_msg_auth (struct iovec *iovec, int iov_len)
+{
+	return (0);
+}
+
+
+int last_lowered = 1;
+
+static void calculate_group_arut (struct orf_token *orf_token)
+{
+//printf ("group arut %d local arut %d gmi_gmi_highest seq %d\n", orf_token->group_arut, gmi_arut, gmi_highest_seq);
+//printf ("last %d group arut %d last arut %d arut %d\n", last_lowered, orf_token->group_arut, last_group_arut, gmi_arut);
+
+	/*
+	 * increase the group arut if we got back the same group
+	 * because everyone has these messages
+	 */
+	messages_free (orf_token->group_arut);
+	if (orf_token->addr_arut.s_addr == this_ip.sin_addr.s_addr) {
+		orf_token->group_arut = gmi_arut;
+	}
+
+	if (gmi_arut < orf_token->group_arut) {
+		orf_token->group_arut = gmi_arut;
+		orf_token->addr_arut.s_addr = this_ip.sin_addr.s_addr;
+	}
+	last_group_arut = orf_token->group_arut;
+}
+
+/*
+ * Message Handlers
+ */
+
+/*
+ * message handler called when TOKEN message type received
+ */
+static int message_handler_orf_token (
+	struct sockaddr_in *system_from,
+	struct iovec *iovec,
+	int iov_len,
+	int bytes_received)
+{
+	struct orf_token *orf_token;
+	int transmits_allowed;
+	int starting_group_arut;
+
+	orf_token = iovec[0].iov_base;
+
+#ifdef PRINT_STATS
+	if (orf_token->header.seqid > 10000) {
+		print_stats ();
+	}
+#endif
+
+	if (memb_state == MEMB_STATE_FORM) {
+		log_printf (LOG_LEVEL_NOTICE, "swallowing ORF token %d.\n", stats_orf_token);
+		poll_timer_delete (*gmi_poll_handle, timer_orf_token_timeout);
+		timer_orf_token_timeout = 0;
+		return (0);
+	}
+
+//printf ("Got orf token from %s\n", inet_ntoa (system_from->sin_addr));
+	starting_group_arut = orf_token->group_arut;
+	stats_orf_token++;
+	
+	transmits_allowed = orf_fcc_allowed (orf_token);
+
+//printf ("retransmit allowed %d\n", transmits_allowed);
+	/*
+	 * Retransmit failed messages and request retransmissions
+	 */
+
+	orf_token_rtr (orf_token, &transmits_allowed);
+//printf ("multicasts allowed %d\n", transmits_allowed);
+
+	/*
+	 * TODO Ok this is ugly and I dont like it.
+	 *
+	 * Flow control to limit number of missing multicast messages
+	 * on lossy switches, this could cause a large window between
+	 * what is delivered locally and what is delivered remotely.
+	 * This window could cause the hole list of the form token to
+	 * be overrun or cause the form token to be large.
+	 */
+
+	if ((gmi_brake + MISSING_MCAST_WINDOW) < orf_token->header.seqid) {
+		transmits_allowed = 0;
+	}
+
+	/*
+	 * Set the group arut and free any messages that can be freed
+	 */
+	if (memb_state != MEMB_STATE_EVS) {
+		calculate_group_arut (orf_token);
+	}
+
+	/*
+	 * Multicast queued messages
+	 */
+	orf_token_mcast (orf_token, transmits_allowed, system_from);
+
+	/*
+	 * Calculate flow control count
+	 */
+	orf_token_fcc (orf_token);
+
+	/*
+	 * Deliver membership and messages required by EVS
+	 */
+	orf_token_evs (orf_token, starting_group_arut);
+
+	if (memb_state == MEMB_STATE_EVS) {
+		calculate_group_arut (orf_token);
+	}
+
+	/*
+	 * Transmit orf_token to next member
+	 */
+	orf_token_send (orf_token);
+
+	return (0);
+}
+
+static int memb_state_gather_enter (void) {
+	struct msghdr msghdr_attempt_join;
+	struct iovec iovec_attempt_join;
+	struct memb_attempt_join memb_attempt_join;
+	int res = 0;
+
+	log_printf (LOG_LEVEL_NOTICE, "entering GATHER state.\n");
+	memb_state = MEMB_STATE_GATHER;
+
+	/*
+	 * Join message starts with no entries
+	 */
+	memb_join.active_rep_list_entries = 0;
+	memb_join.failed_rep_list_entries = 0;
+
+	/*
+	 * Copy local host info
+	 */
+	memb_gather_set[0].s_addr = memb_local_sockaddr_in.sin_addr.s_addr;
+	memb_gather_set_entries = 1;
+
+	/*
+	 * If this node is the representative, send attempt join
+	 */
+	if (memb_local_sockaddr_in.sin_addr.s_addr == memb_conf_id.rep.s_addr) {
+		log_printf (LOG_LEVEL_NOTICE, "SENDING attempt join because this node is ring rep.\n");
+		memb_attempt_join.header.seqid = 0;
+		memb_attempt_join.header.type = MESSAGE_TYPE_MEMB_ATTEMPT_JOIN;
+		
+		iovec_attempt_join.iov_base = &memb_attempt_join;
+		iovec_attempt_join.iov_len = sizeof (struct memb_attempt_join);
+
+		msghdr_attempt_join.msg_name = &sockaddr_in_mcast;
+		msghdr_attempt_join.msg_namelen = sizeof (struct sockaddr_in);
+		msghdr_attempt_join.msg_iov = &iovec_attempt_join;
+		msghdr_attempt_join.msg_iovlen = 1;
+		msghdr_attempt_join.msg_control = 0;
+		msghdr_attempt_join.msg_controllen = 0;
+		msghdr_attempt_join.msg_flags = 0;
+
+		res = sendmsg (gmi_fd, &msghdr_attempt_join, MSG_NOSIGNAL | MSG_DONTWAIT);
+		/*
+		 * res not checked here, there is nothing that can be done
+		 * instead rely on the algorithm to recover from faults
+		 */
+	}
+
+	poll_timer_delete (*gmi_poll_handle, timer_memb_state_gather_timeout);
+
+	poll_timer_add (*gmi_poll_handle, TIMEOUT_STATE_GATHER, 0,
+		memb_timer_function_state_gather, &timer_memb_state_gather_timeout);
+
+	return (res);
+}
+
+struct pend_delv *pend_delv_next_delivery_find (void)
+{
+	struct pend_delv *pend_delv = 0;
+	int i;
+
+	/*
+	 * Find first_delivery queue that is not mepty
+	 * this sets the first pend_delv
+	 */
+	for (i = 0; i < memb_list_entries_confchg; i++) {
+		if (queues_pend_delv[i].first_delivery && 
+			queue_is_empty (&queues_pend_delv[i].queue) == 0) {
+
+			pend_delv = &queues_pend_delv[i];
+//			printf ("Selecting first queue %s\n", inet_ntoa (pend_delv->ip));
+			break;
+		}
+	}
+
+	/*
+	 * Search remaining pend_delv for first deliveries with
+	 * smaller sequence numbers
+	 */
+	for (++i; i < memb_list_entries_confchg; i++) {
+		assert (pend_delv);
+		if (queues_pend_delv[i].first_delivery &&
+			(queue_is_empty (&queues_pend_delv[i].queue) == 0) &&
+			(queues_pend_delv[i].seqid < pend_delv->seqid)) {
+
+			pend_delv = &queues_pend_delv[i];
+//			printf ("Selecting first queue %s\n", inet_ntoa (pend_delv->ip));
+		}
+	}
+		
+	/*
+	 * Found first_delivery queue that wasn't empty, return it
+	 */
+	if (pend_delv) {
+		return (pend_delv);
+	}
+	/*
+	 * No first delivery queues, repeat same
+	 * process looking for any queue
+	 */
+	for (i = 0; i < memb_list_entries_confchg; i++) {
+		if (queue_is_empty (&queues_pend_delv[i].queue) == 0) {
+			pend_delv = &queues_pend_delv[i];
+			break;
+		}
+	}
+
+	/*
+	 * Find lowest sequence number queue
+	 */
+	for (++i; i < memb_list_entries_confchg; i++) {
+		assert (pend_delv);
+		if ((queue_is_empty (&queues_pend_delv[i].queue) == 0) &&
+			(queues_pend_delv[i].seqid < pend_delv->seqid)) {
+			pend_delv = &queues_pend_delv[i];
+		}
+	}
+
+	return (pend_delv);
+}
+
+static int user_deliver ()
+{
+	struct gmi_pend_delv_item *pend_delv_item;
+	int i = 0;
+	int res = 0;
+	struct iovec iovec_delv[256];
+	int iov_len_delv = 0;
+	struct mcast *mcast = 0;
+	int messages_delivered = 0;
+	struct pend_delv *pend_delv;
+	int retval = 0;
+
+	/*
+	 * Find pend_delv with lowest sequence number.  This pend_delv is
+	 * the queue that should be delivered from next
+	 */
+	pend_delv = pend_delv_next_delivery_find ();
+//printf ("Delivering from queue %s\n", inet_ntoa (pend_delv->ip));
+
+	/*
+	 * If a message was not assembled on the queue with the lowest
+	 * sequence number, return since there is no reason to attempt assembly.
+	 */
+	memset (iovec_delv, 0, sizeof (iovec_delv));
+	queue_item_iterator_init (&pend_delv->queue);
+	assert (queue_is_empty (&pend_delv->queue) == 0);
+//printf ("Starting a packet assembly\n");
+	do {
+		pend_delv_item = queue_item_iterator_get (&pend_delv->queue);
+		mcast = pend_delv_item->iovec[0].iov_base;
+
+		assert (pend_delv_item);
+		assert (pend_delv_item->iovec[0].iov_len < MESSAGE_SIZE_MAX);
+		assert (pend_delv_item->iovec[0].iov_len != 0);
+		assert (pend_delv_item->iovec[0].iov_base != 0);
+		assert (mcast != (struct mcast *)0xdeadbeef);
+		assert (pend_delv->ip.s_addr == mcast->source.s_addr);
+
+		messages_delivered += 1;
+
+		/*
+		 * Assemble io vector
+		 */
+		if (pend_delv_item->iovec[0].iov_len == sizeof (struct mcast)) {
+			/*
+			 * Copy iovec from second iovec if this is self-delivered
+			 */
+			memcpy (&iovec_delv[iov_len_delv],
+				&pend_delv_item->iovec[1],
+				sizeof (struct iovec) * pend_delv_item->iov_len - 1);
+			iov_len_delv += pend_delv_item->iov_len - 1;
+		} else {
+			/*
+			 * Copy iovec from first iovec if this is an external message
+			 */
+			iovec_delv[iov_len_delv].iov_base =
+				pend_delv_item->iovec[0].iov_base + sizeof (struct mcast);
+			iovec_delv[iov_len_delv].iov_len =
+				pend_delv_item->iovec[0].iov_len - sizeof (struct mcast);
+			assert (iovec_delv[iov_len_delv].iov_len < MESSAGE_SIZE_MAX);
+			iov_len_delv += 1;
+			if (pend_delv_item->iov_len > 1) {
+				memcpy (&iovec_delv[iov_len_delv],
+					&pend_delv_item->iovec[1],
+					sizeof (struct iovec) * pend_delv_item->iov_len - 1);
+				iov_len_delv += pend_delv_item->iov_len - 1;
+			}
+		}
+
+		assert (iov_len_delv < 256);
+		assert (iov_len_delv > 0);
+
+//printf ("Assembling from packet %d of %d of total %d\n",
+//	mcast->packet_number, mcast->packet_count, mcast->packet_seq);
+		/*
+		 * Deliver message if this is the last packet
+		 */
+		if (mcast->packet_number == mcast->packet_count) {
+			log_printf (LOG_LEVEL_DEBUG, "Last packet, delivering iovec %d entries seq %d\n",
+				iov_len_delv, i);
+
+			gmi_deliver_fn (
+				&mcast->groupname,
+				iovec_delv,
+				iov_len_delv);
+
+			/*
+			 * On the first message delivery:
+			 * Free items in the pending queue up to the barrier message
+			 * set gmi_adut to rut so that message_free may free any messages.
+			 */
+			if (pend_delv->first_delivery) {
+//				printf ("releasing all messages up to %d\n", gmi_adut);
+// TODO actually release the messages from the previous configuration
+// TODO without a fix here, those messages are leaked
+			}
+
+			/*
+			 * Because of the ordering guarantees, we are guaranteed that 
+			 * pend_delv->seqid on every invocation of user_deliver shall
+			 * increase (or reset to zero).  This allows us to set the
+			 * low water mark (gmi_adut) for freeing of messages to atleast
+			 * the beginning of this message.
+			 */ 
+			gmi_adut = pend_delv->seqid;
+
+			/*
+			 * Determine if there are more messages on this queue
+			 */
+			res = queue_item_iterator_next (&pend_delv->queue);
+			if (res == 0) {
+				/*
+				 * More items to deliver set queues seqid head so
+				 * correct pending queue can be selected next time
+				 */
+				pend_delv_item = queue_item_iterator_get (&pend_delv->queue);
+				mcast = pend_delv_item->iovec[0].iov_base;
+				pend_delv->seqid = mcast->header.seqid;
+				for (i = 0; i < messages_delivered; i++) {
+					queue_item_remove (&pend_delv->queue);
+				}
+			} else {
+				/*
+				 * No more items to deliver
+				 */
+				pend_delv->seqid = 0;
+				queue_reinit (&pend_delv->queue);
+			}
+			
+			retval = 1;
+			break; /* From do loop */
+		}
+
+		res = queue_item_iterator_next (&pend_delv->queue);
+	} while (res == 0);
+	return (retval);
+}
+
+struct pend_delv *pend_delv_find (struct in_addr source)
+{
+	struct pend_delv *pend_delv = 0;
+	int i;
+
+	for (i = 0; i < memb_list_entries_confchg; i++) {
+		if (source.s_addr == queues_pend_delv[i].ip.s_addr) {
+			pend_delv = &queues_pend_delv[i];
+			break;
+		}
+	}
+
+	return (pend_delv);
+}
+
+static int delivery_outstanding = 0;
+
+static void pending_queues_deliver (void)
+{
+	struct gmi_rtr_item *gmi_rtr_item_p;
+	int i;
+	int res;
+	struct mcast *mcast;
+	struct gmi_pend_delv_item pend_delv_item;
+	struct pend_delv *pend_delv;
+	int delivered;
+
+//printf ("Delivering messages to pending queues\n");
+	/*
+	 * Deliver messages in order from rtr queue to pending delivery queue
+	 */
+	for (i = gmi_arut + 1; i <= gmi_highest_seq; i++) {
+		res = sq_item_get (&queue_rtr_items, i, (void **)&gmi_rtr_item_p);
+		/*
+		 * If hole, stop assembly
+		 */
+		if (res != 0) {
+			break;
+		}
+		assert (gmi_rtr_item_p->iovec[0].iov_len < MESSAGE_SIZE_MAX);
+		mcast = gmi_rtr_item_p->iovec[0].iov_base;
+		if (mcast == (struct mcast *)0xdeadbeef) {
+			printf ("seqid %d\n", gmi_rtr_item_p->iovec[0].iov_len);
+		}
+		assert (mcast != (struct mcast *)0xdeadbeef);
+
+		/*
+		 * Message found
+		 */
+		log_printf (LOG_LEVEL_DEBUG,
+			"Delivering MCAST message with seqid %d to pending delivery queue\n",
+			mcast->header.seqid);
+
+//printf ("Delivering MCAST from packet %d of %d of total %d seqid %d\n", mcast->packet_number, mcast->packet_count, mcast->packet_seq, mcast->header.seqid);
+		gmi_arut = i;
+
+		/*
+		 * Create pending delivery item
+		 */
+		pend_delv_item.iov_len = gmi_rtr_item_p->iov_len;
+		memcpy (&pend_delv_item.iovec, gmi_rtr_item_p->iovec,
+			sizeof (struct iovec) * gmi_rtr_item_p->iov_len);
+		assert (gmi_rtr_item_p->iov_len < MAXIOVS);
+
+		assert (mcast->source.s_addr != 0);
+		pend_delv = pend_delv_find (mcast->source);
+		assert (pend_delv != 0);
+		assert (pend_delv->ip.s_addr != 0);
+
+		if (mcast->packet_number == 0) {
+			pend_delv->seqid = mcast->header.seqid;
+		}
+
+		/*
+		 * Add pending delivery item to pending delivery queue
+		 */
+		queue_item_add (&pend_delv->queue, &pend_delv_item);
+
+		/*
+		 * If message is complete, attempt delivery of all messages
+		 * that are currently outstanding
+		 */
+		if (mcast->packet_number == mcast->packet_count) {
+//printf ("Starting delivery\n");
+			delivery_outstanding += 1;
+			do {
+				delivered = user_deliver ();
+				if (delivered) {
+					delivery_outstanding -= 1;
+				}
+			} while (delivery_outstanding && delivered);
+		}
+	}
+//printf ("Done delivering messages to pending queues\n");
+}
+
+/*
+ * recv message handler called when MCAST message type received
+ */
+static int message_handler_mcast (
+	struct sockaddr_in *system_from,
+	struct iovec *iovec,
+	int iov_len,
+	int bytes_received)
+{
+	struct gmi_rtr_item gmi_rtr_item;
+	struct mcast *mcast;
+
+	mcast = iovec[0].iov_base;
+
+	/*
+	 * Ignore multicasts for other configurations
+	 * TODO shouldn't we enter gather here?
+	 */
+	if (memcmp (&mcast->memb_conf_id,
+		&memb_form_token_conf_id, sizeof (struct memb_conf_id)) != 0) {
+
+		return (0);
+	}
+
+	/*
+	 * Add mcast message to rtr queue if not already in rtr queue
+	 * otherwise free io vectors
+	 */
+	if (bytes_received > 0 && bytes_received < MESSAGE_SIZE_MAX &&
+		sq_item_inuse (&queue_rtr_items, mcast->header.seqid) == 0) {
+
+		/*
+		 * Allocate new multicast memory block
+		 * TODO we need to free this somewhere
+		 */
+		gmi_rtr_item.iovec[0].iov_base = malloc (bytes_received);
+		if (gmi_rtr_item.iovec[0].iov_base == 0) {
+			return (-1); /* error here is corrected by the algorithm */
+		}
+		memcpy (gmi_rtr_item.iovec[0].iov_base, mcast, bytes_received);
+		gmi_rtr_item.iovec[0].iov_len = bytes_received;
+		assert (gmi_rtr_item.iovec[0].iov_len > 0);
+		assert (gmi_rtr_item.iovec[0].iov_len < MESSAGE_SIZE_MAX);
+		gmi_rtr_item.iov_len = 1;
+		
+		if (mcast->header.seqid > gmi_highest_seq) {
+			gmi_highest_seq = mcast->header.seqid;
+		}
+
+		sq_item_add (&queue_rtr_items, &gmi_rtr_item, mcast->header.seqid);
+	}
+
+	pending_queues_deliver ();
+
+	return (0);
+}
+
+static int message_handler_memb_attempt_join (
+	struct sockaddr_in *system_from,
+	struct iovec *iov,
+	int iov_len,
+	int bytes_received)
+{
+	int token_lost;
+	int found;
+	int i;
+
+	log_printf (LOG_LEVEL_NOTICE, "Got attempt join from %s\n", inet_ntoa (system_from->sin_addr));
+
+	for (token_lost = 0, i = 0; i < memb_list_entries; i++) {
+		if (memb_list[i].sin_addr.s_addr == system_from->sin_addr.s_addr &&
+			memb_conf_id.rep.s_addr != system_from->sin_addr.s_addr) {
+			log_printf (LOG_LEVEL_DEBUG, "ATTEMPT JOIN, token lost, taking attempt join msg.\n");
+			poll_timer_delete (*gmi_poll_handle, timer_orf_token_timeout);
+			timer_orf_token_timeout = 0;
+			memb_conf_id.rep.s_addr = memb_local_sockaddr_in.sin_addr.s_addr;
+			token_lost = 1;
+			break;
+		}
+	}
+	
+	/*
+	 * Not representative
+	 */
+	if (token_lost == 0 &&
+		memb_conf_id.rep.s_addr != memb_local_sockaddr_in.sin_addr.s_addr) {
+
+		log_printf (LOG_LEVEL_NOTICE, "not the rep for this ring, not handling attempt join.\n");
+		return (0);
+	}
+
+	switch (memb_state) {
+		case MEMB_STATE_OPERATIONAL:
+		case MEMB_STATE_COMMIT:
+			memb_state_gather_enter ();
+			/*
+			 * Do NOT place break here, immediately execute gather attempt join
+			 */
+
+		case MEMB_STATE_GATHER:
+			log_printf (LOG_LEVEL_DEBUG, "ATTEMPT JOIN: state gather\n");
+			for (found = 0, i = 0; i < memb_gather_set_entries; i++) {
+				if (memb_gather_set[i].s_addr == system_from->sin_addr.s_addr) {
+					found = 1;
+				}
+			}
+
+			if (found == 0) {
+				memb_gather_set[memb_gather_set_entries++].s_addr = system_from->sin_addr.s_addr;
+				/*
+				 * Sort gather set
+				 */
+				qsort (memb_gather_set, memb_gather_set_entries,
+					sizeof (struct in_addr), in_addr_compare);
+
+			}
+			break;
+
+		default:
+			// TODO what about other states
+			log_printf (LOG_LEVEL_ERROR, "memb_attempt_join: EVS or FORM state attempt join occured %d\n", memb_state);
+	}
+
+	return (0);
+}
+
+static int message_handler_memb_join (
+	struct sockaddr_in *system_from,
+	struct iovec *iovec,
+	int iov_len,
+	int bytes_received)
+{
+	struct memb_join *memb_join;
+	int commit_entry;
+	int found;
+	int consensus;
+
+	/*
+	 * Not representative
+	 */
+	if (memb_conf_id.rep.s_addr != memb_local_sockaddr_in.sin_addr.s_addr) {
+		log_printf (LOG_LEVEL_DEBUG, "not the rep for this ring, not handling join.\n");
+		return (0);
+	}
+
+	switch (memb_state) {
+		case MEMB_STATE_OPERATIONAL:
+		case MEMB_STATE_GATHER:
+			memb_state_commit_enter ();
+			/*
+			 * do not place break in this case, immediately enter COMMIT state
+			 */
+
+		case MEMB_STATE_COMMIT:
+			log_printf (LOG_LEVEL_DEBUG, "JOIN in commit\n");
+			memb_join = (struct memb_join *)iovec[0].iov_base;
+			/*
+			 * Find gather set that matches the system message was from	
+			 */
+			for (found = 0, commit_entry = 0; commit_entry < memb_commit_set_entries; commit_entry++) {
+				if (system_from->sin_addr.s_addr == memb_commit_set[commit_entry].rep.sin_addr.s_addr) {
+					found = 1;
+					break;
+				}
+			}
+
+			/*
+			 * Add system from to commit sets if not currently in commit set
+			 */
+			if (found == 0) {
+				memcpy (&memb_commit_set[commit_entry].rep, system_from, sizeof (struct sockaddr_in));
+				memb_commit_set_entries++;
+			}
+
+			/*
+			 * Set gather join data
+			 */
+			memcpy (memb_commit_set[commit_entry].join_rep_list, memb_join->active_rep_list,
+				sizeof (struct in_addr) * memb_join->active_rep_list_entries);
+			memb_commit_set[commit_entry].join_rep_list_entries = memb_join->active_rep_list_entries;
+
+			/*
+			 * Union all entries into the gather set (join_rep_list[0])
+			 */
+			memb_state_commit_union (commit_entry);
+
+			/*
+			 * Send JOIN message, but only if gather set has changed
+			 */
+			memb_join_send ();
+
+			/*
+			 * If consensus, transition to FORM
+			 */
+			memb_print_commit_set ();
+
+			consensus = memb_state_consensus_commit ();
+			if (consensus) {
+				log_printf (LOG_LEVEL_NOTICE, "CONSENSUS reached!\n");
+				if (memb_local_sockaddr_in.sin_addr.s_addr == memb_gather_set[0].s_addr) {
+					log_printf (LOG_LEVEL_DEBUG, "This node responsible for sending the FORM token.\n");
+
+					poll_timer_delete (*gmi_poll_handle, timer_memb_state_commit_timeout);
+					timer_memb_state_commit_timeout = 0;
+
+					memb_form_token_send_initial ();
+				}
+			}
+			break;
+		/*
+		 * All other cases are ignored on JOINs
+		 */
+		case MEMB_STATE_FORM:
+			log_printf (LOG_LEVEL_WARNING, "JOIN in form, ignoring since consensus reached in state machine.\n");
+			break;
+
+		default:
+			// TODO HANDLE THIS CASE
+			log_printf (LOG_LEVEL_DEBUG, "memb_join: DEFAULT case %d, shouldn't happen!!\n", memb_state);
+			break;
+	}
+
+	return (0);
+}
+
+static int message_handler_memb_form_token (
+	struct sockaddr_in *system_from,
+	struct iovec *iovec,
+	int iov_len,
+	int bytes_received)
+{
+	int i;
+	int local = 0;
+	int res = 0;
+	int swallow_form = 0;
+
+printf ("Got membership form token\n");
+	memcpy (&memb_form_token, iovec->iov_base, sizeof (struct memb_form_token));
+
+	poll_timer_delete (*gmi_poll_handle, timer_form_token_timeout);
+	timer_form_token_timeout = 0;
+
+
+	switch (memb_state) {
+	case MEMB_STATE_OPERATIONAL:
+	case MEMB_STATE_COMMIT:
+		memb_state = MEMB_STATE_FORM;
+		poll_timer_delete (*gmi_poll_handle, timer_memb_state_commit_timeout);
+		timer_memb_state_commit_timeout = 0;
+		/*
+		 * Add member to entry
+		 */
+		memb_form_token.member_list[memb_form_token.member_list_entries].s_addr =
+			memb_local_sockaddr_in.sin_addr.s_addr;
+		memb_form_token.member_list_entries++;
+		/*
+		 * Modify the conf_id as necessary
+		 */
+		memb_form_token_conf_desc_build (&memb_form_token);
+
+		/*
+		 * Stop token timeout timer from firing
+		 * If we are in FORM state, a previous FORM state member
+		 * may have captured the ORF token and swallowed it
+		 */
+		poll_timer_delete (*gmi_poll_handle, timer_orf_token_timeout);
+		timer_orf_token_timeout = 0;
+		break;
+
+	case MEMB_STATE_FORM:
+		memb_state = MEMB_STATE_EVS;
+		memb_form_token_update_highest_seq (&memb_form_token);
+
+		/*
+		 * FORM token has rotated once, now install local variables
+		 *
+		 * Set barrier sequence number
+		 * Set original arut
+		 */
+		gmi_barrier_seq = 0;
+printf ("conf_desc_list %d\n", memb_form_token.conf_desc_list_entries);
+		for (i = 0; i < memb_form_token.conf_desc_list_entries; i++) {
+printf ("highest seq %d %d\n", i, memb_form_token.conf_desc_list[i].highest_seq);
+			if (gmi_barrier_seq < memb_form_token.conf_desc_list[i].highest_seq) {
+				gmi_barrier_seq = memb_form_token.conf_desc_list[i].highest_seq;
+printf ("setting barrier seq to %d\n", gmi_barrier_seq);
+			}
+		}
+		gmi_barrier_seq += 1;
+printf ("setting barrier seq to %d\n", gmi_barrier_seq);
+		gmi_original_arut = gmi_arut;
+
+		/*
+		 * Determine next ORF target
+		 */
+		for (i = 0; i < memb_form_token.member_list_entries; i++) {
+			if (memb_local_sockaddr_in.sin_addr.s_addr == memb_form_token.member_list[i].s_addr) {
+				memb_next.sin_addr.s_addr =
+					memb_form_token.member_list[(i + 1) % memb_form_token.member_list_entries].s_addr;
+				memb_next.sin_family = AF_INET;
+				memb_next.sin_port = sockaddr_in_mcast.sin_port;
+			}
+		}
+		break;
+
+	case MEMB_STATE_EVS:
+		log_printf (LOG_LEVEL_DEBUG, "Swallowing FORM token in EVS state.\n");
+		printf ("FORM CONF ENTRIES %d\n", memb_form_token.conf_desc_list_entries);
+		orf_token_send_initial();
+		swallow_form = 1;
+		return (0);
+
+	default:
+		// TODO
+		log_printf (LOG_LEVEL_ERROR, "memb_form_token: default case, shouldn't happen.\n");
+		return (0);
+	}
+
+	/*
+	 * Find next member
+	 */
+	for (i = 0; i < memb_list_entries; i++) {
+		if (memb_list[i].sin_addr.s_addr == memb_local_sockaddr_in.sin_addr.s_addr) {
+			local = 1;
+			break;
+		}
+	}
+
+	if (memb_list_entries == 0) { /* 0 or 1 members and we are local */
+		local = 1;
+	}
+
+	if (local && (i + 1 < memb_list_entries)) {
+		memb_next.sin_addr.s_addr = memb_list[i + 1].sin_addr.s_addr;
+	} else {
+		/*
+		 * Find next representative
+	 	 */
+		for (i = 0; i < memb_form_token.rep_list_entries; i++) {
+			if (memb_conf_id.rep.s_addr ==
+				memb_form_token.rep_list[i].s_addr) {
+				break;
+			}
+		}
+		memb_next.sin_addr.s_addr =
+			memb_form_token.rep_list[(i + 1) % memb_form_token.rep_list_entries].s_addr;
+	}
+	memb_next.sin_family = AF_INET;
+	memb_next.sin_port = sockaddr_in_mcast.sin_port;
+	if (swallow_form == 0) {
+		res = memb_form_token_send (&memb_form_token);
+	}
+	return (res);
+}
+
+int recv_handler (poll_handle handle, int fd, int revents, void *data)
+{
+	struct msghdr msg_recv;
+	struct message_header *message_header;
+	struct sockaddr_in system_from;
+	int res = 0;
+	int bytes_received;
+
+	/*
+	 * Receive datagram
+	 */
+	msg_recv.msg_name = &system_from;
+	msg_recv.msg_namelen = sizeof (struct sockaddr_in);
+	msg_recv.msg_iov = &gmi_iov_recv;
+	msg_recv.msg_iovlen = 1;
+	msg_recv.msg_control = 0;
+	msg_recv.msg_controllen = 0;
+	msg_recv.msg_flags = 0;
+
+	bytes_received = recvmsg (gmi_fd, &msg_recv, MSG_NOSIGNAL | MSG_DONTWAIT);
+	if (bytes_received == -1) {
+		return (0);
+	} else {
+		stats_recv += bytes_received;
+	}
+
+	/*
+	 * Authenticate datagram
+	 */
+	res = gmi_msg_auth (msg_recv.msg_iov, msg_recv.msg_iovlen);
+	if (res == -1) {
+		return 0;
+	}
+
+	if (stats_tv_start.tv_usec == 0) {
+		gettimeofday (&stats_tv_start, NULL);
+	}
+
+	/*
+	 * Handle incoming message
+	 */
+	message_header = (struct message_header *)msg_recv.msg_iov[0].iov_base;
+	gmi_message_handlers.handler_functions[message_header->type] (
+		&system_from,
+		msg_recv.msg_iov,
+		msg_recv.msg_iovlen,
+		bytes_received);
+
+	return (0);
+}

+ 85 - 0
exec/gmi.h

@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef GMI_H_DEFINED
+#define GMI_H_DEFINED
+
+#include "poll.h"
+
+#define MESSAGE_SIZE_MAX	256000
+
+#define GMI_PRIO_HIGH		0
+#define GMI_PRIO_MED		1
+#define GMI_PRIO_LOW		2
+
+typedef int gmi_join_handle;
+
+struct gmi_groupname {
+	char groupname[16];
+};
+
+poll_handle *gmi_poll_handle;
+
+/*
+ * Group messaging interface
+ * depends on poll abstraction, POSIX, IPV4 or IPV6
+ */
+int gmi_init (
+	struct sockaddr_in *sockaddr_mcast,
+	struct sockaddr_in *sockaddr_bindnet,
+	poll_handle *poll_handle,
+	struct sockaddr_in *bound_to);
+
+
+int gmi_join (
+	struct gmi_groupname *groupname, 
+	void (*deliver_fn) (
+		struct gmi_groupname *groupname,
+		struct iovec *iovec,
+		int iov_len),
+	void (*confchg_fn) (
+		struct sockaddr_in *member_list, int member_list_entries,
+		struct sockaddr_in *left_list, int left_list_entries,
+		struct sockaddr_in *joined_list, int joined_list_entries),
+	gmi_join_handle *handle_out);
+
+int gmi_leave (
+	gmi_join_handle handle_join);
+
+int gmi_mcast (
+	struct gmi_groupname *groupname,
+	struct iovec *iovec,
+	int iov_len,
+	int priority);
+
+#endif /* GMI_H_DEFINED */

+ 59 - 0
exec/handlers.h

@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef HANDLERS_H_DEFINED
+#define HANDLERS_H_DEFINED
+
+#include <netinet/in.h>
+
+struct service_handler {
+	int (**libais_handler_fns) (int fd, void *);
+	int libais_handler_fns_count;
+	int (**aisexec_handler_fns) (int fd, void *);
+	int aisexec_handler_fns_count;
+	int (*confchg_fn) (
+		struct sockaddr_in *member_list, int member_list_entries,
+		struct sockaddr_in *left_list, int left_list_entries,
+		struct sockaddr_in *joined_list, int joined_list_entries);
+	int (*libais_init_fn) (int fd, void *);
+	int (*libais_exit_fn) (int fd);
+	int (*aisexec_init_fn) (void);
+};
+
+#ifdef COMPILE_OUT
+extern struct libais_message_handlers libais_message_handlers[];
+
+extern struct aisexec_message_handlers aisexec_message_handlers;
+#endif
+
+#endif /* HANDLERS_H_DEFINED */

+ 90 - 0
exec/log/print.c

@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/un.h>
+
+#include "print.h"
+
+int log_fd = 0;
+
+struct sockaddr_un syslog_sockaddr = {
+	sun_family: AF_UNIX,
+	sun_path: "/dev/log"
+};
+
+/*
+ * logging printf
+ */
+void
+internal_log_printf (int level, char *string, ...)
+{
+	va_list ap;
+	char newstring[1024];
+	struct msghdr msg_log;
+	struct iovec iov_log;
+	int res;
+
+	va_start(ap, string);
+	
+	sprintf (newstring, "L(%x): %s", level, string);
+	vfprintf(stderr, newstring, ap);
+
+	va_end(ap);
+
+	if (log_fd == 0) {
+		log_fd = socket (AF_UNIX, SOCK_DGRAM, 0);
+	}
+
+	iov_log.iov_base = newstring;
+	iov_log.iov_len = strlen (newstring) + 1;
+
+	msg_log.msg_iov = &iov_log;
+	msg_log.msg_iovlen = 1;
+	msg_log.msg_name = &syslog_sockaddr;
+	msg_log.msg_namelen = sizeof (syslog_sockaddr);
+	msg_log.msg_control = 0;
+	msg_log.msg_controllen = 0;
+	msg_log.msg_flags = 0;
+
+	res = sendmsg (log_fd, &msg_log, MSG_NOSIGNAL | MSG_DONTWAIT);
+printf ("res is %d\n", res);
+}
+
+int main (void) {
+	log_printf (LOG_LEVEL_ERROR, "This is error string 1=%d\n", 1);
+}

+ 64 - 0
exec/log/print.h

@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef PRINT_H_DEFINED
+#define PRINT_H_DEFINED
+
+#include "../include/ais_types.h"
+
+
+#define LOG_LEVEL_ERROR		1
+#define LOG_LEVEL_WARNING	2
+#define LOG_LEVEL_NOTICE	3
+#define LOG_LEVEL_DEBUG		4
+
+extern void internal_log_printf (int level, char *string, ...);
+
+/*
+ * The optimizer will remove DEBUG logging messages in production builds
+ */
+#ifdef DEBUG
+#define log_printf(level,format,args...) { internal_log_printf (level,format,##args); }
+#else
+#define log_printf(level,format,args...) { if (level != LOG_LEVEL_DEBUG) internal_log_printf (level,format,##args); }
+#endif
+
+extern void printSaNameT (char *format, SaNameT *name);
+
+extern void printSaClmNodeAddressT (char *format, SaClmNodeAddressT *nodeAddress);
+
+extern void printSaClmClusterNodeT (char *description, SaClmClusterNodeT *clusterNode);
+
+extern void saAmfPrintGroups (void);
+
+#endif /* PRINT_H_DEFINED */

+ 722 - 0
exec/main.c

@@ -0,0 +1,722 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <assert.h>
+#include <grp.h>
+#include <sys/poll.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/sysinfo.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <sched.h>
+#include <time.h>
+
+#include "../include/ais_types.h"
+#include "../include/ais_msg.h"
+#include "../include/list.h"
+#include "../include/queue.h"
+#include "poll.h"
+#include "gmi.h"
+#include "mempool.h"
+#include "parse.h"
+#include "main.h"
+#include "handlers.h"
+#include "clm.h"
+#include "amf.h"
+#include "ckpt.h"
+#include "print.h"
+
+#define SERVER_BACKLOG 5
+
+int connection_entries = 0;
+struct connection *connections = 0;
+int gid_valid = 20;
+
+struct gmi_groupname aisexec_groupname = { "0123" };
+
+/*
+ * All service handlers in the AIS
+ */
+struct service_handler *ais_service_handlers[] = {
+    &clm_service_handler,
+    &amf_service_handler,
+    &ckpt_service_handler,
+    &ckpt_checkpoint_service_handler,
+    &ckpt_sectioniterator_service_handler
+};
+
+#define AIS_SERVICE_HANDLERS_COUNT 5
+#define AIS_SERVICE_HANDLER_AISEXEC_FUNCTIONS_MAX 40
+
+static int poll_handler_libais_deliver (poll_handle handle, int fd, int revent, void *data);
+
+static inline void ais_done (int err)
+{
+	log_printf (LOG_LEVEL_ERROR, "AIS Executive exiting.\n");
+	exit (1);
+}
+
+static inline int init_connection_entry (int fd)
+{
+	int res;
+
+	memset (&connections[fd], 0, sizeof (struct connection));
+	connections[fd].active = 1;
+	res = queue_init (&connections[fd].outq, SIZEQUEUE, sizeof (struct outq_item));
+	if (res != 0) {
+		goto error_exit;
+	}
+	connections[fd].inb = malloc (sizeof (char) * SIZEINB);
+	if (connections[fd].inb == 0) {
+		queue_free (&connections[fd].outq);
+		goto error_exit;
+	}
+	return (0);
+	
+error_exit:
+	return (-1);
+}
+
+/*
+ * Grows the connections table to fd + 1 in size clearing new entries
+ */
+static inline int grow_connections_table (int fd)
+{
+	struct connection *conn_temp;
+
+	if (fd + 1 > connection_entries) {
+		conn_temp = mempool_realloc (connections, (fd + 1) * sizeof (struct connection));
+		if (conn_temp == 0) {
+			return (-1);
+		}
+		connections = conn_temp;
+		memset (&connections[connection_entries], 0,
+			(fd - connection_entries + 1) * sizeof (struct connection));
+		connection_entries = fd + 1;
+	}
+	return (0);
+}
+
+struct sockaddr_in this_ip;
+#define LOCALHOST_IP inet_addr("127.0.0.1")
+
+char *socketname = "libais.socket";
+
+static void libais_disconnect (int fd)
+{
+	int i;
+
+	close (fd);
+	connections[fd].active = 0;
+	queue_free (&connections[fd].outq);
+	free (connections[fd].inb);
+
+	for (i = 0; i < AIS_SERVICE_HANDLERS_COUNT; i++) {
+		if (ais_service_handlers[i]->libais_exit_fn) {
+			ais_service_handlers[i]->libais_exit_fn (fd);
+		}
+	}
+
+	poll_dispatch_delete (aisexec_poll_handle, fd);
+}
+
+extern int libais_send_response (int s, void *msg, int mlen)
+{
+	struct queue *outq;
+	char *cmsg;
+	int res;
+	int queue_empty;
+	struct outq_item *queue_item;
+	struct outq_item queue_item_out;
+	struct msghdr msg_send;
+	struct iovec iov_send;
+
+	outq = &connections[s].outq;
+
+	msg_send.msg_iov = &iov_send;
+	msg_send.msg_name = 0;
+	msg_send.msg_namelen = 0;
+	msg_send.msg_iovlen = 1;
+	msg_send.msg_control = 0;
+	msg_send.msg_controllen = 0;
+	msg_send.msg_flags = 0;
+
+	if (queue_is_full (outq)) {
+		log_printf (LOG_LEVEL_ERROR, "queue is full.\n");
+		ais_done (1);
+	}
+	while (!queue_is_empty (outq)) {
+		queue_item = queue_item_get (outq);
+		iov_send.iov_base = (void *)connections[s].byte_start;
+		iov_send.iov_len = queue_item->mlen;
+
+retry_sendmsg:
+		res = sendmsg (s, &msg_send, MSG_DONTWAIT | MSG_NOSIGNAL);
+		if (res == -1 && errno == EINTR) {
+			goto retry_sendmsg;
+		}
+		if (res == -1 && errno == EAGAIN) {
+			break; /* outgoing kernel queue full, ais_done while not empty */
+		}
+		if (res == -1) {
+			return (-1); /* message couldn't be sent */
+		}
+
+		/*
+		 * Message sent, try sending another message
+		 */
+		queue_item_remove (outq);
+		connections[s].byte_start = 0;
+		mempool_free (queue_item->msg);
+	} /* while queue not empty */
+
+	res = 0;
+	queue_empty = queue_is_empty (outq);
+	/*
+	 * Send requested message
+	 */
+	if (queue_empty) {
+		iov_send.iov_base = msg;
+		iov_send.iov_len = mlen;
+retry_sendmsg_two:
+		res = sendmsg (s, &msg_send, MSG_DONTWAIT | MSG_NOSIGNAL);
+		if (res == -1 && errno == EINTR) {
+			goto retry_sendmsg_two;
+		}
+		if (res == -1 && errno != EAGAIN) {
+			return (-1);
+		}
+	}
+
+	/*
+	 * If res == -1 , errrno == EAGAIN which means kernel queue full
+	 */
+	if (res == -1)  {
+		cmsg = mempool_malloc (mlen);
+		if (cmsg == 0) {
+			ais_done (1);
+		}
+		queue_item_out.msg = cmsg;
+		queue_item_out.mlen = mlen;
+		memcpy (cmsg, msg, mlen);
+		queue_item_add (outq, &queue_item_out);
+	}
+	return (0);
+}
+		
+static int poll_handler_libais_accept (
+	poll_handle handle,
+	int fd,
+	int revent,
+	void *data)
+{
+	int addrlen;
+	struct sockaddr_un un_addr;
+	int new_fd;
+	int on = 1;
+	int res;
+
+	addrlen = sizeof (struct sockaddr_un);
+
+retry_accept:
+	new_fd = accept (fd, (struct sockaddr *)&un_addr, &addrlen);
+	if (new_fd == -1 && errno == EINTR) {
+		goto retry_accept;
+	}
+
+	if (new_fd == -1) {
+		log_printf (LOG_LEVEL_ERROR, "ERROR: Could not accept Library connection: %s\n", strerror (errno));
+		return (0); /* This is an error, but -1 would indicate disconnect from poll loop */
+	}
+		
+	/*
+	 * Valid accept
+	 */
+
+	/*
+	 * Request credentials of sender provided by kernel
+	 */
+	setsockopt(new_fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on));
+
+	log_printf (LOG_LEVEL_DEBUG, "connection received from libais client %d.\n", new_fd);
+	/*
+	 * Generate new connections array
+	 */
+	res = grow_connections_table (new_fd);
+	if (res == -1) {
+		close (new_fd);
+		return (0); /* This is an error, but -1 would indicate disconnect from poll */
+
+	}
+
+	res = init_connection_entry (new_fd);
+	if (res == -1) {
+		close (new_fd);
+		return (0); /* This is an error, but -1 would indicate disconnect from poll */
+	}
+	poll_dispatch_add (aisexec_poll_handle, new_fd, POLLIN, 0, poll_handler_libais_deliver);
+
+	connections[new_fd].service = SOCKET_SERVICE_INIT;
+	memcpy (&connections[new_fd].ais_ci.un_addr, &un_addr, sizeof (struct sockaddr_un));
+	return (0);
+}
+
+static int poll_handler_libais_deliver (poll_handle handle, int fd, int revent, void *data)
+{
+	int res;
+	struct message_header *header;
+	int service;
+	struct msghdr msg_recv;
+	struct iovec iov_recv;
+	struct cmsghdr *cmsg;
+	char cmsg_cred[CMSG_SPACE (sizeof (struct ucred))];
+	struct ucred *cred;
+	int on = 0;
+
+	msg_recv.msg_iov = &iov_recv;
+	msg_recv.msg_iovlen = 1;
+	msg_recv.msg_name = 0;
+	msg_recv.msg_namelen = 0;
+	msg_recv.msg_flags = 0;
+
+	if (connections[fd].authenticated) {
+		msg_recv.msg_control = 0;
+		msg_recv.msg_controllen = 0;
+	} else {
+		msg_recv.msg_control = (void *)cmsg_cred;
+		msg_recv.msg_controllen = sizeof (cmsg_cred);
+	}
+
+	iov_recv.iov_base = &connections[fd].inb[connections[fd].inb_start];
+	iov_recv.iov_len = (SIZEINB) - connections[fd].inb_start;
+	assert (iov_recv.iov_len != 0);
+//printf ("inb start inb inuse %d %d\n", connections[fd].inb_start, connections[fd].inb_inuse);
+
+retry_recv:
+	res = recvmsg (fd, &msg_recv, MSG_DONTWAIT | MSG_NOSIGNAL);
+//printf ("received %d bytes\n", res);
+	if (res == -1 && errno == EINTR) {
+		goto retry_recv;
+	} else
+	if (res == -1) {
+		goto error_exit;
+	} else
+	if (res == 0) {
+		goto error_exit;
+		return (-1);
+	}
+
+	/*
+	 * Authenticate if this connection has not been authenticated
+	 */
+	if (connections[fd].authenticated == 0) {
+		cmsg = CMSG_FIRSTHDR (&msg_recv);
+		cred = (struct ucred *)CMSG_DATA (cmsg);
+		if (cred) {
+			if (cred->uid == 0 || cred->gid == gid_valid) {
+				setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on));
+				connections[fd].authenticated = 1;
+			}
+		}
+		if (connections[fd].authenticated == 0) {
+			log_printf (LOG_LEVEL_SECURITY, "Connection not authenticated because gid is %d, expecting %d\n", cred->gid, gid_valid);
+		}
+	}
+	/*
+	 * Dispatch all messages received in recvmsg that can be dispatched
+	 * sizeof (struct message_header) needed at minimum to do any processing
+	 */
+	connections[fd].inb_inuse += res;
+	connections[fd].inb_start += res;
+
+	while (connections[fd].inb_inuse >= sizeof (struct message_header) && res != -1) {
+		header = (struct message_header *)&connections[fd].inb[connections[fd].inb_start - connections[fd].inb_inuse];
+
+		if (header->magic != MESSAGE_MAGIC) {
+			log_printf (LOG_LEVEL_SECURITY, "Invalid magic is %x should be %x\n", header->magic, MESSAGE_MAGIC);
+			res = -1;
+			goto error_exit;
+		}
+
+		if (header->size > connections[fd].inb_inuse) {
+			break;
+		}
+		service = connections[fd].service;
+
+		/*
+		 * If this service is in init phase, initialize service
+		 * else handle message using service handlers
+		 */
+		if (service == SOCKET_SERVICE_INIT) {
+			/*
+			 * Initializing service
+			 */
+			res = ais_service_handlers[header->id]->libais_init_fn (fd, header);
+		} else  {
+			/*
+			 * Not an init service, but a standard service
+			 */
+			if (header->id < 0 || header->id > ais_service_handlers[service - 1]->libais_handler_fns_count) {
+				log_printf (LOG_LEVEL_SECURITY, "Invalid header id is %d min 0 max %d\n",
+				header->id, ais_service_handlers[service - 1]->libais_handler_fns_count);
+				res = -1;
+				goto error_exit;
+			}
+	
+			res = ais_service_handlers[service - 1]->libais_handler_fns[header->id](fd, header);
+		}
+		connections[fd].inb_inuse -= header->size;
+	} /* while */
+
+	if (connections[fd].inb_inuse == 0) {
+		connections[fd].inb_start = 0;
+	} else 
+// BUG	if (connections[fd].inb_start + connections[fd].inb_inuse >= SIZEINB) {
+	if (connections[fd].inb_start >= SIZEINB) {
+		/*
+		 * If in buffer is full, move it back to start
+		 */
+		memmove (connections[fd].inb,
+			&connections[fd].inb[connections[fd].inb_start -
+				connections[fd].inb_inuse],
+			sizeof (char) * connections[fd].inb_inuse);
+		connections[fd].inb_start = connections[fd].inb_inuse;
+	}
+
+	
+	return (res);
+
+error_exit:
+	libais_disconnect (fd);
+	return (-1); /* remove entry from poll list */
+}
+
+extern void print_stats (void);
+
+void sigintr_handler (int signum)
+{
+
+#ifdef DEBUG_MEMPOOL
+	int stats_inuse[MEMPOOL_GROUP_SIZE];
+	int stats_avail[MEMPOOL_GROUP_SIZE];
+	int stats_memoryused[MEMPOOL_GROUP_SIZE];
+	int i;
+
+	mempool_getstats (stats_inuse, stats_avail, stats_memoryused);
+	log_printf (LOG_LEVEL_DEBUG, "Memory pools:\n");
+	for (i = 0; i < MEMPOOL_GROUP_SIZE; i++) {
+	log_printf (LOG_LEVEL_DEBUG, "order %d size %d inuse %d avail %d memory used %d\n",
+		i, 1<<i, stats_inuse[i], stats_avail[i], stats_memoryused[i]);
+	}
+#endif
+
+	print_stats ();
+	ais_done (0);
+}
+
+static struct sched_param sched_param = { 
+	sched_priority: 99
+};
+
+static int pool_sizes[] = { 0, 0, 0, 0, 0, 4096, 0, 1, 0, /* 256 */
+					1024, 0, 1, 4096, 0, 0, 0, 0, /* 65536 */
+					1, 1, 1, 1, 1, 1, 1, 1, 1 };
+
+static int (*aisexec_handler_fns[AIS_SERVICE_HANDLER_AISEXEC_FUNCTIONS_MAX]) (int fd, void *);
+static int aisexec_handler_fns_count = 0;
+
+/*
+ * Builds the handler table as an optimization
+ */
+static void aisexec_handler_fns_build (void)
+{
+	int i, j;
+
+	for (i = 0; i < AIS_SERVICE_HANDLERS_COUNT; i++) {
+		for (j = 0; j < ais_service_handlers[i]->aisexec_handler_fns_count; j++) {
+			aisexec_handler_fns[aisexec_handler_fns_count++] = 
+				ais_service_handlers[i]->aisexec_handler_fns[j];
+		}
+	}
+	log_printf (LOG_LEVEL_DEBUG, "built %d handler functions\n", aisexec_handler_fns_count);
+}
+
+char delivery_data[MESSAGE_SIZE_MAX];
+
+static void deliver_fn (
+	struct gmi_groupname *groupname,
+	struct iovec *iovec,
+	int iov_len)
+{
+	struct message_header *header;
+	int res;
+	int pos = 0;
+	int i;
+
+	/*
+	 * Build buffer without iovecs to make processing easier
+	 * This is only used for messages which are multicast with iovecs
+	 * and self-delivered.  All other mechanisms avoid the copy.
+	 */
+	if (iov_len > 1) {
+		for (i = 0; i < iov_len; i++) {
+			memcpy (&delivery_data[pos], iovec[i].iov_base, iovec[i].iov_len);
+			pos += iovec[i].iov_len;
+			assert (pos < MESSAGE_SIZE_MAX);
+		}
+		header = (struct message_header *)delivery_data;
+	} else {
+		header = iovec[0].iov_base;
+	}
+	res = aisexec_handler_fns[header->id](0, header);
+}
+
+static void confchg_fn (
+	struct sockaddr_in *member_list, int member_list_entries,
+	struct sockaddr_in *left_list, int left_list_entries,
+	struct sockaddr_in *joined_list, int joined_list_entries)
+{
+	int i;
+
+	/*
+	 * Call configure change for all APIs
+	 */
+	for (i = 0; i < AIS_SERVICE_HANDLERS_COUNT; i++) {
+		if (ais_service_handlers[i]->confchg_fn) {
+			ais_service_handlers[i]->confchg_fn (member_list, member_list_entries,
+				left_list, left_list_entries, joined_list, joined_list_entries);
+		}
+	}
+}
+
+static void aisexec_group_determine (void) {
+	struct group *group;
+	group = getgrnam ("ais");
+	if (group == 0) {
+		log_printf (LOG_LEVEL_ERROR, "The 'ais' group is not found in /etc/group, please read the documentation.\n");
+		ais_done (-1);
+	}
+	gid_valid = group->gr_gid;
+}
+
+static void aisexec_mempool_init (void)
+{
+	int res;
+
+	res = mempool_init (pool_sizes);
+	if (res == ENOMEM) {
+		log_printf (LOG_LEVEL_ERROR, "Couldn't allocate memory pools, not enough memory");
+		ais_done (1);
+	}
+}
+
+static void aisexec_tty_detach (void)
+{
+#define DEBUG
+#ifndef DEBUG
+	/*
+	 * Disconnect from TTY if this is not a debug run
+	 */
+	switch (fork ()) {
+		case -1:
+			ais_done (1);
+			break;
+		case 0:
+			/*
+			 * child which is disconnected, run this process
+			 */
+			break;
+		default:
+			exit (0);
+			break;
+	}
+#endif
+#undef DEBUG
+}
+
+static void aisexec_service_handlers_init (void)
+{
+	int i;
+	/*
+	 * Initialize all services
+	 */
+	for (i = 0; i < AIS_SERVICE_HANDLERS_COUNT; i++) {
+		if (ais_service_handlers[i]->aisexec_init_fn) {
+			ais_service_handlers[i]->aisexec_init_fn ();
+		}
+	}
+}
+
+static void aisexec_libais_bind (int *server_fd)
+{
+	int libais_server_fd;
+	struct sockaddr_un un_addr;
+	int res;
+
+	/*
+	 * Create socket for libais clients, name socket, listen for connections
+	 */
+	libais_server_fd = socket (PF_UNIX, SOCK_STREAM, 0);
+	if (libais_server_fd == -1) {
+		log_printf (LOG_LEVEL_ERROR ,"Cannot create libais client connections socket.\n");
+		ais_done (1);
+	};
+
+	memset (&un_addr, 0, sizeof (struct sockaddr_un));
+	un_addr.sun_family = AF_UNIX;
+	strcpy (un_addr.sun_path + 1, socketname);
+
+	res = bind (libais_server_fd, (struct sockaddr *)&un_addr, sizeof (struct sockaddr_un));
+	if (res) {
+		log_printf (LOG_LEVEL_ERROR, "ERROR: Could not bind AF_UNIX: %s.\n", strerror (errno));
+		ais_done (1);
+	}
+	listen (libais_server_fd, SERVER_BACKLOG);
+
+	*server_fd = libais_server_fd;
+}
+
+static void aisexec_setscheduler (void)
+{
+	int res;
+
+	res = sched_setscheduler (0, SCHED_RR, &sched_param);
+	if (res == -1) {
+		log_printf (LOG_LEVEL_ERROR, "WARNING: Could not set SCHED_RR at priority 99: %s\n", strerror (errno));
+	}
+}
+
+static void aisexec_mlockall (void)
+{
+	int res;
+
+	res = mlockall (MCL_CURRENT | MCL_FUTURE);
+	if (res == -1) {
+		log_printf (LOG_LEVEL_ERROR, "WARNING: Could not lock memory of service to avoid page faults: %s\n", strerror (errno));
+	};
+}
+
+int main (int argc, char **argv)
+{
+	int libais_server_fd;
+	int res;
+	struct sockaddr_in sockaddr_in_mcast;
+	struct sockaddr_in sockaddr_in_bindnet;
+	gmi_join_handle handle;
+
+
+	char *error_string;
+
+	aisexec_group_determine ();
+
+	aisexec_handler_fns_build ();
+
+	aisexec_poll_handle = poll_create ();
+
+	res = amfReadNetwork (&error_string, &sockaddr_in_mcast, &sockaddr_in_bindnet);
+	if (res == -1) {
+		log_printf (LOG_LEVEL_ERROR, error_string);
+		ais_done (1);
+	}
+	
+
+	/*
+	 * Initialize group messaging interface with multicast address
+	 */
+	gmi_init (&sockaddr_in_mcast, &sockaddr_in_bindnet,
+		&aisexec_poll_handle, &this_ip);
+	
+	aisexec_mempool_init ();
+
+	res = amfReadGroups(&error_string);
+	if (res == -1) {
+		log_printf (LOG_LEVEL_ERROR, error_string);
+		ais_done (1);
+	}
+	
+	aisexec_tty_detach ();
+
+	log_printf (LOG_LEVEL_NOTICE, "AIS Executive Service: Copyright (C) 2002-2004 MontaVista Software, Inc.\n");
+	signal (SIGINT, sigintr_handler);
+
+	aisexec_service_handlers_init ();
+
+	aisexec_libais_bind (&libais_server_fd);
+
+	res = grow_connections_table (libais_server_fd);
+	if (res == -1) {
+		log_printf (LOG_LEVEL_ERROR, "Could not allocate memory for listening socket.\n");
+		ais_done (1);
+	}
+
+	log_printf (LOG_LEVEL_NOTICE, "AIS Executive Service: started and ready to receive connections.\n");
+
+	/*
+	 * Set round robin realtime scheduling with priority 99
+	 * Lock all memory to avoid page faults which may interrupt
+	 * application healthchecking
+	 */
+	aisexec_setscheduler ();
+
+	aisexec_mlockall ();
+
+	/*
+	 * Setup libais connection dispatch routine
+	 */
+	poll_dispatch_add (aisexec_poll_handle, libais_server_fd,
+		POLLIN, 0, poll_handler_libais_accept);
+
+	/*
+	 * Join multicast group and setup delivery
+	 *  and configuration change functions
+	 */
+	gmi_join (0, deliver_fn, confchg_fn, &handle);
+
+	/*
+	 * Start main processing loop
+	 */
+	poll_run (aisexec_poll_handle);
+
+	return (0);
+}

+ 113 - 0
exec/main.h

@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/un.h>
+#include "../include/ais_types.h"
+#include "poll.h"
+#include "clm.h"
+#include "amf.h"
+#include "ckpt.h"
+
+#ifndef AIS_EXEC_H_DEFINED
+#define AIS_EXEC_H_DEFINED
+
+/*
+ * Size of the queue (entries) for I/O's to the API over socket IPC.
+ */
+#define SIZEQUEUE 8192
+
+enum socket_service_type {
+	SOCKET_SERVICE_INIT,
+	SOCKET_SERVICE_CLM,
+	SOCKET_SERVICE_AMF,
+	SOCKET_SERVICE_CKPT,
+	SOCKET_SERVICE_CKPT_CHECKPOINT,
+	SOCKET_SERVICE_CKPT_SECTIONITERATOR
+};
+
+struct aisexec_ci {
+	struct sockaddr_in in_addr;	/* address of AF_INET socket, MUST BE FIRST IN STRUCTURE */
+	SaClmClusterNodeT clusterNode;
+	SaClmClusterChangesT lastChange;
+	unsigned char authentication_key[16];
+	int authenticated;
+};
+
+/*
+ * Connection information for AIS connections
+ */
+struct ais_ci {
+	struct sockaddr_un un_addr;	/* address of AF_UNIX socket, MUST BE FIRST IN STRUCTURE */
+	union {
+		struct aisexec_ci aisexec_ci;
+		struct libclm_ci libclm_ci;
+		struct libamf_ci libamf_ci;
+		struct libckpt_ci libckpt_ci;
+	} u;
+};
+
+struct outq_item {
+	void *msg;
+	size_t mlen;
+};
+
+#define SIZEINB MESSAGE_SIZE_MAX
+
+struct connection {
+	int active;			/* Does this file descriptor have an active connection */
+	char *inb;			/* Input buffer for non-blocking reads */
+	int inb_nextheader;	/* Next message header starts here */
+	int inb_start;		/* Start location of input buffer */
+	int inb_inuse;		/* Bytes currently stored in input buffer */
+	struct queue outq;		/* Circular queue for outgoing requests */
+	int byte_start;			/* Byte to start sending from in head of queue */
+	enum socket_service_type service;/* Type of service so dispatch knows how to route message */
+	struct saAmfComponent *component;	/* Component for which this connection relates to  TODO shouldn't this be in the ci structure */
+	int authenticated;		/* Is this connection authenticated? */
+	struct ais_ci ais_ci;	/* libais connection information */
+};
+
+extern int connection_entries;
+
+extern struct connection *connections;
+
+extern struct sockaddr_in this_ip;
+
+poll_handle aisexec_poll_handle;
+
+extern struct gmi_groupname aisexec_groupname;
+
+extern int libais_send_response (int s, void *msg, int mlen);
+
+#endif /* AIS_EXEC_H_DEFINED */

+ 224 - 0
exec/mempool.c

@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../include/list.h"
+#include "mempool.h"
+
+int mempool_bytes = 0;
+
+struct mempool_list {
+	struct list_head free;
+	short free_entries;
+	short used_entries;
+};
+
+struct mempool_entry {
+	struct list_head list;
+	int mempool_entry;
+	char mem[0];
+};
+
+struct mempool_list mempool_group[MEMPOOL_GROUP_SIZE];
+
+#ifdef MEMPOOL_ON
+int mempool_init (int pool_sizes[MEMPOOL_GROUP_SIZE])
+{
+	int i, j;
+	struct mempool_entry *entry;
+	void *mempool;
+	char *p;
+	int bytes_to_alloc;
+
+	for (i = 0; i < MEMPOOL_GROUP_SIZE; i++) {
+		for (j = 0; j < pool_sizes[i]; j++) {
+			bytes_to_alloc = sizeof (struct mempool_entry) + (1 << i) + 3;
+			bytes_to_alloc &= 0xFFFFFFFC;
+			mempool_bytes += bytes_to_alloc;
+		}
+	}
+	mempool = malloc (mempool_bytes);
+	if (mempool == 0) {
+		return (ENOMEM);
+	}
+	memset (mempool, 0, mempool_bytes);
+
+	for (p = (char *)mempool, i = 0; i < MEMPOOL_GROUP_SIZE; i++) {
+		list_init (&mempool_group[i].free);
+		mempool_group[i].free_entries = pool_sizes[i];
+		mempool_group[i].used_entries = 0;
+		
+		for (j = 0; j < pool_sizes[i]; j++) {
+			entry = (struct mempool_entry *)p;
+
+			entry->mempool_entry = i;
+			list_add (&entry->list, &mempool_group[i].free);
+
+			bytes_to_alloc = sizeof (struct mempool_entry) + (1 << i) + 3;
+			bytes_to_alloc &= 0xFFFFFFFC;
+			p += bytes_to_alloc;
+		}
+	}
+
+	return (0);
+}
+
+void *mempool_malloc (size_t size)
+{
+	struct mempool_entry *mempool_entry;
+	int i;
+#ifdef DEBUG
+	int first = 0;
+
+	int stats_inuse[MEMPOOL_GROUP_SIZE];
+	int stats_avail[MEMPOOL_GROUP_SIZE];
+	int stats_memoryused[MEMPOOL_GROUP_SIZE];
+#endif
+
+	for (i = 0; i < MEMPOOL_GROUP_SIZE; i++) {
+#ifdef DEBUG
+		if (((i << 1) >= size) && first == 0) {
+			first = i;
+		}
+#endif
+
+		if (((1 << i) >= size) &&
+			mempool_group[i].free_entries) {
+	
+			mempool_group[i].used_entries += 1;
+			mempool_group[i].free_entries -= 1;
+			mempool_entry = list_entry (mempool_group[i].free.next,
+				struct mempool_entry, list);
+			list_del (mempool_group[i].free.next);
+			return (&mempool_entry->mem);
+		}
+	}
+
+#ifdef DEBUG
+	mempool_getstats (stats_inuse, stats_avail, stats_memoryused);
+	printf ("MEMORY POOLS first %d %d:\n", first, size);
+	for (i = 0; i < MEMPOOL_GROUP_SIZE; i++) {
+	printf ("order %d size %d inuse %d avail %d memory used %d\n",
+		i, 1<<i, stats_inuse[i], stats_avail[i], stats_memoryused[i]);
+	}
+#endif
+	return (0);
+}
+
+void mempool_free (void *ptr) {
+	struct mempool_entry *mempool_entry;
+
+	mempool_entry = ((struct mempool_entry *)((unsigned long)(ptr) - (unsigned long)(&((struct mempool_entry *)0)->mem)));
+
+	mempool_group[mempool_entry->mempool_entry].free_entries += 1;
+	mempool_group[mempool_entry->mempool_entry].used_entries -= 1;
+	list_add (&mempool_entry->list, &mempool_group[mempool_entry->mempool_entry].free);
+}
+
+void *mempool_realloc (void *ptr, size_t size) {
+	struct mempool_entry *mempool_entry;
+	void *new_ptr;
+
+	mempool_entry = ((struct mempool_entry *)((unsigned long)(ptr) - (unsigned long)(&((struct mempool_entry *)0)->mem)));
+	
+	if (ptr == 0 || (1 << mempool_entry->mempool_entry) < size) {
+		/*
+		 * Must grow allocated block, copy memory, free old block
+		 */
+		new_ptr = (void *)mempool_malloc (size);
+		if (new_ptr == 0) {
+			return (0);
+		}
+		if (ptr) {
+			memcpy (new_ptr, ptr, (1 << mempool_entry->mempool_entry));
+			mempool_free (ptr);
+		}
+		ptr = new_ptr;
+	}
+
+	return (ptr);
+}
+
+char *mempool_strdup (const char *s)
+{
+	char *mem;
+
+	mem = mempool_malloc (strlen (s));
+	strcpy (mem, s);
+	return (mem);
+}
+
+void mempool_getstats (
+	int stats_inuse[MEMPOOL_GROUP_SIZE],
+	int stats_avail[MEMPOOL_GROUP_SIZE],
+	int stats_memoryused[MEMPOOL_GROUP_SIZE])
+{
+	int i;
+
+	for (i = 0; i < MEMPOOL_GROUP_SIZE; i++) {
+		stats_inuse[i] = mempool_group[i].used_entries;
+		stats_avail[i] = mempool_group[i].free_entries;
+		stats_memoryused[i] = (mempool_group[i].used_entries + mempool_group[i].free_entries) * (sizeof (struct mempool_entry) + (1<<i));
+	}
+}
+#else /* MEMPOOL_ON NOT SET */
+int mempool_init (int pool_sizes[MEMPOOL_GROUP_SIZE]) {
+	return (0);
+}
+
+void *mempool_malloc (size_t size) {
+	return (malloc (size));
+}
+void mempool_free (void *ptr) {
+	free (ptr);
+}
+
+void *mempool_realloc (void *ptr, size_t size) {
+	return (realloc (ptr, size));
+}
+
+char *mempool_strdup (const char *s) {
+	return (strdup (s));
+}
+void mempool_getstats (
+	int stats_inuse[MEMPOOL_GROUP_SIZE],
+	int stats_avail[MEMPOOL_GROUP_SIZE],
+	int stats_memoryused[MEMPOOL_GROUP_SIZE]) {
+
+	return;
+}
+#endif

+ 57 - 0
exec/mempool.h

@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "../include/list.h"
+
+#ifndef MEMPOOL_H_DEFINED
+#define MEMPOOL_H_DEFINED
+
+#define MEMPOOL_GROUP_SIZE 24
+
+int mempool_init (int pool_sizes[MEMPOOL_GROUP_SIZE]);
+
+void *mempool_malloc (size_t size);
+
+void mempool_free (void *ptr);
+
+void *mempool_realloc (void *ptr, size_t size);
+
+char *mempool_strdup (const char *s);
+
+void mempool_getstats (
+    int stats_inuse[MEMPOOL_GROUP_SIZE],
+    int stats_avail[MEMPOOL_GROUP_SIZE],
+    int stats_memoryused[MEMPOOL_GROUP_SIZE]);
+
+#endif /* MEMPOOL_H_DEFINED */

+ 444 - 0
exec/parse.c

@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "../include/ais_types.h"
+#include "../include/list.h"
+#include "parse.h"
+#include "mempool.h"
+
+DECLARE_LIST_INIT (saAmfGroupHead);
+
+typedef enum {
+	HEAD,
+	GROUP,
+	UNIT,
+	PROTECTION,
+	COMPONENT
+} SaParsingT;
+
+
+void setSaNameT (SaNameT *name, char *str) {
+	strncpy (name->value, str, SA_MAX_NAME_LENGTH);
+	if (strlen (name->value) > SA_MAX_NAME_LENGTH) {
+		name->length = SA_MAX_NAME_LENGTH;
+	} else {
+		name->length = strlen (str);
+	}
+}
+
+int SaNameTisEqual (SaNameT *str1, char *str2) {
+	if (str1->length == strlen (str2)) {
+		return ((strncmp (str1->value, str2, str1->length)) == 0);
+	} else {
+		return 0;
+	}
+}
+
+int SaNameTisNameT (SaNameT *name1, SaNameT *name2) {
+	if (name1->length == name2->length) {
+		return ((strncmp (name1->value, name2->value, name1->length)) == 0);
+	} else {
+		return 0;
+	}
+}
+
+struct saAmfComponent *findComponent (SaNameT *name)
+{
+	struct list_head *AmfGroupList = 0;
+	struct list_head *AmfUnitList = 0;
+	struct list_head *AmfComponentList = 0;
+
+	struct saAmfGroup *saAmfGroup = 0;
+	struct saAmfUnit *AmfUnit = 0;
+	struct saAmfComponent *AmfComponent = 0;
+	int found = 0;
+
+	/*
+	 * Search all groups
+	 */
+	for (AmfGroupList = saAmfGroupHead.next;
+		AmfGroupList != &saAmfGroupHead && found == 0;
+		AmfGroupList = AmfGroupList->next) {
+
+		saAmfGroup = list_entry (AmfGroupList,
+			struct saAmfGroup, saAmfGroupList);
+
+		/*
+		 * Search all units
+		 */
+		for (AmfUnitList = saAmfGroup->saAmfUnitHead.next;
+			AmfUnitList != &saAmfGroup->saAmfUnitHead && found == 0;
+			AmfUnitList = AmfUnitList->next) {
+
+			AmfUnit = list_entry (AmfUnitList,
+				struct saAmfUnit, saAmfUnitList);
+
+			/*
+			 * Search all components
+			 */
+			for (AmfComponentList = AmfUnit->saAmfComponentHead.next;
+				AmfComponentList != &AmfUnit->saAmfComponentHead && found == 0;
+				AmfComponentList = AmfComponentList->next) {
+
+				AmfComponent = list_entry (AmfComponentList,
+					struct saAmfComponent, saAmfComponentList);
+
+				if (SaNameTisNameT (name, &AmfComponent->name)) {
+					found = 1;
+				}
+			}
+		}
+	}
+
+	if (found) {
+		return (AmfComponent);
+	} else {
+		return (0);
+	}
+}
+char *
+strstr_rs (const char *haystack, const char *needle)
+{
+	char *end_address;
+	char *new_needle;
+
+	new_needle = (char *)mempool_strdup (needle);
+	new_needle[strlen(new_needle) - 1] = '\0';
+
+	end_address = strstr (haystack, new_needle);
+	if (end_address) {
+		end_address += strlen (new_needle);
+		end_address = strstr (end_address, needle + strlen (new_needle));
+	}
+	if (end_address) {
+		end_address += 1; /* skip past { or = */
+		do {
+			if (*end_address == '\t' || *end_address == ' ') {
+				end_address++;
+			} else {
+				break;
+			}
+		} while (*end_address != '\0');
+	}
+
+	mempool_free (new_needle);
+	return (end_address);
+}
+
+static char error_string_response[256];
+
+int amfReadGroups (char **error_string)
+{
+	char line[255];
+	FILE *fp;
+	SaParsingT current_parse = HEAD;
+	int line_number = 0;
+	char *loc;
+	int i;
+
+	struct saAmfGroup *saAmfGroup = 0;
+	struct saAmfUnit *saAmfUnit = 0;
+	struct saAmfProtectionGroup *saAmfProtectionGroup = 0;
+	struct saAmfComponent *saAmfComponent = 0;
+	struct list_head *findAmfUnitList = 0;
+	struct list_head *findAmfComponentList = 0;
+	struct saAmfUnit *findAmfUnit = 0;
+	struct saAmfComponent *findAmfComponent = 0;
+	SaNameT componentName;
+
+	fp = fopen ("/etc/ais/groups.conf", "r");
+	if (fp == 0) {
+		*error_string = "ERROR: Could not open /etc/groups.conf file.\n";
+		return (-1);
+	}
+
+	while (fgets (line, 255, fp)) {
+		line_number += 1;
+		line[strlen(line) - 1] = '\0';
+		/*
+		 * Clear out white space and tabs
+		 */
+		for (i = strlen (line) - 1; i > -1; i--) {
+			if (line[i] == '\t' || line[i] == ' ') {
+				line[i] = '\0';
+			} else {
+				break;
+			}
+		}
+		/*
+		 * Clear out comments and empty lines
+		 */
+		if (line[0] == '#' || line[0] == '\0') {
+			continue;
+		}
+			
+		switch (current_parse) {
+		case HEAD:
+			if (strstr_rs (line, "group{")) {
+				saAmfGroup = (struct saAmfGroup *)mempool_malloc (sizeof (struct saAmfGroup));
+				memset (saAmfGroup, 0, sizeof (struct saAmfGroup));
+				list_init (&saAmfGroup->saAmfGroupList);
+				list_init (&saAmfGroup->saAmfUnitHead);
+				list_init (&saAmfGroup->saAmfProtectionGroupHead);
+				list_add (&saAmfGroup->saAmfGroupList, &saAmfGroupHead);
+				current_parse = GROUP;
+			} else
+			if (strcmp (line, "") == 0) {
+			} else {
+				goto parse_error;
+			}
+			break;
+
+		case GROUP:
+			if ((loc = strstr_rs (line, "name=")) != 0) {
+				setSaNameT (&saAmfGroup->name, loc);
+			} else
+			if ((loc = strstr_rs (line, "model=")) != 0) {
+				if (strcmp (loc, "2n") == 0) {
+					saAmfGroup->model = GROUPCAPABILITYMODEL_2N;
+				} else
+				if (strcmp (loc, "nplusm") == 0) {
+					saAmfGroup->model = GROUPCAPABILITYMODEL_NPLUSM;
+				} else
+				if (strcmp (loc, "nway") == 0) {
+					printf ("nway redundancy model not supported.\n");
+					goto parse_error;
+				} else
+				if (strcmp (loc, "nwayactive") == 0) {
+					printf ("nway active redundancy model not supported.\n");
+					goto parse_error;
+				} else
+				if (strcmp (loc, "noredundancy") == 0) {
+					saAmfGroup->model = GROUPCAPABILITYMODEL_NOREDUNDANCY;
+				} else {
+					goto parse_error;
+				}
+			} else
+			if ((loc = strstr_rs (line, "active-units=")) != 0) {
+				saAmfGroup->saAmfActiveUnitsDesired = atoi (loc);
+			} else 
+			if ((loc = strstr_rs (line, "backup-units=")) != 0) {
+				saAmfGroup->saAmfStandbyUnitsDesired = atoi (loc);
+			} else 
+			if (strstr_rs (line, "unit{")) {
+				saAmfUnit = (struct saAmfUnit *)mempool_malloc (sizeof (struct saAmfUnit));
+				memset (saAmfUnit, 0, sizeof (struct saAmfUnit));
+				saAmfUnit->saAmfGroup = saAmfGroup;
+
+				list_init (&saAmfUnit->saAmfComponentHead);
+				list_add (&saAmfUnit->saAmfUnitList, &saAmfGroup->saAmfUnitHead);
+				current_parse = UNIT;
+			} else
+			if (strstr_rs (line, "protection{")) {
+				saAmfProtectionGroup = (struct saAmfProtectionGroup *)mempool_malloc (sizeof (struct saAmfProtectionGroup));
+				memset (saAmfProtectionGroup, 0, sizeof (struct saAmfProtectionGroup));
+				list_init (&saAmfProtectionGroup->saAmfMembersHead);
+				list_init (&saAmfProtectionGroup->saAmfProtectionGroupList);
+				list_add (&saAmfProtectionGroup->saAmfProtectionGroupList, &saAmfGroup->saAmfProtectionGroupHead);
+
+				current_parse = PROTECTION;
+			} else
+			if (strstr_rs (line, "}")) {
+				current_parse = HEAD;
+			} else {
+				goto parse_error;
+			}
+			break;
+
+		case UNIT:
+			if ((loc = strstr_rs (line, "name=")) != 0) {
+				setSaNameT (&saAmfUnit->name, loc);
+			} else
+			if ((loc = strstr_rs (line, "component{")) != 0) {
+				saAmfComponent = (struct saAmfComponent *)mempool_malloc (sizeof (struct saAmfComponent));
+				memset (saAmfComponent, 0, sizeof (struct saAmfComponent));
+				saAmfComponent->saAmfUnit = saAmfUnit;
+				saAmfComponent->currentReadinessState = SA_AMF_OUT_OF_SERVICE;
+				saAmfComponent->newReadinessState = SA_AMF_OUT_OF_SERVICE;
+				saAmfComponent->currentHAState = SA_AMF_QUIESCED;
+				saAmfComponent->newHAState = SA_AMF_QUIESCED;
+				saAmfComponent->healthcheckInterval = 100;
+				list_init (&saAmfComponent->saAmfComponentList);
+				list_init (&saAmfComponent->saAmfProtectionGroupList);
+				list_add (&saAmfComponent->saAmfComponentList, &saAmfUnit->saAmfComponentHead);
+
+				current_parse = COMPONENT;
+			} else
+			if (strstr_rs (line, "}")) {
+				current_parse = GROUP;
+			} else {
+				goto parse_error;
+			}
+			break;
+
+		case COMPONENT:
+			if ((loc = strstr_rs (line, "name=")) != 0) {
+				setSaNameT (&saAmfComponent->name, loc);
+			} else
+			if ((loc = strstr_rs (line, "model=")) != 0) {
+				if (strcmp (loc, "x_active_and_y_standby") == 0) {
+					saAmfComponent->componentCapabilityModel = SA_AMF_COMPONENT_CAPABILITY_X_ACTIVE_AND_Y_STANDBY;
+				} else
+				if (strcmp (loc, "x_active_or_y_standby") == 0) {
+					saAmfComponent->componentCapabilityModel = SA_AMF_COMPONENT_CAPABILITY_X_ACTIVE_OR_Y_STANDBY;
+				} else
+				if (strcmp (loc, "1_active_or_y_standby") == 0) {
+					saAmfComponent->componentCapabilityModel = SA_AMF_COMPONENT_CAPABILITY_1_ACTIVE_OR_Y_STANDBY;
+				} else
+				if (strcmp (loc, "1_active_or_1_standby") == 0) {
+					saAmfComponent->componentCapabilityModel = SA_AMF_COMPONENT_CAPABILITY_1_ACTIVE_OR_1_STANDBY;
+				} else
+				if (strcmp (loc, "x_active") == 0) {
+					saAmfComponent->componentCapabilityModel = SA_AMF_COMPONENT_CAPABILITY_X_ACTIVE;
+				} else
+				if (strcmp (loc, "1_active") == 0) {
+					saAmfComponent->componentCapabilityModel = SA_AMF_COMPONENT_CAPABILITY_1_ACTIVE;
+				} else
+				if (strcmp (loc, "no_active") == 0) {
+					saAmfComponent->componentCapabilityModel = SA_AMF_COMPONENT_CAPABILITY_NO_ACTIVE;
+				} else {
+					goto parse_error;
+				}
+			} else
+			if (strstr_rs (line, "}")) {
+				current_parse = UNIT;
+			} else {
+				goto parse_error;
+			}
+			break;
+
+		case PROTECTION:
+			if ((loc = strstr_rs (line, "name=")) != 0) {
+				setSaNameT (&saAmfProtectionGroup->name, loc);
+			} else
+			if ((loc = strstr_rs (line, "member=")) != 0) {
+				for (findAmfUnitList = saAmfGroup->saAmfUnitHead.next;
+					findAmfUnitList != &saAmfGroup->saAmfUnitHead;
+					findAmfUnitList = findAmfUnitList->next) {
+
+					findAmfUnit = list_entry (findAmfUnitList, 
+						struct saAmfUnit, saAmfUnitList);
+					for (findAmfComponentList = findAmfUnit->saAmfComponentHead.next;
+						findAmfComponentList != &findAmfUnit->saAmfComponentHead;
+						findAmfComponentList = findAmfComponentList->next) {
+
+						findAmfComponent = list_entry (findAmfComponentList, 
+							struct saAmfComponent, saAmfComponentList);
+
+						if (SaNameTisEqual (&findAmfComponent->name, loc)) {
+							list_add (&findAmfComponent->saAmfProtectionGroupList,
+								&saAmfProtectionGroup->saAmfMembersHead);
+						}
+					}
+					/*
+					 * Connect component to protection group
+					 */
+					setSaNameT (&componentName, loc);
+					saAmfComponent = findComponent (&componentName);
+					saAmfComponent->saAmfProtectionGroup = saAmfProtectionGroup;
+				}
+			} else
+			if (strstr_rs (line, "}")) {
+				current_parse = GROUP;
+			} else {
+				goto parse_error;
+			}
+			break;
+
+		default:
+			printf ("Invalid state\n");
+			goto parse_error;
+			break;
+		}
+	}
+
+	fclose (fp);
+	return (0);
+
+parse_error:
+	sprintf (error_string_response,
+		"ERROR: parse error at /etc/groups.conf:%d\n", line_number);
+	
+	*error_string = error_string_response;
+	fclose (fp);
+	return (-1);
+}
+
+int amfReadNetwork (char **error_string,
+	struct sockaddr_in *mcast_addr,
+	struct sockaddr_in *bindnet_addr)
+{
+	char line[255];
+	FILE *fp;
+	int res = 0;
+	int line_number = 0;
+
+
+	mcast_addr->sin_family = AF_INET;
+	fp = fopen ("/etc/ais/network.conf", "r");
+
+	while (fgets (line, 255, fp)) {
+		line_number += 1;
+		if (strncmp ("mcastaddr:", line, strlen ("mcastaddr:")) == 0) {
+			res = inet_aton (&line[strlen("mcastaddr:")], &mcast_addr->sin_addr);
+		} else
+		if (strncmp ("bindnetaddr:", line, strlen ("bindnetaddr:")) == 0) {
+			res = inet_aton (&line[strlen("bindnetaddr:")], &bindnet_addr->sin_addr);
+		} else
+		if (strncmp ("mcastport:", line, strlen ("mcastport:")) == 0) {
+			res = mcast_addr->sin_port = atoi (&line[strlen("mcastport:")]);
+		} else {
+			res = 0;
+			break;
+		}
+		if (res == 0) {
+			sprintf (error_string_response,	
+				"ERROR: parse error at /etc/ais/network.conf:%d\n", line_number);
+			*error_string = error_string_response;
+			res = -1;
+			break;
+		}
+		res = 0;
+	}
+
+
+	fclose (fp);
+	return (res);
+}

+ 161 - 0
exec/parse.h

@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/select.h>
+#include <netinet/in.h>
+#include "../include/ais_types.h"
+#include "../include/list.h"
+#include "poll.h"
+
+#ifndef PARSE_H_DEFINED
+#define PARSE_H_DEFINED
+
+typedef enum {
+	GROUPCAPABILITYMODEL_2N,
+	GROUPCAPABILITYMODEL_NPLUSM,
+	GROUPCAPABILITYMODEL_NWAY,
+	GROUPCAPABILITYMODEL_NWAYACTIVE,
+	GROUPCAPABILITYMODEL_NOREDUNDANCY
+} SaAmfGroupCapabilityModelT;
+
+enum amfOperationalAdministrativeState {
+	AMF_DISABLED_UNLOCKED = 0,
+	AMF_DISABLED_LOCKED = 1,
+	AMF_ENABLED_UNLOCKED = 2,
+	AMF_ENABLED_STOPPING = 3
+};
+
+struct saAmfUnit {
+	SaNameT name;
+	struct list_head saAmfComponentHead;
+	struct list_head saAmfUnitList;
+	enum amfOperationalAdministrativeState operationalAdministrativeState;
+	struct saAmfGroup *saAmfGroup;
+};
+
+struct saAmfProtectionGroup {
+	SaNameT name;
+	struct list_head saAmfMembersHead;
+	struct list_head saAmfProtectionGroupList;
+};
+
+struct saAmfGroup {
+	SaNameT name;
+	SaAmfGroupCapabilityModelT model;
+	SaUint32T saAmfActiveUnitsDesired;
+	SaUint32T saAmfStandbyUnitsDesired;
+	struct list_head saAmfGroupList;
+	struct list_head saAmfProtectionGroupHead;
+	struct list_head saAmfUnitHead;
+};
+
+/*
+ * State machines for states in AMF
+ */
+enum amfOperationalState {
+	AMF_OPER_DISABLED,
+	AMF_OPER_ENABLED
+};
+
+enum amfAdministrativeState {
+	AMF_ADMIN_UNLOCKED,
+	AMF_ADMIN_LOCKED,
+	AMF_ADMIN_STOPPING
+};
+
+enum amfEnabledUnlockedState {
+	AMF_ENABLED_UNLOCKED_INITIAL = 0,
+	AMF_ENABLED_UNLOCKED_IN_SERVICE_REQUESTED,
+	AMF_ENABLED_UNLOCKED_IN_SERVICE_COMPLETED,
+	AMF_ENABLED_UNLOCKED_ACTIVE_REQUESTED,
+	AMF_ENABLED_UNLOCKED_ACTIVE_COMPLETED,
+	AMF_ENABLED_UNLOCKED_STANDBY_REQUESTED,
+	AMF_ENABLED_UNLOCKED_STANDBY_COMPLETED,
+};
+
+enum amfDisabledUnlockedState {
+	AMF_DISABLED_UNLOCKED_REGISTEREDORERRORCANCEL = 0,
+	AMF_DISABLED_UNLOCKED_FAILED,
+	AMF_DISABLED_UNLOCKED_QUIESCED_REQUESTED,
+	AMF_DISABLED_UNLOCKED_QUIESCED_COMPLETED,
+	AMF_DISABLED_UNLOCKED_OUT_OF_SERVICE_REQUESTED,
+	AMF_DISABLED_UNLOCKED_OUT_OF_SERVICE_COMPLETED
+};
+	
+enum amfDisabledLockedState {
+	AMF_DISABLED_LOCKED_INITIAL = 0,
+	AMF_DISABLED_LOCKED_QUIESCED_REQUESTED,
+	AMF_DISABLED_LOCKED_QUIESCED_COMPLETED,
+	AMF_DISABLED_LOCKED_OUT_OF_SERVICE_REQUESTED,
+	AMF_DISABLED_LOCKED_OUT_OF_SERVICE_COMPLETED
+};
+
+enum amfEnabledStoppingState {
+	AMF_ENABLED_STOPPING_INITIAL = 0,
+	AMF_ENABLED_STOPPING_STOPPING_REQUESTED,
+	AMF_ENABLED_STOPPING_STOPPING_COMPLETED,
+};
+struct saAmfComponent {
+	int registered;
+	int local;
+	int fd;
+	SaNameT name;
+	SaAmfReadinessStateT currentReadinessState;
+	SaAmfReadinessStateT newReadinessState;
+	SaAmfHAStateT currentHAState;
+	SaAmfHAStateT newHAState;
+	enum amfEnabledUnlockedState enabledUnlockedState;
+	enum amfDisabledUnlockedState disabledUnlockedState;
+	SaAmfComponentCapabilityModelT componentCapabilityModel;
+	SaAmfProbableCauseT probableCause;
+	int healthcheckInterval;
+	poll_timer_handle timer_healthcheck;
+	int healthcheck_outstanding;
+	struct saAmfComponent *saAmfProxyComponent;
+	struct list_head saAmfComponentList;
+	struct list_head saAmfProtectionGroupList;
+	struct saAmfUnit *saAmfUnit;
+	struct saAmfProtectionGroup *saAmfProtectionGroup;
+};
+
+extern struct list_head saAmfGroupHead;
+
+extern struct saAmfComponent *findComponent (SaNameT *name);
+
+extern int SaNameTisNameT (SaNameT *name1, SaNameT *name2);
+
+extern int amfReadGroups (char **error_string);
+
+extern int amfReadNetwork (char **error_string, struct sockaddr_in *mcast_addr, struct sockaddr_in *bindnet_addr);
+
+#endif /* PARSE_H_DEFINED */

+ 477 - 0
exec/poll.c

@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <errno.h>
+#include <pthread.h>
+#include <sys/poll.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "poll.h"
+#include "../include/list.h"
+#include "tlist.h"
+
+typedef int (*dispatch_fn_t) (poll_handle poll_handle, int fd, int revents, void *data);
+
+struct poll_instance {
+	struct pollfd *ufds;
+	int nfds;
+	dispatch_fn_t *dispatch_fns;
+	void **data;
+	struct timerlist timerlist;
+	pthread_mutex_t mutex;
+};
+#define POLLINSTANCE_MUTEX_OFFSET offset_of(struct poll_instance, mutex)
+
+struct handle {
+        int valid;
+        void *instance;
+        unsigned int generation;
+};
+
+struct handle_database {
+        unsigned int handle_count;
+        struct handle *handles;
+        unsigned int generation;
+        pthread_mutex_t mutex;
+};
+
+#define offset_of(type,member) (int)(&(((type *)0)->member))
+
+#define HANDLECONVERT_NOLOCKING         0x80000000
+#define HANDLECONVERT_DONTUNLOCKDB      0x40000000
+
+int handle_create (
+		struct handle_database *handle_database,
+		void **instance_out,
+		int instance_size,
+		int *handle_out)
+{
+		int handle;
+		void *new_handles;
+		int found = 0;
+		void *instance;
+
+		pthread_mutex_lock (&handle_database->mutex);
+
+		for (handle = 0; handle < handle_database->handle_count; handle++) {
+			if (handle_database->handles[handle].valid == 0) {
+				found = 1;
+				break;
+			}
+		}
+		if (found == 0) {
+			handle_database->handle_count += 1;
+			new_handles = (struct handle *)realloc (handle_database->handles,
+			sizeof (struct handle) * handle_database->handle_count);
+			if (new_handles == 0) {
+				pthread_mutex_unlock (&handle_database->mutex);
+				errno = ENOMEM;
+				return (-1);
+			}
+			handle_database->handles = new_handles;
+		}
+		instance = (void *)malloc (instance_size);
+		if (instance == 0) {
+			errno = ENOMEM;
+			return (-1);
+		}
+		memset (instance, 0, instance_size);
+
+		handle_database->handles[handle].valid = 1;
+		handle_database->handles[handle].instance = instance;
+		handle_database->handles[handle].generation = handle_database->generation++;
+
+		*handle_out = handle;
+		*instance_out = instance;
+
+		pthread_mutex_unlock (&handle_database->mutex);
+		return (0);
+}
+
+int handle_convert (
+	struct handle_database *handle_database,
+	unsigned int handle,
+	void **instance,
+	int offset_to_mutex,
+	unsigned int *generation_out)
+{
+	int unlock_db;
+	int locking;
+
+	unlock_db = (0 == (offset_to_mutex & HANDLECONVERT_DONTUNLOCKDB));
+	locking = (0 == (offset_to_mutex & HANDLECONVERT_NOLOCKING));
+	offset_to_mutex &= 0x00fffff; /* remove 8 bits of flags */
+
+	if (locking) {
+		pthread_mutex_lock (&handle_database->mutex);
+	}
+
+/* Add this later
+	res = saHandleVerify (handle_database, handle);
+	if (res == -1) {
+		if (locking) {
+			pthread_mutex_unlock (&handle_database->mutex);
+		}
+		errno = ENOENT;
+		return (-1);
+	}
+*/
+
+	*instance = handle_database->handles[handle].instance;
+	if (generation_out) {
+		*generation_out = handle_database->handles[handle].generation;
+	}
+
+	/*
+	 * This function exits holding the mutex in the instance instance
+	 * pointed to by offset_to_mutex (if NOLOCKING isn't set)
+	 */
+	if (locking) {
+		pthread_mutex_lock ((pthread_mutex_t *)(*instance + offset_to_mutex));
+		if (unlock_db) {
+			pthread_mutex_unlock (&handle_database->mutex);
+		}
+	}
+
+	return (0);
+}
+
+
+/*
+ * All instances in one database
+ */
+static struct handle_database poll_instance_database = {
+        handle_count: 0,
+        handles: 0,
+        generation: 0,
+        mutex: PTHREAD_MUTEX_INITIALIZER
+};
+
+poll_handle poll_create (void)
+{
+	poll_handle poll_handle;
+	struct poll_instance *poll_instance;
+	int res;
+
+	res = handle_create (&poll_instance_database, (void *)&poll_instance,
+		sizeof (struct poll_instance), &poll_handle);
+	if (res == -1) {
+		goto error_exit;
+	}
+	poll_instance->ufds = 0;
+	poll_instance->nfds = 0;
+	poll_instance->dispatch_fns = 0;
+	poll_instance->data = 0;
+	timerlist_init (&poll_instance->timerlist);
+
+	return (poll_handle);
+
+error_exit:
+	return (-1);
+}
+
+int poll_destroy (poll_handle poll_handle)
+{
+	struct poll_instance *poll_instance;
+	int res;
+
+	res = handle_convert (&poll_instance_database, poll_handle,
+		(void *)&poll_instance, POLLINSTANCE_MUTEX_OFFSET, 0);
+	if (res == -1) {
+		goto error_exit;
+	}
+
+	if (poll_instance->ufds) {
+		free (poll_instance->ufds);
+	}
+	if (poll_instance->dispatch_fns) {
+		free (poll_instance->dispatch_fns);
+	}
+	if (poll_instance->data) {
+		free (poll_instance->data);
+	}
+	timerlist_free (&poll_instance->timerlist);
+// TODO destroy poll
+
+	return (0);
+
+error_exit:
+	return (-1);
+}
+
+int poll_dispatch_add (
+	poll_handle handle,
+	int fd,
+	int events,
+	void *data,
+	int (*dispatch_fn) (poll_handle poll_handle, int fd, int revents, void *data))
+{
+	struct poll_instance *poll_instance;
+	struct pollfd *ufds;
+	dispatch_fn_t *dispatch_fns;
+	void **data_list;
+	int res;
+	int found = 0;
+	int install_pos;
+
+	res = handle_convert (&poll_instance_database, handle,
+		(void *)&poll_instance, POLLINSTANCE_MUTEX_OFFSET, 0);
+
+	if (res == -1) {
+		goto error_exit;
+	}
+
+	for (found = 0, install_pos = 0; install_pos < poll_instance->nfds; install_pos++) {
+		if (poll_instance->ufds[install_pos].fd == -1) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found == 0) {
+		/*
+		 * Grow pollfd list
+		 */
+		ufds = (struct pollfd *)realloc (poll_instance->ufds,
+			(poll_instance->nfds + 1) * sizeof (struct pollfd));
+		if (ufds == 0) {
+			errno = ENOMEM;
+			goto error_exit;
+		}
+		poll_instance->ufds = ufds;
+	
+		/*
+		 * Grow dispatch functions list
+		 */
+			dispatch_fns = (dispatch_fn_t *)realloc (poll_instance->dispatch_fns,
+			(poll_instance->nfds + 1) * sizeof (dispatch_fn_t));
+		if (dispatch_fns == 0) {
+			errno = ENOMEM;
+			goto error_exit;
+		}
+		poll_instance->dispatch_fns = dispatch_fns;
+	
+		/*
+		 * Grow data list
+		 */
+		data_list = (void **)realloc (poll_instance->data,
+			(poll_instance->nfds + 1) * sizeof (void *));
+		if (data_list == 0) {
+			errno = ENOMEM;
+			goto error_exit;
+		}
+		poll_instance->data = data_list;
+	
+		poll_instance->nfds += 1;
+		install_pos = poll_instance->nfds - 1;
+	}
+	
+	/*
+	 * Install new dispatch handler
+	 */
+	poll_instance->ufds[install_pos].fd = fd;
+	poll_instance->ufds[install_pos].events = events;
+	poll_instance->ufds[install_pos].revents = 0;
+	poll_instance->dispatch_fns[install_pos] = dispatch_fn;
+	poll_instance->data[install_pos] = data;
+
+	return (0);
+
+error_exit:
+	return (-1);
+}
+
+int poll_dispatch_modify (
+	poll_handle handle,
+	int fd,
+	int events,
+	int (*dispatch_fn) (poll_handle poll_handle, int fd, int revents, void *data))
+{
+	struct poll_instance *poll_instance;
+	int i;
+	int res;
+
+	res = handle_convert (&poll_instance_database, handle,
+		(void *)&poll_instance, POLLINSTANCE_MUTEX_OFFSET, 0);
+	if (res == -1) {
+		return (-1);
+	}
+
+	/*
+	 * Find file descriptor to modify events and dispatch function
+	 */
+	for (i = 0; i < poll_instance->nfds; i++) {
+		if (poll_instance->ufds[i].fd == fd) {
+			poll_instance->ufds[i].events = events;
+			poll_instance->dispatch_fns[i] = dispatch_fn;
+			return (0);
+		}
+	}
+
+	errno = EBADF;
+	return (-1);
+}
+
+int poll_dispatch_delete (
+	poll_handle handle,
+	int fd)
+{
+	struct poll_instance *poll_instance;
+	int i;
+	int res;
+	int found = 0;
+
+	res = handle_convert (&poll_instance_database, handle,
+		(void *)&poll_instance, POLLINSTANCE_MUTEX_OFFSET, 0);
+	if (res == -1) {
+		goto error_exit;
+	}
+
+	/*
+	 * Find dispatch fd to delete
+	 */
+	for (i = 0; i < poll_instance->nfds; i++) {
+		if (poll_instance->ufds[i].fd == fd) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found) {
+		poll_instance->ufds[i].fd = -1;
+		return (0);
+	}
+
+error_exit:
+	errno = EBADF;
+	return (-1);
+}
+
+int poll_timer_add (
+	poll_handle handle,
+	int msec_in_future, void *data,
+	void (*timer_fn) (void *data),
+	poll_timer_handle *timer_handle_out)
+{
+	struct poll_instance *poll_instance;
+	poll_timer_handle timer_handle;
+	int res;
+
+	res = handle_convert (&poll_instance_database, handle,
+		(void *)&poll_instance, POLLINSTANCE_MUTEX_OFFSET, 0);
+	if (res == -1) {
+		return (-1);
+	}
+
+	timer_handle = (poll_timer_handle)timerlist_add_future (&poll_instance->timerlist,
+		timer_fn, data, msec_in_future);
+
+	if (timer_handle != 0) {
+		*timer_handle_out = timer_handle;
+		return (0);
+	}
+	return (-1);
+}
+
+int poll_timer_delete (
+	poll_handle handle,
+	poll_timer_handle timer_handle)
+{
+	struct poll_instance *poll_instance;
+	int res;
+
+	if (timer_handle == 0) {
+		return (0);
+	}
+	res = handle_convert (&poll_instance_database, handle,
+		(void *)&poll_instance, POLLINSTANCE_MUTEX_OFFSET, 0);
+	if (res == -1) {
+		return (-1);
+	}
+
+	timerlist_del (&poll_instance->timerlist, (void *)timer_handle);
+	return (0);
+}
+
+int poll_run (
+	poll_handle handle)
+{
+	struct poll_instance *poll_instance;
+	int i;
+	int timeout = -1;
+	int res;
+
+	res = handle_convert (&poll_instance_database, handle,
+		(void *)&poll_instance, POLLINSTANCE_MUTEX_OFFSET, 0);
+	if (res == -1) {
+		goto error_exit;
+	}
+
+	for (;;) {
+		timeout = timerlist_timeout_msec (&poll_instance->timerlist);
+
+retry_poll:
+		res = poll (poll_instance->ufds, poll_instance->nfds, timeout);
+		if (errno == EINTR && res == -1) {
+			goto retry_poll;
+		} else
+		if (res == -1) {
+			goto error_exit;
+		}
+
+
+		for (i = 0; i < poll_instance->nfds; i++) {
+			if (poll_instance->ufds[i].fd != -1 &&
+				poll_instance->ufds[i].revents) {
+
+				res = poll_instance->dispatch_fns[i] (handle, poll_instance->ufds[i].fd, 
+					poll_instance->ufds[i].revents, poll_instance->data[i]);
+
+				/*
+				 * Remove dispatch functions that return -1
+				 */
+				if (res == -1) {
+					poll_instance->ufds[i].fd = -1; /* empty entry */
+				}
+			}
+		}
+		timerlist_expire (&poll_instance->timerlist);
+	} /* for (;;) */
+
+error_exit:
+	return (-1);
+}
+
+int poll_stop (
+	poll_handle handle);

+ 78 - 0
exec/poll.h

@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef POLL_H_DEFINED
+#define POLL_H_DEFINED
+
+typedef int poll_timer_handle;
+typedef int poll_handle;
+
+poll_handle poll_create (void);
+
+int poll_destroy (poll_handle poll_handle);
+
+int poll_dispatch_add (
+	poll_handle handle,
+	int fd,
+	int events,
+	void *data,
+	int (*dispatch_fn) (poll_handle handle, int fd, int revents, void *data));
+
+int poll_dispatch_modify (
+	poll_handle handle,
+	int fd,
+	int events,
+    int (*dispatch_fn) (poll_handle poll_handle, int fd, int revents, void *data));
+
+
+int poll_dispatch_delete (
+	poll_handle handle,
+	int fd);
+
+int poll_timer_add (
+	poll_handle handle,
+	int msec_in_future, void *data,
+	void (*timer_fn) (void *data),
+	poll_timer_handle *timer_handle_out);
+
+int poll_timer_delete (
+	poll_handle handle,
+	poll_timer_handle timer_handle);
+
+int poll_run (
+	poll_handle handle);
+
+int poll_stop (
+	poll_handle handle);
+
+#endif	/* POLL_H_DEFINED */

+ 171 - 0
exec/print.c

@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "print.h"
+#include "parse.h"
+#include "../include/ais_types.h"
+
+/*
+ * logging printf
+ */
+void
+internal_log_printf (int level, char *string, ...)
+{
+	va_list ap;
+	char newstring[1024];
+
+	va_start(ap, string);
+	
+	sprintf (newstring, "L(%x): %s", level, string);
+	vfprintf(stderr, newstring, ap);
+
+	va_end(ap);
+}
+
+extern char *getSaClmNodeAddressT (SaClmNodeAddressT *nodeAddress) {
+	int i;
+	static char node_address[300];
+	int pos;
+
+	for (i = 0, pos = 0; i < nodeAddress->length; i++) {
+		pos += sprintf (&node_address[pos], "%d.", nodeAddress->value[i]);
+	}
+	return (node_address);
+}
+
+void printSaClmClusterNodeT (char *description, SaClmClusterNodeT *clusterNode) {
+	log_printf (LOG_LEVEL_NOTICE, "Node Information for %s:\n", description);
+
+	log_printf (LOG_LEVEL_NOTICE, "\tnode id is %x\n", (int)clusterNode->nodeId);
+
+	log_printf (LOG_LEVEL_NOTICE, "\tnode address is %s\n", getSaClmNodeAddressT (&clusterNode->nodeAddress));
+
+	log_printf (LOG_LEVEL_NOTICE, "\tnode name is %s.\n", getSaNameT (&clusterNode->nodeName));
+
+	log_printf (LOG_LEVEL_NOTICE, "\tcluster name is %s.\n", getSaNameT (&clusterNode->clusterName));
+
+	log_printf (LOG_LEVEL_NOTICE, "\tMember is %d\n", clusterNode->member);
+
+	log_printf (LOG_LEVEL_NOTICE, "\tTimestamp is %llx nanoseconds\n", clusterNode->bootTimestamp);
+}
+
+char *getSaNameT (SaNameT *name)
+{
+	static char ret_name[300];
+
+	memset (ret_name, 0, sizeof (ret_name));
+	if (name->length > 299) {
+		memcpy (ret_name, name->value, 299);
+	} else {
+
+		memcpy (ret_name, name->value, name->length);
+	}
+	return (ret_name);
+}
+
+void saAmfPrintGroups (void)
+{
+	struct list_head *AmfGroupList;
+	struct list_head *AmfUnitList;
+	struct list_head *AmfComponentList;
+	struct list_head *AmfProtectionGroupList;
+	struct saAmfGroup *saAmfGroup;
+	struct saAmfUnit *AmfUnit;
+	struct saAmfComponent *AmfComponent;
+	struct saAmfProtectionGroup *AmfProtectionGroup;
+
+	for (AmfGroupList = saAmfGroupHead.next;
+		AmfGroupList != &saAmfGroupHead;
+		AmfGroupList = AmfGroupList->next) {
+
+		saAmfGroup = list_entry (AmfGroupList, 
+			struct saAmfGroup, saAmfGroupList);
+
+		log_printf (LOG_LEVEL_DEBUG, "group {\n");
+		log_printf (LOG_LEVEL_DEBUG, "\tname = ", getSaNameT (&saAmfGroup->name));
+		log_printf (LOG_LEVEL_DEBUG, "\tmodel = %d\n", saAmfGroup->model);
+		log_printf (LOG_LEVEL_DEBUG, "\tactive-units = %d\n", (int)saAmfGroup->saAmfActiveUnitsDesired);
+		log_printf (LOG_LEVEL_DEBUG, "\tbackup-units = %d\n", (int)saAmfGroup->saAmfStandbyUnitsDesired);
+
+		for (AmfUnitList = saAmfGroup->saAmfUnitHead.next;
+			AmfUnitList != &saAmfGroup->saAmfUnitHead;
+			AmfUnitList = AmfUnitList->next) {
+
+			AmfUnit = list_entry (AmfUnitList, 
+				struct saAmfUnit, saAmfUnitList);
+
+			log_printf (LOG_LEVEL_DEBUG, "\tunit {\n");
+			log_printf (LOG_LEVEL_DEBUG, "\t\tname = ", getSaNameT (&AmfUnit->name));
+
+			for (AmfComponentList = AmfUnit->saAmfComponentHead.next;
+				AmfComponentList != &AmfUnit->saAmfComponentHead;
+				AmfComponentList = AmfComponentList->next) {
+
+				AmfComponent = list_entry (AmfComponentList, 
+					struct saAmfComponent, saAmfComponentList);
+				log_printf (LOG_LEVEL_DEBUG, "\t\tcomponent {\n");
+				log_printf (LOG_LEVEL_DEBUG, "\t\t\tname = ", getSaNameT (&AmfComponent->name));
+				log_printf (LOG_LEVEL_DEBUG, "\t\t\tmodel = %d\n", AmfComponent->componentCapabilityModel);
+				log_printf (LOG_LEVEL_DEBUG, "\t\t}\n");
+			}
+			log_printf (LOG_LEVEL_DEBUG, "\t}\n");
+		}
+
+		for (AmfProtectionGroupList = saAmfGroup->saAmfProtectionGroupHead.next;
+			AmfProtectionGroupList != &saAmfGroup->saAmfProtectionGroupHead;
+			AmfProtectionGroupList = AmfProtectionGroupList->next) {
+
+			AmfProtectionGroup = list_entry (AmfProtectionGroupList, 
+				struct saAmfProtectionGroup, saAmfProtectionGroupList);
+
+			log_printf (LOG_LEVEL_DEBUG, "\tprotection {\n");
+			log_printf (LOG_LEVEL_DEBUG, "\t\tname = ", getSaNameT (&AmfProtectionGroup->name));
+
+			for (AmfComponentList = AmfProtectionGroup->saAmfMembersHead.next;
+				AmfComponentList != &AmfProtectionGroup->saAmfMembersHead;
+				AmfComponentList = AmfComponentList->next) {
+
+				AmfComponent = list_entry (AmfComponentList, 
+					struct saAmfComponent, saAmfProtectionGroupList);
+
+				log_printf (LOG_LEVEL_DEBUG, "\t\tmember = ", getSaNameT (&AmfComponent->name));
+			}
+			log_printf (LOG_LEVEL_DEBUG, "\t}\n");
+		}
+		log_printf (LOG_LEVEL_DEBUG, "}\n");
+	}
+}

+ 65 - 0
exec/print.h

@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef PRINT_H_DEFINED
+#define PRINT_H_DEFINED
+
+#include "../include/ais_types.h"
+
+
+#define LOG_LEVEL_SECURITY	1
+#define LOG_LEVEL_ERROR		2
+#define LOG_LEVEL_WARNING	3
+#define LOG_LEVEL_NOTICE	4
+#define LOG_LEVEL_DEBUG		5
+
+extern void internal_log_printf (int level, char *string, ...);
+
+/*
+ * The optimizer will remove DEBUG logging messages in production builds
+ */
+#ifdef DEBUG
+#define log_printf(level,format,args...) { internal_log_printf (level,format,##args); }
+#else
+#define log_printf(level,format,args...) { if (level != LOG_LEVEL_DEBUG) internal_log_printf (level,format,##args); }
+#endif
+
+extern char *getSaNameT (SaNameT *name);
+
+extern char *getSaClmNodeAddressT (SaClmNodeAddressT *nodeAddress);
+
+extern void printSaClmClusterNodeT (char *description, SaClmClusterNodeT *clusterNode);
+
+extern void saAmfPrintGroups (void);
+
+#endif /* PRINT_H_DEFINED */

+ 560 - 0
exec/profile

@@ -0,0 +1,560 @@
+Flat profile:
+
+Each sample counts as 0.01 seconds.
+  %   cumulative   self              self     total           
+ time   seconds   seconds    calls  ms/call  ms/call  name    
+ 21.95      0.09     0.09   274959     0.00     0.00  message_handler_mcast
+ 19.51      0.17     0.08   274977     0.00     0.00  pending_queues_deliver
+  9.76      0.21     0.04     1655     0.02     0.05  user_deliver
+  9.76      0.25     0.04        1    40.00   409.61  poll_run
+  7.32      0.28     0.03   322067     0.00     0.00  timerlist_expire
+  7.32      0.31     0.03     1623     0.02     0.03  deliver_fn
+  4.88      0.33     0.02   322068     0.00     0.00  timerlist_timeout_msec
+  4.88      0.35     0.02   322046     0.00     0.00  recv_handler
+  2.44      0.36     0.01    47021     0.00     0.00  timerlist_add_future
+  2.44      0.37     0.01    46913     0.00     0.00  message_handler_orf_token
+  2.44      0.38     0.01    46913     0.00     0.00  orf_token_mcast
+  2.44      0.39     0.01    46878     0.00     0.00  messages_free
+  2.44      0.40     0.01     1632     0.01     0.01  SaNameTisNameT
+  2.44      0.41     0.01     1527     0.01     0.01  message_handler_req_exec_ckpt_sectionwrite
+  0.00      0.41     0.00    47304     0.00     0.00  poll_timer_delete
+  0.00      0.41     0.00    47021     0.00     0.00  poll_timer_add
+  0.00      0.41     0.00    47021     0.00     0.00  timerlist_add
+  0.00      0.41     0.00    47019     0.00     0.00  timerlist_del
+  0.00      0.41     0.00    46913     0.00     0.00  orf_token_evs
+  0.00      0.41     0.00    46913     0.00     0.00  orf_token_rtr
+  0.00      0.41     0.00    46878     0.00     0.00  sq_items_release
+  0.00      0.41     0.00     1655     0.00     0.00  pend_delv_next_delivery_find
+  0.00      0.41     0.00     1623     0.00     0.00  queue_reinit
+  0.00      0.41     0.00      726     0.00     0.00  internal_log_printf
+  0.00      0.41     0.00      125     0.00     0.00  mempool_free
+  0.00      0.41     0.00      125     0.00     0.00  mempool_strdup
+  0.00      0.41     0.00      125     0.00     0.00  strstr_rs
+  0.00      0.41     0.00       71     0.00     0.00  ckptConfChg
+  0.00      0.41     0.00       71     0.00     0.00  clmConfChg
+  0.00      0.41     0.00       71     0.00     0.00  confchg_fn
+  0.00      0.41     0.00       71     0.00     0.00  libraryNotificationLeave
+  0.00      0.41     0.00       70     0.00     0.00  message_handler_memb_form_token
+  0.00      0.41     0.00       53     0.00     0.00  message_handler_req_exec_clm_nodejoin
+  0.00      0.41     0.00       52     0.00     0.00  message_handler_memb_attempt_join
+  0.00      0.41     0.00       52     0.00     0.00  message_handler_memb_join
+  0.00      0.41     0.00       41     0.00     0.01  message_handler_req_exec_ckpt_checkpointopen
+  0.00      0.41     0.00       36     0.00     0.00  SaNameTisEqual
+  0.00      0.41     0.00       35     0.00     0.00  memb_form_token_conf_desc_build
+  0.00      0.41     0.00       35     0.00     0.00  queues_pend_delv_memb_new
+  0.00      0.41     0.00       35     0.00     0.00  sq_reinit
+  0.00      0.41     0.00       20     0.00     0.00  queue_init
+  0.00      0.41     0.00       19     0.00     0.00  memb_state_commit_enter
+  0.00      0.41     0.00       19     0.00     0.00  memb_state_gather_enter
+  0.00      0.41     0.00       18     0.00     0.02  findComponent
+  0.00      0.41     0.00       18     0.00     0.00  gmi_mcast
+  0.00      0.41     0.00       18     0.00     0.00  gmi_pend_trans_item_store
+  0.00      0.41     0.00       18     0.00     0.00  libraryNotificationJoin
+  0.00      0.41     0.00       18     0.00     0.00  memb_print_commit_set
+  0.00      0.41     0.00       18     0.00     0.00  memb_state_commit_consensus
+  0.00      0.41     0.00       15     0.00     0.00  orf_timer_function_token_timeout
+  0.00      0.41     0.00       12     0.00     0.00  mempool_malloc
+  0.00      0.41     0.00        5     0.00     0.00  memb_timer_function_state_gather
+  0.00      0.41     0.00        2     0.00     0.01  message_handler_req_exec_ckpt_sectioncreate
+  0.00      0.41     0.00        2     0.00     0.00  poll_dispatch_add
+  0.00      0.41     0.00        1     0.00     0.00  aisexec_libais_bind
+  0.00      0.41     0.00        1     0.00     0.00  amfExecutiveInitialize
+  0.00      0.41     0.00        1     0.00     0.39  amfReadGroups
+  0.00      0.41     0.00        1     0.00     0.00  clmExecutiveInitialize
+  0.00      0.41     0.00        1     0.00     0.00  determine_local_if
+  0.00      0.41     0.00        1     0.00     0.00  gmi_init
+  0.00      0.41     0.00        1     0.00     0.00  gmi_join
+  0.00      0.41     0.00        1     0.00     0.00  grow_connections_table
+  0.00      0.41     0.00        1     0.00     0.00  handle_create
+  0.00      0.41     0.00        1     0.00     0.00  memb_conf_id_build
+  0.00      0.41     0.00        1     0.00     0.00  memb_timer_function_state_commit_timeout
+  0.00      0.41     0.00        1     0.00     0.00  mempool_init
+  0.00      0.41     0.00        1     0.00     0.00  mempool_realloc
+  0.00      0.41     0.00        1     0.00     0.00  poll_create
+  0.00      0.41     0.00        1     0.00     0.00  sq_init
+  0.00      0.41     0.00        1     0.00     0.00  this_ip_set
+  0.00      0.41     0.00        1     0.00     0.00  timerlist_init
+
+ %         the percentage of the total running time of the
+time       program used by this function.
+
+cumulative a running sum of the number of seconds accounted
+ seconds   for by this function and those listed above it.
+
+ self      the number of seconds accounted for by this
+seconds    function alone.  This is the major sort for this
+           listing.
+
+calls      the number of times this function was invoked, if
+           this function is profiled, else blank.
+ 
+ self      the average number of milliseconds spent in this
+ms/call    function per call, if this function is profiled,
+	   else blank.
+
+ total     the average number of milliseconds spent in this
+ms/call    function and its descendents per call, if this 
+	   function is profiled, else blank.
+
+name       the name of the function.  This is the minor sort
+           for this listing. The index shows the location of
+	   the function in the gprof listing. If the index is
+	   in parenthesis it shows where it would appear in
+	   the gprof listing if it were to be printed.
+
+		     Call graph (explanation follows)
+
+
+granularity: each sample hit covers 4 byte(s) for 2.44% of 0.41 seconds
+
+index % time    self  children    called     name
+                                                 <spontaneous>
+[1]    100.0    0.00    0.41                 main [1]
+                0.04    0.37       1/1           poll_run [2]
+                0.00    0.00       1/1           amfReadGroups [18]
+                0.00    0.00       1/1           gmi_init [27]
+                0.00    0.00       2/726         internal_log_printf [36]
+                0.00    0.00       1/1           poll_create [69]
+                0.00    0.00       1/1           mempool_init [67]
+                0.00    0.00       1/1           aisexec_libais_bind [58]
+                0.00    0.00       1/1           grow_connections_table [63]
+                0.00    0.00       1/2           poll_dispatch_add [57]
+                0.00    0.00       1/1           gmi_join [62]
+                0.00    0.00       1/1           amfExecutiveInitialize [59]
+                0.00    0.00       1/1           clmExecutiveInitialize [60]
+-----------------------------------------------
+                0.04    0.37       1/1           main [1]
+[2]     99.9    0.04    0.37       1         poll_run [2]
+                0.02    0.30  322046/322046      recv_handler [3]
+                0.03    0.00  322067/322067      timerlist_expire [9]
+                0.02    0.00  322068/322068      timerlist_timeout_msec [10]
+-----------------------------------------------
+                0.02    0.30  322046/322046      poll_run [2]
+[3]     78.0    0.02    0.30  322046         recv_handler [3]
+                0.09    0.17  274959/274959      message_handler_mcast [4]
+                0.01    0.03   46913/46913       message_handler_orf_token [8]
+                0.00    0.00      70/70          message_handler_memb_form_token [20]
+                0.00    0.00      52/52          message_handler_memb_join [24]
+                0.00    0.00      52/52          message_handler_memb_attempt_join [26]
+-----------------------------------------------
+                0.09    0.17  274959/274959      recv_handler [3]
+[4]     63.3    0.09    0.17  274959         message_handler_mcast [4]
+                0.08    0.09  274959/274977      pending_queues_deliver [5]
+-----------------------------------------------
+                0.00    0.00      18/274977      orf_token_mcast [12]
+                0.08    0.09  274959/274977      message_handler_mcast [4]
+[5]     41.4    0.08    0.09  274977         pending_queues_deliver [5]
+                0.04    0.05    1655/1655        user_deliver [6]
+-----------------------------------------------
+                0.04    0.05    1655/1655        pending_queues_deliver [5]
+[6]     21.9    0.04    0.05    1655         user_deliver [6]
+                0.03    0.02    1623/1623        deliver_fn [7]
+                0.00    0.00    1655/1655        pend_delv_next_delivery_find [34]
+                0.00    0.00    1623/1623        queue_reinit [35]
+-----------------------------------------------
+                0.03    0.02    1623/1623        user_deliver [6]
+[7]     12.1    0.03    0.02    1623         deliver_fn [7]
+                0.01    0.01    1527/1527        message_handler_req_exec_ckpt_sectionwrite [11]
+                0.00    0.00      41/41          message_handler_req_exec_ckpt_checkpointopen [19]
+                0.00    0.00       2/2           message_handler_req_exec_ckpt_sectioncreate [21]
+                0.00    0.00      53/53          message_handler_req_exec_clm_nodejoin [44]
+-----------------------------------------------
+                0.01    0.03   46913/46913       recv_handler [3]
+[8]      9.8    0.01    0.03   46913         message_handler_orf_token [8]
+                0.01    0.00   46913/46913       orf_token_mcast [12]
+                0.01    0.00   46878/46878       messages_free [15]
+                0.00    0.01   46913/47021       poll_timer_add [13]
+                0.00    0.00   46913/46913       orf_token_rtr [32]
+                0.00    0.00   46913/46913       orf_token_evs [31]
+                0.00    0.00   46913/47304       poll_timer_delete [28]
+-----------------------------------------------
+                0.03    0.00  322067/322067      poll_run [2]
+[9]      7.3    0.03    0.00  322067         timerlist_expire [9]
+                0.00    0.00      15/19          memb_state_gather_enter [23]
+                0.00    0.00       5/5           memb_timer_function_state_gather [25]
+                0.00    0.00      15/15          orf_timer_function_token_timeout [55]
+                0.00    0.00       1/1           memb_timer_function_state_commit_timeout [66]
+-----------------------------------------------
+                0.02    0.00  322068/322068      poll_run [2]
+[10]     4.9    0.02    0.00  322068         timerlist_timeout_msec [10]
+-----------------------------------------------
+                0.01    0.01    1527/1527        deliver_fn [7]
+[11]     4.7    0.01    0.01    1527         message_handler_req_exec_ckpt_sectionwrite [11]
+                0.01    0.00    1527/1632        SaNameTisNameT [16]
+-----------------------------------------------
+                0.01    0.00   46913/46913       message_handler_orf_token [8]
+[12]     2.4    0.01    0.00   46913         orf_token_mcast [12]
+                0.00    0.00      18/274977      pending_queues_deliver [5]
+-----------------------------------------------
+                0.00    0.00      19/47021       memb_state_commit_enter [22]
+                0.00    0.00      19/47021       memb_state_gather_enter [23]
+                0.00    0.00      70/47021       message_handler_memb_form_token [20]
+                0.00    0.01   46913/47021       message_handler_orf_token [8]
+[13]     2.4    0.00    0.01   47021         poll_timer_add [13]
+                0.01    0.00   47021/47021       timerlist_add_future [14]
+-----------------------------------------------
+                0.01    0.00   47021/47021       poll_timer_add [13]
+[14]     2.4    0.01    0.00   47021         timerlist_add_future [14]
+                0.00    0.00   47021/47021       timerlist_add [29]
+-----------------------------------------------
+                0.01    0.00   46878/46878       message_handler_orf_token [8]
+[15]     2.4    0.01    0.00   46878         messages_free [15]
+                0.00    0.00   46878/46878       sq_items_release [33]
+-----------------------------------------------
+                0.00    0.00       2/1632        message_handler_req_exec_ckpt_sectioncreate [21]
+                0.00    0.00      40/1632        message_handler_req_exec_ckpt_checkpointopen [19]
+                0.00    0.00      63/1632        findComponent [17]
+                0.01    0.00    1527/1632        message_handler_req_exec_ckpt_sectionwrite [11]
+[16]     2.4    0.01    0.00    1632         SaNameTisNameT [16]
+-----------------------------------------------
+                0.00    0.00      18/18          amfReadGroups [18]
+[17]     0.1    0.00    0.00      18         findComponent [17]
+                0.00    0.00      63/1632        SaNameTisNameT [16]
+-----------------------------------------------
+                0.00    0.00       1/1           main [1]
+[18]     0.1    0.00    0.00       1         amfReadGroups [18]
+                0.00    0.00      18/18          findComponent [17]
+                0.00    0.00     125/125         strstr_rs [39]
+                0.00    0.00      36/36          SaNameTisEqual [45]
+                0.00    0.00      12/12          mempool_malloc [56]
+-----------------------------------------------
+                0.00    0.00      41/41          deliver_fn [7]
+[19]     0.1    0.00    0.00      41         message_handler_req_exec_ckpt_checkpointopen [19]
+                0.00    0.00      40/1632        SaNameTisNameT [16]
+-----------------------------------------------
+                0.00    0.00      70/70          recv_handler [3]
+[20]     0.0    0.00    0.00      70         message_handler_memb_form_token [20]
+                0.00    0.00      70/47021       poll_timer_add [13]
+                0.00    0.00     280/47304       poll_timer_delete [28]
+                0.00    0.00      35/35          memb_form_token_conf_desc_build [46]
+-----------------------------------------------
+                0.00    0.00       2/2           deliver_fn [7]
+[21]     0.0    0.00    0.00       2         message_handler_req_exec_ckpt_sectioncreate [21]
+                0.00    0.00       2/1632        SaNameTisNameT [16]
+-----------------------------------------------
+                0.00    0.00       5/19          memb_timer_function_state_gather [25]
+                0.00    0.00      14/19          message_handler_memb_join [24]
+[22]     0.0    0.00    0.00      19         memb_state_commit_enter [22]
+                0.00    0.00      19/47021       poll_timer_add [13]
+                0.00    0.00      19/47304       poll_timer_delete [28]
+-----------------------------------------------
+                0.00    0.00       1/19          gmi_init [27]
+                0.00    0.00       3/19          message_handler_memb_attempt_join [26]
+                0.00    0.00      15/19          timerlist_expire [9]
+[23]     0.0    0.00    0.00      19         memb_state_gather_enter [23]
+                0.00    0.00      19/47021       poll_timer_add [13]
+                0.00    0.00      38/726         internal_log_printf [36]
+                0.00    0.00      19/47304       poll_timer_delete [28]
+-----------------------------------------------
+                0.00    0.00      52/52          recv_handler [3]
+[24]     0.0    0.00    0.00      52         message_handler_memb_join [24]
+                0.00    0.00      14/19          memb_state_commit_enter [22]
+                0.00    0.00      18/18          memb_print_commit_set [53]
+                0.00    0.00      18/18          memb_state_commit_consensus [54]
+                0.00    0.00      18/726         internal_log_printf [36]
+-----------------------------------------------
+                0.00    0.00       5/5           timerlist_expire [9]
+[25]     0.0    0.00    0.00       5         memb_timer_function_state_gather [25]
+                0.00    0.00       5/19          memb_state_commit_enter [22]
+-----------------------------------------------
+                0.00    0.00      52/52          recv_handler [3]
+[26]     0.0    0.00    0.00      52         message_handler_memb_attempt_join [26]
+                0.00    0.00       3/19          memb_state_gather_enter [23]
+                0.00    0.00      86/726         internal_log_printf [36]
+                0.00    0.00       3/47304       poll_timer_delete [28]
+-----------------------------------------------
+                0.00    0.00       1/1           main [1]
+[27]     0.0    0.00    0.00       1         gmi_init [27]
+                0.00    0.00       1/19          memb_state_gather_enter [23]
+                0.00    0.00       1/20          queue_init [49]
+                0.00    0.00       1/1           sq_init [70]
+                0.00    0.00       1/1           determine_local_if [61]
+                0.00    0.00       1/1           memb_conf_id_build [65]
+                0.00    0.00       1/2           poll_dispatch_add [57]
+-----------------------------------------------
+                0.00    0.00       3/47304       message_handler_memb_attempt_join [26]
+                0.00    0.00      19/47304       memb_state_commit_enter [22]
+                0.00    0.00      19/47304       memb_state_gather_enter [23]
+                0.00    0.00      70/47304       orf_token_evs [31]
+                0.00    0.00     280/47304       message_handler_memb_form_token [20]
+                0.00    0.00   46913/47304       message_handler_orf_token [8]
+[28]     0.0    0.00    0.00   47304         poll_timer_delete [28]
+                0.00    0.00   47019/47019       timerlist_del [30]
+-----------------------------------------------
+                0.00    0.00   47021/47021       timerlist_add_future [14]
+[29]     0.0    0.00    0.00   47021         timerlist_add [29]
+-----------------------------------------------
+                0.00    0.00   47019/47019       poll_timer_delete [28]
+[30]     0.0    0.00    0.00   47019         timerlist_del [30]
+-----------------------------------------------
+                0.00    0.00   46913/46913       message_handler_orf_token [8]
+[31]     0.0    0.00    0.00   46913         orf_token_evs [31]
+                0.00    0.00      70/47304       poll_timer_delete [28]
+                0.00    0.00      70/71          confchg_fn [42]
+                0.00    0.00      35/726         internal_log_printf [36]
+                0.00    0.00      35/35          sq_reinit [48]
+                0.00    0.00      35/35          queues_pend_delv_memb_new [47]
+-----------------------------------------------
+                0.00    0.00   46913/46913       message_handler_orf_token [8]
+[32]     0.0    0.00    0.00   46913         orf_token_rtr [32]
+-----------------------------------------------
+                0.00    0.00   46878/46878       messages_free [15]
+[33]     0.0    0.00    0.00   46878         sq_items_release [33]
+-----------------------------------------------
+                0.00    0.00    1655/1655        user_deliver [6]
+[34]     0.0    0.00    0.00    1655         pend_delv_next_delivery_find [34]
+-----------------------------------------------
+                0.00    0.00    1623/1623        user_deliver [6]
+[35]     0.0    0.00    0.00    1623         queue_reinit [35]
+-----------------------------------------------
+                0.00    0.00       1/726         sigintr_handler [175]
+                0.00    0.00       1/726         memb_timer_function_state_commit_timeout [66]
+                0.00    0.00       2/726         main [1]
+                0.00    0.00      15/726         orf_timer_function_token_timeout [55]
+                0.00    0.00      18/726         message_handler_memb_join [24]
+                0.00    0.00      35/726         orf_token_evs [31]
+                0.00    0.00      38/726         memb_state_gather_enter [23]
+                0.00    0.00      53/726         message_handler_req_exec_clm_nodejoin [44]
+                0.00    0.00      86/726         message_handler_memb_attempt_join [26]
+                0.00    0.00     477/726         clmConfChg [41]
+[36]     0.0    0.00    0.00     726         internal_log_printf [36]
+-----------------------------------------------
+                0.00    0.00     125/125         strstr_rs [39]
+[37]     0.0    0.00    0.00     125         mempool_free [37]
+-----------------------------------------------
+                0.00    0.00     125/125         strstr_rs [39]
+[38]     0.0    0.00    0.00     125         mempool_strdup [38]
+-----------------------------------------------
+                0.00    0.00     125/125         amfReadGroups [18]
+[39]     0.0    0.00    0.00     125         strstr_rs [39]
+                0.00    0.00     125/125         mempool_strdup [38]
+                0.00    0.00     125/125         mempool_free [37]
+-----------------------------------------------
+                0.00    0.00      71/71          confchg_fn [42]
+[40]     0.0    0.00    0.00      71         ckptConfChg [40]
+-----------------------------------------------
+                0.00    0.00      71/71          confchg_fn [42]
+[41]     0.0    0.00    0.00      71         clmConfChg [41]
+                0.00    0.00     477/726         internal_log_printf [36]
+                0.00    0.00      71/71          libraryNotificationLeave [43]
+                0.00    0.00      18/18          gmi_mcast [50]
+-----------------------------------------------
+                0.00    0.00       1/71          memb_timer_function_state_commit_timeout [66]
+                0.00    0.00      70/71          orf_token_evs [31]
+[42]     0.0    0.00    0.00      71         confchg_fn [42]
+                0.00    0.00      71/71          ckptConfChg [40]
+                0.00    0.00      71/71          clmConfChg [41]
+-----------------------------------------------
+                0.00    0.00      71/71          clmConfChg [41]
+[43]     0.0    0.00    0.00      71         libraryNotificationLeave [43]
+-----------------------------------------------
+                0.00    0.00      53/53          deliver_fn [7]
+[44]     0.0    0.00    0.00      53         message_handler_req_exec_clm_nodejoin [44]
+                0.00    0.00      53/726         internal_log_printf [36]
+                0.00    0.00      18/18          libraryNotificationJoin [52]
+-----------------------------------------------
+                0.00    0.00      36/36          amfReadGroups [18]
+[45]     0.0    0.00    0.00      36         SaNameTisEqual [45]
+-----------------------------------------------
+                0.00    0.00      35/35          message_handler_memb_form_token [20]
+[46]     0.0    0.00    0.00      35         memb_form_token_conf_desc_build [46]
+-----------------------------------------------
+                0.00    0.00      35/35          orf_token_evs [31]
+[47]     0.0    0.00    0.00      35         queues_pend_delv_memb_new [47]
+                0.00    0.00      19/20          queue_init [49]
+-----------------------------------------------
+                0.00    0.00      35/35          orf_token_evs [31]
+[48]     0.0    0.00    0.00      35         sq_reinit [48]
+-----------------------------------------------
+                0.00    0.00       1/20          gmi_init [27]
+                0.00    0.00      19/20          queues_pend_delv_memb_new [47]
+[49]     0.0    0.00    0.00      20         queue_init [49]
+-----------------------------------------------
+                0.00    0.00      18/18          clmConfChg [41]
+[50]     0.0    0.00    0.00      18         gmi_mcast [50]
+                0.00    0.00      18/18          gmi_pend_trans_item_store [51]
+-----------------------------------------------
+                0.00    0.00      18/18          gmi_mcast [50]
+[51]     0.0    0.00    0.00      18         gmi_pend_trans_item_store [51]
+-----------------------------------------------
+                0.00    0.00      18/18          message_handler_req_exec_clm_nodejoin [44]
+[52]     0.0    0.00    0.00      18         libraryNotificationJoin [52]
+-----------------------------------------------
+                0.00    0.00      18/18          message_handler_memb_join [24]
+[53]     0.0    0.00    0.00      18         memb_print_commit_set [53]
+-----------------------------------------------
+                0.00    0.00      18/18          message_handler_memb_join [24]
+[54]     0.0    0.00    0.00      18         memb_state_commit_consensus [54]
+-----------------------------------------------
+                0.00    0.00      15/15          timerlist_expire [9]
+[55]     0.0    0.00    0.00      15         orf_timer_function_token_timeout [55]
+                0.00    0.00      15/726         internal_log_printf [36]
+-----------------------------------------------
+                0.00    0.00      12/12          amfReadGroups [18]
+[56]     0.0    0.00    0.00      12         mempool_malloc [56]
+-----------------------------------------------
+                0.00    0.00       1/2           main [1]
+                0.00    0.00       1/2           gmi_init [27]
+[57]     0.0    0.00    0.00       2         poll_dispatch_add [57]
+-----------------------------------------------
+                0.00    0.00       1/1           main [1]
+[58]     0.0    0.00    0.00       1         aisexec_libais_bind [58]
+-----------------------------------------------
+                0.00    0.00       1/1           main [1]
+[59]     0.0    0.00    0.00       1         amfExecutiveInitialize [59]
+-----------------------------------------------
+                0.00    0.00       1/1           main [1]
+[60]     0.0    0.00    0.00       1         clmExecutiveInitialize [60]
+                0.00    0.00       1/1           this_ip_set [71]
+-----------------------------------------------
+                0.00    0.00       1/1           gmi_init [27]
+[61]     0.0    0.00    0.00       1         determine_local_if [61]
+-----------------------------------------------
+                0.00    0.00       1/1           main [1]
+[62]     0.0    0.00    0.00       1         gmi_join [62]
+-----------------------------------------------
+                0.00    0.00       1/1           main [1]
+[63]     0.0    0.00    0.00       1         grow_connections_table [63]
+                0.00    0.00       1/1           mempool_realloc [68]
+-----------------------------------------------
+                0.00    0.00       1/1           poll_create [69]
+[64]     0.0    0.00    0.00       1         handle_create [64]
+-----------------------------------------------
+                0.00    0.00       1/1           gmi_init [27]
+[65]     0.0    0.00    0.00       1         memb_conf_id_build [65]
+-----------------------------------------------
+                0.00    0.00       1/1           timerlist_expire [9]
+[66]     0.0    0.00    0.00       1         memb_timer_function_state_commit_timeout [66]
+                0.00    0.00       1/726         internal_log_printf [36]
+                0.00    0.00       1/71          confchg_fn [42]
+-----------------------------------------------
+                0.00    0.00       1/1           main [1]
+[67]     0.0    0.00    0.00       1         mempool_init [67]
+-----------------------------------------------
+                0.00    0.00       1/1           grow_connections_table [63]
+[68]     0.0    0.00    0.00       1         mempool_realloc [68]
+-----------------------------------------------
+                0.00    0.00       1/1           main [1]
+[69]     0.0    0.00    0.00       1         poll_create [69]
+                0.00    0.00       1/1           handle_create [64]
+                0.00    0.00       1/1           timerlist_init [72]
+-----------------------------------------------
+                0.00    0.00       1/1           gmi_init [27]
+[70]     0.0    0.00    0.00       1         sq_init [70]
+-----------------------------------------------
+                0.00    0.00       1/1           clmExecutiveInitialize [60]
+[71]     0.0    0.00    0.00       1         this_ip_set [71]
+-----------------------------------------------
+                0.00    0.00       1/1           poll_create [69]
+[72]     0.0    0.00    0.00       1         timerlist_init [72]
+-----------------------------------------------
+
+ This table describes the call tree of the program, and was sorted by
+ the total amount of time spent in each function and its children.
+
+ Each entry in this table consists of several lines.  The line with the
+ index number at the left hand margin lists the current function.
+ The lines above it list the functions that called this function,
+ and the lines below it list the functions this one called.
+ This line lists:
+     index	A unique number given to each element of the table.
+		Index numbers are sorted numerically.
+		The index number is printed next to every function name so
+		it is easier to look up where the function in the table.
+
+     % time	This is the percentage of the `total' time that was spent
+		in this function and its children.  Note that due to
+		different viewpoints, functions excluded by options, etc,
+		these numbers will NOT add up to 100%.
+
+     self	This is the total amount of time spent in this function.
+
+     children	This is the total amount of time propagated into this
+		function by its children.
+
+     called	This is the number of times the function was called.
+		If the function called itself recursively, the number
+		only includes non-recursive calls, and is followed by
+		a `+' and the number of recursive calls.
+
+     name	The name of the current function.  The index number is
+		printed after it.  If the function is a member of a
+		cycle, the cycle number is printed between the
+		function's name and the index number.
+
+
+ For the function's parents, the fields have the following meanings:
+
+     self	This is the amount of time that was propagated directly
+		from the function into this parent.
+
+     children	This is the amount of time that was propagated from
+		the function's children into this parent.
+
+     called	This is the number of times this parent called the
+		function `/' the total number of times the function
+		was called.  Recursive calls to the function are not
+		included in the number after the `/'.
+
+     name	This is the name of the parent.  The parent's index
+		number is printed after it.  If the parent is a
+		member of a cycle, the cycle number is printed between
+		the name and the index number.
+
+ If the parents of the function cannot be determined, the word
+ `<spontaneous>' is printed in the `name' field, and all the other
+ fields are blank.
+
+ For the function's children, the fields have the following meanings:
+
+     self	This is the amount of time that was propagated directly
+		from the child into the function.
+
+     children	This is the amount of time that was propagated from the
+		child's children to the function.
+
+     called	This is the number of times the function called
+		this child `/' the total number of times the child
+		was called.  Recursive calls by the child are not
+		listed in the number after the `/'.
+
+     name	This is the name of the child.  The child's index
+		number is printed after it.  If the child is a
+		member of a cycle, the cycle number is printed
+		between the name and the index number.
+
+ If there are any cycles (circles) in the call graph, there is an
+ entry for the cycle-as-a-whole.  This entry shows who called the
+ cycle (as parents) and the members of the cycle (as children.)
+ The `+' recursive calls entry shows the number of function calls that
+ were internal to the cycle, and the calls entry for each member shows,
+ for that member, how many times it was called from other members of
+ the cycle.
+
+
+Index by function name
+
+  [45] SaNameTisEqual         [54] memb_state_commit_consensus [34] pend_delv_next_delivery_find
+  [16] SaNameTisNameT         [22] memb_state_commit_enter [5] pending_queues_deliver
+  [58] aisexec_libais_bind    [23] memb_state_gather_enter [69] poll_create
+  [59] amfExecutiveInitialize [66] memb_timer_function_state_commit_timeout [57] poll_dispatch_add
+  [18] amfReadGroups          [25] memb_timer_function_state_gather [2] poll_run
+  [40] ckptConfChg            [37] mempool_free           [13] poll_timer_add
+  [41] clmConfChg             [67] mempool_init           [28] poll_timer_delete
+  [60] clmExecutiveInitialize [56] mempool_malloc         [49] queue_init
+  [42] confchg_fn             [68] mempool_realloc        [35] queue_reinit
+   [7] deliver_fn             [38] mempool_strdup         [47] queues_pend_delv_memb_new
+  [61] determine_local_if      [4] message_handler_mcast   [3] recv_handler
+  [17] findComponent          [26] message_handler_memb_attempt_join [70] sq_init
+  [27] gmi_init               [20] message_handler_memb_form_token [33] sq_items_release
+  [62] gmi_join               [24] message_handler_memb_join [48] sq_reinit
+  [50] gmi_mcast               [8] message_handler_orf_token [39] strstr_rs
+  [51] gmi_pend_trans_item_store [19] message_handler_req_exec_ckpt_checkpointopen [71] this_ip_set
+  [63] grow_connections_table [21] message_handler_req_exec_ckpt_sectioncreate [29] timerlist_add
+  [64] handle_create          [11] message_handler_req_exec_ckpt_sectionwrite [14] timerlist_add_future
+  [36] internal_log_printf    [44] message_handler_req_exec_clm_nodejoin [30] timerlist_del
+  [52] libraryNotificationJoin [15] messages_free          [9] timerlist_expire
+  [43] libraryNotificationLeave [55] orf_timer_function_token_timeout [72] timerlist_init
+  [65] memb_conf_id_build     [31] orf_token_evs          [10] timerlist_timeout_msec
+  [46] memb_form_token_conf_desc_build [12] orf_token_mcast [6] user_deliver
+  [53] memb_print_commit_set  [32] orf_token_rtr

+ 247 - 0
exec/tlist.c

@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "../include/list.h"
+#include "tlist.h"
+
+struct timer {
+	struct list_head list;
+	struct timeval tv;
+	void (*timer_fn)(void *data);
+	void *data;
+};
+
+void timerlist_init (struct timerlist *timerlist)
+{
+	list_init (&timerlist->timer_head);
+}
+
+void timerlist_free (struct timerlist *timerlist)
+{
+}
+
+int timers_inuse = 0;
+
+static inline void timeval_adjust_to_msec (struct timeval *tv) {
+        tv->tv_usec = (tv->tv_usec / 1000) * 1000;
+}
+
+
+void timerlist_add (struct timerlist *timerlist, struct timer *timer)
+{
+	struct list_head *timer_list = 0;
+	struct timer *timer_from_list;
+	int found;
+
+	timeval_adjust_to_msec (&timer->tv);
+	for (found = 0, timer_list = timerlist->timer_head.next;
+		timer_list != &timerlist->timer_head;
+		timer_list = timer_list->next) {
+
+		timer_from_list = list_entry (timer_list,
+			struct timer, list);
+
+		if ((timer_from_list->tv.tv_sec > timer->tv.tv_sec) ||
+			((timer_from_list->tv.tv_sec == timer->tv.tv_sec) &&
+			(timer_from_list->tv.tv_usec > timer->tv.tv_usec))) {
+			list_add (&timer->list, timer_list->prev);
+			found = 1;
+			break; /* for timer iteration */
+		}
+	}
+	if (found == 0) {
+		list_add (&timer->list, timerlist->timer_head.prev);
+		timers_inuse++;
+	}
+}
+
+timer_handle timerlist_add_future (struct timerlist *timerlist,
+	void (*timer_fn) (void *data),
+	void *data,
+	int msec_in_future)
+{
+	struct timer *timer;
+	struct timeval current_time;
+	int seconds;
+	int mseconds;
+
+	timer = (struct timer *)malloc (sizeof (struct timer));
+	if (timer == 0) {
+		errno = ENOMEM;
+		return (0);
+	}
+	
+	seconds = msec_in_future / 1000;
+	mseconds = msec_in_future % 1000;
+
+	gettimeofday (&current_time, 0);
+	timeval_adjust_to_msec (&current_time);
+	timer->tv.tv_sec = current_time.tv_sec + seconds;
+	timer->tv.tv_usec = current_time.tv_usec + mseconds * 1000;
+	if (timer->tv.tv_usec >= 1000000) {
+		timer->tv.tv_sec++;
+		timer->tv.tv_usec -= 1000000;
+	}
+	timer->data = data;
+	timer->timer_fn = timer_fn;
+	timerlist_add (timerlist, timer);
+
+	return (timer);
+}
+
+void timerlist_del (struct timerlist *timerlist, timer_handle timer_handle)
+{
+	struct timer *timer = (struct timer *)timer_handle;
+
+	list_del (&timer->list);
+	free (timer);
+	timers_inuse--;
+}
+
+int timer_expire_get_tv (struct timerlist *timerlist, struct timeval *tv)
+{
+	struct timeval current_time;
+	struct timer *timer_from_list;
+
+	/*
+	 * empty list, no expire
+	 */
+	if (timerlist->timer_head.next == &timerlist->timer_head) {
+		return (-1);
+	}
+	
+	timer_from_list = list_entry (timerlist->timer_head.next,
+		struct timer, list);
+
+	gettimeofday (&current_time, 0);
+	timeval_adjust_to_msec (&current_time);
+
+	/*
+	 * timer at head of list is expired, zero msecs required
+	 */
+	if ((timer_from_list->tv.tv_sec < current_time.tv_sec) ||
+		((timer_from_list->tv.tv_sec == current_time.tv_sec) &&
+		(timer_from_list->tv.tv_usec <= current_time.tv_usec))) {
+		
+		tv->tv_sec = 0;
+		tv->tv_usec = 0;
+	}
+
+	tv->tv_sec = timer_from_list->tv.tv_sec - current_time.tv_sec;
+	tv->tv_usec = timer_from_list->tv.tv_usec - current_time.tv_usec;
+	if (tv->tv_usec < 0) {
+		tv->tv_sec -= 1;
+		tv->tv_usec += 1000000;
+	}
+	if (tv->tv_sec < 0) {
+		tv->tv_sec = 0;
+		tv->tv_usec = 0;
+	}
+
+	timeval_adjust_to_msec (tv);
+	return (0);
+}
+
+int timerlist_timeout_msec (struct timerlist *timerlist)
+{
+	struct timeval current_time;
+	struct timer *timer_from_list;
+	int time_in_msec;
+
+	/*
+	 * empty list, no expire
+	 */
+	if (timerlist->timer_head.next == &timerlist->timer_head) {
+		return (-1);
+	}
+	
+	timer_from_list = list_entry (timerlist->timer_head.next,
+		struct timer, list);
+
+	gettimeofday (&current_time, 0);
+	timeval_adjust_to_msec (&current_time);
+
+	/*
+	 * timer at head of list is expired, zero msecs required
+	 */
+	if ((timer_from_list->tv.tv_sec < current_time.tv_sec) ||
+		((timer_from_list->tv.tv_sec == current_time.tv_sec) &&
+		(timer_from_list->tv.tv_usec <= current_time.tv_usec))) {
+		return (0);
+	}
+	time_in_msec = ((timer_from_list->tv.tv_sec - current_time.tv_sec) * 1000) + ((timer_from_list->tv.tv_usec - current_time.tv_usec) / 1000);
+
+	return time_in_msec;
+}
+
+void timerlist_expire (struct timerlist *timerlist)
+{
+	struct list_head *timer_list;
+	struct timer *timer_from_list;
+	struct timeval current_time;
+
+	gettimeofday (&current_time, 0);
+	timeval_adjust_to_msec (&current_time);
+
+	for (timer_list = timerlist->timer_head.next;
+		timer_list != &timerlist->timer_head;) {
+
+		timer_from_list = list_entry (timer_list,
+			struct timer, list);
+
+		if ((timer_from_list->tv.tv_sec < current_time.tv_sec) ||
+			((timer_from_list->tv.tv_sec == current_time.tv_sec) &&
+			(timer_from_list->tv.tv_usec <= current_time.tv_usec))) {
+			timer_list = timer_list->next;
+			list_del (&timer_from_list->list);
+			/*
+			 * This list_init is here to allow multiple deletes
+			 * of a timer without corrupting memory
+			 */
+			list_init (&timer_from_list->list);
+
+#ifdef DEBUG_MULTIPLE_DELETE
+timer_from_list->list.next = (struct list_head *)0xdeadbeef;
+timer_from_list->list.prev = (struct list_head *)0xdeadbeef;
+#endif
+			timer_from_list->timer_fn (timer_from_list->data);
+		} else {
+			break; /* for timer iteration */
+		}
+	}
+}

+ 62 - 0
exec/tlist.h

@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/time.h>
+#include "../include/list.h"
+
+#ifndef TLIST_H_DEFINED
+#define TLIST_H_DEFINED
+
+typedef void * timer_handle;
+
+struct timerlist {
+	struct list_head timer_head;
+};
+
+void timerlist_init (struct timerlist *timerlist);
+
+void timerlist_free (struct timerlist *timerlist);
+
+timer_handle timerlist_add_future (struct timerlist *timerlist,
+	void (*timer_fn) (void *data),
+	void *data,
+	int msec_in_future);
+
+void timerlist_del (struct timerlist *timerlist, timer_handle timer_handle);
+
+void timerlist_expire (struct timerlist *timerlist);
+
+int timerlist_timeout_msec (struct timerlist *timerlist);
+
+#endif /* TLIST_H_DEFINED */

+ 221 - 0
include/ais_amf.h

@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AIS_AMF_H_DEFINED
+#define AIS_AMF_H_DEFINED
+
+#include "ais_types.h"
+
+typedef void (*SaAmfHealthcheckCallbackT) (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfHealthcheckT checkType);
+
+typedef void (*SaAmfReadinessStateSetCallbackT) (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfReadinessStateT readinessState);
+
+typedef void (*SaAmfComponentTerminateCallbackT) (
+	SaInvocationT invocation,
+	const SaNameT *compName);
+
+typedef void (*SaAmfCSISetCallbackT) (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	SaAmfCSIFlagsT csiFlags,
+	SaAmfHAStateT *haState,
+	SaNameT *activeCompName,
+	SaAmfCSITransitionDescriptorT transitionDescriptor);
+			
+typedef void (*SaAmfCSIRemoveCallbackT) (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	const SaAmfCSIFlagsT *csiFlags);
+
+typedef void (*SaAmfProtectionGroupTrackCallbackT) (
+	const SaNameT *csiName,
+	SaAmfProtectionGroupNotificationT *notificationBuffer,
+	SaUint32T numberOfItems,
+	SaUint32T numberOfMembers,
+	SaErrorT error);
+
+typedef void (*SaAmfExternalComponentRestartCallbackT) (
+	SaInvocationT invocation,
+	const SaNameT *externalCompName);
+
+typedef void (*SaAmfExternalComponentControlCallbackT) (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName,
+	SaAmfExternalComponentActionT controlAction);
+
+typedef void (*SaAmfPendingOperationConfirmCallbackT) (
+	const SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags);
+
+typedef void (*SaAmfPendingOperationExpiredCallbackT) (
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags);
+
+typedef struct {
+	SaAmfHealthcheckCallbackT
+		saAmfHealthcheckCallback;
+	SaAmfReadinessStateSetCallbackT
+		saAmfReadinessStateSetCallback;
+	SaAmfComponentTerminateCallbackT
+		saAmfComponentTerminateCallback;
+	SaAmfCSISetCallbackT
+		saAmfCSISetCallback;
+	SaAmfCSIRemoveCallbackT
+		saAmfCSIRemoveCallback;
+	SaAmfProtectionGroupTrackCallbackT
+		saAmfProtectionGroupTrackCallback;
+	SaAmfExternalComponentRestartCallbackT
+		saAmfExternalComponentRestartCallback;
+	SaAmfExternalComponentControlCallbackT
+		saAmfExternalComponentControlCallback;
+	SaAmfPendingOperationConfirmCallbackT
+		saAmfPendingOperationConfirmCallback;
+	SaAmfPendingOperationExpiredCallbackT
+		saAmfPendingOperationExpiredCallback;
+} SaAmfCallbacksT;
+
+/*
+ * Interfaces
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SaErrorT
+saAmfInitialize (
+	SaAmfHandleT *amfHandle,
+	const SaAmfCallbacksT *amfCallbacks,
+	const SaVersionT *version);
+
+SaErrorT
+saAmfSelectionObjectGet (
+	const SaAmfHandleT *amfHandle,
+	SaSelectionObjectT *selectionObject);
+
+SaErrorT
+saAmfDispatch (
+	const SaAmfHandleT *amfHandle,
+	SaDispatchFlagsT dispatchFlags);
+
+SaErrorT
+saAmfFinalize (
+	const SaAmfHandleT *amfHandle);
+
+SaErrorT
+saAmfComponentRegister (
+	const SaAmfHandleT *amfHandle,
+	const SaNameT *compName,
+	const SaNameT *proxyCompName);
+
+SaErrorT
+saAmfComponentUnregister (
+	const SaAmfHandleT *amfHandle,
+	const SaNameT *compName,
+	const SaNameT *proxyCompName);
+
+SaErrorT
+saAmfCompNameGet (
+	const SaAmfHandleT *amfHandle,
+	SaNameT *compName);
+
+SaErrorT
+saAmfReadinessStateGet (
+	const SaNameT *compName,
+	SaAmfReadinessStateT *readinessState);
+
+SaErrorT
+saAmfStoppingComplete (
+	SaInvocationT invocation,
+	SaErrorT error);
+
+SaErrorT
+saAmfHAStateGet (
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	SaAmfHAStateT *haState);
+
+SaErrorT
+saAmfProtectionGroupTrackStart (
+	const SaAmfHandleT *amfHandle,
+	const SaNameT *csiName,
+	SaUint8T trackFlags,
+	const SaAmfProtectionGroupNotificationT *notificationBuffer,
+	SaUint32T numberOfItems);
+
+SaErrorT
+saAmfProtectionGroupTrackStop (
+	const SaAmfHandleT *amfHandle,
+	const SaNameT *csiName);
+
+SaErrorT
+saAmfErrorReport (
+	const SaNameT *reportingComponent,
+	const SaNameT *erroneousComponent,
+	SaTimeT errorDetectionTime,
+	const SaAmfErrorDescriptorT *errorDescriptor,
+	const SaAmfAdditionalDataT *additionalData);
+
+SaErrorT
+saAmfErrorCancelAll (
+	const SaNameT *compName);
+
+SaErrorT
+saAmfComponentCapabilityModelGet (
+	const SaNameT *compName,
+	SaAmfComponentCapabilityModelT *componentCapabilityModel);
+
+SaErrorT
+saAmfPendingOperationGet (
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT *pendingOperationFlags);
+
+SaErrorT
+saAmfResponse (
+	SaInvocationT invocation,
+	SaErrorT error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AIS_AMF_H_DEFINED */

+ 174 - 0
include/ais_ckpt.h

@@ -0,0 +1,174 @@
+
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ais_types.h"
+
+#ifndef AIS_CKPT_H_DEFINED
+#define AIS_CKPT_H_DEFINED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SaErrorT
+saCkptInitialize (
+	SaCkptHandleT *ckptHandle,
+	const SaCkptCallbacksT *callbacks,
+	const SaVersionT *version);
+
+SaErrorT
+saCkptSelectionObjectGet (
+	const SaCkptHandleT *ckptHandle,
+	SaSelectionObjectT *selectionObject);
+
+SaErrorT
+saCkptDispatch (
+	const SaCkptHandleT *ckptHandle,
+	SaDispatchFlagsT dispatchFlags);
+
+SaErrorT
+saCkptFinalize (
+	const SaCkptHandleT *ckptHandle);
+
+SaErrorT
+saCkptCheckpointOpen (
+	const SaNameT *checkpointName,
+	const SaCkptCheckpointCreationAttributesT *checkpointCreationAttributes,
+	SaCkptCheckpointOpenFlagsT checkpointOpenFlags,
+	SaTimeT timeout,
+	SaCkptCheckpointHandleT *checkpointHandle);
+
+SaErrorT
+saCkptCheckpointOpenAsync (
+	const SaCkptHandleT *ckptHandle,
+	SaInvocationT invocation,	
+	const SaNameT *checkpointName,
+	const SaCkptCheckpointCreationAttributesT *checkpointCreationAttributes,
+	SaCkptCheckpointOpenFlagsT checkpointOpenFlags);
+
+SaErrorT
+saCkptCheckpointClose (
+	const SaCkptCheckpointHandleT *checkpointHandle);
+
+SaErrorT
+saCkptCheckpointUnlink (
+	const SaNameT *checkpointName);
+
+SaErrorT
+saCkptCheckpointRetentionDurationSet (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	SaTimeT retentionDuration);
+
+SaErrorT
+saCkptActiveCheckpointSet (
+	const SaCkptCheckpointHandleT *checkpointHandle);
+
+SaErrorT
+saCkptCheckpointStatusGet (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	SaCkptCheckpointStatusT *checkpointStatus);
+
+SaErrorT
+saCkptSectionCreate (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	SaCkptSectionCreationAttributesT *sectionCreationAttributes,
+	const void *initialData,
+	SaUint32T initialDataSize);
+
+
+SaErrorT
+saCkptSectionDelete (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	const SaCkptSectionIdT *sectionId);
+
+SaErrorT
+saCkptSectionExpirationTimeSet (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	const SaCkptSectionIdT *sectionId,
+	SaTimeT expirationTime);
+
+SaErrorT
+saCkptSectionIteratorInitialize (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	SaCkptSectionsChosenT sectionsChosen,
+	SaTimeT expirationTime,
+	SaCkptSectionIteratorT *sectionIterator);
+
+SaErrorT
+saCkptSectionIteratorNext (
+	SaCkptSectionIteratorT *sectionIterator,
+	SaCkptSectionDescriptorT *sectionDescriptor);
+
+SaErrorT
+saCkptSectionIteratorFinalize (
+	SaCkptSectionIteratorT *sectionIterator);
+
+SaErrorT
+saCkptCheckpointWrite (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	const SaCkptIOVectorElementT *ioVector,
+	SaUint32T numberOfElements,
+	SaUint32T *erroneousVectorIndex);
+
+SaErrorT
+saCkptSectionOverwrite (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	const SaCkptSectionIdT *secitonId,
+	SaUint8T *dataBuffer,
+	SaSizeT dataSize);
+
+SaErrorT
+saCkptCheckpointRead (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	SaCkptIOVectorElementT *ioVector,
+	SaUint32T numberOfElements,
+	SaUint32T *erroneousVectorIndex);
+
+SaErrorT
+saCkptCheckpointSynchronize (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	SaTimeT timeout);
+
+SaErrorT
+saCkptCheckpointSynchronizeAsync (
+	const SaCkptHandleT *ckptHandle,
+	SaInvocationT invocation,
+	const SaCkptCheckpointHandleT *checkpointHandle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AIS_CKPT_H_DEFINED */

+ 100 - 0
include/ais_clm.h

@@ -0,0 +1,100 @@
+
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ais_types.h"
+
+typedef void (*SaClmClusterNodeGetCallbackT)(
+	SaInvocationT invocation,
+	SaClmClusterNodeT *clusterNode,
+	SaErrorT error);
+
+typedef void (*SaClmClusterTrackCallbackT) (
+	SaClmClusterNotificationT *notificationBuffer,
+	SaUint32T numberOfItems,
+	SaUint32T numberOfMembers,
+	SaUint64T viewNumber,
+	SaErrorT error);
+
+typedef struct {
+	SaClmClusterNodeGetCallbackT saClmClusterNodeGetCallback;
+	SaClmClusterTrackCallbackT saClmClusterTrackCallback;
+} SaClmCallbacksT;
+
+SaErrorT
+saClmInitialize (
+	SaClmHandleT *clmHandle,
+	const SaClmCallbacksT *clmCallbacks,
+	const SaVersionT *version);
+
+
+SaErrorT
+saClmSelectionObjectGet (
+		const SaClmHandleT *clmHandle,
+		SaSelectionObjectT *selectionObject);
+
+SaErrorT
+saClmDispatch (
+	const SaClmHandleT *clmHandle,
+	SaDispatchFlagsT dispatchFlags);
+
+SaErrorT
+saClmFinalize (
+	SaClmHandleT *clmHandle);
+
+SaErrorT
+saClmClusterTrackStart (
+	const SaClmHandleT *clmHandle,
+	SaUint8T trackFlags,
+	SaClmClusterNotificationT *notificationBuffer,
+	SaUint32T numberOfItems);
+
+SaErrorT
+saClmClusterTrackStop (
+	const SaClmHandleT *clmHandle);
+
+SaErrorT
+saClmClusterNodeGet (
+	SaClmNodeIdT nodeId,
+	SaTimeT timeout,
+	SaClmClusterNodeT *clusterNode);
+
+SaErrorT
+saClmClusterNodeGetAsync (
+	const SaClmHandleT *clmHandle,
+	SaInvocationT invocation,
+	SaClmNodeIdT nodeId,
+	SaClmClusterNodeT *clusterNode);
+
+

+ 728 - 0
include/ais_msg.h

@@ -0,0 +1,728 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef AIS_MSG_H_DEFINED
+#define AIS_MSG_H_DEFINED
+
+#include <netinet/in.h>
+#include "ais_types.h"
+
+enum req_amf_response_interfaces {
+	MESSAGE_REQ_AMF_RESPONSE_SAAMFHEALTHCHECKCALLBACK		= 0x10000000,
+	MESSAGE_REQ_AMF_RESPONSE_SAAMFREADINESSSTATESETCALLBACK = 0x20000000,
+	MESSAGE_REQ_AMF_RESPONSE_SAAMFCOMPONENTTERMINATECALLBACK = 0x30000000,
+	MESSAGE_REQ_AMF_RESPONSE_SAAMFCSISETCALLBACK			= 0x40000000,
+	MESSAGE_REQ_AMF_RESPONSE_SAAMFCSIREMOVECALLBACK			= 0x50000000,
+	MESSAGE_REQ_AMF_RESPONSE_SAAMFEXTERNALCOMPONENTRESTARTCALLBACK = 0x60000000,
+	MESSAGE_REQ_AMF_RESPONSE_SAAMFEXTERNALCOMPONENTCONTROLCALLBACK = 0x70000000,
+	MESSAGE_REQ_AMF_RESPONSE_SAAMFPENDINGOPERATIONCONFIRMCALLBACK = 0x80000000
+};
+#define req_amf_response_get_interface(a) (a & 0xf0000000)
+#define req_amf_response_get_connection(a) (a & 0x0fffffff)
+#define req_amf_response_set(interface,connection) (interface | connection)
+
+enum req_init_types {
+	MESSAGE_REQ_CLM_INIT,
+	MESSAGE_REQ_AMF_INIT,
+	MESSAGE_REQ_CKPT_INIT,
+	MESSAGE_REQ_CKPT_CHECKPOINT_INIT,
+	MESSAGE_REQ_CKPT_SECTIONITERATOR_INIT
+};
+
+enum res_init_types {
+	MESSAGE_RES_INIT
+};
+
+enum req_clm_types {
+	MESSAGE_REQ_CLM_TRACKSTART,
+	MESSAGE_REQ_CLM_TRACKSTOP,
+	MESSAGE_REQ_CLM_NODEGET
+};
+
+enum res_clm_types {
+	MESSAGE_RES_CLM_TRACKCALLBACK,
+	MESSAGE_RES_CLM_NODEGET,
+	MESSAGE_RES_CLM_NODEGETCALLBACK
+};
+
+enum req_amf_types {
+	MESSAGE_REQ_AMF_ACTIVATEPOLL,
+	MESSAGE_REQ_AMF_COMPONENTREGISTER,
+	MESSAGE_REQ_AMF_COMPONENTUNREGISTER,
+	MESSAGE_REQ_AMF_READINESSSTATEGET,
+	MESSAGE_REQ_AMF_HASTATEGET,
+	MESSAGE_REQ_AMF_PROTECTIONGROUPTRACKSTART,
+	MESSAGE_REQ_AMF_PROTECTIONGROUPTRACKSTOP,
+	MESSAGE_REQ_AMF_ERRORREPORT,
+	MESSAGE_REQ_AMF_ERRORCANCELALL,
+	MESSAGE_REQ_AMF_STOPPINGCOMPLETE,
+	MESSAGE_REQ_AMF_RESPONSE,
+	MESSAGE_REQ_AMF_COMPONENTCAPABILITYMODELGET
+};
+
+enum res_amf_types {
+	MESSAGE_RES_AMF_ACTIVATEPOLL,
+	MESSAGE_RES_AMF_COMPONENTREGISTER,
+	MESSAGE_RES_AMF_COMPONENTUNREGISTER,
+	MESSAGE_RES_AMF_READINESSSTATEGET,
+	MESSAGE_RES_AMF_HASTATEGET,
+	MESSAGE_RES_AMF_HEALTHCHECKCALLBACK,
+	MESSAGE_RES_AMF_READINESSSTATESETCALLBACK,
+	MESSAGE_RES_AMF_COMPONENTTERMINATECALLBACK,
+	MESSAGE_RES_AMF_CSISETCALLBACK,
+	MESSAGE_RES_AMF_CSIREMOVECALLBACK,
+	MESSAGE_RES_AMF_PROTECTIONGROUPTRACKSTART,
+	MESSAGE_RES_AMF_PROTECTIONGROUPTRACKCALLBACK,
+	MESSAGE_RES_AMF_PROTECTIONGROUPTRACKSTOP,
+	MESSAGE_RES_AMF_COMPONENTCAPABILITYMODELGET,
+	MESSAGE_RES_AMF_ERRORREPORT,
+	MESSAGE_RES_AMF_ERRORCANCELALL
+};
+
+enum req_lib_ckpt_checkpoint_types {
+	MESSAGE_REQ_CKPT_CHECKPOINT_CHECKPOINTOPEN,
+	MESSAGE_REQ_CKPT_CHECKPOINT_CHECKPOINTOPENASYNC,
+	MESSAGE_REQ_CKPT_CHECKPOINT_CHECKPOINTUNLINK,
+	MESSAGE_REQ_CKPT_CHECKPOINT_CHECKPOINTRETENTIONDURATIONSET,
+	MESSAGE_REQ_CKPT_CHECKPOINT_ACTIVECHECKPOINTSET,
+	MESSAGE_REQ_CKPT_CHECKPOINT_CHECKPOINTSTATUSGET,
+	MESSAGE_REQ_CKPT_CHECKPOINT_SECTIONCREATE,
+	MESSAGE_REQ_CKPT_CHECKPOINT_SECTIONDELETE,
+	MESSAGE_REQ_CKPT_CHECKPOINT_SECTIONEXPIRATIONTIMESET,
+	MESSAGE_REQ_CKPT_CHECKPOINT_SECTIONWRITE,
+	MESSAGE_REQ_CKPT_CHECKPOINT_SECTIONOVERWRITE,
+	MESSAGE_REQ_CKPT_CHECKPOINT_SECTIONREAD,
+	MESSAGE_REQ_CKPT_CHECKPOINT_CHECKPOINTSYNCHRONIZE,
+	MESSAGE_REQ_CKPT_CHECKPOINT_CHECKPOINTSYNCHRONIZEASYNC
+};
+
+enum req_lib_ckpt_sectioniterator_types {
+	MESSAGE_REQ_CKPT_SECTIONITERATOR_SECTIONITERATORINITIALIZE,
+	MESSAGE_REQ_CKPT_SECTIONITERATOR_SECTIONITERATORNEXT
+};
+
+enum res_lib_ckpt_types {
+	MESSAGE_RES_CKPT_CHECKPOINTOPENASYNC,
+	MESSAGE_RES_CKPT_CHECKPOINTSYNCHRONIZEASYNC
+};
+
+enum res_lib_ckpt_checkpoint_types {
+	MESSAGE_RES_CKPT_CHECKPOINT_CHECKPOINTOPEN,
+	MESSAGE_RES_CKPT_CHECKPOINT_CHECKPOINTUNLINK,
+	MESSAGE_RES_CKPT_CHECKPOINT_CHECKPOINTRETENTIONDURATIONSET,
+	MESSAGE_RES_CKPT_CHECKPOINT_ACTIVECHECKPOINTSET,
+	MESSAGE_RES_CKPT_CHECKPOINT_CHECKPOINTSTATUSGET,
+	MESSAGE_RES_CKPT_CHECKPOINT_SECTIONCREATE,
+	MESSAGE_RES_CKPT_CHECKPOINT_SECTIONDELETE,
+	MESSAGE_RES_CKPT_CHECKPOINT_SECTIONEXPIRATIONTIMESET,
+	MESSAGE_RES_CKPT_CHECKPOINT_SECTIONWRITE,
+	MESSAGE_RES_CKPT_CHECKPOINT_SECTIONOVERWRITE,
+	MESSAGE_RES_CKPT_CHECKPOINT_SECTIONREAD,
+	MESSAGE_RES_CKPT_CHECKPOINT_CHECKPOINTSYNCHRONIZE
+};
+
+enum res_lib_ckpt_sectioniterator_types {
+	MESSAGE_RES_CKPT_SECTIONITERATOR_SECTIONITERATORINITIALIZE,
+	MESSAGE_RES_CKPT_SECTIONITERATOR_SECTIONITERATORNEXT
+};
+
+enum nodeexec_message_types {
+	MESSAGE_REQ_EXEC_CLM_NODEJOIN,
+	MESSAGE_REQ_EXEC_AMF_COMPONENTREGISTER,
+	MESSAGE_REQ_EXEC_AMF_COMPONENTUNREGISTER,
+	MESSAGE_REQ_EXEC_AMF_ERRORREPORT,
+	MESSAGE_REQ_EXEC_AMF_ERRORCANCELALL,
+	MESSAGE_REQ_EXEC_AMF_READINESSSTATESET,
+	MESSAGE_REQ_EXEC_AMF_HASTATESET,
+	MESSAGE_REQ_EXEC_CKPT_CHECKPOINTOPEN,
+	MESSAGE_REQ_EXEC_CKPT_CHECKPOINTCLOSE,
+	MESSAGE_REQ_EXEC_CKPT_CHECKPOINTUNLINK,
+	MESSAGE_REQ_EXEC_CKPT_CHECKPOINTRETENTIONDURATIONSET,
+	MESSAGE_REQ_EXEC_CKPT_SECTIONCREATE,
+	MESSAGE_REQ_EXEC_CKPT_SECTIONDELETE,
+	MESSAGE_REQ_EXEC_CKPT_SECTIONEXPIRATIONTIMESET,
+	MESSAGE_REQ_EXEC_CKPT_SECTIONWRITE,
+	MESSAGE_REQ_EXEC_CKPT_SECTIONOVERWRITE,
+	MESSAGE_REQ_EXEC_CKPT_SECTIONREAD
+};
+
+#define MESSAGE_MAGIC 0x5a6b7c8d
+struct message_header {
+	int magic;
+	int size;
+	int id;
+};
+
+struct message_source {
+	int fd;
+	struct in_addr in_addr;
+};
+
+struct message_temp {
+	struct message_header header;
+	char message_data[0];
+};
+
+struct req_execauth_xmit_authkey {
+	struct message_header header;
+	int authModule;
+	unsigned char random[16];
+};
+
+struct res_execauth_xmit_signature {
+	struct message_header header;
+	unsigned char signature[64];
+	unsigned int signature_length;
+};
+
+struct req_execauth_connection_authorized {
+	struct message_header header;
+};
+
+struct req_clm_trackstart {
+	struct message_header header;
+	SaUint8T trackFlags;
+	SaClmClusterNotificationT *notificationBufferAddress;
+	SaUint32T numberOfItems;
+};
+
+struct req_lib_init {
+	struct message_header header;
+};
+
+struct res_lib_init {
+	struct message_header header;
+	SaErrorT error;
+};
+
+struct req_lib_amf_componentregister {
+	struct message_header header;
+	SaNameT compName;
+	SaNameT proxyCompName;
+};
+
+struct req_exec_amf_componentregister {
+	struct message_header header;
+	struct message_source source;
+	struct req_lib_amf_componentregister req_lib_amf_componentregister;
+};
+
+struct res_lib_amf_componentregister {
+	struct message_header header;
+	SaErrorT error;
+};
+
+struct req_lib_amf_componentunregister {
+	struct message_header header;
+	SaNameT compName;
+	SaNameT proxyCompName;
+};
+
+struct req_exec_amf_componentunregister {
+	struct message_header header;
+	struct message_source source;
+	struct req_lib_amf_componentunregister req_lib_amf_componentunregister;
+};
+
+struct res_lib_amf_componentunregister {
+	struct message_header header;
+	SaErrorT error;
+};
+
+struct req_amf_readinessstateget {
+	struct message_header header;
+	SaNameT compName;
+};
+
+struct res_amf_readinessstateget {
+	struct message_header header;
+	SaAmfReadinessStateT readinessState;
+	SaErrorT error;
+};
+
+struct res_amf_healthcheckcallback {
+	struct message_header header;
+	int instance;
+	SaInvocationT invocation;
+	SaNameT compName;
+	SaAmfHealthcheckT checkType;
+};
+
+struct res_amf_readinessstatesetcallback {
+	struct message_header header;
+	SaInvocationT invocation;
+	SaNameT compName;
+	SaAmfReadinessStateT readinessState;
+};
+
+struct req_exec_amf_readinessstateset {
+	struct message_header header;
+	SaNameT compName;
+	SaAmfReadinessStateT readinessState;
+};
+
+struct req_exec_amf_hastateset {
+	struct message_header header;
+	SaNameT compName;
+	SaAmfHAStateT haState;
+};
+
+struct req_exec_ckpt_checkpointclose {
+	struct message_header header;
+	SaNameT checkpointName;
+};
+
+struct req_exec_ckpt_checkpointretentiondurationset {
+	struct message_header header;
+	SaNameT checkpointName;
+	SaTimeT retentionDuration;
+};
+
+struct res_amf_componentterminatecallback {
+	struct message_header header;
+	SaInvocationT invocation;
+	SaNameT compName;
+};
+
+struct req_amf_hastateget {
+	struct message_header header;
+	SaNameT compName;
+	SaNameT csiName;
+};
+
+struct res_amf_hastateget {
+	struct message_header header;
+	SaAmfHAStateT haState;
+	SaErrorT error;
+};
+
+struct res_amf_csisetcallback {
+	struct message_header header;
+	SaInvocationT invocation;
+	SaNameT compName;
+	SaNameT csiName;
+	SaAmfCSIFlagsT csiFlags;
+	SaAmfHAStateT haState;
+	SaNameT activeCompName;
+	SaAmfCSITransitionDescriptorT transitionDescriptor;
+};
+
+struct res_amf_csiremovecallback {
+	struct message_header header;
+	SaInvocationT invocation;
+	SaNameT compName;
+	SaNameT csiName;
+	SaAmfCSIFlagsT csiFlags;
+};
+
+struct req_amf_protectiongrouptrackstart {
+	struct message_header header;
+	SaNameT csiName;
+	SaUint8T trackFlags;
+	SaAmfProtectionGroupNotificationT *notificationBufferAddress;
+	SaUint32T numberOfItems;
+};
+
+struct res_amf_protectiongrouptrackstart {
+	struct message_header header;
+	SaErrorT error;
+};
+	
+
+struct req_amf_protectiongrouptrackstop {
+	struct message_header header;
+	SaNameT csiName;
+};
+
+struct res_amf_protectiongrouptrackstop {
+	struct message_header header;
+	SaErrorT error;
+};
+
+struct res_amf_protectiongrouptrackcallback {
+	struct message_header header;
+	SaNameT csiName;
+	SaAmfProtectionGroupNotificationT *notificationBufferAddress;
+	SaUint32T numberOfItems;
+	SaUint32T numberOfMembers;
+	SaUint32T error;
+	SaAmfProtectionGroupNotificationT notificationBuffer[0];
+};
+
+struct req_lib_amf_errorreport {
+	struct message_header header;
+	SaNameT reportingComponent;
+	SaNameT erroneousComponent;
+	SaTimeT errorDetectionTime;
+	SaAmfErrorDescriptorT errorDescriptor;
+	SaAmfAdditionalDataT additionalData;
+};
+
+struct req_exec_amf_errorreport {
+	struct message_header header;
+	struct message_source source;
+	struct req_lib_amf_errorreport req_lib_amf_errorreport;
+};
+
+struct res_lib_amf_errorreport {
+	struct message_header header;
+	SaErrorT error;
+};
+
+struct req_lib_amf_errorcancelall {
+	struct message_header header;
+	SaNameT compName;
+};
+
+struct req_exec_amf_errorcancelall {
+	struct message_header header;
+	struct message_source source;
+	struct req_lib_amf_errorcancelall req_lib_amf_errorcancelall;
+};
+	
+struct res_lib_amf_errorcancelall {
+	struct message_header header;
+	SaErrorT error;
+};
+
+struct req_amf_response {
+	struct message_header header;
+	SaInvocationT invocation;
+	SaErrorT error;
+};
+
+struct req_amf_stoppingcomplete {
+	struct message_header header;
+	SaInvocationT invocation;
+	SaErrorT error;
+};
+
+struct req_amf_componentcapabilitymodelget {
+	struct message_header header;
+	SaNameT compName;
+};
+
+struct res_amf_componentcapabilitymodelget {
+	struct message_header header;
+	SaAmfComponentCapabilityModelT componentCapabilityModel;
+	SaErrorT error;
+};
+
+struct req_amf_activatepoll {
+	struct message_header header;
+};
+
+struct res_amf_activatepoll {
+	struct message_header header;
+};
+
+struct req_lib_ckpt_checkpointopen {
+	struct message_header header;
+	SaNameT checkpointName;
+	SaCkptCheckpointCreationAttributesT checkpointCreationAttributes;
+	SaCkptCheckpointOpenFlagsT checkpointOpenFlags;
+};
+
+struct res_lib_ckpt_checkpointopen {
+	struct message_header header;
+	SaErrorT error;
+};
+
+struct req_exec_ckpt_checkpointopen {
+	struct message_header header;
+	struct message_source source;
+	struct req_lib_ckpt_checkpointopen req_lib_ckpt_checkpointopen;
+};
+
+
+struct req_lib_ckpt_checkpointopenasync {
+	struct message_header header;
+	SaNameT checkpointName;
+	SaCkptCheckpointCreationAttributesT checkpointCreationAttributes;
+	SaCkptCheckpointOpenFlagsT checkpointOpenFlags;
+	SaInvocationT invocation;
+};
+
+struct res_lib_ckpt_checkpointopenasync {
+	struct message_header header;
+	SaCkptCheckpointHandleT checkpointHandle;
+	SaInvocationT invocation;
+	SaErrorT error;
+};
+
+struct req_lib_ckpt_checkpointclose {
+	struct message_header header;
+};
+
+struct res_lib_ckpt_checkpointclose {
+	struct message_header header;
+	SaNameT checkpointName;
+};
+
+struct req_lib_ckpt_checkpointunlink {
+	struct message_header header;
+	SaNameT checkpointName;
+};
+
+struct res_lib_ckpt_checkpointunlink {
+	struct message_header header;
+	SaErrorT error;
+};
+
+struct req_exec_ckpt_checkpointunlink {
+	struct message_header header;
+	struct message_source source;
+	struct req_lib_ckpt_checkpointunlink req_lib_ckpt_checkpointunlink;
+};
+
+struct req_lib_ckpt_checkpointretentiondurationset {
+	struct message_header header;
+	SaTimeT retentionDuration;
+};
+
+struct req_lib_ckpt_activecheckpointset {
+	struct message_header header;
+};
+
+struct res_lib_ckpt_activecheckpointset {
+	struct message_header header;
+	SaErrorT error;
+};
+
+struct req_lib_ckpt_checkpointstatusget {
+	struct message_header header;
+};
+
+struct res_lib_ckpt_checkpointstatusget {
+	struct message_header header;
+	SaCkptCheckpointStatusT checkpointStatus;
+};
+
+struct req_lib_ckpt_sectioncreate {
+	struct message_header header;
+	SaUint32T idLen;
+	SaTimeT expirationTime;
+	SaUint32T initialDataSize;
+};
+
+struct res_lib_ckpt_sectioncreate {
+	struct message_header header;
+	SaErrorT error;
+};
+
+struct req_exec_ckpt_sectioncreate {
+	struct message_header header;
+	struct message_source source;
+	SaNameT checkpointName;
+	struct req_lib_ckpt_sectioncreate req_lib_ckpt_sectioncreate; /* this must be last */
+};
+
+struct req_lib_ckpt_sectiondelete {
+	struct message_header header;
+	SaUint32T idLen;
+};
+
+struct res_lib_ckpt_sectiondelete {
+	struct message_header header;
+	SaErrorT error;
+};
+struct req_exec_ckpt_sectiondelete {
+	struct message_header header;
+	struct message_source source;
+	SaNameT checkpointName;
+	struct req_lib_ckpt_sectiondelete req_lib_ckpt_sectiondelete; /* this must be last */
+};
+
+struct req_lib_ckpt_sectionexpirationtimeset {
+	struct message_header header;
+	SaUint32T idLen;
+	SaTimeT expirationTime;
+};
+
+struct res_lib_ckpt_sectionexpirationtimeset {
+	struct message_header header;
+	SaErrorT error;
+};
+
+struct req_exec_ckpt_sectionexpirationtimeset {
+	struct message_header header;
+	struct message_source source;
+	SaNameT checkpointName;
+	struct req_lib_ckpt_sectionexpirationtimeset req_lib_ckpt_sectionexpirationtimeset;
+};
+
+struct req_lib_ckpt_sectioniteratorinitialize {
+	struct message_header header;
+	SaNameT checkpointName;
+	SaCkptSectionsChosenT sectionsChosen;
+	SaTimeT expirationTime;
+};
+
+struct res_lib_ckpt_sectioniteratorinitialize {
+	struct message_header header;
+	SaErrorT error;
+};
+
+struct req_lib_ckpt_sectioniteratornext {
+	struct message_header header;
+};
+
+struct res_lib_ckpt_sectioniteratornext {
+	struct message_header header;
+	SaCkptSectionDescriptorT sectionDescriptor;
+	SaErrorT error;
+};
+
+struct req_lib_ckpt_sectionwrite {
+	struct message_header header;
+	SaUint32T idLen;
+	SaOffsetT dataOffset;
+	SaOffsetT dataSize;
+};
+
+struct res_lib_ckpt_sectionwrite {
+	struct message_header header;
+	SaErrorT error;
+};
+
+struct req_exec_ckpt_sectionwrite {
+	struct message_header header;
+	struct message_source source;
+	SaNameT checkpointName;
+	struct req_lib_ckpt_sectionwrite req_lib_ckpt_sectionwrite;
+};
+
+struct req_lib_ckpt_sectionoverwrite {
+	struct message_header header;
+	SaUint32T idLen;
+	SaUint32T dataSize;
+};
+
+struct res_lib_ckpt_sectionoverwrite {
+	struct message_header header;
+	SaErrorT error;
+};
+	
+struct req_exec_ckpt_sectionoverwrite {
+	struct message_header header;
+	struct message_source source;
+	SaNameT checkpointName;
+	struct req_lib_ckpt_sectionoverwrite req_lib_ckpt_sectionoverwrite;
+};
+
+struct req_lib_ckpt_sectionread {
+	struct message_header header;
+	SaUint32T idLen;
+	SaOffsetT dataOffset;
+	SaOffsetT dataSize;
+};
+
+struct res_lib_ckpt_sectionread {
+	struct message_header header;
+	SaErrorT error;
+	SaSizeT dataRead;
+};
+
+struct req_exec_ckpt_sectionread {
+	struct message_header header;
+	struct message_source source;
+	SaNameT checkpointName;
+	struct req_lib_ckpt_sectionread req_lib_ckpt_sectionread;
+};
+
+struct req_lib_ckpt_checkpointsynchronize {
+	struct message_header header;
+};
+
+struct res_lib_ckpt_checkpointsynchronize {
+	struct message_header header;
+	SaErrorT error;
+};
+
+struct req_lib_ckpt_checkpointsynchronizeasync {
+	struct message_header header;
+	SaInvocationT invocation;
+};
+
+struct req_clm_trackstop {
+	struct message_header header;
+	SaSizeT dataRead;
+	SaErrorT error;
+};
+	
+struct res_clm_trackcallback {
+	struct message_header header;
+	SaUint64T viewNumber;
+	SaUint32T numberOfItems;
+	SaUint32T numberOfMembers;
+	SaClmClusterNotificationT *notificationBufferAddress;
+	SaClmClusterNotificationT notificationBuffer[0];
+};
+
+struct req_clm_nodeget {
+	struct message_header header;
+	SaClmClusterNodeT *clusterNodeAddress;
+	SaInvocationT invocation;
+	SaClmNodeIdT nodeId;
+};
+
+struct res_clm_nodeget {
+	struct message_header header;
+	SaInvocationT invocation;
+	SaClmClusterNodeT *clusterNodeAddress;
+	SaClmClusterNodeT clusterNode;
+	int valid;
+};
+
+struct res_clm_nodegetcallback {
+	struct message_header header;
+	SaInvocationT invocation;
+	SaClmClusterNodeT *clusterNodeAddress;
+	SaClmClusterNodeT clusterNode;
+	int valid;
+};
+
+struct req_exec_clm_heartbeat {
+	struct message_header header;
+};
+
+struct res_exec_clm_heartbeat {
+	struct message_header header;
+};
+
+struct req_exec_clm_nodejoin {
+	struct message_header header;
+	SaClmClusterNodeT clusterNode;
+};
+
+#endif /* AIS_MSG_H_DEFINED */

+ 394 - 0
include/ais_types.h

@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AIS_TYPES_H_DEFINED
+#define AIS_TYPES_H_DEFINED
+
+typedef enum {
+	SA_FALSE = 0,
+	SA_TRUE = 1
+} SaBoolT;
+
+typedef char SaInt8T;
+typedef short SaInt16T;
+typedef long SaInt32T;
+typedef long long SaInt64T;
+
+typedef unsigned char SaUint8T;
+typedef unsigned short SaUint16T;
+typedef unsigned long SaUint32T;
+typedef unsigned long long SaUint64T;
+
+typedef SaInt64T SaTimeT;
+
+#define SA_MAX_NAME_LENGTH 256
+typedef struct {
+		SaUint16T length;
+		unsigned char value[SA_MAX_NAME_LENGTH];
+} SaNameT;
+
+typedef struct {
+	char releaseCode;
+	unsigned char major;
+	unsigned char minor;
+} SaVersionT;
+
+#define SA_TRACK_CURRENT 0x01
+#define SA_TRACK_CHANGES 0x02
+#define SA_TRACK_CHANGES_ONLY 0x04
+
+#define SA_CLM_LOCAL_NODE_ID 0x00
+
+typedef enum {
+	SA_DISPATCH_ONE = 1,
+	SA_DISPATCH_ALL = 2,
+	SA_DISPATCH_BLOCKING = 3
+} SaDispatchFlagsT;
+
+typedef enum {
+	SA_OK = 1,
+	SA_ERR_LIBRARY = 2,
+	SA_ERR_VERSION = 3,
+	SA_ERR_INIT = 4,
+	SA_ERR_TIMEOUT = 5,
+	SA_ERR_TRY_AGAIN = 6,
+	SA_ERR_INVALID_PARAM = 7,
+	SA_ERR_NO_MEMORY = 8,
+	SA_ERR_BAD_HANDLE = 9,
+	SA_ERR_BUSY = 10,
+	SA_ERR_ACCESS = 11,
+	SA_ERR_NOT_EXIST = 12,
+	SA_ERR_NAME_TOO_LONG = 13,
+	SA_ERR_EXIST = 14,
+	SA_ERR_NO_SPACE = 15,
+	SA_ERR_INTERRUPT = 16,
+	SA_ERR_SYSTEM = 17,
+	SA_ERR_NAME_NOT_FOUND = 18,
+	SA_ERR_NO_RESOURCES = 19,
+	SA_ERR_NOT_SUPPORTED = 20,
+	SA_ERR_BAD_OPERATION = 21,
+	SA_ERR_FAILED_OPERATION = 22,
+	SA_ERR_MESSAGE_ERROR = 23,
+	SA_ERR_NO_MESSAGE = 24,
+	SA_ERR_QUEUE_FULL = 25,
+	SA_ERR_QUEUE_NOT_AVAILABLE = 26,
+	SA_ERR_BAD_CHECKPOINT = 27,
+	SA_ERR_BAD_FLAGS = 28,
+	SA_ERR_SECURITY = 29
+} SaErrorT;
+
+typedef SaUint32T SaClmNodeIdT;
+
+typedef int SaClmHandleT;
+typedef int SaSelectionObjectT;
+typedef int SaInvocationT;
+
+#define SA_CLM_MAX_ADDRESS_LENGTH 64
+typedef struct {
+	SaUint8T length;
+	unsigned char value[SA_CLM_MAX_ADDRESS_LENGTH];
+} SaClmNodeAddressT;
+
+typedef struct {
+	SaClmNodeIdT nodeId;
+	SaClmNodeAddressT nodeAddress;
+	SaNameT nodeName;
+	SaNameT clusterName;
+	SaBoolT member;
+	SaTimeT bootTimestamp;
+} SaClmClusterNodeT;
+
+typedef enum {
+	SA_CLM_NODE_NO_CHANGE = 1,
+	SA_CLM_NODE_JOINED = 2,
+	SA_CLM_NODE_LEFT = 3
+} SaClmClusterChangesT;
+
+typedef struct {
+	SaClmClusterNodeT clusterNode;
+	SaClmClusterChangesT clusterChanges;
+} SaClmClusterNotificationT;
+
+/*
+ * AMF Definitions
+ */
+typedef int SaAmfHandleT;
+
+typedef enum {
+	SA_AMF_HEARTBEAT = 1,
+	SA_AMF_HEALTHCHECK_LEVEL1 = 2,
+	SA_AMF_HEALTHCHECK_LEVEL2 = 3,
+	SA_AMF_HEALTHCHECK_LEVEL3 = 4,
+} SaAmfHealthcheckT;
+
+typedef enum {
+	SA_AMF_OUT_OF_SERVICE = 1,
+	SA_AMF_IN_SERVICE = 2,
+	SA_AMF_STOPPING = 3
+} SaAmfReadinessStateT;
+
+typedef enum {
+	SA_AMF_ACTIVE = 1,
+	SA_AMF_STANDBY = 2,
+	SA_AMF_QUIESCED = 3
+} SaAmfHAStateT;
+
+typedef enum {
+	SA_AMF_COMPONENT_CAPABILITY_X_ACTIVE_AND_Y_STANDBY = 1,
+	SA_AMF_COMPONENT_CAPABILITY_X_ACTIVE_OR_Y_STANDBY = 2,
+	SA_AMF_COMPONENT_CAPABILITY_1_ACTIVE_OR_Y_STANDBY = 3,
+	SA_AMF_COMPONENT_CAPABILITY_1_ACTIVE_OR_1_STANDBY = 4,
+	SA_AMF_COMPONENT_CAPABILITY_X_ACTIVE = 5,
+	SA_AMF_COMPONENT_CAPABILITY_1_ACTIVE = 6,
+	SA_AMF_COMPONENT_CAPABILITY_NO_ACTIVE = 7,
+} SaAmfComponentCapabilityModelT;
+
+#define SA_AMF_CSI_ADD_NEW_ISTANCE 0x01
+#define SA_AMF_CSI_ALL_INSTANCES 0x02
+
+typedef SaUint32T SaAmfCSIFlagsT;
+
+typedef enum {
+	SA_AMF_CSI_NEW_ASSIGN = 1,
+	SA_AMF_CSI_QUIESCED = 2,
+	SA_AMF_CSI_NOT_QUIESCED = 3,
+	SA_AMF_CSI_STILL_ACTIVE = 4
+} SaAmfCSITransitionDescriptorT;
+
+typedef enum {
+	SA_AMF_RESET = 1,
+	SA_AMF_REBOOT = 2,
+	SA_AMF_POWER_ON = 3,
+	SA_AMF_POWER_OFF = 4
+} SaAmfExternalComponentActionT;
+
+#define SA_AMF_SWITCHOVER_OPERATION 0x01
+#define SA_AMF_SHUTDOWN_OPERATION 0x02
+typedef SaUint32T SaAmfPendingOperationFlagsT;
+
+typedef struct {
+	SaNameT compName;
+	SaAmfReadinessStateT readinessState;
+	SaAmfHAStateT haState;
+} SaAmfProtectionGroupMemberT;
+
+typedef enum {
+	SA_AMF_PROTECTION_GROUP_NO_CHANGE = 1,
+	SA_AMF_PROTECTION_GROUP_ADDED = 2,
+	SA_AMF_PROTECTION_GROUP_REMOVED = 3,
+	SA_AMF_PROTECTION_GROUP_STATE_CHANGE = 4
+} SaAmfProtectionGroupChangesT;
+
+typedef struct {
+	SaAmfProtectionGroupMemberT member;
+	SaAmfProtectionGroupChangesT change;
+} SaAmfProtectionGroupNotificationT;
+
+typedef enum {
+	SA_AMF_COMMUNICATION_ALARM_TYPE = 1,
+	SA_AMF_QUALITY_OF_SERVICE_ALARM_TYPE = 2,
+	SA_AMF_PROCESSING_ERROR_ALARM_TYPE = 3,
+	SA_AMF_EQUIPMENT_ALARM_TYPE = 4,
+	SA_AMF_ENVIRONMENTAL_ALARM_TYPE = 5
+} SaAmfErrorReportTypeT;
+
+typedef enum {
+	SA_AMF_APPLICATION_SUBSYSTEM_FAILURE = 1,
+	SA_AMF_BANDWIDTH_REDUCED = 2,
+	SA_AMF_CALL_ESTABLISHMENT_ERROR = 3,
+	SA_AMF_COMMUNICATION_PROTOCOL_ERROR = 4,
+	SA_AMF_COMMUNICATION_SUBSYSTEM_FAILURE = 5,
+	SA_AMF_CONFIGURATION_ERROR = 6,
+	SA_AMF_CONGESTION = 7,
+	SA_AMF_CORRUPT_DATA = 8,
+	SA_AMF_CPU_CYCLES_LIMIT_EXCEEDED = 9,
+	SA_AMF_EQUIPMENT_MALFUNCTION = 10,
+	SA_AMF_FILE_ERROR = 11,
+	SA_AMF_IO_DEVICE_ERROR = 12,
+	SA_AMF_LAN_ERROR, SA_AMF_OUT_OF_MEMORY = 13,
+	SA_AMF_PERFORMANCE_DEGRADED = 14,
+	SA_AMF_PROCESSOR_PROBLEM = 15,
+	SA_AMF_RECEIVE_FAILURE = 16,
+	SA_AMF_REMOTE_NODE_TRNASMISSION_ERROR = 17,
+	SA_AMF_RESOURCE_AT_OR_NEARING_CAPACITY = 18,
+	SA_AMF_RESPONSE_TIME_EXCESSIVE = 19,
+	SA_AMF_RETRANSMISSION_RATE_EXCESSIVE = 20,
+	SA_AMF_SOFTWARE_ERROR = 21,
+	SA_AMF_SOFTWARE_PROGRAM_ABNORMALLY_TERMINATED = 22,
+	SA_AMF_SOFTWARE_PROGRAM_ERROR = 23,
+	SA_AMF_STORAGE_CAPACITY_PROBLEM = 24,
+	SA_AMF_TIMING_PROBLEM = 25,
+	SA_AMF_UNDERLYING_REOUSRCE_UNAVAILABLE = 26,
+	SA_AMF_INTERNAL_ERROR = 27,
+	SA_AMF_NO_SERVICE_ERROR = 28,
+	SA_AMF_SOFTWARE_LIBRARY_ERROR = 29,
+	SA_AMF_NOT_RESPONDING = 30
+} SaAmfProbableCauseT;
+
+typedef enum {
+	SA_AMF_CLEARED = 1,
+	SA_AMF_NO_IMPACT = 2,
+	SA_AMF_INDETERMINATE = 3,
+	SA_AMF_CRITICAL = 4,
+	SA_AMF_MAJOR = 5,
+	SA_AMF_WEDGED_COMPONENT_FAILURE = 6,
+	SA_AMF_COMPONENT_TERMINATED_FAILURE = 7,
+	SA_AMF_NODE_FAILURE = 8,
+	SA_AMF_MINOR = 9,
+	SA_AMF_WARNING = 10
+} SaAmfErrorImpactAndSeverityT;
+
+typedef enum {
+	SA_AMF_NO_RECOMMENDATION = 1,
+	SA_AMF_INTERNALLY_RECOVERED = 2,
+	SA_AMF_COMPONENT_RESTART = 3,
+	SA_AMF_COMPONENT_FAILOVER = 4,
+	SA_AMF_NODE_SWITCHOVER = 5,
+	SA_AMF_NODE_FAILOVER = 6,
+	SA_AMF_NODE_FAILFAST = 7,
+	SA_AMF_CLUSTER_RESET = 8
+} SaAmfRecommendedRecoveryT;
+
+typedef struct {
+	SaAmfErrorReportTypeT errorReportType;
+	SaAmfProbableCauseT probableCause;
+	SaAmfErrorImpactAndSeverityT errorImpactAndSeverity;
+	SaAmfRecommendedRecoveryT recommendedRecovery;
+} SaAmfErrorDescriptorT;
+
+typedef int SaSizeT;
+#define SA_AMF_OPAQUE_BUFFER_SIZE_MAX 512
+typedef struct {
+	char *buffer;
+	SaSizeT size;
+} SaAmfErrorBufferT;
+
+typedef struct {
+	SaAmfErrorBufferT *specificProblem;
+	SaAmfErrorBufferT *additionalText;
+	SaAmfErrorBufferT *additionalInformation;
+} SaAmfAdditionalDataT;
+
+typedef int SaCkptHandleT;
+
+typedef int SaCkptCheckpointHandleT;
+
+typedef int SaCkptSectionIteratorT;
+
+#define SA_CKPT_WR_ALL_REPLICAS 0x1
+#define SA_CKPT_WR_ACTIVE_REPLICA 0x2
+#define SA_CKPT_WR_ACTIVE_REPLICA_WEAK 0x4
+
+typedef SaUint32T SaCkptCheckpointCreationFlagsT;
+
+typedef struct {
+	SaCkptCheckpointCreationFlagsT creationFlags;
+	SaSizeT checkpointSize;
+	SaTimeT retentionDuration;
+	SaUint32T maxSections;
+	SaSizeT maxSectionSize;
+	SaUint32T maxSectionIdSize;
+} SaCkptCheckpointCreationAttributesT;
+
+#define SA_CKPT_CHECKPOINT_READ 0x1
+#define SA_CKPT_CHECKPOINT_WRITE 0x2
+#define SA_CKPT_CHECKPOINT_COLOCATED 0x4
+typedef SaUint32T SaCkptCheckpointOpenFlagsT;
+
+#define SA_CKPT_DEFAULT_SECTION_ID { 0, 0 }
+#define SA_CKPT_GENERATED_SECTION_ID { 0, 0 }
+
+typedef struct {
+	SaUint8T *id;
+	SaUint32T idLen;
+} SaCkptSectionIdT;
+
+typedef struct {
+	SaCkptSectionIdT *sectionId;
+	SaTimeT expirationTime;
+} SaCkptSectionCreationAttributesT;
+
+typedef enum {
+	SA_CKPT_SECTION_VALID = 1,
+	SA_CKPT_SECTION_CORRUPTED = 2
+} SaCkptSectionStateT;
+
+typedef struct {
+	SaCkptSectionIdT sectionId;
+	SaTimeT expirationTime;
+	SaSizeT sectionSize;
+	SaCkptSectionStateT sectionState;
+	SaTimeT lastUpdate;
+} SaCkptSectionDescriptorT;
+
+typedef enum {
+	SA_CKPT_SECTIONS_FOREVER = 1,
+	SA_CKPT_SECTIONS_LEQ_EXPIRATION_TIME = 2,
+	SA_CKPT_SECTIONS_GEQ_EXPIRATION_TIME = 3,
+	SA_CKPT_SECTIONS_CORRUPTED = 4,
+	SA_CKPT_SECTIONS_ANY = 5,
+} SaCkptSectionsChosenT;
+
+// SaOffsetT is not defined in the specification ERRATA
+typedef SaUint32T SaOffsetT;
+
+typedef struct {
+	SaCkptSectionIdT sectionId;
+	void *dataBuffer;
+	SaSizeT dataSize;
+	SaOffsetT dataOffset;
+	SaSizeT readSize;
+} SaCkptIOVectorElementT;
+
+typedef struct {
+	SaCkptCheckpointCreationAttributesT checkpointCreationAttributes;
+	SaUint32T numberOfSections;
+	SaUint32T memoryUsed;
+} SaCkptCheckpointStatusT;
+
+typedef void (*SaCkptCheckpointOpenCallbackT) (
+	SaInvocationT invocation,	
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	SaErrorT error);
+
+typedef void (*SaCkptCheckpointSynchronizeCallbackT) (
+	SaInvocationT invocation,	
+	SaErrorT error);
+
+typedef struct {
+	SaCkptCheckpointOpenCallbackT saCkptCheckpointOpenCallback;
+	SaCkptCheckpointSynchronizeCallbackT saCkptCheckpointSynchronizeCallback;
+} SaCkptCallbacksT;
+
+#endif /* AIS_TYPES_H_DEFINED */

+ 75 - 0
include/list.h

@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This implementation uses the same API as the linux kernel to
+ * help us kernel developers easily use the list primatives
+ */
+#ifndef LIST_H_DEFINED
+#define LIST_H_DEFINED
+
+struct list_head {
+	struct list_head *next;
+	struct list_head *prev;
+};
+
+#define DECLARE_LIST_INIT(name) \
+    struct list_head name = { &(name), &(name) }
+
+static void inline list_init (struct list_head *head)
+{
+	head->next = head;
+	head->prev = head;
+};
+
+static void inline list_add (struct list_head *new, struct list_head *head)
+{
+	head->next->prev = new;
+	new->next = head->next;
+	new->prev = head;
+	head->next = new;
+}
+static void inline list_del (struct list_head *remove)
+{
+	remove->next->prev = remove->prev;
+	remove->prev->next = remove->next;
+#ifdef DEBUG
+	remove->next = (struct list_head *)0xdeadb33f;
+	remove->prev = (struct list_head *)0xdeadb33f;
+#endif
+}
+
+#define list_entry(ptr,type,member)\
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+#endif /* LIST_H_DEFINED */

+ 163 - 0
include/queue.h

@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef QUEUE_H_DEFINED
+#define QUEUE_H_DEFINED
+
+#include "assert.h"
+
+struct queue {
+	int head;
+	int tail;
+	int used;
+	int usedhw;
+	int size;
+	void *items;
+	int size_per_item;
+	int iterator;
+};
+
+static inline int queue_init (struct queue *queue, int queue_items, int size_per_item) {
+	queue->head = 0;
+	queue->tail = queue_items - 1;
+	queue->used = 0;
+	queue->usedhw = 0;
+	queue->size = queue_items;
+	queue->size_per_item = size_per_item;
+
+	queue->items = malloc (queue_items * size_per_item);
+	if (queue->items == 0) {
+		return (-ENOMEM);
+	}
+	memset (queue->items, 0, queue_items * size_per_item);
+	return (0);
+}
+
+static inline int queue_reinit (struct queue *queue)
+{
+	queue->head = 0;
+	queue->tail = queue->size - 1;
+	queue->used = 0;
+	queue->usedhw = 0;
+
+	memset (queue->items, 0, queue->size * queue->size_per_item);
+	return (0);
+}
+
+static inline void queue_free (struct queue *queue) {
+	free (queue->items);
+}
+
+static inline int queue_is_full (struct queue *queue) {
+	return (queue->size - 1 == queue->used);
+}
+
+static inline int queue_is_empty (struct queue *queue) {
+	return (queue->used == 0);
+}
+
+static inline void queue_item_add (struct queue *queue, void *item)
+{
+	char *queue_item;
+	int queue_position;
+
+	queue_position = queue->head;
+	queue_item = queue->items;
+	queue_item += queue_position * queue->size_per_item;
+	memcpy (queue_item, item, queue->size_per_item);
+
+	assert (queue->tail != queue->head);
+
+	queue->head = (queue->head + 1) % queue->size;
+	queue->used++;
+	if (queue->used > queue->usedhw) {
+		queue->usedhw = queue->used;
+	}
+}
+
+static inline void *queue_item_get (struct queue *queue)
+{
+	char *queue_item;
+	int queue_position;
+
+	queue_position = (queue->tail + 1) % queue->size;
+	queue_item = queue->items;
+	queue_item += queue_position * queue->size_per_item;
+	return ((void *)queue_item);
+}
+
+static inline void queue_item_remove (struct queue *queue) {
+	queue->tail = (queue->tail + 1) % queue->size;
+	
+	assert (queue->tail != queue->head);
+
+	queue->used--;
+}
+
+static inline void queue_items_remove (struct queue *queue, int rel_count)
+{
+	queue->tail = (queue->tail + rel_count) % queue->size;
+	
+	assert (queue->tail != queue->head);
+
+	queue->used -= rel_count;
+}
+
+
+static inline void queue_item_iterator_init (struct queue *queue)
+{
+	queue->iterator = (queue->tail + 1) % queue->size;
+}
+
+static inline void *queue_item_iterator_get (struct queue *queue)
+{
+	char *queue_item;
+	int queue_position;
+
+	queue_position = (queue->iterator) % queue->size;
+	if (queue->iterator == queue->head) {
+		return (0);
+	}
+	queue_item = queue->items;
+	queue_item += queue_position * queue->size_per_item;
+	return ((void *)queue_item);
+}
+
+static inline int queue_item_iterator_next (struct queue *queue)
+{
+	queue->iterator = (queue->iterator + 1) % queue->size;
+
+	return (queue->iterator == queue->head);
+}
+
+#endif /* QUEUE_H_DEFINED */

+ 185 - 0
include/sq.h

@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef SORTQUEUE_H_DEFINED
+#define SORTQUEUE_H_DEFINED
+
+#include "errno.h"
+
+struct sq {
+	int head;
+	int size;
+	void *items;
+	unsigned char *items_inuse;
+	int size_per_item;
+	int head_seqid;
+	int item_count;
+};
+
+static inline int sq_init (
+	struct sq *sq,
+	int item_count,
+	int size_per_item,
+	int head_seqid)
+{
+	sq->head = 0;
+	sq->size = item_count;
+	sq->size_per_item = size_per_item;
+	sq->head_seqid = head_seqid;
+	sq->item_count = item_count;
+
+	sq->items = (void *)malloc (item_count * size_per_item);
+	if (sq->items == 0) {
+		return (-ENOMEM);
+	}
+	memset (sq->items, 0, item_count * size_per_item);
+
+	sq->items_inuse = (void *)malloc (item_count * sizeof (char));
+	memset (sq->items_inuse, 0, item_count * sizeof (char));
+	return (0);
+}
+
+static inline void sq_reinit (struct sq *sq, int head_seqid)
+{
+	sq->head = 0;
+	sq->head_seqid = head_seqid;
+
+	memset (sq->items, 0, sq->item_count * sq->size_per_item);
+	memset (sq->items_inuse, 0, sq->item_count * sizeof (char));
+}
+
+static inline void sq_free (struct sq *sq) {
+	free (sq->items);
+	free (sq->items_inuse);
+}
+
+static inline int sq_item_add (
+	struct sq *sq,
+	void *item,
+	int seqid)
+{
+	char *sq_item;
+	int sq_position;
+
+	if (seqid - sq->head_seqid >= sq->size) {
+		return E2BIG;
+	}
+	sq_position = (sq->head + seqid - sq->head_seqid) % sq->size;
+//printf ("item add %d %d %d\n", sq_position, seqid, sq->head_seqid);
+	sq_item = sq->items;
+	sq_item += sq_position * sq->size_per_item;
+	memcpy (sq_item, item, sq->size_per_item);
+	sq->items_inuse[sq_position] = 1;
+
+	return (0);
+}
+
+static inline int sq_item_inuse (
+	struct sq *sq,
+	int seq_id) {
+
+	int sq_position;
+
+	sq_position = (sq->head - sq->head_seqid + seq_id) % sq->size;
+//printf ("in use %d\n", sq_position);
+	return (sq->items_inuse[sq_position]);
+}
+
+static inline int sq_size_get (
+	struct sq *sq)
+{
+	return sq->size;
+}
+
+static inline int sq_item_get (
+	struct sq *sq,
+	int seq_id,
+	void **sq_item_out)
+{
+	char *sq_item;
+	int sq_position;
+
+if (seq_id == -1) {
+	return (ENOENT);
+}
+	assert (seq_id < (sq->head_seqid + sq->size));
+	sq_position = (sq->head - sq->head_seqid + seq_id) % sq->size;
+//printf ("ITEMGET %d %d %d %d\n", sq_position, sq->head, sq->head_seqid, seq_id);
+assert (sq_position >= 0);
+//printf ("itme get in use %d\n", sq_position);
+	if (sq->items_inuse[sq_position] == 0) {
+//printf ("ENOENT\n");
+		return (ENOENT);
+	}
+	sq_item = sq->items;
+	sq_item += sq_position * sq->size_per_item;
+	*sq_item_out = sq_item;
+	return (0);
+}
+
+static inline void sq_items_release (struct sq *sq, int seqid)
+{
+	int oldhead;
+	char *sq_item;
+
+	if (seqid < sq->head_seqid) {
+//printf ("%d %d\n", seqid, sq->head_seqid);
+		return;
+	}
+//printf ("releasing %d\n", seqid);
+
+	oldhead = sq->head;
+
+//printf ("before sq->head %d\n", sq->head);
+	sq->head = (sq->head + seqid - sq->head_seqid + 1) % sq->size;
+//printf ("after sq->head %d\n", sq->head);
+	if ((oldhead + seqid - sq->head_seqid + 1) > sq->size) {
+//printf ("memset 1\n");
+//printf ("%d %d %d %d\n", seqid, sq->head_seqid, sq->head, sq->size);
+		memset (&sq->items_inuse[oldhead], 0, sq->size - oldhead);
+		memset (sq->items_inuse, 0, sq->head * sizeof (char));
+//printf ("SIZEOF %d %d\n", sq->head, sq->head * sizeof (char));
+//		memset (sq->items, 0, (sq->head) * (sq->size_per_item));
+	} else {
+assert (seqid - sq->head_seqid + 1);
+//printf ("memset 2\n");
+//printf ("releasing %d for %d\n", oldhead, seqid - sq->head_seqid + 1);
+		memset (&sq->items_inuse[oldhead - 1], 0, (seqid - sq->head_seqid + 2) * sizeof (char));
+	sq_item = sq->items;
+	sq_item += oldhead * sq->size_per_item;
+//		memset (sq_item[oldhead], 0, (seqid - sq->head_seqid + 1) * (sq->size_per_item));
+	}
+	sq->head_seqid = seqid + 1;
+}
+
+#endif /* SORTQUEUE_H_DEFINED */

+ 28 - 0
init/ais

@@ -0,0 +1,28 @@
+#! /bin/sh
+#
+# Application Interface Specification Startup 
+# chkconfig: 2345 20 20
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
+test -f /usr/sbin/aisexec | exit 0
+
+case "$1" in 
+	start)
+ 		echo -n "Starting Application Interface Specification Executive: " 
+		start-stop-daemon --start --quiet --exec /usr/sbin/aisexec
+		echo "."
+
+		;;
+       	stop)
+		echo -n "Stopping Application Interface Specification Executive: " 
+		start-stop-daemon --stop --quiet --exec /usr/sbin/aisexec
+		echo "."
+               	;;
+       	*)
+               echo "Usage: /etc/init.d/ais {start|stop}" >&2
+               exit 1
+               ;;
+esac
+
+

+ 56 - 0
lib/Makefile

@@ -0,0 +1,56 @@
+# Copyright (c) 2002-2004 MontaVista Software, Inc.
+# 
+# All rights reserved.
+# 
+# This software licensed under BSD license, the text of which follows:
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+# - Redistributions of source code must retain the above copyright notice,
+#   this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright notice,
+#   this list of conditions and the following disclaimer in the documentation
+#   and/or other materials provided with the distribution.
+# - Neither the name of the MontaVista Software, Inc. nor the names of its
+#   contributors may be used to endorse or promote products derived from this
+#   software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+# Production mode flags
+#CFLAGS = -O3 -Wall
+#LDFLAGS = 
+
+# Debug mode flags
+CFLAGS = -g -fPIC -DDEBUG -Wall
+LDFLAGS = -g
+
+# Profile mode flags
+#CFLAGS = -O3 -pg -fPIC -DDEBUG
+#LDFLAGS = -pg
+
+CFLAGS += -fPIC
+
+all:libais.a libais.so.1.0
+
+libais.a: util.o amf.o clm.o ckpt.o
+	$(AR) -rc libais.a util.o amf.o clm.o ckpt.o
+
+libais.so.1.0: util.o amf.o clm.o ckpt.o
+	$(CC) -shared -Wl,-soname,libais.so.1 util.o amf.o clm.o ckpt.o -o $@
+	rm -f libais.so.1 libais.so
+	ln -s libais.so.1.0 libais.so.1
+	ln -s libais.so.1.0 libais.so
+	
+clean:
+	rm -f *.o libais.so* libais.a

+ 938 - 0
lib/amf.c

@@ -0,0 +1,938 @@
+
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * thread locking model is as follows
+ *
+ *	APIs that use handles:
+ *
+ *	Every handle database has a lock.
+ *	Each interface started with SaAmfInitialize has a lock.
+ *	Handle database lock is taken.
+ *	amfInstance lock is taken.
+ *	Handle database lock is released early.
+ *	amfInstance lock is released after amfInstance is out of use.
+ *
+ *	Finalize API:
+ *	Handle database lock is taken
+ *	amf instance lock is taken
+ *	handle is removed
+ *	amf instance lock is released
+ *	handle database lock is released
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/un.h>
+
+#include "../include/ais_types.h"
+#include "../include/ais_amf.h"
+#include "../include/ais_msg.h"
+#include "util.h"
+
+struct message_overlay {
+	struct message_header header;
+	char data[4096];
+};
+
+/*
+ * Data structure for instance data
+ */
+struct amfInstance {
+	int fd;
+	SaAmfCallbacksT callbacks;
+	struct queue inq;
+	SaNameT compName;
+	int compRegistered;
+	struct message_overlay message;
+	pthread_mutex_t mutex;
+};
+#define AMFINSTANCE_MUTEX_OFFSET offset_of(struct amfInstance, mutex)
+
+/*
+ * All instances in one database
+ */
+static struct saHandleDatabase amfHandleDatabase = {
+	handleCount: 0,
+	handles: 0,
+	generation: 0,
+	mutex: PTHREAD_MUTEX_INITIALIZER
+};
+
+/*
+ * Versions supported
+ */
+static SaVersionT amfVersionsSupported[] = {
+	{ 'A', 1, 1 },
+	{ 'a', 1, 1 }
+};
+
+static struct saVersionDatabase amfVersionDatabase = {
+	sizeof (amfVersionsSupported) / sizeof (SaVersionT),
+	amfVersionsSupported
+};
+	
+/*
+ * Implementation
+ */
+SaErrorT
+saAmfInitialize (
+	SaAmfHandleT *amfHandle,
+	const SaAmfCallbacksT *amfCallbacks,
+	const SaVersionT *version)
+{
+	struct amfInstance *amfInstance;
+	SaErrorT error = SA_OK;
+
+	error = saVersionVerify (&amfVersionDatabase, version);
+	if (error != SA_OK) {
+		goto error_nofree;
+	}
+	
+	error = saHandleCreate (&amfHandleDatabase, (void *)&amfInstance,
+		sizeof (struct amfInstance), amfHandle);
+	if (error != SA_OK) {
+		goto error_nofree;
+	}
+
+	/*
+	 * An inq is needed to store async messages while waiting for a 
+	 * sync response
+	 */
+	error = saQueueInit (&amfInstance->inq, 512, sizeof (void *));
+	if (error != SA_OK) {
+		goto error_free;
+	}
+
+	error = saServiceConnect (&amfInstance->fd, MESSAGE_REQ_AMF_INIT);
+	if (error != SA_OK) {
+		goto error_free2;
+	}
+
+	memcpy (&amfInstance->callbacks, amfCallbacks, sizeof (SaAmfCallbacksT));
+
+	pthread_mutex_init (&amfInstance->mutex, NULL);
+
+	return (SA_OK);
+
+error_free2:
+	free (amfInstance->inq.items);
+error_free:
+	saHandleRemove (&amfHandleDatabase, *amfHandle);
+error_nofree:
+	return (error);
+}
+
+SaErrorT
+saAmfSelectionObjectGet (
+	const SaAmfHandleT *amfHandle,
+	SaSelectionObjectT *selectionObject)
+{
+	struct amfInstance *amfInstance;
+	SaErrorT error;
+
+	error = saHandleConvert (&amfHandleDatabase, *amfHandle, (void *)&amfInstance, AMFINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	*selectionObject = amfInstance->fd;
+
+	pthread_mutex_unlock (&amfInstance->mutex);
+	return (SA_OK);
+}
+
+SaErrorT
+saAmfDispatch (
+	const SaAmfHandleT *amfHandle,
+	SaDispatchFlagsT dispatchFlags)
+{
+	struct pollfd ufds;
+	int timeout = -1;
+	SaErrorT error;
+	int dispatch_avail;
+	struct amfInstance *amfInstance;
+	SaAmfCallbacksT callbacks;
+	struct res_amf_healthcheckcallback *res_amf_healthcheckcallback;
+	struct res_amf_readinessstatesetcallback *res_amf_readinessstatesetcallback;
+	struct res_amf_csisetcallback *res_amf_csisetcallback;
+	struct res_amf_csiremovecallback *res_amf_csiremovecallback;
+	struct res_amf_protectiongrouptrackcallback *res_amf_protectiongrouptrackcallback;
+	struct message_header **queue_msg;
+	struct message_header *msg;
+	int empty;
+	int ignore_dispatch = 0;
+	int cont = 1; /* always continue do loop except when set to 0 */
+	int handle_verified = 0;
+	int poll_fd;
+	unsigned int gen_first;
+	unsigned int gen_second;
+
+	/*
+	 * Timeout instantly for SA_DISPATCH_ALL
+	 */
+	if (dispatchFlags == SA_DISPATCH_ALL) {
+		timeout = 0;
+	}
+
+	do {
+		/*
+		 * If flags are SA_DISPATCH_BLOCKING and handle has been
+		 * verified, return SA_OK because a Finalize has been
+		 * called.  Else return error from saHandleConvert
+		 */
+		error = saHandleConvert (&amfHandleDatabase, *amfHandle, (void *)&amfInstance, AMFINSTANCE_MUTEX_OFFSET, &gen_first);
+		if (error != SA_OK) {
+			return (handle_verified ? SA_OK : error);
+		}
+		handle_verified = 1;
+
+		poll_fd = amfInstance->fd;
+
+		/*
+		 * Unlock mutex for potentially long wait in select.  If fd
+		* is closed by amfFinalize in select, select will return
+		 */
+		pthread_mutex_unlock (&amfInstance->mutex);
+		
+		/*
+		 * Read data directly from socket
+		 */
+		ufds.fd = poll_fd;
+		ufds.events = POLLIN;
+		ufds.revents = 0;
+
+		error = saPollRetry (&ufds, 1, timeout);
+		if (error != SA_OK) {
+			goto error_nounlock;
+		}
+
+		dispatch_avail = ufds.revents & POLLIN;
+		if (dispatch_avail == 0 && dispatchFlags == SA_DISPATCH_ALL) {
+			break; /* exit do while cont is 1 loop */
+		} else
+		if (dispatch_avail == 0) {
+			continue; /* next select */
+		}
+
+		/*
+		 * Re-verify amfHandle
+		 */
+		error = saHandleConvert (&amfHandleDatabase, *amfHandle, (void *)&amfInstance, AMFINSTANCE_MUTEX_OFFSET, &gen_second);
+		if (error != SA_OK) {
+			return (handle_verified ? SA_OK : error);
+		}
+
+		/*
+		 * Handle has been removed and then reallocated
+		 */
+		if (gen_first != gen_second) {
+			return (SA_OK);
+		}
+		saQueueIsEmpty(&amfInstance->inq, &empty);
+		if (empty == 0) {
+			/*
+			 * Queue is not empty, read data from queue
+			 */
+			saQueueItemGet (&amfInstance->inq, (void *)&queue_msg);
+			msg = *queue_msg;
+			memcpy (&amfInstance->message, msg, msg->size);
+			saQueueItemRemove (&amfInstance->inq);
+		} else {
+			/*
+			 * Queue empty, read response from socket
+			 */
+			error = saRecvRetry (amfInstance->fd, &amfInstance->message.header, sizeof (struct message_header), MSG_WAITALL | MSG_NOSIGNAL);
+			if (error != SA_OK) {
+				goto error_unlock;
+			}
+			if (amfInstance->message.header.size > sizeof (struct message_header)) {
+				error = saRecvRetry (amfInstance->fd, &amfInstance->message.data,
+					amfInstance->message.header.size - sizeof (struct message_header), MSG_WAITALL | MSG_NOSIGNAL);
+				if (error != SA_OK) {
+					goto error_unlock;
+				}
+			}
+		}
+		/*
+		 * Make copy of callbacks, unlock instance, and call callback
+		 * A risk of this dispatch method is that the callback routines may
+		 * operate at the same time that amfFinalize has been called.
+		 */
+		memcpy (&callbacks, &amfInstance->callbacks, sizeof (SaAmfCallbacksT));
+
+		pthread_mutex_unlock (&amfInstance->mutex);
+
+		/*
+		 * Dispatch incoming response
+		 */
+		switch (amfInstance->message.header.id) {
+		case MESSAGE_RES_AMF_ACTIVATEPOLL:
+			/*
+			 * This is a do nothing message which the node executive sends
+			 * to activate the file handle in poll when the library has
+			 * queued a message into amfHandle->inq
+			 * The dispatch is ignored for the following two cases:
+			 * 1) setting of timeout to zero for the DISPATCH_ALL case
+			 * 2) expiration of the do loop for the DISPATCH_ONE case
+			 */
+			ignore_dispatch = 1;
+			break;
+
+		case MESSAGE_RES_AMF_HEALTHCHECKCALLBACK:
+			res_amf_healthcheckcallback = (struct res_amf_healthcheckcallback *)&amfInstance->message;
+			pthread_mutex_unlock (&amfInstance->mutex);
+
+			callbacks.saAmfHealthcheckCallback (
+				res_amf_healthcheckcallback->invocation,
+				&res_amf_healthcheckcallback->compName,
+				res_amf_healthcheckcallback->checkType);
+			break;
+
+		case MESSAGE_RES_AMF_READINESSSTATESETCALLBACK:
+			res_amf_readinessstatesetcallback = (struct res_amf_readinessstatesetcallback *)&amfInstance->message;
+			callbacks.saAmfReadinessStateSetCallback (
+				res_amf_readinessstatesetcallback->invocation,
+				&res_amf_readinessstatesetcallback->compName,
+				res_amf_readinessstatesetcallback->readinessState);
+			break;
+
+		case MESSAGE_RES_AMF_CSISETCALLBACK:
+			res_amf_csisetcallback = (struct res_amf_csisetcallback *)&amfInstance->message;
+			callbacks.saAmfCSISetCallback (
+				res_amf_csisetcallback->invocation,
+				&res_amf_csisetcallback->compName,
+				&res_amf_csisetcallback->csiName,
+				res_amf_csisetcallback->csiFlags,
+				&res_amf_csisetcallback->haState,
+				&res_amf_csisetcallback->activeCompName,
+				res_amf_csisetcallback->transitionDescriptor);
+			break;
+
+		case MESSAGE_RES_AMF_CSIREMOVECALLBACK:
+			res_amf_csiremovecallback = (struct res_amf_csiremovecallback *)&amfInstance->message;
+			callbacks.saAmfCSIRemoveCallback (
+				res_amf_csiremovecallback->invocation,
+				&res_amf_csiremovecallback->compName,
+				&res_amf_csiremovecallback->csiName,
+				&res_amf_csiremovecallback->csiFlags);
+			break;
+
+		case MESSAGE_RES_AMF_PROTECTIONGROUPTRACKCALLBACK:
+			res_amf_protectiongrouptrackcallback = (struct res_amf_protectiongrouptrackcallback *)&amfInstance->message;
+			memcpy (res_amf_protectiongrouptrackcallback->notificationBufferAddress,
+				res_amf_protectiongrouptrackcallback->notificationBuffer,
+				res_amf_protectiongrouptrackcallback->numberOfItems * sizeof (SaAmfProtectionGroupNotificationT));
+			callbacks.saAmfProtectionGroupTrackCallback(
+				&res_amf_protectiongrouptrackcallback->csiName,
+				res_amf_protectiongrouptrackcallback->notificationBufferAddress,
+				res_amf_protectiongrouptrackcallback->numberOfItems,
+				res_amf_protectiongrouptrackcallback->numberOfMembers,
+				res_amf_protectiongrouptrackcallback->error);
+			break;
+
+		default:
+			error = SA_ERR_LIBRARY;	
+			goto error_nounlock;
+			break;
+		}
+
+		/*
+		 * Determine if more messages should be processed
+		 */
+		switch (dispatchFlags) {
+		case SA_DISPATCH_ONE:
+			if (ignore_dispatch) {
+				ignore_dispatch = 0;
+			} else {
+				cont = 0;
+			}
+			break;
+		case SA_DISPATCH_ALL:
+			if (ignore_dispatch) {
+				ignore_dispatch = 0;
+			}
+			break;
+		case SA_DISPATCH_BLOCKING:
+			break;
+		}
+	} while (cont);
+
+	return (error);
+
+error_unlock:
+	pthread_mutex_unlock (&amfInstance->mutex);
+error_nounlock:
+	return (error);
+}
+
+SaErrorT
+saAmfFinalize (
+	const SaAmfHandleT *amfHandle)
+{
+	struct amfInstance *amfInstance;
+	SaErrorT error;
+
+	error = saHandleConvert (&amfHandleDatabase, *amfHandle, (void *)&amfInstance, AMFINSTANCE_MUTEX_OFFSET | HANDLECONVERT_DONTUNLOCKDB, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	shutdown (amfInstance->fd, 0);
+	close (amfInstance->fd);
+	free (amfInstance->inq.items);
+
+	error = saHandleRemove (&amfHandleDatabase, *amfHandle);
+
+	pthread_mutex_unlock (&amfInstance->mutex);
+
+	saHandleUnlockDatabase (&amfHandleDatabase);
+
+	return (error);
+}
+
+SaErrorT
+saAmfComponentRegister (
+	const SaAmfHandleT *amfHandle,
+	const SaNameT *compName,
+	const SaNameT *proxyCompName)
+{
+	struct amfInstance *amfInstance;
+	SaErrorT error;
+	struct req_lib_amf_componentregister req_lib_amf_componentregister;
+	struct res_lib_amf_componentregister *res_lib_amf_componentregister;
+
+	req_lib_amf_componentregister.header.magic = MESSAGE_MAGIC;
+	req_lib_amf_componentregister.header.size = sizeof (struct req_lib_amf_componentregister);
+	req_lib_amf_componentregister.header.id = MESSAGE_REQ_AMF_COMPONENTREGISTER;
+	memcpy (&req_lib_amf_componentregister.compName, compName, sizeof (SaNameT));
+	if (proxyCompName) {
+		memcpy (&req_lib_amf_componentregister.proxyCompName, proxyCompName, sizeof (SaNameT));
+	} else {
+		memset (&req_lib_amf_componentregister.proxyCompName, 0, sizeof (SaNameT));
+	}
+
+	error = saHandleConvert (&amfHandleDatabase, *amfHandle, (void *)&amfInstance, AMFINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	error = saSendRetry (amfInstance->fd, &req_lib_amf_componentregister, sizeof (struct req_lib_amf_componentregister), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_unlock;
+	}
+
+	/*
+	 * Search for COMPONENTREGISTER responses and queue any
+	 * messages that dont match in this handle's inq.
+	 * This must be done to avoid dropping async messages
+	 * during this sync message retrieval
+	 */
+	error = saRecvQueue (amfInstance->fd, &amfInstance->message,
+		&amfInstance->inq, MESSAGE_RES_AMF_COMPONENTREGISTER);
+	if (error != SA_OK) {
+		goto error_unlock;
+	}
+
+	res_lib_amf_componentregister = (struct res_lib_amf_componentregister *)&amfInstance->message;
+	if (res_lib_amf_componentregister->error == SA_OK) {
+		amfInstance->compRegistered = 1;
+		memcpy (&amfInstance->compName, compName, sizeof (SaNameT));
+	}
+
+	error = res_lib_amf_componentregister->error;
+
+error_unlock:
+	pthread_mutex_unlock (&amfInstance->mutex);
+	return (error);
+}
+
+SaErrorT
+saAmfComponentUnregister (
+	const SaAmfHandleT *amfHandle,
+	const SaNameT *compName,
+	const SaNameT *proxyCompName)
+{
+	struct req_lib_amf_componentunregister req_lib_amf_componentunregister;
+	struct res_lib_amf_componentunregister *res_lib_amf_componentunregister;
+	struct amfInstance *amfInstance;
+	SaErrorT error;
+
+	req_lib_amf_componentunregister.header.magic = MESSAGE_MAGIC;
+	req_lib_amf_componentunregister.header.size = sizeof (struct req_lib_amf_componentunregister);
+	req_lib_amf_componentunregister.header.id = MESSAGE_REQ_AMF_COMPONENTUNREGISTER;
+	memcpy (&req_lib_amf_componentunregister.compName, compName, sizeof (SaNameT));
+	if (proxyCompName) {
+		memcpy (&req_lib_amf_componentunregister.proxyCompName, proxyCompName, sizeof (SaNameT));
+	} else {
+		memset (&req_lib_amf_componentunregister.proxyCompName, 0, sizeof (SaNameT));
+	}	
+
+	error = saHandleConvert (&amfHandleDatabase, *amfHandle, (void *)&amfInstance, AMFINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	error = saSendRetry (amfInstance->fd, &req_lib_amf_componentunregister,
+		sizeof (struct req_lib_amf_componentunregister), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_unlock;
+	}
+
+	/*
+	 * Search for COMPONENTUNREGISTER responses and queue any
+	 * messages that dont match in this handle's inq.
+	 * This must be done to avoid dropping async messages
+	 * during this sync message retrieval
+	 */
+	error = saRecvQueue (amfInstance->fd, &amfInstance->message,
+		&amfInstance->inq, MESSAGE_RES_AMF_COMPONENTUNREGISTER);
+	if (error != SA_OK) {
+		goto error_unlock;
+	}
+	res_lib_amf_componentunregister = (struct res_lib_amf_componentunregister *)&amfInstance->message;
+	if (res_lib_amf_componentunregister->error == SA_OK) {
+		amfInstance->compRegistered = 0;
+	}
+	error = res_lib_amf_componentunregister->error;
+
+error_unlock:
+	pthread_mutex_unlock (&amfInstance->mutex);
+	return (error);
+}
+
+SaErrorT
+saAmfCompNameGet (
+	const SaAmfHandleT *amfHandle,
+	SaNameT *compName)
+{
+	struct amfInstance *amfInstance;
+	SaErrorT error;
+
+	error = saHandleConvert (&amfHandleDatabase, *amfHandle, (void *)&amfInstance, AMFINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	if (amfInstance->compRegistered == 0) {
+		return (SA_ERR_NOT_EXIST);
+	}
+	memcpy (compName, &amfInstance->compName, sizeof (SaNameT));
+
+	pthread_mutex_unlock (&amfInstance->mutex);
+	return (SA_OK);
+}
+
+SaErrorT
+saAmfReadinessStateGet (
+	const SaNameT *compName,
+	SaAmfReadinessStateT *readinessState)
+{
+	int fd;
+	SaErrorT error;
+	struct req_amf_readinessstateget req_amf_readinessstateget;
+	struct res_amf_readinessstateget *res_amf_readinessstateget;
+	struct message_overlay message;
+
+	error = saServiceConnect (&fd, MESSAGE_REQ_AMF_INIT);
+	if (error != SA_OK) {
+		goto exit_noclose;
+	}
+	req_amf_readinessstateget.header.magic = MESSAGE_MAGIC;
+	req_amf_readinessstateget.header.id = MESSAGE_RES_AMF_READINESSSTATEGET;
+	req_amf_readinessstateget.header.size = sizeof (struct req_amf_readinessstateget);
+	memcpy (&req_amf_readinessstateget.compName, compName, sizeof (SaNameT));
+
+	error = saSendRetry (fd, &req_amf_readinessstateget,
+		sizeof (struct req_amf_readinessstateget), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto exit_close;
+	}
+
+	error = saRecvQueue (fd, &message, 0, MESSAGE_RES_AMF_READINESSSTATEGET);
+	res_amf_readinessstateget = (struct res_amf_readinessstateget *)&message;
+	if (error == SA_OK) {
+		memcpy (readinessState, &res_amf_readinessstateget->readinessState, 
+			sizeof (SaAmfReadinessStateT));
+		error = res_amf_readinessstateget->error;
+	}
+		
+exit_close:
+	close (fd);
+exit_noclose:
+	return (error);
+}
+
+SaErrorT
+saAmfStoppingComplete (
+	SaInvocationT invocation,
+	SaErrorT error)
+{
+	struct req_amf_stoppingcomplete req_amf_stoppingcomplete;
+	int fd;
+	SaErrorT errorResult;
+
+	errorResult = saServiceConnect (&fd, MESSAGE_REQ_AMF_INIT);
+	if (errorResult != SA_OK) {
+		goto exit_noclose;
+	}
+	req_amf_stoppingcomplete.header.magic = MESSAGE_MAGIC;
+	req_amf_stoppingcomplete.header.id = MESSAGE_REQ_AMF_STOPPINGCOMPLETE;
+	req_amf_stoppingcomplete.header.size = sizeof (struct req_amf_stoppingcomplete);
+	req_amf_stoppingcomplete.invocation = invocation;
+	req_amf_stoppingcomplete.error = error;
+	errorResult = saSendRetry (fd, &req_amf_stoppingcomplete,
+		sizeof (struct req_amf_stoppingcomplete), MSG_NOSIGNAL);
+
+	close (fd);
+
+exit_noclose:
+	return (errorResult);
+}
+
+SaErrorT
+saAmfHAStateGet (
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	SaAmfHAStateT *haState) {
+
+	struct req_amf_hastateget req_amf_hastateget;
+	struct res_amf_hastateget *res_amf_hastateget;
+	int fd;
+	SaErrorT error;
+	struct message_overlay message;
+
+	error = saServiceConnect (&fd, MESSAGE_REQ_AMF_INIT);
+	if (error != SA_OK) {
+		goto exit_noclose;
+	}
+	req_amf_hastateget.header.magic = MESSAGE_MAGIC;
+	req_amf_hastateget.header.id = MESSAGE_REQ_AMF_HASTATEGET;
+	req_amf_hastateget.header.size = sizeof (struct req_amf_hastateget);
+	memcpy (&req_amf_hastateget.compName, compName, sizeof (SaNameT));
+	memcpy (&req_amf_hastateget.csiName, csiName, sizeof (SaNameT));
+
+	error = saSendRetry (fd, &req_amf_hastateget,
+			sizeof (struct req_amf_hastateget), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto exit_close;
+	}
+
+	error = saRecvQueue (fd, &message, 0, MESSAGE_RES_AMF_HASTATEGET);
+	res_amf_hastateget = (struct res_amf_hastateget *)&message;
+	if (error != SA_OK) {
+		goto exit_close;
+	}
+	
+	error = res_amf_hastateget->error;
+	if (error == SA_OK) {
+		memcpy (haState, &res_amf_hastateget->haState, sizeof (SaAmfHAStateT));
+	}
+
+exit_close:
+	close (fd);
+exit_noclose:
+	return (error);
+}
+
+SaErrorT
+saAmfProtectionGroupTrackStart (
+	const SaAmfHandleT *amfHandle,
+	const SaNameT *csiName,
+	SaUint8T trackFlags,
+	const SaAmfProtectionGroupNotificationT *notificationBuffer,
+	SaUint32T numberOfItems) {
+
+	struct amfInstance *amfInstance;
+	struct req_amf_protectiongrouptrackstart req_amf_protectiongrouptrackstart;
+	struct res_amf_protectiongrouptrackstart *res_amf_protectiongrouptrackstart;
+	SaErrorT error;
+
+	req_amf_protectiongrouptrackstart.header.magic = MESSAGE_MAGIC;
+	req_amf_protectiongrouptrackstart.header.size = sizeof (struct req_amf_protectiongrouptrackstart);
+	req_amf_protectiongrouptrackstart.header.id = MESSAGE_REQ_AMF_PROTECTIONGROUPTRACKSTART;
+	memcpy (&req_amf_protectiongrouptrackstart.csiName, csiName, sizeof (SaNameT));
+	req_amf_protectiongrouptrackstart.trackFlags = trackFlags;
+	req_amf_protectiongrouptrackstart.notificationBufferAddress = (SaAmfProtectionGroupNotificationT *)notificationBuffer;
+	req_amf_protectiongrouptrackstart.numberOfItems = numberOfItems;
+
+	error = saHandleConvert (&amfHandleDatabase, *amfHandle, (void *)&amfInstance, AMFINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	error = saSendRetry (amfInstance->fd, &req_amf_protectiongrouptrackstart,
+		sizeof (struct req_amf_protectiongrouptrackstart), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_unlock;
+	}
+
+	error = saRecvQueue (amfInstance->fd, &amfInstance->message,
+		&amfInstance->inq, MESSAGE_RES_AMF_PROTECTIONGROUPTRACKSTART);
+
+	pthread_mutex_unlock (&amfInstance->mutex);
+
+	res_amf_protectiongrouptrackstart = (struct res_amf_protectiongrouptrackstart *)&amfInstance->message;
+
+	if (error == SA_OK) {
+		return (res_amf_protectiongrouptrackstart->error);
+	}
+
+	return (error);
+
+error_unlock:
+	pthread_mutex_unlock (&amfInstance->mutex);
+
+	return (error);
+}
+
+SaErrorT
+saAmfProtectionGroupTrackStop (
+	const SaAmfHandleT *amfHandle,
+	const SaNameT *csiName) {
+
+	struct amfInstance *amfInstance;
+	struct req_amf_protectiongrouptrackstop req_amf_protectiongrouptrackstop;
+	struct res_amf_protectiongrouptrackstop *res_amf_protectiongrouptrackstop;
+	SaErrorT error;
+
+	req_amf_protectiongrouptrackstop.header.magic = MESSAGE_MAGIC;
+	req_amf_protectiongrouptrackstop.header.size = sizeof (struct req_amf_protectiongrouptrackstop);
+	req_amf_protectiongrouptrackstop.header.id = MESSAGE_REQ_AMF_PROTECTIONGROUPTRACKSTOP;
+	memcpy (&req_amf_protectiongrouptrackstop.csiName, csiName, sizeof (SaNameT));
+
+	error = saHandleConvert (&amfHandleDatabase, *amfHandle, (void *)&amfInstance, AMFINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	error = saSendRetry (amfInstance->fd, &req_amf_protectiongrouptrackstop,
+		sizeof (struct req_amf_protectiongrouptrackstop), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_unlock;
+	}
+
+	error = saRecvQueue (amfInstance->fd, &amfInstance->message,
+		&amfInstance->inq, MESSAGE_RES_AMF_PROTECTIONGROUPTRACKSTOP);
+
+	pthread_mutex_unlock (&amfInstance->mutex);
+
+	res_amf_protectiongrouptrackstop = (struct res_amf_protectiongrouptrackstop *)&amfInstance->message;
+
+	if (error == SA_OK) {
+		return (res_amf_protectiongrouptrackstop->error);
+	}
+
+	return (error);
+
+error_unlock:
+	pthread_mutex_unlock (&amfInstance->mutex);
+	return (error);
+}
+
+SaErrorT
+saAmfErrorReport (
+	const SaNameT *reportingComponent,
+	const SaNameT *erroneousComponent,
+	SaTimeT errorDetectionTime,
+	const SaAmfErrorDescriptorT *errorDescriptor,
+	const SaAmfAdditionalDataT *additionalData) {
+
+	struct req_lib_amf_errorreport req_lib_amf_errorreport;
+	struct res_lib_amf_errorreport *res_lib_amf_errorreport;
+	struct message_overlay message;
+	int fd;
+	SaErrorT error;
+
+	error = saServiceConnect (&fd, MESSAGE_REQ_AMF_INIT);
+	if (error != SA_OK) {
+		goto exit_noclose;
+	}
+	req_lib_amf_errorreport.header.magic = MESSAGE_MAGIC;
+	req_lib_amf_errorreport.header.id = MESSAGE_REQ_AMF_ERRORREPORT;
+	req_lib_amf_errorreport.header.size = sizeof (struct req_lib_amf_errorreport);
+	memcpy (&req_lib_amf_errorreport.reportingComponent, reportingComponent, sizeof (SaNameT));
+	memcpy (&req_lib_amf_errorreport.erroneousComponent, erroneousComponent, sizeof (SaNameT));
+	req_lib_amf_errorreport.errorDetectionTime = errorDetectionTime;
+	memcpy (&req_lib_amf_errorreport.errorDescriptor,
+		errorDescriptor, sizeof (SaAmfErrorDescriptorT));
+	/* TODO this is wrong, and needs some thinking
+	memcpy (&req_lib_amf_errorreport.additionalData,
+		additionalData, sizeof (SaAmfAdditionalDataT));
+	*/
+
+	error = saSendRetry (fd, &req_lib_amf_errorreport,
+		sizeof (struct req_lib_amf_errorreport), MSG_NOSIGNAL);
+
+	/*
+	 * Get response from executive and respond to user application
+	 */
+	error = saRecvQueue (fd, &message, 0, MESSAGE_RES_AMF_ERRORREPORT);
+	if (error != SA_OK) {
+		goto exit_close;
+	}
+
+	res_lib_amf_errorreport = (struct res_lib_amf_errorreport *)&message;
+	error = res_lib_amf_errorreport->error;
+
+exit_close:
+	close (fd);
+exit_noclose:
+	return (error);
+}
+
+SaErrorT
+saAmfErrorCancelAll (
+	const SaNameT *compName) {
+
+	struct req_lib_amf_errorcancelall req_lib_amf_errorcancelall;
+	struct res_lib_amf_errorcancelall *res_lib_amf_errorcancelall;
+	struct message_overlay message;
+	int fd;
+	SaErrorT error;
+
+	error = saServiceConnect (&fd, MESSAGE_REQ_AMF_INIT);
+	if (error != SA_OK) {
+		goto exit_noclose;
+	}
+	req_lib_amf_errorcancelall.header.magic = MESSAGE_MAGIC;
+	req_lib_amf_errorcancelall.header.id = MESSAGE_REQ_AMF_ERRORCANCELALL;
+	req_lib_amf_errorcancelall.header.size = sizeof (struct req_lib_amf_errorcancelall);
+	memcpy (&req_lib_amf_errorcancelall.compName, compName, sizeof (SaNameT));
+
+	error = saSendRetry (fd, &req_lib_amf_errorcancelall,
+		sizeof (struct req_lib_amf_errorcancelall), MSG_NOSIGNAL);
+
+	/*
+	 * Get response from executive and respond to user application
+	 */
+	error = saRecvQueue (fd, &message, 0, MESSAGE_RES_AMF_ERRORCANCELALL);
+	if (error != SA_OK) {
+		goto exit_close;
+	}
+
+	res_lib_amf_errorcancelall = (struct res_lib_amf_errorcancelall *)&message;
+	error = res_lib_amf_errorcancelall->error;
+
+exit_close:
+	close (fd);
+exit_noclose:
+	return (error);
+}
+
+SaErrorT
+saAmfComponentCapabilityModelGet (
+	const SaNameT *compName,
+	SaAmfComponentCapabilityModelT *componentCapabilityModel)
+{
+
+	int fd;
+	SaErrorT error;
+	struct req_amf_componentcapabilitymodelget req_amf_componentcapabilitymodelget;
+	struct res_amf_componentcapabilitymodelget *res_amf_componentcapabilitymodelget;
+	struct message_overlay message;
+
+	error = saServiceConnect (&fd, MESSAGE_REQ_AMF_INIT);
+	if (error != SA_OK) {
+		goto exit_noclose;
+	}
+	req_amf_componentcapabilitymodelget.header.magic = MESSAGE_MAGIC;
+	req_amf_componentcapabilitymodelget.header.id = MESSAGE_REQ_AMF_COMPONENTCAPABILITYMODELGET;
+	req_amf_componentcapabilitymodelget.header.size = sizeof (struct req_amf_componentcapabilitymodelget);
+	memcpy (&req_amf_componentcapabilitymodelget.compName, compName, sizeof (SaNameT));
+
+	error = saSendRetry (fd, &req_amf_componentcapabilitymodelget,
+		sizeof (struct req_amf_componentcapabilitymodelget), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto exit_close;
+	}
+
+	error = saRecvQueue (fd, &message, 0, MESSAGE_RES_AMF_COMPONENTCAPABILITYMODELGET);
+	res_amf_componentcapabilitymodelget = (struct res_amf_componentcapabilitymodelget *)&message;
+	if (error == SA_OK) {
+		memcpy (componentCapabilityModel,
+			&res_amf_componentcapabilitymodelget->componentCapabilityModel, 
+			sizeof (SaAmfComponentCapabilityModelT));
+		error = res_amf_componentcapabilitymodelget->error;
+	}
+		
+exit_close:
+	close (fd);
+exit_noclose:
+	return (error);
+}
+
+SaErrorT
+saAmfPendingOperationGet (
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT *pendingOperationFlags) {
+
+	*pendingOperationFlags = 0;	
+	return (SA_OK);
+}
+
+SaErrorT
+saAmfResponse (
+	SaInvocationT invocation,
+	SaErrorT error)
+{
+	struct req_amf_response req_amf_response;
+	int fd;
+	SaErrorT errorResult;
+
+	errorResult = saServiceConnect (&fd, MESSAGE_REQ_AMF_INIT);
+	if (errorResult != SA_OK) {
+		goto exit_noclose;
+	}
+	req_amf_response.header.magic = MESSAGE_MAGIC;
+	req_amf_response.header.id = MESSAGE_REQ_AMF_RESPONSE;
+	req_amf_response.header.size = sizeof (struct req_amf_response);
+	req_amf_response.invocation = invocation;
+	req_amf_response.error = error;
+	errorResult = saSendRetry (fd, &req_amf_response,
+		sizeof (struct req_amf_response), MSG_NOSIGNAL);
+
+	close (fd);
+
+exit_noclose:
+	return (errorResult);
+}

+ 1251 - 0
lib/ckpt.c

@@ -0,0 +1,1251 @@
+
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/un.h>
+
+#include "../include/list.h"
+#include "../include/ais_types.h"
+#include "../include/ais_ckpt.h"
+#include "../include/ais_msg.h"
+#include "util.h"
+
+struct message_overlay {
+	struct message_header header;
+	char data[4096];
+};
+
+/*
+ * Data structure for instance data
+ */
+struct ckptInstance {
+	int fd;
+	struct queue inq;
+	SaCkptCallbacksT callbacks;
+	pthread_mutex_t mutex;
+};
+#define CKPTINSTANCE_MUTEX_OFFSET HANDLECONVERT_NOLOCKING
+
+struct ckptCheckpointInstance {
+	int fd;
+	SaNameT checkpointName;
+	SaUint32T maxSectionIdSize;
+	pthread_mutex_t mutex;
+};
+//#define CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET offset_of(struct ckptCheckpointInstance, mutex)
+#define CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET_DEMO offset_of(struct ckptCheckpointInstance, mutex)
+#define CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET HANDLECONVERT_NOLOCKING
+
+struct ckptSectionIteratorInstance {
+	int fd;
+	struct list_head sectionIdListHead;
+	SaUint32T maxSectionIdSize;
+	pthread_mutex_t mutex;
+};
+
+//#define CKPTSECTIONITERATORINSTANCE_MUTEX_OFFSET offset_of(struct ckptSectionIteratorInstance, mutex)
+#define CKPTSECTIONITERATORINSTANCE_MUTEX_OFFSET HANDLECONVERT_NOLOCKING
+
+/*
+ * All CKPT instances in this database
+ */
+static struct saHandleDatabase ckptHandleDatabase = {
+    handleCount: 0,
+    handles: 0,
+    generation: 0,
+    mutex: PTHREAD_MUTEX_INITIALIZER
+};
+
+/*
+ *  All Checkpoint instances in this database
+ */
+static struct saHandleDatabase ckptCheckpointHandleDatabase = {
+    handleCount: 0,
+    handles: 0,
+    generation: 0,
+    mutex: PTHREAD_MUTEX_INITIALIZER
+};
+
+/*
+ * All section iterators in this database
+ */
+static struct saHandleDatabase ckptSectionIteratorHandleDatabase = {
+    handleCount: 0,
+    handles: 0,
+    generation: 0,
+    mutex: PTHREAD_MUTEX_INITIALIZER
+};
+
+/*
+ * Versions supported
+ */
+static SaVersionT ckptVersionsSupported[] = {
+	{ 'A', 1, 1 },
+	{ 'a', 1, 1 }
+};
+
+static struct saVersionDatabase ckptVersionDatabase = {
+	sizeof (ckptVersionsSupported) / sizeof (SaVersionT),
+	ckptVersionsSupported
+};
+
+
+//static struct timeval zerousec = {
+//	0, 0
+//};
+
+/*
+ * Implementation
+ */
+SaErrorT
+saCkptInitialize (
+	SaCkptHandleT *ckptHandle,
+	const SaCkptCallbacksT *callbacks,
+	const SaVersionT *version)
+{
+	struct ckptInstance *ckptInstance;
+	SaErrorT error = SA_OK;
+
+	error = saVersionVerify (&ckptVersionDatabase, version);
+	if (error != SA_OK) {
+		goto error_nofree;
+	}
+
+	error = saHandleCreate (&ckptHandleDatabase, (void *)&ckptInstance,
+		sizeof (struct ckptInstance), ckptHandle);
+	if (error != SA_OK) {
+		goto error_nofree;
+	}
+
+	/*
+	 * An inq is needed to store async messages while waiting for a 
+	 * sync response
+	 */
+	error = saQueueInit (&ckptInstance->inq, 512, sizeof (void *));
+	if (error != SA_OK) {
+		goto error_free;
+	}
+
+	error = saServiceConnect (&ckptInstance->fd, MESSAGE_REQ_CKPT_CHECKPOINT_INIT);
+	if (error != SA_OK) {
+		goto error_free2;
+	}
+
+	memcpy (&ckptInstance->callbacks, callbacks, sizeof (SaCkptCallbacksT));
+
+	pthread_mutex_init (&ckptInstance->mutex, NULL);
+
+	return (SA_OK);
+error_free2:
+	free (ckptInstance->inq.items);
+error_free:
+	saHandleRemove (&ckptHandleDatabase, *ckptHandle);
+error_nofree:
+	return (error);
+}
+
+SaErrorT
+saCkptSelectionObjectGet (
+	const SaCkptHandleT *ckptHandle,
+	SaSelectionObjectT *selectionObject)
+{
+	struct ckptInstance *ckptInstance;
+	SaErrorT error;
+
+	error = saHandleConvert (&ckptHandleDatabase, *ckptHandle, (void *)&ckptInstance, CKPTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	*selectionObject = ckptInstance->fd;
+	return (SA_OK);
+}
+
+#ifdef COMPILE_OUT
+SaErrorT
+saCkptDispatch (
+	const SaCkptHandleT *ckptHandle,
+	SaDispatchFlagsT dispatchFlags)
+{
+	fd_set read_fds;
+	SaErrorT error;
+	int dispatch_avail;
+	struct timeval *timeout = 0;
+	struct ckptInstance *ckptInstance;
+	struct message_header **queue_msg;
+	struct message_header *msg;
+	int empty;
+	int ignore_dispatch = 0;
+	int cont = 1; /* always continue do loop except when set to 0 */
+
+	error = saHandleConvert (&ckptHandleDatabase, *ckptHandle, (void *)&ckptInstance, CKPTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	/*
+	 * Timeout instantly for SA_DISPATCH_ALL
+	 */
+	if (dispatchFlags & SA_DISPATCH_ALL) {
+		timeout = &zerousec;
+	}
+
+	do {
+		/*
+		 * Read data directly from socket
+		 */
+		FD_ZERO (&read_fds);
+		FD_SET (ckptInstance->fd, &read_fds);
+
+		error = saSelectRetry (ckptInstance->fd + 1, &read_fds, 0, 0, timeout);
+		if (error != SA_OK) {
+			goto error_exit;
+		}
+
+		dispatch_avail = FD_ISSET (ckptInstance->fd, &read_fds);
+		if (dispatch_avail == 0 && dispatchFlags == SA_DISPATCH_ALL) {
+			break; /* exit do while cont is 1 loop */
+		} else
+		if (dispatch_avail == 0) {
+			continue; /* next select */
+		}
+
+		saQueueIsEmpty(&ckptInstance->inq, &empty);
+		if (empty == 0) {
+			/*
+			 * Queue is not empty, read data from queue
+			 */
+			saQueueItemGet (&ckptInstance->inq, (void **)&queue_msg);
+			msg = *queue_msg;
+			memcpy (&ckptInstance->message, msg, msg->size);
+			saQueueItemRemove (&ckptInstance->inq);
+		} else {
+			/*
+			 * Queue empty, read response from socket
+			 */
+			error = saRecvRetry (ckptInstance->fd, &ckptInstance->message.header, sizeof (struct message_header), MSG_WAITALL | MSG_NOSIGNAL);
+			if (error != SA_OK) {
+				goto error_exit;
+			}
+			if (ckptInstance->message.header.size > sizeof (struct message_header)) {
+				error = saRecvRetry (ckptInstance->fd, &ckptInstance->message.data,
+					ckptInstance->message.header.size - sizeof (struct message_header),
+					MSG_WAITALL | MSG_NOSIGNAL);
+				if (error != SA_OK) {
+					goto error_exit;
+				}
+			}
+		}
+
+		/*
+		 * Dispatch incoming response
+		 */
+		switch (ckptInstance->message.header.id) {
+#ifdef COMPILE_OUT
+		case MESSAGE_RES_CKPT_CHECKPOINT_ACTIVATEPOLL:
+			/*
+			 * This is a do nothing message which the node executive sends
+			 * to activate the file handle in poll when the library has
+			 * queued a message into amfHandle->inq
+			 * The dispatch is ignored for the following two cases:
+			 * 1) setting of timeout to zero for the DISPATCH_ALL case
+			 * 2) expiration of the do loop for the DISPATCH_ONE case
+			 */
+			ignore_dispatch = 1;
+			break;
+
+		case MESSAGE_RES_CKPT_CHECKPOINT_HEALTHCHECKCALLBACK:
+			res_amf_healthcheckcallback = (struct res_amf_healthcheckcallback *)&ckptInstance->message;
+			amfInstance->callbacks.saAmfHealthcheckCallback (
+				res_amf_healthcheckcallback->invocation,
+				&res_amf_healthcheckcallback->compName,
+				res_amf_healthcheckcallback->checkType);
+			break;
+
+		case MESSAGE_RES_CKPT_CHECKPOINT_READINESSSTATESETCALLBACK:
+			res_amf_readinessstatesetcallback = (struct res_amf_readinessstatesetcallback *)&ckptInstance->message;
+			amfInstance->callbacks.saAmfReadinessStateSetCallback (
+				res_amf_readinessstatesetcallback->invocation,
+				&res_amf_readinessstatesetcallback->compName,
+				res_amf_readinessstatesetcallback->readinessState);
+			break;
+
+		case MESSAGE_RES_CKPT_CHECKPOINT_CSISETCALLBACK:
+			res_amf_csisetcallback = (struct res_amf_csisetcallback *)&ckptInstance->message;
+			amfInstance->callbacks.saAmfCSISetCallback (
+				res_amf_csisetcallback->invocation,
+				&res_amf_csisetcallback->compName,
+				&res_amf_csisetcallback->csiName,
+				res_amf_csisetcallback->csiFlags,
+				&res_amf_csisetcallback->haState,
+				&res_amf_csisetcallback->activeCompName,
+				res_amf_csisetcallback->transitionDescriptor);
+			break;
+
+		case MESSAGE_RES_CKPT_CHECKPOINT_CSIREMOVECALLBACK:
+			res_amf_csiremovecallback = (struct res_amf_csiremovecallback *)&ckptInstance->message;
+			amfInstance->callbacks.saAmfCSIRemoveCallback (
+				res_amf_csiremovecallback->invocation,
+				&res_amf_csiremovecallback->compName,
+				&res_amf_csiremovecallback->csiName,
+				&res_amf_csiremovecallback->csiFlags);
+			break;
+
+		case MESSAGE_RES_CKPT_CHECKPOINT_PROTECTIONGROUPTRACKCALLBACK:
+			res_amf_protectiongrouptrackcallback = (struct res_amf_protectiongrouptrackcallback *)&ckptInstance->message;
+			memcpy (res_amf_protectiongrouptrackcallback->notificationBufferAddress,
+				res_amf_protectiongrouptrackcallback->notificationBuffer,
+				res_amf_protectiongrouptrackcallback->numberOfItems * sizeof (SaAmfProtectionGroupNotificationT));
+			amfInstance->callbacks.saAmfProtectionGroupTrackCallback(
+				&res_amf_protectiongrouptrackcallback->csiName,
+				res_amf_protectiongrouptrackcallback->notificationBufferAddress,
+				res_amf_protectiongrouptrackcallback->numberOfItems,
+				res_amf_protectiongrouptrackcallback->numberOfMembers,
+				res_amf_protectiongrouptrackcallback->error);
+			break;
+
+#endif
+		default:
+			// TODO
+			break;
+		}
+		/*
+		 * Determine if more messages should be processed
+		 */
+		switch (dispatchFlags) {
+		case SA_DISPATCH_ONE:
+			if (ignore_dispatch) {
+				ignore_dispatch = 0;
+			} else {
+				cont = 0;
+			}
+			break;
+		case SA_DISPATCH_ALL:
+			if (ignore_dispatch) {
+				ignore_dispatch = 0;
+			}
+			break;
+		case SA_DISPATCH_BLOCKING:
+			break;
+		}
+	} while (cont);
+
+error_exit:
+	return (error);
+}
+#endif
+
+SaErrorT
+saCkptFinalize (
+	const SaCkptHandleT *ckptHandle)
+{
+	struct ckptInstance *ckptInstance;
+	SaErrorT error;
+
+	error = saHandleConvert (&ckptHandleDatabase, *ckptHandle, (void *)&ckptInstance, CKPTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	close (ckptInstance->fd);
+	free (ckptInstance->inq.items);
+	saHandleRemove (&ckptHandleDatabase, *ckptHandle);
+	return (SA_OK);
+}
+
+SaErrorT
+saCkptCheckpointOpen (
+	const SaNameT *checkpointName,
+	const SaCkptCheckpointCreationAttributesT *checkpointCreationAttributes,
+	SaCkptCheckpointOpenFlagsT checkpointOpenFlags,
+	SaTimeT timeout,
+	SaCkptCheckpointHandleT *checkpointHandle)
+{
+	SaErrorT error;
+	struct ckptCheckpointInstance *ckptCheckpointInstance;
+	struct req_lib_ckpt_checkpointopen req_lib_ckpt_checkpointopen;
+	struct res_lib_ckpt_checkpointopen res_lib_ckpt_checkpointopen;
+
+	error = saHandleCreate (&ckptCheckpointHandleDatabase, (void *)&ckptCheckpointInstance,
+		sizeof (struct ckptCheckpointInstance), checkpointHandle);
+	if (error != SA_OK) {
+		goto error_nofree;
+	}
+
+	ckptCheckpointInstance->maxSectionIdSize =
+		checkpointCreationAttributes->maxSectionIdSize;
+
+	error = saServiceConnect (&ckptCheckpointInstance->fd, MESSAGE_REQ_CKPT_CHECKPOINT_INIT);
+	if (error != SA_OK) {
+		goto error_free;
+	}
+
+	pthread_mutex_init (&ckptCheckpointInstance->mutex, NULL);
+
+	req_lib_ckpt_checkpointopen.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_checkpointopen.header.size = sizeof (struct req_lib_ckpt_checkpointopen);
+	req_lib_ckpt_checkpointopen.header.id = MESSAGE_REQ_CKPT_CHECKPOINT_CHECKPOINTOPEN;
+	memcpy (&req_lib_ckpt_checkpointopen.checkpointName, checkpointName, sizeof (SaNameT));
+	memcpy (&ckptCheckpointInstance->checkpointName, checkpointName, sizeof (SaNameT));
+	memcpy (&req_lib_ckpt_checkpointopen.checkpointCreationAttributes,
+		checkpointCreationAttributes,
+		sizeof (SaCkptCheckpointCreationAttributesT));
+	req_lib_ckpt_checkpointopen.checkpointOpenFlags = checkpointOpenFlags;
+
+	error = saSendRetry (ckptCheckpointInstance->fd, &req_lib_ckpt_checkpointopen,
+		sizeof (struct req_lib_ckpt_checkpointopen), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_close;
+	}
+
+	error = saRecvRetry (ckptCheckpointInstance->fd, &res_lib_ckpt_checkpointopen,
+		sizeof (struct res_lib_ckpt_checkpointopen), MSG_WAITALL | MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_close;
+	}
+	
+	if (res_lib_ckpt_checkpointopen.error != SA_OK) {
+		error = res_lib_ckpt_checkpointopen.error;
+		goto error_close;
+	}
+
+	pthread_mutex_init (&ckptCheckpointInstance->mutex, NULL);
+
+error_nofree:
+	return (error);
+error_close:
+	close (ckptCheckpointInstance->fd);
+error_free:
+	saHandleRemove (&ckptCheckpointHandleDatabase, *checkpointHandle);
+	return (error);
+}
+
+SaErrorT
+saCkptCheckpointOpenAsync (
+	const SaCkptHandleT *ckptHandle,
+	SaInvocationT invocation,	
+	const SaNameT *checkpointName,
+	const SaCkptCheckpointCreationAttributesT *checkpointCreationAttributes,
+	SaCkptCheckpointOpenFlagsT checkpointOpenFlags)
+{
+	struct ckptInstance *ckptInstance;
+	SaErrorT error;
+	struct req_lib_ckpt_checkpointopenasync req_lib_ckpt_checkpointopenasync;
+
+	error = saHandleConvert (&ckptHandleDatabase, *ckptHandle, (void *)&ckptInstance, CKPTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	req_lib_ckpt_checkpointopenasync.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_checkpointopenasync.header.size = sizeof (struct req_lib_ckpt_checkpointopenasync);
+	req_lib_ckpt_checkpointopenasync.header.id = MESSAGE_REQ_CKPT_CHECKPOINT_CHECKPOINTOPENASYNC;
+	req_lib_ckpt_checkpointopenasync.invocation = invocation;
+	memcpy (&req_lib_ckpt_checkpointopenasync.checkpointName, checkpointName, sizeof (SaNameT));
+	memcpy (&req_lib_ckpt_checkpointopenasync.checkpointCreationAttributes,
+		checkpointCreationAttributes,
+		sizeof (SaCkptCheckpointCreationAttributesT));
+	
+	req_lib_ckpt_checkpointopenasync.checkpointOpenFlags = checkpointOpenFlags;
+
+        error = saSendRetry (ckptInstance->fd, &req_lib_ckpt_checkpointopenasync,
+		sizeof (struct req_lib_ckpt_checkpointopenasync), MSG_NOSIGNAL);
+
+	return (error);
+}
+
+SaErrorT
+saCkptCheckpointClose (
+	const SaCkptCheckpointHandleT *checkpointHandle)
+{
+	SaErrorT error;
+	struct ckptCheckpointInstance *ckptCheckpointInstance;
+
+	error = saHandleConvert (&ckptCheckpointHandleDatabase, *checkpointHandle,
+		(void *)&ckptCheckpointInstance, CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	close (ckptCheckpointInstance->fd);
+	error = saHandleRemove (&ckptCheckpointHandleDatabase, *checkpointHandle);
+
+error_exit:
+	return (error);
+}
+
+SaErrorT
+saCkptCheckpointUnlink (
+	const SaNameT *checkpointName)
+{
+	SaErrorT error;
+	struct req_lib_ckpt_checkpointunlink req_lib_ckpt_checkpointunlink;
+	struct res_lib_ckpt_checkpointunlink res_lib_ckpt_checkpointunlink;
+	int fd;
+
+	error = saServiceConnect (&fd, MESSAGE_REQ_CKPT_CHECKPOINT_INIT);
+	if (error != SA_OK) {
+		goto exit_noclose;
+	}
+
+	req_lib_ckpt_checkpointunlink.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_checkpointunlink.header.size = sizeof (struct req_lib_ckpt_checkpointunlink);
+	req_lib_ckpt_checkpointunlink.header.id = MESSAGE_REQ_CKPT_CHECKPOINT_CHECKPOINTUNLINK;
+	memcpy (&req_lib_ckpt_checkpointunlink.checkpointName, checkpointName, sizeof (SaNameT));
+
+
+	error = saSendRetry (fd, &req_lib_ckpt_checkpointunlink, sizeof (struct req_lib_ckpt_checkpointunlink), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto exit_close;
+	}
+
+	error = saRecvQueue (fd, &res_lib_ckpt_checkpointunlink,
+		0, MESSAGE_RES_CKPT_CHECKPOINT_CHECKPOINTUNLINK);
+
+exit_close:
+	close (fd);
+	return (error == SA_OK ? res_lib_ckpt_checkpointunlink.error : error);
+exit_noclose:
+	return (error);
+}
+
+SaErrorT
+saCkptCheckpointRetentionDurationSet (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	SaTimeT retentionDuration)
+{
+	SaErrorT error;
+	struct ckptCheckpointInstance *ckptCheckpointInstance;
+	struct req_lib_ckpt_checkpointretentiondurationset req_lib_ckpt_checkpointretentiondurationset;
+
+	error = saHandleConvert (&ckptCheckpointHandleDatabase, *checkpointHandle, (void *)&ckptCheckpointInstance, CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	req_lib_ckpt_checkpointretentiondurationset.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_checkpointretentiondurationset.header.size = sizeof (struct req_lib_ckpt_checkpointretentiondurationset);
+	req_lib_ckpt_checkpointretentiondurationset.header.id = MESSAGE_REQ_CKPT_CHECKPOINT_CHECKPOINTRETENTIONDURATIONSET;
+
+	error = saSendRetry (ckptCheckpointInstance->fd, &req_lib_ckpt_checkpointretentiondurationset, sizeof (struct req_lib_ckpt_checkpointretentiondurationset), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+error_exit:
+	return (error);
+}
+
+SaErrorT
+saCkptActiveCheckpointSet (
+	const SaCkptCheckpointHandleT *checkpointHandle)
+{
+	SaErrorT error;
+	struct ckptCheckpointInstance *ckptCheckpointInstance;
+	struct req_lib_ckpt_activecheckpointset req_lib_ckpt_activecheckpointset;
+	struct res_lib_ckpt_activecheckpointset res_lib_ckpt_activecheckpointset;
+
+	error = saHandleConvert (&ckptCheckpointHandleDatabase, *checkpointHandle, (void *)&ckptCheckpointInstance, CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	req_lib_ckpt_activecheckpointset.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_activecheckpointset.header.size = sizeof (struct req_lib_ckpt_activecheckpointset);
+	req_lib_ckpt_activecheckpointset.header.id = MESSAGE_REQ_CKPT_CHECKPOINT_ACTIVECHECKPOINTSET;
+
+	error = saSendRetry (ckptCheckpointInstance->fd, &req_lib_ckpt_activecheckpointset,
+		sizeof (struct req_lib_ckpt_activecheckpointset), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	error = saRecvQueue (ckptCheckpointInstance->fd, &res_lib_ckpt_activecheckpointset, 0, MESSAGE_RES_CKPT_CHECKPOINT_ACTIVECHECKPOINTSET);
+
+error_exit:
+	return (error == SA_OK ? res_lib_ckpt_activecheckpointset.error : error);
+}
+
+SaErrorT
+saCkptCheckpointStatusGet (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	SaCkptCheckpointStatusT *checkpointStatus)
+{
+	SaErrorT error;
+	struct ckptCheckpointInstance *ckptCheckpointInstance;
+	struct req_lib_ckpt_checkpointstatusget req_lib_ckpt_checkpointstatusget;
+	struct res_lib_ckpt_checkpointstatusget res_lib_ckpt_checkpointstatusget;
+
+	error = saHandleConvert (&ckptCheckpointHandleDatabase, *checkpointHandle,
+		(void *)&ckptCheckpointInstance, CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	req_lib_ckpt_checkpointstatusget.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_checkpointstatusget.header.size = sizeof (struct req_lib_ckpt_checkpointstatusget);
+	req_lib_ckpt_checkpointstatusget.header.id = MESSAGE_REQ_CKPT_CHECKPOINT_CHECKPOINTSTATUSGET;
+
+	error = saSendRetry (ckptCheckpointInstance->fd, &req_lib_ckpt_checkpointstatusget,
+		sizeof (struct req_lib_ckpt_checkpointstatusget), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	error = saRecvQueue (ckptCheckpointInstance->fd, &res_lib_ckpt_checkpointstatusget,
+		0, MESSAGE_RES_CKPT_CHECKPOINT_CHECKPOINTSTATUSGET);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	memcpy (checkpointStatus,
+		&res_lib_ckpt_checkpointstatusget.checkpointStatus,
+		sizeof (SaCkptCheckpointStatusT));
+
+error_exit:
+	return (error);
+}
+
+SaErrorT
+saCkptSectionCreate (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	SaCkptSectionCreationAttributesT *sectionCreationAttributes,
+	const void *initialData,
+	SaUint32T initialDataSize)
+{
+	SaErrorT error;
+	struct ckptCheckpointInstance *ckptCheckpointInstance;
+	struct req_lib_ckpt_sectioncreate req_lib_ckpt_sectioncreate;
+	struct res_lib_ckpt_sectioncreate res_lib_ckpt_sectioncreate;
+
+	error = saHandleConvert (&ckptCheckpointHandleDatabase, *checkpointHandle,
+		(void *)&ckptCheckpointInstance, CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	req_lib_ckpt_sectioncreate.header.magic = MESSAGE_MAGIC;
+
+	req_lib_ckpt_sectioncreate.header.size =
+		sizeof (struct req_lib_ckpt_sectioncreate) +
+		sectionCreationAttributes->sectionId->idLen +
+		initialDataSize; 
+
+	req_lib_ckpt_sectioncreate.header.id = MESSAGE_REQ_CKPT_CHECKPOINT_SECTIONCREATE;
+	req_lib_ckpt_sectioncreate.idLen = sectionCreationAttributes->sectionId->idLen;
+	req_lib_ckpt_sectioncreate.expirationTime = sectionCreationAttributes->expirationTime;
+	req_lib_ckpt_sectioncreate.initialDataSize = initialDataSize;
+
+
+	error = saSendRetry (ckptCheckpointInstance->fd, &req_lib_ckpt_sectioncreate,
+		sizeof (struct req_lib_ckpt_sectioncreate), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	/*
+	 * Write section identifier to server
+	 */
+	error = saSendRetry (ckptCheckpointInstance->fd, sectionCreationAttributes->sectionId->id,
+		sectionCreationAttributes->sectionId->idLen, MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	error = saSendRetry (ckptCheckpointInstance->fd, initialData,
+		initialDataSize, MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	error = saRecvQueue (ckptCheckpointInstance->fd, &res_lib_ckpt_sectioncreate, 0, MESSAGE_RES_CKPT_CHECKPOINT_SECTIONCREATE);
+
+error_exit:
+	return (error == SA_OK ? res_lib_ckpt_sectioncreate.error : error);
+}
+
+
+SaErrorT
+saCkptSectionDelete (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	const SaCkptSectionIdT *sectionId)
+{
+	SaErrorT error;
+	struct ckptCheckpointInstance *ckptCheckpointInstance;
+	struct req_lib_ckpt_sectiondelete req_lib_ckpt_sectiondelete;
+	struct res_lib_ckpt_sectiondelete res_lib_ckpt_sectiondelete;
+
+	error = saHandleConvert (&ckptCheckpointHandleDatabase, *checkpointHandle,
+		(void *)&ckptCheckpointInstance, CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	req_lib_ckpt_sectiondelete.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_sectiondelete.header.size = sizeof (struct req_lib_ckpt_sectiondelete) + sectionId->idLen; 
+	req_lib_ckpt_sectiondelete.header.id = MESSAGE_REQ_CKPT_CHECKPOINT_SECTIONDELETE;
+	req_lib_ckpt_sectiondelete.idLen = sectionId->idLen;
+
+	error = saSendRetry (ckptCheckpointInstance->fd, &req_lib_ckpt_sectiondelete,
+		sizeof (struct req_lib_ckpt_sectiondelete), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	/*
+	 * Write section identifier to server
+	 */
+	error = saSendRetry (ckptCheckpointInstance->fd, sectionId->id,
+		sectionId->idLen, MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+	error = saRecvQueue (ckptCheckpointInstance->fd, &res_lib_ckpt_sectiondelete, 0, MESSAGE_RES_CKPT_CHECKPOINT_SECTIONDELETE);
+
+error_exit:
+	return (error == SA_OK ? res_lib_ckpt_sectiondelete.error : error);
+}
+
+SaErrorT
+saCkptSectionExpirationTimeSet (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	const SaCkptSectionIdT *sectionId,
+	SaTimeT expirationTime)
+{
+	SaErrorT error;
+	struct ckptCheckpointInstance *ckptCheckpointInstance;
+	struct req_lib_ckpt_sectionexpirationtimeset req_lib_ckpt_sectionexpirationtimeset;
+	struct res_lib_ckpt_sectionexpirationtimeset res_lib_ckpt_sectionexpirationtimeset;
+
+	error = saHandleConvert (&ckptCheckpointHandleDatabase, *checkpointHandle,
+		(void *)&ckptCheckpointInstance, CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	req_lib_ckpt_sectionexpirationtimeset.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_sectionexpirationtimeset.header.size = sizeof (struct req_lib_ckpt_sectionexpirationtimeset) + sectionId->idLen; 
+	req_lib_ckpt_sectionexpirationtimeset.header.id = MESSAGE_REQ_CKPT_CHECKPOINT_SECTIONEXPIRATIONTIMESET;
+	req_lib_ckpt_sectionexpirationtimeset.idLen = sectionId->idLen;
+	req_lib_ckpt_sectionexpirationtimeset.expirationTime = expirationTime;
+
+	error = saSendRetry (ckptCheckpointInstance->fd, &req_lib_ckpt_sectionexpirationtimeset,
+		sizeof (struct req_lib_ckpt_sectionexpirationtimeset), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	/*
+	 * Write section identifier to server
+	 */
+	if (sectionId->idLen) {
+		error = saSendRetry (ckptCheckpointInstance->fd, sectionId->id,
+			sectionId->idLen, MSG_NOSIGNAL);
+		if (error != SA_OK) {
+			goto error_exit;
+		}
+	}
+
+	error = saRecvQueue (ckptCheckpointInstance->fd, &res_lib_ckpt_sectionexpirationtimeset,
+		0, MESSAGE_RES_CKPT_CHECKPOINT_SECTIONEXPIRATIONTIMESET);
+
+error_exit:
+	return (error == SA_OK ? res_lib_ckpt_sectionexpirationtimeset.error : error);
+}
+
+SaErrorT
+saCkptSectionIteratorInitialize (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	SaCkptSectionsChosenT sectionsChosen,
+	SaTimeT expirationTime,
+	SaCkptSectionIteratorT *sectionIterator)
+{
+	SaErrorT error;
+	struct ckptCheckpointInstance *ckptCheckpointInstance;
+	struct ckptSectionIteratorInstance *ckptSectionIteratorInstance;
+	struct req_lib_ckpt_sectioniteratorinitialize req_lib_ckpt_sectioniteratorinitialize;
+	struct res_lib_ckpt_sectioniteratorinitialize res_lib_ckpt_sectioniteratorinitialize;
+
+	error = saHandleConvert (&ckptCheckpointHandleDatabase, *checkpointHandle,
+		(void *)&ckptCheckpointInstance, CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	error = saHandleCreate (&ckptSectionIteratorHandleDatabase,
+		(void *)&ckptSectionIteratorInstance,
+		sizeof (struct ckptSectionIteratorInstance), sectionIterator);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+	/*
+	 * Setup section id list for iterator next
+	 */
+	list_init (&ckptSectionIteratorInstance->sectionIdListHead);
+
+	ckptSectionIteratorInstance->maxSectionIdSize =
+		ckptCheckpointInstance->maxSectionIdSize;
+
+	error = saServiceConnect (&ckptSectionIteratorInstance->fd,	
+		MESSAGE_REQ_CKPT_SECTIONITERATOR_INIT);
+	if (error != SA_OK) {
+		goto error_remove;
+	}
+
+	pthread_mutex_init (&ckptSectionIteratorInstance->mutex, NULL);
+
+	req_lib_ckpt_sectioniteratorinitialize.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_sectioniteratorinitialize.header.size = sizeof (struct req_lib_ckpt_sectioniteratorinitialize); 
+	req_lib_ckpt_sectioniteratorinitialize.header.id = MESSAGE_REQ_CKPT_SECTIONITERATOR_SECTIONITERATORINITIALIZE;
+	req_lib_ckpt_sectioniteratorinitialize.sectionsChosen = sectionsChosen;
+	req_lib_ckpt_sectioniteratorinitialize.expirationTime = expirationTime;
+	memcpy (&req_lib_ckpt_sectioniteratorinitialize.checkpointName,
+		&ckptCheckpointInstance->checkpointName, sizeof (SaNameT));
+
+	error = saSendRetry (ckptSectionIteratorInstance->fd,
+		&req_lib_ckpt_sectioniteratorinitialize, sizeof (struct req_lib_ckpt_sectioniteratorinitialize), MSG_NOSIGNAL);
+
+	if (error != SA_OK) {
+		goto error_close;
+	}
+
+	error = saRecvQueue (ckptSectionIteratorInstance->fd,
+		&res_lib_ckpt_sectioniteratorinitialize, 0,
+		MESSAGE_RES_CKPT_SECTIONITERATOR_SECTIONITERATORINITIALIZE);
+
+error_exit:
+	return (error == SA_OK ? res_lib_ckpt_sectioniteratorinitialize.error : error);
+error_close:
+	close (ckptSectionIteratorInstance->fd);
+error_remove:
+	saHandleRemove (&ckptSectionIteratorHandleDatabase, *sectionIterator);
+	return (error);
+}
+
+struct iteratorSectionIdListEntry {
+	struct list_head list;
+	char data[0];
+};
+
+SaErrorT
+saCkptSectionIteratorNext (
+	SaCkptSectionIteratorT *sectionIterator,
+	SaCkptSectionDescriptorT *sectionDescriptor)
+{
+	SaErrorT error;
+	struct ckptSectionIteratorInstance *ckptSectionIteratorInstance;
+	struct req_lib_ckpt_sectioniteratornext req_lib_ckpt_sectioniteratornext;
+	struct res_lib_ckpt_sectioniteratornext res_lib_ckpt_sectioniteratornext;
+	struct iteratorSectionIdListEntry *iteratorSectionIdListEntry;
+
+	error = saHandleConvert (&ckptSectionIteratorHandleDatabase, *sectionIterator,
+		(void *)&ckptSectionIteratorInstance,
+		CKPTSECTIONITERATORINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+	/*
+	 * Allocate section id storage area
+	 */
+	iteratorSectionIdListEntry = malloc (sizeof (struct list_head) +
+		ckptSectionIteratorInstance->maxSectionIdSize);
+	if (iteratorSectionIdListEntry == 0) {
+		error = SA_ERR_NO_MEMORY;
+		goto error_exit;
+	}
+
+	req_lib_ckpt_sectioniteratornext.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_sectioniteratornext.header.size = sizeof (struct req_lib_ckpt_sectioniteratornext); 
+	req_lib_ckpt_sectioniteratornext.header.id = MESSAGE_REQ_CKPT_SECTIONITERATOR_SECTIONITERATORNEXT;
+
+	error = saSendRetry (ckptSectionIteratorInstance->fd,
+		&req_lib_ckpt_sectioniteratornext,
+		sizeof (struct req_lib_ckpt_sectioniteratornext), MSG_NOSIGNAL);
+
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	error = saRecvRetry (ckptSectionIteratorInstance->fd, &res_lib_ckpt_sectioniteratornext,
+		sizeof (struct res_lib_ckpt_sectioniteratornext), MSG_WAITALL | MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	memcpy (sectionDescriptor,
+		&res_lib_ckpt_sectioniteratornext.sectionDescriptor,
+		sizeof (SaCkptSectionDescriptorT));
+
+	sectionDescriptor->sectionId.id = &iteratorSectionIdListEntry->data[0];
+	
+	if ((res_lib_ckpt_sectioniteratornext.header.size - sizeof (struct res_lib_ckpt_sectioniteratornext)) > 0) {
+		error = saRecvRetry (ckptSectionIteratorInstance->fd,
+			sectionDescriptor->sectionId.id,
+			res_lib_ckpt_sectioniteratornext.header.size -
+				sizeof (struct res_lib_ckpt_sectioniteratornext),
+			MSG_WAITALL | MSG_NOSIGNAL);
+	}
+
+	/*
+	 * Add to persistent memory list for this sectioniterator
+	 */
+	if (error == SA_OK && res_lib_ckpt_sectioniteratornext.error == SA_OK) {
+		list_init (&iteratorSectionIdListEntry->list);
+		list_add (&iteratorSectionIdListEntry->list, &ckptSectionIteratorInstance->sectionIdListHead);
+	}
+
+error_exit:
+	return (error == SA_OK ? res_lib_ckpt_sectioniteratornext.error : error);
+}
+	
+SaErrorT
+saCkptSectionIteratorFinalize (
+	SaCkptSectionIteratorT *sectionIterator)
+{
+	SaErrorT error;
+	struct ckptSectionIteratorInstance *ckptSectionIteratorInstance;
+	struct iteratorSectionIdListEntry *iteratorSectionIdListEntry;
+	struct list_head *sectionIdIteratorList;
+	struct list_head *sectionIdIteratorListNext;
+
+	error = saHandleConvert (&ckptSectionIteratorHandleDatabase, *sectionIterator,
+		(void *)&ckptSectionIteratorInstance,
+		CKPTSECTIONITERATORINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	close (ckptSectionIteratorInstance->fd);
+
+	/*
+	 * iterate list of section ids for this iterator to free the allocated memory
+	 * be careful to cache next pointer because free removes memory from use
+	 */
+	for (sectionIdIteratorList = ckptSectionIteratorInstance->sectionIdListHead.next,
+		sectionIdIteratorListNext = sectionIdIteratorList->next;
+		sectionIdIteratorList != &ckptSectionIteratorInstance->sectionIdListHead;
+		sectionIdIteratorList = sectionIdIteratorListNext,
+		sectionIdIteratorListNext = sectionIdIteratorList->next) {
+
+		iteratorSectionIdListEntry = list_entry (sectionIdIteratorList,
+			struct iteratorSectionIdListEntry, list);
+
+		free (iteratorSectionIdListEntry);
+	}
+
+	saHandleRemove (&ckptSectionIteratorHandleDatabase, *sectionIterator);
+
+error_exit:
+	return (error);
+}
+
+SaErrorT
+saCkptCheckpointWrite (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	const SaCkptIOVectorElementT *ioVector,
+	SaUint32T numberOfElements,
+	SaUint32T *erroneousVectorIndex)
+{
+	SaErrorT error = SA_OK;
+	struct ckptCheckpointInstance *ckptCheckpointInstance;
+	struct req_lib_ckpt_sectionwrite req_lib_ckpt_sectionwrite;
+	struct res_lib_ckpt_sectionwrite res_lib_ckpt_sectionwrite;
+	int i;
+	struct iovec iov[3];
+	int iov_len = 0;
+
+	error = saHandleConvert (&ckptCheckpointHandleDatabase, *checkpointHandle,
+		(void *)&ckptCheckpointInstance, CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET_DEMO, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	req_lib_ckpt_sectionwrite.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_sectionwrite.header.id = MESSAGE_REQ_CKPT_CHECKPOINT_SECTIONWRITE;
+
+
+	for (i = 0; i < numberOfElements; i++) {
+
+		req_lib_ckpt_sectionwrite.header.size = sizeof (struct req_lib_ckpt_sectionwrite) + ioVector[i].sectionId.idLen + ioVector[i].dataSize; 
+
+		req_lib_ckpt_sectionwrite.dataOffset = ioVector[i].dataOffset;
+		req_lib_ckpt_sectionwrite.dataSize = ioVector[i].dataSize;
+		req_lib_ckpt_sectionwrite.idLen = ioVector[i].sectionId.idLen;
+
+		iov_len = 0;
+// TODO check for zero length stuff
+		iov[0].iov_base = &req_lib_ckpt_sectionwrite;
+		iov[0].iov_len = sizeof (struct req_lib_ckpt_sectionwrite);
+		iov[1].iov_base = ioVector[i].sectionId.id;
+		iov[1].iov_len = ioVector[i].sectionId.idLen;
+		iov[2].iov_base = ioVector[i].dataBuffer;
+		iov[2].iov_len = ioVector[i].dataSize;
+
+		error = saSendMsgRetry (ckptCheckpointInstance->fd,
+			iov,
+			3);
+		if (error != SA_OK) {
+			goto error_exit;
+		}
+
+		/*
+		 * Receive response
+		 */
+		error = saRecvRetry (ckptCheckpointInstance->fd, &res_lib_ckpt_sectionwrite,
+			sizeof (struct res_lib_ckpt_sectionwrite), MSG_WAITALL | MSG_NOSIGNAL);
+		if (error != SA_OK) {
+			goto error_exit;
+		}
+
+		/*
+		 * If error, report back erroneous index
+		 */
+		if (res_lib_ckpt_sectionwrite.error != SA_OK) {
+			if (erroneousVectorIndex) {
+				*erroneousVectorIndex = i;
+			}
+			goto error_exit;
+		}
+	}
+
+error_exit:
+	pthread_mutex_unlock (&ckptCheckpointInstance->mutex);
+	return (error == SA_OK ? res_lib_ckpt_sectionwrite.error : error);
+}
+
+SaErrorT
+saCkptSectionOverwrite (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	const SaCkptSectionIdT *sectionId,
+	SaUint8T *dataBuffer,
+	SaSizeT dataSize)
+{
+	SaErrorT error;
+	struct ckptCheckpointInstance *ckptCheckpointInstance;
+	struct req_lib_ckpt_sectionoverwrite req_lib_ckpt_sectionoverwrite;
+	struct res_lib_ckpt_sectionoverwrite res_lib_ckpt_sectionoverwrite;
+
+	error = saHandleConvert (&ckptCheckpointHandleDatabase, *checkpointHandle,
+		(void *)&ckptCheckpointInstance, CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	req_lib_ckpt_sectionoverwrite.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_sectionoverwrite.header.size = sizeof (struct req_lib_ckpt_sectionoverwrite) + sectionId->idLen + dataSize; 
+	req_lib_ckpt_sectionoverwrite.header.id = MESSAGE_REQ_CKPT_CHECKPOINT_SECTIONOVERWRITE;
+	req_lib_ckpt_sectionoverwrite.idLen = sectionId->idLen;
+	req_lib_ckpt_sectionoverwrite.dataSize = dataSize;
+	
+	error = saSendRetry (ckptCheckpointInstance->fd, &req_lib_ckpt_sectionoverwrite,
+		sizeof (struct req_lib_ckpt_sectionoverwrite), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	if (sectionId->idLen) {
+		error = saSendRetry (ckptCheckpointInstance->fd, sectionId->id,
+			sectionId->idLen, MSG_NOSIGNAL);
+		if (error != SA_OK) {
+			goto error_exit;
+		}
+	}
+	error = saSendRetry (ckptCheckpointInstance->fd, dataBuffer, dataSize, MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	error = saRecvQueue (ckptCheckpointInstance->fd,
+		&res_lib_ckpt_sectionoverwrite, 0, MESSAGE_RES_CKPT_CHECKPOINT_SECTIONOVERWRITE);
+
+error_exit:
+	return (error == SA_OK ? res_lib_ckpt_sectionoverwrite.error : error);
+}
+
+SaErrorT
+saCkptCheckpointRead (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	SaCkptIOVectorElementT *ioVector,
+	SaUint32T numberOfElements,
+	SaUint32T *erroneousVectorIndex)
+{
+	SaErrorT error = SA_OK;
+	struct ckptCheckpointInstance *ckptCheckpointInstance;
+	struct req_lib_ckpt_sectionread req_lib_ckpt_sectionread;
+	struct res_lib_ckpt_sectionread res_lib_ckpt_sectionread;
+	int dataLength;
+	int i;
+	struct iovec iov[3];
+
+	error = saHandleConvert (&ckptCheckpointHandleDatabase, *checkpointHandle,
+		(void *)&ckptCheckpointInstance, CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET_DEMO, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	req_lib_ckpt_sectionread.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_sectionread.header.id = MESSAGE_REQ_CKPT_CHECKPOINT_SECTIONREAD;
+
+	for (i = 0; i < numberOfElements; i++) {
+		req_lib_ckpt_sectionread.header.size = sizeof (struct req_lib_ckpt_sectionread) +
+			ioVector[i].sectionId.idLen;
+
+		req_lib_ckpt_sectionread.idLen = ioVector[i].sectionId.idLen;
+		req_lib_ckpt_sectionread.dataOffset = ioVector[i].dataOffset;
+		req_lib_ckpt_sectionread.dataSize = ioVector[i].dataSize;
+
+		iov[0].iov_base = &req_lib_ckpt_sectionread;
+		iov[0].iov_len = sizeof (struct req_lib_ckpt_sectionread);
+		iov[1].iov_base = ioVector[i].sectionId.id;
+		iov[1].iov_len = ioVector[i].sectionId.idLen;
+
+		error = saSendMsgRetry (ckptCheckpointInstance->fd,
+			iov,
+			2);
+
+		/*
+		 * Receive response header
+		 */
+		error = saRecvRetry (ckptCheckpointInstance->fd, &res_lib_ckpt_sectionread,
+			sizeof (struct res_lib_ckpt_sectionread), MSG_WAITALL | MSG_NOSIGNAL);
+		if (error != SA_OK) {
+				goto error_exit;
+		}
+		
+		dataLength = res_lib_ckpt_sectionread.header.size - sizeof (struct res_lib_ckpt_sectionread);
+
+		/*
+		 * Receive checkpoint section data
+		 */
+		if (dataLength > 0) {
+			error = saRecvRetry (ckptCheckpointInstance->fd, ioVector[i].dataBuffer,
+				dataLength, MSG_WAITALL | MSG_NOSIGNAL);
+			if (error != SA_OK) {
+					goto error_exit;
+			}
+		}
+		if (res_lib_ckpt_sectionread.error != SA_OK) {
+			if (erroneousVectorIndex) {
+				*erroneousVectorIndex = i;
+			}
+			goto error_exit;
+		}
+
+		/*
+		 * Report back bytes of data read
+		 */
+		ioVector[i].readSize = res_lib_ckpt_sectionread.dataRead;
+	}
+
+error_exit:
+	pthread_mutex_unlock (&ckptCheckpointInstance->mutex);
+	return (error == SA_OK ? res_lib_ckpt_sectionread.error : error);
+}
+
+SaErrorT
+saCkptCheckpointSynchronize (
+	const SaCkptCheckpointHandleT *checkpointHandle,
+	SaTimeT timeout)
+{
+	SaErrorT error;
+	struct ckptCheckpointInstance *ckptCheckpointInstance;
+	struct req_lib_ckpt_checkpointsynchronize req_lib_ckpt_checkpointsynchronize;
+	struct res_lib_ckpt_checkpointsynchronize res_lib_ckpt_checkpointsynchronize;
+
+	error = saHandleConvert (&ckptCheckpointHandleDatabase, *checkpointHandle,
+		(void *)&ckptCheckpointInstance, CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	req_lib_ckpt_checkpointsynchronize.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_checkpointsynchronize.header.size = sizeof (struct req_lib_ckpt_checkpointsynchronize); 
+	req_lib_ckpt_checkpointsynchronize.header.id = MESSAGE_REQ_CKPT_CHECKPOINT_CHECKPOINTSYNCHRONIZE;
+
+	error = saSendRetry (ckptCheckpointInstance->fd, &req_lib_ckpt_checkpointsynchronize,
+		sizeof (struct req_lib_ckpt_checkpointsynchronize), MSG_NOSIGNAL);
+
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	error = saRecvQueue (ckptCheckpointInstance->fd, &res_lib_ckpt_checkpointsynchronize,
+		0, MESSAGE_RES_CKPT_CHECKPOINT_CHECKPOINTSYNCHRONIZE);
+
+error_exit:
+	return (error == SA_OK ? res_lib_ckpt_checkpointsynchronize.error : error);
+}
+
+SaErrorT
+saCkptCheckpointSynchronizeAsync (
+	const SaCkptHandleT *ckptHandle,
+	SaInvocationT invocation,
+	const SaCkptCheckpointHandleT *checkpointHandle)
+{
+	struct ckptInstance *ckptInstance;
+	struct ckptCheckpointInstance *ckptCheckpointInstance;
+	SaErrorT error;
+	struct req_lib_ckpt_checkpointsynchronizeasync req_lib_ckpt_checkpointsynchronizeasync;
+
+	error = saHandleConvert (&ckptCheckpointHandleDatabase, *checkpointHandle,
+		(void *)&ckptCheckpointInstance, CKPTCHECKPOINTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+	error = saHandleConvert (&ckptHandleDatabase, *ckptHandle,
+		(void *)&ckptInstance, CKPTINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	req_lib_ckpt_checkpointsynchronizeasync.header.magic = MESSAGE_MAGIC;
+	req_lib_ckpt_checkpointsynchronizeasync.header.size = sizeof (struct req_lib_ckpt_checkpointsynchronizeasync);
+	req_lib_ckpt_checkpointsynchronizeasync.header.id = MESSAGE_REQ_CKPT_CHECKPOINT_CHECKPOINTOPENASYNC;
+	req_lib_ckpt_checkpointsynchronizeasync.invocation = invocation;
+
+	error = saSendRetry (ckptInstance->fd, &req_lib_ckpt_checkpointsynchronizeasync,
+		sizeof (struct req_lib_ckpt_checkpointsynchronizeasync), MSG_NOSIGNAL);
+
+error_exit:
+	return (error);
+}

+ 476 - 0
lib/clm.c

@@ -0,0 +1,476 @@
+
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/un.h>
+
+#include "../include/ais_types.h"
+#include "../include/ais_clm.h"
+#include "../include/ais_msg.h"
+#include "util.h"
+
+struct message_overlay {
+	struct message_header header;
+	char data[4096];
+};
+
+struct clmInstance {
+	int fd;
+	SaClmCallbacksT callbacks;
+	struct message_overlay message;
+	pthread_mutex_t mutex;
+};
+#define CLMINSTANCE_MUTEX_OFFSET offset_of(struct clmInstance, mutex)
+
+static struct saHandleDatabase clmHandleDatabase = {
+	handleCount: 0,
+	handles: 0,
+	generation: 0,
+	mutex: PTHREAD_MUTEX_INITIALIZER
+};
+
+/*
+ * Versions supported
+ */
+static SaVersionT clmVersionsSupported[] = {
+	{ 'A', 1, 1 },
+	{ 'a', 1, 1 }
+};
+
+static struct saVersionDatabase clmVersionDatabase = {
+	sizeof (clmVersionsSupported) / sizeof (SaVersionT),
+	clmVersionsSupported
+};
+
+
+SaErrorT
+saClmInitialize (
+	SaClmHandleT *clmHandle,
+	const SaClmCallbacksT *clmCallbacks,
+	const SaVersionT *version)
+{
+	struct clmInstance *clmInstance;
+	SaErrorT error = SA_OK;
+
+	error = saVersionVerify (&clmVersionDatabase, version);
+	if (error != SA_OK) {
+		goto error_nofree;
+	}
+
+	error = saHandleCreate (&clmHandleDatabase, (void *)&clmInstance,
+		sizeof (struct clmInstance), clmHandle);
+	if (error != SA_OK) {
+		goto error_nofree;
+	}
+	
+	error = saServiceConnect (&clmInstance->fd, MESSAGE_REQ_CLM_INIT);
+	if (error != SA_OK) {
+		goto error_free;
+	}
+
+	memcpy (&clmInstance->callbacks, clmCallbacks, sizeof (SaClmCallbacksT));
+
+	pthread_mutex_init (&clmInstance->mutex, NULL);
+
+	return (SA_OK);
+
+error_free:
+	saHandleRemove (&clmHandleDatabase, *clmHandle);
+error_nofree:
+	return (error);
+}
+
+SaErrorT
+saClmSelectionObjectGet (
+	const SaClmHandleT *clmHandle,
+	SaSelectionObjectT *selectionObject)
+{
+	struct clmInstance *clmInstance;
+	SaErrorT error;
+
+	error = saHandleConvert (&clmHandleDatabase, *clmHandle, (void *)&clmInstance, CLMINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	*selectionObject = clmInstance->fd;
+
+	pthread_mutex_unlock (&clmInstance->mutex);
+	return (SA_OK);
+}
+
+SaErrorT
+saClmDispatch (
+	const SaClmHandleT *clmHandle,
+	SaDispatchFlagsT dispatchFlags)
+{
+	struct pollfd ufds;
+	int timeout = -1;
+	SaErrorT error;
+	int cont = 1; /* always continue do loop except when set to 0 */
+	int dispatch_avail;
+	int poll_fd;
+	int handle_verified = 0;
+	struct clmInstance *clmInstance;
+	struct res_clm_trackcallback *res_clm_trackcallback;
+	struct res_clm_nodegetcallback *res_clm_nodegetcallback;
+	SaClmCallbacksT callbacks;
+	unsigned int gen_first;
+	unsigned int gen_second;
+
+	/*
+	 * Timeout instantly for SA_DISPATCH_ONE or SA_DISPATCH_ALL and
+	 * wait indefinately for SA_DISPATCH_BLOCKING
+	 */
+	if (dispatchFlags == SA_DISPATCH_ALL) {
+		timeout = 0;
+	}
+
+	do {
+		error = saHandleConvert (&clmHandleDatabase, *clmHandle, (void *)&clmInstance, CLMINSTANCE_MUTEX_OFFSET, &gen_first);
+		if (error != SA_OK) {
+			return (handle_verified ? SA_OK : error);
+		}
+		handle_verified = 1;
+
+		poll_fd = clmInstance->fd;
+
+		/*
+		 * Unlock mutex for potentially long wait in select.  If fd
+		 * is closed by clmFinalize in select, select will return
+		 */
+
+		pthread_mutex_unlock (&clmInstance->mutex);
+
+		ufds.fd = poll_fd;
+		ufds.events = POLLIN;
+		ufds.revents = 0;
+
+		error = saPollRetry (&ufds, 1, timeout);
+		if (error != SA_OK) {
+			goto error_nounlock;
+		}
+
+		dispatch_avail = ufds.revents & POLLIN;
+		if (dispatch_avail == 0 && dispatchFlags == SA_DISPATCH_ALL) {
+			break; /* exit do while cont is 1 loop */
+		}
+		if (dispatch_avail == 0) {
+			continue; /* retry select */
+		}
+		/*
+		 * Re-verify amfHandle
+		 */
+		error = saHandleConvert (&clmHandleDatabase, *clmHandle, (void *)&clmInstance, CLMINSTANCE_MUTEX_OFFSET, &gen_second);
+		if (error != SA_OK) {
+			return (handle_verified ? SA_OK : error);
+		}
+
+		/*
+		 * Handle has been removed and then reallocated
+		 */
+		if (gen_first != gen_second) {
+			return SA_OK;
+		}
+
+		/*
+		 * Read header
+		 */
+		error = saRecvRetry (clmInstance->fd, &clmInstance->message.header, sizeof (struct message_header), MSG_WAITALL | MSG_NOSIGNAL);
+		if (error != SA_OK) {
+			goto error_unlock;
+		}
+
+		/*
+		 * Read data payload
+		 */
+		if (clmInstance->message.header.size > sizeof (struct message_header)) {
+			error = saRecvRetry (clmInstance->fd, &clmInstance->message.data,
+				clmInstance->message.header.size - sizeof (struct message_header), MSG_WAITALL | MSG_NOSIGNAL);
+			if (error != SA_OK) {
+				goto error_unlock;
+			}
+		}
+		/*
+		 * Make copy of callbacks, unlock instance, and call callback
+		 * A risk of this dispatch method is that the callback routines may
+		 * operate at the same time that amfFinalize has been called.
+		*/
+		memcpy (&callbacks, &clmInstance->callbacks, sizeof (SaClmCallbacksT));
+
+		pthread_mutex_unlock (&clmInstance->mutex);
+
+		/*
+		 * Dispatch incoming message
+		 */
+		switch (clmInstance->message.header.id) {
+
+		case MESSAGE_RES_CLM_TRACKCALLBACK:
+			res_clm_trackcallback = (struct res_clm_trackcallback *)&clmInstance->message;
+
+			memcpy (res_clm_trackcallback->notificationBufferAddress,
+				&res_clm_trackcallback->notificationBuffer,
+				res_clm_trackcallback->numberOfItems * sizeof (SaClmClusterNotificationT));
+
+			callbacks.saClmClusterTrackCallback (
+				res_clm_trackcallback->notificationBufferAddress,
+				res_clm_trackcallback->numberOfItems, res_clm_trackcallback->numberOfMembers,
+				res_clm_trackcallback->viewNumber, SA_OK);
+			break;
+
+		case MESSAGE_RES_CLM_NODEGETCALLBACK:
+			res_clm_nodegetcallback = (struct res_clm_nodegetcallback *)&clmInstance->message;
+
+			memcpy (res_clm_nodegetcallback->clusterNodeAddress,
+				&res_clm_nodegetcallback->clusterNode, sizeof (SaClmClusterNodeT));
+
+			callbacks.saClmClusterNodeGetCallback (
+				res_clm_nodegetcallback->invocation,
+				&res_clm_nodegetcallback->clusterNode, SA_OK);
+			break;
+
+		default:
+			error = SA_ERR_LIBRARY;
+			goto error_nounlock;
+			break;
+		}
+		/*
+		 * Determine if more messages should be processed
+		 * */
+		switch (dispatchFlags) {
+		case SA_DISPATCH_ONE:
+			cont = 0;
+			break;
+		case SA_DISPATCH_ALL:
+			break;
+		case SA_DISPATCH_BLOCKING:
+			break;
+		}
+	} while (cont);
+
+	return (error);
+
+error_unlock:
+	pthread_mutex_unlock (&clmInstance->mutex);
+error_nounlock:
+	return (error);
+}
+
+SaErrorT
+saClmFinalize (
+	SaClmHandleT *clmHandle)
+{
+	struct clmInstance *clmInstance;
+	SaErrorT error;
+
+	error = saHandleConvert (&clmHandleDatabase, *clmHandle, (void *)&clmInstance, CLMINSTANCE_MUTEX_OFFSET | HANDLECONVERT_DONTUNLOCKDB, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	shutdown (clmInstance->fd, 0);
+	close (clmInstance->fd);
+	free (clmInstance);
+
+	error = saHandleRemove (&clmHandleDatabase, *clmHandle);
+
+	pthread_mutex_unlock (&clmInstance->mutex);
+
+	saHandleUnlockDatabase (&clmHandleDatabase);
+
+	return (error);
+}
+
+SaErrorT
+saClmClusterTrackStart (
+	const SaClmHandleT *clmHandle,
+	SaUint8T trackFlags,
+	SaClmClusterNotificationT *notificationBuffer,
+	SaUint32T numberOfItems)
+{
+	struct req_clm_trackstart req_trackstart;
+	struct clmInstance *clmInstance;
+	SaErrorT error = SA_OK;
+
+	req_trackstart.header.magic = MESSAGE_MAGIC;
+	req_trackstart.header.size = sizeof (struct req_clm_trackstart);
+	req_trackstart.header.id = MESSAGE_REQ_CLM_TRACKSTART;
+	req_trackstart.trackFlags = trackFlags;
+	req_trackstart.notificationBufferAddress = notificationBuffer;
+	req_trackstart.numberOfItems = numberOfItems;
+
+	error = saHandleConvert (&clmHandleDatabase, *clmHandle, (void *)&clmInstance, CLMINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	error = saSendRetry (clmInstance->fd, &req_trackstart, sizeof (struct req_clm_trackstart), MSG_NOSIGNAL);
+
+	pthread_mutex_unlock (&clmInstance->mutex);
+
+	return (error);
+}
+
+SaErrorT
+saClmClusterTrackStop (
+	const SaClmHandleT *clmHandle)
+{
+	struct clmInstance *clmInstance;
+	struct req_clm_trackstop req_trackstop;
+	SaErrorT error = SA_OK;
+
+	req_trackstop.header.magic = MESSAGE_MAGIC;
+	req_trackstop.header.size = sizeof (struct req_clm_trackstop);
+	req_trackstop.header.id = MESSAGE_REQ_CLM_TRACKSTOP;
+
+	error = saHandleConvert (&clmHandleDatabase, *clmHandle, (void *)&clmInstance, CLMINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	error = saSendRetry (clmInstance->fd, &req_trackstop, sizeof (struct req_clm_trackstop), MSG_NOSIGNAL);
+
+	pthread_mutex_unlock (&clmInstance->mutex);
+
+	return (error);
+}
+
+SaErrorT
+saClmClusterNodeGet (
+	SaClmNodeIdT nodeId,
+	SaTimeT timeout,
+	SaClmClusterNodeT *clusterNode)
+{
+	int fd;
+	struct req_clm_nodeget req_clm_nodeget;
+	struct res_clm_nodeget res_clm_nodeget;
+	struct message_overlay message;
+	SaErrorT error = SA_OK;
+	struct timeval select_timeout;
+	fd_set read_fds;
+
+	select_timeout.tv_usec = 0;
+	select_timeout.tv_sec = 5;
+
+	error = saServiceConnect (&fd, MESSAGE_REQ_CLM_INIT);
+	if (error != SA_OK) {
+		goto error_noclose;
+	}
+
+	/*
+	 * Send request message
+	 */
+	req_clm_nodeget.header.magic = MESSAGE_MAGIC;
+	req_clm_nodeget.header.size = sizeof (struct req_clm_nodeget);
+	req_clm_nodeget.header.id = MESSAGE_REQ_CLM_NODEGET;
+	req_clm_nodeget.nodeId = nodeId;
+	error = saSendRetry (fd, &req_clm_nodeget, sizeof (struct req_clm_nodeget), MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_close;
+	}
+
+	FD_ZERO (&read_fds);
+	FD_SET (fd, &read_fds);
+	/*
+	 * Wait for timeout interval
+	 */
+	error = saSelectRetry (fd + 1, &read_fds, 0, 0, &select_timeout);
+	if (error != SA_OK) {
+		goto error_close;
+	}
+
+	/*
+	 * Was there a timeout in receiving the information?
+	 */
+	if (FD_ISSET (fd, &read_fds) == 0) {
+		error = SA_ERR_TIMEOUT;
+		goto error_close;
+	}
+
+	error = saRecvRetry (fd, &message.header, sizeof (struct message_header), MSG_WAITALL | MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_close;
+	}
+
+	error = saRecvRetry (fd, &message.data, message.header.size - sizeof (struct message_header), MSG_WAITALL | MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_close;
+	}
+
+	memcpy (clusterNode, &res_clm_nodeget.clusterNode, sizeof (SaClmClusterNodeT));
+
+error_close:
+	close (fd);
+error_noclose:
+	return (error);
+}
+
+SaErrorT
+saClmClusterNodeGetAsync (
+	const SaClmHandleT *clmHandle,
+	SaInvocationT invocation,
+	SaClmNodeIdT nodeId,
+	SaClmClusterNodeT *clusterNode)
+{
+	struct clmInstance *clmInstance;
+	struct req_clm_nodeget req_clm_nodeget;
+	SaErrorT error = SA_OK;
+
+	req_clm_nodeget.header.magic = MESSAGE_MAGIC;
+	req_clm_nodeget.header.size = sizeof (struct req_clm_nodeget);
+	req_clm_nodeget.header.id = MESSAGE_REQ_CLM_NODEGET;
+	memcpy (&req_clm_nodeget.invocation, &invocation, sizeof (SaInvocationT));
+	memcpy (&req_clm_nodeget.nodeId, &nodeId, sizeof (SaClmNodeIdT));
+	req_clm_nodeget.clusterNodeAddress = clusterNode;
+
+	error = saHandleConvert (&clmHandleDatabase, *clmHandle, (void *)&clmInstance, CLMINSTANCE_MUTEX_OFFSET, 0);
+	if (error != SA_OK) {
+		return (error);
+	}
+
+	error = saSendRetry (clmInstance->fd, &req_clm_nodeget, sizeof (struct req_clm_nodeget), MSG_NOSIGNAL);
+
+	pthread_mutex_unlock (&clmInstance->mutex);
+
+	return (error);
+}

+ 564 - 0
lib/util.c

@@ -0,0 +1,564 @@
+
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/un.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "../include/ais_types.h"
+#include "../include/ais_msg.h"
+#include "util.h"
+
+SaErrorT
+saServiceConnect (
+	int *fdOut,
+	enum req_init_types initType)
+{
+	int fd;
+	int result;
+	struct sockaddr_un address;
+	struct req_lib_init req_lib_init;
+	struct res_lib_init res_lib_init;
+	SaErrorT error;
+	gid_t egid;
+
+	/*
+	 * Allow set group id binaries to be authenticated
+	 */
+	egid = getegid();
+	setregid (egid, -1);
+
+	memset (&address, 0, sizeof (struct sockaddr_un));
+	address.sun_family = PF_UNIX;
+	strcpy (address.sun_path + 1, "libais.socket");
+	fd = socket (PF_UNIX, SOCK_STREAM, 0);
+	if (fd == -1) {
+		return (SA_ERR_SYSTEM);
+	}
+	result = connect (fd, (struct sockaddr *)&address, sizeof (address));
+	if (result == -1) {
+		return (SA_ERR_TRY_AGAIN);
+	}
+
+	req_lib_init.header.magic = MESSAGE_MAGIC;
+	req_lib_init.header.size = sizeof (req_lib_init);
+	req_lib_init.header.id = initType;
+
+	error = saSendRetry (fd, &req_lib_init, sizeof (struct req_lib_init),
+		MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+	error = saRecvRetry (fd, &res_lib_init,
+		sizeof (struct res_lib_init), MSG_WAITALL | MSG_NOSIGNAL);
+	if (error != SA_OK) {
+		goto error_exit;
+	}
+
+	/*
+	 * Check for security errors
+	 */
+	if (res_lib_init.error != SA_OK) {
+		error = res_lib_init.error;
+		goto error_exit;
+	}
+
+	*fdOut = fd;
+	return (SA_OK);
+error_exit:
+	close (fd);
+	return (error);
+}
+
+SaErrorT
+saRecvRetry (
+	int s,
+	void *msg,
+	size_t len,
+	int flags)
+{
+	SaErrorT error = SA_OK;
+	int result;
+	struct msghdr msg_recv;
+	struct iovec iov_recv;
+
+	iov_recv.iov_base = (void *)msg;
+	iov_recv.iov_len = len;
+
+	msg_recv.msg_iov = &iov_recv;
+	msg_recv.msg_iovlen = 1;
+	msg_recv.msg_name = 0;
+	msg_recv.msg_namelen = 0;
+	msg_recv.msg_control = 0;
+	msg_recv.msg_controllen = 0;
+	msg_recv.msg_flags = 0;
+
+retry_recv:
+	result = recvmsg (s, &msg_recv, flags);
+	if (result == -1 && errno == EINTR) {
+		goto retry_recv;
+	}
+	if (result == -1 || result != len) {
+		error = SA_ERR_SYSTEM;
+	}
+	return (error);
+}
+
+struct message_overlay {
+	struct message_header header;
+	char instance[4096];
+};
+
+SaErrorT
+saRecvQueue (
+	int s,
+	void *msg,
+	struct queue *queue,
+	int findMessageId)
+{
+	struct message_overlay *message_overlay = (struct message_overlay *)msg;
+	void *inq_msg;
+	int match;
+	SaErrorT error;
+
+	do {
+		error = saRecvRetry (s, &message_overlay->header, sizeof (struct message_header), MSG_WAITALL | MSG_NOSIGNAL);
+		if (error != SA_OK) {
+			goto error_exit;
+		}
+		if (message_overlay->header.size > sizeof (struct message_header)) {
+			error = saRecvRetry (s, &message_overlay->instance, message_overlay->header.size - sizeof (struct message_header), MSG_WAITALL | MSG_NOSIGNAL);
+			if (error != SA_OK) {
+				goto error_exit;
+			}
+		}
+		match = (message_overlay->header.id == findMessageId);
+
+		if (match == 0 && queue) {
+			inq_msg = (void *)malloc (message_overlay->header.size);
+			if (inq_msg == 0) {
+				error = SA_ERR_NO_MEMORY;
+				goto error_exit;
+			}
+			memcpy (inq_msg, msg, message_overlay->header.size);
+			error = saQueueItemAdd (queue, &inq_msg);
+			if (error != SA_OK) {
+				free (inq_msg);
+				goto error_exit;
+			}
+
+			error = saActivatePoll (s);
+			if (error != SA_OK) {
+				goto error_exit;
+			}
+		}
+	} while (match == 0);
+
+error_exit:
+	return (error);
+}
+
+SaErrorT
+saActivatePoll (int s) {
+	struct req_amf_activatepoll req_amf_activatepoll;
+	SaErrorT error;
+
+	/*
+	 * Send activate poll to tell nodeexec to activate poll
+	 * on this file descriptor
+	 */
+	req_amf_activatepoll.header.magic = MESSAGE_MAGIC;
+	req_amf_activatepoll.header.size = sizeof (req_amf_activatepoll);
+	req_amf_activatepoll.header.id = MESSAGE_REQ_AMF_ACTIVATEPOLL;
+
+	error = saSendRetry (s, &req_amf_activatepoll,
+		sizeof (struct req_amf_activatepoll), MSG_NOSIGNAL);
+	return (error);
+}
+
+SaErrorT
+saSendRetry (
+	int s,
+	const void *msg,
+	size_t len,
+	int flags)
+{
+	SaErrorT error = SA_OK;
+	int result;
+
+	struct msghdr msg_send;
+	struct iovec iov_send;
+
+	iov_send.iov_base = (void *)msg;
+	iov_send.iov_len = len;
+
+	msg_send.msg_iov = &iov_send;
+	msg_send.msg_iovlen = 1;
+	msg_send.msg_name = 0;
+	msg_send.msg_namelen = 0;
+	msg_send.msg_control = 0;
+	msg_send.msg_controllen = 0;
+	msg_send.msg_flags = 0;
+
+retry_send:
+	result = sendmsg (s, &msg_send, flags);
+	if (result == -1 && errno == EINTR) {
+		goto retry_send;
+	}
+	if (result == -1) {
+		error = SA_ERR_SYSTEM;
+	}
+	return (error);
+}
+
+SaErrorT saSendMsgRetry (
+        int s,
+        struct iovec *iov,
+        int iov_len)
+{
+	SaErrorT error = SA_OK;
+	int result;
+
+	struct msghdr msg_send;
+
+	msg_send.msg_iov = iov;
+	msg_send.msg_iovlen = iov_len;
+	msg_send.msg_name = 0;
+	msg_send.msg_namelen = 0;
+	msg_send.msg_control = 0;
+	msg_send.msg_controllen = 0;
+	msg_send.msg_flags = 0;
+
+retry_send:
+	result = sendmsg (s, &msg_send, MSG_NOSIGNAL);
+	if (result == -1 && errno == EINTR) {
+		goto retry_send;
+	}
+	if (result == -1) {
+		error = SA_ERR_SYSTEM;
+	}
+	return (error);
+}
+
+SaErrorT
+saSelectRetry (
+	int s,
+	fd_set *readfds,
+	fd_set *writefds,
+	fd_set *exceptfds,
+	struct timeval *timeout)
+{
+	SaErrorT error = SA_OK;
+	int result;
+
+retry_select:
+	result = select (s, readfds, writefds, exceptfds, timeout);
+	if (result == -1 && errno == EINTR) {
+		goto retry_select;
+	}
+	if (result == -1) {
+		error = SA_ERR_SYSTEM;
+	}
+
+	return (error);
+}
+
+SaErrorT
+saPollRetry (
+        struct pollfd *ufds,
+        unsigned int nfds,
+        int timeout) 
+{
+	SaErrorT error = SA_OK;
+	int result;
+
+retry_poll:
+	result = poll (ufds, nfds, timeout);
+	if (result == -1 && errno == EINTR) {
+		goto retry_poll;
+	}
+	if (result == -1) {
+		error = SA_ERR_SYSTEM;
+	}
+
+	return (error);
+}
+
+SaErrorT
+saHandleVerify (
+	struct saHandleDatabase *handleDatabase,
+	unsigned int handle)
+{
+	if (handle > handleDatabase->handleCount) {
+		return (SA_ERR_BAD_HANDLE);
+	}
+	if (handleDatabase->handles[handle].valid == 0) {
+		return (SA_ERR_BAD_HANDLE);
+	}
+	return (SA_OK);
+}
+
+SaErrorT
+saHandleCreate (
+	struct saHandleDatabase *handleDatabase,
+	void **instanceOut,
+	int instanceSize,
+	int *handleOut)
+{
+	int handle;
+	void *newHandles;
+	int found = 0;
+	void *instance;
+
+	pthread_mutex_lock (&handleDatabase->mutex);
+
+	for (handle = 0; handle < handleDatabase->handleCount; handle++) {
+		if (handleDatabase->handles[handle].valid == 0) {
+			found = 1;
+			break;
+		}
+	}
+	if (found == 0) {
+		handleDatabase->handleCount += 1;
+		newHandles = (struct saHandle *)realloc (handleDatabase->handles,
+			sizeof (struct saHandle) * handleDatabase->handleCount);
+		if (newHandles == 0) {
+			pthread_mutex_unlock (&handleDatabase->mutex);
+			return (SA_ERR_NO_MEMORY);
+		}
+		handleDatabase->handles = newHandles;
+	}
+	instance = malloc (instanceSize);
+	if (instance == 0) {
+		return (SA_ERR_NO_MEMORY);
+	}
+	memset (instance, 0, instanceSize);
+
+	handleDatabase->handles[handle].valid = 1;
+	handleDatabase->handles[handle].instance = instance;
+	handleDatabase->handles[handle].generation = handleDatabase->generation++;
+
+	*handleOut = handle;
+	*instanceOut = instance;
+
+	pthread_mutex_unlock (&handleDatabase->mutex);
+	return (SA_OK);
+}
+
+SaErrorT
+saHandleRemove (
+	struct saHandleDatabase *handleDatabase,
+	unsigned int handle)
+{
+	free (handleDatabase->handles[handle].instance);
+	memset (&handleDatabase->handles[handle], 0, sizeof (struct saHandle));
+
+	return (SA_OK);
+}
+
+SaErrorT
+saHandleConvert (
+	struct saHandleDatabase *handleDatabase,
+	unsigned int handle,
+	void **instance,
+	int offsetToMutex,
+	unsigned int *generationOut)
+{ 
+	SaErrorT error;
+	int unlockDatabase;
+	int locking;
+
+	unlockDatabase = (0 == (offsetToMutex & HANDLECONVERT_DONTUNLOCKDB));
+	locking = (0 == (offsetToMutex & HANDLECONVERT_NOLOCKING));
+	offsetToMutex &= 0x00ffffff; /* remove 8 bits of flags */
+
+	if (locking) {
+		pthread_mutex_lock (&handleDatabase->mutex);
+	}
+
+	error = saHandleVerify (handleDatabase, handle);
+	if (error != SA_OK) {
+		if (locking) {
+			pthread_mutex_unlock (&handleDatabase->mutex);
+		}
+		return (error);
+	}
+
+	*instance = handleDatabase->handles[handle].instance;
+	if (generationOut) {
+		*generationOut = handleDatabase->handles[handle].generation;
+	}
+
+	/*
+	 * This function exits holding the mutex in the instance instance
+	 * pointed to by offsetToMutex (if NOLOCKING isn't set)
+	 */
+	if (locking) {
+		pthread_mutex_lock ((pthread_mutex_t *)(*instance + offsetToMutex));
+		if (unlockDatabase) {
+			pthread_mutex_unlock (&handleDatabase->mutex);
+		}
+	}
+
+	return (SA_OK);
+}
+
+SaErrorT
+saHandleUnlockDatabase (
+	struct saHandleDatabase *handleDatabase)
+{
+	pthread_mutex_unlock (&handleDatabase->mutex);
+
+	return (SA_OK);
+}
+
+SaErrorT
+saVersionVerify (
+        struct saVersionDatabase *versionDatabase,
+	const SaVersionT *version)
+{
+	int found = 0;
+	int i;
+
+	if (version == 0) {
+		return (SA_ERR_VERSION);
+	}
+
+	for (i = 0; i < versionDatabase->versionCount; i++) {
+		if (memcmp (&versionDatabase->versionsSupported[i], version, sizeof (SaVersionT)) == 0) {
+			found = 1;
+			break;
+		}
+	}
+	return (found ? SA_OK : SA_ERR_VERSION);
+}
+
+
+SaErrorT
+saQueueInit (
+	struct queue *queue,
+	int queueItems,
+	int bytesPerItem)
+{
+	queue->head = 0;
+	queue->tail = queueItems - 1;
+	queue->used = 0;
+	queue->usedhw = 0;
+	queue->size = queueItems;
+	queue->bytesPerItem = bytesPerItem;
+	queue->items = (void *)malloc (queueItems * bytesPerItem);
+	if (queue->items == 0) {
+		return (SA_ERR_NO_MEMORY);
+	}
+	memset (queue->items, 0, queueItems * bytesPerItem);
+	return (SA_OK);
+}
+
+SaErrorT
+saQueueIsFull (
+	struct queue *queue,
+	int *isFull)
+{
+	*isFull = ((queue->size - 1) == queue->used);
+	return (SA_OK);
+}
+
+
+SaErrorT
+saQueueIsEmpty (
+	struct queue *queue,
+	int *isEmpty)
+{
+	*isEmpty = (queue->used == 0);
+	return (SA_OK);
+}
+
+
+SaErrorT
+saQueueItemAdd (
+	struct queue *queue,
+	void *item)
+{
+	char *queueItem;
+	int queuePosition;
+
+	queuePosition = queue->head;
+	queueItem = queue->items;
+	queueItem += queuePosition * queue->bytesPerItem;
+	memcpy (queueItem, item, queue->bytesPerItem);
+
+	if (queue->tail == queue->head) {
+		return (SA_ERR_LIBRARY);
+	}
+	queue->head = (queue->head + 1) % queue->size;
+	queue->used++;
+	if (queue->used > queue->usedhw) {
+		queue->usedhw = queue->used;
+	}
+	return (SA_OK);
+}
+
+SaErrorT
+saQueueItemGet (struct queue *queue, void **item)
+{
+	char *queueItem;
+	int queuePosition;
+
+	queuePosition = (queue->tail + 1) % queue->size;
+	queueItem = queue->items;
+	queueItem += queuePosition * queue->bytesPerItem;
+	*item = (void *)queueItem;
+	return (SA_OK);
+}
+
+SaErrorT
+saQueueItemRemove (struct queue *queue)
+{
+	queue->tail = (queue->tail + 1) % queue->size;
+	if (queue->tail == queue->head) {
+		return (SA_ERR_LIBRARY);
+	}
+	queue->used--;
+	return (SA_OK);
+}

+ 186 - 0
lib/util.h

@@ -0,0 +1,186 @@
+
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AIS_UTIL_H_DEFINED
+#define AIS_UTIL_H_DEFINED
+
+#include <pthread.h>
+#include <sys/poll.h>
+#include "../include/ais_msg.h"
+
+struct saHandle {
+	int valid;
+	void *instance;
+	unsigned int generation;
+};
+
+struct saHandleDatabase {
+	unsigned int handleCount;
+	struct saHandle *handles;
+	unsigned int generation;
+	pthread_mutex_t mutex;
+};
+
+struct saVersionDatabase {
+	int versionCount;
+	SaVersionT *versionsSupported;
+};
+
+struct queue {
+	int head;
+	int tail;
+	int used;
+	int usedhw;
+	int size;
+	void *items;
+	int bytesPerItem;
+};
+
+SaErrorT
+saServiceConnect (
+	int *fdOut,
+	enum req_init_types init_type);
+
+SaErrorT
+saRecvRetry (
+	int s,
+	void *msg,
+	size_t len,
+	int flags);
+
+SaErrorT
+saRecvQueue (
+	int s,
+	void *msg,
+	struct queue *queue,
+	int findMessageId);
+
+SaErrorT
+saActivatePoll (int s);
+
+SaErrorT
+saSendRetry (
+	int s,
+	const void *msg,
+	size_t len,
+	int flags);
+
+SaErrorT saSendMsgRetry (
+	int s,
+	struct iovec *iov,
+	int iov_len);
+
+SaErrorT
+saSelectRetry (
+	int s,
+	fd_set *readfds,
+	fd_set *writefds,
+	fd_set *exceptfds,
+	struct timeval *timeout);
+
+SaErrorT
+saPollRetry (
+	struct pollfd *ufds,
+	unsigned int nfds,
+	int timeout);
+
+SaErrorT
+saHandleVerify (
+	struct saHandleDatabase *handleDatabase,
+	unsigned int handle); 
+
+SaErrorT
+saHandleCreate (
+	struct saHandleDatabase *handleDatabase,
+	void **instance,
+	int instanceSize,
+	int *handleOut);
+
+SaErrorT
+saHandleRemove (
+	struct saHandleDatabase *handleDatabase,
+	unsigned int handle);
+
+SaErrorT
+saHandleConvert (
+	struct saHandleDatabase *handleDatabase,
+	unsigned int handle,
+	void **instance,
+	int offsetToMutex,
+	unsigned int *generationOut);
+
+
+SaErrorT
+saHandleUnlockDatabase (
+	struct saHandleDatabase *handleDatabase);
+
+SaErrorT
+saVersionVerify (
+	struct saVersionDatabase *versionDatabase,
+	const SaVersionT *version);
+
+SaErrorT
+saQueueInit (
+	struct queue *queue,
+	int queueItems,
+	int sizePerItem);
+
+SaErrorT
+saQueueIsFull (
+	struct queue *queue,
+	int *isFull);
+
+SaErrorT
+saQueueIsEmpty (
+	struct queue *queue,
+	int *isEmpty);
+
+SaErrorT
+saQueueItemAdd (
+	struct queue *queue,
+	void *item);
+
+SaErrorT
+saQueueItemGet (struct queue *queue, void **item);
+
+SaErrorT
+saQueueItemRemove (struct queue *queue);
+
+#define offset_of(type,member) (int)(&(((type *)0)->member))
+
+#define HANDLECONVERT_NOLOCKING		0x80000000
+#define HANDLECONVERT_DONTUNLOCKDB	0x40000000
+
+#endif /* AIS_UTIL_H_DEFINED */

+ 14 - 0
loc

@@ -0,0 +1,14 @@
+wc -l exec/*.c exec/*.h include/*.h lib/*.c lib/*.h
+
+echo "Application Interface Specification Implementation Lines Of Code"
+echo -n "exec LOC    "
+cat exec/*.c exec/*.h | wc -l
+
+echo -n "lib LOC     "
+cat lib/*.c lib/*.h | wc -l
+
+echo -n "include LOC "
+cat include/*.h | wc -l
+
+echo -n "total LOC   "
+cat exec/*.c exec/*.h lib/*.c lib/*.h include/*.h | wc -l

+ 92 - 0
test/Makefile

@@ -0,0 +1,92 @@
+# Copyright (c) 2002-2004 MontaVista Software, Inc.
+# 
+# All rights reserved.
+# 
+# This software licensed under BSD license, the text of which follows:
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+# - Redistributions of source code must retain the above copyright notice,
+#   this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright notice,
+#   this list of conditions and the following disclaimer in the documentation
+#   and/or other materials provided with the distribution.
+# - Neither the name of the MontaVista Software, Inc. nor the names of its
+#   contributors may be used to endorse or promote products derived from this
+#   software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+# Production mode flags
+#CFLAGS = -c -O3 -Wall -I../include
+#LDFLAGS = -L../lib
+LIBS = ../lib/libais.a -lpthread
+
+# Debug mode flags
+CFLAGS = -c -g -Wall -DDEBUG -I../include
+LDFLAGS = -g -L../lib
+LIBS = ../lib/libais.a -lpthread
+
+# Profile mode flags
+#CFLAGS = -c -O3 -pg -DDEBUG -I../include
+#LDFLAGS = -pg -L../lib
+#LIBS = ../lib/libais.a
+
+EXTRA_CFLAGS = -I../include
+all: testclm testamf testamf1 testamf2 testamf3 testamf4 testamf5 testamf6 testamfth testckpt ckptstress testparse
+
+testparse: testparse.o
+	$(CC) $(LDFLAGS) -o testparse testparse.o ../exec/parse.o ../exec/print.o ../exec/mempool.o
+
+testtimer: testtimer.o
+	$(CC) $(LDFLAGS) -o testtimer testtimer.o ../exec/timer.o
+
+testamf: testamf.o
+	$(CC) $(LDFLAGS) -o testamf testamf.o $(LIBS)
+
+testamf1: testamf1.o
+	$(CC) $(LDFLAGS) -o testamf1 testamf1.o $(LIBS)
+
+testamf2: testamf2.o
+	$(CC) $(LDFLAGS) -o testamf2 testamf2.o $(LIBS)
+
+testamf3: testamf3.o
+	$(CC) $(LDFLAGS) -o testamf3 testamf3.o $(LIBS)
+
+testamf4: testamf4.o
+	$(CC) $(LDFLAGS) -o testamf4 testamf4.o $(LIBS)
+
+testamf5: testamf5.o
+	$(CC) $(LDFLAGS) -o testamf5 testamf5.o $(LIBS)
+
+testamf6: testamf6.o
+	$(CC) $(LDFLAGS) -o testamf6 testamf6.o $(LIBS)
+
+testamfth: testamfth.o
+	$(CC) $(LDFLAGS) -o testamfth testamfth.o $(LIBS)
+
+testclm: testclm.o
+	$(CC) $(LDFLAGS) -o testclm testclm.o $(LIBS)
+
+testckpt: testckpt.o
+	$(CC) $(LDFLAGS) -o testckpt testckpt.o $(LIBS)
+
+ckptstress: ckptstress.o
+	$(CC) $(LDFLAGS) -o ckptstress ckptstress.o $(LIBS)
+
+clean:
+	rm -f *.o testclm testamf testamf1 testamf2 testamf3 testamf4 testamf5 testamf6 testamfth testckpt ckptstress testparse testtimer
+
+%.o: %.c
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<

+ 200 - 0
test/ckptstress.c

@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/un.h>
+
+#include "ais_types.h"
+#include "ais_ckpt.h"
+
+int ckptinv;
+void printSaNameT (SaNameT *name)
+{
+	int i;
+
+	for (i = 0; i < name->length; i++) {
+		printf ("%c", name->value[i]);
+	}
+}
+
+SaVersionT version = { 'A', 1, 1 };
+
+SaNameT checkpointName = { 5, "abra\0" };
+
+SaCkptCheckpointCreationAttributesT checkpointCreationAttributes = {
+	SA_CKPT_WR_ALL_REPLICAS,
+	100000,
+	0,
+	5,
+	20000,
+	10
+};
+
+SaCkptSectionIdT sectionId1 = {
+	"section ID #1",
+	14
+};
+
+SaCkptSectionIdT sectionId2 = {
+	"section ID #2",
+	14
+};
+SaCkptSectionCreationAttributesT sectionCreationAttributes1 = {
+	&sectionId1,
+	0xFFFFFFFF
+};
+
+SaCkptSectionCreationAttributesT sectionCreationAttributes2 = {
+	&sectionId2,
+	0xFFFFFFFF
+};
+
+char readBuffer1[1025];
+
+char readBuffer2[1025];
+
+SaCkptIOVectorElementT ReadVectorElements[] = {
+	{
+		{
+			"section ID #1",
+			14
+		},
+		readBuffer1,
+		sizeof (readBuffer1),
+		0, 
+		0
+	},
+	{
+		{
+			"section ID #2",
+			14
+		},
+		readBuffer2,
+		sizeof (readBuffer2),
+		0, 
+		0
+	}
+};
+
+#define DATASIZE 250000
+char data[DATASIZE];
+SaCkptIOVectorElementT WriteVectorElements[] = {
+	{
+		{
+			"section ID #1",
+			14
+		},
+		data, /*"written data #1, this should extend past end of old section data", */
+		DATASIZE, /*sizeof ("written data #1, this should extend past end of old section data") + 1, */
+		0, //5, 
+		0
+	}
+#ifdef COMPILE_OUT
+	{
+		{
+			"section ID #2",
+			14
+		},
+		data, /*"written data #2, this should extend past end of old section data" */
+		DATASIZE, /*sizeof ("written data #2, this should extend past end of old section data") + 1, */
+		0, //3, 
+		0
+	}
+#endif
+};
+
+void *th_dispatch (void *arg)
+{
+	int th = (int)arg;
+	SaCkptCheckpointHandleT handle;
+	SaErrorT error;
+	int i;
+	SaUint32T erroroneousVectorIndex = 0;
+
+	error = saCkptCheckpointOpen (&checkpointName,
+		&checkpointCreationAttributes,
+		SA_CKPT_CHECKPOINT_READ|SA_CKPT_CHECKPOINT_WRITE,
+		0,
+		&handle);
+	for (i = 0; i < 1000; i++) {
+		error = saCkptCheckpointWrite (&handle,
+			WriteVectorElements,
+			1,/* placing two here with only one vector element causes an assertion failure !! */
+			&erroroneousVectorIndex);
+		printf ("Thread %d: Attempt %d: error %d\n", th, i, error);
+		if (error != SA_OK) {
+			printf ("Thread %d: Error from write.\n", th);
+		}
+	}
+	return (0);
+}
+
+int main (void) {
+	SaCkptCheckpointHandleT checkpointHandle;
+	SaErrorT error;
+	int i;
+	pthread_t dispatch_thread;
+
+	error = saCkptCheckpointOpen (&checkpointName,
+		&checkpointCreationAttributes,
+		SA_CKPT_CHECKPOINT_READ|SA_CKPT_CHECKPOINT_WRITE,
+		0,
+		&checkpointHandle);
+	printf ("first open result %d (should be 1)\n", error);
+
+	error = saCkptSectionCreate (&checkpointHandle,
+		&sectionCreationAttributes1,
+		"Initial Data #0",
+		strlen ("Initial Data #0") + 1);
+printf ("create2 error is %d\n", error);
+
+	error = saCkptSectionCreate (&checkpointHandle,
+		&sectionCreationAttributes2,
+		"Initial Data #0",
+		strlen ("Initial Data #0") + 1);
+printf ("create2 error is %d\n", error);
+
+	for (i = 0; i < 40; i++) {
+		pthread_create (&dispatch_thread, NULL, th_dispatch, (void *)i);
+	}
+	pthread_join (dispatch_thread, NULL);
+	return (0);
+}

+ 999 - 0
test/scripts/spam

@@ -0,0 +1,999 @@
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &
+./testclm &
+./testamf &

+ 82 - 0
test/scripts/spam2

@@ -0,0 +1,82 @@
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &
+./testamf &

+ 315 - 0
test/testamf.c

@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "ais_types.h"
+#include "ais_amf.h"
+#include "ais_msg.h"
+
+void printSaClmNodeAddressT (SaClmNodeAddressT *nodeAddress) {
+	int i;
+
+	for (i = 0; i < nodeAddress->length; i++) {
+		printf ("%d.", nodeAddress->value[i]);
+	}
+}
+
+void printSaNameT (SaNameT *name)
+{
+	int i;
+
+	for (i = 0; i < name->length; i++) {
+		printf ("%c", name->value[i]);
+	}
+}
+
+void setSanameT (SaNameT *name, char *str) {
+	name->length = strlen (str);
+	memcpy (name->value, str, name->length);
+}
+
+int healthcheck_count = 0;
+void HealthcheckCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfHealthcheckT checkType)
+{
+
+//	if (healthcheck_count++ % 20 == 19) {
+		printf ("20 HealthcheckCallback have occured for component: ");
+		printSaNameT ((SaNameT *)compName);
+		printf ("\n");
+//	}
+	saAmfResponse (invocation, SA_OK);
+
+}
+
+void ReadinessStateSetCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfReadinessStateT readinessState)
+{
+	switch (readinessState) {
+	case SA_AMF_IN_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_IN_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_OUT_OF_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_OUT_OF_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STOPPING:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to stop, stopping.\n");
+		saAmfStoppingComplete (invocation, SA_OK);
+		break;
+	}
+}
+
+void ComponentTerminateCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName)
+{
+	printf ("ComponentTerminateCallback\n");
+}
+
+void CSISetCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	SaAmfCSIFlagsT csiFlags,
+	SaAmfHAStateT *haState,
+	SaNameT *activeCompName,
+	SaAmfCSITransitionDescriptorT transitionDescriptor)
+{
+	switch (*haState) {
+	case SA_AMF_ACTIVE:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+ 		printf (" requested to enter hastate SA_AMF_ACTIVE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STANDBY:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_STANDBY.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_QUIESCED:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_QUIESCED.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	}
+}
+
+void CSIRemoveCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	const SaAmfCSIFlagsT *csiFlags)
+{
+	printf ("CSIRemoveCallback invocation id %x compName ", invocation);
+	printSaNameT ((SaNameT *)compName);
+	printf (" csiName ");
+	printSaNameT ((SaNameT *)csiName);
+	printf ("\n");
+	saAmfResponse (invocation, SA_OK);
+}
+
+void ProtectionGroupTrackCallback (
+	const SaNameT *csiName,
+	SaAmfProtectionGroupNotificationT *notificationBuffer,
+	SaUint32T numberOfItems,
+	SaUint32T numberOfMembers,
+	SaErrorT error)
+{
+	int i;
+
+	printf ("ProtectionGroupTrackCallback items %d members %d\n", (int)numberOfItems, (int)numberOfMembers);
+	printf ("buffer is %p\n", notificationBuffer);
+	for (i = 0; i < numberOfItems; i++) {
+		printf ("component name");
+		printSaNameT (&notificationBuffer[i].member.compName);
+		printf ("\n");
+		printf ("\treadiness state is %d\n",  notificationBuffer[i].member.readinessState);
+		printf ("\thastate %d\n",  notificationBuffer[i].member.haState);
+		printf ("\tchange is %d\n",  notificationBuffer[i].change);
+
+	}
+}
+
+void ExternalComponentRestartCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName)
+{
+	printf ("ExternalComponentRestartCallback\n");
+}
+
+void ExternalComponentControlCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName,
+	SaAmfExternalComponentActionT controlAction)
+{
+	printf ("ExternalComponentControlCallback\n");
+}
+
+void PendingOperationConfirmCallback (
+	const SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationConfirmCallback\n");
+}
+
+void PendingOperationExpiredCallback (
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationExpiredCallback\n");
+}
+
+SaAmfCallbacksT amfCallbacks = {
+	HealthcheckCallback,
+	ReadinessStateSetCallback,
+	ComponentTerminateCallback,
+	CSISetCallback,
+	CSIRemoveCallback,
+	ProtectionGroupTrackCallback,
+	ExternalComponentRestartCallback,
+	ExternalComponentControlCallback,
+	PendingOperationConfirmCallback,
+	PendingOperationExpiredCallback
+};
+
+SaVersionT version = { 'A', 1, 1 };
+
+int main (void) {
+	SaAmfHandleT handle;
+	SaAmfHandleT handleproxy;
+	int result;
+	int select_fd;
+	fd_set read_fds;
+	SaNameT compName;
+	SaNameT proxyCompName;
+	SaNameT csiName;
+	SaAmfReadinessStateT readinessState;
+	SaAmfComponentCapabilityModelT componentCapabilityModel;
+	SaAmfProtectionGroupNotificationT protectionGroupNotificationBuffer[64];
+
+	result = saAmfInitialize (&handle, &amfCallbacks, &version);
+	if (result != SA_OK) {
+	printf ("initialize result is %d\n", result);
+	exit (1);
+	}
+	result = saAmfInitialize (&handleproxy, &amfCallbacks, &version);
+	if (result != SA_OK) {
+	printf ("initialize result is %d\n", result);
+	exit (1);
+	}
+
+	FD_ZERO (&read_fds);
+	saAmfSelectionObjectGet (&handle, &select_fd);
+	FD_SET (select_fd, &read_fds);
+	saAmfSelectionObjectGet (&handleproxy, &select_fd);
+	FD_SET (select_fd, &read_fds);
+
+	setSanameT (&compName, "raidupdate1");
+	setSanameT (&proxyCompName, "raidhotswap1");
+	setSanameT (&csiName, "raidupdate");
+
+
+	result = saAmfComponentRegister (&handleproxy, &proxyCompName, NULL);
+	printf ("register result is %d (should be 1)\n", result);
+	result = saAmfComponentRegister (&handle, &compName, &proxyCompName);
+	printf ("register result is %d (should be 1)\n", result);
+	result = saAmfComponentCapabilityModelGet (&compName, &componentCapabilityModel);
+	printf ("component capability model get is %d (should be 1)\n", result);
+	result = saAmfProtectionGroupTrackStart (&handle, &csiName, SA_TRACK_CURRENT | SA_TRACK_CHANGES_ONLY, protectionGroupNotificationBuffer, 64);
+	printf ("track start result is %d (should be 1)\n", result);
+#ifdef COMPILEOUT
+	result = saAmfProtectionGroupTrackStop (&handle, &csiName);
+	printf ("track stop result is %d (should be 1)\n", result);
+	result = saAmfComponentUnregister (&handle, &compName, &compName);
+	printf ("unregister result is %d (should be 21)\n", result);
+	result = saAmfComponentRegister (&handle, &compName, &proxyCompName);
+	printf ("register result is %d (should be 14)\n", result);
+	result = saAmfComponentUnregister (&handle, &compName, &proxyCompName);
+	printf ("unregister result is %d (should be 1)\n", result);
+	result = saAmfComponentRegister (&handle, &compName, NULL);
+	printf ("register result is %d (should be 1)\n", result);
+	result = saAmfComponentUnregister (&handle, &compName, NULL);
+	printf ("unregister result is %d (should be 1)\n", result);
+	result = saAmfCompNameGet (&handle, &newCompName);
+	printf ("compNameGet result is %d (should be 12)\n", result);
+	result = saAmfComponentRegister (&handle, &compName, NULL);
+	printf ("register result is %d (should be 1)\n", result);
+	result = saAmfCompNameGet (&handle, &newCompName);
+	printf ("compNameGet result is %d (should be 1)\n", result);
+	result = saAmfReadinessStateGet (&compName, &readinessState);
+	printf ("readinessStateGet result is %d (should be 1) state %d (should be 1)\n", result, readinessState);
+	proxyCompName.value[0] = 'a';
+#endif
+	result = saAmfReadinessStateGet (&proxyCompName, &readinessState);
+	printf ("readinessStateGet result is %d (should be 12)\n", result);
+	do {
+		select (select_fd + 1, &read_fds, 0, 0, 0);
+		saAmfDispatch (&handle, SA_DISPATCH_ALL);
+//		printf ("dispatching handleproxy\n");
+		saAmfDispatch (&handleproxy, SA_DISPATCH_ALL);
+	} while (result);
+
+	saAmfFinalize (&handle);
+
+	return (0);
+}

+ 276 - 0
test/testamf1.c

@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sched.h>
+
+#include "ais_types.h"
+#include "ais_amf.h"
+
+void printSaClmNodeAddressT (SaClmNodeAddressT *nodeAddress) {
+	int i;
+
+	for (i = 0; i < nodeAddress->length; i++) {
+		printf ("%d.", nodeAddress->value[i]);
+	}
+}
+
+void printSaNameT (SaNameT *name)
+{
+	int i;
+
+	for (i = 0; i < name->length; i++) {
+		printf ("%c", name->value[i]);
+	}
+}
+
+void setSanameT (SaNameT *name, char *str) {
+	name->length = strlen (str);
+	memcpy (name->value, str, name->length);
+}
+
+int healthcheck_count = 0;
+void HealthcheckCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfHealthcheckT checkType)
+{
+
+//	if (healthcheck_count++ % 20 == 19) {
+		printf ("20 HealthcheckCallback have occured for component: ");
+		printSaNameT ((SaNameT *)compName);
+		printf ("\n");
+//	}
+	saAmfResponse (invocation, SA_OK);
+
+}
+
+void ReadinessStateSetCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfReadinessStateT readinessState)
+{
+	switch (readinessState) {
+	case SA_AMF_IN_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_IN_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_OUT_OF_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_OUT_OF_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STOPPING:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_STOPPING.\n");
+		saAmfStoppingComplete (invocation, SA_OK);
+		break;
+	}
+}
+
+void ComponentTerminateCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName)
+{
+	printf ("ComponentTerminateCallback\n");
+}
+
+void CSISetCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	SaAmfCSIFlagsT csiFlags,
+	SaAmfHAStateT *haState,
+	SaNameT *activeCompName,
+	SaAmfCSITransitionDescriptorT transitionDescriptor)
+{
+	switch (*haState) {
+	case SA_AMF_ACTIVE:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+ 		printf (" requested to enter hastate SA_AMF_ACTIVE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STANDBY:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_STANDBY.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_QUIESCED:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_QUIESCED.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	}
+}
+
+void CSIRemoveCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	const SaAmfCSIFlagsT *csiFlags)
+{
+	printf ("CSIRemoveCallback for component '");
+	printSaNameT ((SaNameT *)compName);
+	printf ("' in CSI '");
+	printSaNameT ((SaNameT *)csiName);
+	printf ("'\n");
+	saAmfResponse (invocation, SA_OK);
+}
+
+void ProtectionGroupTrackCallback (
+	const SaNameT *csiName,
+	SaAmfProtectionGroupNotificationT *notificationBuffer,
+	SaUint32T numberOfItems,
+	SaUint32T numberOfMembers,
+	SaErrorT error)
+{
+	int i;
+
+	printf ("ProtectionGroupTrackCallback items %d members %d\n", (int)numberOfItems, (int)numberOfMembers);
+	printf ("buffer is %p\n", notificationBuffer);
+	for (i = 0; i < numberOfItems; i++) {
+		printf ("component name");
+		printSaNameT (&notificationBuffer[i].member.compName);
+		printf ("\n");
+		printf ("\treadiness state is %d\n",  notificationBuffer[i].member.readinessState);
+		printf ("\thastate %d\n",  notificationBuffer[i].member.haState);
+		printf ("\tchange is %d\n",  notificationBuffer[i].change);
+
+	}
+}
+
+void ExternalComponentRestartCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName)
+{
+	printf ("ExternalComponentRestartCallback\n");
+}
+
+void ExternalComponentControlCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName,
+	SaAmfExternalComponentActionT controlAction)
+{
+	printf ("ExternalComponentControlCallback\n");
+}
+
+void PendingOperationConfirmCallback (
+	const SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationConfirmCallback\n");
+}
+
+void PendingOperationExpiredCallback (
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationExpiredCallback\n");
+}
+
+SaAmfCallbacksT amfCallbacks = {
+	HealthcheckCallback,
+	ReadinessStateSetCallback,
+	ComponentTerminateCallback,
+	CSISetCallback,
+	CSIRemoveCallback,
+	ProtectionGroupTrackCallback,
+	ExternalComponentRestartCallback,
+	ExternalComponentControlCallback,
+	PendingOperationConfirmCallback,
+	PendingOperationExpiredCallback
+};
+
+SaVersionT version = { 'A', 1, 1 };
+
+static struct sched_param sched_param = {
+    sched_priority: 99
+};
+
+int main (void) {
+	SaAmfHandleT handle;
+	int result;
+	int select_fd;
+	fd_set read_fds;
+	SaNameT compName;
+
+   result = sched_setscheduler (0, SCHED_RR, &sched_param);
+    if (result == -1) {
+printf ("couldn't set sched priority\n");
+    }
+
+	result = saAmfInitialize (&handle, &amfCallbacks, &version);
+	if (result != SA_OK) {
+		printf ("initialize result is %d\n", result);
+		exit (1);
+	}
+
+	FD_ZERO (&read_fds);
+	saAmfSelectionObjectGet (&handle, &select_fd);
+	FD_SET (select_fd, &read_fds);
+
+	setSanameT (&compName, "comp_a_in_su_x");
+
+	result = saAmfComponentRegister (&handle, &compName, NULL);
+	printf ("register result is %d (should be 1)\n", result);
+
+	do {
+		select (select_fd + 1, &read_fds, 0, 0, 0);
+		saAmfDispatch (&handle, SA_DISPATCH_ALL);
+	} while (result);
+
+	saAmfFinalize (&handle);
+
+	exit (0);
+}

+ 305 - 0
test/testamf2.c

@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sched.h>
+
+#include "ais_types.h"
+#include "ais_amf.h"
+
+void printSaClmNodeAddressT (SaClmNodeAddressT *nodeAddress) {
+	int i;
+
+	for (i = 0; i < nodeAddress->length; i++) {
+		printf ("%d.", nodeAddress->value[i]);
+	}
+}
+
+void printSaNameT (SaNameT *name)
+{
+	int i;
+
+	for (i = 0; i < name->length; i++) {
+		printf ("%c", name->value[i]);
+	}
+}
+
+void setSanameT (SaNameT *name, char *str) {
+	name->length = strlen (str);
+	memcpy (name->value, str, name->length);
+}
+
+int healthcheck_count = 0;
+void HealthcheckCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfHealthcheckT checkType)
+{
+
+//	if (healthcheck_count++ % 20 == 19) {
+		printf ("20 HealthcheckCallback have occured for component: ");
+		printSaNameT ((SaNameT *)compName);
+		printf ("\n");
+//	}
+	saAmfResponse (invocation, SA_OK);
+	printf ("Healthcheck Count is %d\n", healthcheck_count++);
+
+}
+
+void ReadinessStateSetCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfReadinessStateT readinessState)
+{
+	switch (readinessState) {
+	case SA_AMF_IN_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_IN_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_OUT_OF_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_OUT_OF_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STOPPING:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+                printf ("' requested to enter operational state SA_AMF_STOPPING.\n");                saAmfStoppingComplete (invocation, SA_OK);
+		break;
+	}
+}
+
+void ComponentTerminateCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName)
+{
+	printf ("ComponentTerminateCallback\n");
+}
+
+void CSISetCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	SaAmfCSIFlagsT csiFlags,
+	SaAmfHAStateT *haState,
+	SaNameT *activeCompName,
+	SaAmfCSITransitionDescriptorT transitionDescriptor)
+{
+	switch (*haState) {
+	case SA_AMF_ACTIVE:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+ 		printf (" requested to enter hastate SA_AMF_ACTIVE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STANDBY:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_STANDBY.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_QUIESCED:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_QUIESCED.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	}
+}
+
+void CSIRemoveCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	const SaAmfCSIFlagsT *csiFlags)
+{
+	printf ("CSIRemoveCallback for component '");
+	printSaNameT ((SaNameT *)compName);
+	printf ("' in CSI '");
+	printSaNameT ((SaNameT *)csiName);
+	printf ("'\n");
+	saAmfResponse (invocation, SA_OK);
+}
+
+void ProtectionGroupTrackCallback (
+	const SaNameT *csiName,
+	SaAmfProtectionGroupNotificationT *notificationBuffer,
+	SaUint32T numberOfItems,
+	SaUint32T numberOfMembers,
+	SaErrorT error)
+{
+	int i;
+
+	printf ("ProtectionGroupTrackCallback items %d members %d\n", (int)numberOfItems, (int)numberOfMembers);
+	printf ("buffer is %p\n", notificationBuffer);
+	for (i = 0; i < numberOfItems; i++) {
+		printf ("component name");
+		printSaNameT (&notificationBuffer[i].member.compName);
+		printf ("\n");
+		printf ("\treadiness state is %d\n",  notificationBuffer[i].member.readinessState);
+		printf ("\thastate %d\n",  notificationBuffer[i].member.haState);
+		printf ("\tchange is %d\n",  notificationBuffer[i].change);
+
+	}
+}
+
+void ExternalComponentRestartCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName)
+{
+	printf ("ExternalComponentRestartCallback\n");
+}
+
+void ExternalComponentControlCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName,
+	SaAmfExternalComponentActionT controlAction)
+{
+	printf ("ExternalComponentControlCallback\n");
+}
+
+void PendingOperationConfirmCallback (
+	const SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationConfirmCallback\n");
+}
+
+void PendingOperationExpiredCallback (
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationExpiredCallback\n");
+}
+
+SaAmfCallbacksT amfCallbacks = {
+	HealthcheckCallback,
+	ReadinessStateSetCallback,
+	ComponentTerminateCallback,
+	CSISetCallback,
+	CSIRemoveCallback,
+	ProtectionGroupTrackCallback,
+	ExternalComponentRestartCallback,
+	ExternalComponentControlCallback,
+	PendingOperationConfirmCallback,
+	PendingOperationExpiredCallback
+};
+
+SaVersionT version = { 'A', 1, 1 };
+
+int main (void) {
+	SaAmfHandleT handle;
+	int result;
+	int select_fd;
+	fd_set read_fds;
+	SaNameT compName;
+	int i;
+	SaAmfErrorDescriptorT errorDescriptor;
+
+	result = saAmfInitialize (&handle, &amfCallbacks, &version);
+	if (result != SA_OK) {
+		printf ("initialize result is %d\n", result);
+		exit (1);
+	}
+
+	FD_ZERO (&read_fds);
+	saAmfSelectionObjectGet (&handle, &select_fd);
+	FD_SET (select_fd, &read_fds);
+
+	setSanameT (&compName, "comp_b_in_su_x");
+
+	result = saAmfComponentRegister (&handle, &compName, NULL);
+
+	printf ("register result is %d (should be 1)\n", result);
+
+	i = 0;
+	do {
+		select (select_fd + 1, &read_fds, 0, 0, 0);
+		saAmfDispatch (&handle, SA_DISPATCH_ALL);
+//	} while (1);
+	} while (i++ < 4);
+
+	printf ("Unregistering component\n");
+	result = saAmfComponentUnregister (&handle, &compName, NULL);
+
+//	select (select_fd + 1, &read_fds, 0, 0, 0);
+	saAmfDispatch (&handle, SA_DISPATCH_ALL);
+
+	sleep (1);
+	printf ("Registering component\n");
+	result = saAmfComponentRegister (&handle, &compName, NULL);
+
+	sleep (1);
+	select (select_fd + 1, &read_fds, 0, 0, 0);
+	saAmfDispatch (&handle, SA_DISPATCH_ALL);
+
+	printf ("REPORTING ERROR.\n");
+	errorDescriptor.probableCause = 5;
+	result = saAmfErrorReport (&compName, &compName,
+		0,
+       	&errorDescriptor,
+		NULL);
+
+	select (select_fd + 1, &read_fds, 0, 0, 0);
+	saAmfDispatch (&handle, SA_DISPATCH_ALL);
+
+	sleep (1);
+	printf ("CANCELING ERROR.\n");
+	result = saAmfErrorCancelAll (&compName);
+	do {
+		select (select_fd + 1, &read_fds, 0, 0, 0);
+		saAmfDispatch (&handle, SA_DISPATCH_ALL);
+	} while (result);
+
+	saAmfFinalize (&handle);
+
+	return (0);
+}

+ 266 - 0
test/testamf3.c

@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "ais_types.h"
+#include "ais_amf.h"
+
+void printSaClmNodeAddressT (SaClmNodeAddressT *nodeAddress) {
+	int i;
+
+	for (i = 0; i < nodeAddress->length; i++) {
+		printf ("%d.", nodeAddress->value[i]);
+	}
+}
+
+void printSaNameT (SaNameT *name)
+{
+	int i;
+
+	for (i = 0; i < name->length; i++) {
+		printf ("%c", name->value[i]);
+	}
+}
+
+void setSanameT (SaNameT *name, char *str) {
+	name->length = strlen (str);
+	memcpy (name->value, str, name->length);
+}
+
+int healthcheck_count = 0;
+void HealthcheckCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfHealthcheckT checkType)
+{
+
+//	if (healthcheck_count++ % 20 == 19) {
+		printf ("20 HealthcheckCallback have occured for component: ");
+		printSaNameT ((SaNameT *)compName);
+		printf ("\n");
+//	}
+	saAmfResponse (invocation, SA_OK);
+
+}
+
+void ReadinessStateSetCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfReadinessStateT readinessState)
+{
+	switch (readinessState) {
+	case SA_AMF_IN_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_IN_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_OUT_OF_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_OUT_OF_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STOPPING:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_STOPPING.\n");
+		saAmfStoppingComplete (invocation, SA_OK);
+		break;
+	}
+}
+
+void ComponentTerminateCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName)
+{
+	printf ("ComponentTerminateCallback\n");
+}
+
+void CSISetCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	SaAmfCSIFlagsT csiFlags,
+	SaAmfHAStateT *haState,
+	SaNameT *activeCompName,
+	SaAmfCSITransitionDescriptorT transitionDescriptor)
+{
+	switch (*haState) {
+	case SA_AMF_ACTIVE:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+ 		printf (" requested to enter hastate SA_AMF_ACTIVE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STANDBY:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_STANDBY.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_QUIESCED:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_QUIESCED.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	}
+}
+
+void CSIRemoveCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	const SaAmfCSIFlagsT *csiFlags)
+{
+	printf ("CSIRemoveCallback for component '");
+	printSaNameT ((SaNameT *)compName);
+	printf ("' in CSI '");
+	printSaNameT ((SaNameT *)csiName);
+	printf ("'\n");
+	saAmfResponse (invocation, SA_OK);
+}
+
+void ProtectionGroupTrackCallback (
+	const SaNameT *csiName,
+	SaAmfProtectionGroupNotificationT *notificationBuffer,
+	SaUint32T numberOfItems,
+	SaUint32T numberOfMembers,
+	SaErrorT error)
+{
+	int i;
+
+	printf ("ProtectionGroupTrackCallback items %d members %d\n", (int)numberOfItems, (int)numberOfMembers);
+	printf ("buffer is %p\n", notificationBuffer);
+	for (i = 0; i < numberOfItems; i++) {
+		printf ("component name");
+		printSaNameT (&notificationBuffer[i].member.compName);
+		printf ("\n");
+		printf ("\treadiness state is %d\n",  notificationBuffer[i].member.readinessState);
+		printf ("\thastate %d\n",  notificationBuffer[i].member.haState);
+		printf ("\tchange is %d\n",  notificationBuffer[i].change);
+
+	}
+}
+
+void ExternalComponentRestartCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName)
+{
+	printf ("ExternalComponentRestartCallback\n");
+}
+
+void ExternalComponentControlCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName,
+	SaAmfExternalComponentActionT controlAction)
+{
+	printf ("ExternalComponentControlCallback\n");
+}
+
+void PendingOperationConfirmCallback (
+	const SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationConfirmCallback\n");
+}
+
+void PendingOperationExpiredCallback (
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationExpiredCallback\n");
+}
+
+SaAmfCallbacksT amfCallbacks = {
+	HealthcheckCallback,
+	ReadinessStateSetCallback,
+	ComponentTerminateCallback,
+	CSISetCallback,
+	CSIRemoveCallback,
+	ProtectionGroupTrackCallback,
+	ExternalComponentRestartCallback,
+	ExternalComponentControlCallback,
+	PendingOperationConfirmCallback,
+	PendingOperationExpiredCallback
+};
+
+SaVersionT version = { 'A', 1, 1 };
+
+int main (void) {
+	SaAmfHandleT handle;
+	int result;
+	int select_fd;
+	fd_set read_fds;
+	SaNameT compName;
+
+	result = saAmfInitialize (&handle, &amfCallbacks, &version);
+	if (result != SA_OK) {
+		printf ("initialize result is %d\n", result);
+		exit (1);
+	}
+
+	FD_ZERO (&read_fds);
+	saAmfSelectionObjectGet (&handle, &select_fd);
+	FD_SET (select_fd, &read_fds);
+
+	setSanameT (&compName, "comp_a_in_su_y");
+
+	result = saAmfComponentRegister (&handle, &compName, NULL);
+	printf ("register result is %d (should be 1)\n", result);
+
+	do {
+		select (select_fd + 1, &read_fds, 0, 0, 0);
+		saAmfDispatch (&handle, SA_DISPATCH_ALL);
+	} while (result);
+
+	saAmfFinalize (&handle);
+
+	exit (0);
+}

+ 265 - 0
test/testamf4.c

@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "ais_types.h"
+#include "ais_amf.h"
+
+void printSaClmNodeAddressT (SaClmNodeAddressT *nodeAddress) {
+	int i;
+
+	for (i = 0; i < nodeAddress->length; i++) {
+		printf ("%d.", nodeAddress->value[i]);
+	}
+}
+
+void printSaNameT (SaNameT *name)
+{
+	int i;
+
+	for (i = 0; i < name->length; i++) {
+		printf ("%c", name->value[i]);
+	}
+}
+
+void setSanameT (SaNameT *name, char *str) {
+	name->length = strlen (str);
+	memcpy (name->value, str, name->length);
+}
+
+int healthcheck_count = 0;
+void HealthcheckCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfHealthcheckT checkType)
+{
+
+//	if (healthcheck_count++ % 20 == 19) {
+		printf ("20 HealthcheckCallback have occured for component: ");
+		printSaNameT ((SaNameT *)compName);
+		printf ("\n");
+//	}
+	saAmfResponse (invocation, SA_OK);
+
+}
+
+void ReadinessStateSetCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfReadinessStateT readinessState)
+{
+	switch (readinessState) {
+	case SA_AMF_IN_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_IN_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_OUT_OF_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_OUT_OF_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STOPPING:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+                printf ("' requested to enter operational state SA_AMF_STOPPING.\n");                saAmfStoppingComplete (invocation, SA_OK);
+		break;
+	}
+}
+
+void ComponentTerminateCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName)
+{
+	printf ("ComponentTerminateCallback\n");
+}
+
+void CSISetCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	SaAmfCSIFlagsT csiFlags,
+	SaAmfHAStateT *haState,
+	SaNameT *activeCompName,
+	SaAmfCSITransitionDescriptorT transitionDescriptor)
+{
+	switch (*haState) {
+	case SA_AMF_ACTIVE:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+ 		printf (" requested to enter hastate SA_AMF_ACTIVE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STANDBY:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_STANDBY.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_QUIESCED:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_QUIESCED.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	}
+}
+
+void CSIRemoveCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	const SaAmfCSIFlagsT *csiFlags)
+{
+	printf ("CSIRemoveCallback for component '");
+	printSaNameT ((SaNameT *)compName);
+	printf ("' in CSI '");
+	printSaNameT ((SaNameT *)csiName);
+	printf ("'\n");
+	saAmfResponse (invocation, SA_OK);
+}
+
+void ProtectionGroupTrackCallback (
+	const SaNameT *csiName,
+	SaAmfProtectionGroupNotificationT *notificationBuffer,
+	SaUint32T numberOfItems,
+	SaUint32T numberOfMembers,
+	SaErrorT error)
+{
+	int i;
+
+	printf ("ProtectionGroupTrackCallback items %d members %d\n", (int)numberOfItems, (int)numberOfMembers);
+	printf ("buffer is %p\n", notificationBuffer);
+	for (i = 0; i < numberOfItems; i++) {
+		printf ("component name");
+		printSaNameT (&notificationBuffer[i].member.compName);
+		printf ("\n");
+		printf ("\treadiness state is %d\n",  notificationBuffer[i].member.readinessState);
+		printf ("\thastate %d\n",  notificationBuffer[i].member.haState);
+		printf ("\tchange is %d\n",  notificationBuffer[i].change);
+
+	}
+}
+
+void ExternalComponentRestartCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName)
+{
+	printf ("ExternalComponentRestartCallback\n");
+}
+
+void ExternalComponentControlCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName,
+	SaAmfExternalComponentActionT controlAction)
+{
+	printf ("ExternalComponentControlCallback\n");
+}
+
+void PendingOperationConfirmCallback (
+	const SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationConfirmCallback\n");
+}
+
+void PendingOperationExpiredCallback (
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationExpiredCallback\n");
+}
+
+SaAmfCallbacksT amfCallbacks = {
+	HealthcheckCallback,
+	ReadinessStateSetCallback,
+	ComponentTerminateCallback,
+	CSISetCallback,
+	CSIRemoveCallback,
+	ProtectionGroupTrackCallback,
+	ExternalComponentRestartCallback,
+	ExternalComponentControlCallback,
+	PendingOperationConfirmCallback,
+	PendingOperationExpiredCallback
+};
+
+SaVersionT version = { 'A', 1, 1 };
+
+int main (void) {
+	SaAmfHandleT handle;
+	int result;
+	int select_fd;
+	fd_set read_fds;
+	SaNameT compName;
+
+	result = saAmfInitialize (&handle, &amfCallbacks, &version);
+	if (result != SA_OK) {
+		printf ("initialize result is %d\n", result);
+		exit (1);
+	}
+
+	FD_ZERO (&read_fds);
+	saAmfSelectionObjectGet (&handle, &select_fd);
+	FD_SET (select_fd, &read_fds);
+
+	setSanameT (&compName, "comp_b_in_su_y");
+
+	result = saAmfComponentRegister (&handle, &compName, NULL);
+	printf ("register result is %d (should be 1)\n", result);
+
+	do {
+		select (select_fd + 1, &read_fds, 0, 0, 0);
+		saAmfDispatch (&handle, SA_DISPATCH_ALL);
+	} while (result);
+
+	saAmfFinalize (&handle);
+
+	exit (0);
+}

+ 266 - 0
test/testamf5.c

@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "ais_types.h"
+#include "ais_amf.h"
+
+void printSaClmNodeAddressT (SaClmNodeAddressT *nodeAddress) {
+	int i;
+
+	for (i = 0; i < nodeAddress->length; i++) {
+		printf ("%d.", nodeAddress->value[i]);
+	}
+}
+
+void printSaNameT (SaNameT *name)
+{
+	int i;
+
+	for (i = 0; i < name->length; i++) {
+		printf ("%c", name->value[i]);
+	}
+}
+
+void setSanameT (SaNameT *name, char *str) {
+	name->length = strlen (str);
+	memcpy (name->value, str, name->length);
+}
+
+int healthcheck_count = 0;
+void HealthcheckCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfHealthcheckT checkType)
+{
+
+//	if (healthcheck_count++ % 20 == 19) {
+		printf ("20 HealthcheckCallback have occured for component: ");
+		printSaNameT ((SaNameT *)compName);
+		printf ("\n");
+//	}
+	saAmfResponse (invocation, SA_OK);
+
+}
+
+void ReadinessStateSetCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfReadinessStateT readinessState)
+{
+	switch (readinessState) {
+	case SA_AMF_IN_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_IN_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_OUT_OF_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_OUT_OF_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STOPPING:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_STOPPING.\n");
+		saAmfStoppingComplete (invocation, SA_OK);
+		break;
+	}
+}
+
+void ComponentTerminateCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName)
+{
+	printf ("ComponentTerminateCallback\n");
+}
+
+void CSISetCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	SaAmfCSIFlagsT csiFlags,
+	SaAmfHAStateT *haState,
+	SaNameT *activeCompName,
+	SaAmfCSITransitionDescriptorT transitionDescriptor)
+{
+	switch (*haState) {
+	case SA_AMF_ACTIVE:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+ 		printf (" requested to enter hastate SA_AMF_ACTIVE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STANDBY:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_STANDBY.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_QUIESCED:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_QUIESCED.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	}
+}
+
+void CSIRemoveCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	const SaAmfCSIFlagsT *csiFlags)
+{
+	printf ("CSIRemoveCallback for component '");
+	printSaNameT ((SaNameT *)compName);
+	printf ("' in CSI '");
+	printSaNameT ((SaNameT *)csiName);
+	printf ("'\n");
+	saAmfResponse (invocation, SA_OK);
+}
+
+void ProtectionGroupTrackCallback (
+	const SaNameT *csiName,
+	SaAmfProtectionGroupNotificationT *notificationBuffer,
+	SaUint32T numberOfItems,
+	SaUint32T numberOfMembers,
+	SaErrorT error)
+{
+	int i;
+
+	printf ("ProtectionGroupTrackCallback items %d members %d\n", (int)numberOfItems, (int)numberOfMembers);
+	printf ("buffer is %p\n", notificationBuffer);
+	for (i = 0; i < numberOfItems; i++) {
+		printf ("component name");
+		printSaNameT (&notificationBuffer[i].member.compName);
+		printf ("\n");
+		printf ("\treadiness state is %d\n",  notificationBuffer[i].member.readinessState);
+		printf ("\thastate %d\n",  notificationBuffer[i].member.haState);
+		printf ("\tchange is %d\n",  notificationBuffer[i].change);
+
+	}
+}
+
+void ExternalComponentRestartCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName)
+{
+	printf ("ExternalComponentRestartCallback\n");
+}
+
+void ExternalComponentControlCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName,
+	SaAmfExternalComponentActionT controlAction)
+{
+	printf ("ExternalComponentControlCallback\n");
+}
+
+void PendingOperationConfirmCallback (
+	const SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationConfirmCallback\n");
+}
+
+void PendingOperationExpiredCallback (
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationExpiredCallback\n");
+}
+
+SaAmfCallbacksT amfCallbacks = {
+	HealthcheckCallback,
+	ReadinessStateSetCallback,
+	ComponentTerminateCallback,
+	CSISetCallback,
+	CSIRemoveCallback,
+	ProtectionGroupTrackCallback,
+	ExternalComponentRestartCallback,
+	ExternalComponentControlCallback,
+	PendingOperationConfirmCallback,
+	PendingOperationExpiredCallback
+};
+
+SaVersionT version = { 'A', 1, 1 };
+
+int main (void) {
+	SaAmfHandleT handle;
+	int result;
+	int select_fd;
+	fd_set read_fds;
+	SaNameT compName;
+
+	result = saAmfInitialize (&handle, &amfCallbacks, &version);
+	if (result != SA_OK) {
+		printf ("initialize result is %d\n", result);
+		exit (1);
+	}
+
+	FD_ZERO (&read_fds);
+	saAmfSelectionObjectGet (&handle, &select_fd);
+	FD_SET (select_fd, &read_fds);
+
+	setSanameT (&compName, "comp_a_in_su_z");
+
+	result = saAmfComponentRegister (&handle, &compName, NULL);
+	printf ("register result is %d (should be 1)\n", result);
+
+	do {
+		select (select_fd + 1, &read_fds, 0, 0, 0);
+		saAmfDispatch (&handle, SA_DISPATCH_ALL);
+	} while (result);
+
+	saAmfFinalize (&handle);
+
+	return (0);
+}

+ 266 - 0
test/testamf6.c

@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "ais_types.h"
+#include "ais_amf.h"
+
+void printSaClmNodeAddressT (SaClmNodeAddressT *nodeAddress) {
+	int i;
+
+	for (i = 0; i < nodeAddress->length; i++) {
+		printf ("%d.", nodeAddress->value[i]);
+	}
+}
+
+void printSaNameT (SaNameT *name)
+{
+	int i;
+
+	for (i = 0; i < name->length; i++) {
+		printf ("%c", name->value[i]);
+	}
+}
+
+void setSanameT (SaNameT *name, char *str) {
+	name->length = strlen (str);
+	memcpy (name->value, str, name->length);
+}
+
+int healthcheck_count = 0;
+void HealthcheckCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfHealthcheckT checkType)
+{
+	SaErrorT res;
+
+//	if (healthcheck_count++ % 20 == 19) {
+		printf ("20 HealthcheckCallback have occured for component: ");
+		printSaNameT ((SaNameT *)compName);
+		printf ("\n");
+//	}
+	res = saAmfResponse (invocation, SA_OK);
+	printf ("response res is %d\n", res);
+
+}
+
+void ReadinessStateSetCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfReadinessStateT readinessState)
+{
+	switch (readinessState) {
+	case SA_AMF_IN_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_IN_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_OUT_OF_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_OUT_OF_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STOPPING:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+                printf ("' requested to enter operational state SA_AMF_STOPPING.\n");                saAmfStoppingComplete (invocation, SA_OK);
+		break;
+	}
+}
+
+void ComponentTerminateCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName)
+{
+	printf ("ComponentTerminateCallback\n");
+}
+
+void CSISetCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	SaAmfCSIFlagsT csiFlags,
+	SaAmfHAStateT *haState,
+	SaNameT *activeCompName,
+	SaAmfCSITransitionDescriptorT transitionDescriptor)
+{
+	switch (*haState) {
+	case SA_AMF_ACTIVE:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+ 		printf (" requested to enter hastate SA_AMF_ACTIVE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STANDBY:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_STANDBY.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_QUIESCED:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_QUIESCED.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	}
+}
+
+void CSIRemoveCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	const SaAmfCSIFlagsT *csiFlags)
+{
+	printf ("CSIRemoveCallback for component '");
+	printSaNameT ((SaNameT *)compName);
+	printf ("' in CSI '");
+	printSaNameT ((SaNameT *)csiName);
+	printf ("'\n");
+	saAmfResponse (invocation, SA_OK);
+}
+
+void ProtectionGroupTrackCallback (
+	const SaNameT *csiName,
+	SaAmfProtectionGroupNotificationT *notificationBuffer,
+	SaUint32T numberOfItems,
+	SaUint32T numberOfMembers,
+	SaErrorT error)
+{
+	int i;
+
+	printf ("ProtectionGroupTrackCallback items %d members %d\n", (int)numberOfItems, (int)numberOfMembers);
+	printf ("buffer is %p\n", notificationBuffer);
+	for (i = 0; i < numberOfItems; i++) {
+		printf ("component name");
+		printSaNameT (&notificationBuffer[i].member.compName);
+		printf ("\n");
+		printf ("\treadiness state is %d\n",  notificationBuffer[i].member.readinessState);
+		printf ("\thastate %d\n",  notificationBuffer[i].member.haState);
+		printf ("\tchange is %d\n",  notificationBuffer[i].change);
+
+	}
+}
+
+void ExternalComponentRestartCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName)
+{
+	printf ("ExternalComponentRestartCallback\n");
+}
+
+void ExternalComponentControlCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName,
+	SaAmfExternalComponentActionT controlAction)
+{
+	printf ("ExternalComponentControlCallback\n");
+}
+
+void PendingOperationConfirmCallback (
+	const SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationConfirmCallback\n");
+}
+
+void PendingOperationExpiredCallback (
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationExpiredCallback\n");
+}
+
+SaAmfCallbacksT amfCallbacks = {
+	HealthcheckCallback,
+	ReadinessStateSetCallback,
+	ComponentTerminateCallback,
+	CSISetCallback,
+	CSIRemoveCallback,
+	ProtectionGroupTrackCallback,
+	ExternalComponentRestartCallback,
+	ExternalComponentControlCallback,
+	PendingOperationConfirmCallback,
+	PendingOperationExpiredCallback
+};
+
+SaVersionT version = { 'A', 1, 1 };
+
+int main (void) {
+	SaAmfHandleT handle;
+	int result;
+	int select_fd;
+	fd_set read_fds;
+	SaNameT compName;
+
+	result = saAmfInitialize (&handle, &amfCallbacks, &version);
+	if (result != SA_OK) {
+		printf ("initialize result is %d\n", result);
+		exit (1);
+	}
+
+	FD_ZERO (&read_fds);
+	saAmfSelectionObjectGet (&handle, &select_fd);
+	FD_SET (select_fd, &read_fds);
+
+	setSanameT (&compName, "comp_b_in_su_z");
+
+	result = saAmfComponentRegister (&handle, &compName, NULL);
+	printf ("register result is %d (should be 1)\n", result);
+
+	do {
+		select (select_fd + 1, &read_fds, 0, 0, 0);
+		saAmfDispatch (&handle, SA_DISPATCH_ALL);
+	} while (result);
+
+	saAmfFinalize (&handle);
+	return (0);
+}

+ 280 - 0
test/testamfth.c

@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "ais_types.h"
+#include "ais_amf.h"
+#include "ais_msg.h"
+
+void printSaClmNodeAddressT (SaClmNodeAddressT *nodeAddress) {
+	int i;
+
+	for (i = 0; i < nodeAddress->length; i++) {
+		printf ("%d.", nodeAddress->value[i]);
+	}
+}
+
+void printSaNameT (SaNameT *name)
+{
+	int i;
+
+	for (i = 0; i < name->length; i++) {
+		printf ("%c", name->value[i]);
+	}
+}
+
+void setSanameT (SaNameT *name, char *str) {
+	name->length = strlen (str);
+	memcpy (name->value, str, name->length);
+}
+
+int healthcheck_count = 0;
+void HealthcheckCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfHealthcheckT checkType)
+{
+
+//	if (healthcheck_count++ % 20 == 19) {
+		printf ("20 HealthcheckCallback have occured for component: ");
+		printSaNameT ((SaNameT *)compName);
+		printf ("\n");
+//	}
+	saAmfResponse (invocation, SA_OK);
+
+}
+
+void ReadinessStateSetCallback (SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfReadinessStateT readinessState)
+{
+	switch (readinessState) {
+	case SA_AMF_IN_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_IN_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_OUT_OF_SERVICE:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_OUT_OF_SERVICE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STOPPING:
+		printf ("ReadinessStateSetCallback: '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("' requested to enter operational state SA_AMF_STOPPING.\n");
+		saAmfStoppingComplete (invocation, SA_OK);
+		break;
+	}
+}
+
+void ComponentTerminateCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName)
+{
+	printf ("ComponentTerminateCallback\n");
+}
+
+void CSISetCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	SaAmfCSIFlagsT csiFlags,
+	SaAmfHAStateT *haState,
+	SaNameT *activeCompName,
+	SaAmfCSITransitionDescriptorT transitionDescriptor)
+{
+	switch (*haState) {
+	case SA_AMF_ACTIVE:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+ 		printf (" requested to enter hastate SA_AMF_ACTIVE.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_STANDBY:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_STANDBY.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	case SA_AMF_QUIESCED:
+		printf ("CSISetCallback: '"); 
+		printSaNameT ((SaNameT *)compName);
+		printf ("' for CSI '");
+		printSaNameT ((SaNameT *)compName);
+		printf ("'");
+		printf (" requested to enter hastate SA_AMF_QUIESCED.\n");
+		saAmfResponse (invocation, SA_OK);
+		break;
+	}
+}
+
+void CSIRemoveCallback (
+	SaInvocationT invocation,
+	const SaNameT *compName,
+	const SaNameT *csiName,
+	const SaAmfCSIFlagsT *csiFlags)
+{
+	printf ("CSIRemoveCallback for component '");
+	printSaNameT ((SaNameT *)compName);
+	printf ("' in CSI '");
+	printSaNameT ((SaNameT *)csiName);
+	printf ("'\n");
+	saAmfResponse (invocation, SA_OK);
+}
+
+void ProtectionGroupTrackCallback (
+	const SaNameT *csiName,
+	SaAmfProtectionGroupNotificationT *notificationBuffer,
+	SaUint32T numberOfItems,
+	SaUint32T numberOfMembers,
+	SaErrorT error)
+{
+	int i;
+
+	printf ("ProtectionGroupTrackCallback items %d members %d\n", (int)numberOfItems, (int)numberOfMembers);
+	printf ("buffer is %p\n", notificationBuffer);
+	for (i = 0; i < numberOfItems; i++) {
+		printf ("component name");
+		printSaNameT (&notificationBuffer[i].member.compName);
+		printf ("\n");
+		printf ("\treadiness state is %d\n",  notificationBuffer[i].member.readinessState);
+		printf ("\thastate %d\n",  notificationBuffer[i].member.haState);
+		printf ("\tchange is %d\n",  notificationBuffer[i].change);
+
+	}
+}
+
+void ExternalComponentRestartCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName)
+{
+	printf ("ExternalComponentRestartCallback\n");
+}
+
+void ExternalComponentControlCallback (
+	const SaInvocationT invocation,
+	const SaNameT *externalCompName,
+	SaAmfExternalComponentActionT controlAction)
+{
+	printf ("ExternalComponentControlCallback\n");
+}
+
+void PendingOperationConfirmCallback (
+	const SaInvocationT invocation,
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationConfirmCallback\n");
+}
+
+void PendingOperationExpiredCallback (
+	const SaNameT *compName,
+	SaAmfPendingOperationFlagsT pendingOperationFlags)
+{
+	printf ("PendingOperationExpiredCallback\n");
+}
+
+SaAmfCallbacksT amfCallbacks = {
+	HealthcheckCallback,
+	ReadinessStateSetCallback,
+	ComponentTerminateCallback,
+	CSISetCallback,
+	CSIRemoveCallback,
+	ProtectionGroupTrackCallback,
+	ExternalComponentRestartCallback,
+	ExternalComponentControlCallback,
+	PendingOperationConfirmCallback,
+	PendingOperationExpiredCallback
+};
+
+SaVersionT version = { 'A', 1, 1 };
+
+void *th_dispatch (void *arg)
+{
+	SaErrorT result;
+	SaAmfHandleT *handle = (SaAmfHandleT *)arg;
+
+	printf ("THREAD DISPATCH starting.\n");
+	result = saAmfDispatch (handle, SA_DISPATCH_BLOCKING);
+	printf ("THREAD DISPATCH return result is %d\n", result);
+	return (0);
+}
+
+int main (void) {
+	SaAmfHandleT handle;
+	int result;
+	SaNameT compName;
+	pthread_t dispatch_thread;
+
+	result = saAmfInitialize (&handle, &amfCallbacks, &version);
+	if (result != SA_OK) {
+		printf ("initialize result is %d\n", result);
+		exit (1);
+	}
+
+	setSanameT (&compName, "raidupdate1");
+
+	result = saAmfComponentRegister (&handle, &compName, NULL);
+	printf ("register result is %d (should be 1)\n", result);
+
+	pthread_create (&dispatch_thread, NULL, th_dispatch, &handle);
+
+	sleep (5);
+
+printf ("Finalizing handle\n");
+	saAmfFinalize (&handle);
+	sleep (1); /* this sleep isn't really necessary */
+	result = saAmfInitialize (&handle, &amfCallbacks, &version);
+	result = saAmfComponentRegister (&handle, &compName, NULL);
+	pthread_create (&dispatch_thread, NULL, th_dispatch, &handle);
+	sleep (10);
+
+	exit (0);
+}

+ 347 - 0
test/testckpt.c

@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/un.h>
+
+#include "ais_types.h"
+#include "ais_ckpt.h"
+
+int ckptinv;
+void printSaNameT (SaNameT *name)
+{
+	int i;
+
+	for (i = 0; i < name->length; i++) {
+		printf ("%c", name->value[i]);
+	}
+}
+
+SaVersionT version = { 'A', 1, 1 };
+
+SaNameT checkpointName = { 5, "abra\0" };
+
+SaCkptCheckpointCreationAttributesT checkpointCreationAttributes = {
+	SA_CKPT_WR_ALL_REPLICAS,
+	100000,
+	0,
+	5,
+	20000,
+	10
+};
+
+SaCkptSectionIdT sectionId1 = {
+	"section ID #1",
+	14
+};
+
+SaCkptSectionIdT sectionId2 = {
+	"section ID #2",
+	14
+};
+SaCkptSectionCreationAttributesT sectionCreationAttributes1 = {
+	&sectionId1,
+	0xFFFFFFFF
+};
+
+SaCkptSectionCreationAttributesT sectionCreationAttributes2 = {
+	&sectionId2,
+	0xFFFFFFFF
+};
+
+char readBuffer1[1025];
+
+char readBuffer2[1025];
+
+SaCkptIOVectorElementT ReadVectorElements[] = {
+	{
+		{
+			"section ID #1",
+			14
+		},
+		readBuffer1,
+		sizeof (readBuffer1),
+		0, 
+		0
+	},
+	{
+		{
+			"section ID #2",
+			14
+		},
+		readBuffer2,
+		sizeof (readBuffer2),
+		0, 
+		0
+	}
+};
+
+#define DATASIZE 127000
+char data[DATASIZE];
+SaCkptIOVectorElementT WriteVectorElements[] = {
+	{
+		{
+			"section ID #1",
+			14
+		},
+		data, /*"written data #1, this should extend past end of old section data", */
+		DATASIZE, /*sizeof ("data #1, this should extend past end of old section data") + 1, */
+		0, //5, 
+		0
+	}
+#ifdef COMPILE_OUT
+	{
+		{
+			"section ID #2",
+			14
+		},
+		data, /*"written data #2, this should extend past end of old section data" */
+		DATASIZE, /*sizeof ("written data #2, this should extend past end of old section data") + 1, */
+		0, //3, 
+		0
+	}
+#endif
+};
+
+int main (void) {
+	SaCkptCheckpointHandleT checkpointHandle;
+	SaCkptCheckpointHandleT checkpointHandle2;
+	SaCkptCheckpointHandleT checkpointHandleRead;
+	SaCkptCheckpointStatusT checkpointStatus;
+	SaCkptSectionIteratorT sectionIterator;
+	SaCkptSectionDescriptorT sectionDescriptor;
+	SaUint32T erroroneousVectorIndex = 0;
+	SaErrorT error;
+	
+	error = saCkptCheckpointOpen (&checkpointName,
+		&checkpointCreationAttributes,
+		SA_CKPT_CHECKPOINT_READ|SA_CKPT_CHECKPOINT_WRITE,
+		0,
+		&checkpointHandle);
+	printf ("first open result %d (should be 1)\n", error);
+
+// start of stuff
+	error = saCkptSectionCreate (&checkpointHandle,
+		&sectionCreationAttributes1,
+		"Initial Data #0",
+		strlen ("Initial Data #0") + 1);
+printf ("create1 error is %d\n", error);
+	error = saCkptSectionCreate (&checkpointHandle,
+		&sectionCreationAttributes2,
+		"Initial Data #0",
+		strlen ("Initial Data #0") + 1);
+printf ("create2 error is %d\n", error);
+	printf ("saCkptSectionCreate result %d (should be 1)\n", error);
+for (ckptinv = 0; ckptinv < 500000; ckptinv++) {
+printf ("Writing checkpoint loop %d\n", ckptinv);
+	/*
+	 * Test checkpoint write
+	 */
+	error = saCkptCheckpointWrite (&checkpointHandle,
+		WriteVectorElements,
+		1,
+		&erroroneousVectorIndex);
+if (error != SA_OK) {
+	printf ("saCkptCheckpointWrite result %d (should be 1)\n", error);
+	exit (1);
+}
+}
+exit (1);
+
+	error = saCkptCheckpointUnlink (&checkpointName);
+	printf ("unlink result %d (should be 1)\n", error);
+
+	error = saCkptCheckpointOpen (&checkpointName,
+		&checkpointCreationAttributes,
+		SA_CKPT_CHECKPOINT_READ|SA_CKPT_CHECKPOINT_WRITE,
+		0,
+		&checkpointHandle2);
+	printf ("open after unlink result %d (should be 7)\n", error);
+
+	error = saCkptCheckpointClose (&checkpointHandle);
+	printf ("close result %d (should be 1)\n", error);
+
+	error = saCkptCheckpointOpen (&checkpointName,
+		&checkpointCreationAttributes,
+		SA_CKPT_CHECKPOINT_READ,
+		0,
+		&checkpointHandleRead);
+	printf ("read only open result %d (should be 1)\n", error);
+
+	error = saCkptCheckpointOpen (&checkpointName,
+		&checkpointCreationAttributes,
+		SA_CKPT_CHECKPOINT_READ|SA_CKPT_CHECKPOINT_WRITE,
+		0,
+		&checkpointHandle);
+	printf ("open after unlink/close result %d (should be 1)\n", error);
+
+	error = saCkptCheckpointRetentionDurationSet (&checkpointHandle,
+		10000);
+	printf ("set checkpoint retention duration result %d (should be 1)\n", error);
+
+	error = saCkptCheckpointStatusGet (&checkpointHandle,
+		&checkpointStatus);
+	printf ("saCkptCheckpointStatusGet result %d (should be 1)\n", error);
+	if (error == SA_OK) {
+		printf ("Memory used %d in %d sections.\n", (int)checkpointStatus.memoryUsed,
+			(int)checkpointStatus.numberOfSections);
+	}
+	
+	error = saCkptSectionCreate (&checkpointHandleRead,
+		&sectionCreationAttributes1,
+		"Initial Data #0",
+		strlen ("Initial Data #0") + 1);
+	printf ("saCkptSectionCreate result %d (should be 11)\n", error);
+
+	error = saCkptSectionCreate (&checkpointHandle,
+		&sectionCreationAttributes1,
+		"Initial Data #0",
+		strlen ("Initial Data #0") + 1);
+	printf ("saCkptSectionCreate result %d (should be 1)\n", error);
+		
+	error = saCkptSectionCreate (&checkpointHandle,
+		&sectionCreationAttributes1,
+		"Initial Data #0",
+		strlen ("Initial Data #0") + 1);
+	printf ("saCkptSectionCreate result %d (should be 14)\n", error);
+		
+#ifdef COMPILE_OUT
+	error = saCkptSectionDelete (&checkpointHandle,
+		&sectionId1);
+	printf ("saCkptSectionDelete result %d (should be 1)\n", error);
+		
+	error = saCkptSectionCreate (&checkpointHandle,
+		&sectionCreationAttributes1,
+		"Initial Data #0",
+		strlen ("Initial Data #0") + 1);
+	printf ("saCkptSectionCreate result %d (should be 1)\n", error);
+#endif
+
+	error = saCkptSectionExpirationTimeSet (&checkpointHandle,
+		&sectionId1,
+		0xFFAAAAAA);
+	printf ("saCkptSectionExpirationTimeSet result %d (should be 1)\n", error);
+		
+
+	error = saCkptSectionOverwrite (&checkpointHandle,
+		&sectionId1,
+		"Overwrite Data #1",
+		strlen ("Overwrite Data #1") + 1);
+	printf ("saCkptSectionOverwrite result %d (should be 1)\n", error);
+
+	/*
+	 * Test checkpoint read
+	 */
+	memset (readBuffer1, 0, sizeof (readBuffer1));
+	memset (readBuffer2, 0, sizeof (readBuffer2));
+	error = saCkptSectionCreate (&checkpointHandle,
+		&sectionCreationAttributes2,
+		"Initial Data #2",
+		strlen ("Initial Data #2") + 1);
+	printf ("saCkptSectionCreate result %d (should be 1)\n", error);
+
+	error = saCkptCheckpointRead (&checkpointHandle,
+		ReadVectorElements,
+		2,
+		&erroroneousVectorIndex);
+	printf ("saCkptCheckpointRead result %d (should be 1)\n", error);
+	printf ("Buffers after checkpoint read\n");
+	printf (" buffer #1: '%s'\n", readBuffer1);
+	printf (" buffer #2: '%s'\n", readBuffer2);
+
+//sleep (20);
+for (ckptinv = 0; ckptinv < 2000; ckptinv++) {
+	/*
+	 * Test checkpoint write
+	 */
+	error = saCkptCheckpointWrite (&checkpointHandle,
+		WriteVectorElements,
+		2,
+		&erroroneousVectorIndex);
+if (error != SA_OK) {
+printf ("Writing checkpoint loop %d\n", ckptinv);
+	printf ("saCkptCheckpointWrite result %d (should be 1)\n", error);
+exit (1);
+}
+}
+exit (1);
+	error = saCkptCheckpointRead (&checkpointHandle,
+		ReadVectorElements,
+		2,
+		&erroroneousVectorIndex);
+//	printf ("saCkptCheckpointRead result %d (should be 1)\n", error);
+//	printf ("Buffers after checkpoint write are:\n");
+//	printf (" buffer #1: '%s'\n", readBuffer1);
+//	printf (" buffer #2: '%s'\n", readBuffer2);
+
+	error = saCkptCheckpointStatusGet (&checkpointHandle,
+		&checkpointStatus);
+	printf ("saCkptCheckpointStatusGet result %d (should be 1)\n", error);
+	if (error == SA_OK) {
+		printf ("Memory used %d in %d sections.\n", (int)checkpointStatus.memoryUsed,
+			(int)checkpointStatus.numberOfSections);
+	}
+	error = saCkptSectionIteratorInitialize (&checkpointHandle,
+		0,
+		0,
+		&sectionIterator);
+	printf ("saCkptSectionIteratorInitialize result %d (should be 1)\n", error);
+
+	/*
+	 * Iterate all sections
+	 */
+	do {
+		error = saCkptSectionIteratorNext (&sectionIterator,
+			&sectionDescriptor);
+		printf ("saCkptSectionIteratorNext result %d (should be 1)\n", error);
+		if (error == SA_OK) {
+			printf ("Section '%s' expires %llx size %d state %x update %llx\n",
+				sectionDescriptor.sectionId.id,
+				sectionDescriptor.expirationTime,
+				sectionDescriptor.sectionSize,
+				sectionDescriptor.sectionState,
+				sectionDescriptor.lastUpdate);
+		}
+	} while (error == SA_OK);
+
+	error = saCkptSectionIteratorFinalize (&sectionIterator);
+	printf ("saCkptSectionIteratorFinalize result %d (should be 1)\n", error);
+	return (0);
+}

+ 191 - 0
test/testclm.c

@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/un.h>
+
+#include "ais_types.h"
+#include "ais_clm.h"
+
+void printSaClmNodeAddressT (SaClmNodeAddressT *nodeAddress) {
+	int i;
+
+	for (i = 0; i < nodeAddress->length; i++) {
+		printf ("%d.", nodeAddress->value[i]);
+	}
+}
+
+void printSaNameT (SaNameT *name)
+{
+	int i;
+
+	for (i = 0; i < name->length; i++) {
+		printf ("%c", name->value[i]);
+	}
+}
+
+void printSaClmClusterNodeT (char *description, SaClmClusterNodeT *clusterNode) {
+	printf ("Node Information for %s\n", description);
+
+	printf ("\tnode id is %x\n", (int)clusterNode->nodeId);
+
+	printf ("\tnode address is ");
+	printSaClmNodeAddressT (&clusterNode->nodeAddress);
+	printf ("\n");
+
+	printf ("\tNode name is ");
+	printSaNameT (&clusterNode->nodeName);
+	printf ("\n");
+
+	printf ("\tCluster name is ");
+	printSaNameT (&clusterNode->clusterName);
+	printf ("\n");
+
+	printf ("\tMember is %d\n", clusterNode->member);
+
+	printf ("\tTimestamp is %llx nanoseconds\n", clusterNode->bootTimestamp);
+}
+
+void NodeGetCallback (
+	SaInvocationT invocation,
+	SaClmClusterNodeT *clusterNode,
+	SaErrorT error) 
+{
+	char buf[128];
+
+	if (invocation == 0x60) {
+	sprintf (buf, "NodeGetCallback different machine invocation %x", invocation);
+	} else {
+	sprintf (buf, "NodeGetCallback local machine %x", invocation);
+	}
+
+
+	printSaClmClusterNodeT (buf, clusterNode);
+}
+
+void TrackCallback (
+	SaClmClusterNotificationT *notificationBuffer,
+	SaUint32T numberOfItems,
+	SaUint32T numberOfMembers,
+	SaUint64T viewNumber,
+	SaErrorT error)
+{
+	int i;
+
+	printf ("Calling track callback %p\n", notificationBuffer);
+	for (i = 0; i < numberOfItems; i++) {
+	switch (notificationBuffer[i].clusterChanges) {
+	case SA_CLM_NODE_NO_CHANGE:
+		printf ("NODE STATE NO CHANGE.\n");
+		break;
+	case SA_CLM_NODE_JOINED:
+		printf ("NODE STATE JOINED.\n");
+		break;
+	case SA_CLM_NODE_LEFT:
+		printf ("NODE STATE LEFT.\n");
+		break;
+	}
+		printSaClmClusterNodeT ("TRACKING", &notificationBuffer[i].clusterNode);
+	}
+	printf ("Done calling trackCallback\n");
+}
+
+SaClmCallbacksT callbacks = {
+	NodeGetCallback,
+	TrackCallback
+};
+
+SaVersionT version = { 'A', 1, 1 };
+
+int main (void) {
+	SaClmHandleT handle;
+	fd_set read_fds;
+	int select_fd;
+	int result;
+	SaClmClusterNotificationT clusterNotificationBuffer[64];
+
+	result = saClmInitialize (&handle, &callbacks, &version);
+	if (result != SA_OK) {
+		printf ("Could not initialize Cluster Membership API instance error %d\n", result);
+		exit (1);
+	}
+
+//	result = saClmClusterNodeGet (0x6201a8c0, 0, &clusterNode);
+//	printSaClmClusterNodeT ("saClmClusterNodeGet ip 192.168.1.98", &clusterNode);
+#ifdef COMPILE_OUT
+	result = saClmClusterNodeGet (SA_CLM_LOCAL_NODE_ID, 0, &clusterNode);
+
+	printSaClmClusterNodeT ("saClmClusterNodeGet SA_CLM_LOCAL_NODE_ID", &clusterNode);
+
+	result = saClmClusterNodeGetAsync (&handle, 0x55, SA_CLM_LOCAL_NODE_ID, &clusterNode);
+	printf ("result is %d\n", result);
+
+	result = saClmClusterNodeGetAsync (&handle, 0x60, 0x6201a8c0, &clusterNode);
+	printf ("result is %d\n", result);
+	result = saClmClusterNodeGetAsync (&handle, 0x59, SA_CLM_LOCAL_NODE_ID, &clusterNode);
+	printf ("result is %d\n", result);
+
+	result = saClmClusterNodeGetAsync (&handle, 0x57, SA_CLM_LOCAL_NODE_ID, &clusterNode);
+	printf ("result is %d\n", result);
+
+#endif
+
+printf ("notify buffer is %p\n", clusterNotificationBuffer);
+	saClmClusterTrackStart (&handle, SA_TRACK_CURRENT | SA_TRACK_CHANGES_ONLY, clusterNotificationBuffer, 64);
+
+	saClmSelectionObjectGet (&handle, &select_fd);
+
+printf ("select fd is %d\n", select_fd);
+	FD_ZERO (&read_fds);
+	FD_SET (select_fd, &read_fds);
+	do {
+printf ("starting select\n");
+		result = select (select_fd + 1, &read_fds, 0, 0, 0);
+		if (result == -1) {
+			perror ("select\n");
+		}
+printf ("done with select\n");
+		saClmDispatch (&handle, SA_DISPATCH_ALL);
+	} while (result);
+
+	saClmClusterTrackStop (&handle);
+	saClmFinalize (&handle);
+
+	return (0);
+}

+ 54 - 0
test/testparse.c

@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include "../include/ais_types.h"
+#include "../exec/parse.h"
+#include "../exec/print.h"
+
+int main (void)
+{
+	char *error;
+	int result;
+
+	result = amfReadGroups (&error);
+	if (result == -1) {
+		printf ("Parse Error: %s\n", error);
+		exit (-1);
+	}
+	
+	saAmfPrintGroups ();
+
+	return (0);
+}

+ 75 - 0
test/testtimer.c

@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@mvista.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+
+#include "../exec/timer.h"
+
+void timer_function (void *data)
+{
+	printf ("timer %p\n", data);
+}	
+
+int main (void)
+{
+	int msec;
+	struct timer *timer;
+	int randomvalue;
+	int i;
+
+printf ("adding timers\n");
+	for (i = 0; i < 1000; i++) {
+		timer = (struct timer *)malloc (sizeof (struct timer));
+		randomvalue = random()%5000;
+		timer->function = timer_function;
+		timer->data = (void *)randomvalue;
+		timer_add_msec_in_future (timer, randomvalue);
+	}
+printf ("done adding timers\n");
+
+	for (;;) {
+		msec = timer_expire_get_msec();
+//		printf ("msec to next timer expire %d\n", msec);
+		if (msec == -1) {
+			printf ("no more timers\n");
+			break;
+		}
+		poll (0, 0, msec);
+		timer_expire ();
+	}
+
+	return (0);
+}