diff --git a/include/cucumber-cpp/internal/connectors/wire/WireServer.hpp b/include/cucumber-cpp/internal/connectors/wire/WireServer.hpp index f0900698..63b10377 100644 --- a/include/cucumber-cpp/internal/connectors/wire/WireServer.hpp +++ b/include/cucumber-cpp/internal/connectors/wire/WireServer.hpp @@ -63,6 +63,11 @@ class TCPSocketServer : public SocketServer { */ void listen(const port_type port); + /** + * Bind and listen to a TCP port on the given endpoint + */ + void listen(const tcp::endpoint endpoint); + /** * Endpoint (IP address and port number) that this server is currently * listening on. diff --git a/src/connectors/wire/WireServer.cpp b/src/connectors/wire/WireServer.cpp index 737ca1c5..9d8e268d 100644 --- a/src/connectors/wire/WireServer.cpp +++ b/src/connectors/wire/WireServer.cpp @@ -45,7 +45,11 @@ TCPSocketServer::TCPSocketServer(const ProtocolHandler *protocolHandler) : } void TCPSocketServer::listen(const port_type port) { - doListen(acceptor, tcp::endpoint(tcp::v4(), port)); + listen(tcp::endpoint(tcp::v4(), port)); +} + +void TCPSocketServer::listen(const tcp::endpoint endpoint) { + doListen(acceptor, endpoint); acceptor.set_option(tcp::no_delay(true)); } diff --git a/src/main.cpp b/src/main.cpp index 4d8ab551..02845a18 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,7 +7,7 @@ namespace { -void acceptWireProtocol(int port, const std::string& unixPath, bool verbose) { +void acceptWireProtocol(const std::string& host, int port, const std::string& unixPath, bool verbose) { using namespace ::cucumber::internal; CukeEngineImpl cukeEngine; JsonSpiritWireMessageCodec wireCodec; @@ -27,9 +27,9 @@ void acceptWireProtocol(int port, const std::string& unixPath, bool verbose) { { TCPSocketServer* const tcpServer = new TCPSocketServer(&protocolHandler); server.reset(tcpServer); - tcpServer->listen(port); + tcpServer->listen(tcp::endpoint(boost::asio::ip::address::from_string(host), port)); if (verbose) - std::clog << "Listening on port " << tcpServer->listenEndpoint() << std::endl; + std::clog << "Listening on " << tcpServer->listenEndpoint() << std::endl; } server->acceptOnce(); } @@ -42,6 +42,7 @@ int main(int argc, char **argv) { optionDescription.add_options() ("help,h", "help for cucumber-cpp") ("verbose,v", "verbose output") + ("listen,l", value(), "listening address of wireserver") ("port,p", value(), "listening port of wireserver, use '0' (zero) to select an ephemeral port") #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) ("unix,u", value(), "listening unix socket of wireserver (disables listening on port)") @@ -56,6 +57,11 @@ int main(int argc, char **argv) { exit(1); } + std::string listenHost("127.0.0.1"); + if (optionVariableMap.count("listen")) { + listenHost = optionVariableMap["listen"].as(); + } + int port = 3902; if (optionVariableMap.count("port")) { port = optionVariableMap["port"].as(); @@ -74,7 +80,7 @@ int main(int argc, char **argv) { } try { - acceptWireProtocol(port, unixPath, verbose); + acceptWireProtocol(listenHost, port, unixPath, verbose); } catch (std::exception &e) { std::cerr << e.what() << std::endl; exit(1); diff --git a/tests/integration/WireServerTest.cpp b/tests/integration/WireServerTest.cpp index d8373133..c1518ac5 100644 --- a/tests/integration/WireServerTest.cpp +++ b/tests/integration/WireServerTest.cpp @@ -100,6 +100,7 @@ TEST_F(TCPSocketServerTest, exitsOnFirstConnectionClosed) { // given tcp::iostream client(server->listenEndpoint()); ASSERT_THAT(client, IsConnected()); + ASSERT_THAT(server->listenEndpoint().address().to_string(), std::string("0.0.0.0")); // when client.close(); @@ -142,6 +143,34 @@ TEST_F(TCPSocketServerTest, receiveAndSendsSingleLineMassages) { EXPECT_THAT(client, EventuallyReceives("C")); } +class TCPSocketServerLocalhostTest : public SocketServerTest { +protected: + boost::scoped_ptr server; + + virtual SocketServer* createListeningServer() { + server.reset(new TCPSocketServer(&protocolHandler)); + server->listen(tcp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 0)); + return server.get(); + } + + virtual void destroyListeningServer() { + server.reset(); + } +}; + +TEST_F(TCPSocketServerLocalhostTest, listensOnLocalhost) { + // given + tcp::iostream client(server->listenEndpoint()); + ASSERT_THAT(client, IsConnected()); + ASSERT_THAT(server->listenEndpoint().address().to_string(), std::string("127.0.0.1")); + + // when + client.close(); + + // then + EXPECT_THAT(serverThread, EventuallyTerminates()); +} + #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) class UnixSocketServerTest : public SocketServerTest { protected: