Unverified Commit 385c78fb authored by Dennis Jenkins's avatar Dennis Jenkins Committed by GitHub

Merge pull request #385 from dennisjenkins75/ephemeral-ports

Ephemeral ports
parents f8265da3 ce55436b
...@@ -53,6 +53,10 @@ public: ...@@ -53,6 +53,10 @@ public:
return listener.isBound(); return listener.isBound();
} }
Port getPort() const {
return listener.getPort();
}
Async::Promise<Tcp::Listener::Load> requestLoad(const Tcp::Listener::Load& old); Async::Promise<Tcp::Listener::Load> requestLoad(const Tcp::Listener::Load& old);
static Options options(); static Options options();
......
...@@ -53,6 +53,7 @@ public: ...@@ -53,6 +53,7 @@ public:
void bind(const Address& address); void bind(const Address& address);
bool isBound() const; bool isBound() const;
Port getPort() const;
void run(); void run();
void runThreaded(); void runThreaded();
......
...@@ -184,7 +184,7 @@ Listener::bind(const Address& address) { ...@@ -184,7 +184,7 @@ Listener::bind(const Address& address) {
TRY(::listen(fd, backlog_)); TRY(::listen(fd, backlog_));
break; break;
} }
// At this point, it is still possible that we couldn't bind any socket. If it is the case, the previous // 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. // loop would have exited naturally and addr will be null.
if (addr == nullptr) { if (addr == nullptr) {
...@@ -207,6 +207,31 @@ Listener::isBound() const { ...@@ -207,6 +207,31 @@ Listener::isBound() const {
return listen_fd != -1; 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 void
Listener::run() { Listener::run() {
reactor_.run(); reactor_.run();
......
...@@ -179,3 +179,16 @@ TEST(listener_test, listener_bind_port_not_free_throw_runtime) { ...@@ -179,3 +179,16 @@ TEST(listener_test, listener_bind_port_not_free_throw_runtime) {
FAIL() << "Expected std::runtime_error"; 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