kudu-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From danburk...@apache.org
Subject kudu git commit: rpc: add experimental rpc_reuseport flag
Date Thu, 03 May 2018 16:53:07 GMT
Repository: kudu
Updated Branches:
  refs/heads/master 96fa80503 -> eded05723


rpc: add experimental rpc_reuseport flag

This option sets the SO_REUSEPORT socket option on a server's bound
socket. This socket option is supported on all platforms which Kudu
supports, except RHEL 6.4 and below.

The motivation is to use the option in the minicluster so that master
ports can be reserved by the mini cluster control processes and reused
by the master processes.

When rpc_reuseport is set on RHEL 6.4 the server fails to startup with
the following message (which is expected):

$ cat /etc/redhat-release
CentOS release 6.4 (Final)
$ ./kudu-master --fs-wal-dir=/tmp/kudu-master --logtostderr --unlock-experimental-flags --rpc-reuseport=true
...
F0501 14:56:30.672461  3271 master_main.cc:74] Check failed: _s.ok() Bad status: Network error:
failed to set SO_REUSEPORT: Protocol not available (error 92)

Change-Id: I5d8ce9faa646fa2be554f5cfdf8b6ed0c48b496e
Reviewed-on: http://gerrit.cloudera.org:8080/8279
Reviewed-by: Alexey Serbin <aserbin@cloudera.com>
Tested-by: Kudu Jenkins


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/eded0572
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/eded0572
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/eded0572

Branch: refs/heads/master
Commit: eded05723e6166b676074c5a548ac1278c7c4401
Parents: 96fa805
Author: Dan Burkert <danburkert@apache.org>
Authored: Sun Oct 15 12:16:30 2017 -0700
Committer: Dan Burkert <danburkert@apache.org>
Committed: Thu May 3 16:52:50 2018 +0000

----------------------------------------------------------------------
 src/kudu/rpc/messenger.cc        |  12 +++-
 src/kudu/rpc/messenger.h         |   7 +++
 src/kudu/rpc/rpc-test.cc         |   4 +-
 src/kudu/server/rpc_server.cc    |   7 ++-
 src/kudu/server/rpc_server.h     |   1 +
 src/kudu/server/server_base.cc   |   4 ++
 src/kudu/util/net/socket-test.cc |   2 +-
 src/kudu/util/net/socket.cc      | 114 +++++++++++++++-------------------
 src/kudu/util/net/socket.h       |   7 +++
 9 files changed, 88 insertions(+), 70 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/eded0572/src/kudu/rpc/messenger.cc
----------------------------------------------------------------------
diff --git a/src/kudu/rpc/messenger.cc b/src/kudu/rpc/messenger.cc
index 67cd502..17ac0c5 100644
--- a/src/kudu/rpc/messenger.cc
+++ b/src/kudu/rpc/messenger.cc
@@ -81,7 +81,8 @@ MessengerBuilder::MessengerBuilder(std::string name)
       rpc_encryption_("optional"),
       rpc_tls_ciphers_(kudu::security::SecurityDefaults::kDefaultTlsCiphers),
       rpc_tls_min_protocol_(kudu::security::SecurityDefaults::kDefaultTlsMinVersion),
