>From f4df1f84092d11b916614e23bfd309a7ed5011af Mon Sep 17 00:00:00 2001
From: Steven Dake <sdake@redhat.com>
Date: Thu, 13 May 2010 15:13:44 -0700
Subject: [PATCH] This initial patch formulates the start of the vinzvault repo.  Currently the
 project uses automake.  To bulid, run ./autogen.sh followed by configure
 followed by make.

To configure the software, src/main.c must be hand modified.  The README file
contains more details about how to do this.

The software currently implements D1HT EDRA.  An example run should produce
output like this:
[root@vm-12 src]# ./vinzvault
vinzvault [D1HTNE] Initializing transport (UDP/IP).
vinzvault [D1HTUD] Initializing transmit/receive security: not using security (mode 0).
vinzvault [D1HTUD] The network interface [10.16.32.112] is now up.
vinzvault [D1HTED] JOINED member (10.16.32.112)
vinzvault [D1HTED] JOINED member (10.16.32.109)
vinzvault [D1HTED] JOINED member (10.16.32.110)
vinzvault [D1HTED] JOINED member (10.16.32.111)
vinzvault [D1HTED] LEAVING member (10.16.32.109)
vinzvault [D1HTED] LEAVING member (10.16.32.110)

Signed-off-by: Steven Dake <sdake@redhat.com>
---
 AUTHORS             |   11 +
 COPYING             |  340 ++++++++++
 LICENSE             |   34 +
 Makefile.am         |   26 +
 README              |   82 +++
 autogen.sh          |    5 +
 configure.ac        |  390 ++++++++++++
 include/Makefile.am |   23 +
 loc                 |    4 +
 src/Makefile.am     |   47 ++
 src/d1ht.h          |   69 ++
 src/d1htedra.c      |  902 +++++++++++++++++++++++++++
 src/d1htedra.h      |   45 ++
 src/d1htip.c        |  630 +++++++++++++++++++
 src/d1htip.h        |   85 +++
 src/d1htnet.c       |  195 ++++++
 src/d1htnet.h       |   60 ++
 src/d1htpoll.c      |  480 ++++++++++++++
 src/d1htpoll.h      |   97 +++
 src/d1htudp.c       | 1125 +++++++++++++++++++++++++++++++++
 src/d1htudp.h       |   65 ++
 src/hdb.h           |  461 ++++++++++++++
 src/list.h          |   86 +++
 src/logsys.c        | 1717 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/logsys.h        |  431 +++++++++++++
 src/main.c          |   92 +++
 src/swab.h          |   49 ++
 src/tlist.h         |  301 +++++++++
 28 files changed, 7852 insertions(+), 0 deletions(-)
 create mode 100644 AUTHORS
 create mode 100644 COPYING
 create mode 100644 LICENSE
 create mode 100644 Makefile.am
 create mode 100755 README
 create mode 100755 autogen.sh
 create mode 100644 configure.ac
 create mode 100644 include/Makefile.am
 create mode 100755 loc
 create mode 100644 src/Makefile.am
 create mode 100644 src/d1ht.h
 create mode 100644 src/d1htedra.c
 create mode 100644 src/d1htedra.h
 create mode 100644 src/d1htip.c
 create mode 100644 src/d1htip.h
 create mode 100644 src/d1htnet.c
 create mode 100644 src/d1htnet.h
 create mode 100644 src/d1htpoll.c
 create mode 100644 src/d1htpoll.h
 create mode 100644 src/d1htudp.c
 create mode 100644 src/d1htudp.h
 create mode 100644 src/hdb.h
 create mode 100644 src/list.h
 create mode 100644 src/logsys.c
 create mode 100644 src/logsys.h
 create mode 100644 src/main.c
 create mode 100644 src/swab.h
 create mode 100644 src/tlist.h

diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..1a9beac
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,11 @@
+Christine Caulfield <ccaulfie@redhat.com>
+* IP Abstractions, UDP layer, NSS integration
+
+Steven Dake <sdake@redhat.com>
+* d1ht, automake
+
+Jim Meyering <jim@meyering.net>
+* Initial automake framework
+
+Fabio M. Di Nitto <fdinitto@redhat.com>
+* logsys, automake
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7ab29d5
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,34 @@
+The license of all files are clearly marked in the individual file copyright.
+
+The vinzvault software distribution is available under the terms of the
+GNU Public License version 2.  See COPYING for a full copy of the license.
+
+Some components of vinzvault are avaliable under Modified BSD license without
+attribution clause.  The full text of that license is here:
+
+Copyright (C) 2002-2004 MontaVista Software
+Copyright (C) 2004-2010 Red Hat, Inc.
+
+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.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..ee1fe31
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,26 @@
+EXTRA_DIST		= 
+
+AUTOMAKE_OPTIONS	= foreign
+
+MAINTAINERCLEANFILES	= Makefile.in aclocal.m4 configure depcomp	\
+			  config.guess config.sub missing install-sh	\
+			  autoheader automake autoconf config.status	\
+			  config.log
+
+dist_doc_DATA		= AUTHORS COPYING LICENSE
+
+corosysconfdir		= ${VINZVAULTCONFDIR}
+
+corosysconf_DATA	= 
+
+SUBDIRS			= include src
+
+install-exec-local:
+
+uninstall-local:
+
+lint:
+	for dir in src; do make -C $$dir lint; done
+
+dist-clean-local:
+	rm -f autoconf automake autoheader
diff --git a/README b/README
new file mode 100755
index 0000000..2c440f8
--- /dev/null
+++ b/README
@@ -0,0 +1,82 @@
+------------
+Introduction
+------------
+Vinzvault is a key/value storage system designed for virtual machine image
+files.  We intend to trade off high cost components that offer better
+performance at lower scale, for lower cost components that offer very large
+scale.  We want our software to work for 100,000 physical node datacenters.
+
+---------------------
+To build the software
+---------------------
+bigiron% ./autogen.sh
+bigiron% ./configure
+bigiron% ./make
+
+The software currently has no configuration file.  The configuration is
+hardcoded in main.c.
+
+The really important configuration options are these IP addresses.
+
+        d1htip_parse (&d1ht_config.interface.bindnet, "10.16.32.0", AF_INET);
+
+        d1htip_parse (&d1ht_config.search_addr[0], "10.16.32.109", AF_INET);
+
+        d1htip_parse (&d1ht_config.search_addr[1], "10.16.32.110", AF_INET);
+
+bindnet is used to bind to the network interface on your local system.
+
+search_addr[0] and search_addr[1] is where to search for the active DHT.
+
+In my systems, I use 10.16.32.109, start vinzvault there, then start on other
+nodes.  If you don't start search_addr[0] first there may be problems ;-)
+
+--------------
+Example Output
+--------------
+[root@north-12 src]# ./vinzvault
+vinzvault [D1HTNE] Initializing transport (UDP/IP).
+vinzvault [D1HTUD] Initializing transmit/receive security: not using security (mode 0).
+vinzvault [D1HTUD] The network interface [10.16.32.112] is now up.
+vinzvault [D1HTED] JOINED member (10.16.32.112)
+vinzvault [D1HTED] JOINED member (10.16.32.109)
+vinzvault [D1HTED] JOINED member (10.16.32.110)
+vinzvault [D1HTED] JOINED member (10.16.32.111)
+vinzvault [D1HTED] LEAVING member (10.16.32.109)
+vinzvault [D1HTED] LEAVING member (10.16.32.110)
+
+In this example vinzvault was started and immediately detected members
+112,109,110,111. then 109 and 110 were killed (via ctrl-c).
+
+----------
+components
+----------
+* funcitonal
+ A 100k node count capable scale overlay membership algorithm (D1HT EDRA)
+
+* not developed:
+A db interface that takes get/put requests on an individual node
+bsaed upon D1HT routing tables.
+A component that interfaces with kvm in some way to provide
+access to the D1HT routing tables.
+A component that converts an image file into block image that
+can be exported from vinzvault.
+probably some other things ;-=)
+
+-------------
+Project goals
+-------------
+* Easy to use, deploy, and manage.
+* 100,000 host count scalability.
+* Only depend on commodity hardware systems.
+* Migration works seamlessly within a datacenter without SAN hardware.
+* VM block images can be replicated to N where N is configurable per VM image.
+* VM block images can be replicated to various data centers.
+* Low latency block storage access for all VMs.
+* Tuneable block sizes per VM.
+* Use standard network mechanisms to transmit blocks to the various replicas.
+* Avoid multicast.
+* Ensure only authorized host machines may connect to the vinzvault storage
+  areas.
+* No central metadata server - everything is 100% distributed.
+
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..83770a1
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+echo Building configuration system...
+autoreconf -i && echo Now run ./configure and make
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..f5fe4e2
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,390 @@
+#
+# Copyright 2010 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# bootstrap / init
+AC_PREREQ([2.61])
+
+AC_INIT([vinzvault], [0.0.1], [vinzvault@fedorahosted.org])
+AM_INIT_AUTOMAKE([-Wno-portability])
+
+AC_CONFIG_SRCDIR([src/d1ht.h])
+AC_CONFIG_HEADER([include/vinzvault/config.h])
+
+AC_CANONICAL_HOST
+
+AC_LANG([C])
+
+dnl Fix default variables - "prefix" variable if not specified
+if test "$prefix" = "NONE"; then
+	prefix="/usr"
+
+	dnl Fix "localstatedir" variable if not specified
+	if test "$localstatedir" = "\${prefix}/var"; then
+		localstatedir="/var"
+	fi
+	dnl Fix "sysconfdir" variable if not specified
+	if test "$sysconfdir" = "\${prefix}/etc"; then
+		sysconfdir="/etc"
+	fi
+	dnl Fix "libdir" variable if not specified
+	if test "$libdir" = "\${exec_prefix}/lib"; then
+		if test -e /usr/lib64; then
+			libdir="/usr/lib64"
+		else
+			libdir="/usr/lib"
+		fi
+	fi
+fi
+
+# check stolen from gnulib/m4/gnu-make.m4
+if ! ${MAKE-make} --version /cannot/make/this >/dev/null 2>&1; then
+	AC_MSG_ERROR([you don't seem to have GNU make; it is required])
+fi
+
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+AC_CHECK_PROGS([GROFF], [groff])
+
+# Checks for libraries.
+AC_CHECK_LIB([dl], [dlopen])
+AC_CHECK_LIB([pthread], [pthread_create])
+AC_CHECK_LIB([socket], [socket])
+AC_CHECK_LIB([nsl], [t_open])
+AC_CHECK_LIB([rt], [sched_getscheduler])
+
+# Checks for header files.
+AC_FUNC_ALLOCA
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netdb.h netinet/in.h stdint.h \
+		  stdlib.h string.h sys/ioctl.h sys/param.h sys/socket.h \
+		  sys/time.h syslog.h unistd.h sys/types.h getopt.h malloc.h \
+		  sys/sockio.h utmpx.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_UID_T
+AC_C_INLINE
+AC_TYPE_INT16_T
+AC_TYPE_INT32_T
+AC_TYPE_INT64_T
+AC_TYPE_INT8_T
+AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
+AC_HEADER_TIME
+AC_TYPE_UINT16_T
+AC_TYPE_UINT32_T
+AC_TYPE_UINT64_T
+AC_TYPE_UINT8_T
+AC_C_VOLATILE
+
+# Checks for library functions.
+AC_FUNC_CLOSEDIR_VOID
+AC_FUNC_ERROR_AT_LINE
+AC_REPLACE_FNMATCH
+AC_FUNC_FORK
+AC_PROG_GCC_TRADITIONAL
+AC_FUNC_MALLOC
+AC_FUNC_MEMCMP
+AC_FUNC_REALLOC
+AC_FUNC_SELECT_ARGTYPES
+AC_TYPE_SIGNAL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS([alarm alphasort atexit bzero dup2 endgrent endpwent fcntl \
+		getcwd getpeerucred getpeereid gettimeofday inet_ntoa memmove \
+		memset mkdir scandir select socket strcasecmp strchr strdup \
+		strerror strrchr strspn strstr pthread_spin_lock \
+		pthread_spin_unlock pthread_setschedparam \
+		sched_get_priority_max sched_setscheduler])
+
+AC_CONFIG_FILES([Makefile
+		 include/Makefile
+		 src/Makefile])
+
+### Local business
+
+# ===============================================
+# Helpers
+# ===============================================
+
+## helper for CC stuff
+cc_supports_flag() {
+	local CFLAGS="$@"
+	AC_MSG_CHECKING([whether $CC supports "$@"])
+	AC_COMPILE_IFELSE([int main(){return 0;}] ,
+			  [RC=0; AC_MSG_RESULT([yes])],
+			  [RC=1; AC_MSG_RESULT([no])])
+	return $RC
+}
+
+## cleanup
+AC_MSG_NOTICE(Sanitizing prefix: ${prefix})
+case $prefix in
+  NONE) prefix=/usr/local;;
+esac
+
+AC_MSG_NOTICE(Sanitizing exec_prefix: ${exec_prefix})
+case $exec_prefix in
+  dnl For consistency with Vinzvault, map NONE->$prefix
+  NONE)   exec_prefix=$prefix;;
+  prefix) exec_prefix=$prefix;;
+esac
+
+## local defines
+PACKAGE_FEATURES=""
+
+LINT_FLAGS="-weak -unrecog +posixlib +ignoresigns -fcnuse \
+	-badflag -D__gnuc_va_list=va_list -D__attribute\(x\)="
+
+AC_ARG_ENABLE([fatal-warnings],
+	[  --enable-fatal-warnings : enable fatal warnings. ],
+	[ default="no" ])
+
+AC_ARG_ENABLE([debug],
+	[ --enable-debug          : enable debug build. ],
+	[ default="no" ])
+
+AC_ARG_ENABLE([coverage],
+	[  --enable-coverage       : coverage analysis of the codebase. ],
+	[ default="no" ])
+
+AC_ARG_WITH([initddir],
+	[  --with-initddir=DIR     : path to init script directory. ],
+	[ INITDDIR="$withval" ],
+	[ INITDDIR="$sysconfdir/init.d" ])
+
+# OS detection
+# THIS SECTION MUST DIE!
+CP=cp
+OS_LDL="-ldl"
+case "$host_os" in
+	*linux*)
+		AC_DEFINE_UNQUOTED([COROSYNC_LINUX], [1],
+				   [Compiling for Linux platform])
+		OS_CFLAGS=""
+		OS_CPPFLAGS=""
+		OS_LDFLAGS=""
+		OS_DYFLAGS="-rdynamic"
+		DARWIN_OPTS=""
+	;;
+	*)
+		AC_MSG_ERROR([Unsupported OS? hmmmm])
+	;;
+esac
+
+AC_SUBST(CP)
+# *FLAGS handling goes here
+
+ENV_CFLAGS="$CFLAGS"
+ENV_CPPFLAGS="$CPPFLAGS"
+ENV_LDFLAGS="$LDFLAGS"
+
+# debug build stuff
+if test "x${enable_debug}" = xyes; then
+	AC_DEFINE_UNQUOTED([DEBUG], [1], [Compiling Debugging code])
+	OPT_CFLAGS="-O0"
+	PACKAGE_FEATURES="$PACKAGE_FEATURES debug"
+else
+	OPT_CFLAGS="-O3"
+fi
+
+# gdb flags
+if test "x${GCC}" = xyes; then
+	GDB_FLAGS="-ggdb3"
+else
+	GDB_FLAGS="-g"
+fi
+
+# Look for libnss
+if test "x${enable_nss}" = xyes; then
+	PKG_CHECK_MODULES([nss],[nss])
+	AC_DEFINE_UNQUOTED([HAVE_LIBNSS], 1, [have libnss])
+	PACKAGE_FEATURES="$PACKAGE_FEATURES nss"
+fi
+
+if test "x${enable_testagents}" = xyes; then
+	AC_DEFINE_UNQUOTED([HAVE_TESTAGENTS], 1, [have testagents])
+	PACKAGE_FEATURES="$PACKAGE_FEATURES testagents"
+fi
+
+if test "x${enable_rdma}" = xyes; then
+	PKG_CHECK_MODULES([rdmacm],[rdmacm])
+	PKG_CHECK_MODULES([ibverbs],[ibverbs])
+	AC_DEFINE_UNQUOTED([HAVE_RDMA], 1, [have rdmacm])
+	PACKAGE_FEATURES="$PACKAGE_FEATURES rdma"
+fi
+
+if test "x${enable_augeas}" = xyes; then
+	PACKAGE_FEATURES="$PACKAGE_FEATURES augeas"
+fi
+
+# extra warnings
+EXTRA_WARNINGS=""
+
+WARNLIST="
+	all
+	shadow
+	missing-prototypes
+	missing-declarations
+	strict-prototypes
+	declaration-after-statement
+	pointer-arith
+	write-strings
+	cast-align
+	bad-function-cast
+	missing-format-attribute
+	format=2
+	format-security
+	format-nonliteral
+	no-long-long
+	unsigned-char
+	gnu89-inline
+	no-strict-aliasing
+	"
+
+for j in $WARNLIST; do
+	if cc_supports_flag -W$j; then
+		EXTRA_WARNINGS="$EXTRA_WARNINGS -W$j";
+	fi
+done
+
+if test "x${enable_coverage}" = xyes && \
+		cc_supports_flag -ftest-coverage && \
+		cc_supports_flag -fprofile-arcs ; then
+	AC_MSG_NOTICE([Enabling Coverage (enable -O0 by default)])
+	OPT_CFLAGS="-O0"
+	COVERAGE_CFLAGS="-ftest-coverage -fprofile-arcs"
+	COVERAGE_LDFLAGS="-ftest-coverage -fprofile-arcs"
+	COVERAGE_LCRSO_EXTRA_LDFLAGS="-rdynamic"
+	PACKAGE_FEATURES="$PACKAGE_FEATURES coverage"
+else
+	COVERAGE_CFLAGS=""
+	COVERAGE_LDFLAGS=""
+	COVERAGE_LCRSO_EXTRA_LDFLAGS=""
+fi
+
+
+if test "x${enable_small_memory_footprint}" = xyes ; then
+	AC_DEFINE_UNQUOTED([HAVE_SMALL_MEMORY_FOOTPRINT], 1, [have small_memory_footprint])
+	PACKAGE_FEATURES="$PACKAGE_FEATURES small-memory-footprint"
+fi
+
+if test "x${enable_ansi}" = xyes && \
+		cc_supports_flag -std=iso9899:199409 ; then
+	AC_MSG_NOTICE([Enabling ANSI Compatibility])
+	ANSI_CPPFLAGS="-ansi -D_GNU_SOURCE -DANSI_ONLY"
+	PACKAGE_FEATURES="$PACKAGE_FEATURES ansi"
+else
+	ANSI_CPPFLAGS=""
+fi
+
+if test "x${enable_fatal_warnings}" = xyes && \
+		cc_supports_flag -Werror ; then
+	AC_MSG_NOTICE([Enabling Fatal Warnings (-Werror)])
+	WERROR_CFLAGS="-Werror"
+	PACKAGE_FEATURES="$PACKAGE_FEATURES fatal-warnings"
+else
+	WERROR_CFLAGS=""
+fi
+
+# final build of *FLAGS
+CFLAGS="$ENV_CFLAGS $OPT_CFLAGS $GDB_FLAGS $OS_CFLAGS \
+	$COVERAGE_CFLAGS $EXTRA_WARNINGS $WERROR_CFLAGS $NSS_CFLAGS"
+CPPFLAGS="$ENV_CPPFLAGS $ANSI_CPPFLAGS $OS_CPPFLAGS"
+LDFLAGS="$ENV_LDFLAGS $COVERAGE_LDFLAGS $OS_LDFLAGS"
+
+# substitute what we need:
+AC_SUBST([INITDDIR])
+AC_SUBST([LCRSODIR])
+AC_SUBST([SOCKETDIR])
+
+AC_SUBST([SOMAJOR])
+AC_SUBST([SOMINOR])
+AC_SUBST([SOMICRO])
+AC_SUBST([SONAME])
+AC_SUBST([COVERAGE_LCRSO_EXTRA_LDFLAGS])
+AC_SUBST([OS_DYFLAGS])
+
+AC_SUBST([OS_LDL])
+AM_CONDITIONAL(INSTALL_TESTAGENTS, test -n "${enable_testagents}")
+AM_CONDITIONAL(AUGTOOL, test -n "${AUGTOOL}")
+AC_SUBST([NSS_LDFLAGS])
+
+AM_CONDITIONAL(BUILD_DARWIN, test -n "${DARWIN_OPTS}")
+AM_CONDITIONAL(BUILD_SOLARIS, test -n "${SOLARIS_OPTS}")
+AC_SUBST([DARWIN_OPTS])
+AC_SUBST([SOLARIS_OPTS])
+
+AM_CONDITIONAL(BUILD_HTML_DOCS, test -n "${GROFF}")
+
+AC_SUBST([LINT_FLAGS])
+
+AC_DEFINE_UNQUOTED([LCRSODIR], "$(eval echo ${LCRSODIR})", [LCRSO directory])
+AC_DEFINE_UNQUOTED([SOCKETDIR], "$(eval echo ${SOCKETDIR})", [Socket directory])
+AC_DEFINE_UNQUOTED([LOCALSTATEDIR], "$(eval echo ${localstatedir})", [localstate directory])
+
+COROSYSCONFDIR=${sysconfdir}/vinzvault
+AC_SUBST([COROSYSCONFDIR])
+AC_DEFINE_UNQUOTED([COROSYSCONFDIR], "$(eval echo ${COROSYSCONFDIR})", [vinzvault config directory])
+
+AC_DEFINE_UNQUOTED([PACKAGE_FEATURES], "${PACKAGE_FEATURES}", [vinzvault built-in features])
+
+AC_OUTPUT
+
+AC_MSG_RESULT([])
+AC_MSG_RESULT([$PACKAGE configuration:])
+AC_MSG_RESULT([  Version                  = ${VERSION}])
+AC_MSG_RESULT([  Prefix                   = ${prefix}])
+AC_MSG_RESULT([  Executables              = ${sbindir}])
+AC_MSG_RESULT([  Man pages                = ${mandir}])
+AC_MSG_RESULT([  Doc dir                  = ${docdir}])
+AC_MSG_RESULT([  Libraries                = ${libdir}])
+AC_MSG_RESULT([  Header files             = ${includedir}])
+AC_MSG_RESULT([  Arch-independent files   = ${datadir}])
+AC_MSG_RESULT([  State information        = ${localstatedir}])
+AC_MSG_RESULT([  System configuration     = ${sysconfdir}])
+AC_MSG_RESULT([  System init.d directory  = ${INITDDIR}])
+AC_MSG_RESULT([  vinzvault config dir      = ${COROSYSCONFDIR}])
+AC_MSG_RESULT([  LCRSO                    = ${LCRSODIR}])
+AC_MSG_RESULT([  SOCKETDIR                = ${SOCKETDIR}])
+AC_MSG_RESULT([  Features                 =${PACKAGE_FEATURES}])
+AC_MSG_RESULT([])
+AC_MSG_RESULT([$PACKAGE build info:])
+AC_MSG_RESULT([  Library SONAME           = ${SONAME}])
+LIB_MSG_RESULT(m4_shift(local_soname_list))dnl
+AC_MSG_RESULT([  Default optimization     = ${OPT_CFLAGS}])
+AC_MSG_RESULT([  Default debug options    = ${GDB_CFLAGS}])
+AC_MSG_RESULT([  Extra compiler warnings  = ${EXTRA_WARNING}])
+AC_MSG_RESULT([  Env. defined CFLAG       = ${ENV_CFLAGS}])
+AC_MSG_RESULT([  Env. defined CPPFLAGS    = ${ENV_CPPFLAGS}])
+AC_MSG_RESULT([  Env. defined LDFLAGS     = ${ENV_LDFLAGS}])
+AC_MSG_RESULT([  OS   defined CFLAGS      = ${OS_CFLAGS}])
+AC_MSG_RESULT([  OS   defined CPPFLAGS    = ${OS_CPPFLAGS}])
+AC_MSG_RESULT([  OS   defined LDFLAGS     = ${OS_LDFLAGS}])
+AC_MSG_RESULT([  OS   defined LDL         = ${OS_LDL}])
+AC_MSG_RESULT([  OS   defined DYFLAGS     = ${OS_DYFLAGS}])
+AC_MSG_RESULT([  ANSI defined CPPFLAGS    = ${ANSI_CPPFLAGS}])
+AC_MSG_RESULT([  Coverage     CFLAGS      = ${COVERAGE_CFLAGS}])
+AC_MSG_RESULT([  Coverage     LDFLAGS     = ${COVERAGE_LDFLAGS}])
+AC_MSG_RESULT([  Fatal War.   CFLAGS      = ${WERROR_CFLAGS}])
+AC_MSG_RESULT([  Final        CFLAGS      = ${CFLAGS}])
+AC_MSG_RESULT([  Final        CPPFLAGS    = ${CPPFLAGS}])
+AC_MSG_RESULT([  Final        LDFLAGS     = ${LDFLAGS}])
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..52b72c7
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,23 @@
+#
+# Copyright 2010 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+MAINTAINERCLEANFILES    = Makefile.in vinzvault/config.h.in
+
+VV_H			= vv_config.h
+VV_INTERNAL_H		=
+noinst_HEADERS          = $(VV_INTERNAL_H:%=vinzvault/%)
+
+nobase_include_HEADERS	= 
diff --git a/loc b/loc
new file mode 100755
index 0000000..a411c65
--- /dev/null
+++ b/loc
@@ -0,0 +1,4 @@
+echo "VinzVault Source LOC"
+echo "--------------------"
+echo -n "src LOC     "
+printf "%7.7s\n" `find src -name *.[ch] -exec cat {} \; | wc -l`
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..19d298f
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,47 @@
+#
+# Copyright 2010 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+MAINTAINERCLEANFILES	= Makefile.in
+
+AM_CFLAGS		= -fPIC
+
+INCLUDES		= -I$(top_builddir)/include -I$(top_srcdir)/include $(nss_CFLAGS) $(rdmacm_CFLAGS) $(ibverbs_CFLAGS)
+
+
+sbin_PROGRAMS		= vinzvault
+
+vinzvault_SOURCES	= d1htpoll.c d1htip.c d1htnet.c d1htudp.c \
+			  d1htedra.c logsys.c main.c
+vinzvault_LDADD	  	= 
+vinzvault_DEPENDENCIES	=
+
+noinst_HEADERS		= tlist.h d1htnet.h d1htudp.h d1htip.h d1htedra.h
+
+EXTRA_DIST		= 
+
+lint:
+	-splint $(INCLUDES) $(LINT_FLAGS) $(CFLAGS) *.c
+
+all-local: 
+	@echo Built vinzvault Executive
+
+install-exec-local:
+
+uninstall-local:
+
+clean-local:
+	rm -f vinzvault vinzvault *.o *.lcrso gmon.out *.da *.bb *.bbg
diff --git a/src/d1ht.h b/src/d1ht.h
new file mode 100644
index 0000000..a22b31c
--- /dev/null
+++ b/src/d1ht.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef D1HT_H_DEFINED
+#define D1HT_H_DEFINED
+
+#include <stdint.h>
+#include "d1htip.h"
+#include "hdb.h"
+
+struct d1ht_interface {
+	struct d1ht_ip_address bindnet;
+	struct d1ht_ip_address boundto;
+	uint16_t ip_port;
+};
+
+enum { D1HT_PRIVATE_KEY_LEN = 128 };
+
+enum d1ht_crypto_type {
+	D1HT_CRYPTO_TYPE_NONE = 0,
+	D1HT_CRYPTO_TYPE_NSS_SYMMETRIC = 1
+};
+
+struct d1ht_config {
+	int version;
+
+	/*
+	 * network
+	 */
+	struct d1ht_interface interface;
+
+	struct d1ht_ip_address search_addr[10];
+
+	enum d1ht_crypto_type crypto_type;
+
+	/*
+	 * Configurable parameters
+	 */
+	uint32_t theta_timeout;
+
+	uint32_t tdetect_timeout;
+
+	uint32_t lookup_timeout;
+
+	/*
+	 * key information
+	 */
+	unsigned char private_key[D1HT_PRIVATE_KEY_LEN];
+
+	unsigned int private_key_len;
+
+	int transport_number;
+};
+
+#endif /* D1HT_H_DEFINED */
diff --git a/src/d1htedra.c b/src/d1htedra.c
new file mode 100644
index 0000000..60a4e6b
--- /dev/null
+++ b/src/d1htedra.c
@@ -0,0 +1,902 @@
+/*
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <config.h>
+
+#include <assert.h>
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sched.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <limits.h>
+
+#include "logsys.h"
+
+LOGSYS_DECLARE_SUBSYS("D1HTEDRA");
+
+#include "d1htedra.h"
+#include "d1htnet.h"
+
+#include "tlist.h"
+
+#define ENDIAN_LOCAL					 0xff22
+
+enum message_type {
+	MESSAGE_TYPE_EVENT = 0,
+	MESSAGE_TYPE_EVENT_RES = 1,
+	MESSAGE_TYPE_LOOKUP = 2,
+	MESSAGE_TYPE_LOOKUP_RES = 3,
+	MESSAGE_TYPE_INSERT = 4,
+	MESSAGE_TYPE_INSERT_RES = 5
+};
+
+enum event_type {
+	EVENT_TYPE_LEAVE,
+	EVENT_TYPE_JOIN
+};
+
+struct message_header {
+	uint16_t type;
+	uint16_t endian_detector;
+};
+
+struct stored_event {
+	struct d1ht_ip_address source;
+	enum event_type type;
+	uint32_t ttl;
+};
+
+struct msg_event {
+	struct message_header hdr;
+	struct d1ht_ip_address source;
+	uint32_t ttl;
+	uint32_t stored_events_count;
+	struct stored_event stored_events[32];
+};
+	
+struct msg_event_res {
+	struct message_header hdr;
+	struct d1ht_ip_address source;
+	uint32_t ttl;
+};
+
+struct msg_lookup {
+	struct message_header hdr;
+	struct d1ht_ip_address source;
+};
+
+struct msg_lookup_res {
+	struct message_header hdr;
+	struct d1ht_ip_address source;
+	struct d1ht_ip_address succ;
+};
+
+struct msg_insert {
+	struct message_header hdr;
+	struct d1ht_ip_address source;
+};
+
+struct msg_insert_res {
+	struct message_header hdr;
+	struct d1ht_ip_address source;
+	struct d1ht_ip_address new_member;
+	uint32_t my_member_count;
+	struct d1ht_ip_address my_member_list[64];
+};
+
+struct d1htedra_instance {
+	int iface_changes;
+
+	struct d1ht_ip_address my_id;
+
+	struct d1ht_ip_address my_member_list[1024];
+
+	uint32_t my_member_count;
+
+	uint32_t my_curr_idx;
+
+	struct stored_event stored_events[512];
+
+	uint32_t stored_events_count;
+
+	poll_timer_handle timer_theta;
+
+	poll_timer_handle timer_tdetect;
+
+	poll_timer_handle timer_lookup;
+
+	hdb_handle_t d1htedra_poll_handle;
+
+	void (*d1htedra_deliver_fn) (
+		unsigned int nodeid,
+		const void *msg,
+		unsigned int msg_len,
+		int endian_conversion_required);
+
+	void *d1htnet_context;
+
+	struct d1ht_config *d1ht_config;
+};
+
+struct message_handlers {
+	int count;
+	int (*handler_functions[7]) (
+		struct d1htedra_instance *instance,
+		const void *msg,
+		size_t msg_len,
+		int endian_conversion_needed);
+};
+
+/*
+ * forward decls
+ */
+static void main_deliver_fn (
+	void *context,
+	const void *msg,
+	unsigned int msg_len);
+
+static inline void member_pred (
+	struct d1htedra_instance *instance,
+	uint32_t steps,
+	struct d1ht_ip_address **pred);
+
+static inline void member_succ (
+	struct d1htedra_instance *instance,
+	uint32_t steps,
+	struct d1ht_ip_address **succ);
+
+static void reset_timer_lookup (struct d1htedra_instance *instance);
+
+static void reset_timer_theta (struct d1htedra_instance *instance);
+
+static void reset_timer_tdetect (struct d1htedra_instance *instance);
+
+static void msg_event_transmit (
+	struct d1htedra_instance *instance,
+	uint32_t ttl,
+	struct stored_event *stored_event,
+	uint32_t stored_event_count,
+	struct d1ht_ip_address *target);
+
+static void msg_event_res_transmit (
+	struct d1htedra_instance *instance,
+	uint32_t ttl,
+	struct d1ht_ip_address *target);
+
+static void msg_lookup_transmit (
+	struct d1htedra_instance *instance);
+
+static void msg_lookup_res_transmit (
+	struct d1htedra_instance *instance,
+	struct d1ht_ip_address *succ,
+	struct d1ht_ip_address *target);
+
+static void msg_insert_transmit (
+	struct d1htedra_instance *instance,
+	struct d1ht_ip_address *target);
+
+static void msg_insert_res_transmit (
+	struct d1htedra_instance *instance,
+	struct d1ht_ip_address *new_member,
+	struct d1ht_ip_address *target);
+
+static int message_handler_event (
+	struct d1htedra_instance *instance,
+	const void *msg,
+	size_t msg_len,
+	int endian_conversion_needed);
+
+static int message_handler_event_res (
+	struct d1htedra_instance *instance,
+	const void *msg,
+	size_t msg_len,
+	int endian_conversion_needed);
+
+static int message_handler_lookup (
+	struct d1htedra_instance *instance,
+	const void *msg,
+	size_t msg_len,
+	int endian_conversion_needed);
+
+static int message_handler_lookup_res (
+	struct d1htedra_instance *instance,
+	const void *msg,
+	size_t msg_len,
+	int endian_conversion_needed);
+		
+static int message_handler_insert (
+	struct d1htedra_instance *instance,
+	const void *msg,
+	size_t msg_len,
+	int endian_conversion_needed);
+
+static int message_handler_insert_res (
+	struct d1htedra_instance *instance,
+	const void *msg,
+	size_t msg_len,
+	int endian_conversion_needed);
+
+static void d1htedra_instance_initialize (struct d1htedra_instance *instance);
+
+struct message_handlers d1htedra_message_handlers = {
+	6,
+	{
+		message_handler_event,
+		message_handler_event_res,
+		message_handler_lookup,
+		message_handler_lookup_res,
+		message_handler_insert,
+		message_handler_insert_res,
+	}
+};
+
+static void main_iface_change_fn (
+	void *context,
+	const struct d1ht_ip_address *iface_addr);
+
+static inline uint32_t ones32(uint32_t x)
+{
+        x -= ((x >> 1) & 0x55555555);
+        x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
+        x = (((x >> 4) + x) & 0x0f0f0f0f);
+        x += (x >> 8);
+        x += (x >> 16);
+        return(x & 0x0000003f);
+}
+
+static inline uint32_t log2_ceiling (uint32_t x)
+{
+	int32_t y = (x & (x - 1));
+
+	y |= -y;
+	y >>= 31;
+	x |= (x >> 1);
+	x |= (x >> 2);
+	x |= (x >> 4);
+	x |= (x >> 8);
+	x |= (x >> 16);
+	return (ones32(x >> 1) - y);
+}
+
+static inline int power (uint32_t x, uint32_t y)
+{
+	uint32_t res;
+
+	uint32_t i;
+
+	if (y == 0) {
+		return 1;
+	}
+	if (y == 1) {
+		return x;
+	}
+
+	for (i = 0, res=1; i < y; i++) {
+		res = res * x;
+	}
+	return (res);
+}
+
+static void d1htedra_instance_initialize (struct d1htedra_instance *instance)
+{
+	memset (instance, 0, sizeof (struct d1htedra_instance));
+}
+
+/*
+ * Exported interfaces
+ */
+int d1htedra_initialize (
+	hdb_handle_t poll_handle,
+	void **srp_context,
+	struct d1ht_config *d1ht_config)
+{
+	struct d1htedra_instance *instance;
+
+	instance = malloc (sizeof (struct d1htedra_instance));
+	if (instance == NULL) {
+		goto error_exit;
+	}
+	d1htedra_instance_initialize (instance);
+
+	instance->d1ht_config = d1ht_config;
+
+	instance->d1htedra_poll_handle = poll_handle;
+
+	d1htnet_initialize (
+		poll_handle,
+		&instance->d1htnet_context,
+		d1ht_config,
+		instance,
+		main_deliver_fn,
+		main_iface_change_fn);
+
+	*srp_context = instance;
+	return (0);
+
+error_exit:
+	return (-1);
+}
+
+void d1htedra_finalize (
+	void *srp_context)
+{
+//	struct d1htedra_instance *instance = (struct d1htedra_instance *)srp_context;
+
+	free (srp_context);
+}
+
+int d1htedra_crypto_set (
+	void *srp_context,
+	unsigned int type)
+{
+	struct d1htedra_instance *instance = (struct d1htedra_instance *)srp_context;
+	int res;
+
+	res = d1htnet_crypto_set(instance->d1htnet_context, type);
+
+	return (res);
+}
+
+int d1htedra_my_family_get (
+	void *srp_context)
+{
+	struct d1htedra_instance *instance = (struct d1htedra_instance *)srp_context;
+	int res;
+
+	res = instance->d1ht_config->interface.boundto.family;
+
+	return (res);
+}
+
+static int my_d1htip_compare (const void *a, const void *b)
+{
+	const struct d1ht_ip_address *d1ht_ip_a = (const struct d1ht_ip_address *)a;
+	const struct d1ht_ip_address *d1ht_ip_b = (const struct d1ht_ip_address *)b;
+
+	return (d1htip_compare (d1ht_ip_a, d1ht_ip_b));
+}
+
+static inline void member_add (
+	struct d1htedra_instance *instance,
+	struct d1ht_ip_address *addr)
+{
+	uint32_t i;
+
+	/*
+	 * Prevent duplicate membership additions
+	 */
+	for (i = 0; i < instance->my_member_count; i++) {
+		if (d1htip_compare (&instance->my_member_list[i], addr) == 0) {
+			return;
+		}
+	}
+		
+	log_printf (LOGSYS_LEVEL_NOTICE, "JOINED member (%s)\n",
+		d1htip_print (addr));
+	memcpy (&instance->my_member_list[instance->my_member_count],
+		addr, sizeof (struct d1ht_ip_address));
+	instance->my_member_count++;
+        qsort (instance->my_member_list, instance->my_member_count,
+		sizeof (struct d1ht_ip_address),
+                my_d1htip_compare);
+	for (i = 0; i < instance->my_member_count; i++) {
+		if (d1htip_compare (&instance->my_member_list[i], &instance->my_id) == 0) {
+			log_printf (LOGSYS_LEVEL_DEBUG, "my current idx %d\n",
+				i);
+			instance->my_curr_idx = i;
+			break;
+		}
+	}
+}
+
+static inline void member_del (
+	struct d1htedra_instance *instance,
+	struct d1ht_ip_address *addr)
+{
+	int i;
+	uint32_t found = 0;
+
+	for (i = 0; i < instance->my_member_count; i++) {
+		if (d1htip_compare (&instance->my_member_list[i], addr) == 0) {
+			memmove (&instance->my_member_list[i],
+				&instance->my_member_list[i + 1],
+				(instance->my_member_count - i - 1) * (sizeof (struct d1ht_ip_address)));
+			instance->my_member_count -= 1;
+
+			found = 1;
+			break;;
+		}
+	}
+	if (found == 0) {
+		return;
+	}
+	log_printf (LOGSYS_LEVEL_NOTICE, "LEAVING member (%s)\n",
+		d1htip_print (addr));
+	for (i = 0; i < instance->my_member_count; i++) {
+		if (d1htip_compare (&instance->my_member_list[i], &instance->my_id) == 0) {
+			log_printf (LOGSYS_LEVEL_DEBUG, "my current idx %d\n",
+				i);
+			instance->my_curr_idx = i;
+			break;
+		}
+	}
+}
+
+static inline void member_pred (
+	struct d1htedra_instance *instance,
+	uint32_t steps,
+	struct d1ht_ip_address **pred)
+{
+	uint32_t my_idx;
+
+	if (instance->my_member_count == 1) {
+		*pred = NULL;
+		return;
+	}
+	if (instance->my_curr_idx - steps >= 0xFFFF) {
+		my_idx = instance->my_member_count + instance->my_curr_idx - steps;
+	} else {
+		my_idx = (instance->my_curr_idx - steps) % instance->my_member_count;
+	}
+	*pred = &instance->my_member_list[my_idx];
+	log_printf (LOGSYS_LEVEL_DEBUG,
+		"pred is %s %d\n", d1htip_print (*pred), instance->my_member_count);
+}
+static inline void member_succ (
+	struct d1htedra_instance *instance,
+	uint32_t steps,
+	struct d1ht_ip_address **succ)
+{
+	uint32_t my_idx;
+
+	if (instance->my_member_count == 0) {
+		*succ = NULL;
+		return;
+	}
+	my_idx = (instance->my_curr_idx + steps) % instance->my_member_count;
+	*succ = &instance->my_member_list[my_idx];
+	log_printf (LOGSYS_LEVEL_DEBUG,
+		"successor is %s my_idx %d cur_idx %d steps %d members %d\n", d1htip_print (*succ), my_idx, instance->my_curr_idx, steps, instance->my_member_count);
+}
+
+static void store_event (
+	struct d1htedra_instance *instance,
+	struct d1ht_ip_address *source,
+	enum event_type type)
+{
+	d1htip_copy (&instance->stored_events[instance->stored_events_count].source, source);
+	instance->stored_events[instance->stored_events_count].type = type;
+	instance->stored_events[instance->stored_events_count].ttl = 0;
+	instance->stored_events_count += 1;
+}
+	
+static void reset_events (struct d1htedra_instance *instance)
+{
+	instance->stored_events_count = 0;
+}
+
+static void timer_function_lookup (void *data)
+{
+	msg_lookup_transmit (data);
+	reset_timer_lookup (data);
+}
+
+static void timer_function_theta (void *data)
+{
+	struct d1htedra_instance *instance = (struct d1htedra_instance *)data;
+	static struct d1ht_ip_address *target;
+
+	int i = 0;
+	uint32_t ttl;
+	uint32_t log_node_count;
+
+	reset_timer_theta (instance);
+
+	/*
+	 * No membership and no stored event count - noop
+	 */
+	if (instance->my_member_count == 0 &&
+		instance->stored_events_count == 0) {
+		return;
+	}
+
+	if (instance->stored_events_count) {
+		log_printf (LOGSYS_LEVEL_DEBUG, "propogating events:\n");
+	}
+	for (i = 0; i < instance->stored_events_count; i++) {
+		log_printf (LOGSYS_LEVEL_DEBUG,
+			"event %d node %s got event type %d\n", i,
+			d1htip_print (&instance->stored_events[i].source),
+			instance->stored_events[i].type);
+	}
+
+	log_node_count = log2_ceiling (instance->my_member_count);
+
+	for (ttl = 0; ttl < log_node_count; ttl++) {
+		member_succ (instance, power (2,ttl), &target);
+		log_printf (LOGSYS_LEVEL_DEBUG, "theta targets nodecount %d log_node_count %d %s ttl = %d\n",
+			instance->my_member_count, log_node_count, d1htip_print (target), ttl);
+		msg_event_transmit (instance,
+			ttl,
+			instance->stored_events,
+			instance->stored_events_count,
+			target);
+	}
+	reset_events (instance);
+}
+
+static void timer_function_tdetect (void *data)
+{
+	struct d1htedra_instance *instance = (struct d1htedra_instance *)data;
+
+	uint32_t ttl;
+	uint32_t log_node_count;
+	struct d1ht_ip_address *pred;
+	struct d1ht_ip_address pred_copy;
+	struct d1ht_ip_address *target;
+
+	log_printf (LOGSYS_LEVEL_DEBUG,
+		"previous member lost\n");
+	member_pred (instance, 1, &pred);
+	d1htip_copy (&pred_copy, pred);
+	store_event (instance, pred, EVENT_TYPE_LEAVE);
+	member_del (instance, &pred_copy);
+
+	log_node_count = log2_ceiling (instance->my_member_count);
+
+	for (ttl = 0; ttl < log_node_count; ttl++) {
+		member_succ (instance, power (2,ttl), &target);
+		log_printf (LOGSYS_LEVEL_DEBUG, "tdetect targets %s ttl = %d\n", d1htip_print (target), ttl);
+		msg_event_transmit (instance,
+			ttl,
+			instance->stored_events,
+			instance->stored_events_count,
+			target);
+	}
+	reset_events (instance);
+}
+
+static void cancel_timer_lookup (struct d1htedra_instance *instance)
+{
+	poll_timer_delete (instance->d1htedra_poll_handle,
+		instance->timer_lookup);
+}
+
+static void reset_timer_lookup (struct d1htedra_instance *instance)
+{
+	poll_timer_delete (instance->d1htedra_poll_handle,
+		instance->timer_lookup);
+	poll_timer_add (instance->d1htedra_poll_handle,
+		instance->d1ht_config->lookup_timeout,
+		(void *)instance,
+		timer_function_lookup,
+		&instance->timer_lookup);
+}
+
+static void reset_timer_theta (struct d1htedra_instance *instance)
+{
+	poll_timer_delete (instance->d1htedra_poll_handle,
+		instance->timer_theta);
+	poll_timer_add (instance->d1htedra_poll_handle,
+		instance->d1ht_config->theta_timeout,
+		(void *)instance,
+		timer_function_theta,
+		&instance->timer_theta);
+}
+
+static void reset_timer_tdetect (struct d1htedra_instance *instance)
+{
+	poll_timer_delete (instance->d1htedra_poll_handle,
+		instance->timer_tdetect);
+	poll_timer_add (instance->d1htedra_poll_handle,
+		instance->d1ht_config->tdetect_timeout,
+		(void *)instance,
+		timer_function_tdetect,
+		&instance->timer_tdetect);
+}
+
+static int message_handler_event (
+	struct d1htedra_instance *instance,
+	const void *msg,
+	size_t msg_len,
+	int endian_conversion_needed)
+{
+	struct msg_event *msg_event = (struct msg_event *)msg;
+	struct d1ht_ip_address *target;
+	int i;
+	uint32_t my_ttl;
+	
+	log_printf (LOGSYS_LEVEL_DEBUG, "message_handler_event\n");
+	reset_timer_tdetect (instance);
+	for (i = 0; i < msg_event->stored_events_count; i++) {
+		if (msg_event->stored_events[i].type == EVENT_TYPE_JOIN) {
+			member_add (instance, &msg_event->stored_events[i].source);
+		} else {
+			member_del (instance, &msg_event->stored_events[i].source);
+		}
+	}
+
+	msg_event_res_transmit (instance, msg_event->ttl, &msg_event->source);
+
+	if (msg_event->ttl) {
+		my_ttl = msg_event->ttl - 1;
+		for (i = 0; i <= my_ttl; i++) {
+			msg_event->ttl -= 1;
+			d1htip_copy (&msg_event->source, &instance->my_id);
+			member_succ (instance, power (2, i), &target);
+			log_printf (LOGSYS_LEVEL_DEBUG,
+				"handler event targets %s ttl = %d\n", d1htip_print (target), msg_event->ttl);
+			d1htnet_unicast_send (instance->d1htnet_context, 
+				msg_event,
+				sizeof (struct msg_event),
+				target);
+		}
+	}
+	
+	return (0);
+}
+static int message_handler_event_res (
+	struct d1htedra_instance *instance,
+	const void *msg,
+	size_t msg_len,
+	int endian_conversion_needed)
+{
+	struct msg_event_res *msg_event_res = (struct msg_event_res *)msg;
+
+	msg_event_res = 0;
+	log_printf (LOGSYS_LEVEL_DEBUG, "message_handler_event_res\n");
+//	remove_event (instance, msg_event_res->ttl);
+	return (0);
+}
+
+static int message_handler_lookup (
+	struct d1htedra_instance *instance,
+	const void *msg,
+	size_t msg_len,
+	int endian_conversion_needed)
+{
+	struct msg_lookup *msg_lookup = (void *)msg;
+	struct d1ht_ip_address *succ;
+
+	log_printf (LOGSYS_LEVEL_DEBUG, "message_handler_lookup\n");
+
+	member_succ (instance, 1, &succ);
+	msg_lookup_res_transmit (instance, succ, &msg_lookup->source);
+	return (0);
+}
+
+static int message_handler_lookup_res (
+	struct d1htedra_instance *instance,
+	const void *msg,
+	size_t msg_len,
+	int endian_conversion_needed)
+{
+	struct msg_lookup_res *msg_lookup_res = (void *)msg;
+
+	log_printf (LOGSYS_LEVEL_DEBUG, "message_handler_lookup_res\n");
+
+	msg_insert_transmit (instance, &msg_lookup_res->succ);
+	return (0);
+}
+
+static int message_handler_insert (
+	struct d1htedra_instance *instance,
+	const void *msg,
+	size_t msg_len,
+	int endian_conversion_needed)
+{
+	struct msg_insert *msg_insert = (void *)msg;
+
+	msg_insert_res_transmit (instance, &msg_insert->source, &msg_insert->source);
+	return (0);
+}
+
+static int message_handler_insert_res (
+	struct d1htedra_instance *instance,
+	const void *msg,
+	size_t msg_len,
+	int endian_conversion_needed)
+{
+	uint32_t i;
+
+	struct msg_insert_res *msg_insert_res = (void *)msg;
+
+	log_printf (LOGSYS_LEVEL_DEBUG, "message_handler_insert_res\n");
+	for (i = 0; i < msg_insert_res->my_member_count; i++) {
+		member_add (instance, &msg_insert_res->my_member_list[i]);
+	}
+	store_event (instance, &msg_insert_res->new_member, EVENT_TYPE_JOIN);
+	cancel_timer_lookup (instance);
+	return (0);
+}
+
+static void msg_event_res_transmit (
+	struct d1htedra_instance *instance,
+	uint32_t ttl,
+	struct d1ht_ip_address *target)
+{
+	struct msg_event_res msg_event_res;
+
+	msg_event_res.hdr.type = MESSAGE_TYPE_EVENT_RES;
+	msg_event_res.hdr.endian_detector = ENDIAN_LOCAL;
+	d1htip_copy (&msg_event_res.source, &instance->my_id);
+
+	d1htnet_unicast_send (instance->d1htnet_context, 
+		&msg_event_res,
+		sizeof (struct msg_event_res),
+		target);
+}
+
+static void msg_lookup_transmit (struct d1htedra_instance *instance)
+{
+	struct msg_lookup msg_lookup;
+
+	msg_lookup.hdr.type = MESSAGE_TYPE_LOOKUP;
+	msg_lookup.hdr.endian_detector = ENDIAN_LOCAL;
+
+	d1htip_copy (&msg_lookup.source, &instance->my_id);
+
+	d1htnet_unicast_send (instance->d1htnet_context, 
+		&msg_lookup,
+		sizeof (struct msg_lookup),
+		&instance->d1ht_config->search_addr[0]);
+}
+
+static void msg_lookup_res_transmit (
+	struct d1htedra_instance *instance,
+	struct d1ht_ip_address *succ,
+	struct d1ht_ip_address *target)
+{
+	struct msg_lookup_res msg_lookup_res;
+
+	msg_lookup_res.hdr.type = MESSAGE_TYPE_LOOKUP_RES;
+	msg_lookup_res.hdr.endian_detector = ENDIAN_LOCAL;
+	d1htip_copy (&msg_lookup_res.source, &instance->my_id);
+	d1htip_copy (&msg_lookup_res.succ, succ);
+
+	d1htnet_unicast_send (instance->d1htnet_context, 
+		&msg_lookup_res,
+		sizeof (struct msg_lookup_res),
+		target);
+}
+
+static void msg_insert_transmit (
+	struct d1htedra_instance *instance,
+	struct d1ht_ip_address *target)
+{
+	struct msg_insert msg_insert;
+
+	msg_insert.hdr.type = MESSAGE_TYPE_INSERT;
+	msg_insert.hdr.endian_detector = ENDIAN_LOCAL;
+	d1htip_copy (&msg_insert.source, &instance->my_id);
+
+	d1htnet_unicast_send (instance->d1htnet_context, 
+		&msg_insert,
+		sizeof (struct msg_insert),
+		target);
+}
+
+static void msg_insert_res_transmit (
+	struct d1htedra_instance *instance,
+	struct d1ht_ip_address *new_member,
+	struct d1ht_ip_address *target)
+{
+	struct msg_insert_res msg_insert_res;
+
+	msg_insert_res.hdr.type = MESSAGE_TYPE_INSERT_RES;
+	msg_insert_res.hdr.endian_detector = ENDIAN_LOCAL;
+	d1htip_copy (&msg_insert_res.source, &instance->my_id);
+	d1htip_copy (&msg_insert_res.new_member, new_member);
+
+	memcpy (msg_insert_res.my_member_list, instance->my_member_list,
+		instance->my_member_count * sizeof (struct d1ht_ip_address));
+	msg_insert_res.my_member_count = instance->my_member_count;
+
+	d1htnet_unicast_send (instance->d1htnet_context, 
+		&msg_insert_res,
+		sizeof (struct msg_insert_res),
+		target);
+}
+
+static void msg_event_transmit (
+	struct d1htedra_instance *instance,
+	uint32_t ttl,
+	struct stored_event *stored_event,
+	uint32_t stored_event_count,
+	struct d1ht_ip_address *target)
+{
+	struct msg_event msg_event;
+
+	if (ttl > 0 && instance->stored_events_count == 0) {
+		return;
+	}
+
+	msg_event.hdr.type = MESSAGE_TYPE_EVENT;
+	msg_event.hdr.endian_detector = ENDIAN_LOCAL;
+
+	d1htip_copy (&msg_event.source, &instance->my_id);
+	memcpy (msg_event.stored_events, stored_event,
+		sizeof (struct stored_event) * stored_event_count);
+	msg_event.stored_events_count = stored_event_count;
+	msg_event.ttl = ttl;
+
+	d1htnet_unicast_send (instance->d1htnet_context, 
+		&msg_event,
+		sizeof (struct msg_event),
+		target);
+}
+
+static void main_deliver_fn (
+	void *context,
+	const void *msg,
+	unsigned int msg_len)
+{
+	struct d1htedra_instance *instance = context;
+	const struct message_header *message_header = msg;
+	if (msg_len < sizeof (struct message_header)) {
+		log_printf (LOGSYS_LEVEL_NOTICE,
+			    "Received message is too short...  ignoring %u.\n",
+			    (unsigned int)msg_len);
+		return;
+	}
+
+	if ((int)message_header->type >= d1htedra_message_handlers.count) {
+		log_printf (LOGSYS_LEVEL_NOTICE,
+			"Type of received message is wrong...  ignoring %d.\n", (int)message_header->type);
+		return;
+	}
+
+	/*
+	 * Handle incoming message
+	 */
+	d1htedra_message_handlers.handler_functions[(int)message_header->type] (
+		instance,
+		msg,
+		msg_len,
+		message_header->endian_detector != ENDIAN_LOCAL);
+}
+
+void main_iface_change_fn (
+	void *context,
+	const struct d1ht_ip_address *iface_addr)
+{
+	struct d1htedra_instance *instance = context;
+
+	d1htip_copy (&instance->my_id, iface_addr);
+	member_add (instance, &instance->my_id);
+
+	timer_function_lookup (instance);
+	reset_timer_theta (instance);
+}
diff --git a/src/d1htedra.h b/src/d1htedra.h
new file mode 100644
index 0000000..ca8fcc7
--- /dev/null
+++ b/src/d1htedra.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef D1HTEDRA_H_DEFINED
+#define D1HTEDRA_H_DEFINED
+
+#include "d1ht.h"
+#include "d1htpoll.h"
+
+/*
+ * Create a protocol instance
+ */
+int d1htedra_initialize (
+	hdb_handle_t poll_handle,
+	void **srp_context,
+	struct d1ht_config *d1ht_config);
+
+void d1htedra_finalize (void *srp_context);
+
+extern int d1htedra_my_family_get (
+	void *srp_context);
+
+extern int d1htedra_crypto_set (
+	void *srp_context,
+	unsigned int type);
+
+void d1htedra_service_ready_register (
+	void *srp_context,
+	void (*totem_service_ready) (void));
+
+#endif /* D1HTEDRA_H_DEFINED */
diff --git a/src/d1htip.c b/src/d1htip.c
new file mode 100644
index 0000000..19360af
--- /dev/null
+++ b/src/d1htip.c
@@ -0,0 +1,630 @@
+/*
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <config.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#if defined(COROSYNC_SOLARIS)
+#include <net/if.h>
+#include <sys/sockio.h>
+#endif
+#if defined(COROSYNC_BSD) || defined(COROSYNC_DARWIN)
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <netinet/in_var.h>
+#include <netinet/in.h>
+#include <ifaddrs.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#if defined(COROSYNC_LINUX)
+#include <net/if.h>
+#include <asm/types.h>
+#include <linux/rtnetlink.h>
+#endif
+
+#include "d1htip.h"
+#include "swab.h"
+
+#define LOCALHOST_IPV4 "127.0.0.1"
+#define LOCALHOST_IPV6 "::1"
+
+#define NETLINK_BUFSIZE 16384
+
+#ifdef SO_NOSIGPIPE
+void d1htip_nosigpipe(int s)
+{
+	int on = 1;
+	setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&on, sizeof(on));
+}
+#endif
+
+/* Compare two addresses */
+int d1htip_equal(const struct d1ht_ip_address *addr1,
+		  const struct d1ht_ip_address *addr2)
+{
+	int addrlen = 0;
+
+	if (addr1->family != addr2->family)
+		return 0;
+
+	if (addr1->family == AF_INET) {
+		addrlen = sizeof(struct in_addr);
+	}
+	if (addr1->family == AF_INET6) {
+		addrlen = sizeof(struct in6_addr);
+	}
+	assert(addrlen);
+
+	if (memcmp(addr1->addr, addr2->addr, addrlen) == 0)
+		return 1;
+	else
+		return 0;
+
+}
+
+/* Copy a d1ht_ip_address */
+void d1htip_copy(struct d1ht_ip_address *addr1,
+		  const struct d1ht_ip_address *addr2)
+{
+	memcpy(addr1, addr2, sizeof(struct d1ht_ip_address));
+}
+
+void d1htip_copy_endian_convert(struct d1ht_ip_address *addr1,
+				 const struct d1ht_ip_address *addr2)
+{
+	addr1->nodeid = swab32(addr2->nodeid);
+	addr1->family = swab16(addr2->family);
+	memcpy(addr1->addr, addr2->addr, D1HTIP_ADDRLEN);
+}
+
+/* For sorting etc. params are void * for qsort's benefit */
+int d1htip_compare(const void *a, const void *b)
+{
+	int i;
+	const struct d1ht_ip_address *d1htip_a = (const struct d1ht_ip_address *)a;
+	const struct d1ht_ip_address *d1htip_b = (const struct d1ht_ip_address *)b;
+	struct in_addr ipv4_a1;
+	struct in_addr ipv4_a2;
+	struct in6_addr ipv6_a1;
+	struct in6_addr ipv6_a2;
+	unsigned short family;
+
+	/*
+	 * Use memcpy to align since d1ht_ip_address is unaligned on various archs
+	 */
+	memcpy (&family, &d1htip_a->family, sizeof (unsigned short));
+
+	if (family == AF_INET) {
+		memcpy (&ipv4_a1, d1htip_a->addr, sizeof (struct in_addr));
+		memcpy (&ipv4_a2, d1htip_b->addr, sizeof (struct in_addr));
+		if (ipv4_a1.s_addr == ipv4_a2.s_addr) {
+			return (0);
+		}
+		if (htonl(ipv4_a1.s_addr) < htonl(ipv4_a2.s_addr)) {
+			return -1;
+		} else {
+			return +1;
+		}
+	} else
+	if (family == AF_INET6) {
+		/*
+		 * We can only compare 8 bits at time for portability reasons
+		 */
+		memcpy (&ipv6_a1, d1htip_a->addr, sizeof (struct in6_addr));
+		memcpy (&ipv6_a2, d1htip_b->addr, sizeof (struct in6_addr));
+		for (i = 0; i < 16; i++) {
+			int res = ipv6_a1.s6_addr[i] -
+				ipv6_a2.s6_addr[i];
+			if (res) {
+				return res;
+			}
+		}
+		return 0;
+	} else {
+		/*
+		 * Family not set, should be!
+	 	 */
+		assert (0);
+	}
+	return 0;
+}
+
+/* Build a localhost d1ht_ip_address */
+int d1htip_localhost(int family, struct d1ht_ip_address *localhost)
+{
+	const char *addr_text;
+
+	memset (localhost, 0, sizeof (struct d1ht_ip_address));
+
+	if (family == AF_INET) {
+		addr_text = LOCALHOST_IPV4;
+		if (inet_pton(family, addr_text, (char *)&localhost->nodeid) <= 0) {
+			return -1;
+		}
+	} else {
+		addr_text = LOCALHOST_IPV6;
+	}
+
+	if (inet_pton(family, addr_text, (char *)localhost->addr) <= 0)
+		return -1;
+
+	localhost->family = family;
+
+	return 0;
+}
+
+int d1htip_localhost_check(const struct d1ht_ip_address *addr)
+{
+	struct d1ht_ip_address localhost;
+
+	if (d1htip_localhost(addr->family, &localhost))
+		return 0;
+	return d1htip_equal(addr, &localhost);
+}
+
+const char *d1htip_print(const struct d1ht_ip_address *addr)
+{
+	static char buf[INET6_ADDRSTRLEN];
+
+	return (inet_ntop(addr->family, addr->addr, buf, sizeof(buf)));
+}
+
+/* Make a d1ht_ip_address into a usable sockaddr_storage */
+int d1htip_d1htip_to_sockaddr_convert(struct d1ht_ip_address *ip_addr,
+					uint16_t port, struct sockaddr_storage *saddr, int *addrlen)
+{
+	int ret = -1;
+
+	if (ip_addr->family == AF_INET) {
+		struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
+
+		memset(sin, 0, sizeof(struct sockaddr_in));
+#if defined(COROSYNC_BSD) || defined(COROSYNC_DARWIN)
+		sin->sin_len = sizeof(struct sockaddr_in);
+#endif
+		sin->sin_family = ip_addr->family;
+		sin->sin_port = ntohs(port);
+		memcpy(&sin->sin_addr, ip_addr->addr, sizeof(struct in_addr));
+		*addrlen = sizeof(struct sockaddr_in);
+		ret = 0;
+	}
+
+	if (ip_addr->family == AF_INET6) {
+		struct sockaddr_in6 *sin = (struct sockaddr_in6 *)saddr;
+
+		memset(sin, 0, sizeof(struct sockaddr_in6));
+#if defined(COROSYNC_BSD) || defined(COROSYNC_DARWIN)
+		sin->sin6_len = sizeof(struct sockaddr_in6);
+#endif
+		sin->sin6_family = ip_addr->family;
+		sin->sin6_port = ntohs(port);
+		sin->sin6_scope_id = 2;
+		memcpy(&sin->sin6_addr, ip_addr->addr, sizeof(struct in6_addr));
+
+		*addrlen = sizeof(struct sockaddr_in6);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/* Converts an address string string into a d1ht_ip_address.
+   family can be AF_INET, AF_INET6 or 0 ("for "don't care")
+*/
+int d1htip_parse(struct d1ht_ip_address *d1htip, const char *addr, int family)
+{
+	struct addrinfo *ainfo;
+	struct addrinfo ahints;
+	struct sockaddr_in *sa;
+	struct sockaddr_in6 *sa6;
+	int ret;
+
+	memset(&ahints, 0, sizeof(ahints));
+	ahints.ai_socktype = SOCK_DGRAM;
+	ahints.ai_protocol = IPPROTO_UDP;
+	ahints.ai_family   = family;
+
+	/* Lookup the nodename address */
+	ret = getaddrinfo(addr, NULL, &ahints, &ainfo);
+	if (ret)
+		return -1;
+
+	sa = (struct sockaddr_in *)ainfo->ai_addr;
+	sa6 = (struct sockaddr_in6 *)ainfo->ai_addr;
+	d1htip->family = ainfo->ai_family;
+
+	if (ainfo->ai_family == AF_INET)
+		memcpy(d1htip->addr, &sa->sin_addr, sizeof(struct in_addr));
+	else
+		memcpy(d1htip->addr, &sa6->sin6_addr, sizeof(struct in6_addr));
+
+	return 0;
+}
+
+/* Make a sockaddr_* into a d1ht_ip_address */
+int d1htip_sockaddr_to_d1htip_convert(const struct sockaddr_storage *saddr,
+					struct d1ht_ip_address *ip_addr)
+{
+	int ret = -1;
+
+	ip_addr->family = saddr->ss_family;
+	ip_addr->nodeid = 0;
+
+	if (saddr->ss_family == AF_INET) {
+		const struct sockaddr_in *sin = (const struct sockaddr_in *)saddr;
+
+		memcpy(ip_addr->addr, &sin->sin_addr, sizeof(struct in_addr));
+		ret = 0;
+	}
+
+	if (saddr->ss_family == AF_INET6) {
+		const struct sockaddr_in6 *sin
+		  = (const struct sockaddr_in6 *)saddr;
+
+		memcpy(ip_addr->addr, &sin->sin6_addr, sizeof(struct in6_addr));
+
+		ret = 0;
+	}
+	return ret;
+}
+
+/*
+ * On Solaris, man if_tcp describes this method
+ */
+#if defined(COROSYNC_SOLARIS)
+int d1htip_iface_check(struct d1ht_ip_address *bindnet,
+	struct d1ht_ip_address *boundto,
+	int *interface_up,
+	int *interface_num,
+	int mask_high_bit)
+{
+	struct sockaddr_storage bindnet_ss;
+	struct sockaddr_in *bindnet_sin = (struct sockaddr_in *)&bindnet_ss;
+        struct sockaddr_in *sockaddr_in;
+        int id_fd;
+        struct lifconf lifconf;
+	struct lifreq *lifreq;
+        int numreqs = 0;
+        int i;
+        in_addr_t mask_addr;
+	int res = -1;
+	int addrlen;
+
+	d1htip_d1htip_to_sockaddr_convert (bindnet,
+		0, &bindnet_ss, &addrlen);
+
+	*interface_up = 0;
+	id_fd = socket (AF_INET, SOCK_STREAM, 0);
+	lifconf.lifc_family = AF_UNSPEC;
+	lifconf.lifc_flags = 0;
+	lifconf.lifc_buf = NULL;
+	lifconf.lifc_len = 0;
+	do {
+		numreqs += 32;
+		lifconf.lifc_len = sizeof (struct lifreq) * numreqs;
+		lifconf.lifc_buf = (void *)realloc(lifconf.lifc_buf, lifconf.lifc_len);
+		res = ioctl (id_fd, SIOCGLIFCONF, &lifconf);
+		if (res < 0) {
+			close (id_fd);
+			return -1;
+		}
+	} while (lifconf.lifc_len == sizeof (struct lifconf) * numreqs);
+	res = -1;
+
+	lifreq = (struct lifreq *)lifconf.lifc_buf;
+	/*
+	* Find interface address to bind to
+	*/
+	for (i = 0; i < lifconf.lifc_len / sizeof (struct lifreq); i++) {
+		sockaddr_in = (struct sockaddr_in *)&lifreq[i].lifr_addr;
+		mask_addr = inet_addr ("255.255.255.0");
+
+		if ((sockaddr_in->sin_family == AF_INET) &&
+			(sockaddr_in->sin_addr.s_addr & mask_addr) ==
+			(bindnet_sin->sin_addr.s_addr & mask_addr)) {
+
+			res = i;
+
+			/*
+			 * Setup boundto output
+			 */
+			d1htip_sockaddr_to_d1htip_convert((struct sockaddr_storage *)sockaddr_in, boundto);
+			boundto->nodeid = sockaddr_in->sin_addr.s_addr;
+#if __BYTE_ORDER == __BIG_ENDIAN
+			boundto->nodeid = swab32 (boundto->nodeid);
+#endif
+
+			if (ioctl(id_fd, SIOCGLIFFLAGS, &lifreq[i]) < 0) {
+				printf ("couldn't do ioctl\n");
+			}
+
+			*interface_up = lifreq[i].lifr_flags & IFF_UP;
+
+			if (ioctl(id_fd, SIOCGLIFINDEX, &lifreq[i]) < 0) {
+				printf ("couldn't do ioctl\n");
+			}
+			*interface_num = lifreq[i].lifr_index;
+
+
+			break;
+		}
+	}
+	free (lifconf.lifc_buf);
+	close (id_fd);
+
+	return (res);
+}
+#endif
+
+#if defined(COROSYNC_BSD) || defined(COROSYNC_DARWIN)
+int d1htip_iface_check(struct d1ht_ip_address *bindnet,
+	struct d1ht_ip_address *boundto,
+	int *interface_up,
+	int *interface_num,
+	int mask_high_bit)
+{
+#define NEXT_IFR(a)	((struct ifreq *)((u_char *)&(a)->ifr_addr +\
+	((a)->ifr_addr.sa_len ? (a)->ifr_addr.sa_len : sizeof((a)->ifr_addr))))
+
+	struct sockaddr_in *intf_addr_mask;
+	struct sockaddr_storage bindnet_ss;
+	struct sockaddr_in *intf_addr_sin;
+	struct sockaddr_in *bindnet_sin = (struct sockaddr_in *)&bindnet_ss;
+	struct ifaddrs *ifap, *ifa;
+	int res = -1;
+	int addrlen;
+
+	*interface_up = 0;
+	*interface_num = 0;
+
+	d1htip_d1htip_to_sockaddr_convert(bindnet,
+		0, &bindnet_ss, &addrlen);
+
+	if (getifaddrs(&ifap) != 0)
+		return -1;
+
+	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+		intf_addr_sin	= (struct sockaddr_in *)ifa->ifa_addr;
+		intf_addr_mask	= (struct sockaddr_in *)ifa->ifa_netmask;
+
+		if (intf_addr_sin->sin_family != AF_INET)
+			continue;
+
+		if ( bindnet_sin->sin_family == AF_INET &&
+			 (intf_addr_sin->sin_addr.s_addr & intf_addr_mask->sin_addr.s_addr) ==
+			 (bindnet_sin->sin_addr.s_addr & intf_addr_mask->sin_addr.s_addr)) {
+
+			d1htip_copy(boundto, bindnet);
+			memcpy(boundto->addr, &intf_addr_sin->sin_addr, sizeof(intf_addr_sin->sin_addr));
+
+			/* Get interface infos
+			 */
+			*interface_up = ifa->ifa_flags & IFF_UP;
+			*interface_num = if_nametoindex(ifa->ifa_name);
+
+			/*
+			 * Handle case, when nodeid is set to 0 or not set.
+			 */
+			if (bindnet->family == AF_INET && bindnet->nodeid == 0) {
+				unsigned int nodeid = 0;
+				memcpy (&nodeid, boundto->addr, sizeof (int));
+#if _BYTE_ORDER == _BIG_ENDIAN
+				nodeid = swab32 (nodeid);
+#endif
+				/*
+				 * Mask 32nd bit off to workaround bugs in other peoples code
+				 * (if configuration requests it).
+				 */
+				if (mask_high_bit) {
+					nodeid &= 0x7FFFFFFF;
+				}
+				boundto->nodeid = nodeid;
+			}
+			res = 0;
+			break; /* for */
+		}
+	}
+
+	freeifaddrs(ifap);
+
+	return (res);
+}
+#elif defined(COROSYNC_LINUX)
+
+static void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
+{
+        while (RTA_OK(rta, len)) {
+                if (rta->rta_type <= max)
+                        tb[rta->rta_type] = rta;
+                rta = RTA_NEXT(rta,len);
+        }
+}
+
+int d1htip_iface_check(struct d1ht_ip_address *bindnet,
+			struct d1ht_ip_address *boundto,
+			int *interface_up,
+			int *interface_num)
+{
+	int fd;
+	int res = -1;
+	struct {
+                struct nlmsghdr nlh;
+                struct rtgenmsg g;
+        } req;
+        struct sockaddr_nl nladdr;
+	struct d1ht_ip_address ipaddr;
+	static char rcvbuf[NETLINK_BUFSIZE];
+
+	*interface_up = 0;
+	*interface_num = 0;
+	memset(&ipaddr, 0, sizeof(ipaddr));
+
+	/* Make sure we preserve these */
+	ipaddr.family = bindnet->family;
+	ipaddr.nodeid = bindnet->nodeid;
+
+	/* Ask netlink for a list of interface addresses */
+	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (fd <0)
+		return -1;
+
+        setsockopt(fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf));
+
+        memset(&nladdr, 0, sizeof(nladdr));
+        nladdr.nl_family = AF_NETLINK;
+
+        memset(&req, 0, sizeof(req));
+        req.nlh.nlmsg_len = sizeof(req);
+        req.nlh.nlmsg_type = RTM_GETADDR;
+        req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+        req.nlh.nlmsg_pid = 0;
+        req.nlh.nlmsg_seq = 1;
+        req.g.rtgen_family = bindnet->family;
+
+        if (sendto(fd, (void *)&req, sizeof(req), 0,
+		   (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0)  {
+		close(fd);
+		return -1;
+	}
+
+	/* Look through the return buffer for our address */
+	while (1)
+	{
+		int status;
+		struct nlmsghdr *h;
+		struct iovec iov = { rcvbuf, sizeof(rcvbuf) };
+		struct msghdr msg = {
+			(void*)&nladdr, sizeof(nladdr),
+			&iov,   1,
+			NULL,   0,
+			0
+		};
+
+		status = recvmsg(fd, &msg, 0);
+		if (!status) {
+			close(fd);
+			return -1;
+		}
+
+		h = (struct nlmsghdr *)rcvbuf;
+		if (h->nlmsg_type == NLMSG_DONE)
+			break;
+
+		if (h->nlmsg_type == NLMSG_ERROR) {
+			close(fd);
+			return -1;
+		}
+
+		while (NLMSG_OK(h, status)) {
+			if (h->nlmsg_type == RTM_NEWADDR) {
+				struct ifaddrmsg *ifa = NLMSG_DATA(h);
+				struct rtattr *tb[IFA_MAX+1];
+				int len = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
+				int found_if = 0;
+
+				memset(tb, 0, sizeof(tb));
+
+				parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len);
+
+				memcpy(ipaddr.addr, RTA_DATA(tb[IFA_ADDRESS]), D1HTIP_ADDRLEN);
+				if (d1htip_equal(&ipaddr, bindnet)) {
+					found_if = 1;
+				}
+
+				/* If the address we have is an IPv4 network address, then
+				   substitute the actual IP address of this interface */
+				if (!found_if && tb[IFA_LOCAL] && ifa->ifa_family == AF_INET) {
+					uint32_t network;
+					uint32_t addr;
+					uint32_t netmask = htonl(~((1<<(32-ifa->ifa_prefixlen))-1));
+
+					memcpy(&network, RTA_DATA(tb[IFA_LOCAL]), sizeof(uint32_t));
+					memcpy(&addr, bindnet->addr, sizeof(uint32_t));
+
+					if ((addr & netmask) == (network & netmask)) {
+						memcpy(ipaddr.addr, RTA_DATA(tb[IFA_ADDRESS]), D1HTIP_ADDRLEN);
+						found_if = 1;
+					}
+				}
+
+				if (found_if) {
+
+					/* Found it - check I/F is UP */
+					struct ifreq ifr;
+					int ioctl_fd; /* Can't do ioctls on netlink FDs */
+
+					ioctl_fd = socket(AF_INET, SOCK_STREAM, 0);
+					if (ioctl_fd < 0) {
+						close(fd);
+						return -1;
+					}
+					memset(&ifr, 0, sizeof(ifr));
+					ifr.ifr_ifindex = ifa->ifa_index;
+
+					/* SIOCGIFFLAGS needs an interface name */
+					status = ioctl(ioctl_fd, SIOCGIFNAME, &ifr);
+					status = ioctl(ioctl_fd, SIOCGIFFLAGS, &ifr);
+					close(ioctl_fd);
+					if (status) {
+						res = -1;
+						goto finished;
+					}
+
+					if (ifr.ifr_flags & IFF_UP)
+						*interface_up = 1;
+
+					*interface_num = ifa->ifa_index;
+					/*
+					 * Mask 32nd bit off to workaround bugs in other peoples code
+					 * (if configuration requests it).
+					 */
+					if (ipaddr.family == AF_INET && ipaddr.nodeid == 0) {
+						unsigned int nodeid = 0;
+						memcpy (&nodeid, ipaddr.addr, sizeof (int));
+#if __BYTE_ORDER == __BIG_ENDIAN
+                                                nodeid = swab32 (nodeid);
+#endif
+						ipaddr.nodeid = nodeid;
+					}
+					d1htip_copy (boundto, &ipaddr);
+					res = 0;
+					goto finished;
+				}
+			}
+
+			h = NLMSG_NEXT(h, status);
+		}
+	}
+	res = -1; /* address not found */
+finished:
+	close(fd);
+	return res;
+}
+#endif /* COROSYNC_LINUX */
diff --git a/src/d1htip.h b/src/d1htip.h
new file mode 100644
index 0000000..9a0d017
--- /dev/null
+++ b/src/d1htip.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef D1HTIP_H_DEFINED
+#define D1HTIP_H_DEFINED
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef SO_NOSIGPIPE
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+void d1htip_nosigpipe(int s);
+#else
+#define d1htip_nosigpipe(s)
+#endif
+
+#define D1HTIP_ADDRLEN (sizeof(struct in6_addr))
+
+/* These are the things that get passed around */
+#define D1HT_IP_ADDRESS
+struct d1ht_ip_address
+{
+	unsigned int   nodeid;
+	unsigned short family;
+	unsigned char  addr[D1HTIP_ADDRLEN];
+} __attribute__((packed));
+
+
+extern int d1htip_equal(const struct d1ht_ip_address *addr1,
+			 const struct d1ht_ip_address *addr2);
+extern int d1htip_compare(const void *a, const void *b);
+extern void d1htip_copy(struct d1ht_ip_address *addr1,
+			 const struct d1ht_ip_address *addr2);
+extern void d1htip_copy_endian_convert(struct d1ht_ip_address *addr1,
+					const struct d1ht_ip_address *addr2);
+int d1htip_localhost(int family, struct d1ht_ip_address *localhost);
+extern int d1htip_localhost_check(const struct d1ht_ip_address *addr);
+extern const char *d1htip_print(const struct d1ht_ip_address *addr);
+extern int d1htip_sockaddr_to_d1htip_convert(const struct sockaddr_storage *saddr,
+					       struct d1ht_ip_address *ip_addr);
+extern int d1htip_d1htip_to_sockaddr_convert(struct d1ht_ip_address *ip_addr,
+					       uint16_t port, struct sockaddr_storage *saddr, int *addrlen);
+extern int d1htip_parse(struct d1ht_ip_address *d1htip, const char *addr,
+			 int family);
+extern int d1htip_iface_check(struct d1ht_ip_address *bindnet,
+			       struct d1ht_ip_address *boundto,
+			       int *interface_up,
+			       int *interface_num);
+
+/* These two simulate a zero in_addr by clearing the family field */
+static inline void d1htip_zero_set(struct d1ht_ip_address *addr)
+{
+	addr->family = 0;
+}
+static inline int d1htip_zero_check(const struct d1ht_ip_address *addr)
+{
+	return (addr->family == 0);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/d1htnet.c b/src/d1htnet.c
new file mode 100644
index 0000000..351a5cd
--- /dev/null
+++ b/src/d1htnet.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <config.h>
+
+#include "d1htudp.h"
+#include "d1htnet.h"
+#include "hdb.h"
+#include "stdio.h"
+
+#include "logsys.h"
+
+LOGSYS_DECLARE_SUBSYS("D1HTNET");
+
+struct transport {
+	const char *name;
+	
+	int (*initialize) (
+		hdb_handle_t poll_handle,
+		void **transport_instance,
+		struct d1ht_config *d1ht_config,
+		void *context,
+
+		void (*deliver_fn) (
+		void *context,
+		const void *msg,
+		unsigned int msg_len),
+
+		void (*iface_change_fn) (
+			void *context,
+			const struct d1ht_ip_address *iface_address));
+
+	int (*unicast_send) (
+		void *transport_context,
+		const void *msg,
+		unsigned int msg_len,
+		struct d1ht_ip_address *target);
+
+	int (*iface_check) (void *transport_context);
+
+	int (*finalize) (void *transport_context);
+
+	const char *(*iface_print) (void *transport_context);
+
+	int (*iface_get) (
+		void *transport_context,
+		struct d1ht_ip_address *addr);
+
+	int (*crypto_set) (
+		void *transport_context,
+		unsigned int type);
+};
+
+struct transport transport_entries[] = {
+	{
+		.name = "UDP/IP",
+		.initialize = d1htudp_initialize,
+		.unicast_send = d1htudp_unicast_send,
+		.iface_check = d1htudp_iface_check,
+		.finalize = d1htudp_finalize,
+		.iface_print = d1htudp_iface_print,
+		.iface_get = d1htudp_iface_get,
+		.crypto_set = d1htudp_crypto_set,
+	}
+};
+	
+struct d1htnet_instance {
+	void *transport_context;
+
+	struct transport *transport;
+};
+
+static void d1htnet_instance_initialize (
+	struct d1htnet_instance *instance,
+	struct d1ht_config *config)
+{
+	int transport;
+
+	transport = 0;
+
+	log_printf (LOGSYS_LEVEL_NOTICE,
+		"Initializing transport (%s).\n", transport_entries[transport].name);
+
+	instance->transport = &transport_entries[transport];
+}
+
+int d1htnet_crypto_set (
+	void *net_context,
+	 unsigned int type)
+{
+	struct d1htnet_instance *instance = (struct d1htnet_instance *)net_context;
+	int res = 0;
+
+	res = instance->transport->crypto_set (instance->transport_context, type);
+
+	return res;
+}
+
+int d1htnet_finalize (
+	void *net_context)
+{
+	struct d1htnet_instance *instance = (struct d1htnet_instance *)net_context;
+	int res = 0;
+
+	res = instance->transport->finalize (instance->transport_context);
+
+	return (res);
+}
+
+int d1htnet_initialize (
+	hdb_handle_t poll_handle,
+	void **net_context,
+	struct d1ht_config *d1ht_config,
+	void *context,
+
+	void (*deliver_fn) (
+		void *context,
+		const void *msg,
+		unsigned int msg_len),
+
+	void (*iface_change_fn) (
+		void *context,
+		const struct d1ht_ip_address *iface_address))
+{
+
+	struct d1htnet_instance *instance;
+	unsigned int res;
+
+	instance = malloc (sizeof (struct d1htnet_instance));
+	if (instance == NULL) {
+		return (-1);
+	}
+	d1htnet_instance_initialize (instance, d1ht_config);
+
+	res = instance->transport->initialize (poll_handle,
+		&instance->transport_context, d1ht_config,
+		context, deliver_fn, iface_change_fn);
+
+	if (res == -1) {
+		goto error_destroy;
+	}
+
+	*net_context = instance;
+	return (0);
+
+error_destroy:
+	free (instance);
+	return (-1);
+}
+
+int d1htnet_unicast_send (
+	void *net_context,
+	const void *msg,
+	unsigned int msg_len,
+	struct d1ht_ip_address *target)
+{
+	struct d1htnet_instance *instance = (struct d1htnet_instance *)net_context;
+	int res = 0;
+
+	res = instance->transport->unicast_send (instance->transport_context, msg, msg_len, target);
+
+	return (res);
+}
+
+extern int d1htnet_iface_check (void *net_context)
+{
+	struct d1htnet_instance *instance = (struct d1htnet_instance *)net_context;
+	int res = 0;
+
+	res = instance->transport->iface_check (instance->transport_context);
+
+	return (res);
+}
+
+const char *d1htnet_iface_print (void *net_context)  {
+	struct d1htnet_instance *instance = (struct d1htnet_instance *)net_context;
+	const char *ret_char;
+
+	ret_char = instance->transport->iface_print (instance->transport_context);
+	return (ret_char);
+}
diff --git a/src/d1htnet.h b/src/d1htnet.h
new file mode 100644
index 0000000..f117b5e
--- /dev/null
+++ b/src/d1htnet.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef D1HTNET_H_DEFINED
+#define D1HTNET_H_DEFINED
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "d1ht.h"
+
+/*
+ * Create an instance
+ */
+extern int d1htnet_initialize (
+	hdb_handle_t poll_handle,
+	void **net_context,
+	struct d1ht_config *d1ht_config,
+	void *context,
+
+	void (*deliver_fn) (
+		void *context,
+		const void *msg,
+		unsigned int msg_len),
+
+	void (*iface_change_fn) (
+		void *context,
+		const struct d1ht_ip_address *iface_address));
+
+extern int d1htnet_unicast_send (
+	void *net_context,
+	const void *msg,
+	unsigned int msg_len,
+	struct d1ht_ip_address *addr);
+
+extern int d1htnet_iface_check (void *net_context);
+
+extern int d1htnet_finalize (void *net_context);
+
+extern const char *d1htnet_iface_print (void *net_context);
+
+extern int d1htnet_crypto_set (
+	void *net_context,
+	unsigned int type);
+
+#endif /* D1HTNET_H_DEFINED */
diff --git a/src/d1htpoll.c b/src/d1htpoll.c
new file mode 100644
index 0000000..354a844
--- /dev/null
+++ b/src/d1htpoll.c
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ * Copyright (c) 2006-2009 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@redhat.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <sys/poll.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "hdb.h"
+#include "d1htpoll.h"
+#include "list.h"
+#include "tlist.h"
+
+typedef int (*dispatch_fn_t) (hdb_handle_t hdb_handle, int fd, int revents, void *data);
+
+struct poll_entry {
+	struct pollfd ufd;
+	dispatch_fn_t dispatch_fn;
+	void *data;
+};
+
+struct poll_instance {
+	struct poll_entry *poll_entries;
+	struct pollfd *ufds;
+	int poll_entry_count;
+	struct timerlist timerlist;
+	int stop_requested;
+	int pipefds[2];
+};
+
+DECLARE_HDB_DATABASE (poll_instance_database,NULL);
+
+static int dummy_dispatch_fn (hdb_handle_t handle, int fd, int revents, void *data) {
+	return (0);
+}
+
+hdb_handle_t poll_create (void)
+{
+	hdb_handle_t handle;
+	struct poll_instance *poll_instance;
+	unsigned int res;
+
+	res = hdb_handle_create (&poll_instance_database,
+		sizeof (struct poll_instance), &handle);
+	if (res != 0) {
+		goto error_exit;
+	}
+	res = hdb_handle_get (&poll_instance_database, handle,
+		(void *)&poll_instance);
+	if (res != 0) {
+		goto error_destroy;
+	}
+
+	poll_instance->poll_entries = 0;
+	poll_instance->ufds = 0;
+	poll_instance->poll_entry_count = 0;
+	poll_instance->stop_requested = 0;
+	timerlist_init (&poll_instance->timerlist);
+
+	res = pipe (poll_instance->pipefds);
+	if (res != 0) {
+		goto error_destroy;
+	}
+
+	/*
+	 * Allow changes in modify to propogate into new poll instance
+	 */
+	res = poll_dispatch_add (
+		handle,
+		poll_instance->pipefds[0],
+		POLLIN,
+		NULL,
+		dummy_dispatch_fn);
+	if (res != 0) {
+		goto error_destroy;
+	}
+		
+	return (handle);
+
+error_destroy:
+	hdb_handle_destroy (&poll_instance_database, handle);
+
+error_exit:
+	return (-1);
+}
+
+int poll_destroy (hdb_handle_t handle)
+{
+	struct poll_instance *poll_instance;
+	int res = 0;
+
+	res = hdb_handle_get (&poll_instance_database, handle,
+		(void *)&poll_instance);
+	if (res != 0) {
+		res = -ENOENT;
+		goto error_exit;
+	}
+
+	free (poll_instance->poll_entries);
+	free (poll_instance->ufds);
+
+	hdb_handle_destroy (&poll_instance_database, handle);
+
+	hdb_handle_put (&poll_instance_database, handle);
+
+error_exit:
+	return (res);
+}
+
+int poll_dispatch_add (
+	hdb_handle_t handle,
+	int fd,
+	int events,
+	void *data,
+	int (*dispatch_fn) (
+		hdb_handle_t hdb_handle_t,
+		int fd,
+		int revents,
+		void *data))
+{
+	struct poll_instance *poll_instance;
+	struct poll_entry *poll_entries;
+	struct pollfd *ufds;
+	int found = 0;
+	int install_pos;
+	int res = 0;
+
+	res = hdb_handle_get (&poll_instance_database, handle,
+		(void *)&poll_instance);
+	if (res != 0) {
+		res = -ENOENT;
+		goto error_exit;
+	}
+
+	for (found = 0, install_pos = 0; install_pos < poll_instance->poll_entry_count; install_pos++) {
+		if (poll_instance->poll_entries[install_pos].ufd.fd == -1) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found == 0) {
+		/*
+		 * Grow pollfd list
+		 */
+		poll_entries = (struct poll_entry *)realloc (poll_instance->poll_entries,
+			(poll_instance->poll_entry_count + 1) *
+			sizeof (struct poll_entry));
+		if (poll_entries == NULL) {
+			res = -ENOMEM;
+			goto error_put;
+		}
+		poll_instance->poll_entries = poll_entries;
+
+		ufds = (struct pollfd *)realloc (poll_instance->ufds,
+			(poll_instance->poll_entry_count + 1) *
+			sizeof (struct pollfd));
+		if (ufds == NULL) {
+			res = -ENOMEM;
+			goto error_put;
+		}
+		poll_instance->ufds = ufds;
+
+		poll_instance->poll_entry_count += 1;
+		install_pos = poll_instance->poll_entry_count - 1;
+	}
+
+	/*
+	 * Install new dispatch handler
+	 */
+	poll_instance->poll_entries[install_pos].ufd.fd = fd;
+	poll_instance->poll_entries[install_pos].ufd.events = events;
+	poll_instance->poll_entries[install_pos].ufd.revents = 0;
+	poll_instance->poll_entries[install_pos].dispatch_fn = dispatch_fn;
+	poll_instance->poll_entries[install_pos].data = data;
+
+error_put:
+	hdb_handle_put (&poll_instance_database, handle);
+
+error_exit:
+	return (res);
+}
+
+int poll_dispatch_modify (
+	hdb_handle_t handle,
+	int fd,
+	int events,
+	int (*dispatch_fn) (
+		hdb_handle_t hdb_handle_t,
+		int fd,
+		int revents,
+		void *data))
+{
+	struct poll_instance *poll_instance;
+	int i;
+	int res = 0;
+
+	res = hdb_handle_get (&poll_instance_database, handle,
+		(void *)&poll_instance);
+	if (res != 0) {
+		res = -ENOENT;
+		goto error_exit;
+	}
+
+	/*
+	 * Find file descriptor to modify events and dispatch function
+	 */
+	for (i = 0; i < poll_instance->poll_entry_count; i++) {
+		if (poll_instance->poll_entries[i].ufd.fd == fd) {
+			int change_notify = 0;
+
+			if (poll_instance->poll_entries[i].ufd.events != events) {
+				change_notify = 1;
+			}
+			poll_instance->poll_entries[i].ufd.events = events;
+			poll_instance->poll_entries[i].dispatch_fn = dispatch_fn;
+			if (change_notify) {
+				char buf;
+				write (poll_instance->pipefds[1], &buf, 1);
+			}
+
+			goto error_put;
+		}
+	}
+
+	res = -EBADF;
+
+error_put:
+	hdb_handle_put (&poll_instance_database, handle);
+
+error_exit:
+	return (res);
+}
+
+int poll_dispatch_delete (
+	hdb_handle_t handle,
+	int fd)
+{
+	struct poll_instance *poll_instance;
+	int i;
+	int res = 0;
+
+	res = hdb_handle_get (&poll_instance_database, handle,
+		(void *)&poll_instance);
+	if (res != 0) {
+		res = -ENOENT;
+		goto error_exit;
+	}
+
+	/*
+	 * Find dispatch fd to delete
+	 */
+	res = -EBADF;
+	for (i = 0; i < poll_instance->poll_entry_count; i++) {
+		if (poll_instance->poll_entries[i].ufd.fd == fd) {
+			poll_instance->ufds[i].fd = -1;
+			poll_instance->poll_entries[i].ufd.fd = -1;
+			poll_instance->poll_entries[i].ufd.revents = 0;
+
+			res = 0;
+			break;
+		}
+	}
+
+
+	hdb_handle_put (&poll_instance_database, handle);
+
+error_exit:
+	return (res);
+}
+
+int poll_timer_add (
+	hdb_handle_t handle,
+	int msec_duration, void *data,
+	void (*timer_fn) (void *data),
+	poll_timer_handle *timer_handle_out)
+{
+	struct poll_instance *poll_instance;
+	int res = 0;
+
+	if (timer_handle_out == NULL) {
+		res = -ENOENT;
+		goto error_exit;
+	}
+
+	res = hdb_handle_get (&poll_instance_database, handle,
+		(void *)&poll_instance);
+	if (res != 0) {
+		res = -ENOENT;
+		goto error_exit;
+	}
+
+	timerlist_add_duration (&poll_instance->timerlist,
+		timer_fn, data, ((unsigned long long)msec_duration) * 1000000ULL, timer_handle_out);
+
+	hdb_handle_put (&poll_instance_database, handle);
+error_exit:
+	return (res);
+}
+
+int poll_timer_delete (
+	hdb_handle_t handle,
+	poll_timer_handle th)
+{
+	struct poll_instance *poll_instance;
+	int res = 0;
+
+	if (th == 0) {
+		return (0);
+	}
+	res = hdb_handle_get (&poll_instance_database, handle,
+		(void *)&poll_instance);
+	if (res != 0) {
+		res = -ENOENT;
+		goto error_exit;
+	}
+
+	timerlist_del (&poll_instance->timerlist, (void *)th);
+
+	hdb_handle_put (&poll_instance_database, handle);
+
+error_exit:
+	return (res);
+}
+
+int poll_stop (
+	hdb_handle_t handle)
+{
+	struct poll_instance *poll_instance;
+	unsigned int res;
+
+	res = hdb_handle_get (&poll_instance_database, handle,
+		(void *)&poll_instance);
+	if (res != 0) {
+		res = -ENOENT;
+		goto error_exit;
+	}
+
+	poll_instance->stop_requested = 1;
+
+	hdb_handle_put (&poll_instance_database, handle);
+error_exit:
+	return (res);
+}
+
+
+int poll_run (
+	hdb_handle_t handle)
+{
+	struct poll_instance *poll_instance;
+	int i;
+	unsigned long long expire_timeout_msec = -1;
+	int res;
+	int poll_entry_count;
+
+	res = hdb_handle_get (&poll_instance_database, handle,
+		(void *)&poll_instance);
+	if (res != 0) {
+		goto error_exit;
+	}
+
+	for (;;) {
+rebuild_poll:
+		for (i = 0; i < poll_instance->poll_entry_count; i++) {
+			memcpy (&poll_instance->ufds[i],
+				&poll_instance->poll_entries[i].ufd,
+				sizeof (struct pollfd));
+		}
+		expire_timeout_msec = timerlist_msec_duration_to_expire (&poll_instance->timerlist);
+
+		if (expire_timeout_msec != -1 && expire_timeout_msec > 0xFFFFFFFF) {
+			expire_timeout_msec = 0xFFFFFFFE;
+		}
+
+retry_poll:
+		res = poll (poll_instance->ufds,
+			poll_instance->poll_entry_count, expire_timeout_msec);
+		if (poll_instance->stop_requested) {
+			return (0);
+		}
+		if (errno == EINTR && res == -1) {
+			goto retry_poll;
+		} else
+		if (res == -1) {
+			goto error_exit;
+		}
+
+		if (poll_instance->ufds[0].revents) {
+			char buf;
+			read (poll_instance->ufds[0].fd, &buf, 1);
+			goto rebuild_poll;
+		}
+		poll_entry_count = poll_instance->poll_entry_count;
+		for (i = 0; i < poll_entry_count; i++) {
+			if (poll_instance->ufds[i].fd != -1 &&
+				poll_instance->ufds[i].revents) {
+
+				res = poll_instance->poll_entries[i].dispatch_fn (handle,
+					poll_instance->ufds[i].fd,
+					poll_instance->ufds[i].revents,
+					poll_instance->poll_entries[i].data);
+
+				/*
+				 * Remove dispatch functions that return -1
+				 */
+				if (res == -1) {
+					poll_instance->poll_entries[i].ufd.fd = -1; /* empty entry */
+				}
+			}
+		}
+		timerlist_expire (&poll_instance->timerlist);
+	} /* for (;;) */
+
+	hdb_handle_put (&poll_instance_database, handle);
+error_exit:
+	return (-1);
+}
+
+#ifdef COMPILE_OUT
+void poll_print_state (
+	hdb_handle_t handle,
+	int fd)
+{
+	struct poll_instance *poll_instance;
+	int i;
+	int res = 0;
+	res = hdb_handle_get (&poll_instance_database, handle,
+		(void *)&poll_instance);
+	if (res != 0) {
+		res = -ENOENT;
+		exit (1);
+	}
+
+	for (i = 0; i < poll_instance->poll_entry_count; i++) {
+		if (poll_instance->poll_entries[i].ufd.fd == fd) {
+		printf ("fd %d\n", poll_instance->poll_entries[i].ufd.fd);
+		printf ("events %d\n", poll_instance->poll_entries[i].ufd.events);
+		printf ("dispatch_fn %p\n", poll_instance->poll_entries[i].dispatch_fn);
+		}
+	}
+}
+
+#endif
diff --git a/src/d1htpoll.h b/src/d1htpoll.h
new file mode 100644
index 0000000..7a2663c
--- /dev/null
+++ b/src/d1htpoll.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@redhat.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef POLL_H_DEFINED
+#define POLL_H_DEFINED
+
+#include <pthread.h>
+
+#include "hdb.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void * poll_timer_handle;
+
+hdb_handle_t poll_create (void);
+
+int poll_destroy (hdb_handle_t hdb_handle);
+
+int poll_dispatch_add (
+	hdb_handle_t handle,
+	int fd,
+	int events,
+	void *data,
+
+	int (*dispatch_fn) (hdb_handle_t handle,
+		int fd,
+		int revents,
+		void *data));
+
+int poll_dispatch_modify (
+	hdb_handle_t handle,
+	int fd,
+	int events,
+
+	int (*dispatch_fn) (hdb_handle_t hdb_handle_t,
+		int fd,
+		int revents,
+		void *data));
+
+
+int poll_dispatch_delete (
+	hdb_handle_t handle,
+	int fd);
+
+int poll_timer_add (
+	hdb_handle_t handle,
+	int msec_in_future, void *data,
+	void (*timer_fn) (void *data),
+	poll_timer_handle *timer_handle_out);
+
+int poll_timer_delete (
+	hdb_handle_t handle,
+	poll_timer_handle timer_handle);
+
+int poll_run (
+	hdb_handle_t handle);
+
+int poll_stop (
+	hdb_handle_t handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* POLL_H_DEFINED */
diff --git a/src/d1htudp.c b/src/d1htudp.c
new file mode 100644
index 0000000..ee30dd0
--- /dev/null
+++ b/src/d1htudp.c
@@ -0,0 +1,1125 @@
+/*
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <pthread.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sched.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <limits.h>
+
+#include "list.h"
+#include "hdb.h"
+#include "swab.h"
+#include "d1htpoll.h"
+#include "logsys.h"
+#include "d1htudp.h"
+
+LOGSYS_DECLARE_SUBSYS("D1HTUDP");
+
+#ifdef HAVE_LIBNSS
+#include <nss.h>
+#include <pk11pub.h>
+#include <pkcs11.h>
+#include <prerror.h>
+#endif
+
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+
+#define NETIF_STATE_REPORT_UP		1
+#define NETIF_STATE_REPORT_DOWN		2
+
+#define BIND_STATE_UNBOUND	0
+#define BIND_STATE_REGULAR	1
+#define BIND_STATE_LOOPBACK	2
+
+#define FRAME_SIZE_MAX 64000
+
+#define HMAC_HASH_SIZE 20
+struct security_header {
+	unsigned char hash_digest[HMAC_HASH_SIZE]; /* The hash *MUST* be first in the data structure */
+	unsigned char salt[16]; /* random number */
+	char msg[0];
+} __attribute__((packed));
+
+struct d1htudp_socket {
+	int mcast_send;
+	int token;
+};
+
+struct d1htudp_instance {
+#ifdef HAVE_LIBNSS
+	PK11SymKey   *nss_sym_key;
+
+	PK11SymKey   *nss_sym_key_sign;
+#endif
+
+	unsigned char d1htudp_private_key[1024];
+
+	unsigned int d1htudp_private_key_len;
+
+	hdb_handle_t d1htudp_poll_handle;
+
+	struct d1ht_interface *d1ht_interface;
+
+	int netif_state_report;
+
+	int netif_bind_state;
+
+	void *context;
+
+	void (*d1htudp_deliver_fn) (
+		void *context,
+		const void *msg,
+		unsigned int msg_len);
+
+	void (*d1htudp_iface_change_fn) (
+		void *context,
+		const struct d1ht_ip_address *iface_address);
+
+	void *udp_context;
+
+	char iov_buffer[FRAME_SIZE_MAX];
+
+	struct iovec d1htudp_iov_recv;
+
+	int socket_fd;
+
+	int stats_sent;
+
+	int stats_recv;
+
+	int stats_delv;
+
+	int stats_remcasts;
+
+	int stats_orf_token;
+
+	struct timeval stats_tv_start;
+
+	struct d1ht_ip_address my_id;
+
+	int firstrun;
+
+	poll_timer_handle timer_netif_check_timeout;
+
+	unsigned int my_memb_entries;
+
+	struct d1ht_config *d1ht_config;
+
+	struct d1ht_ip_address token_target;
+};
+
+static int d1htudp_build_sockets (
+	struct d1htudp_instance *instance,
+	struct d1ht_ip_address *bindnet_address,
+	struct d1ht_ip_address *bound_to);
+
+static struct d1ht_ip_address localhost;
+
+static void d1htudp_instance_initialize (struct d1htudp_instance *instance)
+{
+	memset (instance, 0, sizeof (struct d1htudp_instance));
+
+	instance->netif_state_report = NETIF_STATE_REPORT_UP | NETIF_STATE_REPORT_DOWN;
+
+	instance->d1htudp_iov_recv.iov_base = instance->iov_buffer;
+
+	instance->d1htudp_iov_recv.iov_len = FRAME_SIZE_MAX; //sizeof (instance->iov_buffer);
+
+	/*
+	 * There is always atleast 1 processor
+	 */
+	instance->my_memb_entries = 1;
+}
+
+#ifdef HAVE_LIBNSS
+
+static unsigned char *copy_from_iovec(
+	const struct iovec *iov,
+	unsigned int iov_len,
+	size_t *buf_size)
+{
+	int i;
+	size_t bufptr;
+	size_t buflen = 0;
+	unsigned char *newbuf;
+
+	for (i=0; i<iov_len; i++)
+		buflen += iov[i].iov_len;
+
+	newbuf = malloc(buflen);
+	if (!newbuf)
+		return NULL;
+
+	bufptr=0;
+	for (i=0; i<iov_len; i++) {
+		memcpy(newbuf+bufptr, iov[i].iov_base, iov[i].iov_len);
+		bufptr += iov[i].iov_len;
+	}
+	*buf_size = buflen;
+	return newbuf;
+}
+
+static void copy_to_iovec(
+	struct iovec *iov,
+	unsigned int iov_len,
+	const unsigned char *buf,
+	size_t buf_size)
+{
+	int i;
+	size_t copylen;
+	size_t bufptr = 0;
+
+	bufptr=0;
+	for (i=0; i<iov_len; i++) {
+		copylen = iov[i].iov_len;
+		if (bufptr + copylen > buf_size) {
+			copylen = buf_size - bufptr;
+		}
+		memcpy(iov[i].iov_base, buf+bufptr, copylen);
+		bufptr += copylen;
+		if (iov[i].iov_len != copylen) {
+			iov[i].iov_len = copylen;
+			return;
+		}
+	}
+}
+
+static void init_nss_crypto (struct d1htudp_instance *instance)
+{
+	PK11SlotInfo*      aes_slot = NULL;
+	PK11SlotInfo*      sha1_slot = NULL;
+	SECItem            key_item;
+	SECStatus          rv;
+
+	log_printf(LOGSYS_LEVEL_NOTICE,
+		"Initializing transmit/receive security: NSS AES128CBC/SHA1HMAC (mode 1).\n");
+	rv = NSS_NoDB_Init(".");
+	if (rv != SECSuccess)
+	{
+		log_printf(LOGSYS_LEVEL_NOTICE, "NSS initialization failed (err %d)\n",
+			PR_GetError());
+		goto out;
+	}
+
+	aes_slot = PK11_GetBestSlot(instance->d1ht_config->crypto_crypt_type, NULL);
+	if (aes_slot == NULL)
+	{
+		log_printf(LOGSYS_LEVEL_NOTICE, "Unable to find security slot (err %d)\n",
+			PR_GetError());
+		goto out;
+	}
+
+	sha1_slot = PK11_GetBestSlot(CKM_SHA_1_HMAC, NULL);
+	if (sha1_slot == NULL)
+	{
+		log_printf(LOGSYS_LEVEL_NOTICE, "Unable to find security slot (err %d)\n",
+			PR_GetError());
+		goto out;
+	}
+	/*
+	 * Make the private key into a SymKey that we can use
+	 */
+	key_item.type = siBuffer;
+	key_item.data = instance->d1ht_config->private_key;
+	key_item.len = 32; /* Use 128 bits */
+
+	instance->nss_sym_key = PK11_ImportSymKey(aes_slot,
+		instance->d1ht_config->crypto_crypt_type,
+		PK11_OriginUnwrap, CKA_ENCRYPT|CKA_DECRYPT,
+		&key_item, NULL);
+	if (instance->nss_sym_key == NULL)
+	{
+		log_printf(LOGSYS_LEVEL_NOTICE,
+			intf(instance->d1htudp_log_level_security, "Failure to import key into NSS (err %d)\n",
+			PR_GetError());
+		goto out;
+	}
+
+	instance->nss_sym_key_sign = PK11_ImportSymKey(sha1_slot,
+		CKM_SHA_1_HMAC,
+		PK11_OriginUnwrap, CKA_SIGN,
+		&key_item, NULL);
+	if (instance->nss_sym_key_sign == NULL) {
+		log_printf(LOGSYS_LEVEL_NOTICE,
+			"Failure to import key into NSS (err %d)\n",
+			PR_GetError());
+		goto out;
+	}
+out:
+	return;
+}
+
+static int encrypt_and_sign_nss (
+	struct d1htudp_instance *instance,
+	unsigned char *buf,
+	size_t *buf_len,
+	const struct iovec *iovec,
+	unsigned int iov_len)
+{
+	PK11Context*       enc_context = NULL;
+	SECStatus          rv1, rv2;
+	int                tmp1_outlen;
+	unsigned int       tmp2_outlen;
+	unsigned char      *inbuf;
+	unsigned char      *data;
+	unsigned char      *outdata;
+	size_t             datalen;
+	SECItem            no_params;
+	SECItem            iv_item;
+	struct security_header *header;
+	SECItem      *nss_sec_param;
+	unsigned char nss_iv_data[16];
+	SECStatus          rv;
+
+	no_params.type = siBuffer;
+	no_params.data = 0;
+	no_params.len = 0;
+
+	tmp1_outlen = tmp2_outlen = 0;
+	inbuf = copy_from_iovec(iovec, iov_len, &datalen);
+	if (!inbuf) {
+		log_printf(LOGSYS_LEVEL_NOTICE,
+			"malloc error copying buffer from iovec\n");
+		return -1;
+	}
+
+	data = inbuf + sizeof (struct security_header);
+	datalen -= sizeof (struct security_header);
+
+	outdata = buf + sizeof (struct security_header);
+	header = (struct security_header *)buf;
+
+	rv = PK11_GenerateRandom (
+		nss_iv_data,
+		sizeof (nss_iv_data));
+	if (rv != SECSuccess) {
+		log_printf(LOGSYS_LEVEL_NOTICE,
+			"Failure to generate a random number %d\n",
+			PR_GetError());
+	}
+
+	memcpy(header->salt, nss_iv_data, sizeof(nss_iv_data));
+	iv_item.type = siBuffer;
+	iv_item.data = nss_iv_data;
+	iv_item.len = sizeof (nss_iv_data);
+
+	nss_sec_param = PK11_ParamFromIV (
+		instance->d1ht_config->crypto_crypt_type,
+		&iv_item);
+	if (nss_sec_param == NULL) {
+		log_printf(LOGSYS_LEVEL_NOTICE,
+			"Failure to set up PKCS11 param (err %d)\n",
+			PR_GetError());
+		goto out;
+	}
+
+	/*
+	 * Create cipher context for encryption
+	 */
+	enc_context = PK11_CreateContextBySymKey (
+		instance->d1ht_config->crypto_crypt_type,
+		CKA_ENCRYPT,
+		instance->nss_sym_key,
+		nss_sec_param);
+	if (!enc_context) {
+		char err[1024];
+		PR_GetErrorText(err);
+		err[PR_GetErrorTextLength()] = 0;
+		log_printf(LOGSYS_LEVEL_NOTICE,
+			"PK11_CreateContext failed (encrypt) crypt_type=%d (err %d): %s\n",
+			instance->d1ht_config->crypto_crypt_type,
+			PR_GetError(), err);
+		return -1;
+	}
+	rv1 = PK11_CipherOp(enc_context, outdata,
+			    &tmp1_outlen, FRAME_SIZE_MAX - sizeof(struct security_header),
+			    data, datalen);
+	rv2 = PK11_DigestFinal(enc_context, outdata + tmp1_outlen, &tmp2_outlen,
+			       FRAME_SIZE_MAX - tmp1_outlen);
+	PK11_DestroyContext(enc_context, PR_TRUE);
+
+	*buf_len = tmp1_outlen + tmp2_outlen;
+	free(inbuf);
+//	memcpy(&outdata[*buf_len], nss_iv_data, sizeof(nss_iv_data));
+
+	if (rv1 != SECSuccess || rv2 != SECSuccess)
+		goto out;
+
+	/* Now do the digest */
+	enc_context = PK11_CreateContextBySymKey(CKM_SHA_1_HMAC,
+		CKA_SIGN, instance->nss_sym_key_sign, &no_params);
+	if (!enc_context) {
+		char err[1024];
+		PR_GetErrorText(err);
+		err[PR_GetErrorTextLength()] = 0;
+		log_printf(LOGSYS_LEVEL_NOTICE,
+			,"encrypt: PK11_CreateContext failed (digest) err %d: %s\n",
+			PR_GetError(), err);
+		return -1;
+	}
+
+
+	PK11_DigestBegin(enc_context);
+
+	rv1 = PK11_DigestOp(enc_context, outdata - 16, *buf_len + 16);
+	rv2 = PK11_DigestFinal(enc_context, header->hash_digest, &tmp2_outlen, sizeof(header->hash_digest));
+
+	PK11_DestroyContext(enc_context, PR_TRUE);
+
+	if (rv1 != SECSuccess || rv2 != SECSuccess)
+		goto out;
+
+
+	*buf_len = *buf_len + sizeof(struct security_header);
+	SECITEM_FreeItem(nss_sec_param, PR_TRUE);
+	return 0;
+
+out:
+	return -1;
+}
+
+
+static int authenticate_and_decrypt_nss (
+	struct d1htudp_instance *instance,
+	struct iovec *iov,
+	unsigned int iov_len)
+{
+	PK11Context*  enc_context = NULL;
+	SECStatus     rv1, rv2;
+	int           tmp1_outlen;
+	unsigned int  tmp2_outlen;
+	unsigned char outbuf[FRAME_SIZE_MAX];
+	unsigned char digest[HMAC_HASH_SIZE];
+	unsigned char *outdata;
+	int           result_len;
+	unsigned char *data;
+	unsigned char *inbuf;
+	size_t        datalen;
+	struct security_header *header = (struct security_header *)iov[0].iov_base;
+	SECItem no_params;
+	SECItem ivdata;
+
+	no_params.type = siBuffer;
+	no_params.data = 0;
+	no_params.len = 0;
+
+	tmp1_outlen = tmp2_outlen = 0;
+	if (iov_len > 1) {
+		inbuf = copy_from_iovec(iov, iov_len, &datalen);
+		if (!inbuf) {
+			log_printf(LOGSYS_LEVEL_NOTICE,
+				"malloc error copying buffer from iovec\n");
+			return -1;
+		}
+	}
+	else {
+		inbuf = (unsigned char *)iov[0].iov_base;
+		datalen = iov[0].iov_len;
+	}
+	data = inbuf + sizeof (struct security_header) - 16;
+	datalen = datalen - sizeof (struct security_header) + 16;
+
+	outdata = outbuf + sizeof (struct security_header);
+
+	/* Check the digest */
+	enc_context = PK11_CreateContextBySymKey (
+		CKM_SHA_1_HMAC, CKA_SIGN,
+		instance->nss_sym_key_sign,
+		&no_params);
+	if (!enc_context) {
+		char err[1024];
+		PR_GetErrorText(err);
+		err[PR_GetErrorTextLength()] = 0;
+		log_printf(LOGSYS_LEVEL_NOTICE,
+			"PK11_CreateContext failed (check digest) err %d: %s\n",
+			PR_GetError(), err);
+		return -1;
+	}
+
+	PK11_DigestBegin(enc_context);
+
+	rv1 = PK11_DigestOp(enc_context, data, datalen);
+	rv2 = PK11_DigestFinal(enc_context, digest, &tmp2_outlen, sizeof(digest));
+
+	PK11_DestroyContext(enc_context, PR_TRUE);
+
+	if (rv1 != SECSuccess || rv2 != SECSuccess) {
+		log_printf(LOGSYS_LEVEL_NOTICE,
+			"Digest check failed\n");
+		return -1;
+	}
+
+	if (memcmp(digest, header->hash_digest, tmp2_outlen) != 0) {
+		log_printf(LOGSYS_LEVEL_NOTICE,
+			"Digest does not match\n");
+		return -1;
+	}
+
+	/*
+	 * Get rid of salt
+	 */
+	data += 16;
+	datalen -= 16;
+
+	/* Create cipher context for decryption */
+	ivdata.type = siBuffer;
+	ivdata.data = header->salt;
+	ivdata.len = sizeof(header->salt);
+
+	enc_context = PK11_CreateContextBySymKey(
+		instance->d1ht_config->crypto_crypt_type,
+		CKA_DECRYPT,
+		instance->nss_sym_key, &ivdata);
+	if (!enc_context) {
+		log_printf(LOGSYS_LEVEL_NOTICE,
+			"PK11_CreateContext (decrypt) failed (err %d)\n",
+			PR_GetError());
+		return -1;
+	}
+
+	rv1 = PK11_CipherOp(enc_context, outdata, &tmp1_outlen,
+			    sizeof(outbuf) - sizeof (struct security_header),
+			    data, datalen);
+	if (rv1 != SECSuccess) {
+		log_printf(LOGSYS_LEVEL_NOTICE,
+			"PK11_CipherOp (decrypt) failed (err %d)\n",
+			PR_GetError());
+	}
+	rv2 = PK11_DigestFinal(enc_context, outdata + tmp1_outlen, &tmp2_outlen,
+			       sizeof(outbuf) - tmp1_outlen);
+	PK11_DestroyContext(enc_context, PR_TRUE);
+	result_len = tmp1_outlen + tmp2_outlen + sizeof (struct security_header);
+
+	/* Copy it back to the buffer */
+	copy_to_iovec(iov, iov_len, outbuf, result_len);
+	if (iov_len > 1)
+		free(inbuf);
+
+	if (rv1 != SECSuccess || rv2 != SECSuccess)
+		return -1;
+
+	return 0;
+}
+#endif
+
+static int encrypt_and_sign_worker (
+	struct d1htudp_instance *instance,
+	unsigned char *buf,
+	size_t *buf_len,
+	const struct iovec *iovec,
+	unsigned int iov_len)
+{
+#ifdef HAVE_LIBNSS
+	if (instance->d1ht_config->crypto_type == D1HT_CRYPTO_TYPE_NSS_SYMMETRIC)
+		return encrypt_and_sign_nss(instance, buf, buf_len, iovec, iov_len);
+#endif
+	return -1;
+}
+
+static int authenticate_and_decrypt (
+	struct d1htudp_instance *instance,
+	struct iovec *iov,
+	unsigned int iov_len)
+{
+	unsigned char type;
+	unsigned char *endbuf = (unsigned char *)iov[iov_len-1].iov_base;
+	int res = -1;
+
+	/*
+	 * Get the encryption type and remove it from the buffer
+	 */
+	type = endbuf[iov[iov_len-1].iov_len-1];
+	iov[iov_len-1].iov_len -= 1;
+
+	/*
+	 * Only try higher crypto options if NEW has been requested
+	 */
+#ifdef HAVE_LIBNSS
+	if (type == D1HT_CRYPTO_TYPE_NSS_SYMMETRIC)
+	    res = authenticate_and_decrypt_nss(instance, iov, iov_len);
+#endif
+
+	return res;
+}
+
+static void init_crypto(struct d1htudp_instance *instance)
+{
+	if (instance->d1ht_config->crypto_type == D1HT_CRYPTO_TYPE_NONE) {
+		log_printf(LOGSYS_LEVEL_NOTICE,
+			"Initializing transmit/receive security: not using security (mode 0).\n");
+	}
+#ifdef HAVE_NSS
+	init_nss_crypto (instance);
+#endif
+}
+
+int d1htudp_crypto_set (
+	void *udp_context,
+	 unsigned int type)
+{
+	struct d1htudp_instance *instance = (struct d1htudp_instance *)udp_context;
+	int res = 0;
+
+	instance = 0;
+
+	return (res);
+}
+
+
+static inline void ucast_sendmsg (
+	struct d1htudp_instance *instance,
+	const void *msg,
+	unsigned int msg_len,
+	struct d1ht_ip_address *target)
+{
+	struct msghdr msg_ucast;
+	int res = 0;
+	size_t buf_len;
+	unsigned char sheader[sizeof (struct security_header)];
+	unsigned char encrypt_data[64000];
+	struct iovec iovec_encrypt[2];
+	const struct iovec *iovec_sendmsg;
+	struct sockaddr_storage sockaddr;
+	struct iovec iovec;
+	unsigned int iov_len;
+	int addrlen;
+
+	if (instance->d1ht_config->crypto_type != D1HT_CRYPTO_TYPE_NONE) {
+		iovec_encrypt[0].iov_base = (void *)sheader;
+		iovec_encrypt[0].iov_len = sizeof (struct security_header);
+		iovec_encrypt[1].iov_base = (void *)msg;
+		iovec_encrypt[1].iov_len = msg_len;
+
+		/*
+		 * Encrypt and digest the message
+		 */
+		encrypt_and_sign_worker (
+			instance,
+			encrypt_data,
+			&buf_len,
+			iovec_encrypt,
+			2);
+
+		encrypt_data[buf_len++] = instance->d1ht_config->crypto_type;
+
+		iovec_encrypt[0].iov_base = (void *)encrypt_data;
+		iovec_encrypt[0].iov_len = buf_len;
+		iovec_sendmsg = &iovec_encrypt[0];
+		iov_len = 1;
+	} else {
+		iovec.iov_base = (void *)msg;
+		iovec.iov_len = msg_len;
+		iovec_sendmsg = &iovec;
+		iov_len = 1;
+	}
+
+	/*
+	 * Build unicast message
+	 */
+	d1htip_d1htip_to_sockaddr_convert(target,
+		instance->d1ht_interface->ip_port, &sockaddr, &addrlen);
+	msg_ucast.msg_name = &sockaddr;
+	msg_ucast.msg_namelen = addrlen;
+	msg_ucast.msg_iov = (void *) iovec_sendmsg;
+	msg_ucast.msg_iovlen = iov_len;
+#if !defined(COROSYNC_SOLARIS)
+	msg_ucast.msg_control = 0;
+	msg_ucast.msg_controllen = 0;
+	msg_ucast.msg_flags = 0;
+#else
+	msg_ucast.msg_accrights = NULL;
+	msg_ucast.msg_accrightslen = 0;
+#endif
+
+
+	/*
+	 * Transmit unicast message
+	 * An error here is recovered by td1htsrp
+	 */
+	res = sendmsg (instance->socket_fd, &msg_ucast,
+		MSG_NOSIGNAL);
+	if (res < 0) {
+		char error_str[100];
+		strerror_r (errno, error_str, sizeof(error_str));
+		log_printf(LOGSYS_LEVEL_DEBUG,
+			"sendmsg(ucast) failed (non-critical): %s\n", error_str);
+	}
+}
+
+int d1htudp_finalize (
+	void *udp_context)
+{
+	struct d1htudp_instance *instance = (struct d1htudp_instance *)udp_context;
+	int res = 0;
+
+	if (instance->socket_fd > 0) {
+		close (instance->socket_fd);
+	 	poll_dispatch_delete (instance->d1htudp_poll_handle,
+			instance->socket_fd);
+	}
+
+	return (res);
+}
+
+/*
+ * Only designed to work with a message with one iov
+ */
+
+static int net_deliver_fn (
+	hdb_handle_t handle,
+	int fd,
+	int revents,
+	void *data)
+{
+	struct d1htudp_instance *instance = (struct d1htudp_instance *)data;
+	struct msghdr msg_recv;
+	struct iovec *iovec;
+	struct security_header *security_header;
+	struct sockaddr_storage system_from;
+	int bytes_received;
+	int res = 0;
+	unsigned char *msg_offset;
+	unsigned int size_delv;
+
+	iovec = &instance->d1htudp_iov_recv;
+
+	/*
+	 * Receive datagram
+	 */
+	msg_recv.msg_name = &system_from;
+	msg_recv.msg_namelen = sizeof (struct sockaddr_storage);
+	msg_recv.msg_iov = iovec;
+	msg_recv.msg_iovlen = 1;
+#if !defined(COROSYNC_SOLARIS)
+	msg_recv.msg_control = 0;
+	msg_recv.msg_controllen = 0;
+	msg_recv.msg_flags = 0;
+#else
+	msg_recv.msg_accrights = NULL;
+	msg_recv.msg_accrightslen = 0;
+#endif
+
+	bytes_received = recvmsg (fd, &msg_recv, MSG_NOSIGNAL | MSG_DONTWAIT);
+	if (bytes_received == -1) {
+		return (0);
+	} else {
+		instance->stats_recv += bytes_received;
+	}
+
+	if ((instance->d1ht_config->crypto_type != D1HT_CRYPTO_TYPE_NONE) &&
+		(bytes_received < sizeof (struct security_header))) {
+
+		log_printf(LOGSYS_LEVEL_ERROR,
+			"Received message is too short...  ignoring %d.\n", bytes_received);
+		return (0);
+	}
+
+	security_header = (struct security_header *)iovec->iov_base;
+
+	iovec->iov_len = bytes_received;
+	if (instance->d1ht_config->crypto_type != D1HT_CRYPTO_TYPE_NONE) {
+		/*
+		 * Authenticate and if authenticated, decrypt datagram
+		 */
+
+		res = authenticate_and_decrypt (instance, iovec, 1);
+		if (res == -1) {
+		log_printf(LOGSYS_LEVEL_ERROR,
+			"Received message has invalid digest... ignoring.\n");
+		log_printf(LOGSYS_LEVEL_ERROR,
+				"Invalid packet data\n");
+			iovec->iov_len = FRAME_SIZE_MAX;
+			return 0;
+		}
+		msg_offset = (unsigned char *)iovec->iov_base +
+			sizeof (struct security_header);
+		size_delv = bytes_received - sizeof (struct security_header);
+	} else {
+		msg_offset = (void *)iovec->iov_base;
+		size_delv = bytes_received;
+	}
+
+	/*
+	 * Handle incoming message
+	 */
+	instance->d1htudp_deliver_fn (
+		instance->context,
+		msg_offset,
+		size_delv);
+
+	iovec->iov_len = FRAME_SIZE_MAX;
+	return (0);
+}
+
+static int netif_determine (
+	struct d1htudp_instance *instance,
+	struct d1ht_ip_address *bindnet,
+	struct d1ht_ip_address *bound_to,
+	int *interface_up,
+	int *interface_num)
+{
+	int res;
+
+	res = d1htip_iface_check (bindnet, bound_to,
+		interface_up, interface_num);
+
+
+	return (res);
+}
+
+
+/*
+ * If the interface is up, the sockets for td1ht are built.  If the interface is down
+ * this function is requeued in the timer list to retry building the sockets later.
+ */
+static void timer_function_netif_check_timeout (
+	void *data)
+{
+	struct d1htudp_instance *instance = (struct d1htudp_instance *)data;
+	int res;
+	int interface_up;
+	int interface_num;
+	struct d1ht_ip_address *bind_address;
+
+	/*
+	 * Build sockets for every interface
+	 */
+	netif_determine (instance,
+		&instance->d1ht_interface->bindnet,
+		&instance->d1ht_interface->boundto,
+		&interface_up, &interface_num);
+	/*
+	 * If the network interface isn't back up and we are already
+	 * in loopback mode, add timer to check again and return
+	 */
+	if ((instance->netif_bind_state == BIND_STATE_LOOPBACK &&
+		interface_up == 0) ||
+
+	(instance->my_memb_entries == 1 &&
+		instance->netif_bind_state == BIND_STATE_REGULAR &&
+		interface_up == 1)) {
+
+		poll_timer_add (instance->d1htudp_poll_handle,
+			1000,//instance->d1ht_config->downcheck_timeout,
+			(void *)instance,
+			timer_function_netif_check_timeout,
+			&instance->timer_netif_check_timeout);
+
+		/*
+		 * Add a timer to check for a downed regular interface
+		 */
+		return;
+	}
+
+	if (interface_up == 0) {
+		/*
+		 * Interface is not up
+		 */
+		instance->netif_bind_state = BIND_STATE_LOOPBACK;
+		bind_address = &localhost;
+
+		/*
+		 * Add a timer to retry building interfaces and request memb_gather_enter
+		 */
+		poll_timer_add (instance->d1htudp_poll_handle,
+			1000,//instance->d1ht_config->downcheck_timeout,
+			(void *)instance,
+			timer_function_netif_check_timeout,
+			&instance->timer_netif_check_timeout);
+	} else {
+		/*
+		 * Interface is up
+		 */
+		instance->netif_bind_state = BIND_STATE_REGULAR;
+		bind_address = &instance->d1ht_interface->bindnet;
+	}
+	/*
+	 * Create and bind the multicast and unicast sockets
+	 */
+	res = d1htudp_build_sockets (instance,
+		bind_address,
+		&instance->d1ht_interface->boundto);
+
+	poll_dispatch_add (
+		instance->d1htudp_poll_handle,
+		instance->socket_fd,
+		POLLIN, instance, net_deliver_fn);
+
+	d1htip_copy (&instance->my_id, &instance->d1ht_interface->boundto);
+
+	/*
+	 * This reports changes in the interface to the user and td1htsrp
+	 */
+	if (instance->netif_bind_state == BIND_STATE_REGULAR) {
+		if (instance->netif_state_report & NETIF_STATE_REPORT_UP) {
+			log_printf(LOGSYS_LEVEL_NOTICE,
+				"The network interface [%s] is now up.\n",
+				d1htip_print (&instance->d1ht_interface->boundto));
+			instance->netif_state_report = NETIF_STATE_REPORT_DOWN;
+			instance->d1htudp_iface_change_fn (instance->context, &instance->my_id);
+		}
+		/*
+		 * Add a timer to check for interface going down in single membership
+		 */
+		if (instance->my_memb_entries == 1) {
+			poll_timer_add (instance->d1htudp_poll_handle,
+				1000,//instance->d1ht_config->downcheck_timeout,
+				(void *)instance,
+				timer_function_netif_check_timeout,
+				&instance->timer_netif_check_timeout);
+		}
+
+	} else {
+		if (instance->netif_state_report & NETIF_STATE_REPORT_DOWN) {
+			log_printf(LOGSYS_LEVEL_NOTICE,
+				"The network interface is down.\n");
+			instance->d1htudp_iface_change_fn (instance->context, &instance->my_id);
+		}
+		instance->netif_state_report = NETIF_STATE_REPORT_UP;
+
+	}
+}
+
+static int d1htudp_build_sockets_ip (
+	struct d1htudp_instance *instance,
+	struct d1ht_ip_address *bindnet_address,
+	struct d1ht_ip_address *bound_to)
+{
+	struct sockaddr_storage sockaddr;
+	unsigned int sendbuf_size;
+        unsigned int recvbuf_size;
+        unsigned int optlen = sizeof (sendbuf_size);
+	int addrlen;
+	int res;
+	int flag;
+
+	instance->socket_fd = socket (bindnet_address->family, SOCK_DGRAM, 0);
+	if (instance->socket_fd == -1) {
+		perror ("socket");
+		return (-1);
+	}
+
+	d1htip_nosigpipe (instance->socket_fd);
+	res = fcntl (instance->socket_fd, F_SETFL, O_NONBLOCK);
+	if (res == -1) {
+		char error_str[100];
+		strerror_r (errno, error_str, 100);
+		log_printf(LOGSYS_LEVEL_WARNING,
+			"Could not set non-blocking operation on multicast socket: %s\n", error_str);
+		return (-1);
+	}
+
+	/*
+	 * Force reuse
+	 */
+	 flag = 1;
+	 if (setsockopt(instance->socket_fd, SOL_SOCKET, SO_REUSEADDR,
+		(char *)&flag, sizeof (flag)) < 0) {
+
+	 	perror("setsockopt reuseaddr");
+		return (-1);
+	}
+
+	/*
+	 * Bind socket to interface
+	 */
+	d1htip_d1htip_to_sockaddr_convert(bound_to,
+		instance->d1ht_interface->ip_port, &sockaddr, &addrlen);
+	res = bind (instance->socket_fd, (struct sockaddr *)&sockaddr, addrlen);
+	if (res == -1) {
+		perror ("bind mcast recv socket failed");
+		return (-1);
+	}
+
+	recvbuf_size = 150000;
+	sendbuf_size = 150000;
+	/*
+	 * Set buffer sizes to avoid overruns
+	 */
+	 res = setsockopt (instance->socket_fd, SOL_SOCKET, SO_RCVBUF, &recvbuf_size, optlen);
+
+	res = getsockopt (instance->socket_fd, SOL_SOCKET, SO_RCVBUF, &recvbuf_size, &optlen);
+	if (res == 0) {
+		log_printf(LOGSYS_LEVEL_DEBUG,
+			"membership socket buffer size (%d bytes).\n", recvbuf_size);
+	}
+
+	return 0;
+}
+
+static int d1htudp_build_sockets (
+	struct d1htudp_instance *instance,
+	struct d1ht_ip_address *bindnet_address,
+	struct d1ht_ip_address *bound_to)
+{
+	int interface_num;
+	int interface_up;
+	int res;
+
+	/*
+	 * Determine the ip address bound to and the interface name
+	 */
+	res = netif_determine (instance,
+		bindnet_address,
+		bound_to,
+		&interface_up,
+		&interface_num);
+
+	if (res == -1) {
+		return (-1);
+	}
+
+	d1htip_copy(&instance->my_id, bound_to);
+
+	res = d1htudp_build_sockets_ip (instance, bindnet_address, bound_to);
+
+	return res;
+}
+
+/*
+ * Create an instance
+ */
+int d1htudp_initialize (
+	hdb_handle_t poll_handle,
+	void **udp_context,
+	struct d1ht_config *d1ht_config,
+	void *context,
+
+	void (*deliver_fn) (
+		void *context,
+		const void *msg,
+		unsigned int msg_len),
+
+	void (*iface_change_fn) (
+		void *context,
+		const struct d1ht_ip_address *iface_address))
+{
+	struct d1htudp_instance *instance;
+
+	instance = malloc (sizeof (struct d1htudp_instance));
+	if (instance == NULL) {
+		return (-1);
+	}
+
+	d1htudp_instance_initialize (instance);
+
+	instance->d1ht_config = d1ht_config;
+
+	/*
+	* Initialize random number generator for later use to generate salt
+	*/
+	memcpy (instance->d1htudp_private_key, d1ht_config->private_key,
+		d1ht_config->private_key_len);
+
+	instance->d1htudp_private_key_len = d1ht_config->private_key_len;
+
+	init_crypto(instance);
+
+	/*
+	 * Initialize local variables for d1htudp
+	 */
+	instance->d1ht_interface = &d1ht_config->interface;
+	memset (instance->iov_buffer, 0, FRAME_SIZE_MAX);
+
+	instance->d1htudp_poll_handle = poll_handle;
+
+	instance->context = context;
+	instance->d1htudp_deliver_fn = deliver_fn;
+
+	instance->d1htudp_iface_change_fn = iface_change_fn;
+
+	/*
+	 * RRP layer isn't ready to receive message because it hasn't
+	 * initialized yet.  Add short timer to check the interfaces.
+	 */
+	poll_timer_add (instance->d1htudp_poll_handle,
+		100,
+		(void *)instance,
+		timer_function_netif_check_timeout,
+		&instance->timer_netif_check_timeout);
+
+	*udp_context = instance;
+	return (0);
+}
+
+int d1htudp_unicast_send (
+	void *udp_context,
+	const void *msg,
+	unsigned int msg_len,
+	struct d1ht_ip_address *target)
+{
+	struct d1htudp_instance *instance = (struct d1htudp_instance *)udp_context;
+	int res = 0;
+
+	ucast_sendmsg (instance, msg, msg_len, target);
+
+	return (res);
+}
+
+extern int d1htudp_iface_check (void *udp_context)
+{
+	struct d1htudp_instance *instance = (struct d1htudp_instance *)udp_context;
+	int res = 0;
+
+	timer_function_netif_check_timeout (instance);
+
+	return (res);
+}
+
+const char *d1htudp_iface_print (void *udp_context)  {
+	struct d1htudp_instance *instance = (struct d1htudp_instance *)udp_context;
+	const char *ret_char;
+
+	ret_char = d1htip_print (&instance->my_id);
+
+	return (ret_char);
+}
+
+int d1htudp_iface_get (
+	void *udp_context,
+	struct d1ht_ip_address *addr)
+{
+	struct d1htudp_instance *instance = (struct d1htudp_instance *)udp_context;
+	int res = 0;
+
+	memcpy (addr, &instance->my_id, sizeof (struct d1ht_ip_address));
+
+	return (res);
+}
diff --git a/src/d1htudp.h b/src/d1htudp.h
new file mode 100644
index 0000000..73d9955
--- /dev/null
+++ b/src/d1htudp.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef D1HTUDP_H_DEFINED
+#define D1HTUDP_H_DEFINED
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "hdb.h"
+#include "d1htip.h"
+#include "d1ht.h"
+
+/*
+ * Create an instance
+ */
+extern int d1htudp_initialize (
+	hdb_handle_t poll_handle,
+	void **udp_context,
+	struct d1ht_config *d1ht_config,
+	void *context,
+
+	void (*deliver_fn) (
+		void *context,
+		const void *msg,
+		unsigned int msg_len),
+
+	void (*iface_change_fn) (
+		void *context,
+		const struct d1ht_ip_address *iface_address));
+
+extern int d1htudp_unicast_send (
+	void *udp_context,
+	const void *msg,
+	unsigned int msg_len,
+	struct d1ht_ip_address *target);
+
+extern int d1htudp_iface_check (void *udp_context);
+
+extern int d1htudp_finalize (void *udp_context);
+
+extern const char *d1htudp_iface_print (void *udp_context);
+
+extern int d1htudp_iface_get (
+	void *udp_context,
+	struct d1ht_ip_address *addr);
+
+extern int d1htudp_crypto_set (
+	void *udp_context,
+	unsigned int type);
+
+#endif /* D1HTUDP_H_DEFINED */
diff --git a/src/hdb.h b/src/hdb.h
new file mode 100644
index 0000000..860738f
--- /dev/null
+++ b/src/hdb.h
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2002-2006 MontaVista Software, Inc.
+ * Copyright (c) 2006-2009 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@redhat.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HDB_H_DEFINED
+#define HDB_H_DEFINED
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <errno.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+typedef uint64_t hdb_handle_t;
+
+/*
+ * Formatting for string printing on 32/64 bit systems
+ */
+#define HDB_D_FORMAT "%"PRIu64
+#define HDB_X_FORMAT "%"PRIx64
+
+enum HDB_HANDLE_STATE {
+	HDB_HANDLE_STATE_EMPTY,
+	HDB_HANDLE_STATE_PENDINGREMOVAL,
+	HDB_HANDLE_STATE_ACTIVE
+};
+
+struct hdb_handle {
+	int state;
+	void *instance;
+	int check;
+	int ref_count;
+};
+
+struct hdb_handle_database {
+	unsigned int handle_count;
+	struct hdb_handle *handles;
+	unsigned int iterator;
+        void (*destructor) (void *);
+#if defined(HAVE_PTHREAD_SPIN_LOCK)
+	pthread_spinlock_t lock;
+#else
+	pthread_mutex_t lock;
+#endif
+	unsigned int first_run;
+};
+
+#if defined(HAVE_PTHREAD_SPIN_LOCK)
+static inline void hdb_database_lock (pthread_spinlock_t *spinlock)
+{
+	pthread_spin_lock (spinlock);
+}
+
+static inline void hdb_database_unlock (pthread_spinlock_t *spinlock)
+{
+	pthread_spin_unlock (spinlock);
+}
+static inline void hdb_database_lock_init (pthread_spinlock_t *spinlock)
+{
+	pthread_spin_init (spinlock, 0);
+}
+
+static inline void hdb_database_lock_destroy (pthread_spinlock_t *spinlock)
+{
+	pthread_spin_destroy (spinlock);
+}
+
+#else
+static inline void hdb_database_lock (pthread_mutex_t *mutex)
+{
+	pthread_mutex_lock (mutex);
+}
+
+static inline void hdb_database_unlock (pthread_mutex_t *mutex)
+{
+	pthread_mutex_unlock (mutex);
+}
+static inline void hdb_database_lock_init (pthread_mutex_t *mutex)
+{
+	pthread_mutex_init (mutex, NULL);
+}
+
+static inline void hdb_database_lock_destroy (pthread_mutex_t *mutex)
+{
+	pthread_mutex_destroy (mutex);
+}
+#endif
+
+#define DECLARE_HDB_DATABASE(database_name,destructor_function)		\
+static struct hdb_handle_database (database_name) = {			\
+	.handle_count	= 0,						\
+	.handles 	= NULL,						\
+	.iterator	= 0,						\
+	.destructor	= destructor_function,				\
+	.first_run	= 1						\
+};									\
+
+static inline void hdb_create (
+	struct hdb_handle_database *handle_database)
+{
+	memset (handle_database, 0, sizeof (struct hdb_handle_database));
+	hdb_database_lock_init (&handle_database->lock);
+}
+
+static inline void hdb_destroy (
+	struct hdb_handle_database *handle_database)
+{
+	free (handle_database->handles);
+	hdb_database_lock_destroy (&handle_database->lock);
+	memset (handle_database, 0, sizeof (struct hdb_handle_database));
+}
+
+
+static inline int hdb_handle_create (
+	struct hdb_handle_database *handle_database,
+	int instance_size,
+	hdb_handle_t *handle_id_out)
+{
+	int handle;
+	unsigned int check;
+	void *new_handles;
+	int found = 0;
+	void *instance;
+	int i;
+
+	if (handle_database->first_run == 1) {
+		handle_database->first_run = 0;
+		hdb_database_lock_init (&handle_database->lock);
+	}
+	hdb_database_lock (&handle_database->lock);
+
+	for (handle = 0; handle < handle_database->handle_count; handle++) {
+		if (handle_database->handles[handle].state == HDB_HANDLE_STATE_EMPTY) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found == 0) {
+		handle_database->handle_count += 1;
+		new_handles = (struct hdb_handle *)realloc (handle_database->handles,
+			sizeof (struct hdb_handle) * handle_database->handle_count);
+		if (new_handles == NULL) {
+			hdb_database_unlock (&handle_database->lock);
+			errno = ENOMEM;
+			return (-1);
+		}
+		handle_database->handles = new_handles;
+	}
+
+	instance = (void *)malloc (instance_size);
+	if (instance == 0) {
+		errno = ENOMEM;
+		return (-1);
+	}
+
+	/*
+	 * This code makes sure the random number isn't zero
+	 * We use 0 to specify an invalid handle out of the 1^64 address space
+	 * If we get 0 200 times in a row, the RNG may be broken
+	 */
+	for (i = 0; i < 200; i++) {
+		check = random();
+
+		if (check != 0 && check != 0xffffffff) {
+			break;
+		}
+	}
+
+	memset (instance, 0, instance_size);
+
+	handle_database->handles[handle].state = HDB_HANDLE_STATE_ACTIVE;
+
+	handle_database->handles[handle].instance = instance;
+
+	handle_database->handles[handle].ref_count = 1;
+
+	handle_database->handles[handle].check = check;
+
+	*handle_id_out = (((unsigned long long)(check)) << 32) | handle;
+
+	hdb_database_unlock (&handle_database->lock);
+
+	return (0);
+}
+
+static inline int hdb_handle_get (
+	struct hdb_handle_database *handle_database,
+	hdb_handle_t handle_in,
+	void **instance)
+{
+	unsigned int check = ((unsigned int)(((unsigned long long)handle_in) >> 32));
+	unsigned int handle = handle_in & 0xffffffff;
+
+	if (handle_database->first_run == 1) {
+		handle_database->first_run = 0;
+		hdb_database_lock_init (&handle_database->lock);
+	}
+	hdb_database_lock (&handle_database->lock);
+
+	*instance = NULL;
+	if (handle >= handle_database->handle_count) {
+		hdb_database_unlock (&handle_database->lock);
+		errno = EBADF;
+		return (-1);
+	}
+
+	if (handle_database->handles[handle].state != HDB_HANDLE_STATE_ACTIVE) {
+		hdb_database_unlock (&handle_database->lock);
+		errno = EBADF;
+		return (-1);
+	}
+
+	if (check != 0xffffffff &&
+		check != handle_database->handles[handle].check) {
+
+		hdb_database_unlock (&handle_database->lock);
+		errno = EBADF;
+		return (-1);
+	}
+
+	*instance = handle_database->handles[handle].instance;
+
+	handle_database->handles[handle].ref_count += 1;
+
+	hdb_database_unlock (&handle_database->lock);
+	return (0);
+}
+
+static inline int hdb_handle_get_always (
+	struct hdb_handle_database *handle_database,
+	hdb_handle_t handle_in,
+	void **instance)
+{
+	unsigned int check = ((unsigned int)(((unsigned long long)handle_in) >> 32));
+	unsigned int handle = handle_in & 0xffffffff;
+
+	if (handle_database->first_run == 1) {
+		handle_database->first_run = 0;
+		hdb_database_lock_init (&handle_database->lock);
+	}
+	hdb_database_lock (&handle_database->lock);
+
+	*instance = NULL;
+	if (handle >= handle_database->handle_count) {
+		hdb_database_unlock (&handle_database->lock);
+		errno = EBADF;
+		return (-1);
+	}
+
+	if (handle_database->handles[handle].state == HDB_HANDLE_STATE_EMPTY) {
+		hdb_database_unlock (&handle_database->lock);
+		errno = EBADF;
+		return (-1);
+	}
+
+	if (check != 0xffffffff &&
+		check != handle_database->handles[handle].check) {
+
+		hdb_database_unlock (&handle_database->lock);
+		errno = EBADF;
+		return (-1);
+	}
+
+	*instance = handle_database->handles[handle].instance;
+
+	handle_database->handles[handle].ref_count += 1;
+
+	hdb_database_unlock (&handle_database->lock);
+	return (0);
+}
+
+static inline int hdb_handle_put (
+	struct hdb_handle_database *handle_database,
+	hdb_handle_t handle_in)
+{
+	unsigned int check = ((unsigned int)(((unsigned long long)handle_in) >> 32));
+	unsigned int handle = handle_in & 0xffffffff;
+
+	if (handle_database->first_run == 1) {
+		handle_database->first_run = 0;
+		hdb_database_lock_init (&handle_database->lock);
+	}
+	hdb_database_lock (&handle_database->lock);
+
+	if (handle >= handle_database->handle_count) {
+		hdb_database_unlock (&handle_database->lock);
+
+		errno = EBADF;
+		return (-1);
+	}
+
+	if (check != 0xffffffff &&
+		check != handle_database->handles[handle].check) {
+
+		hdb_database_unlock (&handle_database->lock);
+		errno = EBADF;
+		return (-1);
+	}
+
+	handle_database->handles[handle].ref_count -= 1;
+	assert (handle_database->handles[handle].ref_count >= 0);
+
+	if (handle_database->handles[handle].ref_count == 0) {
+		if (handle_database->destructor) {
+			handle_database->destructor (handle_database->handles[handle].instance);
+		}
+		free (handle_database->handles[handle].instance);
+		memset (&handle_database->handles[handle], 0, sizeof (struct hdb_handle));
+	}
+	hdb_database_unlock (&handle_database->lock);
+	return (0);
+}
+
+static inline int hdb_handle_destroy (
+	struct hdb_handle_database *handle_database,
+	hdb_handle_t handle_in)
+{
+	unsigned int check = ((unsigned int)(((unsigned long long)handle_in) >> 32));
+	unsigned int handle = handle_in & 0xffffffff;
+	int res;
+
+	if (handle_database->first_run == 1) {
+		handle_database->first_run = 0;
+		hdb_database_lock_init (&handle_database->lock);
+	}
+	hdb_database_lock (&handle_database->lock);
+
+	if (handle >= handle_database->handle_count) {
+		hdb_database_unlock (&handle_database->lock);
+
+		errno = EBADF;
+		return (-1);
+	}
+
+	if (check != 0xffffffff &&
+		check != handle_database->handles[handle].check) {
+		hdb_database_unlock (&handle_database->lock);
+		errno = EBADF;
+		return (-1);
+	}
+
+	handle_database->handles[handle].state = HDB_HANDLE_STATE_PENDINGREMOVAL;
+	hdb_database_unlock (&handle_database->lock);
+	res = hdb_handle_put (handle_database, handle_in);
+	return (res);
+}
+
+static inline int hdb_handle_refcount_get (
+	struct hdb_handle_database *handle_database,
+	hdb_handle_t handle_in)
+{
+	unsigned int check = ((unsigned int)(((unsigned long long)handle_in) >> 32));
+	unsigned int handle = handle_in & 0xffffffff;
+
+	int refcount = 0;
+
+	if (handle_database->first_run == 1) {
+		handle_database->first_run = 0;
+		hdb_database_lock_init (&handle_database->lock);
+	}
+	hdb_database_lock (&handle_database->lock);
+
+	if (handle >= handle_database->handle_count) {
+		hdb_database_unlock (&handle_database->lock);
+		errno = EBADF;
+		return (-1);
+	}
+
+	if (check != 0xffffffff &&
+		check != handle_database->handles[handle].check) {
+		hdb_database_unlock (&handle_database->lock);
+		errno = EBADF;
+		return (-1);
+	}
+
+	refcount = handle_database->handles[handle].ref_count;
+
+	hdb_database_unlock (&handle_database->lock);
+
+	return (refcount);
+}
+
+static inline void hdb_iterator_reset (
+	struct hdb_handle_database *handle_database)
+{
+	handle_database->iterator = 0;
+}
+
+static inline int hdb_iterator_next (
+	struct hdb_handle_database *handle_database,
+	void **instance,
+	hdb_handle_t *handle)
+{
+	int res = -1;
+
+	while (handle_database->iterator < handle_database->handle_count) {
+		*handle = ((unsigned long long)(handle_database->handles[handle_database->iterator].check) << 32) | handle_database->iterator;
+		res = hdb_handle_get (
+			handle_database,
+			*handle,
+			instance);
+
+		handle_database->iterator += 1;
+		if (res == 0) {
+			break;
+		}
+	}
+	return (res);
+}
+
+static inline unsigned int hdb_base_convert (hdb_handle_t handle)
+{
+	return (handle & 0xffffffff);
+}
+
+static inline unsigned long long hdb_nocheck_convert (unsigned int handle)
+{
+	unsigned long long retvalue = 0xffffffffULL << 32 | handle;
+
+	return (retvalue);
+}
+
+#endif /* HDB_H_DEFINED */
diff --git a/src/list.h b/src/list.h
new file mode 100644
index 0000000..631578c
--- /dev/null
+++ b/src/list.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*
+ * This API shamelessly borrowed from linux kernel tree.
+ */
+#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 *element, struct list_head *head)
+{
+	head->next->prev = element;
+	element->next = head->next;
+	element->prev = head;
+	head->next = element;
+}
+static void inline list_add_tail (struct list_head *element, struct list_head *head)
+{
+	head->prev->next = element;
+	element->next = head;
+	element->prev = head->prev;
+	head->prev = element;
+}
+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)))
+
+static inline int list_empty(const struct list_head *l)
+{
+	return l->next == l;
+}
+
+static inline void list_splice (struct list_head *list, struct list_head *head)
+{
+	struct list_head *first;
+	struct list_head *last;
+	struct list_head *current;
+
+	first = list->next;
+	last = list->prev;
+	current = head->next;
+
+	first->prev = head;
+	head->next = first;
+	last->next = current;
+	current->prev = last;
+}
+
+#endif /* LIST_H_DEFINED */
diff --git a/src/logsys.c b/src/logsys.c
new file mode 100644
index 0000000..f649e5f
--- /dev/null
+++ b/src/logsys.c
@@ -0,0 +1,1717 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ * Copyright (c) 2006-2009 Red Hat, Inc.
+ *
+ * Author: Steven Dake (sdake@redhat.com)
+ * Author: Lon Hohberger (lhh@redhat.com)
+ * Author: Fabio M. Di Nitto (fdinitto@redhat.com)
+ *
+ * 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.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#if defined(COROSYNC_LINUX)
+#include <linux/un.h>
+#endif
+#if defined(COROSYNC_BSD) || defined(COROSYNC_DARWIN)
+#include <sys/un.h>
+#endif
+#include <syslog.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <limits.h>
+
+#include <corosync/engine/logsys.h>
+
+#define YIELD_AFTER_LOG_OPS 10
+
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+
+#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+
+/*
+ * syslog prioritynames, facility names to value mapping
+ * Some C libraries build this in to their headers, but it is non-portable
+ * so logsys supplies its own version.
+ */
+struct syslog_names {
+	const char *c_name;
+	int c_val;
+};
+
+struct syslog_names prioritynames[] =
+{
+	{ "alert", LOG_ALERT },
+	{ "crit", LOG_CRIT },
+	{ "debug", LOG_DEBUG },
+	{ "emerg", LOG_EMERG },
+	{ "err", LOG_ERR },
+	{ "error", LOG_ERR },
+	{ "info", LOG_INFO },
+	{ "notice", LOG_NOTICE },
+	{ "warning", LOG_WARNING },
+	{ NULL, -1 }
+};
+
+struct syslog_names facilitynames[] =
+{
+	{ "auth", LOG_AUTH },
+	{ "cron", LOG_CRON },
+	{ "daemon", LOG_DAEMON },
+	{ "kern", LOG_KERN },
+	{ "lpr", LOG_LPR },
+	{ "mail", LOG_MAIL },
+	{ "news", LOG_NEWS },
+	{ "syslog", LOG_SYSLOG },
+	{ "user", LOG_USER },
+	{ "uucp", LOG_UUCP },
+	{ "local0", LOG_LOCAL0 },
+	{ "local1", LOG_LOCAL1 },
+	{ "local2", LOG_LOCAL2 },
+	{ "local3", LOG_LOCAL3 },
+	{ "local4", LOG_LOCAL4 },
+	{ "local5", LOG_LOCAL5 },
+	{ "local6", LOG_LOCAL6 },
+	{ "local7", LOG_LOCAL7 },
+	{ NULL, -1 }
+};
+
+
+/*
+ * These are not static so they can be read from the core file
+ */
+int *flt_data;
+
+unsigned int flt_data_size;
+
+#define COMBINE_BUFFER_SIZE 2048
+
+/* values for logsys_logger init_status */
+#define LOGSYS_LOGGER_INIT_DONE		0
+#define LOGSYS_LOGGER_NEEDS_INIT	1
+
+static int logsys_system_needs_init = LOGSYS_LOGGER_NEEDS_INIT;
+
+static int logsys_sched_param_queued = 0;
+static int logsys_sched_policy;
+static struct sched_param logsys_sched_param;
+
+static int logsys_after_log_ops_yield = 10;
+
+/*
+ * need unlogical order to preserve 64bit alignment
+ */
+struct logsys_logger {
+	char subsys[LOGSYS_MAX_SUBSYS_NAMELEN];	/* subsystem name */
+	char *logfile;				/* log to file */
+	FILE *logfile_fp;			/* track file descriptor */
+	unsigned int mode;			/* subsystem mode */
+	unsigned int debug;			/* debug on|off */
+	int syslog_facility;			/* facility */
+	int syslog_priority;			/* priority */
+	int logfile_priority;			/* priority to file */
+	int init_status;			/* internal field to handle init queues
+						   for subsystems */
+};
+
+/*
+ * operating global variables
+ */
+
+static struct logsys_logger logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT + 1];
+
+static int wthread_active = 0;
+
+static int wthread_should_exit = 0;
+
+static pthread_mutex_t logsys_config_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static unsigned int records_written = 1;
+
+static pthread_t logsys_thread_id;
+
+static pthread_cond_t logsys_cond;
+
+static pthread_mutex_t logsys_cond_mutex;
+
+#if defined(HAVE_PTHREAD_SPIN_LOCK)
+static pthread_spinlock_t logsys_idx_spinlock;
+#else
+static pthread_mutex_t logsys_idx_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+static unsigned int log_rec_idx;
+
+static int logsys_buffer_full = 0;
+
+static char *format_buffer=NULL;
+
+static int log_requests_pending = 0;
+
+static int log_requests_lost = 0;
+
+void *logsys_rec_end;
+
+#define FDHEAD_INDEX	(flt_data_size)
+
+#define FDTAIL_INDEX 	(flt_data_size + 1)
+
+#define FDMAX_ARGS	64
+
+/* forward declarations */
+static void logsys_close_logfile(int subsysid);
+
+#ifdef LOGSYS_DEBUG
+static char *decode_mode(int subsysid, char *buf, size_t buflen)
+{
+	memset(buf, 0, buflen);
+
+	if (logsys_loggers[subsysid].mode & LOGSYS_MODE_OUTPUT_FILE)
+		snprintf(buf+strlen(buf), buflen, "FILE,");
+
+	if (logsys_loggers[subsysid].mode & LOGSYS_MODE_OUTPUT_STDERR)
+		snprintf(buf+strlen(buf), buflen, "STDERR,");
+
+	if (logsys_loggers[subsysid].mode & LOGSYS_MODE_OUTPUT_SYSLOG)
+		snprintf(buf+strlen(buf), buflen, "SYSLOG,");
+
+	if (subsysid == LOGSYS_MAX_SUBSYS_COUNT) {
+		if (logsys_loggers[subsysid].mode & LOGSYS_MODE_FORK)
+			snprintf(buf+strlen(buf), buflen, "FORK,");
+
+		if (logsys_loggers[subsysid].mode & LOGSYS_MODE_THREADED)
+			snprintf(buf+strlen(buf), buflen, "THREADED,");
+	}
+
+	memset(buf+strlen(buf)-1,0,1);
+
+	return buf;
+}
+
+static const char *decode_debug(int subsysid)
+{
+	if (logsys_loggers[subsysid].debug)
+		return "on";
+
+	return "off";
+}
+
+static const char *decode_status(int subsysid)
+{
+	if (!logsys_loggers[subsysid].init_status)
+		return "INIT_DONE";
+
+	return "NEEDS_INIT";
+}
+
+static void dump_subsys_config(int subsysid)
+{
+	char modebuf[1024];
+
+	fprintf(stderr,
+		"ID: %d\n"
+		"subsys: %s\n"
+		"logfile: %s\n"
+		"logfile_fp: %p\n"
+		"mode: %s\n"
+		"debug: %s\n"
+		"syslog_fac: %s\n"
+		"syslog_pri: %s\n"
+		"logfile_pri: %s\n"
+		"init_status: %s\n",
+		subsysid,
+		logsys_loggers[subsysid].subsys,
+		logsys_loggers[subsysid].logfile,
+		logsys_loggers[subsysid].logfile_fp,
+		decode_mode(subsysid, modebuf, sizeof(modebuf)),
+		decode_debug(subsysid),
+		logsys_facility_name_get(logsys_loggers[subsysid].syslog_facility),
+		logsys_priority_name_get(logsys_loggers[subsysid].syslog_priority),
+		logsys_priority_name_get(logsys_loggers[subsysid].logfile_priority),
+		decode_status(subsysid));
+}
+
+static void dump_full_config(void)
+{
+	int i;
+
+	for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
+		if (strlen(logsys_loggers[i].subsys) > 0)
+			dump_subsys_config(i);
+	}
+}
+#endif
+
+/*
+ * Helpers for _logsys_log_rec functionality
+ */
+static inline void my_memcpy_32bit (int *dest, const int *src, unsigned int words)
+{
+	unsigned int word_idx;
+	for (word_idx = 0; word_idx < words; word_idx++) {
+		dest[word_idx] = src[word_idx];
+	}
+}
+
+static inline void my_memcpy_8bit (char *dest, const char *src,
+				   unsigned int bytes)
+{
+	unsigned int byte_idx;
+
+	for (byte_idx = 0; byte_idx < bytes; byte_idx++) {
+		dest[byte_idx] = src[byte_idx];
+	}
+}
+
+#if defined(HAVE_PTHREAD_SPIN_LOCK)
+static void logsys_lock (void)
+{
+	pthread_spin_lock (&logsys_idx_spinlock);
+}
+static void logsys_unlock (void)
+{
+	pthread_spin_unlock (&logsys_idx_spinlock);
+}
+#else
+static void logsys_lock (void)
+{
+	pthread_mutex_lock (&logsys_idx_mutex);
+}
+static void logsys_unlock (void)
+{
+	pthread_mutex_unlock (&logsys_idx_mutex);
+}
+#endif
+
+/*
+ * Before any write operation, a reclaim on the buffer area must be executed
+ */
+static inline void records_reclaim (unsigned int idx, unsigned int words)
+{
+	unsigned int should_reclaim;
+
+	should_reclaim = 0;
+
+	if ((idx + words) >= flt_data_size) {
+		logsys_buffer_full = 1;
+	}
+	if (logsys_buffer_full == 0) {
+		return;
+	}
+
+	logsys_lock();
+	if (flt_data[FDTAIL_INDEX] > flt_data[FDHEAD_INDEX]) {
+		if (idx + words >= flt_data[FDTAIL_INDEX]) {
+			should_reclaim = 1;
+		}
+	} else {
+		if ((idx + words) >= (flt_data[FDTAIL_INDEX] + flt_data_size)) {
+			should_reclaim = 1;
+		}
+	}
+
+	if (should_reclaim) {
+		int words_needed = 0;
+
+		words_needed = words + 1;
+		do {
+			unsigned int old_tail;
+
+			words_needed -= flt_data[flt_data[FDTAIL_INDEX]];
+			old_tail = flt_data[FDTAIL_INDEX];
+			flt_data[FDTAIL_INDEX] =
+				(flt_data[FDTAIL_INDEX] +
+				flt_data[flt_data[FDTAIL_INDEX]]) % (flt_data_size);
+			if (log_rec_idx == old_tail) {
+				log_requests_lost += 1;
+				log_rec_idx = flt_data[FDTAIL_INDEX];
+			}
+		} while (words_needed > 0);
+	}
+	logsys_unlock();
+}
+
+#define idx_word_step(idx)						\
+do {									\
+	if (idx > (flt_data_size - 1)) {				\
+		idx = 0;						\
+	}								\
+} while (0);
+
+#define idx_buffer_step(idx)						\
+do {									\
+	if (idx > (flt_data_size - 1)) {				\
+		idx = ((idx) % (flt_data_size));			\
+	}								\
+} while (0);
+
+/*
+ * Internal threaded logging implementation
+ */
+static inline int strcpy_cutoff (char *dest, const char *src, size_t cutoff,
+				 size_t buf_len)
+{
+	size_t len = strlen (src);
+	if (buf_len <= 1) {
+		if (buf_len == 0)
+			dest[0] = 0;
+		return 0;
+	}
+
+	if (cutoff == 0) {
+		cutoff = len;
+	}
+
+	cutoff = MIN (cutoff, buf_len - 1);
+	len = MIN (len, cutoff);
+	memcpy (dest, src, len);
+	memset (dest + len, ' ', cutoff - len);
+	dest[cutoff] = '\0';
+
+	return (cutoff);
+}
+
+static const char log_month_name[][4] = {
+	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+/*
+ * %s SUBSYSTEM
+ * %n FUNCTION NAME
+ * %f FILENAME
+ * %l FILELINE
+ * %p PRIORITY
+ * %t TIMESTAMP
+ * %b BUFFER
+ *
+ * any number between % and character specify field length to pad or chop
+*/
+static void log_printf_to_logs (
+	unsigned int rec_ident,
+	const char *file_name,
+	const char *function_name,
+	int file_line,
+	const char *buffer)
+{
+	char normal_output_buffer[COMBINE_BUFFER_SIZE];
+	char syslog_output_buffer[COMBINE_BUFFER_SIZE];
+	char char_time[128];
+	char line_no[30];
+	unsigned int format_buffer_idx = 0;
+	unsigned int normal_output_buffer_idx = 0;
+	unsigned int syslog_output_buffer_idx = 0;
+	struct timeval tv;
+	size_t cutoff;
+	unsigned int normal_len, syslog_len;
+	int subsysid;
+	unsigned int level;
+	int c;
+	struct tm tm_res;
+
+	if (LOGSYS_DECODE_RECID(rec_ident) != LOGSYS_RECID_LOG) {
+		return;
+	}
+
+	subsysid = LOGSYS_DECODE_SUBSYSID(rec_ident);
+	level = LOGSYS_DECODE_LEVEL(rec_ident);
+
+	while ((c = format_buffer[format_buffer_idx])) {
+		cutoff = 0;
+		if (c != '%') {
+			normal_output_buffer[normal_output_buffer_idx++] = c;
+			syslog_output_buffer[syslog_output_buffer_idx++] = c;
+			format_buffer_idx++;
+		} else {
+			const char *normal_p, *syslog_p;
+
+			format_buffer_idx += 1;
+			if (isdigit (format_buffer[format_buffer_idx])) {
+				cutoff = atoi (&format_buffer[format_buffer_idx]);
+			}
+			while (isdigit (format_buffer[format_buffer_idx])) {
+				format_buffer_idx += 1;
+			}
+
+			switch (format_buffer[format_buffer_idx]) {
+				case 's':
+					normal_p = logsys_loggers[subsysid].subsys;
+					syslog_p = logsys_loggers[subsysid].subsys;
+					break;
+
+				case 'n':
+					normal_p = function_name;
+					syslog_p = function_name;
+					break;
+
+				case 'f':
+					normal_p = file_name;
+					syslog_p = file_name;
+					break;
+
+				case 'l':
+					sprintf (line_no, "%d", file_line);
+					normal_p = line_no;
+					syslog_p = line_no;
+					break;
+
+				case 't':
+					gettimeofday (&tv, NULL);
+					(void)localtime_r ((time_t *)&tv.tv_sec, &tm_res);
+					snprintf (char_time, sizeof (char_time), "%s %02d %02d:%02d:%02d",
+					    log_month_name[tm_res.tm_mon], tm_res.tm_mday, tm_res.tm_hour,
+					    tm_res.tm_min, tm_res.tm_sec);
+					normal_p = char_time;
+
+					/*
+					 * syslog does timestamping on its own.
+					 * also strip extra space in case.
+					 */
+					syslog_p = "";
+					break;
+
+				case 'b':
+					normal_p = buffer;
+					syslog_p = buffer;
+					break;
+
+				case 'p':
+					normal_p = logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT].subsys;
+					syslog_p = "";
+					break;
+
+				default:
+					normal_p = "";
+					syslog_p = "";
+					break;
+			}
+			normal_len = strcpy_cutoff (normal_output_buffer + normal_output_buffer_idx,
+					     normal_p, cutoff,
+					     (sizeof (normal_output_buffer)
+					      - normal_output_buffer_idx));
+			normal_output_buffer_idx += normal_len;
+			syslog_len = strcpy_cutoff (syslog_output_buffer + syslog_output_buffer_idx,
+					     syslog_p, cutoff,
+					     (sizeof (syslog_output_buffer)
+					      - syslog_output_buffer_idx));
+			syslog_output_buffer_idx += syslog_len;
+			format_buffer_idx += 1;
+		}
+		if ((normal_output_buffer_idx >= sizeof (normal_output_buffer) - 2) ||
+		    (syslog_output_buffer_idx >= sizeof (syslog_output_buffer) - 1)) {
+			/* Note: we make allowance for '\0' at the end of
+			 * both of these arrays and normal_output_buffer also
+			 * needs a '\n'.
+			 */
+			break;
+		}
+	}
+
+	normal_output_buffer[normal_output_buffer_idx] = '\0';
+	syslog_output_buffer[syslog_output_buffer_idx] = '\0';
+
+	/*
+	 * Output to syslog
+	 */
+	if ((logsys_loggers[subsysid].mode & LOGSYS_MODE_OUTPUT_SYSLOG) &&
+	     ((level <= logsys_loggers[subsysid].syslog_priority) ||
+	     (logsys_loggers[subsysid].debug != 0))) {
+		syslog (level | logsys_loggers[subsysid].syslog_facility, "%s", syslog_output_buffer);
+	}
+
+	/*
+	 * Terminate string with \n \0
+	 */
+	normal_output_buffer[normal_output_buffer_idx++] = '\n';
+	normal_output_buffer[normal_output_buffer_idx] = '\0';
+
+	/*
+	 * Output to configured file
+	 */
+	if (((logsys_loggers[subsysid].mode & LOGSYS_MODE_OUTPUT_FILE) &&
+	     (logsys_loggers[subsysid].logfile_fp != NULL)) &&
+	    ((level <= logsys_loggers[subsysid].logfile_priority) ||
+	     (logsys_loggers[subsysid].debug != 0))) {
+		/*
+		 * Output to a file
+		 */
+		if ((fwrite (normal_output_buffer, strlen (normal_output_buffer), 1,
+			    logsys_loggers[subsysid].logfile_fp) < 1) ||
+		    (fflush (logsys_loggers[subsysid].logfile_fp) == EOF)) {
+			char tmpbuffer[1024];
+			/*
+			 * if we are here, it's bad.. it's really really bad.
+			 * Best thing would be to light a candle in a church
+			 * and pray.
+			 */
+			snprintf(tmpbuffer, sizeof(tmpbuffer),
+				"LOGSYS EMERGENCY: %s Unable to write to %s.",
+				logsys_loggers[subsysid].subsys,
+				logsys_loggers[subsysid].logfile);
+			pthread_mutex_lock (&logsys_config_mutex);
+			logsys_close_logfile(subsysid);
+			logsys_loggers[subsysid].mode &= ~LOGSYS_MODE_OUTPUT_FILE;
+			pthread_mutex_unlock (&logsys_config_mutex);
+			log_printf_to_logs(
+					   LOGSYS_ENCODE_RECID(
+						LOGSYS_LEVEL_EMERG,
+						subsysid,
+						LOGSYS_RECID_LOG),
+					   __FILE__, __FUNCTION__, __LINE__,
+					   tmpbuffer);
+		}
+	}
+
+	/*
+	 * Output to stderr
+	 */
+	if ((logsys_loggers[subsysid].mode & LOGSYS_MODE_OUTPUT_STDERR) &&
+	     ((level <= logsys_loggers[subsysid].logfile_priority) ||
+	     (logsys_loggers[subsysid].debug != 0))) {
+		if (write (STDERR_FILENO, normal_output_buffer, strlen (normal_output_buffer)) < 0) {
+			char tmpbuffer[1024];
+			/*
+			 * if we are here, it's bad.. it's really really bad.
+			 * Best thing would be to light 20 candles for each saint
+			 * in the calendar and pray a lot...
+			 */
+			pthread_mutex_lock (&logsys_config_mutex);
+			logsys_loggers[subsysid].mode &= ~LOGSYS_MODE_OUTPUT_STDERR;
+			pthread_mutex_unlock (&logsys_config_mutex);
+			snprintf(tmpbuffer, sizeof(tmpbuffer),
+				"LOGSYS EMERGENCY: %s Unable to write to STDERR.",
+				logsys_loggers[subsysid].subsys);
+			log_printf_to_logs(
+					   LOGSYS_ENCODE_RECID(
+						LOGSYS_LEVEL_EMERG,
+						subsysid,
+						LOGSYS_RECID_LOG),
+					   __FILE__, __FUNCTION__, __LINE__,
+					   tmpbuffer);
+		}
+	}
+}
+
+static void record_print (const char *buf)
+{
+	const int *buf_uint32t = (const int *)buf;
+	unsigned int rec_size = buf_uint32t[0];
+	unsigned int rec_ident = buf_uint32t[1];
+	unsigned int file_line = buf_uint32t[2];
+	unsigned int i;
+	unsigned int words_processed;
+	unsigned int arg_size_idx;
+	const void *arguments[FDMAX_ARGS];
+	unsigned int arg_count;
+
+	arg_size_idx = 4;
+	words_processed = 4;
+	arg_count = 0;
+
+	for (i = 0; words_processed < rec_size; i++) {
+		arguments[arg_count++] = &buf_uint32t[arg_size_idx + 1];
+		arg_size_idx += buf_uint32t[arg_size_idx] + 1;
+		words_processed += buf_uint32t[arg_size_idx] + 1;
+	}
+
+	/*
+	 * (char *)arguments[0] -> subsystem
+	 * (char *)arguments[1] -> file_name
+	 * (char *)arguments[2] -> function_name
+	 * (char *)arguments[3] -> message
+	 */
+
+	log_printf_to_logs (
+		rec_ident,
+		(char *)arguments[1],
+		(char *)arguments[2],
+		file_line,
+		(char *)arguments[3]);
+}
+
+static int record_read (char *buf, int rec_idx, int *log_msg) {
+	unsigned int rec_size;
+	unsigned int rec_ident;
+	int firstcopy, secondcopy;
+
+	rec_size = flt_data[rec_idx];
+	rec_ident = flt_data[(rec_idx + 1) % flt_data_size];
+
+	/*
+	 * Not a log record
+	 */
+	if (LOGSYS_DECODE_RECID(rec_ident) != LOGSYS_RECID_LOG) {
+		*log_msg = 0;
+        	return ((rec_idx + rec_size) % flt_data_size);
+	}
+
+	/*
+	 * A log record
+	 */
+	*log_msg = 1;
+
+        firstcopy = rec_size;
+        secondcopy = 0;
+        if (firstcopy + rec_idx > flt_data_size) {
+                firstcopy = flt_data_size - rec_idx;
+                secondcopy -= firstcopy - rec_size;
+        }
+        memcpy (&buf[0], &flt_data[rec_idx], firstcopy << 2);
+        if (secondcopy) {
+                memcpy (&buf[(firstcopy << 2)], &flt_data[0], secondcopy << 2);
+        }
+        return ((rec_idx + rec_size) % flt_data_size);
+}
+
+static inline void wthread_signal (void)
+{
+	if (wthread_active == 0) {
+		return;
+	}
+	pthread_mutex_lock (&logsys_cond_mutex);
+	pthread_cond_signal (&logsys_cond);
+	pthread_mutex_unlock (&logsys_cond_mutex);
+}
+
+static inline void wthread_wait (void)
+{
+	pthread_mutex_lock (&logsys_cond_mutex);
+	pthread_cond_wait (&logsys_cond, &logsys_cond_mutex);
+	pthread_mutex_unlock (&logsys_cond_mutex);
+}
+
+static inline void wthread_wait_locked (void)
+{
+	pthread_cond_wait (&logsys_cond, &logsys_cond_mutex);
+	pthread_mutex_unlock (&logsys_cond_mutex);
+}
+
+static void *logsys_worker_thread (void *data) __attribute__((__noreturn__));
+static void *logsys_worker_thread (void *data)
+{
+	int log_msg;
+	char buf[COMBINE_BUFFER_SIZE];
+
+	memset (buf, 0, sizeof (buf));
+
+	/*
+	 * Signal wthread_create that the initialization process may continue
+	 */
+	wthread_signal ();
+	logsys_lock();
+	log_rec_idx = flt_data[FDTAIL_INDEX];
+	logsys_unlock();
+
+	for (;;) {
+		wthread_wait ();
+		/*
+		 * Read and copy the logging record index position
+		 * It may have been updated by records_reclaim if
+		 * messages were lost or or log_rec on the first new
+		 * logging record available
+		 */
+		/*
+		 * Process any pending log messages here
+		 */
+		for (;;) {
+			int yield_counter = 1;
+
+			logsys_lock();
+			if (log_requests_lost > 0) {
+				printf ("lost %d log requests\n", log_requests_lost);
+				log_requests_pending -= log_requests_lost;
+				log_requests_lost = 0;
+			}
+			if (log_requests_pending == 0) {
+				logsys_unlock();
+				break;
+			}
+			log_rec_idx = record_read (buf, log_rec_idx, &log_msg);
+			if (log_msg) {
+				log_requests_pending -= 1;
+			}
+			logsys_unlock();
+
+			/*
+			 * print the stored buffer
+			 */
+			if (log_msg) {
+				record_print (buf);
+				if (yield_counter++ > logsys_after_log_ops_yield) {
+					yield_counter = 0;
+					sched_yield ();
+				}
+			}
+		}
+
+		if (wthread_should_exit) {
+			pthread_exit (NULL);
+		}
+	}
+}
+
+static void wthread_create (void)
+{
+	int res;
+
+	if (wthread_active) {
+		return;
+	}
+
+	wthread_active = 1;
+
+	pthread_mutex_init (&logsys_cond_mutex, NULL);
+	pthread_cond_init (&logsys_cond, NULL);
+	pthread_mutex_lock (&logsys_cond_mutex);
+
+	/*
+	 * TODO: propagate pthread_create errors back to the caller
+	 */
+	res = pthread_create (&logsys_thread_id, NULL,
+		logsys_worker_thread, NULL);
+
+	if (res == 0) {
+		/*
+		 * Wait for thread to be started
+		 */
+		wthread_wait_locked ();
+		if (logsys_sched_param_queued == 1) {
+			/*
+			 * TODO: propagate logsys_thread_priority_set errors back to
+			 * the caller
+			 */
+			res = logsys_thread_priority_set (logsys_sched_policy,
+						    &logsys_sched_param,
+						    logsys_after_log_ops_yield);
+			logsys_sched_param_queued = 0;
+		}
+	} else {
+		wthread_active = 0;
+	}
+}
+
+static int _logsys_config_subsys_get_unlocked (const char *subsys)
+{
+	unsigned int i;
+
+	if (!subsys) {
+		return LOGSYS_MAX_SUBSYS_COUNT;
+	}
+
+ 	for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
+		if (strcmp (logsys_loggers[i].subsys, subsys) == 0) {
+			return i;
+		}
+	}
+
+	return (-1);
+}
+
+static void syslog_facility_reconf (void)
+{
+	closelog();
+	openlog(logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT].subsys,
+		LOG_CONS|LOG_PID,
+		logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT].syslog_facility);
+}
+
+/*
+ * this is always invoked within the mutex, so it's safe to parse the
+ * whole thing as we need.
+ */
+static void logsys_close_logfile (
+	int subsysid)
+{
+	int i;
+
+	if ((logsys_loggers[subsysid].logfile_fp == NULL) &&
+	    (logsys_loggers[subsysid].logfile == NULL)) {
+		return;
+	}
+
+	/*
+	 * if there is another subsystem or system using the same fp,
+	 * then we clean our own structs, but we can't close the file
+	 * as it is in use by somebody else.
+	 * Only the last users will be allowed to perform the fclose.
+	 */
+ 	for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
+		if ((logsys_loggers[i].logfile_fp == logsys_loggers[subsysid].logfile_fp) &&
+		    (i != subsysid)) {
+			logsys_loggers[subsysid].logfile = NULL;
+			logsys_loggers[subsysid].logfile_fp = NULL;
+			return;
+		}
+	}
+
+	/*
+	 * if we are here, we are the last users of that fp, so we can safely
+	 * close it.
+	 */
+	fclose (logsys_loggers[subsysid].logfile_fp);
+	logsys_loggers[subsysid].logfile_fp = NULL;
+	free (logsys_loggers[subsysid].logfile);
+	logsys_loggers[subsysid].logfile = NULL;
+}
+
+/*
+ * we need a version that can work when somebody else is already
+ * holding a config mutex lock or we will never get out of here
+ */
+static int logsys_config_file_set_unlocked (
+		int subsysid,
+		const char **error_string,
+		const char *file)
+{
+	static char error_string_response[512];
+	int i;
+
+	logsys_close_logfile(subsysid);
+
+	if ((file == NULL) ||
+	    (strcmp(logsys_loggers[subsysid].subsys, "") == 0)) {
+		return (0);
+	}
+
+	if (strlen(file) >= PATH_MAX) {
+		snprintf (error_string_response,
+			sizeof(error_string_response),
+			"%s: logfile name exceed maximum system filename lenght\n",
+			logsys_loggers[subsysid].subsys);
+		*error_string = error_string_response;
+		return (-1);
+	}
+
+	for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
+		if ((logsys_loggers[i].logfile != NULL) &&
+			(strcmp (logsys_loggers[i].logfile, file) == 0) &&
+			(i != subsysid)) {
+				logsys_loggers[subsysid].logfile =
+					logsys_loggers[i].logfile;
+				logsys_loggers[subsysid].logfile_fp =
+					logsys_loggers[i].logfile_fp;
+				return (0);
+		}
+	}
+
+	logsys_loggers[subsysid].logfile = strdup(file);
+	if (logsys_loggers[subsysid].logfile == NULL) {
+		snprintf (error_string_response,
+			sizeof(error_string_response),
+			"Unable to allocate memory for logfile '%s'\n",
+			file);
+		*error_string = error_string_response;
+		return (-1);
+	}
+
+	logsys_loggers[subsysid].logfile_fp = fopen (file, "a+");
+	if (logsys_loggers[subsysid].logfile_fp == NULL) {
+		char error_str[100];
+		strerror_r (errno, error_str, 100);
+		free(logsys_loggers[subsysid].logfile);
+		logsys_loggers[subsysid].logfile = NULL;
+		snprintf (error_string_response,
+			sizeof(error_string_response),
+			"Can't open logfile '%s' for reason (%s).\n",
+				 file, error_str);
+		*error_string = error_string_response;
+		return (-1);
+	}
+
+	return (0);
+}
+
+static void logsys_subsys_init (
+		const char *subsys,
+		int subsysid)
+{
+	if (logsys_system_needs_init == LOGSYS_LOGGER_NEEDS_INIT) {
+		logsys_loggers[subsysid].init_status =
+			LOGSYS_LOGGER_NEEDS_INIT;
+	} else {
+		memcpy(&logsys_loggers[subsysid],
+		       &logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT],
+		       sizeof(logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT]));
+		logsys_loggers[subsysid].init_status =
+			LOGSYS_LOGGER_INIT_DONE;
+	}
+	strncpy (logsys_loggers[subsysid].subsys, subsys,
+		LOGSYS_MAX_SUBSYS_NAMELEN);
+}
+
+/*
+ * Internal API - exported
+ */
+
+int _logsys_system_setup(
+	const char *mainsystem,
+	unsigned int mode,
+	unsigned int debug,
+	const char *logfile,
+	int logfile_priority,
+	int syslog_facility,
+	int syslog_priority)
+{
+	int i;
+	const char *errstr;
+	char tempsubsys[LOGSYS_MAX_SUBSYS_NAMELEN];
+
+	if ((mainsystem == NULL) ||
+	    (strlen(mainsystem) >= LOGSYS_MAX_SUBSYS_NAMELEN)) {
+		return -1;
+	}
+
+	i = LOGSYS_MAX_SUBSYS_COUNT;
+
+	pthread_mutex_lock (&logsys_config_mutex);
+
+	snprintf(logsys_loggers[i].subsys,
+		 LOGSYS_MAX_SUBSYS_NAMELEN,
+		"%s", mainsystem);
+
+	logsys_loggers[i].mode = mode;
+
+	logsys_loggers[i].debug = debug;
+
+	if (logsys_config_file_set_unlocked (i, &errstr, logfile) < 0) {
+		pthread_mutex_unlock (&logsys_config_mutex);
+		return (-1);
+	}
+	logsys_loggers[i].logfile_priority = logfile_priority;
+
+	logsys_loggers[i].syslog_facility = syslog_facility;
+	logsys_loggers[i].syslog_priority = syslog_priority;
+	syslog_facility_reconf();
+
+	logsys_loggers[i].init_status = LOGSYS_LOGGER_INIT_DONE;
+
+	logsys_system_needs_init = LOGSYS_LOGGER_INIT_DONE;
+
+	for (i = 0; i < LOGSYS_MAX_SUBSYS_COUNT; i++) {
+		if ((strcmp (logsys_loggers[i].subsys, "") != 0) &&
+			(logsys_loggers[i].init_status ==
+			 LOGSYS_LOGGER_NEEDS_INIT)) {
+				strncpy (tempsubsys, logsys_loggers[i].subsys,
+					LOGSYS_MAX_SUBSYS_NAMELEN);
+				logsys_subsys_init(tempsubsys, i);
+		}
+	}
+
+	pthread_mutex_unlock (&logsys_config_mutex);
+
+	return (0);
+}
+
+unsigned int _logsys_subsys_create (const char *subsys)
+{
+	int i;
+
+	if ((subsys == NULL) ||
+	    (strlen(subsys) >= LOGSYS_MAX_SUBSYS_NAMELEN)) {
+		return -1;
+	}
+
+	pthread_mutex_lock (&logsys_config_mutex);
+
+	i = _logsys_config_subsys_get_unlocked (subsys);
+	if ((i > -1) && (i < LOGSYS_MAX_SUBSYS_COUNT)) {
+		pthread_mutex_unlock (&logsys_config_mutex);
+		return i;
+	}
+
+	for (i = 0; i < LOGSYS_MAX_SUBSYS_COUNT; i++) {
+		if (strcmp (logsys_loggers[i].subsys, "") == 0) {
+			logsys_subsys_init(subsys, i);
+			break;
+		}
+	}
+
+	if (i >= LOGSYS_MAX_SUBSYS_COUNT) {
+		i = -1;
+	}
+
+	pthread_mutex_unlock (&logsys_config_mutex);
+	return i;
+}
+
+int _logsys_wthread_create (void)
+{
+	if (((logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT].mode & LOGSYS_MODE_FORK) == 0) &&
+		((logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT].mode & LOGSYS_MODE_THREADED) != 0)) {
+		wthread_create();
+	}
+	return (0);
+}
+
+int _logsys_rec_init (unsigned int fltsize)
+{
+	/*
+	 * we need to allocate:
+	 * - requested size +
+	 *   2 extra unsigned ints for HEAD/TAIL tracking
+	 *
+	 * then round it up to the next PAGESIZE
+	 */
+	size_t flt_real_size;
+
+	/*
+	 * XXX: kill me for 1.1 because I am a dirty hack
+	 * temporary workaround that will be replaced by supporting
+	 * 0 byte size flight recorder buffer.
+	 * 0 byte size buffer will enable direct printing to logs
+	 *   without flight recoder.
+	 */
+	if (fltsize < 64000) {
+		fltsize = 64000;
+	}
+
+	flt_real_size = ROUNDUP(
+			(fltsize + (2 * sizeof (unsigned int))),
+			sysconf(_SC_PAGESIZE));
+
+	flt_data = malloc (flt_real_size);
+	if (flt_data == NULL) {
+		return (-1);
+	}
+
+	memset (flt_data, 0, flt_real_size);
+	/*
+	 * flt_data_size tracks data by ints and not bytes/chars.
+	 *
+	 * the last 2 ints are reserved to store HEAD/TAIL information.
+	 * hide them from the rotating buffer.
+	 */
+
+	flt_data_size = ((flt_real_size / sizeof (unsigned int)) - 2);
+
+	/*
+	 * First record starts at zero
+	 * Last record ends at zero
+	 */
+	flt_data[FDHEAD_INDEX] = 0;
+	flt_data[FDTAIL_INDEX] = 0;
+
+#if defined(HAVE_PTHREAD_SPIN_LOCK)
+	pthread_spin_init (&logsys_idx_spinlock, 0);
+#endif
+
+	return (0);
+}
+
+
+/*
+ * u32 RECORD SIZE
+ * u32 record ident
+ * u32 arg count
+ * u32 file line
+ * u32 subsys length
+ * buffer null terminated subsys
+ * u32 filename length
+ * buffer null terminated filename
+ * u32 filename length
+ * buffer null terminated function
+ * u32 arg1 length
+ * buffer arg1
+ * ... repeats length & arg
+ */
+
+void _logsys_log_rec (
+	unsigned int rec_ident,
+	const char *function_name,
+	const char *file_name,
+	int file_line,
+	...)
+{
+	va_list ap;
+	const void *buf_args[FDMAX_ARGS];
+	unsigned int buf_len[FDMAX_ARGS];
+	unsigned int i;
+	unsigned int idx;
+	unsigned int arguments = 0;
+	unsigned int record_reclaim_size = 0;
+	unsigned int index_start;
+	int words_written;
+	int subsysid;
+
+	subsysid = LOGSYS_DECODE_SUBSYSID(rec_ident);
+
+	/*
+	 * Decode VA Args
+	 */
+	va_start (ap, file_line);
+	arguments = 3;
+	for (;;) {
+		buf_args[arguments] = va_arg (ap, void *);
+		if (buf_args[arguments] == LOGSYS_REC_END) {
+			break;
+		}
+		buf_len[arguments] = va_arg (ap, int);
+		record_reclaim_size += ((buf_len[arguments] + 3) >> 2) + 1;
+		arguments++;
+		if (arguments >= FDMAX_ARGS) {
+			break;
+		}
+	}
+	va_end (ap);
+
+	/*
+	 * Encode logsys subsystem identity, filename, and function
+	 */
+	buf_args[0] = logsys_loggers[subsysid].subsys;
+	buf_len[0] = strlen (logsys_loggers[subsysid].subsys) + 1;
+	buf_args[1] = file_name;
+	buf_len[1] = strlen (file_name) + 1;
+	buf_args[2] = function_name;
+	buf_len[2] = strlen (function_name) + 1;
+	for (i = 0; i < 3; i++) {
+		record_reclaim_size += ((buf_len[i] + 3) >> 2) + 1;
+	}
+
+	idx = flt_data[FDHEAD_INDEX];
+	index_start = idx;
+
+	/*
+	 * Reclaim data needed for record including 4 words for the header
+	 */
+	records_reclaim (idx, record_reclaim_size + 4);
+
+	/*
+	 * Write record size of zero and rest of header information
+	 */
+	flt_data[idx++] = 0;
+	idx_word_step(idx);
+
+	flt_data[idx++] = rec_ident;
+	idx_word_step(idx);
+
+	flt_data[idx++] = file_line;
+	idx_word_step(idx);
+
+	flt_data[idx++] = records_written;
+	idx_word_step(idx);
+	/*
+	 * Encode all of the arguments into the log message
+	 */
+	for (i = 0; i < arguments; i++) {
+		unsigned int bytes;
+		unsigned int full_words;
+		unsigned int total_words;
+
+		bytes = buf_len[i];
+		full_words = bytes >> 2;
+		total_words = (bytes + 3) >> 2;
+
+		flt_data[idx++] = total_words;
+		idx_word_step(idx);
+
+		/*
+		 * determine if this is a wrapped write or normal write
+		 */
+		if (idx + total_words < flt_data_size) {
+			/*
+			 * dont need to wrap buffer
+			 */
+			my_memcpy_32bit (&flt_data[idx], buf_args[i], full_words);
+			if (bytes % 4) {
+				my_memcpy_8bit ((char *)&flt_data[idx + full_words],
+					((const char *)buf_args[i]) + (full_words << 2), bytes % 4);
+			}
+		} else {
+			/*
+			 * need to wrap buffer
+			 */
+			unsigned int first;
+			unsigned int second;
+
+			first = flt_data_size - idx;
+			if (first > full_words) {
+				first = full_words;
+			}
+			second = full_words - first;
+			my_memcpy_32bit (&flt_data[idx],
+					 (const int *)buf_args[i], first);
+			my_memcpy_32bit (&flt_data[0],
+				(const int *)(((const unsigned char *)buf_args[i]) + (first << 2)),
+				second);
+			if (bytes % 4) {
+				my_memcpy_8bit ((char *)&flt_data[0 + second],
+					((const char *)buf_args[i]) + (full_words << 2), bytes % 4);
+			}
+		}
+		idx += total_words;
+		idx_buffer_step (idx);
+	}
+	words_written = idx - index_start;
+	if (words_written < 0) {
+		words_written += flt_data_size;
+	}
+
+	/*
+	 * Commit the write of the record size now that the full record
+	 * is in the memory buffer
+	 */
+	flt_data[index_start] = words_written;
+
+	/*
+	 * If the index of the current head equals the current log_rec_idx,
+	 * and this is not a log_printf operation, set the log_rec_idx to
+	 * the new head position and commit the new head.
+	 */
+	logsys_lock();
+	if (LOGSYS_DECODE_RECID(rec_ident) == LOGSYS_RECID_LOG) {
+		log_requests_pending += 1;
+	}
+	if (log_requests_pending == 0) {
+		log_rec_idx = idx;
+	}
+	flt_data[FDHEAD_INDEX] = idx;
+	logsys_unlock();
+	records_written++;
+}
+
+void _logsys_log_vprintf (
+	unsigned int rec_ident,
+	const char *function_name,
+	const char *file_name,
+	int file_line,
+	const char *format,
+	va_list ap)
+{
+	char logsys_print_buffer[COMBINE_BUFFER_SIZE];
+	unsigned int len;
+	unsigned int level;
+	int subsysid;
+	const char *short_file_name;
+
+	subsysid = LOGSYS_DECODE_SUBSYSID(rec_ident);
+	level = LOGSYS_DECODE_LEVEL(rec_ident);
+
+	if ((level > logsys_loggers[subsysid].syslog_priority) &&
+	    (level > logsys_loggers[subsysid].logfile_priority) &&
+	    (logsys_loggers[subsysid].debug == 0)) {
+		return;
+	}
+
+	len = vsprintf (logsys_print_buffer, format, ap);
+	if (logsys_print_buffer[len - 1] == '\n') {
+		logsys_print_buffer[len - 1] = '\0';
+		len -= 1;
+	}
+#ifdef BUILDING_IN_PLACE
+	short_file_name = file_name;
+#else
+	short_file_name = strrchr (file_name, '/');
+	if (short_file_name == NULL)
+		short_file_name = file_name;
+	else
+		short_file_name++; /* move past the "/" */
+#endif /* BUILDING_IN_PLACE */
+
+	/*
+	 * Create a log record
+	 */
+	_logsys_log_rec (
+		rec_ident,
+		function_name,
+		short_file_name,
+		file_line,
+		logsys_print_buffer, len + 1,
+		LOGSYS_REC_END);
+
+	if ((logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT].mode & LOGSYS_MODE_THREADED) == 0) {
+		/*
+		 * Output (and block) if the log mode is not threaded otherwise
+		 * expect the worker thread to output the log data once signaled
+		 */
+		log_printf_to_logs (rec_ident,
+				    short_file_name, function_name, file_line,
+				    logsys_print_buffer);
+	} else {
+		/*
+		 * Signal worker thread to display logging output
+		 */
+		wthread_signal ();
+	}
+}
+
+void _logsys_log_printf (
+	unsigned int rec_ident,
+	const char *function_name,
+	const char *file_name,
+	int file_line,
+	const char *format,
+	...)
+{
+	va_list ap;
+
+	va_start (ap, format);
+	_logsys_log_vprintf (rec_ident, function_name, file_name, file_line,
+		format, ap);
+	va_end (ap);
+}
+
+int _logsys_config_subsys_get (const char *subsys)
+{
+	unsigned int i;
+
+	pthread_mutex_lock (&logsys_config_mutex);
+
+	i = _logsys_config_subsys_get_unlocked (subsys);
+
+	pthread_mutex_unlock (&logsys_config_mutex);
+
+	return i;
+}
+
+/*
+ * External Configuration and Initialization API
+ */
+void logsys_fork_completed (void)
+{
+	logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT].mode &= ~LOGSYS_MODE_FORK;
+	_logsys_wthread_create ();
+}
+
+unsigned int logsys_config_mode_set (const char *subsys, unsigned int mode)
+{
+	int i;
+
+	pthread_mutex_lock (&logsys_config_mutex);
+	if (subsys != NULL) {
+		i = _logsys_config_subsys_get_unlocked (subsys);
+		if (i >= 0) {
+			logsys_loggers[i].mode = mode;
+			i = 0;
+		}
+	} else {
+		for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
+			logsys_loggers[i].mode = mode;
+		}
+		i = 0;
+	}
+	pthread_mutex_unlock (&logsys_config_mutex);
+
+	return i;
+}
+
+unsigned int logsys_config_mode_get (const char *subsys)
+{
+	int i;
+
+	i = _logsys_config_subsys_get (subsys);
+	if (i < 0) {
+		return i;
+	}
+
+	return logsys_loggers[i].mode;
+}
+
+int logsys_config_file_set (
+		const char *subsys,
+		const char **error_string,
+		const char *file)
+{
+	int i;
+	int res;
+
+	pthread_mutex_lock (&logsys_config_mutex);
+
+	if (subsys != NULL) {
+		i = _logsys_config_subsys_get_unlocked (subsys);
+		if (i < 0) {
+			res = i;
+		} else {
+			res = logsys_config_file_set_unlocked(i, error_string, file);
+		}
+	} else {
+		for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
+			res = logsys_config_file_set_unlocked(i, error_string, file);
+			if (res < 0) {
+				break;
+			}
+		}
+	}
+
+	pthread_mutex_unlock (&logsys_config_mutex);
+	return res;
+}
+
+int logsys_format_set (const char *format)
+{
+	int ret = 0;
+
+	pthread_mutex_lock (&logsys_config_mutex);
+
+	if (format_buffer) {
+		free(format_buffer);
+		format_buffer = NULL;
+	}
+
+	format_buffer = strdup(format ? format : "%p [%6s] %b");
+	if (format_buffer == NULL) {
+		ret = -1;
+	}
+
+	pthread_mutex_unlock (&logsys_config_mutex);
+	return ret;
+}
+
+char *logsys_format_get (void)
+{
+	return format_buffer;
+}
+
+unsigned int logsys_config_syslog_facility_set (
+	const char *subsys,
+	unsigned int facility)
+{
+	int i;
+
+	pthread_mutex_lock (&logsys_config_mutex);
+	if (subsys != NULL) {
+		i = _logsys_config_subsys_get_unlocked (subsys);
+		if (i >= 0) {
+			logsys_loggers[i].syslog_facility = facility;
+			if (i == LOGSYS_MAX_SUBSYS_COUNT) {
+				syslog_facility_reconf();
+			}
+			i = 0;
+		}
+	} else {
+		for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
+			logsys_loggers[i].syslog_facility = facility;
+		}
+		syslog_facility_reconf();
+		i = 0;
+	}
+	pthread_mutex_unlock (&logsys_config_mutex);
+
+	return i;
+}
+
+unsigned int logsys_config_syslog_priority_set (
+	const char *subsys,
+	unsigned int priority)
+{
+	int i;
+
+	pthread_mutex_lock (&logsys_config_mutex);
+	if (subsys != NULL) {
+		i = _logsys_config_subsys_get_unlocked (subsys);
+		if (i >= 0) {
+			logsys_loggers[i].syslog_priority = priority;
+			i = 0;
+		}
+	} else {
+		for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
+			logsys_loggers[i].syslog_priority = priority;
+		}
+		i = 0;
+	}
+	pthread_mutex_unlock (&logsys_config_mutex);
+
+	return i;
+}
+
+unsigned int logsys_config_logfile_priority_set (
+	const char *subsys,
+	unsigned int priority)
+{
+	int i;
+
+	pthread_mutex_lock (&logsys_config_mutex);
+	if (subsys != NULL) {
+		i = _logsys_config_subsys_get_unlocked (subsys);
+		if (i >= 0) {
+			logsys_loggers[i].logfile_priority = priority;
+			i = 0;
+		}
+	} else {
+		for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
+			logsys_loggers[i].logfile_priority = priority;
+		}
+		i = 0;
+	}
+	pthread_mutex_unlock (&logsys_config_mutex);
+
+	return i;
+}
+
+unsigned int logsys_config_debug_set (
+	const char *subsys,
+	unsigned int debug)
+{
+	int i;
+
+	pthread_mutex_lock (&logsys_config_mutex);
+	if (subsys != NULL) {
+		i = _logsys_config_subsys_get_unlocked (subsys);
+		if (i >= 0) {
+			logsys_loggers[i].debug = debug;
+			i = 0;
+		}
+	} else {
+		for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
+			logsys_loggers[i].debug = debug;
+		}
+		i = 0;
+	}
+	pthread_mutex_unlock (&logsys_config_mutex);
+
+	return i;
+}
+
+int logsys_facility_id_get (const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; facilitynames[i].c_name != NULL; i++) {
+		if (strcasecmp(name, facilitynames[i].c_name) == 0) {
+			return (facilitynames[i].c_val);
+		}
+	}
+	return (-1);
+}
+
+const char *logsys_facility_name_get (unsigned int facility)
+{
+	unsigned int i;
+
+	for (i = 0; facilitynames[i].c_name != NULL; i++) {
+		if (facility == facilitynames[i].c_val) {
+			return (facilitynames[i].c_name);
+		}
+	}
+	return (NULL);
+}
+
+int logsys_priority_id_get (const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; prioritynames[i].c_name != NULL; i++) {
+		if (strcasecmp(name, prioritynames[i].c_name) == 0) {
+			return (prioritynames[i].c_val);
+		}
+	}
+	return (-1);
+}
+
+const char *logsys_priority_name_get (unsigned int priority)
+{
+	unsigned int i;
+
+	for (i = 0; prioritynames[i].c_name != NULL; i++) {
+		if (priority == prioritynames[i].c_val) {
+			return (prioritynames[i].c_name);
+		}
+	}
+	return (NULL);
+}
+
+int logsys_thread_priority_set (
+	int policy,
+	const struct sched_param *param,
+        unsigned int after_log_ops_yield)
+
+{
+	int res = 0;
+
+#if defined(HAVE_PTHREAD_SETSCHEDPARAM) && defined(HAVE_SCHED_GET_PRIORITY_MAX)
+	if (wthread_active == 0) {
+		logsys_sched_policy = policy;
+		memcpy(&logsys_sched_param, &param, sizeof(struct sched_param));
+		logsys_sched_param_queued = 1;
+	} else {
+		res = pthread_setschedparam (logsys_thread_id, policy, param);
+	}
+#endif
+
+	if (after_log_ops_yield > 0) {
+		logsys_after_log_ops_yield = after_log_ops_yield;
+	}
+
+	return (res);
+}
+
+int logsys_log_rec_store (const char *filename)
+{
+	int fd;
+	ssize_t written_size;
+	size_t size_to_write = (flt_data_size + 2) * sizeof (unsigned int);
+
+	fd = open (filename, O_CREAT|O_RDWR, 0700);
+	if (fd < 0) {
+		return (-1);
+	}
+
+	written_size = write (fd, &flt_data_size, sizeof(unsigned int));
+	if ((written_size < 0) || (written_size != sizeof(unsigned int))) {
+		close (fd);
+		return (-1);
+	}
+
+	written_size = write (fd, flt_data, size_to_write);
+	if (close (fd) != 0)
+		return (-1);
+	if (written_size < 0) {
+		return (-1);
+	} else if ((size_t)written_size != size_to_write) {
+		return (-1);
+	}
+
+	return (0);
+}
+
+void logsys_atexit (void)
+{
+	if (wthread_active) {
+		wthread_should_exit = 1;
+		wthread_signal ();
+		pthread_join (logsys_thread_id, NULL);
+	}
+}
+
+void logsys_flush (void)
+{
+	wthread_signal ();
+}
diff --git a/src/logsys.h b/src/logsys.h
new file mode 100644
index 0000000..19e5dae
--- /dev/null
+++ b/src/logsys.h
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2002-2004 MontaVista Software, Inc.
+ * Copyright (c) 2006-2009 Red Hat, Inc.
+ *
+ * Author: Steven Dake (sdake@redhat.com)
+ * Author: Lon Hohberger (lhh@redhat.com)
+ * Author: Fabio M. Di Nitto (fdinitto@redhat.com)
+ *
+ * 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.
+ */
+#ifndef LOGSYS_H_DEFINED
+#define LOGSYS_H_DEFINED
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <pthread.h>
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * All of the LOGSYS_MODE's can be ORed together for combined behavior
+ *
+ * FORK and THREADED are ignored for SUBSYSTEMS
+ */
+#define LOGSYS_MODE_OUTPUT_FILE		(1<<0)
+#define LOGSYS_MODE_OUTPUT_STDERR	(1<<1)
+#define LOGSYS_MODE_OUTPUT_SYSLOG	(1<<2)
+#define LOGSYS_MODE_FORK		(1<<3)
+#define LOGSYS_MODE_THREADED		(1<<4)
+
+/*
+ * Log priorities, compliant with syslog and SA Forum Log spec.
+ */
+#define LOGSYS_LEVEL_EMERG		LOG_EMERG
+#define LOGSYS_LEVEL_ALERT		LOG_ALERT
+#define LOGSYS_LEVEL_CRIT		LOG_CRIT
+#define LOGSYS_LEVEL_ERROR		LOG_ERR
+#define LOGSYS_LEVEL_WARNING		LOG_WARNING
+#define LOGSYS_LEVEL_NOTICE		LOG_NOTICE
+#define LOGSYS_LEVEL_INFO		LOG_INFO
+#define LOGSYS_LEVEL_DEBUG		LOG_DEBUG
+
+/*
+ * All of the LOGSYS_RECID's are mutually exclusive. Only one RECID at any time
+ * can be specified.
+ *
+ * RECID_LOG indicates a message that should be sent to log. Anything else
+ * is stored only in the flight recorder.
+ */
+
+#define LOGSYS_RECID_MAX		((UINT_MAX) >> LOGSYS_SUBSYSID_END)
+
+#define LOGSYS_RECID_LOG		(LOGSYS_RECID_MAX - 1)
+#define LOGSYS_RECID_ENTER		(LOGSYS_RECID_MAX - 2)
+#define LOGSYS_RECID_LEAVE		(LOGSYS_RECID_MAX - 3)
+#define LOGSYS_RECID_TRACE1		(LOGSYS_RECID_MAX - 4)
+#define LOGSYS_RECID_TRACE2		(LOGSYS_RECID_MAX - 5)
+#define LOGSYS_RECID_TRACE3		(LOGSYS_RECID_MAX - 6)
+#define LOGSYS_RECID_TRACE4		(LOGSYS_RECID_MAX - 7)
+#define LOGSYS_RECID_TRACE5		(LOGSYS_RECID_MAX - 8)
+#define LOGSYS_RECID_TRACE6		(LOGSYS_RECID_MAX - 9)
+#define LOGSYS_RECID_TRACE7		(LOGSYS_RECID_MAX - 10)
+#define LOGSYS_RECID_TRACE8		(LOGSYS_RECID_MAX - 11)
+
+
+/*
+ * Internal APIs that must be globally exported
+ * (External API below)
+ */
+
+/*
+ * logsys_logger bits
+ *
+ * SUBSYS_COUNT defines the maximum number of subsystems
+ * SUBSYS_NAMELEN defines the maximum len of a subsystem name
+ */
+#define LOGSYS_MAX_SUBSYS_COUNT		64
+#define LOGSYS_MAX_SUBSYS_NAMELEN	64
+
+/*
+ * rec_ident explained:
+ *
+ * rec_ident is an unsigned int and carries bitfields information
+ * on subsys_id, log priority (level) and type of message (RECID).
+ *
+ * level values are imported from syslog.h.
+ * At the time of writing it's a 3 bits value (0 to 7).
+ *
+ * subsys_id is any value between 0 and 64 (LOGSYS_MAX_SUBSYS_COUNT)
+ *
+ * RECID identifies the type of message. A set of predefined values
+ * are available via logsys, but other custom values can be defined
+ * by users.
+ *
+ * ----
+ * bitfields:
+ *
+ * 0  - 2 level
+ * 3  - 9 subsysid
+ * 10 - n RECID
+ */
+
+#define LOGSYS_LEVEL_END		(3)
+#define LOGSYS_SUBSYSID_END		(LOGSYS_LEVEL_END + 7)
+
+#define LOGSYS_RECID_LEVEL_MASK		(LOG_PRIMASK)
+#define LOGSYS_RECID_SUBSYSID_MASK	((2 << (LOGSYS_SUBSYSID_END - 1)) - \
+					(LOG_PRIMASK + 1))
+#define LOGSYS_RECID_RECID_MASK		(UINT_MAX - \
+					(LOGSYS_RECID_SUBSYSID_MASK + LOG_PRIMASK))
+
+#define LOGSYS_ENCODE_RECID(level,subsysid,recid) \
+	(((recid) << LOGSYS_SUBSYSID_END) | \
+	((subsysid) << LOGSYS_LEVEL_END) | \
+	(level))
+
+#define LOGSYS_DECODE_LEVEL(rec_ident) \
+	((rec_ident) & LOGSYS_RECID_LEVEL_MASK)
+
+#define LOGSYS_DECODE_SUBSYSID(rec_ident) \
+	(((rec_ident) & LOGSYS_RECID_SUBSYSID_MASK) >> LOGSYS_LEVEL_END)
+
+#define LOGSYS_DECODE_RECID(rec_ident) \
+	(((rec_ident) & LOGSYS_RECID_RECID_MASK) >> LOGSYS_SUBSYSID_END)
+
+#ifndef LOGSYS_UTILS_ONLY
+
+extern int _logsys_system_setup(
+	const char *mainsystem,
+	unsigned int mode,
+	unsigned int debug,
+	const char *logfile,
+	int logfile_priority,
+	int syslog_facility,
+	int syslog_priority);
+
+extern int _logsys_config_subsys_get (
+	const char *subsys);
+
+extern unsigned int _logsys_subsys_create (const char *subsys);
+
+extern int _logsys_rec_init (unsigned int size);
+
+extern void _logsys_log_vprintf (
+	unsigned int rec_ident,
+	const char *function_name,
+	const char *file_name,
+	int file_line,
+	const char *format,
+	va_list ap) __attribute__((format(printf, 5, 0)));
+
+extern void _logsys_log_printf (
+	unsigned int rec_ident,
+	const char *function_name,
+	const char *file_name,
+	int file_line,
+	const char *format,
+	...) __attribute__((format(printf, 5, 6)));
+
+extern void _logsys_log_rec (
+	unsigned int rec_ident,
+	const char *function_name,
+	const char *file_name,
+	int file_line,
+	...);
+
+extern int _logsys_wthread_create (void);
+
+static int logsys_subsys_id __attribute__((unused)) = LOGSYS_MAX_SUBSYS_COUNT;
+
+/*
+ * External API - init
+ * See below:
+ *
+ * LOGSYS_DECLARE_SYSTEM
+ * LOGSYS_DECLARE_SUBSYS
+ *
+ */
+extern void logsys_fork_completed (void);
+
+extern void logsys_atexit (void);
+
+/*
+ * External API - misc
+ */
+extern void logsys_flush (void);
+
+extern int logsys_log_rec_store (const char *filename);
+
+/*
+ * External API - configuration
+ */
+
+/*
+ * configuration bits that can only be done for the whole system
+ */
+extern int logsys_format_set (
+	const char *format);
+
+extern char *logsys_format_get (void);
+
+/*
+ * per system/subsystem settings.
+ *
+ * NOTE: once a subsystem is created and configured, changing
+ * the default does NOT affect the subsystems.
+ *
+ * Pass a NULL subsystem to change them all
+ */
+extern unsigned int logsys_config_syslog_facility_set (
+	const char *subsys,
+	unsigned int facility);
+
+extern unsigned int logsys_config_syslog_priority_set (
+	const char *subsys,
+	unsigned int priority);
+
+extern unsigned int logsys_config_mode_set (
+	const char *subsys,
+	unsigned int mode);
+
+extern unsigned int logsys_config_mode_get (
+	const char *subsys);
+
+/*
+ * to close a logfile, just invoke this function with a NULL
+ * file or if you want to change logfile, the old one will
+ * be closed for you.
+ */
+extern int logsys_config_file_set (
+	const char *subsys,
+	const char **error_string,
+	const char *file);
+
+extern unsigned int logsys_config_logfile_priority_set (
+	const char *subsys,
+	unsigned int priority);
+
+/*
+ * enabling debug, disable message priority filtering.
+ * everything is sent everywhere. priority values
+ * for file and syslog are not overwritten.
+ */
+extern unsigned int logsys_config_debug_set (
+	const char *subsys,
+	unsigned int value);
+
+/*
+ * External API - helpers
+ *
+ * convert facility/priority to/from name/values
+ */
+extern int logsys_facility_id_get (
+	const char *name);
+
+extern const char *logsys_facility_name_get (
+	unsigned int facility);
+
+extern int logsys_priority_id_get (
+	const char *name);
+
+extern const char *logsys_priority_name_get (
+	unsigned int priority);
+
+extern int logsys_thread_priority_set (
+	int policy,
+	const struct sched_param *param,
+	unsigned int after_log_ops_yield);
+
+/*
+ * External definitions
+ */
+extern void *logsys_rec_end;
+
+#define LOGSYS_REC_END (&logsys_rec_end)
+
+#define LOGSYS_DECLARE_SYSTEM(name,mode,debug,file,file_priority,	\
+		syslog_facility,syslog_priority,format,fltsize)		\
+__attribute__ ((constructor))						\
+static void logsys_system_init (void)					\
+{									\
+	if (_logsys_system_setup (name,mode,debug,file,file_priority,	\
+			syslog_facility,syslog_priority) < 0) {		\
+		fprintf (stderr,					\
+			"Unable to setup logging system: %s.\n", name);	\
+		exit (-1);						\
+	}								\
+									\
+	if (logsys_format_set (format) < 0) {				\
+		fprintf (stderr,					\
+			"Unable to setup logging format.\n");		\
+		exit (-1);						\
+	}								\
+									\
+	if (_logsys_rec_init (fltsize) < 0) {				\
+		fprintf (stderr,					\
+			"Unable to initialize log flight recorder.\n");	\
+		exit (-1);						\
+	}								\
+									\
+	if (_logsys_wthread_create() < 0) {				\
+		fprintf (stderr,					\
+			"Unable to initialize logging thread.\n");	\
+		exit (-1);						\
+	}								\
+}
+
+#define LOGSYS_DECLARE_SUBSYS(subsys)					\
+__attribute__ ((constructor))						\
+static void logsys_subsys_init (void)					\
+{									\
+	logsys_subsys_id =						\
+		_logsys_subsys_create ((subsys));			\
+	if (logsys_subsys_id == -1) {					\
+		fprintf (stderr,					\
+		"Unable to create logging subsystem: %s.\n", subsys);	\
+		exit (-1);						\
+	}								\
+}
+
+#define log_rec(rec_ident, args...)					\
+do {									\
+	_logsys_log_rec (rec_ident,  __FUNCTION__,			\
+		__FILE__,  __LINE__, ##args,				\
+		LOGSYS_REC_END);					\
+} while(0)
+
+#define log_printf(level, format, args...)				\
+ do {									\
+	_logsys_log_printf (						\
+		LOGSYS_ENCODE_RECID(level,				\
+				    logsys_subsys_id,			\
+				    LOGSYS_RECID_LOG),			\
+		 __FUNCTION__, __FILE__, __LINE__,			\
+		format, ##args);					\
+} while(0)
+
+#define ENTER() do {							\
+	_logsys_log_rec (						\
+		LOGSYS_ENCODE_RECID(LOGSYS_LEVEL_DEBUG,			\
+				    logsys_subsys_id,			\
+				    LOGSYS_RECID_ENTER),		\
+		__FUNCTION__, __FILE__,  __LINE__, LOGSYS_REC_END);	\
+} while(0)
+
+#define LEAVE() do {							\
+	_logsys_log_rec (						\
+		LOGSYS_ENCODE_RECID(LOGSYS_LEVEL_DEBUG,			\
+				    logsys_subsys_id,			\
+				    LOGSYS_RECID_LEAVE),		\
+		__FUNCTION__, __FILE__,  __LINE__, LOGSYS_REC_END);	\
+} while(0)
+
+#define TRACE(recid, format, args...) do {				\
+	_logsys_log_printf (						\
+		LOGSYS_ENCODE_RECID(LOGSYS_LEVEL_DEBUG,			\
+				    logsys_subsys_id,			\
+				    recid),				\
+		 __FUNCTION__, __FILE__, __LINE__,			\
+		format, ##args);					\
+} while(0)
+
+#define TRACE1(format, args...) do {					\
+	TRACE(LOGSYS_RECID_TRACE1, format, ##args);			\
+} while(0)
+
+#define TRACE2(format, args...) do {					\
+	TRACE(LOGSYS_RECID_TRACE2, format, ##args);			\
+} while(0)
+
+#define TRACE3(format, args...) do {					\
+	TRACE(LOGSYS_RECID_TRACE3, format, ##args);			\
+} while(0)
+
+#define TRACE4(format, args...) do {					\
+	TRACE(LOGSYS_RECID_TRACE4, format, ##args);			\
+} while(0)
+
+#define TRACE5(format, args...) do {					\
+	TRACE(LOGSYS_RECID_TRACE5, format, ##args);			\
+} while(0)
+
+#define TRACE6(format, args...) do {					\
+	TRACE(LOGSYS_RECID_TRACE6, format, ##args);			\
+} while(0)
+
+#define TRACE7(format, args...) do {					\
+	TRACE(LOGSYS_RECID_TRACE7, format, ##args);			\
+} while(0)
+
+#define TRACE8(format, args...) do {					\
+	TRACE(LOGSYS_RECID_TRACE8, format, ##args);			\
+} while(0)
+
+#endif /* LOGSYS_UTILS_ONLY */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LOGSYS_H_DEFINED */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..031ee66
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <config.h>
+
+#include <pthread.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <sys/uio.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.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 <semaphore.h>
+
+#include "logsys.h"
+#include "d1ht.h"
+#include "d1htip.h"
+#include "d1htpoll.h"
+#include "d1htedra.h"
+
+LOGSYS_DECLARE_SYSTEM ("vinzvault",
+	LOGSYS_MODE_OUTPUT_STDERR | LOGSYS_MODE_THREADED,
+	0,
+	NULL,
+	LOG_INFO,
+	LOG_DAEMON,
+	LOG_INFO,
+	NULL,
+	1000000);
+
+static hdb_handle_t vinzvault_poll_handle;
+
+int main (void)
+{
+	void *d1htedra_instance;
+
+	struct d1ht_config d1ht_config;
+
+	d1htip_parse (&d1ht_config.interface.bindnet, "10.16.32.0", AF_INET);
+
+	d1htip_parse (&d1ht_config.search_addr[0], "10.16.32.109", AF_INET);
+
+	d1htip_parse (&d1ht_config.search_addr[1], "10.16.32.110", AF_INET);
+
+	d1ht_config.interface.ip_port = 9123;
+
+	d1ht_config.theta_timeout = 1000;
+
+	d1ht_config.tdetect_timeout = 2000;
+
+	d1ht_config.lookup_timeout = 1000;
+
+	d1ht_config.crypto_type = D1HT_CRYPTO_TYPE_NONE;
+
+	d1ht_config.private_key_len = 0;
+
+	vinzvault_poll_handle = poll_create ();
+	d1htedra_initialize (vinzvault_poll_handle, &d1htedra_instance, &d1ht_config);
+
+	poll_run (vinzvault_poll_handle);
+
+	return (0);
+}
diff --git a/src/swab.h b/src/swab.h
new file mode 100644
index 0000000..7b17754
--- /dev/null
+++ b/src/swab.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <sys/types.h>
+
+#define swab16(x) \
+({ \
+	uint16_t __x = (x); \
+		((uint16_t)( \
+		(((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
+		(((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
+})
+
+#define swab32(x) \
+({ \
+	uint32_t __x = (x); \
+		((uint32_t)( \
+		(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+		(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
+		(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
+		(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
+})
+#define swab64(x) \
+({ \
+	uint64_t __x = (x); \
+		((uint64_t)( \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) <<  8) | \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >>  8) | \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
+		(uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
+})
diff --git a/src/tlist.h b/src/tlist.h
new file mode 100644
index 0000000..eea47ae
--- /dev/null
+++ b/src/tlist.h
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef TLIST_H_DEFINED
+#define TLIST_H_DEFINED
+
+#include <sys/time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+#include "list.h"
+
+#ifndef HZ
+	#define HZ 100  /* 10ms */
+#endif
+
+#ifndef TIMER_HANDLE
+typedef void * timer_handle;
+#define TIMER_HANDLE
+#endif
+
+#define TIMERLIST_MS_IN_SEC   1000ULL
+#define TIMERLIST_US_IN_SEC   1000000ULL
+#define TIMERLIST_NS_IN_SEC   1000000000ULL
+#define TIMERLIST_US_IN_MSEC  1000ULL
+#define TIMERLIST_NS_IN_MSEC  1000000ULL
+#define TIMERLIST_NS_IN_USEC  1000ULL
+
+struct timerlist {
+	struct list_head timer_head;
+	struct list_head *timer_iter;
+};
+
+struct timerlist_timer {
+	struct list_head list;
+	unsigned long long expire_time;
+	int is_absolute_timer;
+	void (*timer_fn)(void *data);
+	void *data;
+	timer_handle handle_addr;
+};
+
+static inline void timerlist_init (struct timerlist *timerlist)
+{
+	list_init (&timerlist->timer_head);
+}
+
+static inline unsigned long long timerlist_nano_from_epoch (void)
+{
+	unsigned long long nano_from_epoch;
+	struct timeval time_from_epoch;
+	gettimeofday (&time_from_epoch, 0);
+
+	nano_from_epoch = ((time_from_epoch.tv_sec * TIMERLIST_NS_IN_SEC) +
+		(time_from_epoch.tv_usec * TIMERLIST_NS_IN_USEC));
+
+	return (nano_from_epoch);
+}
+
+#if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
+static inline unsigned long long timerlist_nano_current_get (void)
+{
+	unsigned long long nano_monotonic;
+	struct timespec ts;
+
+	clock_gettime (CLOCK_MONOTONIC, &ts);
+
+	nano_monotonic = (ts.tv_sec * TIMERLIST_NS_IN_SEC) + (unsigned long long )ts.tv_nsec;
+	return (nano_monotonic);
+}
+
+static inline unsigned long long timerlist_nano_monotonic_hz (void) {
+	unsigned long long nano_monotonic_hz;
+	struct timespec ts;
+
+	clock_getres (CLOCK_MONOTONIC, &ts);
+
+	nano_monotonic_hz = TIMERLIST_NS_IN_SEC / ((ts.tv_sec * TIMERLIST_NS_IN_SEC) + ts.tv_nsec);
+
+	return (nano_monotonic_hz);
+}
+#else
+#warning "Your system doesn't support monotonic timer. gettimeofday will be used"
+static inline unsigned long long timerlist_nano_current_get (void)
+{
+	return (timerlist_nano_from_epoch ());
+}
+
+static inline unsigned long long timerlist_nano_monotonic_hz (void) {
+	return HZ;
+}
+#endif
+
+static inline void timerlist_add (struct timerlist *timerlist, struct timerlist_timer *timer)
+{
+	struct list_head *timer_list = 0;
+	struct timerlist_timer *timer_from_list;
+	int found;
+
+	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 timerlist_timer, list);
+
+		if (timer_from_list->expire_time > timer->expire_time) {
+			list_add (&timer->list, timer_list->prev);
+			found = 1;
+			break; /* for timer iteration */
+		}
+	}
+	if (found == 0) {
+		list_add (&timer->list, timerlist->timer_head.prev);
+	}
+}
+
+static inline int timerlist_add_absolute (struct timerlist *timerlist,
+	void (*timer_fn) (void *data),
+	void *data,
+	unsigned long long nano_from_epoch,
+	timer_handle *handle)
+{
+	struct timerlist_timer *timer;
+
+	timer = (struct timerlist_timer *)malloc (sizeof (struct timerlist_timer));
+	if (timer == 0) {
+		errno = ENOMEM;
+		return (-1);
+	}
+
+	timer->expire_time = nano_from_epoch;
+	timer->is_absolute_timer = 1;
+	timer->data = data;
+	timer->timer_fn = timer_fn;
+	timer->handle_addr = handle;
+	timerlist_add (timerlist, timer);
+
+	*handle = timer;
+	return (0);
+}
+
+static inline int timerlist_add_duration (struct timerlist *timerlist,
+	void (*timer_fn) (void *data),
+	void *data,
+	unsigned long long nano_duration,
+	timer_handle *handle)
+{
+	struct timerlist_timer *timer;
+
+	timer = (struct timerlist_timer *)malloc (sizeof (struct timerlist_timer));
+	if (timer == 0) {
+		errno = ENOMEM;
+		return (-1);
+	}
+
+	timer->expire_time = timerlist_nano_current_get () + nano_duration;
+	timer->is_absolute_timer = 0;
+	timer->data = data;
+	timer->timer_fn = timer_fn;
+	timer->handle_addr = handle;
+	timerlist_add (timerlist, timer);
+
+	*handle = timer;
+	return (0);
+}
+
+static inline void timerlist_del (struct timerlist *timerlist,
+				  timer_handle _timer_handle)
+{
+	struct timerlist_timer *timer = (struct timerlist_timer *)_timer_handle;
+
+	memset (timer->handle_addr, 0, sizeof (struct timerlist_timer *));
+	/*
+	 * If the next timer after the currently expiring timer because
+	 * timerlist_del is called from a timer handler, get to the next
+	 * timer
+	 */
+	if (timerlist->timer_iter == &timer->list) {
+		timerlist->timer_iter = timerlist->timer_iter->next;
+	}
+	list_del (&timer->list);
+	list_init (&timer->list);
+	free (timer);
+}
+
+static inline unsigned long long timerlist_expire_time (struct timerlist *timerlist, timer_handle _timer_handle)
+{
+	struct timerlist_timer *timer = (struct timerlist_timer *)_timer_handle;
+
+	return (timer->expire_time);
+}
+
+static inline void timerlist_pre_dispatch (struct timerlist *timerlist, timer_handle _timer_handle)
+{
+	struct timerlist_timer *timer = (struct timerlist_timer *)_timer_handle;
+
+	memset (timer->handle_addr, 0, sizeof (struct timerlist_timer *));
+	list_del (&timer->list);
+	list_init (&timer->list);
+}
+
+static inline void timerlist_post_dispatch (struct timerlist *timerlist, timer_handle _timer_handle)
+{
+	struct timerlist_timer *timer = (struct timerlist_timer *)_timer_handle;
+
+	free (timer);
+}
+
+/*
+ * returns the number of msec until the next timer will expire for use with poll
+ */
+static inline unsigned long long timerlist_msec_duration_to_expire (struct timerlist *timerlist)
+{
+	struct timerlist_timer *timer_from_list;
+	volatile unsigned long long current_time;
+	volatile unsigned long long msec_duration_to_expire;
+
+	/*
+	 * empty list, no expire
+	 */
+	if (timerlist->timer_head.next == &timerlist->timer_head) {
+		return (-1);
+	}
+
+	timer_from_list = list_entry (timerlist->timer_head.next,
+		struct timerlist_timer, list);
+
+	if (timer_from_list->is_absolute_timer) {
+		current_time = timerlist_nano_from_epoch ();
+	} else {
+		current_time = timerlist_nano_current_get ();
+	}
+
+	/*
+	 * timer at head of list is expired, zero msecs required
+	 */
+	if (timer_from_list->expire_time < current_time) {
+		return (0);
+	}
+
+	msec_duration_to_expire = ((timer_from_list->expire_time - current_time) / TIMERLIST_NS_IN_MSEC) +
+		(1000 / HZ);
+	return (msec_duration_to_expire);
+}
+
+/*
+ * Expires any timers that should be expired
+ */
+static inline void timerlist_expire (struct timerlist *timerlist)
+{
+	struct timerlist_timer *timer_from_list;
+	unsigned long long current_time_from_epoch;
+	unsigned long long current_monotonic_time;
+	unsigned long long current_time;
+
+	current_monotonic_time = timerlist_nano_current_get ();
+	current_time_from_epoch = current_time = timerlist_nano_from_epoch ();
+
+	for (timerlist->timer_iter = timerlist->timer_head.next;
+		timerlist->timer_iter != &timerlist->timer_head;) {
+
+		timer_from_list = list_entry (timerlist->timer_iter,
+			struct timerlist_timer, list);
+
+		current_time = (timer_from_list->is_absolute_timer ? current_time_from_epoch : current_monotonic_time);
+
+		if (timer_from_list->expire_time < current_time) {
+			timerlist->timer_iter = timerlist->timer_iter->next;
+
+			timerlist_pre_dispatch (timerlist, timer_from_list);
+
+			timer_from_list->timer_fn (timer_from_list->data);
+
+			timerlist_post_dispatch (timerlist, timer_from_list);
+		} else {
+			break; /* for timer iteration */
+		}
+	}
+	timerlist->timer_iter = 0;
+}
+#endif /* TLIST_H_DEFINED */
-- 
1.6.2.5

