PROTON-1733: [cpp] access actual listening port for listen on port 0

Added proton::listener::port() to provide access to the port.
Updated tests to listen on port 0 as a safe, portable way to allocate ports.


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

Branch: refs/heads/master
Commit: d6cef7b8ca32c470cbae57e6f7a6b7e4c508a06d
Parents: 59cedf3
Author: Alan Conway <[email protected]>
Authored: Thu Jan 4 15:52:47 2018 -0500
Committer: Alan Conway <[email protected]>
Committed: Thu Jan 4 16:07:22 2018 -0500

----------------------------------------------------------------------
 examples/cpp/broker.cpp                         |   5 +-
 examples/cpp/direct_recv.cpp                    |   2 +-
 examples/cpp/direct_send.cpp                    |   2 +-
 examples/cpp/example_test.py                    | 107 +++++--------
 examples/cpp/flow_control.cpp                   |  14 +-
 examples/cpp/server_direct.cpp                  |   4 +-
 examples/cpp/simple_recv.cpp                    |   1 -
 examples/cpp/ssl.cpp                            |  16 +-
 examples/cpp/ssl_client_cert.cpp                |  22 ++-
 .../bindings/cpp/include/proton/listener.hpp    |   5 +
 proton-c/bindings/cpp/src/container_test.cpp    |  21 +--
 proton-c/bindings/cpp/src/listener.cpp          |  10 ++
 .../cpp/src/proactor_container_impl.cpp         |   2 +-
 proton-c/bindings/cpp/src/test_port.hpp         | 160 -------------------
 tools/py/proctest.py                            |  21 ---
 15 files changed, 100 insertions(+), 292 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/examples/cpp/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.cpp b/examples/cpp/broker.cpp
