Merge pull request #1483 from skypexu/bind_reuseport_fix

Add a new bind() and bind6() interface and make REUSEPORT as an option.
This commit is contained in:
Günter Obiltschnig 2016-11-09 10:23:54 +01:00 committed by GitHub
commit 2c35d50889
10 changed files with 192 additions and 4 deletions

View File

@ -89,6 +89,20 @@ public:
/// ///
/// Calls to connect cannot() come before calls to bind(). /// Calls to connect cannot() come before calls to bind().
void bind(const SocketAddress& address, bool reuseAddress, bool reusePort);
/// Bind a local address to the socket.
///
/// This is usually only done when establishing a server
/// socket.
///
/// If reuseAddress is true, sets the SO_REUSEADDR
/// socket option.
///
/// If reusePort is true, sets the SO_REUSEPORT
/// socket option.
///
/// Calls to connect cannot() come before calls to bind().
int sendBytes(const void* buffer, int length, int flags = 0); int sendBytes(const void* buffer, int length, int flags = 0);
/// Sends the contents of the given buffer through /// Sends the contents of the given buffer through
/// the socket. /// the socket.

View File

@ -82,6 +82,20 @@ public:
/// ///
/// Calls to connect() cannot come before calls to bind(). /// Calls to connect() cannot come before calls to bind().
void bind(const SocketAddress& address, bool reuseAddress, bool reusePort);
/// Bind a local address to the socket.
///
/// This is usually only done when establishing a server
/// socket.
///
/// If reuseAddress is true, sets the SO_REUSEADDR
/// socket option.
///
/// If reusePort is true, sets the SO_REUSEPORT
/// socket option.
///
/// Calls to connect() cannot come before calls to bind().
int sendBytes(const void* buffer, int length, int flags = 0); int sendBytes(const void* buffer, int length, int flags = 0);
/// Sends the contents of the given buffer through /// Sends the contents of the given buffer through
/// the socket. /// the socket.

View File

@ -82,6 +82,19 @@ public:
/// If reuseAddress is true, sets the SO_REUSEADDR /// If reuseAddress is true, sets the SO_REUSEADDR
/// socket option. /// socket option.
virtual void bind(const SocketAddress& address, bool reuseAddress, bool reusePort);
/// Binds a local address to the socket.
///
/// This is usually only done when establishing a server
/// socket. TCP clients should not bind a socket to a
/// specific address.
///
/// If reuseAddress is true, sets the SO_REUSEADDR
/// socket option.
///
/// If reuseAddress is true, sets the SO_REUSEPORT
/// socket option.
virtual void bind(Poco::UInt16 port, bool reuseAddress = false); virtual void bind(Poco::UInt16 port, bool reuseAddress = false);
/// Binds a local port to the socket. /// Binds a local port to the socket.
/// ///
@ -91,6 +104,18 @@ public:
/// If reuseAddress is true, sets the SO_REUSEADDR /// If reuseAddress is true, sets the SO_REUSEADDR
/// socket option. /// socket option.
virtual void bind(Poco::UInt16 port, bool reuseAddress, bool reusePort);
/// Binds a local port to the socket.
///
/// This is usually only done when establishing a server
/// socket.
///
/// If reuseAddress is true, sets the SO_REUSEADDR
/// socket option.
///
/// If reusePort is true, sets the SO_REUSEPORT
/// socket option.
virtual void bind6(const SocketAddress& address, bool reuseAddress = false, bool ipV6Only = false); virtual void bind6(const SocketAddress& address, bool reuseAddress = false, bool ipV6Only = false);
/// Binds a local IPv6 address to the socket. /// Binds a local IPv6 address to the socket.
/// ///
@ -108,6 +133,26 @@ public:
/// If the library has not been built with IPv6 support, /// If the library has not been built with IPv6 support,
/// a Poco::NotImplementedException will be thrown. /// a Poco::NotImplementedException will be thrown.
virtual void bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only);
/// Binds a local IPv6 address to the socket.
///
/// This is usually only done when establishing a server
/// socket. TCP clients should not bind a socket to a
/// specific address.
///
/// If reuseAddress is true, sets the SO_REUSEADDR
/// socket option.
///
/// If reusePort is true, sets the SO_REUSEPORT
/// socket option.
///
/// The given address must be an IPv6 address. The
/// IPPROTO_IPV6/IPV6_V6ONLY option is set on the socket
/// according to the ipV6Only parameter.
///
/// If the library has not been built with IPv6 support,
/// a Poco::NotImplementedException will be thrown.
virtual void bind6(Poco::UInt16 port, bool reuseAddress = false, bool ipV6Only = false); virtual void bind6(Poco::UInt16 port, bool reuseAddress = false, bool ipV6Only = false);
/// Binds a local IPv6 port to the socket. /// Binds a local IPv6 port to the socket.
/// ///
@ -124,6 +169,24 @@ public:
/// If the library has not been built with IPv6 support, /// If the library has not been built with IPv6 support,
/// a Poco::NotImplementedException will be thrown. /// a Poco::NotImplementedException will be thrown.
virtual void bind6(Poco::UInt16 port, bool reuseAddress, bool reusePort, bool ipV6Only);
/// Binds a local IPv6 port to the socket.
///
/// This is usually only done when establishing a server
/// socket.
///
/// If reuseAddress is true, sets the SO_REUSEADDR
/// socket option.
///
/// If reusePort is true, sets the SO_REUSEPORT
/// socket option.
/// The given address must be an IPv6 address. The
/// IPPROTO_IPV6/IPV6_V6ONLY option is set on the socket
/// according to the ipV6Only parameter.
///
/// If the library has not been built with IPv6 support,
/// a Poco::NotImplementedException will be thrown.
virtual void listen(int backlog = 64); virtual void listen(int backlog = 64);
/// Puts the socket into listening state. /// Puts the socket into listening state.
/// ///

