Commit 7ab03028 authored by Dennis Jenkins's avatar Dennis Jenkins

Issue #383: Implemented ephemeral TCP port for listener, exposed in endpoint. ...

Issue #383: Implemented ephemeral TCP port for listener, exposed in endpoint.  Requires additional logic outside of Pistache for maximal benefit.  To get an ephemeral port, just create an Address or Port with a TCP port number of 0, then call Endpoint::getPort() after the Pistache accept thread has created the socket.
parent fc16ec32
......@@ -53,6 +53,10 @@ public:
return listener.isBound();
}
Port getPort() const {
return listener.getPort();
}
Async::Promise<Tcp::Listener::Load> requestLoad(const Tcp::Listener::Load& old);
static Options options();
......
......@@ -53,6 +53,7 @@ public:
void bind(const Address& address);
bool isBound() const;
Port getPort() const;
void run();
void runThreaded();
......
......@@ -184,7 +184,7 @@ Listener::bind(const Address& address) {
TRY(::listen(fd, backlog_));
break;
}
// At this point, it is still possible that we couldn't bind any socket. If it is the case, the previous
// loop would have exited naturally and addr will be null.
if (addr == nullptr) {
......@@ -207,6 +207,31 @@ Listener::isBound() const {
return listen_fd != -1;
}
// Return actual TCP port Listener is on, or 0 on error / no port.
// Notes:
// 1) Default constructor for 'Port()' sets value to 0.
// 2) Socket is created inside 'Listener::run()', which is called from
// 'Endpoint::serve()' and 'Endpoint::serveThreaded()'. So getting the
// port is only useful if you attempt to do so from a _different_ thread
// than the one running 'Listener::run()'. So for a traditional single-
// threaded program this method is of little value.
Port
Listener::getPort() const {
if (listen_fd == -1) {
return Port();
}
struct sockaddr_in sock_addr = {0};
socklen_t addrlen = sizeof(sock_addr);
auto sock_addr_alias = reinterpret_cast<struct sockaddr*>(&sock_addr);
if (-1 == getsockname(listen_fd, sock_addr_alias, &addrlen)) {
return Port();
}
return Port(ntohs(sock_addr.sin_port));
}
void
Listener::run() {
reactor_.run();
......
......@@ -179,3 +179,16 @@ TEST(listener_test, listener_bind_port_not_free_throw_runtime) {
FAIL() << "Expected std::runtime_error";
}
}
// Listener should be able to bind port 0 directly to get an ephemeral port.
TEST(listener_test, listener_bind_ephemeral_port) {
Pistache::Port port(0);
Pistache::Address address(Pistache::Ipv4::any(), port);
Pistache::Tcp::Listener listener;
listener.setHandler(Pistache::Http::make_handler<DummyHandler>());
listener.bind(address);
Pistache::Port bound_port = listener.getPort();
ASSERT_TRUE(bound_port > (uint16_t)0);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment