qpid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From acon...@apache.org
Subject [2/7] qpid-proton git commit: PROTON-865: C++ reactor binding for proton.
Date Fri, 04 Sep 2015 19:14:29 GMT
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/container_impl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/container_impl.cpp b/proton-c/bindings/cpp/src/container_impl.cpp
new file mode 100644
index 0000000..75293f1
--- /dev/null
+++ b/proton-c/bindings/cpp/src/container_impl.cpp
@@ -0,0 +1,181 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "proton/container.hpp"
+#include "proton/event.hpp"
+#include "proton/messaging_event.hpp"
+#include "proton/connection.hpp"
+#include "proton/session.hpp"
+#include "proton/messaging_adapter.hpp"
+#include "proton/acceptor.hpp"
+#include "proton/error.hpp"
+#include "proton/url.hpp"
+#include "proton/sender.hpp"
+#include "proton/receiver.hpp"
+
+#include "msg.hpp"
+#include "container_impl.hpp"
+#include "connector.hpp"
+#include "contexts.hpp"
+#include "uuid.hpp"
+
+#include "proton/connection.h"
+#include "proton/session.h"
+#include "proton/handlers.h"
+#include "proton/reactor.h"
+
+namespace proton {
+
+namespace {
+
+struct handler_context {
+    static handler_context& get(pn_handler_t* h) {
+        return *reinterpret_cast<handler_context*>(pn_handler_mem(h));
+    }
+    static void cleanup(pn_handler_t*) {}
+
+    static void dispatch(pn_handler_t *c_handler, pn_event_t *c_event, pn_event_type_t type)
+    {
+        handler_context& hc(handler_context::get(c_handler));
+        messaging_event mevent(c_event, type, *hc.container_);
+        mevent.dispatch(*hc.handler_);
+        return;
+    }
+
+    container *container_;
+    handler *handler_;
+};
+
+
+// Used to sniff for connector events before the reactor's global handler sees them.
+class override_handler : public handler
+{
+  public:
+    counted_ptr<pn_handler_t> base_handler;
+
+    override_handler(pn_handler_t *h) : base_handler(h) {}
+
+    virtual void on_unhandled(event &e) {
+        proton_event *pne = dynamic_cast<proton_event *>(&e);
+        // If not a Proton reactor event, nothing to override, nothing to pass along.
+        if (!pne) return;
+        int type = pne->type();
+        if (!type) return;  // Also not from the reactor
+
+        pn_event_t *cevent = pne->pn_event();
+        pn_connection_t *conn = pn_event_connection(cevent);
+        if (conn && type != PN_CONNECTION_INIT) {
+            handler *override = connection_context::get(conn).handler.get();
+            if (override) e.dispatch(*override);
+        }
+        pn_handler_dispatch(base_handler.get(), cevent, (pn_event_type_t) type);
+    }
+};
+
+} // namespace
+
+counted_ptr<pn_handler_t> container_impl::cpp_handler(handler *h)
+{
+    counted_ptr<pn_handler_t> handler(
+        pn_handler_new(&handler_context::dispatch, sizeof(struct handler_context),
+                       &handler_context::cleanup),
+        false);
+    handler_context &hc = handler_context::get(handler.get());
+    hc.container_ = &container_;
+    hc.handler_ = h;
+    return handler;
+}
+
+container_impl::container_impl(container& c, handler *h, const std::string& id) :
+    container_(c), reactor_(reactor::create()), handler_(h), container_id_(id),
+    link_id_(0)
+{
+    if (container_id_.empty()) container_id_ = uuid().str();
+    container_context(pn_cast(reactor_.get()), container_);
+
+    // Set our own global handler that "subclasses" the existing one
+    pn_handler_t *global_handler = pn_reactor_get_global_handler(pn_cast(reactor_.get()));
+    override_handler_.reset(new override_handler(global_handler));
+    counted_ptr<pn_handler_t> cpp_global_handler(cpp_handler(override_handler_.get()));
+    pn_reactor_set_global_handler(pn_cast(reactor_.get()), cpp_global_handler.get());
+    if (handler_) {
+        counted_ptr<pn_handler_t> pn_handler(cpp_handler(handler_));
+        pn_reactor_set_handler(pn_cast(reactor_.get()), pn_handler.get());
+    }
+
+
+    // Note: we have just set up the following handlers that see events in this order:
+    // messaging_handler (Proton C events), pn_flowcontroller (optional), messaging_adapter,
+    // messaging_handler (Messaging events from the messaging_adapter, i.e. the delegate),
+    // connector override, the reactor's default globalhandler (pn_iohandler)
+}
+
+container_impl::~container_impl() {}
+
+connection& container_impl::connect(const proton::url &url, handler *h) {
+    counted_ptr<pn_handler_t> chandler = h ? cpp_handler(h) : counted_ptr<pn_handler_t>();
+    connection& conn(           // Reactor owns the reference.
+        *connection::cast(pn_reactor_connection(pn_cast(reactor_.get()), chandler.get())));
+    PN_UNIQUE_PTR<connector> ctor(new connector(conn));
+    ctor->address(url);  // TODO: url vector
+    connection_context& cc(connection_context::get(pn_cast(&conn)));
+    cc.container_impl = this;
+    cc.handler.reset(ctor.release());
+    conn.open();
+    return conn;
+}
+
+sender& container_impl::create_sender(const proton::url &url) {
+    connection& conn = connect(url, 0);
+    std::string path = url.path();
+    sender& snd = conn.default_session().create_sender(container_id_ + '-' + path);
+    snd.target().address(path);
+    snd.open();
+    return snd;
+}
+
+receiver& container_impl::create_receiver(const proton::url &url) {
+    connection& conn = connect(url, 0);
+    std::string path = url.path();
+    receiver& rcv = conn.default_session().create_receiver(container_id_ + '-' + path);
+    pn_terminus_set_address(pn_link_source(pn_cast(&rcv)), path.c_str());
+    rcv.open();
+    return rcv;
+}
+
+acceptor& container_impl::listen(const proton::url& url) {
+    pn_acceptor_t *acptr = pn_reactor_acceptor(
+        pn_cast(reactor_.get()), url.host().c_str(), url.port().c_str(), NULL);
+    if (acptr)
+        return *acceptor::cast(acptr);
+    else
+        throw error(MSG("accept fail: " <<
+                        pn_error_text(pn_io_error(pn_reactor_io(pn_cast(reactor_.get()))))
+                        << "(" << url << ")"));
+}
+
+std::string container_impl::next_link_name() {
+    std::ostringstream s;
+    // TODO aconway 2015-09-01: atomic operation
+    s << prefix_ << std::hex << ++link_id_;
+    return s.str();
+}
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/container_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/container_impl.hpp b/proton-c/bindings/cpp/src/container_impl.hpp
new file mode 100644
index 0000000..f02e36e
--- /dev/null
+++ b/proton-c/bindings/cpp/src/container_impl.hpp
@@ -0,0 +1,77 @@
+#ifndef PROTON_CPP_CONTAINERIMPL_H
+#define PROTON_CPP_CONTAINERIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "proton/export.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/connection.hpp"
+#include "proton/link.hpp"
+#include "proton/duration.hpp"
+
+#include "proton/reactor.h"
+
+#include <string>
+
+namespace proton {
+
+class dispatch_helper;
+class connection;
+class connector;
+class acceptor;
+class container;
+
+class container_impl
+{
+  public:
+    PN_CPP_EXTERN container_impl(container&, handler *, const std::string& id);
+    PN_CPP_EXTERN ~container_impl();
+    PN_CPP_EXTERN connection& connect(const url&, handler *h);
+    PN_CPP_EXTERN sender& create_sender(connection &connection, const std::string &addr, handler *h);
+    PN_CPP_EXTERN sender& create_sender(const url&);
+    PN_CPP_EXTERN receiver& create_receiver(connection &connection, const std::string &addr, bool dynamic, handler *h);
+    PN_CPP_EXTERN receiver& create_receiver(const url&);
+    PN_CPP_EXTERN class acceptor& listen(const url&);
+    PN_CPP_EXTERN duration timeout();
+    PN_CPP_EXTERN void timeout(duration timeout);
+
+    counted_ptr<pn_handler_t> cpp_handler(handler *h);
+
+    std::string next_link_name();
+
+  private:
+
+    container& container_;
+    PN_UNIQUE_PTR<reactor> reactor_;
+    handler *handler_;
+    PN_UNIQUE_PTR<messaging_adapter> messaging_adapter_;
+    PN_UNIQUE_PTR<handler> override_handler_;
+    PN_UNIQUE_PTR<handler> flow_controller_;
+    std::string container_id_;
+    uint64_t link_id_;
+    std::string prefix_;
+
+  friend class container;
+};
+
+}
+
+#endif  /*!PROTON_CPP_CONTAINERIMPL_H*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/contexts.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/contexts.cpp b/proton-c/bindings/cpp/src/contexts.cpp
new file mode 100644
index 0000000..4d17e54
--- /dev/null
+++ b/proton-c/bindings/cpp/src/contexts.cpp
@@ -0,0 +1,116 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "contexts.hpp"
+#include "msg.hpp"
+
+#include "proton/error.hpp"
+#include "proton/handler.hpp"
+
+#include "proton/object.h"
+#include "proton/message.h"
+#include "proton/session.h"
+#include "proton/link.h"
+
+namespace proton {
+
+namespace {
+
+// A proton class for counted c++ objects used as proton attachments
+extern pn_class_t* COUNTED_CONTEXT;
+#define CID_cpp_context CID_pn_void
+static const pn_class_t *cpp_context_reify(void *object) { return COUNTED_CONTEXT; }
+#define cpp_context_new NULL
+#define cpp_context_free NULL
+#define cpp_context_initialize NULL
+void cpp_context_incref(void* p) { proton::incref(reinterpret_cast<counted*>(p)); }
+void cpp_context_decref(void* p) { proton::decref(reinterpret_cast<counted*>(p)); }
+// Always return 1 to prevent the class finalizer logic running after we are deleted.
+int cpp_context_refcount(void* p) { return 1; }
+#define cpp_context_finalize NULL
+#define cpp_context_hashcode NULL
+#define cpp_context_compare NULL
+#define cpp_context_inspect NULL
+
+pn_class_t COUNTED_CONTEXT_ = PN_METACLASS(cpp_context);
+pn_class_t *COUNTED_CONTEXT = &COUNTED_CONTEXT_;
+}
+
+
+void set_context(pn_record_t* record, pn_handle_t handle, counted* value)
+{
+    pn_record_def(record, handle, COUNTED_CONTEXT);
+    pn_record_set(record, handle, value);
+}
+
+counted* get_context(pn_record_t* record, pn_handle_t handle) {
+    return reinterpret_cast<counted*>(pn_record_get(record, handle));
+}
+
+// Connection context
+
+PN_HANDLE(CONNECTION_CONTEXT)
+
+connection_context::connection_context() : default_session(), container_impl() {}
+connection_context::~connection_context() {}
+
+struct connection_context& connection_context::get(pn_connection_t* c) {
+    connection_context* ctx = reinterpret_cast<connection_context*>(
+        get_context(pn_connection_attachments(c), CONNECTION_CONTEXT));
+    if (!ctx) {
+        ctx = new connection_context();
+        set_context(pn_connection_attachments(c), CONNECTION_CONTEXT, ctx);
+    }
+    return *ctx;
+}
+
+PN_HANDLE(CONTAINER_CONTEXT)
+
+void container_context(pn_reactor_t *r, container& c) {
+    pn_record_t *record = pn_reactor_attachments(r);
+    pn_record_def(record, CONTAINER_CONTEXT, PN_VOID);
+    pn_record_set(record, CONTAINER_CONTEXT, &c);
+}
+
+container &container_context(pn_reactor_t *pn_reactor) {
+    pn_record_t *record = pn_reactor_attachments(pn_reactor);
+    container *ctx = reinterpret_cast<container*>(pn_record_get(record, CONTAINER_CONTEXT));
+    if (!ctx) throw error(MSG("Reactor has no C++ container context"));
+    return *ctx;
+}
+
+PN_HANDLE(EVENT_CONTEXT)
+
+void event_context(pn_event_t *pn_event, pn_message_t *m) {
+    pn_record_t *record = pn_event_attachments(pn_event);
+    pn_record_def(record, EVENT_CONTEXT, PN_OBJECT); // refcount it for life of the event
+    pn_record_set(record, EVENT_CONTEXT, m);
+}
+
+pn_message_t *event_context(pn_event_t *pn_event) {
+    if (!pn_event) return NULL;
+    pn_record_t *record = pn_event_attachments(pn_event);
+    pn_message_t *ctx = (pn_message_t *) pn_record_get(record, EVENT_CONTEXT);
+    return ctx;
+}
+
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/contexts.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/contexts.hpp b/proton-c/bindings/cpp/src/contexts.hpp
new file mode 100644
index 0000000..2285245
--- /dev/null
+++ b/proton-c/bindings/cpp/src/contexts.hpp
@@ -0,0 +1,61 @@
+#ifndef PROTON_CPP_CONTEXTS_H
+#define PROTON_CPP_CONTEXTS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/counted.hpp"
+#include "proton/reactor.h"
+#include "proton/memory.hpp"
+#include "proton/session.hpp"
+
+#include <proton/message.h>
+
+namespace proton {
+
+class session;
+class handler;
+class container_impl;
+
+counted* get_context(pn_record_t*, pn_handle_t handle);
+void set_context(pn_record_t*, pn_handle_t, counted* value);
+
+struct connection_context : public counted {
+    static connection_context& get(pn_connection_t* c);
+
+    connection_context();
+    ~connection_context();
+
+    PN_UNIQUE_PTR<class handler> handler;
+    session* default_session;   // Owned by connection
+    class container_impl* container_impl;
+};
+
+class container;
+void container_context(pn_reactor_t *, container&);
+container& container_context(pn_reactor_t *);
+
+void event_context(pn_event_t *pn_event, pn_message_t *m);
+pn_message_t *event_context(pn_event_t *pn_event);
+
+}
+
+#endif  /*!PROTON_CPP_CONTEXTS_H*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/conversion_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/conversion_test.cpp b/proton-c/bindings/cpp/src/conversion_test.cpp
new file mode 100644
index 0000000..84c96f4
--- /dev/null
+++ b/proton-c/bindings/cpp/src/conversion_test.cpp
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Pointer conversion test.
+// NOTE needs to be run with valgrind to be effective.
+
+
+#include "test_bits.hpp"
+#include "proton/connection.hpp"
+#include "proton/session.hpp"
+
+using namespace std;
+using namespace proton;
+
+template <class connection_ptr, class session_ptr>
+void test_owning() {
+
+    connection_ptr conn(connection::cast(pn_connection()));
+    session& s = conn->default_session();
+    session_ptr p = s.ptr();
+    session_ptr p2 = s.ptr();
+}
+
+template <class connection_ptr, class session_ptr>
+void test_counted() {
+    connection_ptr conn(connection::cast(pn_connection()), false);
+    session& s = conn->default_session();
+    session_ptr p = s.ptr();
+    session_ptr p2 = s.ptr();
+}
+
+void test_auto() {
+    std::auto_ptr<connection> conn(connection::cast(pn_connection()));
+    session& s = conn->default_session();
+    std::auto_ptr<session> p(s.ptr().release());
+}
+
+int main(int argc, char** argv) {
+    int failed = 0;
+    failed += run_test(&test_counted<counted_ptr<connection>,
+                       counted_ptr<session> >, "counted");
+
+    
+
+#if PN_HAS_STD_PTR
+    failed += run_test(&test_owning<std::shared_ptr<connection>,
+                       std::shared_ptr<session> >, "std::shared");
+    failed += run_test(&test_owning<std::unique_ptr<connection>,
+                       std::unique_ptr<session> >, "std::unique");
+#endif
+#if PN_HAS_BOOST
+    failed += run_test(&test_owning<boost::shared_ptr<connection>,
+                       boost::shared_ptr<session> >, "boost::shared");
+    failed += run_test(&test_counted<boost::intrusive_ptr<connection>,
+                       boost::intrusive_ptr<session> >, "boost::intrusive");
+#endif
+    return failed;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/data.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/data.cpp b/proton-c/bindings/cpp/src/data.cpp
new file mode 100644
index 0000000..fd11eaa
--- /dev/null
+++ b/proton-c/bindings/cpp/src/data.cpp
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "proton_bits.hpp"
+#include "proton/data.hpp"
+
+#include <proton/codec.h>
+
+namespace proton {
+
+void data::operator delete(void *p) { ::pn_data_free(reinterpret_cast<pn_data_t*>(p)); }
+
+data& data::operator=(const data& x) { ::pn_data_copy(pn_cast(this), pn_cast(&x)); return *this; }
+
+void data::clear() { ::pn_data_clear(pn_cast(this)); }
+
+bool data::empty() const { return ::pn_data_size(pn_cast(this)) == 0; }
+
+std::ostream& operator<<(std::ostream& o, const data& d) { return o << inspectable(pn_cast(&d)); }
+
+PN_UNIQUE_PTR<data> data::create() { return PN_UNIQUE_PTR<data>(cast(::pn_data(0))); }
+
+encoder& data::encoder() { return reinterpret_cast<class encoder&>(*this); }
+decoder& data::decoder() { return reinterpret_cast<class decoder&>(*this); }
+
+namespace {
+
+// Compare nodes, return -1 if a<b, 0 if a==b, +1 if a>b
+// Forward-declare so we can use it recursively.
+int compare_next(data& a, data& b);
+
+template <class T> int compare(const T& a, const T& b) {
+    if (a < b) return -1;
+    else if (a > b) return +1;
+    else return 0;
+}
+
+int compare_container(data& a, data& b) {
+    decoder::scope sa(a.decoder()), sb(b.decoder());
+    // Compare described vs. not-described.
+    int cmp = compare(sa.is_described, sb.is_described);
+    if (cmp) return cmp;
+    // Lexical sort (including descriptor if there is one)
+    size_t min_size = std::min(sa.size, sb.size) + int(sa.is_described);
+    for (size_t i = 0; i < min_size; ++i) {
+        cmp = compare_next(a, b);
+        if (cmp) return cmp;
+    }
+    return compare(sa.size, sb.size);
+}
+
+template <class T> int compare_simple(data& a, data& b) {
+    T va = T();
+    T vb = T();
+    a.decoder() >> va;
+    b.decoder() >> vb;
+    return compare(va, vb);
+}
+
+int compare_next(data& a, data& b) {
+    // Sort by type_id first.
+    type_id ta = a.type(), tb = b.type();
+    int cmp = compare(ta, tb);
+    if (cmp) return cmp;
+
+    switch (ta) {
+      case NULL_: return 0;
+      case ARRAY:
+      case LIST:
+      case MAP:
+      case DESCRIBED:
+        return compare_container(a, b);
+      case BOOL: return compare_simple<amqp_bool>(a, b);
+      case UBYTE: return compare_simple<amqp_ubyte>(a, b);
+      case BYTE: return compare_simple<amqp_byte>(a, b);
+      case USHORT: return compare_simple<amqp_ushort>(a, b);
+      case SHORT: return compare_simple<amqp_short>(a, b);
+      case UINT: return compare_simple<amqp_uint>(a, b);
+      case INT: return compare_simple<amqp_int>(a, b);
+      case CHAR: return compare_simple<amqp_char>(a, b);
+      case ULONG: return compare_simple<amqp_ulong>(a, b);
+      case LONG: return compare_simple<amqp_long>(a, b);
+      case TIMESTAMP: return compare_simple<amqp_timestamp>(a, b);
+      case FLOAT: return compare_simple<amqp_float>(a, b);
+      case DOUBLE: return compare_simple<amqp_double>(a, b);
+      case DECIMAL32: return compare_simple<amqp_decimal32>(a, b);
+      case DECIMAL64: return compare_simple<amqp_decimal64>(a, b);
+      case DECIMAL128: return compare_simple<amqp_decimal128>(a, b);
+      case UUID: return compare_simple<amqp_uuid>(a, b);
+      case BINARY: return compare_simple<amqp_binary>(a, b);
+      case STRING: return compare_simple<amqp_string>(a, b);
+      case SYMBOL: return compare_simple<amqp_symbol>(a, b);
+    }
+    // Invalid but equal type_id, treat as equal.
+    return 0;
+}
+
+int compare(data& a, data& b) {
+    a.decoder().rewind();
+    b.decoder().rewind();
+    while (a.decoder().more() && b.decoder().more()) {
+        int cmp = compare_next(a, b);
+        if (cmp != 0) return cmp;
+    }
+    if (b.decoder().more()) return -1;
+    if (a.decoder().more()) return 1;
+    return 0;
+}
+} // namespace
+
+bool data::operator==(const data& x) const {
+    return compare(const_cast<data&>(*this), const_cast<data&>(x)) == 0;
+}
+bool data::operator<(const data& x) const {
+    return compare(const_cast<data&>(*this), const_cast<data&>(x)) < 0;
+}
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/decoder.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/decoder.cpp b/proton-c/bindings/cpp/src/decoder.cpp
new file mode 100644
index 0000000..e118e5a
--- /dev/null
+++ b/proton-c/bindings/cpp/src/decoder.cpp
@@ -0,0 +1,328 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "proton/decoder.hpp"
+#include "proton/data.hpp"
+#include <proton/codec.h>
+#include "proton_bits.hpp"
+#include "msg.hpp"
+
+namespace proton {
+
+/**@file
+ *
+ * Note the pn_data_t "current" node is always pointing *before* the next value
+ * to be returned by the decoder.
+ *
+ */
+static const std::string prefix("decode: ");
+decode_error::decode_error(const std::string& msg) throw() : error(prefix+msg) {}
+
+namespace {
+struct save_state {
+    pn_data_t* data;
+    pn_handle_t handle;
+    save_state(pn_data_t* d) : data(d), handle(pn_data_point(d)) {}
+    ~save_state() { if (data) pn_data_restore(data, handle); }
+    void cancel() { data = 0; }
+};
+
+struct narrow {
+    pn_data_t* data;
+    narrow(pn_data_t* d) : data(d) { pn_data_narrow(d); }
+    ~narrow() { pn_data_widen(data); }
+};
+
+template <class T> T check(T result) {
+    if (result < 0)
+        throw decode_error("" + error_str(result));
+    return result;
+}
+
+}
+
+void decoder::decode(const char* i, size_t size) {
+    save_state ss(pn_cast(this));
+    const char* end = i + size;
+    while (i < end) {
+        i += check(pn_data_decode(pn_cast(this), i, end - i));
+    }
+}
+
+void decoder::decode(const std::string& buffer) {
+    decode(buffer.data(), buffer.size());
+}
+
+bool decoder::more() const {
+    save_state ss(pn_cast(this));
+    return pn_data_next(pn_cast(this));
+}
+
+void decoder::rewind() { ::pn_data_rewind(pn_cast(this)); }
+
+void decoder::backup() { ::pn_data_prev(pn_cast(this)); }
+
+data& decoder::data() { return *data::cast(pn_cast(this)); }
+
+namespace {
+
+void bad_type(type_id want, type_id got) {
+    if (want != got)
+        throw decode_error("expected "+type_name(want)+" found "+type_name(got));
+}
+
+type_id pre_get(pn_data_t* data) {
+    if (!pn_data_next(data)) throw decode_error("no more data");
+    type_id t = type_id(pn_data_type(data));
+    if (t < 0) throw decode_error("invalid data");
+    return t;
+}
+
+// Simple extract with no type conversion.
+template <class T, class U> void extract(pn_data_t* data, T& value, U (*get)(pn_data_t*)) {
+    save_state ss(data);
+    bad_type(type_id_of<T>::value, pre_get(data));
+    value = get(data);
+    ss.cancel();                // No error, no rewind
+}
+
+}
+
+void decoder::check_type(type_id want) {
+    type_id got = type();
+    if (want != got) bad_type(want, got);
+}
+
+type_id decoder::type() const {
+    save_state ss(pn_cast(this));
+    return pre_get(pn_cast(this));
+}
+
+decoder& operator>>(decoder& d, start& s) {
+    save_state ss(pn_cast(&d));
+    s.type = pre_get(pn_cast(&d));
+    switch (s.type) {
+      case ARRAY:
+        s.size = pn_data_get_array(pn_cast(&d));
+        s.element = type_id(pn_data_get_array_type(pn_cast(&d))); s.is_described = pn_data_is_array_described(pn_cast(&d));
+        break;
+      case LIST:
+        s.size = pn_data_get_list(pn_cast(&d));
+        break;
+      case MAP:
+        s.size = pn_data_get_map(pn_cast(&d));
+        break;
+      case DESCRIBED:
+        s.is_described = true;
+        s.size = 1;
+        break;
+      default:
+        throw decode_error(MSG("" << s.type << " is not a container type"));
+    }
+    pn_data_enter(pn_cast(&d));
+    ss.cancel();
+    return d;
+}
+
+decoder& operator>>(decoder& d, finish) { pn_data_exit(pn_cast(&d)); return d; }
+
+decoder& operator>>(decoder& d, skip) { pn_data_next(pn_cast(&d)); return d; }
+
+decoder& operator>>(decoder& d, rewind) { d.rewind(); return d; }
+
+decoder& operator>>(decoder& d, data& v) {
+    if (pn_cast(&d) == pn_cast(&v)) throw decode_error("extract into self");
+    v.clear();
+    {
+        narrow n(pn_cast(&d));
+        check(pn_data_appendn(pn_cast(&v), pn_cast(&d), 1));
+    }
+    if (!pn_data_next(pn_cast(&d))) throw decode_error("no more data");
+    return d;
+}
+
+
+decoder& operator>>(decoder& d, amqp_null) {
+    save_state ss(pn_cast(&d));
+    bad_type(NULL_, pre_get(pn_cast(&d)));
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_bool& value) {
+    extract(pn_cast(&d), value, pn_data_get_bool);
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_ubyte& value) {
+    save_state ss(pn_cast(&d));
+    switch (pre_get(pn_cast(&d))) {
+      case UBYTE: value = pn_data_get_ubyte(pn_cast(&d)); break;
+      default: bad_type(UBYTE, type_id(type_id(pn_data_type(pn_cast(&d)))));
+    }
+    ss.cancel();
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_byte& value) {
+    save_state ss(pn_cast(&d));
+    switch (pre_get(pn_cast(&d))) {
+      case BYTE: value = pn_data_get_byte(pn_cast(&d)); break;
+      default: bad_type(BYTE, type_id(type_id(pn_data_type(pn_cast(&d)))));
+    }
+    ss.cancel();
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_ushort& value) {
+    save_state ss(pn_cast(&d));
+    switch (pre_get(pn_cast(&d))) {
+      case UBYTE: value = pn_data_get_ubyte(pn_cast(&d)); break;
+      case USHORT: value = pn_data_get_ushort(pn_cast(&d)); break;
+      default: bad_type(USHORT, type_id(type_id(pn_data_type(pn_cast(&d)))));
+    }
+    ss.cancel();
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_short& value) {
+    save_state ss(pn_cast(&d));
+    switch (pre_get(pn_cast(&d))) {
+      case BYTE: value = pn_data_get_byte(pn_cast(&d)); break;
+      case SHORT: value = pn_data_get_short(pn_cast(&d)); break;
+      default: bad_type(SHORT, type_id(pn_data_type(pn_cast(&d))));
+    }
+    ss.cancel();
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_uint& value) {
+    save_state ss(pn_cast(&d));
+    switch (pre_get(pn_cast(&d))) {
+      case UBYTE: value = pn_data_get_ubyte(pn_cast(&d)); break;
+      case USHORT: value = pn_data_get_ushort(pn_cast(&d)); break;
+      case UINT: value = pn_data_get_uint(pn_cast(&d)); break;
+      default: bad_type(UINT, type_id(pn_data_type(pn_cast(&d))));
+    }
+    ss.cancel();
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_int& value) {
+    save_state ss(pn_cast(&d));
+    switch (pre_get(pn_cast(&d))) {
+      case BYTE: value = pn_data_get_byte(pn_cast(&d)); break;
+      case SHORT: value = pn_data_get_short(pn_cast(&d)); break;
+      case INT: value = pn_data_get_int(pn_cast(&d)); break;
+      default: bad_type(INT, type_id(pn_data_type(pn_cast(&d))));
+    }
+    ss.cancel();
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_ulong& value) {
+    save_state ss(pn_cast(&d));
+    switch (pre_get(pn_cast(&d))) {
+      case UBYTE: value = pn_data_get_ubyte(pn_cast(&d)); break;
+      case USHORT: value = pn_data_get_ushort(pn_cast(&d)); break;
+      case UINT: value = pn_data_get_uint(pn_cast(&d)); break;
+      case ULONG: value = pn_data_get_ulong(pn_cast(&d)); break;
+      default: bad_type(ULONG, type_id(pn_data_type(pn_cast(&d))));
+    }
+    ss.cancel();
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_long& value) {
+    save_state ss(pn_cast(&d));
+    switch (pre_get(pn_cast(&d))) {
+      case BYTE: value = pn_data_get_byte(pn_cast(&d)); break;
+      case SHORT: value = pn_data_get_short(pn_cast(&d)); break;
+      case INT: value = pn_data_get_int(pn_cast(&d)); break;
+      case LONG: value = pn_data_get_long(pn_cast(&d)); break;
+      default: bad_type(LONG, type_id(pn_data_type(pn_cast(&d))));
+    }
+    ss.cancel();
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_char& value) {
+    extract(pn_cast(&d), value, pn_data_get_char);
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_timestamp& value) {
+    extract(pn_cast(&d), value, pn_data_get_timestamp);
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_float& value) {
+    save_state ss(pn_cast(&d));
+    switch (pre_get(pn_cast(&d))) {
+      case FLOAT: value = pn_data_get_float(pn_cast(&d)); break;
+      case DOUBLE: value = pn_data_get_double(pn_cast(&d)); break;
+      default: bad_type(FLOAT, type_id(pn_data_type(pn_cast(&d))));
+    }
+    ss.cancel();
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_double& value) {
+    save_state ss(pn_cast(&d));
+    switch (pre_get(pn_cast(&d))) {
+      case FLOAT: value = pn_data_get_float(pn_cast(&d)); break;
+      case DOUBLE: value = pn_data_get_double(pn_cast(&d)); break;
+      default: bad_type(DOUBLE, type_id(pn_data_type(pn_cast(&d))));
+    }
+    ss.cancel();
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_decimal32& value) {
+    extract(pn_cast(&d), value, pn_data_get_decimal32);
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_decimal64& value) {
+    extract(pn_cast(&d), value, pn_data_get_decimal64);
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_decimal128& value)  {
+    extract(pn_cast(&d), value, pn_data_get_decimal128);
+    return d;
+}
+
+decoder& operator>>(decoder& d, amqp_uuid& value)  {
+    extract(pn_cast(&d), value, pn_data_get_uuid);
+    return d;
+}
+
+decoder& operator>>(decoder& d, std::string& value) {
+    save_state ss(pn_cast(&d));
+    switch (pre_get(pn_cast(&d))) {
+      case STRING: value = str(pn_data_get_string(pn_cast(&d))); break;
+      case BINARY: value = str(pn_data_get_binary(pn_cast(&d))); break;
+      case SYMBOL: value = str(pn_data_get_symbol(pn_cast(&d))); break;
+      default: bad_type(STRING, type_id(pn_data_type(pn_cast(&d))));
+    }
+    ss.cancel();
+    return d;
+}
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/delivery.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/delivery.cpp b/proton-c/bindings/cpp/src/delivery.cpp
new file mode 100644
index 0000000..1962fa2
--- /dev/null
+++ b/proton-c/bindings/cpp/src/delivery.cpp
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/delivery.hpp"
+#include "proton/delivery.h"
+
+namespace proton {
+
+bool delivery::settled() { return pn_delivery_settled(pn_cast(this)); }
+
+void delivery::settle() { pn_delivery_settle(pn_cast(this)); }
+
+void delivery::update(delivery::state state) { pn_delivery_update(pn_cast(this), state); }
+
+void delivery::settle(delivery::state state) {
+    update(state);
+    settle();
+}
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/duration.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/duration.cpp b/proton-c/bindings/cpp/src/duration.cpp
new file mode 100644
index 0000000..8c8263e
--- /dev/null
+++ b/proton-c/bindings/cpp/src/duration.cpp
@@ -0,0 +1,31 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "proton/duration.hpp"
+#include <limits>
+
+namespace proton {
+
+const duration duration::FOREVER(std::numeric_limits<amqp_ulong>::max());
+const duration duration::IMMEDIATE(0);
+const duration duration::SECOND(1000);
+const duration duration::MINUTE(SECOND * 60);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/encoder.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/encoder.cpp b/proton-c/bindings/cpp/src/encoder.cpp
new file mode 100644
index 0000000..9904b2a
--- /dev/null
+++ b/proton-c/bindings/cpp/src/encoder.cpp
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "proton/encoder.hpp"
+#include "proton/data.hpp"
+#include <proton/codec.h>
+#include "proton_bits.hpp"
+#include "msg.hpp"
+
+namespace proton {
+
+static const std::string prefix("encode: ");
+encode_error::encode_error(const std::string& msg) throw() : error(prefix+msg) {}
+
+namespace {
+struct save_state {
+    pn_data_t* data;
+    pn_handle_t handle;
+    save_state(pn_data_t* d) : data(d), handle(pn_data_point(d)) {}
+    ~save_state() { if (data) pn_data_restore(data, handle); }
+    void cancel() { data = 0; }
+};
+
+void check(int result, pn_data_t* data) {
+    if (result < 0)
+        throw encode_error(error_str(pn_data_error(data), result));
+}
+}
+
+bool encoder::encode(char* buffer, size_t& size) {
+    save_state ss(pn_cast(this)); // In case of error
+    ssize_t result = pn_data_encode(pn_cast(this), buffer, size);
+    if (result == PN_OVERFLOW) {
+        result = pn_data_encoded_size(pn_cast(this));
+        if (result >= 0) {
+            size = result;
+            return false;
+        }
+    }
+    check(result, pn_cast(this));
+    size = result;
+    ss.cancel();                // Don't restore state, all is well.
+    pn_data_clear(pn_cast(this));
+    return true;
+}
+
+void encoder::encode(std::string& s) {
+    size_t size = s.size();
+    if (!encode(&s[0], size)) {
+        s.resize(size);
+        encode(&s[0], size);
+    }
+}
+
+std::string encoder::encode() {
+    std::string s;
+    encode(s);
+    return s;
+}
+
+data& encoder::data() { return *data::cast(pn_cast(this)); }
+
+encoder& operator<<(encoder& e, const start& s) {
+    switch (s.type) {
+      case ARRAY: pn_data_put_array(pn_cast(&e), s.is_described, pn_type_t(s.element)); break;
+      case MAP: pn_data_put_map(pn_cast(&e)); break;
+      case LIST: pn_data_put_list(pn_cast(&e)); break;
+      case DESCRIBED: pn_data_put_described(pn_cast(&e)); break;
+      default:
+        throw encode_error(MSG("" << s.type << " is not a container type"));
+    }
+    pn_data_enter(pn_cast(&e));
+    return e;
+}
+
+encoder& operator<<(encoder& e, finish) {
+    pn_data_exit(pn_cast(&e));
+    return e;
+}
+
+namespace {
+template <class T, class U>
+encoder& insert(encoder& e, pn_data_t* data, T& value, int (*put)(pn_data_t*, U)) {
+    save_state ss(data);         // Save state in case of error.
+    check(put(data, value), data);
+    ss.cancel();                // Don't restore state, all is good.
+    return e;
+}
+}
+
+encoder& operator<<(encoder& e, amqp_null) { pn_data_put_null(pn_cast(&e)); return e; }
+encoder& operator<<(encoder& e, amqp_bool value) { return insert(e, pn_cast(&e), value, pn_data_put_bool); }
+encoder& operator<<(encoder& e, amqp_ubyte value) { return insert(e, pn_cast(&e), value, pn_data_put_ubyte); }
+encoder& operator<<(encoder& e, amqp_byte value) { return insert(e, pn_cast(&e), value, pn_data_put_byte); }
+encoder& operator<<(encoder& e, amqp_ushort value) { return insert(e, pn_cast(&e), value, pn_data_put_ushort); }
+encoder& operator<<(encoder& e, amqp_short value) { return insert(e, pn_cast(&e), value, pn_data_put_short); }
+encoder& operator<<(encoder& e, amqp_uint value) { return insert(e, pn_cast(&e), value, pn_data_put_uint); }
+encoder& operator<<(encoder& e, amqp_int value) { return insert(e, pn_cast(&e), value, pn_data_put_int); }
+encoder& operator<<(encoder& e, amqp_char value) { return insert(e, pn_cast(&e), value, pn_data_put_char); }
+encoder& operator<<(encoder& e, amqp_ulong value) { return insert(e, pn_cast(&e), value, pn_data_put_ulong); }
+encoder& operator<<(encoder& e, amqp_long value) { return insert(e, pn_cast(&e), value, pn_data_put_long); }
+encoder& operator<<(encoder& e, amqp_timestamp value) { return insert(e, pn_cast(&e), value, pn_data_put_timestamp); }
+encoder& operator<<(encoder& e, amqp_float value) { return insert(e, pn_cast(&e), value, pn_data_put_float); }
+encoder& operator<<(encoder& e, amqp_double value) { return insert(e, pn_cast(&e), value, pn_data_put_double); }
+encoder& operator<<(encoder& e, amqp_decimal32 value) { return insert(e, pn_cast(&e), value, pn_data_put_decimal32); }
+encoder& operator<<(encoder& e, amqp_decimal64 value) { return insert(e, pn_cast(&e), value, pn_data_put_decimal64); }
+encoder& operator<<(encoder& e, amqp_decimal128 value) { return insert(e, pn_cast(&e), value, pn_data_put_decimal128); }
+encoder& operator<<(encoder& e, amqp_uuid value) { return insert(e, pn_cast(&e), value, pn_data_put_uuid); }
+encoder& operator<<(encoder& e, amqp_string value) { return insert(e, pn_cast(&e), value, pn_data_put_string); }
+encoder& operator<<(encoder& e, amqp_symbol value) { return insert(e, pn_cast(&e), value, pn_data_put_symbol); }
+encoder& operator<<(encoder& e, amqp_binary value) { return insert(e, pn_cast(&e), value, pn_data_put_binary); }
+
+encoder& operator<<(encoder& e, const data& v) {
+    if (pn_cast(&e) == pn_cast(&v)) throw encode_error("cannot insert into self");
+    check(pn_data_append(pn_cast(&e), pn_cast(&v)), pn_cast(&e));
+    return e;
+}
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/endpoint.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/endpoint.cpp b/proton-c/bindings/cpp/src/endpoint.cpp
new file mode 100644
index 0000000..ed14937
--- /dev/null
+++ b/proton-c/bindings/cpp/src/endpoint.cpp
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/endpoint.hpp"
+#include "proton/connection.hpp"
+#include "proton/transport.hpp"
+#include "proton/connection.h"
+
+namespace proton {
+
+const int endpoint::LOCAL_UNINIT = PN_LOCAL_UNINIT;
+const int endpoint::REMOTE_UNINIT = PN_REMOTE_UNINIT;
+const int endpoint::LOCAL_ACTIVE = PN_LOCAL_ACTIVE;
+const int endpoint::REMOTE_ACTIVE = PN_REMOTE_ACTIVE;
+const int endpoint::LOCAL_CLOSED = PN_LOCAL_CLOSED;
+const int endpoint::REMOTE_CLOSED = PN_REMOTE_CLOSED;
+const int endpoint::LOCAL_MASK = PN_LOCAL_MASK;
+const int endpoint::REMOTE_MASK = PN_REMOTE_MASK;
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/error.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/error.cpp b/proton-c/bindings/cpp/src/error.cpp
new file mode 100644
index 0000000..fb409ef
--- /dev/null
+++ b/proton-c/bindings/cpp/src/error.cpp
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "proton/error.hpp"
+
+namespace proton {
+
+static const std::string prefix("proton: ");
+
+error::error(const std::string& msg) throw() : std::runtime_error(prefix+msg) {}
+
+timeout_error::timeout_error(const std::string& msg) throw() : error(msg) {}
+
+message_reject::message_reject(const std::string& msg) throw() : error(msg) {}
+
+message_release::message_release(const std::string& msg) throw() : error(msg) {}
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/event.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/event.cpp b/proton-c/bindings/cpp/src/event.cpp
new file mode 100644
index 0000000..d7a99dc
--- /dev/null
+++ b/proton-c/bindings/cpp/src/event.cpp
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/reactor.h"
+#include "proton/event.h"
+
+#include "proton/delivery.hpp"
+#include "proton/error.hpp"
+#include "proton/event.hpp"
+#include "proton/handler.hpp"
+#include "proton/receiver.hpp"
+#include "proton/sender.hpp"
+
+#include "msg.hpp"
+#include "contexts.hpp"
+
+namespace proton {
+
+event::event() {}
+
+event::~event() {}
+
+
+container &event::container() {
+    // Subclasses to override as appropriate
+    throw error(MSG("No container context for event"));
+}
+
+connection &event::connection() {
+    throw error(MSG("No connection context for event"));
+}
+
+sender& event::sender() {
+    throw error(MSG("No sender context for event"));
+}
+
+receiver& event::receiver() {
+    throw error(MSG("No receiver context for event"));
+}
+
+link& event::link() {
+    throw error(MSG("No link context for event"));
+}
+
+delivery& event::delivery() {
+    throw error(MSG("No link context for event"));
+}
+
+class message &event::message() {
+    throw error(MSG("No message associated with event"));
+}
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/facade.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/facade.cpp b/proton-c/bindings/cpp/src/facade.cpp
new file mode 100644
index 0000000..6d0291a
--- /dev/null
+++ b/proton-c/bindings/cpp/src/facade.cpp
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "proton/facade.hpp"
+#include <proton/object.h>
+
+#if PN_HAS_CPP11
+#include <type_traits>
+#endif
+
+#include <assert.h>
+
+// For empty check.
+#include "proton/acceptor.hpp"
+#include "proton/connection.hpp"
+#include "proton/data.hpp"
+#include "proton/decoder.hpp"
+#include "proton/delivery.hpp"
+#include "proton/encoder.hpp"
+#include "proton/facade.hpp"
+#include "proton/link.hpp"
+#include "proton/message.hpp"
+#include "proton/session.hpp"
+#include "proton/terminus.hpp"
+#include "proton/transport.hpp"
+
+namespace proton {
+
+void incref(const void* p) {
+    if (p) ::pn_incref(const_cast<void*>(p));
+}
+
+void decref(const void* p) {
+    if (p) ::pn_decref(const_cast<void*>(p));
+}
+
+// Make sure facade types are empty.
+#if PN_HAS_CPP11
+#define CHECK_EMPTY(T) static_assert(std::is_empty<T>::value,  "facade " #T " not empty")
+#else
+#define CHECK_EMPTY(T) struct T##_CHECK_EMPTY__ { char T##__facade_not_empty[sizeof(T) == 1 ? 1 : -1]; }
+#endif
+
+CHECK_EMPTY(acceptor);
+CHECK_EMPTY(connection);
+CHECK_EMPTY(data);
+CHECK_EMPTY(decoder);
+CHECK_EMPTY(delivery);
+CHECK_EMPTY(encoder);
+CHECK_EMPTY(link);
+CHECK_EMPTY(message);
+CHECK_EMPTY(session);
+CHECK_EMPTY(terminus);
+CHECK_EMPTY(transport);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/grep
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/grep b/proton-c/bindings/cpp/src/grep
new file mode 100644
index 0000000..2842f5c
--- /dev/null
+++ b/proton-c/bindings/cpp/src/grep
@@ -0,0 +1,47 @@
+  /home/aconway/proton/proton-c/bindings/cpp/src:
+  total used in directory 256 available 122608224
+  drwxrwxr-x. 3 aconway aconway  4096 Jun 11 14:47 .
+  drwxrwxr-x. 4 aconway aconway  4096 Jun 11 14:48 ..
+  -rw-rw-r--. 1 aconway aconway  1478 Jun 10 08:40 Acceptor.cpp
+  -rw-rw-r--. 1 aconway aconway  1401 Jun 10 08:40 Acking.cpp
+  -rw-rw-r--. 1 aconway aconway  1295 Jun 11 14:45 proton_bits.cpp
+  -rw-rw-r--. 1 aconway aconway   915 Jun 11 14:44 proton_bits.h
+  drwxrwxr-x. 2 aconway aconway  4096 Jun 10 08:40 blocking
+  -rw-rw-r--. 1 aconway aconway  2390 Jun 10 08:40 Connection.cpp
+  -rw-rw-r--. 1 aconway aconway  4285 Jun 10 08:40 ConnectionImpl.cpp
+  -rw-rw-r--. 1 aconway aconway  2531 Jun 10 08:40 ConnectionImpl.h
+  -rw-rw-r--. 1 aconway aconway  2131 Jun 10 08:40 connector.cpp
+  -rw-rw-r--. 1 aconway aconway  1624 Jun 10 08:40 connector.h
+  -rw-rw-r--. 1 aconway aconway  3188 Jun 10 08:40 Container.cpp
+  -rw-rw-r--. 1 aconway aconway 12183 Jun 10 08:40 ContainerImpl.cpp
+  -rw-rw-r--. 1 aconway aconway  2689 Jun 10 08:40 ContainerImpl.h
+  -rw-rw-r--. 1 aconway aconway  2846 Jun 10 08:40 contexts.cpp
+  -rw-rw-r--. 1 aconway aconway  1764 Jun 10 08:40 contexts.h
+  -rw-rw-r--. 1 aconway aconway  4992 Jun 11 14:45 Data.cpp
+  -rw-rw-r--. 1 aconway aconway  4494 Jun 11 14:46 Decoder.cpp
+  -rw-rw-r--. 1 aconway aconway  1590 Jun 10 08:40 Delivery.cpp
+  -rw-rw-r--. 1 aconway aconway  1752 Jun 10 08:40 Duration.cpp
+  -rw-rw-r--. 1 aconway aconway  3933 Jun 11 14:47 Encoder.cpp
+  -rw-rw-r--. 1 aconway aconway  1125 Jun 10 08:40 Endpoint.cpp
+  -rw-rw-r--. 1 aconway aconway  1882 Jun 10 08:40 Event.cpp
+  -rw-rw-r--. 1 aconway aconway  1315 Jun 10 08:40 Handler.cpp
+  -rw-rw-r--. 1 aconway aconway  4220 Jun 11 11:13 interop_test.cpp
+  -rw-rw-r--. 1 aconway aconway  2821 Jun 10 08:40 Link.cpp
+  -rw-rw-r--. 1 aconway aconway 13358 Jun 10 08:40 Message.cpp
+  -rw-rw-r--. 1 aconway aconway 13424 Jun 10 08:40 MessagingAdapter.cpp
+  -rw-rw-r--. 1 aconway aconway  5864 Jun 10 08:40 MessagingEvent.cpp
+  -rw-rw-r--. 1 aconway aconway  5230 Jun 10 08:40 MessagingHandler.cpp
+  -rw-rw-r--. 1 aconway aconway  2587 Jun 10 08:40 Msg.h
+  -rw-rw-r--. 1 aconway aconway  3000 Jun 10 08:40 PrivateImplRef.h
+  -rw-rw-r--. 1 aconway aconway  6032 Jun 10 08:40 ProtonEvent.cpp
+  -rw-rw-r--. 1 aconway aconway  3818 Jun 10 08:40 ProtonHandler.cpp
+  -rw-rw-r--. 1 aconway aconway  2209 Jun 10 08:40 ProtonImplRef.h
+  -rw-rw-r--. 1 aconway aconway  1396 Jun 10 08:40 Receiver.cpp
+  -rw-rw-r--. 1 aconway aconway  2119 Jun 10 08:40 Sender.cpp
+  -rw-rw-r--. 1 aconway aconway  2031 Jun 10 08:40 Session.cpp
+  -rw-rw-r--. 1 aconway aconway  2850 Jun 10 08:40 Terminus.cpp
+  -rw-rw-r--. 1 aconway aconway  1234 Jun 10 08:40 Transport.cpp
+  -rw-rw-r--. 1 aconway aconway  6251 Jun 10 18:27 types.cpp
+  -rw-rw-r--. 1 aconway aconway  1942 Jun 10 08:40 Url.cpp
+  -rw-rw-r--. 1 aconway aconway  1469 Jun 10 08:40 Url.h
+  -rw-rw-r--. 1 aconway aconway  2211 Jun 11 14:47 Value.cpp

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/handler.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/handler.cpp b/proton-c/bindings/cpp/src/handler.cpp
new file mode 100644
index 0000000..8e0f675
--- /dev/null
+++ b/proton-c/bindings/cpp/src/handler.cpp
@@ -0,0 +1,35 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "proton/handler.hpp"
+#include "proton/event.hpp"
+
+namespace proton {
+
+handler::handler() {}
+handler::~handler() {}
+
+void handler::on_unhandled(event &e) {}
+
+void handler::add_child_handler(handler &e) {
+    push_back(&e);
+}
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/interop_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/interop_test.cpp b/proton-c/bindings/cpp/src/interop_test.cpp
new file mode 100644
index 0000000..8637d45
--- /dev/null
+++ b/proton-c/bindings/cpp/src/interop_test.cpp
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "proton/decoder.hpp"
+#include "proton/encoder.hpp"
+#include "proton/data.hpp"
+#include "test_bits.hpp"
+#include <string>
+#include <sstream>
+#include <fstream>
+#include <streambuf>
+#include <iosfwd>
+
+using namespace std;
+using namespace proton;
+
+std::string tests_dir;
+
+string read(string filename) {
+    filename = tests_dir+string("/interop/")+filename+string(".amqp");
+    ifstream ifs(filename.c_str());
+    if (!ifs.good()) FAIL("Can't open " << filename);
+    return string(istreambuf_iterator<char>(ifs), istreambuf_iterator<char>());
+}
+
+template <class T> T get(decoder& d) { return d.get_as<T, type_id_of<T>::value>(); }
+
+template <class T> std::string str(const T& value) {
+    ostringstream oss;
+    oss << value;
+    return oss.str();
+}
+
+// Test data ostream operator
+void test_data_ostream() {
+    data_value dv;
+    dv.decoder().decode(read("primitives"));
+    ASSERT_EQUAL("true, false, 42, 42, -42, 12345, -12345, 12345, -12345, 0.125, 0.125", str(dv));
+}
+
+// Test extracting to exact AMQP types works corectly, extrating to invalid types fails.
+void test_decoder_primitves_exact() {
+    data_value dv;
+    dv.decoder().decode(read("primitives"));
+    decoder& d(dv.decoder());
+    ASSERT(d.more());
+    try { get< ::int8_t>(d); FAIL("got bool as byte"); } catch(decode_error){}
+    ASSERT_EQUAL(true, get<bool>(d));
+    ASSERT_EQUAL(false, get<bool>(d));
+    try { get< ::int8_t>(d); FAIL("got ubyte as byte"); } catch(decode_error){}
+    ASSERT_EQUAL(42, get< ::uint8_t>(d));
+    try { get< ::int32_t>(d); FAIL("got uint as ushort"); } catch(decode_error){}
+    ASSERT_EQUAL(42, get< ::uint16_t>(d));
+    try { get< ::uint16_t>(d); FAIL("got short as ushort"); } catch(decode_error){}
+    ASSERT_EQUAL(-42, get< ::int16_t>(d));
+    ASSERT_EQUAL(12345, get< ::uint32_t>(d));
+    ASSERT_EQUAL(-12345, get< ::int32_t>(d));
+    ASSERT_EQUAL(12345, get< ::uint64_t>(d));
+    ASSERT_EQUAL(-12345, get< ::int64_t>(d));
+    try { get<double>(d); FAIL("got float as double"); } catch(decode_error){}
+    ASSERT_EQUAL(0.125, get<float>(d));
+    try { get<float>(d); FAIL("got double as float"); } catch(decode_error){}
+    ASSERT_EQUAL(0.125, get<double>(d));
+    ASSERT(!d.more());
+}
+
+// Test inserting primitive sand encoding as AMQP.
+void test_encoder_primitives() {
+    data_value dv;
+    encoder& e = dv.encoder();
+    e << true << false;
+    e << ::uint8_t(42);
+    e << ::uint16_t(42) << ::int16_t(-42);
+    e << ::uint32_t(12345) << ::int32_t(-12345);
+    e << ::uint64_t(12345) << ::int64_t(-12345);
+    e << float(0.125) << double(0.125);
+    ASSERT_EQUAL("true, false, 42, 42, -42, 12345, -12345, 12345, -12345, 0.125, 0.125", str(e.data()));
+    std::string data = e.encode();
+    ASSERT_EQUAL(read("primitives"), data);
+}
+
+// Test type conversions.
+void test_value_conversions() {
+    data_value v;
+    ASSERT_EQUAL(true, bool(v = true));
+    ASSERT_EQUAL(2, int(v=amqp_byte(2)));
+    ASSERT_EQUAL(3, long(v=amqp_byte(3)));
+    ASSERT_EQUAL(3, long(v=amqp_byte(3)));
+    ASSERT_EQUAL(1.0, double(v=amqp_float(1.0)));
+    ASSERT_EQUAL(1.0, float(v=amqp_double(1.0)));
+    try { (void)bool(v = amqp_byte(1)); FAIL("got byte as bool"); } catch (decode_error) {}
+    try { (void)float(v = true); FAIL("got bool as float"); } catch (decode_error) {}
+}
+
+// TODO aconway 2015-06-11: interop test is not complete.
+
+int main(int argc, char** argv) {
+    int failed = 0;
+    if (argc != 2) FAIL("Usage: " << argv[0] << " tests-dir");
+    tests_dir = argv[1];
+
+    failed += RUN_TEST(test_data_ostream);
+    failed += RUN_TEST(test_decoder_primitves_exact);
+    failed += RUN_TEST(test_encoder_primitives);
+    failed += RUN_TEST(test_value_conversions);
+    return failed;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/link.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/link.cpp b/proton-c/bindings/cpp/src/link.cpp
new file mode 100644
index 0000000..12c8790
--- /dev/null
+++ b/proton-c/bindings/cpp/src/link.cpp
@@ -0,0 +1,92 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "proton/link.hpp"
+#include "proton/error.hpp"
+#include "proton/connection.hpp"
+#include "container_impl.hpp"
+#include "msg.hpp"
+#include "contexts.hpp"
+
+#include "proton/connection.h"
+#include "proton/session.h"
+#include "proton/link.h"
+
+namespace proton {
+
+void link::open() {
+    pn_link_open(pn_cast(this));
+}
+
+void link::close() {
+    pn_link_close(pn_cast(this));
+}
+
+bool link::is_sender() { return pn_link_is_sender(pn_cast(this)); }
+bool link::is_receiver() { return pn_link_is_receiver(pn_cast(this)); }
+
+sender& link::sender() {
+    if (!is_sender()) throw error("link is not a sender");
+    return *reinterpret_cast<class sender*>(this);
+}
+
+receiver& link::receiver() {
+    if (!is_receiver()) throw error("link is not a receiver");
+    return *reinterpret_cast<class receiver*>(this);
+}
+
+int link::credit() {
+    return pn_link_credit(pn_cast(this));
+}
+
+bool link::has_source() { return pn_link_source(pn_cast(this)); }
+bool link::has_target() { return pn_link_target(pn_cast(this)); }
+bool link::has_remote_source() { return pn_link_remote_source(pn_cast(this)); }
+bool link::has_remote_target() { return pn_link_remote_target(pn_cast(this)); }
+
+terminus& link::source() { return *terminus::cast(pn_link_source(pn_cast(this))); }
+terminus& link::target() { return *terminus::cast(pn_link_target(pn_cast(this))); }
+terminus& link::remote_source() { return *terminus::cast(pn_link_remote_source(pn_cast(this))); }
+terminus& link::remote_target() { return *terminus::cast(pn_link_remote_target(pn_cast(this))); }
+
+std::string link::name() { return std::string(pn_link_name(pn_cast(this)));}
+
+class connection &link::connection() {
+    return *connection::cast(pn_session_connection(pn_link_session(pn_cast(this))));
+}
+
+link* link::next(endpoint::state mask) {
+    return link::cast(pn_link_next(pn_cast(this), (pn_state_t) mask));
+}
+
+void link::handler(class handler &h) {
+    pn_record_t *record = pn_link_attachments(pn_cast(this));
+    connection_context& cc(connection_context::get(pn_cast(&connection())));
+    counted_ptr<pn_handler_t> chandler = cc.container_impl->cpp_handler(&h);
+    pn_record_set_handler(record, chandler.get());
+}
+
+void link::detach_handler() {
+    pn_record_t *record = pn_link_attachments(pn_cast(this));
+    pn_record_set_handler(record, 0);
+}
+
+endpoint::state link::state() { return pn_link_state(pn_cast(this)); }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/message.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/message.cpp b/proton-c/bindings/cpp/src/message.cpp
new file mode 100644
index 0000000..9b26bac
--- /dev/null
+++ b/proton-c/bindings/cpp/src/message.cpp
@@ -0,0 +1,215 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/message.hpp"
+#include "proton/error.hpp"
+#include "proton/link.hpp"
+#include "proton/delivery.hpp"
+#include "proton/message.h"
+#include "proton/sender.hpp"
+#include "proton/receiver.hpp"
+#include "proton/delivery.h"
+#include "msg.hpp"
+#include "proton_bits.hpp"
+
+#include <cstring>
+#include <assert.h>
+
+namespace proton {
+
+void message::operator delete(void *p) { ::pn_message_free(reinterpret_cast<pn_message_t*>(p)); }
+
+PN_UNIQUE_PTR<message> message::create() { return PN_UNIQUE_PTR<message>(cast(::pn_message())); }
+
+message& message::operator=(const message& m) {
+    // TODO aconway 2015-08-10: need more efficient pn_message_copy function
+    std::string data;
+    m.encode(data);
+    decode(data);
+    return *this;
+}
+
+void message::clear() { pn_message_clear(pn_cast(this)); }
+
+namespace {
+void check(int err) {
+    if (err) throw error(error_str(err));
+}
+
+} // namespace
+
+void message::id(const data& id) { *data::cast(pn_message_id(pn_cast(this))) = id; }
+const data& message::id() const { return *data::cast(pn_message_id(pn_cast(this))); }
+data& message::id() { return *data::cast(pn_message_id(pn_cast(this))); }
+
+void message::user(const std::string &id) {
+    check(pn_message_set_user_id(pn_cast(this), pn_bytes(id)));
+}
+
+std::string message::user() const {
+    return str(pn_message_get_user_id(pn_cast(this)));
+}
+
+void message::address(const std::string &addr) {
+    check(pn_message_set_address(pn_cast(this), addr.c_str()));
+}
+
+std::string message::address() const {
+    const char* addr = pn_message_get_address(pn_cast(this));
+    return addr ? std::string(addr) : std::string();
+}
+
+void message::subject(const std::string &s) {
+    check(pn_message_set_subject(pn_cast(this), s.c_str()));
+}
+
+std::string message::subject() const {
+    const char* s = pn_message_get_subject(pn_cast(this));
+    return s ? std::string(s) : std::string();
+}
+
+void message::reply_to(const std::string &s) {
+    check(pn_message_set_reply_to(pn_cast(this), s.c_str()));
+}
+
+std::string message::reply_to() const {
+    const char* s = pn_message_get_reply_to(pn_cast(this));
+    return s ? std::string(s) : std::string();
+}
+
+void message::correlation_id(const data& id) {
+    *data::cast(pn_message_correlation_id(pn_cast(this))) = id;
+}
+
+const data& message::correlation_id() const {
+    return *data::cast(pn_message_correlation_id(pn_cast(this)));
+}
+
+data& message::correlation_id() {
+    return *data::cast(pn_message_correlation_id(pn_cast(this)));
+}
+
+void message::content_type(const std::string &s) {
+    check(pn_message_set_content_type(pn_cast(this), s.c_str()));
+}
+
+std::string message::content_type() const {
+    const char* s = pn_message_get_content_type(pn_cast(this));
+    return s ? std::string(s) : std::string();
+}
+
+void message::content_encoding(const std::string &s) {
+    check(pn_message_set_content_encoding(pn_cast(this), s.c_str()));
+}
+
+std::string message::content_encoding() const {
+    const char* s = pn_message_get_content_encoding(pn_cast(this));
+    return s ? std::string(s) : std::string();
+}
+
+void message::expiry(amqp_timestamp t) {
+    pn_message_set_expiry_time(pn_cast(this), t.milliseconds);
+}
+amqp_timestamp message::expiry() const {
+    return amqp_timestamp(pn_message_get_expiry_time(pn_cast(this)));
+}
+
+void message::creation_time(amqp_timestamp t) {
+    pn_message_set_creation_time(pn_cast(this), t);
+}
+amqp_timestamp message::creation_time() const {
+    return pn_message_get_creation_time(pn_cast(this));
+}
+
+void message::group_id(const std::string &s) {
+    check(pn_message_set_group_id(pn_cast(this), s.c_str()));
+}
+
+std::string message::group_id() const {
+    const char* s = pn_message_get_group_id(pn_cast(this));
+    return s ? std::string(s) : std::string();
+}
+
+void message::reply_to_group_id(const std::string &s) {
+    check(pn_message_set_reply_to_group_id(pn_cast(this), s.c_str()));
+}
+
+std::string message::reply_to_group_id() const {
+    const char* s = pn_message_get_reply_to_group_id(pn_cast(this));
+    return s ? std::string(s) : std::string();
+}
+
+void message::body(const data& v) { body() = v; }
+
+const data& message::body() const {
+    return *data::cast(pn_message_body(pn_cast(this)));
+}
+
+data& message::body() {
+    return *data::cast(pn_message_body(pn_cast(this)));
+}
+
+void message::encode(std::string &s) const {
+    size_t sz = s.capacity();
+    if (sz < 512) sz = 512;
+    while (true) {
+        s.resize(sz);
+        int err = pn_message_encode(pn_cast(this), (char *) s.data(), &sz);
+        if (err) {
+            if (err != PN_OVERFLOW)
+                check(err);
+        } else {
+            s.resize(sz);
+            return;
+        }
+        sz *= 2;
+    }
+}
+
+std::string message::encode() const {
+    std::string data;
+    encode(data);
+    return data;
+}
+
+void message::decode(const std::string &s) {
+    check(pn_message_decode(pn_cast(this), s.data(), s.size()));
+}
+
+void message::decode(proton::link &link, proton::delivery &delivery) {
+    std::string buf;
+    buf.resize(pn_delivery_pending(pn_cast(&delivery)));
+    ssize_t n = pn_link_recv(pn_cast(&link), (char *) buf.data(), buf.size());
+    if (n != (ssize_t) buf.size()) throw error(MSG("link read failure"));
+    clear();
+    decode(buf);
+    pn_link_advance(pn_cast(&link));
+}
+
+void message_value::swap(message_value& x) {
+    // This works with unique_ptr and auto_ptr (which has no swap)
+    message* a = message_.release();
+    message* b = x.message_.release();
+    message_.reset(b);
+    x.message_.reset(a);
+}
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/src/messaging_adapter.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/messaging_adapter.cpp b/proton-c/bindings/cpp/src/messaging_adapter.cpp
new file mode 100644
index 0000000..39d80b8
--- /dev/null
+++ b/proton-c/bindings/cpp/src/messaging_adapter.cpp
@@ -0,0 +1,395 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "proton/messaging_adapter.hpp"
+#include "proton/messaging_event.hpp"
+#include "proton/sender.hpp"
+#include "proton/error.hpp"
+#include "msg.hpp"
+
+#include "proton/link.h"
+#include "proton/handlers.h"
+#include "proton/delivery.h"
+#include "proton/connection.h"
+#include "proton/session.h"
+
+namespace proton {
+messaging_adapter::messaging_adapter(messaging_handler &delegate_) :
+    messaging_handler(true, delegate_.prefetch_, delegate_.auto_settle_, delegate_.auto_accept_, delegate_.peer_close_iserror_),
+    delegate_(delegate_)
+{}
+
+
+messaging_adapter::~messaging_adapter(){}
+
+
+void messaging_adapter::on_reactor_init(event &e) {
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        messaging_event mevent(messaging_event::START, *pe);
+        delegate_.on_start(mevent);
+    }
+}
+
+void messaging_adapter::on_link_flow(event &e) {
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_event_t *pne = pe->pn_event();
+        pn_link_t *lnk = pn_event_link(pne);
+        if (lnk && pn_link_is_sender(lnk) && pn_link_credit(lnk) > 0) {
+            // create on_message extended event
+            messaging_event mevent(messaging_event::SENDABLE, *pe);
+            delegate_.on_sendable(mevent);;
+        }
+   }
+}
+
+void messaging_adapter::on_delivery(event &e) {
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_event_t *cevent = pe->pn_event();
+        pn_link_t *lnk = pn_event_link(cevent);
+        pn_delivery_t *dlv = pn_event_delivery(cevent);
+
+        if (pn_link_is_receiver(lnk)) {
+            if (!pn_delivery_partial(dlv) && pn_delivery_readable(dlv)) {
+                // generate on_message
+                messaging_event mevent(messaging_event::MESSAGE, *pe);
+                mevent.message_.decode(*reinterpret_cast<link*>(lnk), *reinterpret_cast<delivery*>(dlv));
+                if (pn_link_state(lnk) & PN_LOCAL_CLOSED) {
+                    if (auto_accept_) {
+                        pn_delivery_update(dlv, PN_RELEASED);
+                        pn_delivery_settle(dlv);
+                    }
+                }
+                else {
+                    try {
+                        delegate_.on_message(mevent);
+                        if (auto_accept_) {
+                            pn_delivery_update(dlv, PN_ACCEPTED);
+                            pn_delivery_settle(dlv);
+                        }
+                    }
+                    catch (message_reject &) {
+                        pn_delivery_update(dlv, PN_REJECTED);
+                        pn_delivery_settle(dlv);
+                    }
+                    catch (message_release &) {
+                        pn_delivery_update(dlv, PN_REJECTED);
+                        pn_delivery_settle(dlv);
+                    }
+                }
+            }
+            else if (pn_delivery_updated(dlv) && pn_delivery_settled(dlv)) {
+                messaging_event mevent(messaging_event::SETTLED, *pe);
+                delegate_.on_settled(mevent);
+            }
+        } else {
+            // sender
+            if (pn_delivery_updated(dlv)) {
+                amqp_ulong rstate = pn_delivery_remote_state(dlv);
+                if (rstate == PN_ACCEPTED) {
+                    messaging_event mevent(messaging_event::ACCEPTED, *pe);
+                    delegate_.on_accepted(mevent);
+                }
+                else if (rstate == PN_REJECTED) {
+                    messaging_event mevent(messaging_event::REJECTED, *pe);
+                    delegate_.on_rejected(mevent);
+                }
+                else if (rstate == PN_RELEASED || rstate == PN_MODIFIED) {
+                    messaging_event mevent(messaging_event::RELEASED, *pe);
+                    delegate_.on_released(mevent);
+                }
+
+                if (pn_delivery_settled(dlv)) {
+                    messaging_event mevent(messaging_event::SETTLED, *pe);
+                    delegate_.on_settled(mevent);
+                }
+                if (auto_settle_)
+                    pn_delivery_settle(dlv);
+            }
+        }
+    }
+}
+
+namespace {
+
+bool is_local_open(pn_state_t state) {
+    return state & PN_LOCAL_ACTIVE;
+}
+
+bool is_local_unititialised(pn_state_t state) {
+    return state & PN_LOCAL_UNINIT;
+}
+
+bool is_local_closed(pn_state_t state) {
+    return state & PN_LOCAL_CLOSED;
+}
+
+bool is_remote_open(pn_state_t state) {
+    return state & PN_REMOTE_ACTIVE;
+}
+
+} // namespace
+
+void messaging_adapter::on_link_remote_close(event &e) {
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_event_t *cevent = pe->pn_event();
+        pn_link_t *lnk = pn_event_link(cevent);
+        pn_state_t state = pn_link_state(lnk);
+        if (pn_condition_is_set(pn_link_remote_condition(lnk))) {
+            messaging_event mevent(messaging_event::LINK_ERROR, *pe);
+            on_link_error(mevent);
+        }
+        else if (is_local_closed(state)) {
+            messaging_event mevent(messaging_event::LINK_CLOSED, *pe);
+            on_link_closed(mevent);
+        }
+        else {
+            messaging_event mevent(messaging_event::LINK_CLOSING, *pe);
+            on_link_closing(mevent);
+        }
+        pn_link_close(lnk);
+    }
+}
+
+void messaging_adapter::on_session_remote_close(event &e) {
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_event_t *cevent = pe->pn_event();
+        pn_session_t *session = pn_event_session(cevent);
+        pn_state_t state = pn_session_state(session);
+        if (pn_condition_is_set(pn_session_remote_condition(session))) {
+            messaging_event mevent(messaging_event::SESSION_ERROR, *pe);
+            on_session_error(mevent);
+        }
+        else if (is_local_closed(state)) {
+            messaging_event mevent(messaging_event::SESSION_CLOSED, *pe);
+            on_session_closed(mevent);
+        }
+        else {
+            messaging_event mevent(messaging_event::SESSION_CLOSING, *pe);
+            on_session_closing(mevent);
+        }
+        pn_session_close(session);
+    }
+}
+
+void messaging_adapter::on_connection_remote_close(event &e) {
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_event_t *cevent = pe->pn_event();
+        pn_connection_t *connection = pn_event_connection(cevent);
+        pn_state_t state = pn_connection_state(connection);
+        if (pn_condition_is_set(pn_connection_remote_condition(connection))) {
+            messaging_event mevent(messaging_event::CONNECTION_ERROR, *pe);
+            on_connection_error(mevent);
+        }
+        else if (is_local_closed(state)) {
+            messaging_event mevent(messaging_event::CONNECTION_CLOSED, *pe);
+            on_connection_closed(mevent);
+        }
+        else {
+            messaging_event mevent(messaging_event::CONNECTION_CLOSING, *pe);
+            on_connection_closing(mevent);
+        }
+        pn_connection_close(connection);
+    }
+}
+
+void messaging_adapter::on_connection_local_open(event &e) {
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_connection_t *connection = pn_event_connection(pe->pn_event());
+        if (is_remote_open(pn_connection_state(connection))) {
+            messaging_event mevent(messaging_event::CONNECTION_OPENED, *pe);
+            on_connection_opened(mevent);
+        }
+    }
+}
+
+void messaging_adapter::on_connection_remote_open(event &e) {
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_connection_t *connection = pn_event_connection(pe->pn_event());
+        if (is_local_open(pn_connection_state(connection))) {
+            messaging_event mevent(messaging_event::CONNECTION_OPENED, *pe);
+            on_connection_opened(mevent);
+        }
+        else if (is_local_unititialised(pn_connection_state(connection))) {
+            messaging_event mevent(messaging_event::CONNECTION_OPENING, *pe);
+            on_connection_opening(mevent);
+            pn_connection_open(connection);
+        }
+    }
+}
+
+void messaging_adapter::on_session_local_open(event &e) {
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_session_t *session = pn_event_session(pe->pn_event());
+        if (is_remote_open(pn_session_state(session))) {
+            messaging_event mevent(messaging_event::SESSION_OPENED, *pe);
+            on_session_opened(mevent);
+        }
+    }
+}
+
+void messaging_adapter::on_session_remote_open(event &e) {
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_session_t *session = pn_event_session(pe->pn_event());
+        if (is_local_open(pn_session_state(session))) {
+            messaging_event mevent(messaging_event::SESSION_OPENED, *pe);
+            on_session_opened(mevent);
+        }
+        else if (is_local_unititialised(pn_session_state(session))) {
+            messaging_event mevent(messaging_event::SESSION_OPENING, *pe);
+            on_session_opening(mevent);
+            pn_session_open(session);
+        }
+    }
+}
+
+void messaging_adapter::on_link_local_open(event &e) {
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_link_t *link = pn_event_link(pe->pn_event());
+        if (is_remote_open(pn_link_state(link))) {
+            messaging_event mevent(messaging_event::LINK_OPENED, *pe);
+            on_link_opened(mevent);
+        }
+    }
+}
+
+void messaging_adapter::on_link_remote_open(event &e) {
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_link_t *link = pn_event_link(pe->pn_event());
+        if (is_local_open(pn_link_state(link))) {
+            messaging_event mevent(messaging_event::LINK_OPENED, *pe);
+            on_link_opened(mevent);
+        }
+        else if (is_local_unititialised(pn_link_state(link))) {
+            messaging_event mevent(messaging_event::LINK_OPENING, *pe);
+            on_link_opening(mevent);
+            pn_link_open(link);
+        }
+    }
+}
+
+void messaging_adapter::on_transport_tail_closed(event &e) {
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_connection_t *conn = pn_event_connection(pe->pn_event());
+        if (conn && is_local_open(pn_connection_state(conn))) {
+            messaging_event mevent(messaging_event::DISCONNECTED, *pe);
+            delegate_.on_disconnected(mevent);
+        }
+    }
+}
+
+
+void messaging_adapter::on_connection_opened(event &e) {
+    delegate_.on_connection_opened(e);
+}
+
+void messaging_adapter::on_session_opened(event &e) {
+    delegate_.on_session_opened(e);
+}
+
+void messaging_adapter::on_link_opened(event &e) {
+    delegate_.on_link_opened(e);
+}
+
+void messaging_adapter::on_connection_opening(event &e) {
+    delegate_.on_connection_opening(e);
+}
+
+void messaging_adapter::on_session_opening(event &e) {
+    delegate_.on_session_opening(e);
+}
+
+void messaging_adapter::on_link_opening(event &e) {
+    delegate_.on_link_opening(e);
+}
+
+void messaging_adapter::on_connection_error(event &e) {
+    delegate_.on_connection_error(e);
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_connection_t *connection = pn_event_connection(pe->pn_event());
+        pn_connection_close(connection);
+    }
+}
+
+void messaging_adapter::on_session_error(event &e) {
+    delegate_.on_session_error(e);
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_session_t *session = pn_event_session(pe->pn_event());
+        pn_session_close(session);
+    }
+}
+
+void messaging_adapter::on_link_error(event &e) {
+    delegate_.on_link_error(e);
+    proton_event *pe = dynamic_cast<proton_event*>(&e);
+    if (pe) {
+        pn_link_t *link = pn_event_link(pe->pn_event());
+        pn_link_close(link);
+    }
+}
+
+void messaging_adapter::on_connection_closed(event &e) {
+    delegate_.on_connection_closed(e);
+}
+
+void messaging_adapter::on_session_closed(event &e) {
+    delegate_.on_session_closed(e);
+}
+
+void messaging_adapter::on_link_closed(event &e) {
+    delegate_.on_link_closed(e);
+}
+
+void messaging_adapter::on_connection_closing(event &e) {
+    delegate_.on_connection_closing(e);
+    if (peer_close_iserror_)
+        on_connection_error(e);
+}
+
+void messaging_adapter::on_session_closing(event &e) {
+    delegate_.on_session_closing(e);
+    if (peer_close_iserror_)
+        on_session_error(e);
+}
+
+void messaging_adapter::on_link_closing(event &e) {
+    delegate_.on_link_closing(e);
+    if (peer_close_iserror_)
+        on_link_error(e);
+}
+
+void messaging_adapter::on_unhandled(event &e) {
+}
+
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


Mime
View raw message