View File

@ -86,6 +86,19 @@ public:
/// If reuseAddress is true, sets the SO_REUSEADDR /// If reuseAddress is true, sets the SO_REUSEADDR
/// socket option. /// socket option.
virtual void bind(const SocketAddress& address, bool reuseAddress, bool reusePort );
/// Bind a local address to the socket.
///
/// This is usually only done when establishing a server
/// socket. TCP clients should not bind a socket to a
/// specific address.
///
/// If reuseAddress is true, sets the SO_REUSEADDR
/// socket option.
///
/// If reusePort is true, sets the SO_REUSEPORT
/// socket option.
virtual void bind6(const SocketAddress& address, bool reuseAddress = false, bool ipV6Only = false); virtual void bind6(const SocketAddress& address, bool reuseAddress = false, bool ipV6Only = false);
/// Bind a local IPv6 address to the socket. /// Bind a local IPv6 address to the socket.
/// ///
@ -103,6 +116,26 @@ public:
/// If the library has not been built with IPv6 support, /// If the library has not been built with IPv6 support,
/// a Poco::NotImplementedException will be thrown. /// a Poco::NotImplementedException will be thrown.
virtual void bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only);
/// Bind a local IPv6 address to the socket.
///
/// This is usually only done when establishing a server
/// socket. TCP clients should not bind a socket to a
/// specific address.
///
/// If reuseAddress is true, sets the SO_REUSEADDR
/// socket option.
///
/// If reusePort is true, sets the SO_REUSEPORT
/// socket option.
///
/// The given address must be an IPv6 address. The
/// IPPROTO_IPV6/IPV6_V6ONLY option is set on the socket
/// according to the ipV6Only parameter.
///
/// If the library has not been built with IPv6 support,
/// a Poco::NotImplementedException will be thrown.
virtual void listen(int backlog = 64); virtual void listen(int backlog = 64);
/// Puts the socket into listening state. /// Puts the socket into listening state.
/// ///

View File

@ -52,7 +52,9 @@ public:
virtual void connect(const SocketAddress& address, const Poco::Timespan& timeout); virtual void connect(const SocketAddress& address, const Poco::Timespan& timeout);
virtual void connectNB(const SocketAddress& address); virtual void connectNB(const SocketAddress& address);
virtual void bind(const SocketAddress& address, bool reuseAddress = false); virtual void bind(const SocketAddress& address, bool reuseAddress = false);
virtual void bind(const SocketAddress& address, bool reuseAddress, bool reusePort);
virtual void bind6(const SocketAddress& address, bool reuseAddress = false, bool ipV6Only = false); virtual void bind6(const SocketAddress& address, bool reuseAddress = false, bool ipV6Only = false);
virtual void bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only);
virtual void listen(int backlog = 64); virtual void listen(int backlog = 64);
virtual void close(); virtual void close();
virtual void shutdownReceive(); virtual void shutdownReceive();

View File

