Commit a6579040 authored by gejun's avatar gejun

r35395: server supports port=0

parent b98af84f
......@@ -646,6 +646,15 @@ struct RevertServerStatus {
}
};
static int get_port_from_fd(int fd) {
struct sockaddr_in addr;
socklen_t size = sizeof(addr);
if (getsockname(fd, (struct sockaddr*)&addr, &size) < 0) {
return -1;
}
return ntohs(addr.sin_port);
}
int Server::StartInternal(const butil::ip_t& ip,
const PortRange& port_range,
const ServerOptions *opt) {
......@@ -877,6 +886,15 @@ int Server::StartInternal(const butil::ip_t& ip,
}
return -1;
}
if (_listen_addr.port == 0) {
// port=0 makes kernel dynamically select a port from
// https://en.wikipedia.org/wiki/Ephemeral_port
_listen_addr.port = get_port_from_fd(sockfd);
if (_listen_addr.port <= 0) {
LOG(ERROR) << "Fail to get port from fd=" << sockfd;
return -1;
}
}
if (_am == NULL) {
_am = BuildAcceptor();
if (NULL == _am) {
......@@ -906,6 +924,12 @@ int Server::StartInternal(const butil::ip_t& ip,
<< " is same with port=" << _listen_addr.port << " to Start()";
return -1;
}
if (_options.internal_port == 0) {
LOG(ERROR) << "ServerOptions.internal_port cannot be 0, which"
" allocates a dynamic and probabaly unfiltered port,"
" against the purpose of \"being internal\".";
return -1;
}
butil::EndPoint internal_point = _listen_addr;
internal_point.port = _options.internal_port;
butil::fd_guard sockfd(tcp_listen(internal_point, FLAGS_reuse_addr));
......
......@@ -409,28 +409,25 @@ public:
Server(ProfilerLinker = ProfilerLinker());
~Server();
// Start this server. Use default options if `opt' is NULL.
// This function can be called multiple times if the server is completely
// stopped by Stop() and Join().
// A set of functions to start this server.
// Returns 0 on success, -1 otherwise and errno is set appropriately.
// Notes:
// * Default options are taken if `opt' is NULL.
// * A server can be started more than once if the server is completely
// stopped by Stop() and Join().
// * port can be 0, which makes kernel to choose a port dynamically.
// Start on a single address "0.0.0.0:8000".
// Start on an address in form of "0.0.0.0:8000".
int Start(const char* ip_port_str, const ServerOptions* opt);
int Start(const butil::EndPoint& ip_port, const ServerOptions* opt);
// Start on IP_ANY:port.
int Start(int port, const ServerOptions* opt);
// Start on ip:port enclosed in butil::EndPoint which is defined in
// src/butil/endpoint.h
int Start(const butil::EndPoint& ip_port, const ServerOptions* opt);
// Start on `ip_str' + any useable port in `port_range'
int Start(const char* ip_str, PortRange port_range,
const ServerOptions *opt);
// Start on `ip_str' + any useable port in `range'
int Start(const char* ip_str, PortRange range, const ServerOptions *opt);
// NOTE: Stop() is paired with Join() to stop a server with minimum lost
// of requests. The point of separating them is that you can Stop()
// multiple servers before Join()-ing them, the total time to Join is
// NOTE: Stop() is paired with Join() to stop a server without losing
// requests. The point of separating them is that you can Stop() multiple
// servers before Join() them, in which case the total time to Join is
// time of the slowest Join(). Otherwise you have to Join() them one by
// one, in which case the total time is sum of all Join().
......
......@@ -164,6 +164,13 @@ TEST_F(ServerTest, sanity) {
// accept hostname as well.
ASSERT_EQ(0, server.Start("localhost:8613", NULL));
}
{
brpc::Server server;
ASSERT_EQ(0, server.Start("localhost:0", NULL));
// port should be replaced with the actually used one.
ASSERT_NE(0, server.listen_address().port);
}
{
brpc::Server server;
ASSERT_EQ(-1, server.Start(99999, NULL));
......
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