You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2017/10/19 12:40:00 UTC

[14/50] qpid-proton git commit: PROTON-1618: c++ container: unambiguous listen success/fail indicator

PROTON-1618: c++ container: unambiguous listen success/fail indicator

Added listener_handler::on_open() to indicate a successful listen.

After a call to container::listen():
- on success, call listener_handler::on_open() before any call to listener_handler::on_accept()
- on failure, call listener_handler::on_error() followed by listener_handler::on_close()

An application can tell from the first event received (on_open() vs. on_close()) if the
listen call succeeded or failed.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/31d5ba09
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/31d5ba09
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/31d5ba09

Branch: refs/heads/go1
Commit: 31d5ba096aa850e49b0f2475a3c1ef9f171f9a3c
Parents: d0b641b
Author: Alan Conway <ac...@redhat.com>
Authored: Tue Oct 10 16:24:28 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Oct 11 22:04:42 2017 -0400

----------------------------------------------------------------------
 .../bindings/cpp/include/proton/container.hpp   | 12 ++-
 .../cpp/include/proton/listen_handler.hpp       |  3 +
 proton-c/bindings/cpp/src/container_test.cpp    | 89 ++++++++++++--------
 .../cpp/src/proactor_container_impl.cpp         | 10 ++-
 4 files changed, 74 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/31d5ba09/proton-c/bindings/cpp/include/proton/container.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/container.hpp b/proton-c/bindings/cpp/include/proton/container.hpp