@ -83,6 +83,12 @@ void DatagramSocket::bind(const SocketAddress& address, bool reuseAddress)
} }
void DatagramSocket::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
{
impl()->bind(address, reuseAddress, reusePort);
}
int DatagramSocket::sendBytes(const void* buffer, int length, int flags) int DatagramSocket::sendBytes(const void* buffer, int length, int flags)
{ {
return impl()->sendBytes(buffer, length, flags); return impl()->sendBytes(buffer, length, flags);

View File

@ -86,6 +86,12 @@ void RawSocket::bind(const SocketAddress& address, bool reuseAddress)
} }
void RawSocket::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
{
impl()->bind(address, reuseAddress, reusePort);
}
int RawSocket::sendBytes(const void* buffer, int length, int flags) int RawSocket::sendBytes(const void* buffer, int length, int flags)
{ {
return impl()->sendBytes(buffer, length, flags); return impl()->sendBytes(buffer, length, flags);

View File

@ -80,6 +80,12 @@ void ServerSocket::bind(const SocketAddress& address, bool reuseAddress)
} }
void ServerSocket::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
{
impl()->bind(address, reuseAddress, reusePort);
}
void ServerSocket::bind(Poco::UInt16 port, bool reuseAddress) void ServerSocket::bind(Poco::UInt16 port, bool reuseAddress)
{ {
IPAddress wildcardAddr; IPAddress wildcardAddr;
@ -88,12 +94,24 @@ void ServerSocket::bind(Poco::UInt16 port, bool reuseAddress)
} }
void ServerSocket::bind(Poco::UInt16 port, bool reuseAddress, bool reusePort)
{
IPAddress wildcardAddr;
SocketAddress address(wildcardAddr, port);
impl()->bind(address, reuseAddress, reusePort);
}
void ServerSocket::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only) void ServerSocket::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only)
{ {
impl()->bind6(address, reuseAddress, ipV6Only); impl()->bind6(address, reuseAddress, ipV6Only);
} }
void ServerSocket::bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only)
{
impl()->bind6(address, reuseAddress, reusePort, ipV6Only);
}
void ServerSocket::bind6(Poco::UInt16 port, bool reuseAddress, bool ipV6Only) void ServerSocket::bind6(Poco::UInt16 port, bool reuseAddress, bool ipV6Only)
{ {
#if defined(POCO_HAVE_IPv6) #if defined(POCO_HAVE_IPv6)
@ -106,6 +124,17 @@ void ServerSocket::bind6(Poco::UInt16 port, bool reuseAddress, bool ipV6Only)
} }
void ServerSocket::bind6(Poco::UInt16 port, bool reuseAddress, bool reusePort, bool ipV6Only)
{
#if defined(POCO_HAVE_IPv6)
IPAddress wildcardAddr(IPAddress::IPv6);
SocketAddress address(wildcardAddr, port);
impl()->bind6(address, reuseAddress, reusePort, ipV6Only);
#else
throw Poco::NotImplementedException("No IPv6 support available");
#endif // POCO_HAVE_IPv6
}
void ServerSocket::listen(int backlog) void ServerSocket::listen(int backlog)
{ {
impl()->listen(backlog); impl()->listen(backlog);

View File

@ -190,16 +190,21 @@ void SocketImpl::connectNB(const SocketAddress& address)
void SocketImpl::bind(const SocketAddress& address, bool reuseAddress) void SocketImpl::bind(const SocketAddress& address, bool reuseAddress)
{
bind(address, reuseAddress, true);
}
void SocketImpl::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
{ {
if (_sockfd == POCO_INVALID_SOCKET) if (_sockfd == POCO_INVALID_SOCKET)
{ {
init(address.af()); init(address.af());
} }
if (reuseAddress) if (reuseAddress)
{
setReuseAddress(true); setReuseAddress(true);
if (reusePort)
setReusePort(true); setReusePort(true);
}
#if defined(POCO_VXWORKS) #if defined(POCO_VXWORKS)
int rc = ::bind(_sockfd, (sockaddr*) address.addr(), address.length()); int rc = ::bind(_sockfd, (sockaddr*) address.addr(), address.length());
#else #else
@ -210,6 +215,12 @@ void SocketImpl::bind(const SocketAddress& address, bool reuseAddress)
void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only) void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only)
{
bind6(address, reuseAddress, true, ipV6Only);
}
void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only)
{ {
#if defined(POCO_HAVE_IPv6) #if defined(POCO_HAVE_IPv6)
if (address.family() != SocketAddress::IPv6) if (address.family() != SocketAddress::IPv6)
@ -225,10 +236,9 @@ void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV
if (ipV6Only) throw Poco::NotImplementedException("IPV6_V6ONLY not defined."); if (ipV6Only) throw Poco::NotImplementedException("IPV6_V6ONLY not defined.");
#endif #endif
if (reuseAddress) if (reuseAddress)
{
setReuseAddress(true); setReuseAddress(true);
if (reusePort)
setReusePort(true); setReusePort(true);
}
int rc = ::bind(_sockfd, address.addr(), address.length()); int rc = ::bind(_sockfd, address.addr(), address.length());
if (rc != 0) error(address.toString()); if (rc != 0) error(address.toString());
#else #else

View File

@ -257,12 +257,23 @@ void WebSocketImpl::bind(const SocketAddress& address, bool reuseAddress)
} }
void WebSocketImpl::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
{
throw Poco::InvalidAccessException("Cannot bind() a WebSocketImpl");
}
void WebSocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only) void WebSocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only)
{ {
throw Poco::InvalidAccessException("Cannot bind6() a WebSocketImpl"); throw Poco::InvalidAccessException("Cannot bind6() a WebSocketImpl");
} }
void WebSocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only)
{
throw Poco::InvalidAccessException("Cannot bind6() a WebSocketImpl");
}
void WebSocketImpl::listen(int backlog) void WebSocketImpl::listen(int backlog)
{ {
throw Poco::InvalidAccessException("Cannot listen() on a WebSocketImpl"); throw Poco::InvalidAccessException("Cannot listen() on a WebSocketImpl");