PROTON-1618: c++ provide separate test_port implementation Break unwanted dependency between C++ and C test trees.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/b4e0edd2 Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/b4e0edd2 Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/b4e0edd2 Branch: refs/heads/go1 Commit: b4e0edd2cab25b95a6fa245d00c35928de01550e Parents: a518b1c Author: Alan Conway <acon...@redhat.com> Authored: Mon Oct 16 18:11:52 2017 +0100 Committer: Alan Conway <acon...@redhat.com> Committed: Mon Oct 16 18:33:02 2017 +0100 ---------------------------------------------------------------------- proton-c/bindings/cpp/src/container_test.cpp | 27 +---- proton-c/bindings/cpp/src/test_port.hpp | 129 ++++++++++++++++++++++ proton-c/src/tests/test_port.h | 4 +- 3 files changed, 135 insertions(+), 25 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b4e0edd2/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 c9657b9..fc368d0 100644 --- a/proton-c/bindings/cpp/src/container_test.cpp +++ b/proton-c/bindings/cpp/src/container_test.cpp @@ -19,9 +19,7 @@ #include "test_bits.hpp" -extern "C" { -#include "../../../../src/tests/test_port.h" -} +#include "test_port.hpp" #include "proton/connection.hpp" #include "proton/connection_options.hpp" @@ -39,23 +37,6 @@ extern "C" { namespace { -std::string make_url(const std::string& host, int port) { - std::ostringstream url; - url << "amqp://" << host << ":" << port; - return url.str(); -} - -// C++ Wrapper for C test port. -// Binds to a port with REUSEADDR set so that the port is protected from -// other processes and can safely be used for listening. -class listen_port { - ::test_port_t tp; - public: - listen_port() { tp = ::test_port(""); } // NOTE: assign tp, don't initialize - Windows. - ~listen_port() { ::test_port_close(&tp); } - int port() const { return tp.port; } - std::string url(const std::string& host="") const { return make_url(host, tp.port); } -}; struct test_listen_handler : public proton::listen_handler { bool on_open_, on_accept_, on_close_; @@ -91,7 +72,7 @@ class test_handler : public proton::messaging_handler { std::string peer_vhost; std::string peer_container_id; - listen_port port; + test_port port; proton::listener listener; test_listen_handler listen_handler; @@ -183,7 +164,7 @@ int test_container_bad_address() { } class stop_tester : public proton::messaging_handler { - listen_port port; + test_port port; proton::listener listener; // Set up a listener which would block forever @@ -232,7 +213,7 @@ int test_container_stop() { struct hang_tester : public proton::messaging_handler { proton::listener listener; - listen_port port; + test_port port; bool done; hang_tester() : done(false) {} http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b4e0edd2/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 new file mode 100644 index 0000000..eb94e84 --- /dev/null +++ b/proton-c/bindings/cpp/src/test_port.hpp @@ -0,0 +1,129 @@ +#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 +}; + +#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 << "amp://" << host << ":" << port_; + return url.str(); + } +}; + + + +#endif // TEST_PORT_HPP http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b4e0edd2/proton-c/src/tests/test_port.h ---------------------------------------------------------------------- diff --git a/proton-c/src/tests/test_port.h b/proton-c/src/tests/test_port.h index 85a3fd7..0569c44 100644 --- a/proton-c/src/tests/test_port.h +++ b/proton-c/src/tests/test_port.h @@ -104,9 +104,9 @@ test_port_t test_port(const char* host) { test_port_t tp = {0}; tp.sock = socket(AF_INET, SOCK_STREAM, 0); check_err(tp.sock < 0, "socket"); - int on = 1; #ifndef _WIN32 - check_err(setsockopt(tp.sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)), "setsockopt"); + int on = 1; + check_err(setsockopt(tp.sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)), "setsockopt");;; #endif struct sockaddr_in addr = {0}; addr.sin_family = AF_INET; /* set the type of connection to TCP/IP */ --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org For additional commands, e-mail: commits-h...@qpid.apache.org