index d30e45a..fe3857d 100644
--- a/proton-c/bindings/cpp/include/proton/container.hpp
+++ b/proton-c/bindings/cpp/include/proton/container.hpp
@@ -120,12 +120,16 @@ class PN_CPP_CLASS_EXTERN container {
 
     /// Listen for new connections on `listen_url`.
     ///
-    /// listen_handler::on_accept is called for each incoming connection to determine
+    /// If the listener opens successfully, listen_handler::on_open() is called.
+    /// If it fails to open, listen_handler::on_error() then listen_handler::close()
+    /// are called.
+    ///
+    /// listen_handler::on_accept() is called for each incoming connection to determine
     /// the @ref connection_options to use, including the @ref messaging_handler.
     ///
-    /// **Thread safety** - Calls to `listen_handler` methods
-    /// are serialized for this listener, but handlers attached to
-    /// separate listeners can be safely called concurrently.
+    /// **Thread safety** - Calls to `listen_handler` methods are serialized for
+    /// this listener, but handlers attached to separate listeners may be called
+    /// concurrently.
     PN_CPP_EXTERN listener listen(const std::string& listen_url,
                                   listen_handler& handler);
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/31d5ba09/proton-c/bindings/cpp/include/proton/listen_handler.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/listen_handler.hpp b/proton-c/bindings/cpp/include/proton/listen_handler.hpp
index 4ce20e9..3e18475 100644
--- a/proton-c/bindings/cpp/include/proton/listen_handler.hpp
+++ b/proton-c/bindings/cpp/include/proton/listen_handler.hpp
@@ -38,6 +38,9 @@ class listen_handler {
   public:
     virtual ~listen_handler() {}
 
+    /// Called when the listener is opened successfully.
+    virtual void on_open(listener&) {}
+
     /// Called for each accepted connection.
     ///
     /// Returns connection_options to apply, including a proton::messaging_handler for

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/31d5ba09/proton-c/bindings/cpp/src/container_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/container_test.cpp b/proton-c/bindings/cpp/src/container_test.cpp
index c2b1609..3b0c86f 100644
--- a/proton-c/bindings/cpp/src/container_test.cpp
+++ b/proton-c/bindings/cpp/src/container_test.cpp
@@ -35,20 +35,21 @@
 
 namespace {
 
-static std::string int2string(int n) {
-    std::ostringstream strm;
-    strm << n;
-    return strm.str();
+static std::string make_url(const std::string host, int port) {
+    std::ostringstream url;
+    url << "amqp://" << host << ":" << port;
+    return url.str();
 }
 
-int listen_on_random_port(proton::container& c, proton::listener& l) {
-    int port;
+int listen_on_random_port(proton::container& c, proton::listener& l, proton::listen_handler* lh=0) {
+    int port = 0;
     // I'm going to hell for this:
     std::srand((unsigned int)time(0));
     while (true) {
         port = 20000 + (std::rand() % 30000);
+        std::string url = make_url("", port);
         try {
-            l = c.listen("0.0.0.0:" + int2string(port));
+            l = lh ? c.listen(url, *lh) : c.listen(url);
             break;
         } catch (...) {
             // keep trying
@@ -57,6 +58,31 @@ int listen_on_random_port(proton::container& c, proton::listener& l) {
     return port;
 }
 
+struct test_listen_handler : public proton::listen_handler {
+    bool on_open_, on_accept_, on_close_;
+    std::string on_error_;
+    test_listen_handler() : on_open_(false), on_accept_(false), on_close_(false) {}
+    proton::connection_options on_accept(proton::listener&) PN_CPP_OVERRIDE {
+        on_accept_ = true;
+        return proton::connection_options();
+    }
+    void on_open(proton::listener&) PN_CPP_OVERRIDE {
+        on_open_ = true;
+        ASSERT(!on_accept_);
+        ASSERT(on_error_.empty());
+        ASSERT(!on_close_);
+    }
+    void on_close(proton::listener&) PN_CPP_OVERRIDE {
+        on_close_ = true;
+        ASSERT(on_open_ || on_error_.size());
+    }
+
+    void on_error(proton::listener&, const std::string& e) PN_CPP_OVERRIDE {
+        on_error_ = e;
+        ASSERT(!on_close_);
+    }
+};
+
 class test_handler : public proton::messaging_handler {
   public:
     const std::string host;
@@ -67,17 +93,21 @@ class test_handler : public proton::messaging_handler {
     std::string peer_vhost;
     std::string peer_container_id;
     proton::listener listener;
+    test_listen_handler listen_handler;
 
     test_handler(const std::string h, const proton::connection_options& c_opts)
         : host(h), opts(c_opts), closing(false), done(false)
     {}
 
     void on_container_start(proton::container &c) PN_CPP_OVERRIDE {
-        int port = listen_on_random_port(c, listener);
-        proton::connection conn = c.connect(host + ":" + int2string(port), opts);
+        int port = listen_on_random_port(c, listener, &listen_handler);
+        proton::connection conn = c.connect(make_url(host, port), opts);
     }
 
     void on_connection_open(proton::connection &c) PN_CPP_OVERRIDE {
+        ASSERT(listen_handler.on_open_);
+        ASSERT(!listen_handler.on_close_);
+        ASSERT(listen_handler.on_error_.empty());
         if (peer_vhost.empty() && !c.virtual_host().empty())
             peer_vhost = c.virtual_host();
         if (peer_container_id.empty() && !c.container_id().empty())
@@ -94,26 +124,28 @@ class test_handler : public proton::messaging_handler {
 
 int test_container_default_container_id() {
     proton::connection_options opts;
-    test_handler th(std::string("127.0.0.1"), opts);
+    test_handler th("", opts);
     proton::container(th).run();
     ASSERT(!th.peer_container_id.empty());
+    ASSERT(th.listen_handler.on_error_.empty());
+    ASSERT(th.listen_handler.on_close_);
     return 0;
 }
 
 int test_container_vhost() {
     proton::connection_options opts;
-    opts.virtual_host(std::string("a.b.c"));
-    test_handler th(std::string("127.0.0.1"), opts);
+    opts.virtual_host("a.b.c");
+    test_handler th("", opts);
     proton::container(th).run();
-    ASSERT_EQUAL(th.peer_vhost, std::string("a.b.c"));
+    ASSERT_EQUAL(th.peer_vhost, "a.b.c");
     return 0;
 }
 
 int test_container_default_vhost() {
     proton::connection_options opts;
-    test_handler th(std::string("127.0.0.1"), opts);
+    test_handler th("127.0.0.1", opts);
     proton::container(th).run();
-    ASSERT_EQUAL(th.peer_vhost, std::string("127.0.0.1"));
+    ASSERT_EQUAL(th.peer_vhost, "127.0.0.1");
     return 0;
 }
 
@@ -123,25 +155,13 @@ int test_container_no_vhost() {
     // Sadly whether or not a 'hostname' field was received cannot be
     // determined from here, so just exercise the code
     proton::connection_options opts;
-    opts.virtual_host(std::string(""));
-    test_handler th(std::string("127.0.0.1"), opts);
+    opts.virtual_host("");
+    test_handler th("127.0.0.1", opts);
     proton::container(th).run();
-    ASSERT_EQUAL(th.peer_vhost, std::string(""));
+    ASSERT_EQUAL(th.peer_vhost, "");
     return 0;
 }
 
-struct test_listener : public proton::listen_handler {
-    bool on_accept_, on_close_;
-    std::string on_error_;
-    test_listener() : on_accept_(false), on_close_(false) {}
-    proton::connection_options on_accept(proton::listener&) PN_CPP_OVERRIDE {
-        on_accept_ = true;
-        return proton::connection_options();
-    }
-    void on_close(proton::listener&) PN_CPP_OVERRIDE { on_close_ = true; }
-    void on_error(proton::listener&, const std::string& e) PN_CPP_OVERRIDE { on_error_ = e; }
-};
-
 int test_container_bad_address() {
     // Listen on a bad address, check for leaks
     // Regression test for https://issues.apache.org/jira/browse/PROTON-1217
@@ -151,10 +171,11 @@ int test_container_bad_address() {
     try { c.listen("999.666.999.666:0"); } catch (const proton::error&) {}
     c.run();
     // Dummy listener.
-    test_listener l;
-    test_handler h2(std::string("999.999.999.666"), proton::connection_options());
+    test_listen_handler l;
+    test_handler h2("999.999.999.666", proton::connection_options());
     try { c.listen("999.666.999.666:0", l); } catch (const proton::error&) {}
     c.run();
+    ASSERT(!l.on_open_);
     ASSERT(!l.on_accept_);
     ASSERT(l.on_close_);
     ASSERT(!l.on_error_.empty());
@@ -168,7 +189,7 @@ class stop_tester : public proton::messaging_handler {
     void on_container_start(proton::container& c) PN_CPP_OVERRIDE {
         ASSERT(state==0);
         int port = listen_on_random_port(c, listener);
-        c.connect("127.0.0.1:" + int2string(port));
+        c.connect(make_url("", port));
         c.auto_stop(false);
         state = 1;
     }
@@ -216,7 +237,7 @@ struct hang_tester : public proton::messaging_handler {
     hang_tester() : done(false) {}
 
     void connect(proton::container* c) {
-        c->connect("localhost:"+ int2string(port));
+        c->connect(make_url("", port));
     }
 
     void on_container_start(proton::container& c) PN_CPP_OVERRIDE {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/31d5ba09/proton-c/bindings/cpp/src/proactor_container_impl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proactor_container_impl.cpp b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
index e83cc66..ec617bd 100644
--- a/proton-c/bindings/cpp/src/proactor_container_impl.cpp
+++ b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
@@ -498,9 +498,15 @@ bool container::impl::handle(pn_event_t* event) {
         }
         return false;
     }
-    case PN_LISTENER_OPEN:
+    case PN_LISTENER_OPEN: {
+        pn_listener_t* l = pn_event_listener(event);
+        listener_context &lc(listener_context::get(l));
+        if (lc.listen_handler_) {
+            listener lstnr(l);
+            lc.listen_handler_->on_open(lstnr);
+        }
         return false;
-
+    }
     case PN_LISTENER_ACCEPT: {
         pn_listener_t* l = pn_event_listener(event);
         pn_connection_t* c = pn_connection();


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