| /* |
| * 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 "test_bits.hpp" |
| #include "proton/connection.hpp" |
| #include "proton/connection_options.hpp" |
| #include "proton/container.hpp" |
| #include "proton/default_container.hpp" |
| #include "proton/messaging_handler.hpp" |
| #include "proton/listener.hpp" |
| #include "proton/listen_handler.hpp" |
| #include "proton/thread_safe.hpp" |
| |
| #include <cstdlib> |
| #include <ctime> |
| #include <string> |
| #include <cstdio> |
| #include <sstream> |
| |
| namespace { |
| |
| static std::string int2string(int n) { |
| std::ostringstream strm; |
| strm << n; |
| return strm.str(); |
| } |
| |
| int listen_on_random_port(proton::container& c, proton::listener& l) { |
| int port; |
| // I'm going to hell for this: |
| std::srand((unsigned int)time(0)); |
| while (true) { |
| port = 20000 + (std::rand() % 30000); |
| try { |
| l = c.listen("0.0.0.0:" + int2string(port)); |
| break; |
| } catch (...) { |
| // keep trying |
| } |
| } |
| return port; |
| } |
| |
| class test_handler : public proton::messaging_handler { |
| public: |
| const std::string host; |
| proton::connection_options opts; |
| bool closing; |
| bool done; |
| |
| std::string peer_vhost; |
| proton::listener listener; |
| |
| 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); |
| } |
| |
| void on_connection_open(proton::connection &c) PN_CPP_OVERRIDE { |
| if (peer_vhost.empty() && !c.virtual_host().empty()) |
| peer_vhost = c.virtual_host(); |
| if (!closing) c.close(); |
| closing = true; |
| } |
| |
| void on_connection_close(proton::connection &) PN_CPP_OVERRIDE { |
| if (!done) listener.stop(); |
| done = true; |
| } |
| }; |
| |
| 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); |
| proton::default_container(th).run(); |
| ASSERT_EQUAL(th.peer_vhost, std::string("a.b.c")); |
| return 0; |
| } |
| |
| int test_container_default_vhost() { |
| proton::connection_options opts; |
| test_handler th(std::string("127.0.0.1"), opts); |
| proton::default_container(th).run(); |
| ASSERT_EQUAL(th.peer_vhost, std::string("127.0.0.1")); |
| return 0; |
| } |
| |
| int test_container_no_vhost() { |
| // explicitly setting an empty virtual-host will cause the Open |
| // performative to be sent without a hostname field present. |
| // 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); |
| proton::default_container(th).run(); |
| ASSERT_EQUAL(th.peer_vhost, std::string("")); |
| 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() PN_CPP_OVERRIDE { |
| on_accept_ = true; |
| return proton::connection_options(); |
| } |
| void on_close() PN_CPP_OVERRIDE { on_close_ = true; } |
| void on_error(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 |
| |
| proton::default_container c; |
| // Default fixed-option listener. Valgrind for leaks. |
| try { c.listen("999.666.999.666:0"); } catch (const proton::error&) {} |
| // Dummy listener. |
| test_listener l; |
| test_handler h2(std::string("999.999.999.666"), proton::connection_options()); |
| try { c.listen("999.666.999.666:0", l); } catch (const proton::error&) {} |
| ASSERT(!l.on_accept_); |
| ASSERT(l.on_close_); |
| ASSERT(!l.on_error_.empty()); |
| return 0; |
| } |
| |
| class stop_tester : public proton::messaging_handler { |
| proton::listener listener; |
| |
| // Set up a listener which would block forever |
| 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.auto_stop(false); |
| state = 1; |
| } |
| |
| // Get here twice - once for listener, once for connector |
| void on_connection_open(proton::connection &c) PN_CPP_OVERRIDE { |
| c.close(); |
| state++; |
| } |
| |
| void on_connection_close(proton::connection &c) PN_CPP_OVERRIDE { |
| ASSERT(state==3); |
| c.container().stop(); |
| state = 4; |
| } |
| void on_container_stop(proton::container & ) PN_CPP_OVERRIDE { |
| ASSERT(state==4); |
| state = 5; |
| } |
| |
| public: |
| stop_tester(): state(0) {} |
| |
| int state; |
| }; |
| |
| int test_container_stop() { |
| stop_tester t; |
| proton::default_container(t).run(); |
| ASSERT(t.state==5); |
| return 0; |
| } |
| |
| } |
| |
| int main(int, char**) { |
| int failed = 0; |
| RUN_TEST(failed, test_container_vhost()); |
| RUN_TEST(failed, test_container_default_vhost()); |
| RUN_TEST(failed, test_container_no_vhost()); |
| RUN_TEST(failed, test_container_bad_address()); |
| RUN_TEST(failed, test_container_stop()); |
| return failed; |
| } |
| |