index 6637719..f48fb37 100644
--- a/examples/cpp/broker.cpp
+++ b/examples/cpp/broker.cpp
@@ -389,7 +389,6 @@ class broker {
         container_("broker"), queues_(container_), listener_(queues_)
     {
         container_.listen(addr, listener_);
-        std::cout << "broker listening on " << addr << std::endl;
     }
 
     void run() {
@@ -410,6 +409,10 @@ class broker {
             return proton::connection_options().handler(*(new 
connection_handler(queues_)));
         }
 
+        void on_open(proton::listener& l) OVERRIDE {
+            std::cout << "broker listening on " << l.port() << std::endl;
+        }
+
         void on_error(proton::listener&, const std::string& s) OVERRIDE {
             std::cerr << "listen error: " << s << std::endl;
             throw std::runtime_error(s);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/examples/cpp/direct_recv.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/direct_recv.cpp b/examples/cpp/direct_recv.cpp
index c98a4bf..43a018c 100644
--- a/examples/cpp/direct_recv.cpp
+++ b/examples/cpp/direct_recv.cpp
@@ -48,7 +48,7 @@ class direct_recv : public proton::messaging_handler {
 
     void on_container_start(proton::container &c) OVERRIDE {
         listener = c.listen(url);
-        std::cout << "direct_recv listening on " << url << std::endl;
+        std::cout << "listening on " << listener.port() << std::endl;
     }
 
     void on_message(proton::delivery &d, proton::message &msg) OVERRIDE {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/examples/cpp/direct_send.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/direct_send.cpp b/examples/cpp/direct_send.cpp
index 2a2b3e2..b8cf93f 100644
--- a/examples/cpp/direct_send.cpp
+++ b/examples/cpp/direct_send.cpp
@@ -49,7 +49,7 @@ class simple_send : public proton::messaging_handler {
 
     void on_container_start(proton::container &c) OVERRIDE {
         listener = c.listen(url);
-        std::cout << "direct_send listening on " << url << std::endl;
+        std::cout << "direct_send listening on " << listener.port() << 
std::endl;
     }
 
     void on_sendable(proton::sender &sender) OVERRIDE {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index fa6143f..df26a38 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -60,6 +60,10 @@ mech_list: EXTERNAL DIGEST-MD5 SCRAM-SHA-1 CRAM-MD5 PLAIN 
ANONYMOUS
 # Globally initialize Cyrus SASL configuration
 _cyrusSetup('sasl_conf')
 
+def wait_listening(proc):
+    m = proc.wait_re(".*listening on ([0-9]+)$")
+    return m.group(1), m.group(0)+"\n" # Return (port, line)
+
 class BrokerTestCase(ProcTestCase):
     """
     ExampleTest that starts a broker in setUpClass and kills it in 
tearDownClass.
@@ -68,10 +72,9 @@ class BrokerTestCase(ProcTestCase):
     @classmethod
     def setUpClass(cls):
         cls.broker = None       # In case Proc throws, create the attribute.
-        with TestPort() as tp:
-            cls.addr = "%s:%s/example" % (tp.host, tp.port)
-            cls.broker = Proc([cls.broker_exe, "-a", tp.addr])
-            cls.broker.wait_re("listening")
+        cls.broker = Proc([cls.broker_exe, "-a", "//:0"])
+        cls.port, line = wait_listening(cls.broker)
+        cls.addr = "//:%s/example" % cls.port
 
     @classmethod
     def tearDownClass(cls):
@@ -92,9 +95,8 @@ All mimsy were the borogroves, => ALL MIMSY WERE THE 
BOROGROVES,
 And the mome raths outgrabe. => AND THE MOME RATHS OUTGRABE.
 """
 
-def recv_expect(name, addr):
-    return "%s listening on %s\n%s" % (
-        name, addr, "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)]))
+def recv_expect():
+    return "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)])
 
 class ContainerExampleTest(BrokerTestCase):
     """Run the container examples, verify they behave as expected."""
@@ -105,37 +107,30 @@ class ContainerExampleTest(BrokerTestCase):
         self.assertMultiLineEqual('Hello World!\n', self.proc(["helloworld", 
self.addr]).wait_exit())
 
     def test_simple_send_recv(self):
-        self.assertMultiLineEqual("all messages confirmed\n",
-                         self.proc(["simple_send", "-a", 
self.addr]).wait_exit())
-        self.assertMultiLineEqual(recv_expect("simple_recv", self.addr), 
self.proc(["simple_recv", "-a", self.addr]).wait_exit())
+        self.assertMultiLineEqual("all messages confirmed\n", 
self.proc(["simple_send", "-a", self.addr]).wait_exit())
+        self.assertMultiLineEqual(recv_expect(), self.proc(["simple_recv", 
"-a", self.addr]).wait_exit())
 
     def test_simple_recv_send(self):
         # Start receiver first, then run sender"""
         recv = self.proc(["simple_recv", "-a", self.addr])
-        self.assertMultiLineEqual("all messages confirmed\n",
-                         self.proc(["simple_send", "-a", 
self.addr]).wait_exit())
-        self.assertMultiLineEqual(recv_expect("simple_recv", self.addr), 
recv.wait_exit())
+        self.assertMultiLineEqual("all messages confirmed\n", 
self.proc(["simple_send", "-a", self.addr]).wait_exit())
+        self.assertMultiLineEqual(recv_expect(), recv.wait_exit())
 
 
     def test_simple_send_direct_recv(self):
-        with TestPort() as tp:
-            addr = "%s/examples" % tp.addr
-            recv = self.proc(["direct_recv", "-a", addr])
-            recv.wait_re("listening")
-            self.assertMultiLineEqual("all messages confirmed\n",
-                             self.proc(["simple_send", "-a", 
addr]).wait_exit())
-            self.assertMultiLineEqual(recv_expect("direct_recv", addr), 
recv.wait_exit())
+        recv = self.proc(["direct_recv", "-a", "//:0"])
+        port, line = wait_listening(recv)
+        addr = "//:%s/examples" % port
+        self.assertMultiLineEqual("all messages confirmed\n",
+                                  self.proc(["simple_send", "-a", 
addr]).wait_exit())
+        self.assertMultiLineEqual(line+recv_expect(), recv.wait_exit())
 
     def test_simple_recv_direct_send(self):
-        with TestPort() as tp:
-            addr = "%s/examples" % tp.addr
-            send = self.proc(["direct_send", "-a", addr])
-            send.wait_re("listening")
-            self.assertMultiLineEqual(recv_expect("simple_recv", addr),
-                             self.proc(["simple_recv", "-a", 
addr]).wait_exit())
-            self.assertMultiLineEqual(
-                "direct_send listening on %s\nall messages confirmed\n" % addr,
-                send.wait_exit())
+        send = self.proc(["direct_send", "-a", "//:0"])
+        port, line = wait_listening(send)
+        addr = "//:%s/examples" % port
+        self.assertMultiLineEqual(recv_expect(), self.proc(["simple_recv", 
"-a", addr]).wait_exit())
+        self.assertMultiLineEqual(line+"all messages confirmed\n", 
send.wait_exit())
 
     def test_request_response(self):
         server = self.proc(["server", self.addr, "example"]) # self.addr has 
the connection info
@@ -144,12 +139,10 @@ class ContainerExampleTest(BrokerTestCase):
                          self.proc(["client", "-a", self.addr]).wait_exit())
 
     def test_request_response_direct(self):
-        with TestPort() as tp:
-            addr = "%s/examples" % tp.addr
-            server = self.proc(["server_direct", "-a", addr])
-            server.wait_re("listening")
-            self.assertMultiLineEqual(CLIENT_EXPECT,
-                             self.proc(["client", "-a", addr]).wait_exit())
+        server = self.proc(["server_direct", "-a", "//:0"])
+        port, line = wait_listening(server);
+        addr = "//:%s/examples" % port
+        self.assertMultiLineEqual(CLIENT_EXPECT, self.proc(["client", "-a", 
addr]).wait_exit())
 
     def test_flow_control(self):
         want="""success: Example 1: simple credit
@@ -157,8 +150,7 @@ success: Example 2: basic drain
 success: Example 3: drain without credit
 success: Example 4: high/low watermark
 """
-        with TestPort() as tp:
-            self.assertMultiLineEqual(want, self.proc(["flow_control", 
"--address", tp.addr, "--quiet"]).wait_exit())
+        self.assertMultiLineEqual(want, self.proc(["flow_control", 
"--quiet"]).wait_exit())
 
     def test_encode_decode(self):
         want="""
@@ -242,33 +234,23 @@ class ContainerExampleSSLTest(BrokerTestCase):
 
     def test_ssl(self):
         # SSL without SASL, VERIFY_PEER_NAME
-        with TestPort() as tp:
-            addr = "amqps://%s/examples" % tp.addr
-            # Disable valgrind when using OpenSSL
-            out = self.proc(["ssl", "-a", addr, "-c", 
self.ssl_certs_dir()]).wait_exit()
-            expect = "Outgoing client connection connected via SSL.  Server 
certificate identity CN=test_server\nHello World!"
-            expect_found = (out.find(expect) >= 0)
-            self.assertEqual(expect_found, True)
+        # Disable valgrind when using OpenSSL
+        out = self.proc(["ssl", "-c", self.ssl_certs_dir()]).wait_exit()
+        expect = "Server certificate identity CN=test_server\nHello World!"
+        self.assertIn(expect, out)
 
     def test_ssl_no_name(self):
         # VERIFY_PEER
-        with TestPort() as tp:
-            addr = "amqps://%s/examples" % tp.addr
-            # Disable valgrind when using OpenSSL
-            out = self.proc(["ssl", "-a", addr, "-c", self.ssl_certs_dir(), 
"-v", "noname"], valgrind=False).wait_exit()
-            expect = "Outgoing client connection connected via SSL.  Server 
certificate identity CN=test_server\nHello World!"
-            expect_found = (out.find(expect) >= 0)
-            self.assertEqual(expect_found, True)
+        # Disable valgrind when using OpenSSL
+        out = self.proc(["ssl", "-c", self.ssl_certs_dir(), "-v", "noname"], 
valgrind=False).wait_exit()
+        expect = "Outgoing client connection connected via SSL.  Server 
certificate identity CN=test_server\nHello World!"
+        self.assertIn(expect, out)
 
     def test_ssl_bad_name(self):
         # VERIFY_PEER
-        with TestPort() as tp:
-            addr = "amqps://%s/examples" % tp.addr
-            # Disable valgrind when using OpenSSL
-            out = self.proc(["ssl", "-a", addr, "-c", self.ssl_certs_dir(), 
"-v", "fail"]).wait_exit()
-            expect = "Expected failure of connection with wrong peer name"
-            expect_found = (out.find(expect) >= 0)
-            self.assertEqual(expect_found, True)
+        out = self.proc(["ssl", "-c", self.ssl_certs_dir(), "-v", 
"fail"]).wait_exit()
+        expect = "Expected failure of connection with wrong peer name"
+        self.assertIn(expect, out)
 
     def test_ssl_client_cert(self):
         # SSL with SASL EXTERNAL
@@ -276,12 +258,9 @@ class ContainerExampleSSLTest(BrokerTestCase):
 Outgoing client connection connected via SSL.  Server certificate identity 
CN=test_server
 Hello World!
 """
-        with TestPort() as tp:
-            addr = "amqps://%s/examples" % tp.addr
-            # Disable valgrind when using OpenSSL
-            out = self.proc(["ssl_client_cert", addr, 
self.ssl_certs_dir()]).wait_exit()
-            expect_found = (out.find(expect) >= 0)
-            self.assertEqual(expect_found, True)
+        # Disable valgrind when using OpenSSL
+        out = self.proc(["ssl_client_cert", self.ssl_certs_dir()]).wait_exit()
+        self.assertIn(expect, out)
 
 if __name__ == "__main__":
     unittest.main()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/examples/cpp/flow_control.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/flow_control.cpp b/examples/cpp/flow_control.cpp
index f27b6f4..4c97344 100644
--- a/examples/cpp/flow_control.cpp
+++ b/examples/cpp/flow_control.cpp
@@ -195,17 +195,19 @@ class flow_receiver : public proton::messaging_handler {
 
 class flow_control : public proton::messaging_handler {
   private:
-    std::string url;
     proton::listener listener;
     flow_sender send_handler;
     flow_receiver receive_handler;
 
   public:
-    flow_control(const std::string& u) : url(u), receive_handler(send_handler) 
{}
+    flow_control() : receive_handler(send_handler) {}
 
     void on_container_start(proton::container &c) OVERRIDE {
-        listener = c.listen(url, 
proton::connection_options().handler(send_handler));
-        c.connect(url);
+        // Listen on a dynamic port on the local host.
+        listener = c.listen("//:0", 
proton::connection_options().handler(send_handler));
+        std::ostringstream url;
+        url << "//:" << listener.port() << "/example"; // Connect to the 
actual listening port
+        c.connect(url.str());
     }
 
     void on_connection_open(proton::connection &c) OVERRIDE {
@@ -223,11 +225,9 @@ class flow_control : public proton::messaging_handler {
 int main(int argc, char **argv) {
     // Pick an "unusual" port since we are going to be talking to
     // ourselves, not a broker.
-    std::string address("127.0.0.1:8888");
     bool quiet = false;
 
     example::options opts(argc, argv);
-    opts.add_value(address, 'a', "address", "connect and send to URL", "URL");
     opts.add_flag(quiet, 'q', "quiet", "suppress additional commentary of 
credit allocation and consumption");
 
     try {
@@ -235,7 +235,7 @@ int main(int argc, char **argv) {
         if (quiet)
             verbose = false;
 
-        flow_control fc(address);
+        flow_control fc;
         proton::container(fc).run();
 
         return 0;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/examples/cpp/server_direct.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/server_direct.cpp b/examples/cpp/server_direct.cpp
index 3bfd60a..cf3447c 100644
--- a/examples/cpp/server_direct.cpp
+++ b/examples/cpp/server_direct.cpp
@@ -50,8 +50,8 @@ class server : public proton::messaging_handler {
     server(const std::string &u) : url(u), address_counter(0) {}
 
     void on_container_start(proton::container &c) OVERRIDE {
-        c.listen(url);
-        std::cout << "server listening on " << url << std::endl;
+        proton::listener l = c.listen(url);
+        std::cout << "server listening on " << l.port() << std::endl;
     }
 
     std::string to_upper(const std::string &s) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/examples/cpp/simple_recv.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/simple_recv.cpp b/examples/cpp/simple_recv.cpp
index 39b4dfd..5a7cde4 100644
--- a/examples/cpp/simple_recv.cpp
+++ b/examples/cpp/simple_recv.cpp
@@ -54,7 +54,6 @@ class simple_recv : public proton::messaging_handler {
         if (!user.empty()) co.user(user);
         if (!password.empty()) co.password(password);
         receiver = c.open_receiver(url, co);
-        std::cout << "simple_recv listening on " << url << std::endl;
     }
 
     void on_message(proton::delivery &d, proton::message &msg) OVERRIDE {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/examples/cpp/ssl.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/ssl.cpp b/examples/cpp/ssl.cpp
index d93454f..8979ecb 100644
--- a/examples/cpp/ssl.cpp
+++ b/examples/cpp/ssl.cpp
@@ -80,12 +80,9 @@ struct server_handler : public proton::messaging_handler {
 
 class hello_world_direct : public proton::messaging_handler {
   private:
-    std::string url;
     server_handler s_handler;
 
   public:
-    hello_world_direct(const std::string& u) : url(u) {}
-
     void on_container_start(proton::container &c) OVERRIDE {
         // Configure listener.  Details vary by platform.
         ssl_certificate server_cert = platform_certificate("tserver", 
"tserverpw");
@@ -116,8 +113,10 @@ class hello_world_direct : public 
proton::messaging_handler {
         } else throw std::logic_error("bad verify mode: " + verify);
 
         c.client_connection_options(client_opts);
-        s_handler.listener = c.listen(url);
-        c.open_sender(url);
+        s_handler.listener = c.listen("//:0"); // Listen on port 0 to get a 
dynamic port
+        std::ostringstream url;
+        url << "//:" << s_handler.listener.port() << "/example"; // Connect to 
the actual port
+        c.open_sender(url.str());
     }
 
     void on_connection_open(proton::connection &c) OVERRIDE {
@@ -150,12 +149,7 @@ class hello_world_direct : public 
proton::messaging_handler {
 };
 
 int main(int argc, char **argv) {
-    // Pick an "unusual" port since we are going to be talking to
-    // ourselves, not a broker.
-    // Note the use of "amqps" as the URL scheme to denote a TLS/SSL 
connection.
-    std::string address("amqps://127.0.0.1:8888/examples");
     example::options opts(argc, argv);
-    opts.add_value(address, 'a', "address", "connect and send to URL", "URL");
     opts.add_value(cert_directory, 'c', "cert_directory",
                    "directory containing SSL certificates and private key 
information", "CERTDIR");
     opts.add_value(verify, 'v', "verify", "verify type: \"minimum\", \"full\", 
\"fail\"", "VERIFY");
@@ -171,7 +165,7 @@ int main(int argc, char **argv) {
         if (verify != verify_noname && verify != verify_full && verify != 
verify_fail)
             throw std::runtime_error("bad verify argument: " + verify);
 
-        hello_world_direct hwd(address);
+        hello_world_direct hwd;
         proton::container(hwd).run();
         return 0;
     } catch (const std::exception& e) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/examples/cpp/ssl_client_cert.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/ssl_client_cert.cpp b/examples/cpp/ssl_client_cert.cpp
index 32a9a1d..792a6c7 100644
--- a/examples/cpp/ssl_client_cert.cpp
+++ b/examples/cpp/ssl_client_cert.cpp
@@ -31,6 +31,7 @@
 #include <proton/transport.hpp>
 
 #include <iostream>
+#include <sstream>
 
 #include "fake_cpp11.hpp"
 
@@ -76,11 +77,9 @@ struct server_handler : public proton::messaging_handler {
 
 class hello_world_direct : public proton::messaging_handler {
   private:
-    std::string url;
     server_handler s_handler;
 
   public:
-    hello_world_direct(const std::string& u) : url(u) {}
 
     void on_container_start(proton::container &c) OVERRIDE {
         // Configure listener.  Details vary by platform.
@@ -103,8 +102,10 @@ class hello_world_direct : public 
proton::messaging_handler {
         client_opts.ssl_client_options(ssl_cli).sasl_allowed_mechs("EXTERNAL");
         c.client_connection_options(client_opts);
 
-        s_handler.listener = c.listen(url);
-        c.open_sender(url);
+        s_handler.listener = c.listen("//:0");
+        std::ostringstream url;
+        url << "//:" << s_handler.listener.port() << "/example"; // Connect to 
the actual port
+        c.open_sender(url.str());
     }
 
     void on_connection_open(proton::connection &c) OVERRIDE {
@@ -128,19 +129,16 @@ class hello_world_direct : public 
proton::messaging_handler {
 
 int main(int argc, char **argv) {
     try {
-        // Pick an "unusual" port since we are going to be talking to 
ourselves, not a broker.
-        // Note the use of "amqps" as the URL scheme to denote a TLS/SSL 
connection.
-        std::string url = argc > 1 ? argv[1] : 
"amqps://127.0.0.1:8888/examples";
         // Location of certificates and private key information:
-        if (argc > 2) {
-            cert_directory = argv[2];
+        if (argc > 1) {
+            cert_directory = argv[1];
             size_t sz = cert_directory.size();
             if (sz && cert_directory[sz -1] != '/')
                 cert_directory.append("/");
+        } else {
+            cert_directory = "ssl_certs/";
         }
-        else cert_directory = "ssl_certs/";
-
-        hello_world_direct hwd(url);
+        hello_world_direct hwd;
         proton::container(hwd).run();
         return 0;
     } catch (const std::exception& e) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/proton-c/bindings/cpp/include/proton/listener.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/listener.hpp 
b/proton-c/bindings/cpp/include/proton/listener.hpp
index f344892..f1ca9ac 100644
--- a/proton-c/bindings/cpp/include/proton/listener.hpp
+++ b/proton-c/bindings/cpp/include/proton/listener.hpp
@@ -51,6 +51,11 @@ class PN_CPP_CLASS_EXTERN listener {
     /// container::listen that returned this listener.
     PN_CPP_EXTERN void stop();
 
+    /// Return the port used by the listener.
+    /// If port 0 was passed to container::listen, this will be a dynamically 
allocated port.
+    /// @throw proton::error if the listener does not have a port
+    PN_CPP_EXTERN int port();
+
   private:
     pn_listener_t* listener_;
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/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 c0a9734..93733a5 100644
--- a/proton-c/bindings/cpp/src/container_test.cpp
+++ b/proton-c/bindings/cpp/src/container_test.cpp
@@ -19,7 +19,6 @@
 
 
 #include "test_bits.hpp"
-#include "test_port.hpp"
 
 #include "proton/connection.hpp"
 #include "proton/connection_options.hpp"
@@ -37,6 +36,11 @@
 
 namespace {
 
+std::string make_url(std::string host, int port) {
+    std::ostringstream url;
+    url << "//" << host << ":" << port;
+    return url.str();
+}
 
 struct test_listen_handler : public proton::listen_handler {
     bool on_open_, on_accept_, on_close_;
@@ -72,7 +76,6 @@ class test_handler : public proton::messaging_handler {
 
     std::string peer_vhost;
     std::string peer_container_id;
-    test_port port;
     proton::listener listener;
     test_listen_handler listen_handler;
 
@@ -81,8 +84,8 @@ class test_handler : public proton::messaging_handler {
     {}
 
     void on_container_start(proton::container &c) PN_CPP_OVERRIDE {
-        listener = c.listen(port.url(), listen_handler);
-        proton::connection conn = c.connect(port.url(host), opts);
+        listener = c.listen("//:0", listen_handler);
+        proton::connection conn = c.connect(make_url(host, listener.port()), 
opts);
     }
 
     void on_connection_open(proton::connection &c) PN_CPP_OVERRIDE {
@@ -164,14 +167,13 @@ int test_container_bad_address() {
 }
 
 class stop_tester : public proton::messaging_handler {
-    test_port port;
     proton::listener listener;
 
     // Set up a listener which would block forever
     void on_container_start(proton::container& c) PN_CPP_OVERRIDE {
         ASSERT(state==0);
-        listener = c.listen(port.url());
-        c.connect(port.url());
+        listener = c.listen("//localhost:0");
+        c.connect(make_url("", listener.port()));
         c.auto_stop(false);
         state = 1;
     }
@@ -213,17 +215,16 @@ int test_container_stop() {
 
 struct hang_tester : public proton::messaging_handler {
     proton::listener listener;
-    test_port port;
     bool done;
 
     hang_tester() : done(false) {}
 
     void connect(proton::container* c) {
-        c->connect(port.url());
+        c->connect(make_url("", listener.port()));
     }
 
     void on_container_start(proton::container& c) PN_CPP_OVERRIDE {
-        listener = c.listen(port.url());
+        listener = c.listen("//:0");
         c.schedule(proton::duration(250), make_work(&hang_tester::connect, 
this, &c));
     }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/proton-c/bindings/cpp/src/listener.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/listener.cpp 
b/proton-c/bindings/cpp/src/listener.cpp
index 53f238c..7effbf4 100644
--- a/proton-c/bindings/cpp/src/listener.cpp
+++ b/proton-c/bindings/cpp/src/listener.cpp
@@ -22,6 +22,7 @@
 #include "proton/listen_handler.hpp"
 
 #include <proton/listener.h>
+#include <proton/netaddr.h>
 
 #include "contexts.hpp"
 
@@ -33,8 +34,17 @@ listener::listener(pn_listener_t* l): listener_(l) {}
 listener::listener(const listener& l) : listener_(l.listener_) {}
 listener::~listener() {}
 listener& listener::operator=(const listener& l) { listener_ = l.listener_; 
return *this; }
+
 void listener::stop() { if (listener_) pn_listener_close(listener_); }
 
+int listener::port() {
+    char port[16] = "invalid";
+    pn_netaddr_host_port(pn_netaddr_listening(listener_), NULL, 0, port, 
sizeof(port));
+    int i = atoi(port);
+    if (!i) throw error("listener has no port");
+    return i;
+}
+
 listen_handler::~listen_handler() {}
 void listen_handler::on_open(listener&) {}
 connection_options listen_handler::on_accept(listener&) { return 
connection_options(); }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/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 3e68c44..188a8d6 100644
--- a/proton-c/bindings/cpp/src/proactor_container_impl.cpp
+++ b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
@@ -367,7 +367,7 @@ pn_listener_t* container::impl::listen_common_lh(const 
std::string& addr) {
     if (stopping_)
         throw proton::error("container is stopping");
 
-    proton::url url(addr);
+    proton::url url(addr, false); // Don't want un-helpful defaults like 
"localhost"
 
     // Figure out correct string len then create connection address
     int len = pn_proactor_addr(0, 0, url.host().c_str(), url.port().c_str());

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/proton-c/bindings/cpp/src/test_port.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/test_port.hpp 
b/proton-c/bindings/cpp/src/test_port.hpp
deleted file mode 100644
index cc592fa..0000000
--- a/proton-c/bindings/cpp/src/test_port.hpp
+++ /dev/null
@@ -1,160 +0,0 @@
-#ifndef TEST_PORT_HPP
-#define TEST_PORT_HPP
-
-/*
- * 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 <cstring>
-#include <cerrno>
-
-/* Some simple platform-secifics to acquire an unused socket */
-
-#if defined(_WIN32)
-
-extern "C" {
-# include <winsock2.h>
-# include <ws2tcpip.h>
-}
-
-typedef SOCKET sock_t;
-
-void check_err(int ret, const char *what) {
-  if (ret) {
-    char buf[512];
-    FormatMessage(
-      FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
-      NULL, WSAGetLastError(), NULL, buf, sizeof(buf), NULL);
-    fprintf(stderr, "%s: %s\n", what, buf);
-    throw std::runtime_error(buf);
-  }
-}
-
-class test_socket {
-  public:
-    SOCKET sock_;
-    test_socket() {
-        WORD wsa_ver = MAKEWORD(2, 2);
-        WSADATA unused;
-        check_err(WSAStartup(wsa_ver, &unused), "WSAStartup");
-        sock_ = socket(AF_INET, SOCK_STREAM, 0);
-        check_err(sock_ < 0, "socket");
-    }
-    ~test_socket() { WSACleanup(); }
-    void close_early()  { closesocket(sock_); } // Windows won't allow two 
sockets on a port
-};
-
-#elif defined(__APPLE__) || defined(__FreeBSD__)
-
-// BSD derivatives don't support the same SO_REUSEADDR semantics as Linux so
-// do the same thing as windows and hope for the best
-extern "C" {
-# include <sys/types.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <unistd.h>
-# include <netdb.h>
-}
-
-void check_err(int ret, const std::string& what) {
-    if (ret) throw std::runtime_error(what + ": " + std::strerror(errno));
-}
-
-class test_socket {
-  public:
-    int sock_;
-    test_socket() : sock_(socket(AF_INET, SOCK_STREAM, 0)) {
-        check_err(sock_ < 0, "socket");
-        int on = 1;
-        check_err(setsockopt(sock_, SOL_SOCKET, SO_REUSEADDR, (const 
char*)&on, sizeof(on)),
-                  "setsockop");
-    }
-    ~test_socket() { }
-    void close_early() {
-        close(sock_);
-    }
-};
-
-#else  /* POSIX */
-
-extern "C" {
-# include <sys/types.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <unistd.h>
-# include <netdb.h>
-}
-
-void check_err(int ret, const std::string& what) {
-    if (ret) throw std::runtime_error(what + ": " + std::strerror(errno));
-}
-
-class test_socket {
-  public:
-    int sock_;
-    test_socket() : sock_(socket(AF_INET, SOCK_STREAM, 0)) {
-        check_err(sock_ < 0, "socket");
-        int on = 1;
-        check_err(setsockopt(sock_, SOL_SOCKET, SO_REUSEADDR, (const 
char*)&on, sizeof(on)),
-                  "setsockop");
-    }
-    ~test_socket() { close(sock_); }
-    void close_early() {}   // Don't close early on POSIX, keep the port safe
-};
-
-#endif
-
-#define TEST_PORT_MAX_STR 1060
-
-/* Acquire a port suitable for listening */
-class test_port {
-    test_socket sock_;
-    int port_;
-
-  public:
-
-    /* Acquire a port suitable for listening */
-    test_port() : port_(0) {
-        /* Create a socket and bind(INADDR_LOOPBACK:0) to get a free port.
-           Set socket options so the port can be bound and used for listen() 
within this process,
-           even though it is bound to the test_port socket.
-           Use host to create the host_port address string.
-        */
-        struct sockaddr_in addr = {0};
-        addr.sin_family = AF_INET;    /* set the type of connection to TCP/IP 
*/
-        addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-        addr.sin_port = 0;            /* bind to port 0 */
-        check_err(bind(sock_.sock_, (struct sockaddr*)&addr, sizeof(addr)), 
"bind");
-        socklen_t len = sizeof(addr);
-        check_err(getsockname(sock_.sock_, (struct sockaddr*)&addr, &len), 
"getsockname");
-        port_ = ntohs(addr.sin_port);
-        sock_.close_early();
-    }
-
-    int port() const { return port_; }
-
-    std::string url(const std::string& host="") const {
-        std::ostringstream url;
-        url << "amqp://" << host << ":" << port_;
-        return url.str();
-    }
-};
-
-
-
-#endif // TEST_PORT_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6cef7b8/tools/py/proctest.py
----------------------------------------------------------------------
diff --git a/tools/py/proctest.py b/tools/py/proctest.py
index 33cf26e..940ffe7 100644
--- a/tools/py/proctest.py
+++ b/tools/py/proctest.py
@@ -33,27 +33,6 @@ from os.path import dirname as dirname
 
 DEFAULT_TIMEOUT=10
 
-class TestPort(object):
-    """Get an unused port using bind(0) and SO_REUSEADDR and hold it till 
close()
-    Can be used as `with TestPort() as tp:` Provides tp.host, tp.port and 
tp.addr
-    (a "host:port" string)
-    """
-    def __init__(self):
-        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-        self.sock.bind(('127.0.0.1', 0)) # Testing examples is local only
-        self.host, self.port = socket.getnameinfo(self.sock.getsockname(), 0)
-        self.addr = "%s:%s" % (self.host, self.port)
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, *args):
-        self.close()
-
-    def close(self):
-        self.sock.close()
-
 class ProcError(Exception):
     """An exception that displays failed process output"""
     def __init__(self, proc, what="bad exit status"):


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to