incremental
diff --git a/boost-dbus/include/dbus/connection.hpp b/boost-dbus/include/dbus/connection.hpp
new file mode 100644
index 0000000..a7185a5
--- /dev/null
+++ b/boost-dbus/include/dbus/connection.hpp
@@ -0,0 +1,130 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_CONNECTION_HPP
+#define DBUS_CONNECTION_HPP
+
+#include <dbus/connection_service.hpp>
+#include <dbus/element.hpp>
+#include <dbus/message.hpp>
+#include <chrono>
+#include <string>
+#include <boost/asio.hpp>
+
+namespace dbus {
+
+class filter;
+class match;
+
+/// Root D-Bus IO object
+/**
+ * A connection to a bus, through which messages may be sent or received.
+ */
+class connection : public boost::asio::basic_io_object<connection_service> {
+ public:
+  /// Open a connection to a specified address.
+  /**
+ * @param io_service The io_service object that the connection will use to
+ * wire D-Bus for asynchronous operation.
+ *
+ * @param address The address of the bus to connect to.
+ *
+ * @throws boost::system::system_error When opening the connection failed.
+ */
+  connection(boost::asio::io_service& io, const string& address)
+      : basic_io_object<connection_service>(io) {
+    this->get_service().open(this->get_implementation(), address);
+  }
+
+  /// Open a connection to a well-known bus.
+  /**
+ * D-Bus connections are usually opened to well-known buses like the
+ * system or session bus.
+ *
+ * @param bus The well-known bus to connect to.
+ *
+ * @throws boost::system::system_error When opening the connection failed.
+ */
+  // TODO: change this unsigned to an enumeration
+  connection(boost::asio::io_service& io, const int bus)
+      : basic_io_object<connection_service>(io) {
+    this->get_service().open(this->get_implementation(), bus);
+  }
+
+  /// Send a message.
+  /**
+ * @param m The message to send.
+ *
+ * @return The reply received.
+ *
+ * @throws boost::system::system_error When the response timed out or
+ * there was some other error.
+ */
+  message send(message& m) {
+    return this->get_service().send(this->get_implementation(), m);
+  }
+
+  /// Send a message.
+  /**
+ * @param m The message to send.
+ *
+ * @param t Time to wait for a reply. Passing 0 as the timeout means
+ * that you wish to ignore the reply. (Or catch it later somehow...)
+ *
+ * @return The reply received.
+ *
+ * @throws boost::system::system_error When the response timed out (if
+ * timeout was not 0), or there was some other error.
+ */
+  template <typename Duration>
+  message send(message& m, const Duration& t) {
+    return this->get_service().send(this->get_implementation(), m, t);
+  }
+
+  /// Send a message asynchronously.
+  /**
+ * @param m The message to send.
+ *
+ * @param handler Handler for the reply.
+ *
+ * @return Asynchronous result
+ */
+  template <typename MessageHandler>
+  inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,
+                                       void(boost::system::error_code, message))
+      async_send(message& m, BOOST_ASIO_MOVE_ARG(MessageHandler) handler) {
+    return this->get_service().async_send(
+        this->get_implementation(), m,
+        BOOST_ASIO_MOVE_CAST(MessageHandler)(handler));
+  }
+
+  /// Create a new match.
+  void new_match(match& m) {
+    this->get_service().new_match(this->get_implementation(), m);
+  }
+
+  /// Destroy a match.
+  void delete_match(match& m) {
+    this->get_service().delete_match(this->get_implementation(), m);
+  }
+
+  /// Create a new filter.
+  void new_filter(filter& f) {
+    this->get_service().new_filter(this->get_implementation(), f);
+  }
+
+  /// Destroy a filter.
+  void delete_filter(filter& f) {
+    this->get_service().delete_filter(this->get_implementation(), f);
+  }
+
+  // FIXME the only way around this I see is to expose start() here, which seems
+  // ugly
+  friend class filter;
+};
+
+}  // namespace dbus
+
+#endif  // DBUS_CONNECTION_HPP
diff --git a/boost-dbus/include/dbus/connection_service.hpp b/boost-dbus/include/dbus/connection_service.hpp
new file mode 100644
index 0000000..28318c6
--- /dev/null
+++ b/boost-dbus/include/dbus/connection_service.hpp
@@ -0,0 +1,105 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_CONNECTION_SERVICE_HPP
+#define DBUS_CONNECTION_SERVICE_HPP
+
+#include <boost/asio.hpp>
+#include <boost/asio/io_service.hpp>
+
+#include <dbus/detail/async_send_op.hpp>
+#include <dbus/element.hpp>
+#include <dbus/error.hpp>
+#include <dbus/message.hpp>
+
+#include <dbus/impl/connection.ipp>
+
+namespace dbus {
+namespace bus {
+static const int session = DBUS_BUS_SESSION;
+static const int system = DBUS_BUS_SYSTEM;
+static const int starter = DBUS_BUS_STARTER;
+}  // namespace bus
+
+class filter;
+class match;
+class connection;
+
+class connection_service : public boost::asio::detail::service_base<connection_service> {
+ public:
+  typedef impl::connection implementation_type;
+
+  inline explicit connection_service(boost::asio::io_service& io)
+      : boost::asio::detail::service_base<connection_service>(io) {}
+
+  inline void construct(implementation_type& impl) {}
+
+  inline void destroy(implementation_type& impl) {}
+
+  inline void shutdown_service() {
+    // TODO is there anything that needs shutting down?
+  }
+
+  inline void open(implementation_type& impl, const string& address) {
+    boost::asio::io_service& io = this->get_io_service();
+
+    impl.open(io, address);
+  }
+
+  inline void open(implementation_type& impl, const int bus = bus::system) {
+    boost::asio::io_service& io = this->get_io_service();
+
+    impl.open(io, bus);
+  }
+
+  inline message send(implementation_type& impl, message& m) {
+    return impl.send_with_reply_and_block(m);
+  }
+
+  template <typename Duration>
+  inline message send(implementation_type& impl, message& m, const Duration& timeout) {
+    if (timeout == Duration::zero()) {
+      // TODO this can return false if it failed
+      impl.send(m);
+      return message();
+    } else {
+      return impl.send_with_reply_and_block(
+          m, std::chrono::milliseconds(timeout).count());
+    }
+  }
+
+  template <typename MessageHandler>
+  inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,
+                                       void(boost::system::error_code, message))
+      async_send(implementation_type& impl, message& m,
+                 BOOST_ASIO_MOVE_ARG(MessageHandler) handler) {
+    // begin asynchronous operation
+    impl.start(this->get_io_service());
+
+    boost::asio::detail::async_result_init<
+        MessageHandler, void(boost::system::error_code, message)>
+        init(BOOST_ASIO_MOVE_CAST(MessageHandler)(handler));
+    detail::async_send_op<typename boost::asio::handler_type<
+        MessageHandler, void(boost::system::error_code, message)>::type>(
+        this->get_io_service(),
+        BOOST_ASIO_MOVE_CAST(MessageHandler)(init.handler))(impl, m);
+
+    return init.result.get();
+  }
+
+ private:
+  friend connection;
+  inline void new_match(implementation_type& impl, match& m);
+
+  inline void delete_match(implementation_type& impl, match& m);
+
+  inline void new_filter(implementation_type& impl, filter& f);
+
+  inline void delete_filter(implementation_type& impl, filter& f);
+};
+
+}  // namespace dbus
+
+#endif  // DBUS_CONNECTION_SERVICE_HPP
diff --git a/boost-dbus/include/dbus/detail/async_send_op.hpp b/boost-dbus/include/dbus/detail/async_send_op.hpp
new file mode 100644
index 0000000..996a4e7
--- /dev/null
+++ b/boost-dbus/include/dbus/detail/async_send_op.hpp
@@ -0,0 +1,78 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_ASYNC_SEND_OP_HPP
+#define DBUS_ASYNC_SEND_OP_HPP
+
+#include <boost/scoped_ptr.hpp>
+
+#include <dbus/dbus.h>
+#include <dbus/error.hpp>
+#include <dbus/message.hpp>
+
+#include <dbus/impl/connection.ipp>
+
+namespace dbus {
+namespace detail {
+
+template <typename MessageHandler>
+struct async_send_op {
+  boost::asio::io_service& io_;
+  message message_;
+  MessageHandler handler_;
+  async_send_op(boost::asio::io_service& io,BOOST_ASIO_MOVE_ARG(MessageHandler) handler);
+  static void callback(DBusPendingCall* p, void* userdata);  // for C API
+  void operator()(impl::connection& c, message& m);  // initiate operation
+  void operator()();  // bound completion handler form
+};
+
+template <typename MessageHandler>
+async_send_op<MessageHandler>::async_send_op(boost::asio::io_service& io,BOOST_ASIO_MOVE_ARG(MessageHandler)handler)
+    : io_(io), handler_(BOOST_ASIO_MOVE_CAST(MessageHandler)(handler)) {}
+
+template <typename MessageHandler>
+void async_send_op<MessageHandler>::operator()(impl::connection& c,
+                                               message& m) {
+  DBusPendingCall* p;
+  c.send_with_reply(m, &p, -1);
+
+  // We have to throw this onto the heap so that the
+  // C API can store it as `void *userdata`
+  async_send_op* op =
+      new async_send_op(BOOST_ASIO_MOVE_CAST(async_send_op)(*this));
+
+  dbus_pending_call_set_notify(p, &callback, op, NULL);
+
+  // FIXME Race condition: another thread might have
+  // processed the pending call's reply before a notify
+  // function could be set. If so, the notify function
+  // will never trigger, so it must be called manually:
+  if (dbus_pending_call_get_completed(p)) {
+    // TODO: does this work, or might it call the notify
+    // function too many times? Might have to use steal_reply
+    // callback(p, op);
+  }
+}
+
+template <typename MessageHandler>
+void async_send_op<MessageHandler>::callback(DBusPendingCall* p,
+                                             void* userdata) {
+  boost::scoped_ptr<async_send_op> op(static_cast<async_send_op*>(userdata));
+
+  op->message_ = dbus_pending_call_steal_reply(p);
+  dbus_pending_call_unref(p);
+
+  op->io_.post(BOOST_ASIO_MOVE_CAST(async_send_op)(*op));
+}
+
+template <typename MessageHandler>
+void async_send_op<MessageHandler>::operator()() {
+  handler_(error(message_).error_code(), message_);
+}
+
+}  // namespace detail
+}  // namespace dbus
+
+#endif  // DBUS_ASYNC_SEND_OP_HPP
diff --git a/boost-dbus/include/dbus/detail/queue.hpp b/boost-dbus/include/dbus/detail/queue.hpp
new file mode 100644
index 0000000..c435af3
--- /dev/null
+++ b/boost-dbus/include/dbus/detail/queue.hpp
@@ -0,0 +1,98 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_QUEUE_HPP
+#define DBUS_QUEUE_HPP
+
+#include <deque>
+#include <functional>
+#include <boost/asio.hpp>
+#include <boost/asio/detail/mutex.hpp>
+
+namespace dbus {
+namespace detail {
+
+template <typename Message>
+class queue {
+ public:
+  typedef ::boost::asio::detail::mutex mutex_type;
+  typedef Message message_type;
+  typedef std::function<void(boost::system::error_code, Message)> handler_type;
+
+ private:
+  boost::asio::io_service& io;
+  mutex_type mutex;
+  std::deque<message_type> messages;
+  std::deque<handler_type> handlers;
+
+ public:
+  queue(boost::asio::io_service& io_service) : io(io_service) {}
+
+ private:
+  class closure {
+    handler_type handler_;
+    message_type message_;
+    boost::system::error_code error_;
+
+   public:
+    void operator()() { handler_(error_, message_); }
+    closure(BOOST_ASIO_MOVE_ARG(handler_type) h, Message m,
+            boost::system::error_code e = boost::system::error_code())
+        : handler_(h), message_(m), error_(e) {}
+  };
+
+ public:
+  void push(message_type m) {
+    mutex_type::scoped_lock lock(mutex);
+    if (handlers.empty())
+      messages.push_back(m);
+    else {
+      handler_type h = handlers.front();
+      handlers.pop_front();
+
+      lock.unlock();
+
+      io.post(closure(BOOST_ASIO_MOVE_CAST(handler_type)(h), m));
+    }
+  }
+
+  template <typename MessageHandler>
+  inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,
+                                       void(boost::system::error_code,
+                                            message_type))
+      async_pop(BOOST_ASIO_MOVE_ARG(MessageHandler) h) {
+    typedef ::boost::asio::detail::async_result_init<
+        MessageHandler, void(boost::system::error_code, message_type)>
+        init_type;
+
+    mutex_type::scoped_lock lock(mutex);
+    if (messages.empty()) {
+      init_type init(BOOST_ASIO_MOVE_CAST(MessageHandler)(h));
+
+      handlers.push_back(init.handler);
+
+      lock.unlock();
+
+      return init.result.get();
+
+    } else {
+      message_type m = messages.front();
+      messages.pop_front();
+
+      lock.unlock();
+
+      init_type init(BOOST_ASIO_MOVE_CAST(MessageHandler)(h));
+
+      io.post(closure(BOOST_ASIO_MOVE_CAST(handler_type)(init.handler), m));
+
+      return init.result.get();
+    }
+  }
+};
+
+}  // namespace detail
+}  // namespace dbus
+
+#endif  // DBUS_QUEUE_HPP
diff --git a/boost-dbus/include/dbus/detail/watch_timeout.hpp b/boost-dbus/include/dbus/detail/watch_timeout.hpp
new file mode 100644
index 0000000..ef2e708
--- /dev/null
+++ b/boost-dbus/include/dbus/detail/watch_timeout.hpp
@@ -0,0 +1,151 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_WATCH_TIMEOUT_HPP
+#define DBUS_WATCH_TIMEOUT_HPP
+
+#include <dbus/dbus.h>
+#include <boost/asio/generic/stream_protocol.hpp>
+#include <boost/asio/steady_timer.hpp>
+
+#include <chrono>
+
+namespace dbus {
+namespace detail {
+
+static void watch_toggled(DBusWatch *dbus_watch, void *data);
+struct watch_handler {
+  DBusWatchFlags flags;
+  DBusWatch *dbus_watch;
+  watch_handler(DBusWatchFlags f, DBusWatch *w) : flags(f), dbus_watch(w) {}
+  void operator()(boost::system::error_code ec, size_t) {
+    if (ec) return;
+    dbus_watch_handle(dbus_watch, flags);
+
+    boost::asio::generic::stream_protocol::socket &socket = *static_cast<boost::asio::generic::stream_protocol::socket *>(
+        dbus_watch_get_data(dbus_watch));
+
+    watch_toggled(dbus_watch, &socket.get_io_service());
+  }
+};
+static void watch_toggled(DBusWatch *dbus_watch, void *data) {
+  boost::asio::generic::stream_protocol::socket &socket =
+      *static_cast<boost::asio::generic::stream_protocol::socket *>(dbus_watch_get_data(dbus_watch));
+
+  if (dbus_watch_get_enabled(dbus_watch)) {
+    if (dbus_watch_get_flags(dbus_watch) & DBUS_WATCH_READABLE)
+      socket.async_read_some(boost::asio::null_buffers(),
+                             watch_handler(DBUS_WATCH_READABLE, dbus_watch));
+
+    if (dbus_watch_get_flags(dbus_watch) & DBUS_WATCH_WRITABLE)
+      socket.async_write_some(boost::asio::null_buffers(),
+                              watch_handler(DBUS_WATCH_WRITABLE, dbus_watch));
+
+  } else {
+    socket.cancel();
+  }
+}
+
+static dbus_bool_t add_watch(DBusWatch *dbus_watch, void *data) {
+  if (!dbus_watch_get_enabled(dbus_watch)) return TRUE;
+
+  boost::asio::io_service &io = *static_cast<boost::asio::io_service *>(data);
+
+  int fd = dbus_watch_get_unix_fd(dbus_watch);
+
+  if (fd == -1)
+    // socket based watches
+    fd = dbus_watch_get_socket(dbus_watch);
+
+  boost::asio::generic::stream_protocol::socket &socket = *new boost::asio::generic::stream_protocol::socket(io);
+
+  socket.assign(boost::asio::generic::stream_protocol(0, 0), fd);
+
+  dbus_watch_set_data(dbus_watch, &socket, NULL);
+
+  watch_toggled(dbus_watch, &io);
+  return TRUE;
+}
+
+static void remove_watch(DBusWatch *dbus_watch, void *data) {
+  delete static_cast<boost::asio::generic::stream_protocol::socket *>(
+      dbus_watch_get_data(dbus_watch));
+}
+
+struct timeout_handler {
+  DBusTimeout *dbus_timeout;
+  timeout_handler(DBusTimeout *t) : dbus_timeout(t) {}
+  void operator()(boost::system::error_code ec) {
+    if (ec) return;
+    dbus_timeout_handle(dbus_timeout);
+  }
+};
+
+static void timeout_toggled(DBusTimeout *dbus_timeout, void *data) {
+  boost::asio::steady_timer &timer =
+      *static_cast<boost::asio::steady_timer *>(dbus_timeout_get_data(dbus_timeout));
+
+  if (dbus_timeout_get_enabled(dbus_timeout)) {
+    boost::asio::steady_timer::duration interval =
+        std::chrono::milliseconds(dbus_timeout_get_interval(dbus_timeout));
+    timer.expires_from_now(interval);
+    timer.cancel();
+    timer.async_wait(timeout_handler(dbus_timeout));
+  } else {
+    timer.cancel();
+  }
+}
+
+static dbus_bool_t add_timeout(DBusTimeout *dbus_timeout, void *data) {
+  if (!dbus_timeout_get_enabled(dbus_timeout)) return TRUE;
+
+  boost::asio::io_service &io = *static_cast<boost::asio::io_service *>(data);
+
+  boost::asio::steady_timer &timer = *new boost::asio::steady_timer(io);
+
+  dbus_timeout_set_data(dbus_timeout, &timer, NULL);
+
+  timeout_toggled(dbus_timeout, &io);
+  return TRUE;
+}
+
+static void remove_timeout(DBusTimeout *dbus_timeout, void *data) {
+  delete static_cast<boost::asio::steady_timer *>(dbus_timeout_get_data(dbus_timeout));
+}
+
+struct dispatch_handler {
+  boost::asio::io_service &io;
+  DBusConnection *conn;
+  dispatch_handler(boost::asio::io_service &i, DBusConnection *c)
+      : io(i), conn(c) {}
+  void operator()() {
+    if (dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS)
+      io.post(dispatch_handler(io, conn));
+  }
+};
+
+static void dispatch_status(DBusConnection *conn, DBusDispatchStatus new_status,
+                            void *data) {
+  boost::asio::io_service &io = *static_cast<boost::asio::io_service *>(data);
+  if (new_status == DBUS_DISPATCH_DATA_REMAINS)
+    io.post(dispatch_handler(io, conn));
+}
+
+static void set_watch_timeout_dispatch_functions(DBusConnection *conn,
+                                                 boost::asio::io_service &io) {
+  dbus_connection_set_watch_functions(conn, &add_watch, &remove_watch,
+                                      &watch_toggled, &io, NULL);
+
+  dbus_connection_set_timeout_functions(conn, &add_timeout, &remove_timeout,
+                                        &timeout_toggled, &io, NULL);
+
+  dbus_connection_set_dispatch_status_function(conn, &dispatch_status, &io,
+                                               NULL);
+}
+
+}  // namespace detail
+}  // namespace dbus
+
+#endif  // DBUS_WATCH_TIMEOUT_HPP
diff --git a/boost-dbus/include/dbus/element.hpp b/boost-dbus/include/dbus/element.hpp
new file mode 100644
index 0000000..276b593
--- /dev/null
+++ b/boost-dbus/include/dbus/element.hpp
@@ -0,0 +1,182 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_ELEMENT_HPP
+#define DBUS_ELEMENT_HPP
+
+#include <dbus/dbus.h>
+#include <string>
+#include <boost/cstdint.hpp>
+
+namespace dbus {
+
+/// Message elements
+/**
+ * D-Bus Messages are composed of simple elements of one of these types
+ */
+// bool // is this simply valid? It might pack wrong...
+// http://maemo.org/api_refs/5.0/5.0-final/dbus/api/group__DBusTypes.html
+typedef boost::uint8_t byte;
+
+typedef boost::int16_t int16;
+typedef boost::uint16_t uint16;
+typedef boost::int32_t int32;
+typedef boost::uint32_t uint32;
+
+typedef boost::int64_t int64;
+typedef boost::uint64_t uint64;
+// double
+// unix_fd
+
+typedef std::string string;
+struct object_path {
+  string value;
+};
+struct signature {
+  string value;
+};
+
+/// Traits template for message elements
+/**
+ * D-Bus Message elements are identified by unique integer type codes.
+ */
+template <typename InvalidType>
+struct element {
+  static const int code = DBUS_TYPE_INVALID;
+};
+
+template <>
+struct element<bool> {
+  static const int code = DBUS_TYPE_BOOLEAN;
+};
+
+template <>
+struct element<byte> {
+  static const int code = DBUS_TYPE_BYTE;
+};
+
+template <>
+struct element<int16> {
+  static const int code = DBUS_TYPE_INT16;
+};
+
+template <>
+struct element<uint16> {
+  static const int code = DBUS_TYPE_UINT16;
+};
+
+template <>
+struct element<int32> {
+  static const int code = DBUS_TYPE_INT32;
+};
+
+template <>
+struct element<uint32> {
+  static const int code = DBUS_TYPE_UINT32;
+};
+
+template <>
+struct element<int64> {
+  static const int code = DBUS_TYPE_INT64;
+};
+
+template <>
+struct element<uint64> {
+  static const int code = DBUS_TYPE_UINT64;
+};
+
+template <>
+struct element<double> {
+  static const int code = DBUS_TYPE_DOUBLE;
+};
+
+template <>
+struct element<string> {
+  static const int code = DBUS_TYPE_STRING;
+};
+
+template <>
+struct element<object_path> {
+  static const int code = DBUS_TYPE_OBJECT_PATH;
+};
+
+template <>
+struct element<signature> {
+  static const int code = DBUS_TYPE_SIGNATURE;
+};
+
+template <typename InvalidType>
+struct is_fixed_type {
+  static const int value = false;
+};
+
+template <>
+struct is_fixed_type<bool> {
+  static const int value = true;
+};
+
+template <>
+struct is_fixed_type<byte> {
+  static const int value = true;
+};
+
+template <>
+struct is_fixed_type<int16> {
+  static const int value = true;
+};
+
+template <>
+struct is_fixed_type<uint16> {
+  static const int value = true;
+};
+
+template <>
+struct is_fixed_type<int32> {
+  static const int value = true;
+};
+
+template <>
+struct is_fixed_type<uint32> {
+  static const int value = true;
+};
+
+template <>
+struct is_fixed_type<int64> {
+  static const int value = true;
+};
+
+template <>
+struct is_fixed_type<uint64> {
+  static const int value = true;
+};
+
+template <>
+struct is_fixed_type<double> {
+  static const int value = true;
+};
+
+template <typename InvalidType>
+struct is_string_type {
+  static const bool value = false;
+};
+
+template <>
+struct is_string_type<string> {
+  static const bool value = true;
+};
+
+template <>
+struct is_string_type<object_path> {
+  static const bool value = true;
+};
+
+template <>
+struct is_string_type<signature> {
+  static const bool value = true;
+};
+
+}  // namespace dbus
+
+#endif  // DBUS_ELEMENT_HPP
diff --git a/boost-dbus/include/dbus/endpoint.hpp b/boost-dbus/include/dbus/endpoint.hpp
new file mode 100644
index 0000000..a574e8f
--- /dev/null
+++ b/boost-dbus/include/dbus/endpoint.hpp
@@ -0,0 +1,34 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_ENDPOINT_HPP
+#define DBUS_ENDPOINT_HPP
+
+#include <dbus/dbus.h>
+#include <dbus/element.hpp>
+#include <dbus/message.hpp>
+
+namespace dbus {
+
+class endpoint {
+  string process_name_;
+  string path_;
+  string interface_;
+
+ public:
+  endpoint(const string& process_name, const string& path,
+           const string& interface)
+      : process_name_(process_name), path_(path), interface_(interface) {}
+
+  const string& get_path() const { return path_; }
+
+  const string& get_interface() const { return interface_; }
+
+  const string& get_process_name() const { return process_name_; }
+};
+
+}  // namespace dbus
+
+#endif  // DBUS_ENDPOINT_HPP
diff --git a/boost-dbus/include/dbus/error.hpp b/boost-dbus/include/dbus/error.hpp
new file mode 100644
index 0000000..3b07c9f
--- /dev/null
+++ b/boost-dbus/include/dbus/error.hpp
@@ -0,0 +1,64 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_ERROR_HPP
+#define DBUS_ERROR_HPP
+
+#include <dbus/dbus.h>
+#include <dbus/element.hpp>
+#include <dbus/message.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/system/system_error.hpp>
+
+namespace dbus {
+
+class error : public boost::system::error_category {
+  DBusError error_;
+
+ public:
+  error() { dbus_error_init(&error_); }
+
+  error(DBusError *src) {
+    dbus_error_init(&error_);
+    dbus_move_error(src, &error_);
+  }
+
+  error(dbus::message &m) {
+    dbus_error_init(&error_);
+    dbus_set_error_from_message(&error_, m);
+  }
+
+  ~error() { dbus_error_free(&error_); }
+
+  const char *name() const BOOST_SYSTEM_NOEXCEPT { return error_.name; }
+
+  string message(int value) const { return error_.message; }
+
+  bool is_set() const { return dbus_error_is_set(&error_); }
+
+  operator const DBusError *() const { return &error_; }
+
+  operator DBusError *() { return &error_; }
+
+  boost::system::error_code error_code() const;
+  boost::system::system_error system_error() const;
+  void throw_if_set() const;
+};
+
+inline boost::system::error_code error::error_code() const {
+  return boost::system::error_code(is_set(), *this);
+}
+
+inline boost::system::system_error error::system_error() const {
+  return boost::system::system_error(error_code());
+}
+
+inline void error::throw_if_set() const {
+  if (is_set()) throw system_error();
+}
+
+}  // namespace dbus
+
+#endif  // DBUS_ERROR_HPP
diff --git a/boost-dbus/include/dbus/filter.hpp b/boost-dbus/include/dbus/filter.hpp
new file mode 100644
index 0000000..5d60d33
--- /dev/null
+++ b/boost-dbus/include/dbus/filter.hpp
@@ -0,0 +1,56 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_FILTER_HPP
+#define DBUS_FILTER_HPP
+
+#include <dbus/connection.hpp>
+#include <dbus/detail/queue.hpp>
+#include <dbus/message.hpp>
+#include <functional>
+#include <boost/asio.hpp>
+
+namespace dbus {
+
+/// Represents a filter of incoming messages.
+/**
+ * Filters examine incoming messages, demuxing them to multiple queues.
+ */
+class filter {
+  connection& connection_;
+  std::function<bool(message&)> predicate_;
+  detail::queue<message> queue_;
+
+ public:
+  bool offer(message& m) {
+    bool filtered = predicate_(m);
+    if (filtered) queue_.push(m);
+    return filtered;
+  }
+
+  template <typename MessagePredicate>
+  filter(connection& c, BOOST_ASIO_MOVE_ARG(MessagePredicate) p)
+      : connection_(c),
+        predicate_(BOOST_ASIO_MOVE_CAST(MessagePredicate)(p)),
+        queue_(connection_.get_io_service()) {
+    connection_.new_filter(*this);
+  }
+
+  ~filter() { connection_.delete_filter(*this); }
+
+  template <typename MessageHandler>
+  inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,
+                                       void(boost::system::error_code, message))
+      async_dispatch(BOOST_ASIO_MOVE_ARG(MessageHandler) handler) {
+    // begin asynchronous operation
+    connection_.get_implementation().start(connection_.get_io_service());
+
+    return queue_.async_pop(BOOST_ASIO_MOVE_CAST(MessageHandler)(handler));
+  }
+};
+}  // namespace dbus
+
+#include <dbus/impl/filter.ipp>
+#endif  // DBUS_FILTER_HPP
diff --git a/boost-dbus/include/dbus/impl/connection.ipp b/boost-dbus/include/dbus/impl/connection.ipp
new file mode 100644
index 0000000..24a257d
--- /dev/null
+++ b/boost-dbus/include/dbus/impl/connection.ipp
@@ -0,0 +1,102 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_CONNECTION_IPP
+#define DBUS_CONNECTION_IPP
+
+#include <dbus/dbus.h>
+#include <dbus/detail/watch_timeout.hpp>
+
+#include <boost/atomic.hpp>
+
+namespace dbus {
+namespace impl {
+
+class connection {
+ public:
+  boost::atomic<bool> is_paused;
+  DBusConnection* conn;
+
+  connection() : is_paused(true), conn(NULL) {}
+
+  void open(boost::asio::io_service& io, int bus) {
+    error e;
+    conn = dbus_bus_get_private((DBusBusType)bus, e);
+    e.throw_if_set();
+
+    dbus_connection_set_exit_on_disconnect(conn, false);
+
+    detail::set_watch_timeout_dispatch_functions(conn, io);
+  }
+
+  void open(boost::asio::io_service& io, const string& address) {
+    error e;
+    conn = dbus_connection_open_private(address.c_str(), e);
+    e.throw_if_set();
+
+    dbus_bus_register(conn, e);
+    e.throw_if_set();
+
+    dbus_connection_set_exit_on_disconnect(conn, false);
+
+    detail::set_watch_timeout_dispatch_functions(conn, io);
+  }
+
+  ~connection() {
+    if (conn != NULL) {
+      dbus_connection_close(conn);
+      dbus_connection_unref(conn);
+    }
+  }
+
+  operator DBusConnection*() { return conn; }
+  operator const DBusConnection*() const { return conn; }
+
+  message send_with_reply_and_block(message& m,
+                                    int timeout_in_milliseconds = -1) {
+    error e;
+    DBusMessage* out = dbus_connection_send_with_reply_and_block(
+        conn, m, timeout_in_milliseconds, e);
+    e.throw_if_set();
+    message reply(out);
+
+    return reply;
+  }
+
+  void send(message& m) {
+    // ignoring message serial for now
+    dbus_connection_send(conn, m, NULL);
+  }
+
+  void send_with_reply(message& m, DBusPendingCall** p,
+                       int timeout_in_milliseconds = -1) {
+    dbus_connection_send_with_reply(conn, m, p, timeout_in_milliseconds);
+  }
+
+  // begin asynchronous operation
+  // FIXME should not get io from an argument
+  void start(boost::asio::io_service& io) {
+    bool old_value(true);
+    if (is_paused.compare_exchange_strong(old_value, false)) {
+      // If two threads call connection::async_send()
+      // simultaneously on a paused connection, then
+      // only one will pass the CAS instruction and
+      // only one dispatch_handler will be injected.
+      io.post(detail::dispatch_handler(io, conn));
+    }
+  }
+
+  void cancel(boost::asio::io_service& io) {
+    bool old_value(false);
+    if (is_paused.compare_exchange_strong(old_value, true)) {
+      // TODO
+    }
+  }
+};
+
+}  // namespace impl
+}  // namespace dbus
+
+#endif  // DBUS_CONNECTION_IPP
diff --git a/boost-dbus/include/dbus/impl/filter.ipp b/boost-dbus/include/dbus/impl/filter.ipp
new file mode 100644
index 0000000..a64d6fd
--- /dev/null
+++ b/boost-dbus/include/dbus/impl/filter.ipp
@@ -0,0 +1,39 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_FILTER_IPP
+#define DBUS_FILTER_IPP
+
+namespace dbus {
+namespace impl {
+
+inline DBusHandlerResult filter_callback(DBusConnection* c, DBusMessage* m,
+                                  void* userdata) {
+  try {
+    filter& f = *static_cast<filter*>(userdata);
+    message m_(m);
+    if (f.offer(m_)) {
+      return DBUS_HANDLER_RESULT_HANDLED;
+    }
+  } catch (...) {
+    // do not throw in C callbacks. Just don't.
+  }
+
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+}  // namespace impl
+
+void connection_service::new_filter(implementation_type& impl, filter& f) {
+  dbus_connection_add_filter(impl, &impl::filter_callback, &f, NULL);
+}
+
+void connection_service::delete_filter(implementation_type& impl, filter& f) {
+  dbus_connection_remove_filter(impl, &impl::filter_callback, &f);
+}
+
+}  // namespace dbus
+
+#endif  // DBUS_FILTER_IPP
diff --git a/boost-dbus/include/dbus/impl/match.ipp b/boost-dbus/include/dbus/impl/match.ipp
new file mode 100644
index 0000000..9f6a5da
--- /dev/null
+++ b/boost-dbus/include/dbus/impl/match.ipp
@@ -0,0 +1,26 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_MATCH_IPP
+#define DBUS_MATCH_IPP
+
+namespace dbus {
+void connection_service::new_match(implementation_type& impl, match& m) {
+  error e;
+  dbus_bus_add_match(impl, m.get_expression().c_str(), e);
+  e.throw_if_set();
+  // eventually, for complete asynchronicity, this should connect to
+  // org.freedesktop.DBus and call AddMatch
+}
+
+void connection_service::delete_match(implementation_type& impl, match& m) {
+  error e;
+  dbus_bus_remove_match(impl, m.get_expression().c_str(), e);
+  e.throw_if_set();
+}
+
+}  // namespace dbus
+
+#endif  // DBUS_MATCH_IPP
diff --git a/boost-dbus/include/dbus/impl/message_iterator.hpp b/boost-dbus/include/dbus/impl/message_iterator.hpp
new file mode 100644
index 0000000..44bcf2e
--- /dev/null
+++ b/boost-dbus/include/dbus/impl/message_iterator.hpp
@@ -0,0 +1,50 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_IMPL_MESSAGE_ITERATOR_HPP
+#define DBUS_IMPL_MESSAGE_ITERATOR_HPP
+
+#include <dbus/dbus.h>
+
+namespace dbus {
+
+class message;
+
+namespace impl {
+
+class message_iterator {
+  DBusMessageIter DBusMessageIter_;
+
+ public:
+  // writing
+  static void init_append(message &m, message_iterator &i);
+
+  void append_basic(int code, const void *value);
+
+  void open_container(int code, const char *signature, message_iterator &);
+  void close_container(message_iterator &);
+  void abandon_container(message_iterator &);
+
+  void append_fixed_array(int code, const void *value, int n_elements);
+
+  // reading
+  static bool init(message &m, message_iterator &i);
+
+  bool next();
+  bool has_next();
+  int get_arg_type();
+
+  void get_basic(void *value);
+
+  void recurse(message_iterator &);
+
+  int get_element_type();
+  void get_fixed_array(void *value, int *n_elements);
+};
+
+}  // namespace impl
+}  // namespace dbus
+
+#endif  // DBUS_IMPL_MESSAGE_ITERATOR_HPP
diff --git a/boost-dbus/include/dbus/impl/message_iterator.ipp b/boost-dbus/include/dbus/impl/message_iterator.ipp
new file mode 100644
index 0000000..eb2584f
--- /dev/null
+++ b/boost-dbus/include/dbus/impl/message_iterator.ipp
@@ -0,0 +1,89 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_IMPL_MESSAGE_ITERATOR_IPP
+#define DBUS_IMPL_MESSAGE_ITERATOR_IPP
+
+#include <dbus/impl/message_iterator.hpp>
+
+namespace dbus {
+namespace impl {
+
+inline void message_iterator::init_append(message& m, message_iterator& i)
+{
+  dbus_message_iter_init_append(m, &i.DBusMessageIter_);
+}
+inline void message_iterator::append_basic(int code, const void *value)
+{
+  // returns false if not enough memory- throw bad_alloc
+  dbus_message_iter_append_basic(&DBusMessageIter_, code, value);
+}
+inline void message_iterator::open_container(int code, const char *signature, message_iterator& sub)
+{
+  // returns false if not enough memory- throw bad_alloc
+  dbus_message_iter_open_container(&DBusMessageIter_, code, signature, &sub.DBusMessageIter_);
+}
+
+inline void message_iterator::close_container(message_iterator& sub)
+{
+  // returns false if not enough memory- throw bad_alloc
+  dbus_message_iter_close_container(&DBusMessageIter_, &sub.DBusMessageIter_);
+}
+
+inline void message_iterator::abandon_container(message_iterator& sub)
+{
+  dbus_message_iter_abandon_container(&DBusMessageIter_, &sub.DBusMessageIter_);
+}
+
+inline void message_iterator::append_fixed_array(int code, const void *value, int n_elements)
+{
+  // returns false if not enough memory- throw bad_alloc
+  dbus_message_iter_append_fixed_array(&DBusMessageIter_, code, value, n_elements);
+}
+
+inline bool message_iterator::init(message& m, message_iterator& i)
+{
+  return dbus_message_iter_init(m, &i.DBusMessageIter_);
+}
+
+inline bool message_iterator::next()
+{
+  return dbus_message_iter_next(&DBusMessageIter_);
+}
+
+inline bool message_iterator::has_next()
+{
+  return dbus_message_iter_has_next(&DBusMessageIter_);
+}
+
+inline int message_iterator::get_arg_type()
+{
+  return dbus_message_iter_get_arg_type(&DBusMessageIter_);
+}
+
+inline void message_iterator::get_basic(void *value)
+{
+  dbus_message_iter_get_basic(&DBusMessageIter_, value);
+}
+
+inline void message_iterator::recurse(message_iterator& sub)
+{
+  dbus_message_iter_recurse(&DBusMessageIter_, &sub.DBusMessageIter_);
+}
+
+inline int message_iterator::get_element_type()
+{
+  return dbus_message_iter_get_element_type(&DBusMessageIter_);
+}
+
+inline void message_iterator::get_fixed_array(void *value, int *n_elements)
+{
+  dbus_message_iter_get_fixed_array(&DBusMessageIter_, value, n_elements);
+}
+
+} // namespace impl
+} // namespace dbus
+
+#endif // DBUS_IMPL_MESSAGE_ITERATOR_IPP
diff --git a/boost-dbus/include/dbus/match.hpp b/boost-dbus/include/dbus/match.hpp
new file mode 100644
index 0000000..0488aa0
--- /dev/null
+++ b/boost-dbus/include/dbus/match.hpp
@@ -0,0 +1,46 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_MATCH_HPP
+#define DBUS_MATCH_HPP
+
+#include <string>
+#include <boost/asio.hpp>
+
+#include <dbus/connection.hpp>
+#include <dbus/error.hpp>
+
+namespace dbus {
+
+/// Simple placeholder object for a match rule.
+/**
+ * A match rule determines what messages will be received by this application.
+ *
+ * Each rule will be represented by an instance of match. To remove that rule,
+ * dispose of the object.
+ */
+class match {
+  connection& connection_;
+  std::string expression_;
+
+ public:
+  match(connection& c, BOOST_ASIO_MOVE_ARG(std::string) e)
+      : connection_(c), expression_(BOOST_ASIO_MOVE_CAST(std::string)(e)) {
+    connection_.new_match(*this);
+  }
+
+  ~match() { connection_.delete_match(*this); }
+
+  const std::string& get_expression() const { return expression_; }
+
+  match(match&&) = delete;
+  match& operator=(match&&) = delete;
+};
+
+}  // namespace dbus
+
+#include <dbus/impl/match.ipp>
+
+#endif  // DBUS_MATCH_HPP
diff --git a/boost-dbus/include/dbus/message.hpp b/boost-dbus/include/dbus/message.hpp
new file mode 100644
index 0000000..aa5e89c
--- /dev/null
+++ b/boost-dbus/include/dbus/message.hpp
@@ -0,0 +1,224 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_MESSAGE_HPP
+#define DBUS_MESSAGE_HPP
+
+#include <dbus/dbus.h>
+#include <dbus/element.hpp>
+#include <dbus/endpoint.hpp>
+#include <dbus/impl/message_iterator.hpp>
+#include <iostream>
+#include <vector>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/utility/enable_if.hpp>
+
+inline void intrusive_ptr_add_ref(DBusMessage* m) { dbus_message_ref(m); }
+
+inline void intrusive_ptr_release(DBusMessage* m) { dbus_message_unref(m); }
+
+namespace dbus {
+
+class message {
+  boost::intrusive_ptr<DBusMessage> message_;
+
+ public:
+  /// Create a method call message
+  static message new_call(const endpoint& destination,
+                          const string& method_name) {
+    return dbus_message_new_method_call(
+        destination.get_process_name().c_str(), destination.get_path().c_str(),
+        destination.get_interface().c_str(), method_name.c_str());
+  }
+
+  /// Create a method return message
+  static message new_return(message& call) {
+    return dbus_message_new_method_return(call);
+  }
+
+  /// Create an error message
+  static message new_error(message& call, const string& error_name,
+                           const string& error_message) {
+    return dbus_message_new_error(call, error_name.c_str(),
+                                  error_message.c_str());
+  }
+
+  /// Create a signal message
+  static message new_signal(const endpoint& origin, const string& signal_name) {
+    return dbus_message_new_signal(origin.get_path().c_str(),
+                                   origin.get_interface().c_str(),
+                                   signal_name.c_str());
+  }
+
+  message() {}
+
+  message(DBusMessage* m) : message_(dbus_message_ref(m)) {}
+
+  operator DBusMessage*() { return message_.get(); }
+
+  operator const DBusMessage*() const { return message_.get(); }
+
+  string get_path() const {
+    return sanitize(dbus_message_get_path(message_.get()));
+  }
+
+  string get_interface() const {
+    return sanitize(dbus_message_get_interface(message_.get()));
+  }
+
+  string get_member() const {
+    return sanitize(dbus_message_get_member(message_.get()));
+  }
+
+  string get_type() const {
+    return sanitize(
+        dbus_message_type_to_string(dbus_message_get_type(message_.get())));
+  }
+
+  string get_sender() const {
+    return sanitize(dbus_message_get_sender(message_.get()));
+  }
+
+  string get_destination() const {
+    return sanitize(dbus_message_get_destination(message_.get()));
+  }
+
+  uint32 get_serial() { return dbus_message_get_serial(message_.get()); }
+
+  message& set_serial(uint32 serial) {
+    dbus_message_set_serial(message_.get(), serial);
+    return *this;
+  }
+
+  uint32 get_reply_serial() {
+    return dbus_message_get_reply_serial(message_.get());
+  }
+
+  message& set_reply_serial(uint32 reply_serial) {
+    dbus_message_set_reply_serial(message_.get(), reply_serial);
+    return *this;
+  }
+
+  struct packer {
+    impl::message_iterator iter_;
+    packer(message& m) { impl::message_iterator::init_append(m, iter_); }
+    template <typename Element>
+    packer& pack(const Element& e) {
+      return *this << e;
+    }
+  };
+  struct unpacker {
+    impl::message_iterator iter_;
+    unpacker(message& m) { impl::message_iterator::init(m, iter_); }
+
+    template <typename Element>
+    unpacker& unpack(Element& e) {
+      return *this >> e;
+    }
+  };
+
+  template <typename Element>
+  packer pack(const Element& e) {
+    return packer(*this).pack(e);
+  }
+
+  template <typename Element>
+  unpacker unpack(Element& e) {
+    return unpacker(*this).unpack(e);
+  }
+
+ private:
+  static std::string sanitize(const char* str) {
+    return (str == NULL) ? "(null)" : str;
+  }
+};
+
+template <typename Element>
+message::packer operator<<(message m, const Element& e) {
+  return message::packer(m).pack(e);
+}
+
+template <typename Element>
+typename boost::enable_if<is_fixed_type<Element>, message::packer&>::type
+operator<<(message::packer& p, const Element& e) {
+  p.iter_.append_basic(element<Element>::code, &e);
+  return p;
+}
+
+inline message::packer& operator<<(message::packer& p, const char* c) {
+  p.iter_.append_basic(element<string>::code, &c);
+  return p;
+}
+
+inline message::packer& operator<<(message::packer& p, const string& e) {
+  const char* c = e.c_str();
+  return p << c;
+}
+
+template <typename Element>
+message::unpacker operator>>(message m, Element& e) {
+  return message::unpacker(m).unpack(e);
+}
+
+template <typename Element>
+typename boost::enable_if<is_fixed_type<Element>, message::unpacker&>::type
+operator>>(message::unpacker& u, Element& e) {
+  u.iter_.get_basic(&e);
+  u.iter_.next();
+  return u;
+}
+
+inline message::unpacker& operator>>(message::unpacker& u, string& s) {
+  const char* c;
+  u.iter_.get_basic(&c);
+  s.assign(c);
+  u.iter_.next();
+  return u;
+}
+
+template <typename Element>
+inline message::unpacker& operator>>(message::unpacker& u,
+                                     std::vector<Element>& s) {
+  static_assert(std::is_same<Element, std::string>::value,
+                "only std::vector<std::string> is implemented for now");
+  impl::message_iterator sub;
+  u.iter_.recurse(sub);
+
+  const char* c;
+  while (sub.has_next()) {
+    sub.get_basic(&c);
+    s.emplace_back(c);
+    sub.next();
+  }
+
+  // TODO(ed)
+  // Make this generic for all types.  The below code is close, but there's
+  // template issues and things I don't understand;
+  /*
+  auto e = message::unpacker(sub);
+  while (sub.has_next()) {
+    s.emplace_back();
+    Element& element = s.back();
+    e.unpack(element);
+  }
+*/
+  return u;
+}
+
+inline std::ostream& operator<<(std::ostream& os, const message& m) {
+  os << "type='" << m.get_type() << "',"
+     << "sender='" << m.get_sender() << "',"
+     << "interface='" << m.get_interface() << "',"
+     << "member='" << m.get_member() << "',"
+     << "path='" << m.get_path() << "',"
+     << "destination='" << m.get_destination() << "'";
+  return os;
+}
+
+}  // namespace dbus
+
+#include <dbus/impl/message_iterator.ipp>
+
+#endif  // DBUS_MESSAGE_HPP
diff --git a/boost-dbus/include/dbus/utility.hpp b/boost-dbus/include/dbus/utility.hpp
new file mode 100644
index 0000000..47fad1c
--- /dev/null
+++ b/boost-dbus/include/dbus/utility.hpp
@@ -0,0 +1,39 @@
+// Copyright (c) Ed Tanous
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_UTILITY_HPP
+#define DBUS_UTILITY_HPP
+
+#include <boost/iostreams/stream.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+
+namespace dbus {
+
+inline void read_dbus_xml_names(std::string& xml_data_in,
+                                std::vector<std::string>& values_out) {
+  // populate tree structure pt
+  using boost::property_tree::ptree;
+  ptree pt;
+  std::cout << xml_data_in;
+  std::stringstream ss;
+  ss << xml_data_in;
+  read_xml(ss, pt);
+  
+  // traverse node to find other nodes
+  for (const auto& interface : pt.get_child("node")) {
+    if (interface.first == "node") {
+      auto t = interface.second.get<std::string>("<xmlattr>", "default");
+      for (const auto& subnode : interface.second.get_child("<xmlattr>")) {
+        if (subnode.first == "name") {
+          std::string t = subnode.second.get("", "unknown");
+          values_out.push_back(t);
+        }
+      }
+    }
+  }
+}
+}
+#endif  // DBUS_UTILITY_HPP
\ No newline at end of file