-      enable_inbound_tls_(false) {
+      enable_inbound_tls_(false),
+      reuseport_(false) {
 }
 
 MessengerBuilder& MessengerBuilder::set_connection_keepalive_time(const MonoDelta &keepalive)
{
@@ -178,6 +179,11 @@ MessengerBuilder& MessengerBuilder::enable_inbound_tls() {
   return *this;
 }
 
+MessengerBuilder& MessengerBuilder::set_reuseport() {
+  reuseport_ = true;
+  return *this;
+}
+
 Status MessengerBuilder::Build(shared_ptr<Messenger> *msgr) {
   // Initialize SASL library before we start making requests
   RETURN_NOT_OK(SaslInit(!keytab_file_.empty()));
@@ -311,6 +317,9 @@ Status Messenger::AddAcceptorPool(const Sockaddr &accept_addr,
   Socket sock;
   RETURN_NOT_OK(sock.Init(0));
   RETURN_NOT_OK(sock.SetReuseAddr(true));
+  if (reuseport_) {
+    RETURN_NOT_OK(sock.SetReusePort(true));
+  }
   RETURN_NOT_OK(sock.Bind(accept_addr));
   Sockaddr remote;
   RETURN_NOT_OK(sock.GetSocketAddress(&remote));
@@ -402,6 +411,7 @@ Messenger::Messenger(const MessengerBuilder &bld)
     rpc_negotiation_timeout_ms_(bld.rpc_negotiation_timeout_ms_),
     sasl_proto_name_(bld.sasl_proto_name_),
     keytab_file_(bld.keytab_file_),
+    reuseport_(bld.reuseport_),
     retain_self_(this) {
   for (int i = 0; i < bld.num_reactors_; i++) {
     reactors_.push_back(new Reactor(retain_self_, i, bld));

http://git-wip-us.apache.org/repos/asf/kudu/blob/eded0572/src/kudu/rpc/messenger.h
----------------------------------------------------------------------
diff --git a/src/kudu/rpc/messenger.h b/src/kudu/rpc/messenger.h
index 3835cea..64a804b 100644
--- a/src/kudu/rpc/messenger.h
+++ b/src/kudu/rpc/messenger.h
@@ -163,6 +163,9 @@ class MessengerBuilder {
   // Configure the messenger to enable TLS encryption on inbound connections.
   MessengerBuilder& enable_inbound_tls();
 
+  // Configure the messenger to set the SO_REUSEPORT socket option.
+  MessengerBuilder& set_reuseport();
+
   Status Build(std::shared_ptr<Messenger> *msgr);
 
  private:
@@ -185,6 +188,7 @@ class MessengerBuilder {
   std::string rpc_private_key_password_cmd_;
   std::string keytab_file_;
   bool enable_inbound_tls_;
+  bool reuseport_;
 };
 
 // A Messenger is a container for the reactor threads which run event loops
@@ -399,6 +403,9 @@ class Messenger {
   // Path to the Kerberos Keytab file for this server.
   const std::string keytab_file_;
 
+  // Whether to set SO_REUSEPORT on the listening sockets.
+  bool reuseport_;
+
   // The ownership of the Messenger object is somewhat subtle. The pointer graph
   // looks like this:
   //

http://git-wip-us.apache.org/repos/asf/kudu/blob/eded0572/src/kudu/rpc/rpc-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/rpc/rpc-test.cc b/src/kudu/rpc/rpc-test.cc
index 89ea70d..077b5a3 100644
--- a/src/kudu/rpc/rpc-test.cc
+++ b/src/kudu/rpc/rpc-test.cc
@@ -802,10 +802,10 @@ TEST_P(TestRpc, TestRpcSidecarLimits) {
     ASSERT_STR_MATCHES(status.ToString(),
                        // Linux
                        "Connection reset by peer"
+                       // While reading from socket.
+                       "|recv got EOF from"
                        // Linux, SSL enabled
                        "|failed to read from TLS socket"
-                       // macOS, while reading from socket.
-                       "|got EOF from remote"
                        // macOS, while writing to socket.
                        "|Protocol wrong type for socket"
                        // macOS, sendmsg(): the sum of the iov_len values overflows an ssize_t

http://git-wip-us.apache.org/repos/asf/kudu/blob/eded0572/src/kudu/server/rpc_server.cc
----------------------------------------------------------------------
diff --git a/src/kudu/server/rpc_server.cc b/src/kudu/server/rpc_server.cc
index fc8be32..1c6eeab 100644
--- a/src/kudu/server/rpc_server.cc
+++ b/src/kudu/server/rpc_server.cc
@@ -80,6 +80,10 @@ DEFINE_bool(rpc_server_allow_ephemeral_ports, false,
             "only allowed in tests.");
 TAG_FLAG(rpc_server_allow_ephemeral_ports, unsafe);
 
+DEFINE_bool(rpc_reuseport, false,
+            "Whether to set the SO_REUSEPORT option on listening RPC sockets.");
+TAG_FLAG(rpc_reuseport, experimental);
+
 namespace kudu {
 
 RpcServerOptions::RpcServerOptions()
@@ -88,7 +92,8 @@ RpcServerOptions::RpcServerOptions()
     num_acceptors_per_address(FLAGS_rpc_num_acceptors_per_address),
     num_service_threads(FLAGS_rpc_num_service_threads),
     default_port(0),
-    service_queue_length(FLAGS_rpc_service_queue_length) {
+    service_queue_length(FLAGS_rpc_service_queue_length),
+    rpc_reuseport(FLAGS_rpc_reuseport) {
 }
 
 RpcServer::RpcServer(RpcServerOptions opts)

http://git-wip-us.apache.org/repos/asf/kudu/blob/eded0572/src/kudu/server/rpc_server.h
----------------------------------------------------------------------
diff --git a/src/kudu/server/rpc_server.h b/src/kudu/server/rpc_server.h
index bba385e..6d32c12 100644
--- a/src/kudu/server/rpc_server.h
+++ b/src/kudu/server/rpc_server.h
@@ -52,6 +52,7 @@ struct RpcServerOptions {
   uint32_t num_service_threads;
   uint16_t default_port;
   size_t service_queue_length;
+  bool rpc_reuseport;
 };
 
 class RpcServer {

http://git-wip-us.apache.org/repos/asf/kudu/blob/eded0572/src/kudu/server/server_base.cc
----------------------------------------------------------------------
diff --git a/src/kudu/server/server_base.cc b/src/kudu/server/server_base.cc
index 8834573..f693a73 100644
--- a/src/kudu/server/server_base.cc
+++ b/src/kudu/server/server_base.cc
@@ -470,6 +470,10 @@ Status ServerBase::Init() {
          .set_keytab_file(FLAGS_keytab_file)
          .enable_inbound_tls();
 
+  if (options_.rpc_opts.rpc_reuseport) {
+    builder.set_reuseport();
+  }
+
   RETURN_NOT_OK(builder.Build(&messenger_));
   rpc_server_->set_too_busy_hook(std::bind(
       &ServerBase::ServiceQueueOverflowed, this, std::placeholders::_1));

http://git-wip-us.apache.org/repos/asf/kudu/blob/eded0572/src/kudu/util/net/socket-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/util/net/socket-test.cc b/src/kudu/util/net/socket-test.cc
index b69879f..8ecea4e 100644
--- a/src/kudu/util/net/socket-test.cc
+++ b/src/kudu/util/net/socket-test.cc
@@ -84,6 +84,6 @@ TEST_F(SocketTest, TestRecvReset) {
 }
 
 TEST_F(SocketTest, TestRecvEOF) {
-  DoTest(true, "Recv\\(\\) got EOF from remote 127.0.0.1:[0-9]+");
+  DoTest(true, "recv got EOF from 127.0.0.1:[0-9]+");
 }
 } // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/eded0572/src/kudu/util/net/socket.cc
----------------------------------------------------------------------
diff --git a/src/kudu/util/net/socket.cc b/src/kudu/util/net/socket.cc
index 5ea1b70..f1d2466 100644
--- a/src/kudu/util/net/socket.cc
+++ b/src/kudu/util/net/socket.cc
@@ -61,6 +61,9 @@ DEFINE_bool(socket_inject_short_recvs, false,
 TAG_FLAG(socket_inject_short_recvs, hidden);
 TAG_FLAG(socket_inject_short_recvs, unsafe);
 
+using std::string;
+using strings::Substitute;
+
 namespace kudu {
 
 Socket::Socket()
@@ -93,8 +96,7 @@ Status Socket::Close() {
   int fd = fd_;
   if (::close(fd) < 0) {
     int err = errno;
-    return Status::NetworkError(std::string("close error: ") +
-                                ErrnoToString(err), Slice(), err);
+    return Status::NetworkError("close error", ErrnoToString(err), err);
   }
   fd_ = -1;
   return Status::OK();
@@ -112,8 +114,7 @@ Status Socket::Shutdown(bool shut_read, bool shut_write) {
   }
   if (::shutdown(fd_, flags) < 0) {
     int err = errno;
-    return Status::NetworkError(std::string("shutdown error: ") +
-                                ErrnoToString(err), Slice(), err);
+    return Status::NetworkError("shutdown error", ErrnoToString(err), err);
   }
   return Status::OK();
 }
@@ -133,8 +134,7 @@ Status Socket::Init(int flags) {
   Reset(::socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC | nonblocking_flag, 0));
   if (fd_ < 0) {
     int err = errno;
-    return Status::NetworkError(std::string("error opening socket: ") +
-                                ErrnoToString(err), Slice(), err);
+    return Status::NetworkError("error opening socket", ErrnoToString(err), err);
   }
 
   return Status::OK();
@@ -146,20 +146,15 @@ Status Socket::Init(int flags) {
   Reset(::socket(AF_INET, SOCK_STREAM, 0));
   if (fd_ < 0) {
     int err = errno;
-    return Status::NetworkError(std::string("error opening socket: ") +
-                                ErrnoToString(err), Slice(), err);
+    return Status::NetworkError("error opening socket", ErrnoToString(err), err);
   }
   RETURN_NOT_OK(SetNonBlocking(flags & FLAG_NONBLOCKING));
   RETURN_NOT_OK(SetCloseOnExec());
 
   // Disable SIGPIPE.
   int set = 1;
-  if (setsockopt(fd_, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(set)) == -1) {
-    int err = errno;
-    return Status::NetworkError(std::string("failed to set SO_NOSIGPIPE: ") +
-                                ErrnoToString(err), Slice(), err);
-  }
-
+  RETURN_NOT_OK_PREPEND(SetSockOpt(SOL_SOCKET, SO_NOSIGPIPE, set),
+                        "failed to set SO_NOSIGPIPE");
   return Status::OK();
 }
 
@@ -167,24 +162,18 @@ Status Socket::Init(int flags) {
 
 Status Socket::SetNoDelay(bool enabled) {
   int flag = enabled ? 1 : 0;
-  if (setsockopt(fd_, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) == -1) {
-    int err = errno;
-    return Status::NetworkError(std::string("failed to set TCP_NODELAY: ") +
-                                ErrnoToString(err), Slice(), err);
-  }
+  RETURN_NOT_OK_PREPEND(SetSockOpt(IPPROTO_TCP, TCP_NODELAY, flag),
+                        "failed to set TCP_NODELAY");
   return Status::OK();
 }
 
 Status Socket::SetTcpCork(bool enabled) {
 #if defined(__linux__)
   int flag = enabled ? 1 : 0;
-  if (setsockopt(fd_, IPPROTO_TCP, TCP_CORK, &flag, sizeof(flag)) == -1) {
-    int err = errno;
-    return Status::NetworkError(std::string("failed to set TCP_CORK: ") +
-                                ErrnoToString(err), Slice(), err);
-  }
+  RETURN_NOT_OK_PREPEND(SetSockOpt(IPPROTO_TCP, TCP_CORK, flag),
+                        "failed to set TCP_CORK");
 #endif // defined(__linux__)
-  // TODO: Use TCP_NOPUSH for OSX if perf becomes an issue.
+  // TODO(unknown): Use TCP_NOPUSH for OSX if perf becomes an issue.
   return Status::OK();
 }
 
@@ -229,14 +218,12 @@ Status Socket::SetCloseOnExec() {
   if (curflags == -1) {
     int err = errno;
     Reset(-1);
-    return Status::NetworkError(std::string("fcntl(F_GETFD) error: ") +
-                                ErrnoToString(err), Slice(), err);
+    return Status::NetworkError("fcntl(F_GETFD) error", ErrnoToString(err), err);
   }
   if (fcntl(fd_, F_SETFD, curflags | FD_CLOEXEC) == -1) {
     int err = errno;
     Reset(-1);
-    return Status::NetworkError(std::string("fcntl(F_SETFD) error: ") +
-                                ErrnoToString(err), Slice(), err);
+    return Status::NetworkError("fcntl(F_SETFD) error", ErrnoToString(err), err);
   }
   return Status::OK();
 }
@@ -250,13 +237,16 @@ Status Socket::SetRecvTimeout(const MonoDelta& timeout) {
 }
 
 Status Socket::SetReuseAddr(bool flag) {
-  int err;
   int int_flag = flag ? 1 : 0;
-  if (setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, &int_flag, sizeof(int_flag)) == -1) {
-    err = errno;
-    return Status::NetworkError(std::string("failed to set SO_REUSEADDR: ") +
-                                ErrnoToString(err), Slice(), err);
-  }
+  RETURN_NOT_OK_PREPEND(SetSockOpt(SOL_SOCKET, SO_REUSEADDR, int_flag),
+                        "failed to set SO_REUSEADDR");
+  return Status::OK();
+}
+
+Status Socket::SetReusePort(bool flag) {
+  int int_flag = flag ? 1 : 0;
+  RETURN_NOT_OK_PREPEND(SetSockOpt(SOL_SOCKET, SO_REUSEPORT, int_flag),
+                        "failed to set SO_REUSEPORT");
   return Status::OK();
 }
 
@@ -280,10 +270,9 @@ Status Socket::GetSocketAddress(Sockaddr *cur_addr) const {
   struct sockaddr_in sin;
   socklen_t len = sizeof(sin);
   DCHECK_GE(fd_, 0);
-  if (::getsockname(fd_, (struct sockaddr *)&sin, &len) == -1) {
+  if (::getsockname(fd_, reinterpret_cast<struct sockaddr*>(&sin), &len) ==
-1) {
     int err = errno;
-    return Status::NetworkError(std::string("getsockname error: ") +
-                                ErrnoToString(err), Slice(), err);
+    return Status::NetworkError("getsockname error", ErrnoToString(err), err);
   }
   *cur_addr = sin;
   return Status::OK();
@@ -293,10 +282,9 @@ Status Socket::GetPeerAddress(Sockaddr *cur_addr) const {
   struct sockaddr_in sin;
   socklen_t len = sizeof(sin);
   DCHECK_GE(fd_, 0);
-  if (::getpeername(fd_, (struct sockaddr *)&sin, &len) == -1) {
+  if (::getpeername(fd_, reinterpret_cast<struct sockaddr*>(&sin), &len) ==
-1) {
     int err = errno;
-    return Status::NetworkError(std::string("getpeername error: ") +
-                                ErrnoToString(err), Slice(), err);
+    return Status::NetworkError("getpeername error", ErrnoToString(err), err);
   }
   *cur_addr = sin;
   return Status::OK();
@@ -348,8 +336,7 @@ Status Socket::Accept(Socket *new_conn, Sockaddr *remote, int flags) {
                              &olen, accept_flags));
   if (fd < 0) {
     int err = errno;
-    return Status::NetworkError(std::string("accept4(2) error: ") +
-                                ErrnoToString(err), Slice(), err);
+    return Status::NetworkError("accept4(2) error", ErrnoToString(err), err);
   }
   new_conn->Reset(fd);
 
@@ -358,8 +345,7 @@ Status Socket::Accept(Socket *new_conn, Sockaddr *remote, int flags) {
   RETRY_ON_EINTR(fd, accept(fd_, (struct sockaddr*)&addr, &olen));
   if (fd < 0) {
     int err = errno;
-    return Status::NetworkError(std::string("accept(2) error: ") +
-                                ErrnoToString(err), Slice(), err);
+    return Status::NetworkError("accept(2) error", ErrnoToString(err), err);
   }
   new_conn->Reset(fd);
   RETURN_NOT_OK(new_conn->SetNonBlocking(flags & FLAG_NONBLOCKING));
@@ -393,10 +379,9 @@ Status Socket::Connect(const Sockaddr &remote) {
   struct sockaddr_in addr;
   memcpy(&addr, &remote.addr(), sizeof(sockaddr_in));
   DCHECK_GE(fd_, 0);
-  if (::connect(fd_, (const struct sockaddr*)&addr, sizeof(addr)) < 0) {
+  if (::connect(fd_, reinterpret_cast<const struct sockaddr*>(&addr), sizeof(addr))
< 0) {
     int err = errno;
-    return Status::NetworkError(std::string("connect(2) error: ") +
-                                ErrnoToString(err), Slice(), err);
+    return Status::NetworkError("connect(2) error", ErrnoToString(err), err);
   }
   return Status::OK();
 }
@@ -408,8 +393,7 @@ Status Socket::GetSockError() const {
   ret = ::getsockopt(fd_, SOL_SOCKET, SO_ERROR, &val, &val_len);
   if (ret) {
     int err = errno;
-    return Status::NetworkError(std::string("getsockopt(SO_ERROR) failed: ") +
-                                ErrnoToString(err), Slice(), err);
+    return Status::NetworkError("getsockopt(SO_ERROR) failed", ErrnoToString(err), err);
   }
   if (val != 0) {
     return Status::NetworkError(ErrnoToString(val), Slice(), val);
@@ -427,8 +411,7 @@ Status Socket::Write(const uint8_t *buf, int32_t amt, int32_t *nwritten)
{
   int res = ::send(fd_, buf, amt, MSG_NOSIGNAL);
   if (res < 0) {
     int err = errno;
-    return Status::NetworkError(std::string("write error: ") +
-                                ErrnoToString(err), Slice(), err);
+    return Status::NetworkError("write error", ErrnoToString(err), err);
   }
   *nwritten = res;
   return Status::OK();
@@ -451,8 +434,7 @@ Status Socket::Writev(const struct ::iovec *iov, int iov_len,
   ssize_t res = ::sendmsg(fd_, &msg, MSG_NOSIGNAL);
   if (PREDICT_FALSE(res < 0)) {
     int err = errno;
-    return Status::NetworkError(std::string("sendmsg error: ") +
-                                ErrnoToString(err), Slice(), err);
+    return Status::NetworkError("sendmsg error", ErrnoToString(err), err);
   }
 
   *nwritten = res;
@@ -524,15 +506,12 @@ Status Socket::Recv(uint8_t *buf, int32_t amt, int32_t *nread) {
     Sockaddr remote;
     GetPeerAddress(&remote);
     if (res == 0) {
-      std::string error_message = strings::Substitute("Recv() got EOF from remote $0",
-                                                      remote.ToString());
+      string error_message = Substitute("recv got EOF from $0", remote.ToString());
       return Status::NetworkError(error_message, Slice(), ESHUTDOWN);
     }
     int err = errno;
-    std::string error_message = strings::Substitute("recv error from $0: $1",
-                                                    remote.ToString(),
-                                                    ErrnoToString(err));
-    return Status::NetworkError(error_message, Slice(), err);
+    string error_message = Substitute("recv error from $0", remote.ToString());
+    return Status::NetworkError(error_message, ErrnoToString(err), err);
   }
   *nread = res;
   return Status::OK();
@@ -587,12 +566,17 @@ Status Socket::SetTimeout(int opt, const char* optname, const MonoDelta&
timeout
   }
   struct timeval tv;
   timeout.ToTimeVal(&tv);
-  socklen_t optlen = sizeof(tv);
-  if (::setsockopt(fd_, SOL_SOCKET, opt, &tv, optlen) == -1) {
+  RETURN_NOT_OK_PREPEND(SetSockOpt(SOL_SOCKET, opt, tv),
+                        Substitute("failed to set socket option $0 to $1",
+                                   optname, timeout.ToString()));
+  return Status::OK();
+}
+
+template<typename T>
+Status Socket::SetSockOpt(int level, int option, const T& value) {
+  if (::setsockopt(fd_, level, option, &value, sizeof(T)) == -1) {
     int err = errno;
-    return Status::NetworkError(
-        StringPrintf("Failed to set %s to %s", optname, timeout.ToString().c_str()),
-        ErrnoToString(err), err);
+    return Status::NetworkError(ErrnoToString(err), Slice(), err);
   }
   return Status::OK();
 }

http://git-wip-us.apache.org/repos/asf/kudu/blob/eded0572/src/kudu/util/net/socket.h
----------------------------------------------------------------------
diff --git a/src/kudu/util/net/socket.h b/src/kudu/util/net/socket.h
index 0b1c83b..992c44a 100644
--- a/src/kudu/util/net/socket.h
+++ b/src/kudu/util/net/socket.h
@@ -85,6 +85,9 @@ class Socket {
   // Sets SO_REUSEADDR to 'flag'. Should be used prior to Bind().
   Status SetReuseAddr(bool flag);
 
+  // Sets SO_REUSEPORT to 'flag'. Should be used prior to Bind().
+  Status SetReusePort(bool flag);
+
   // Convenience method to invoke the common sequence:
   // 1) SetReuseAddr(true)
   // 2) Bind()
@@ -161,6 +164,10 @@ class Socket {
   // based on the value of FLAGS_local_ip_for_outbound_sockets.
   Status BindForOutgoingConnection();
 
+  // Set an option on the socket.
+  template<typename T>
+  Status SetSockOpt(int level, int option, const T& value);
+
   int fd_;
 
   DISALLOW_COPY_AND_ASSIGN(Socket);


Mime
View raw message