diff --git a/hazelcast/include/hazelcast/client/config/ClientNetworkConfig.h b/hazelcast/include/hazelcast/client/config/ClientNetworkConfig.h
index a39cf631d1..a01e1c6d78 100644
--- a/hazelcast/include/hazelcast/client/config/ClientNetworkConfig.h
+++ b/hazelcast/include/hazelcast/client/config/ClientNetworkConfig.h
@@ -22,6 +22,7 @@
#include "hazelcast/util/HazelcastDll.h"
#include "hazelcast/client/config/SSLConfig.h"
#include "hazelcast/client/config/ClientAwsConfig.h"
+#include "hazelcast/client/config/SocketOptions.h"
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
#pragma warning(push)
@@ -180,6 +181,8 @@ namespace hazelcast {
*/
ClientNetworkConfig &addAddress(const Address &address);
+ SocketOptions &getSocketOptions();
+
private:
static int32_t CONNECTION_ATTEMPT_PERIOD;
@@ -194,6 +197,7 @@ namespace hazelcast {
std::vector
addressList;
+ SocketOptions socketOptions;
};
}
}
diff --git a/hazelcast/include/hazelcast/client/config/SocketOptions.h b/hazelcast/include/hazelcast/client/config/SocketOptions.h
new file mode 100644
index 0000000000..14fa317d6c
--- /dev/null
+++ b/hazelcast/include/hazelcast/client/config/SocketOptions.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef HAZELCAST_CLIENT_CONFIG_SOCKETOPTIONS_H_
+#define HAZELCAST_CLIENT_CONFIG_SOCKETOPTIONS_H_
+
+#include "hazelcast/util/HazelcastDll.h"
+
+#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
+#pragma warning(push)
+#pragma warning(disable: 4251) //for dll export
+#endif
+
+namespace hazelcast {
+ namespace client {
+ namespace config {
+ /**
+ * TCP Socket options
+ */
+ class HAZELCAST_API SocketOptions {
+ public:
+ /**
+ * constant for kilobyte
+ */
+ static const int KILO_BYTE = 1024;
+
+ /**
+ * default buffer size of Bytes
+ */
+ static const int DEFAULT_BUFFER_SIZE_BYTE = 128 * KILO_BYTE;
+
+ SocketOptions();
+
+ /**
+ * TCP_NODELAY socket option
+ *
+ * @return true if enabled
+ */
+ bool isTcpNoDelay() const;
+
+ /**
+ * Enable/disable TCP_NODELAY socket option.
+ *
+ * @param tcpNoDelay
+ */
+ SocketOptions &setTcpNoDelay(bool tcpNoDelay);
+
+ /**
+ * SO_KEEPALIVE socket option
+ *
+ * @return true if enabled
+ */
+ bool isKeepAlive() const;
+
+ /**
+ * Enable/disable SO_KEEPALIVE socket option.
+ *
+ * @param keepAlive enabled if true
+ * @return SocketOptions configured
+ */
+ SocketOptions &setKeepAlive(bool keepAlive);
+
+ /**
+ * SO_REUSEADDR socket option.
+ *
+ * @return true if enabled
+ */
+ bool isReuseAddress() const;
+
+ /**
+ * Enable/disable the SO_REUSEADDR socket option.
+ *
+ * @param reuseAddress enabled if true
+ * @return SocketOptions configured
+ */
+ SocketOptions &setReuseAddress(bool reuseAddress);
+
+ /**
+ * Gets SO_LINGER with the specified linger time in seconds
+ * @return lingerSeconds value in seconds
+ */
+ int getLingerSeconds() const;
+
+ /**
+ * Enable/disable SO_LINGER with the specified linger time in seconds
+ *
+ * if set to a value of 0 or less then it is disabled.
+ *
+ * Default value is 3.
+ *
+ * @param lingerSeconds value in seconds
+ * @return SocketOptions configured
+ */
+ SocketOptions &setLingerSeconds(int lingerSeconds);
+
+ /**
+ * If set to 0 or less, then it is not set on the socket.
+ *
+ * The default value is DEFAULT_BUFFER_SIZE_BYTE
+ *
+ * Gets the SO_SNDBUF and SO_RCVBUF options value in bytes
+ * @return bufferSize Number of bytes
+ */
+ int getBufferSizeInBytes() const;
+
+ /**
+ * If set to 0 or less, then it is not set on the socket.
+ *
+ * The default value is DEFAULT_BUFFER_SIZE_BYTE
+ *
+ * Sets the SO_SNDBUF and SO_RCVBUF options to the specified value in bytes
+ *
+ * @param bufferSize Number of bytes
+ * @return SocketOptions configured
+ */
+ SocketOptions &setBufferSizeInBytes(int bufferSize);
+
+ private:
+ // socket options
+
+ bool tcpNoDelay;
+
+ bool keepAlive;
+
+ bool reuseAddress;
+
+ int lingerSeconds;
+
+ int bufferSize;
+
+ };
+
+ }
+ }
+}
+
+#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
+#pragma warning(pop)
+#endif
+
+#endif /* HAZELCAST_CLIENT_CONFIG_SOCKETOPTIONS_H_ */
diff --git a/hazelcast/include/hazelcast/client/connection/IOSelector.h b/hazelcast/include/hazelcast/client/connection/IOSelector.h
index 26d4cefa3b..30bb00f903 100644
--- a/hazelcast/include/hazelcast/client/connection/IOSelector.h
+++ b/hazelcast/include/hazelcast/client/connection/IOSelector.h
@@ -38,6 +38,9 @@ namespace hazelcast {
namespace client {
class Socket;
+ namespace config {
+ class SocketOptions;
+ }
namespace connection {
class ListenerTask;
@@ -47,7 +50,7 @@ namespace hazelcast {
class HAZELCAST_API IOSelector : public util::Runnable {
public:
- IOSelector(ClientConnectionManagerImpl &connectionManager);
+ IOSelector(ClientConnectionManagerImpl &connectionManager, const config::SocketOptions &socketOptions);
virtual ~IOSelector();
@@ -89,6 +92,7 @@ namespace hazelcast {
std::auto_ptr wakeUpSocket;
util::ConcurrentQueue listenerTasks;
util::AtomicBoolean isAlive;
+ const config::SocketOptions &socketOptions;
};
}
}
diff --git a/hazelcast/include/hazelcast/client/connection/InSelector.h b/hazelcast/include/hazelcast/client/connection/InSelector.h
index 6c4865e12b..3d553385db 100644
--- a/hazelcast/include/hazelcast/client/connection/InSelector.h
+++ b/hazelcast/include/hazelcast/client/connection/InSelector.h
@@ -28,7 +28,7 @@ namespace hazelcast {
namespace connection {
class HAZELCAST_API InSelector : public IOSelector {
public:
- InSelector(ClientConnectionManagerImpl &connectionManager);
+ InSelector(ClientConnectionManagerImpl &connectionManager, const config::SocketOptions &socketOptions);
void listenInternal();
diff --git a/hazelcast/include/hazelcast/client/connection/OutSelector.h b/hazelcast/include/hazelcast/client/connection/OutSelector.h
index efb47ec4e8..114c9fc483 100644
--- a/hazelcast/include/hazelcast/client/connection/OutSelector.h
+++ b/hazelcast/include/hazelcast/client/connection/OutSelector.h
@@ -34,7 +34,7 @@ namespace hazelcast {
namespace connection {
class HAZELCAST_API OutSelector : public IOSelector {
public:
- OutSelector(ClientConnectionManagerImpl &connectionManager);
+ OutSelector(ClientConnectionManagerImpl &connectionManager, const config::SocketOptions &socketOptions);
void listenInternal();
diff --git a/hazelcast/include/hazelcast/client/internal/socket/SSLSocket.h b/hazelcast/include/hazelcast/client/internal/socket/SSLSocket.h
index b0d2334a01..1aa722f87e 100644
--- a/hazelcast/include/hazelcast/client/internal/socket/SSLSocket.h
+++ b/hazelcast/include/hazelcast/client/internal/socket/SSLSocket.h
@@ -23,6 +23,7 @@
#include "hazelcast/client/Socket.h"
#include "hazelcast/client/Address.h"
+#include "hazelcast/client/config/SocketOptions.h"
#include "hazelcast/util/AtomicBoolean.h"
#if !defined(MSG_NOSIGNAL)
@@ -54,7 +55,8 @@ namespace hazelcast {
/**
* Constructor
*/
- SSLSocket(const client::Address &address, asio::ssl::context &sslContext);
+ SSLSocket(const client::Address &address, asio::ssl::context &sslContext,
+ client::config::SocketOptions &socketOptions);
/**
* Destructor
@@ -107,6 +109,7 @@ namespace hazelcast {
std::vector getCiphers() const;
std::auto_ptr localSocketAddress() const;
+
private:
SSLSocket(const Socket &rhs);
@@ -137,6 +140,8 @@ namespace hazelcast {
void checkDeadline(const asio::error_code &ec);
+ void setSocketOptions();
+
client::Address remoteEndpoint;
asio::io_service ioService;
@@ -145,6 +150,7 @@ namespace hazelcast {
asio::deadline_timer deadline;
asio::error_code errorCode;
int socketId;
+ const client::config::SocketOptions &socketOptions;
};
std::ostream &operator<<(std::ostream &out, const SSLSocket::CipherInfo &info);
diff --git a/hazelcast/include/hazelcast/client/internal/socket/TcpSocket.h b/hazelcast/include/hazelcast/client/internal/socket/TcpSocket.h
index a5acb9bc01..256b42e059 100644
--- a/hazelcast/include/hazelcast/client/internal/socket/TcpSocket.h
+++ b/hazelcast/include/hazelcast/client/internal/socket/TcpSocket.h
@@ -35,19 +35,21 @@ typedef int socklen_t;
#include
#include
#include
+#include
#endif
-#include "hazelcast/client/Socket.h"
+#include
+#include
+#include "hazelcast/client/Socket.h"
+#include "hazelcast/client/config/SocketOptions.h"
#include "hazelcast/client/Address.h"
#include "hazelcast/util/AtomicBoolean.h"
-#include
-#include
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
#pragma warning(push)
-#pragma warning(disable: 4251) //for dll export
+#pragma warning(disable: 4251) //for dll export
#endif
#if !defined(MSG_NOSIGNAL)
@@ -71,7 +73,7 @@ namespace hazelcast {
/**
* Constructor
*/
- TcpSocket(const client::Address &address);
+ TcpSocket(const client::Address &address, const client::config::SocketOptions *socketOptions);
/**
* Destructor
@@ -119,6 +121,7 @@ namespace hazelcast {
void setBlocking(bool blocking);
std::auto_ptr localSocketAddress() const;
+
private:
TcpSocket(const Socket &rhs);
@@ -128,6 +131,8 @@ namespace hazelcast {
void throwIOException(int error, const char *methodName, const char *prefix) const;
+ void setSocketOptions(const client::config::SocketOptions &socketOptions);
+
const Address configAddress;
struct addrinfo *serverInfo;
diff --git a/hazelcast/src/hazelcast/client/config/ClientNetworkConfig.cpp b/hazelcast/src/hazelcast/client/config/ClientNetworkConfig.cpp
index 5d0b7c8575..5278ee3565 100644
--- a/hazelcast/src/hazelcast/client/config/ClientNetworkConfig.cpp
+++ b/hazelcast/src/hazelcast/client/config/ClientNetworkConfig.cpp
@@ -108,6 +108,10 @@ namespace hazelcast {
addressList.push_back(address);
return *this;
}
+
+ SocketOptions &ClientNetworkConfig::getSocketOptions() {
+ return socketOptions;
+ }
}
}
}
diff --git a/hazelcast/src/hazelcast/client/config/SocketOptions.cpp b/hazelcast/src/hazelcast/client/config/SocketOptions.cpp
new file mode 100644
index 0000000000..1d78b4f857
--- /dev/null
+++ b/hazelcast/src/hazelcast/client/config/SocketOptions.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "hazelcast/client/config/SocketOptions.h"
+
+namespace hazelcast {
+ namespace client {
+ namespace config {
+ SocketOptions::SocketOptions() : tcpNoDelay(true), keepAlive(true), reuseAddress(true), lingerSeconds(3),
+ bufferSize(DEFAULT_BUFFER_SIZE_BYTE) {}
+
+ bool SocketOptions::isTcpNoDelay() const {
+ return tcpNoDelay;
+ }
+
+ SocketOptions &SocketOptions::setTcpNoDelay(bool tcpNoDelay) {
+ SocketOptions::tcpNoDelay = tcpNoDelay;
+ return *this;
+ }
+
+ bool SocketOptions::isKeepAlive() const {
+ return keepAlive;
+ }
+
+ SocketOptions &SocketOptions::setKeepAlive(bool keepAlive) {
+ SocketOptions::keepAlive = keepAlive;
+ return *this;
+ }
+
+ bool SocketOptions::isReuseAddress() const {
+ return reuseAddress;
+ }
+
+ SocketOptions &SocketOptions::setReuseAddress(bool reuseAddress) {
+ SocketOptions::reuseAddress = reuseAddress;
+ return *this;
+ }
+
+ int SocketOptions::getLingerSeconds() const {
+ return lingerSeconds;
+ }
+
+ SocketOptions &SocketOptions::setLingerSeconds(int lingerSeconds) {
+ SocketOptions::lingerSeconds = lingerSeconds;
+ return *this;
+ }
+
+ int SocketOptions::getBufferSizeInBytes() const {
+ return bufferSize;
+ }
+
+ SocketOptions &SocketOptions::setBufferSizeInBytes(int bufferSize) {
+ SocketOptions::bufferSize = bufferSize;
+ return *this;
+ }
+
+ }
+ }
+}
diff --git a/hazelcast/src/hazelcast/client/connection/ClientConnectionManagerImpl.cpp b/hazelcast/src/hazelcast/client/connection/ClientConnectionManagerImpl.cpp
index 4f597aa516..b745f82c86 100644
--- a/hazelcast/src/hazelcast/client/connection/ClientConnectionManagerImpl.cpp
+++ b/hazelcast/src/hazelcast/client/connection/ClientConnectionManagerImpl.cpp
@@ -66,8 +66,9 @@ namespace hazelcast {
const boost::shared_ptr &addressTranslator,
const std::vector > &addressProviders)
: logger(client.getLogger()), client(client),
- socketInterceptor(client.getClientConfig().getSocketInterceptor()), inSelector(*this),
- outSelector(*this),
+ socketInterceptor(client.getClientConfig().getSocketInterceptor()),
+ inSelector(*this, client.getClientConfig().getNetworkConfig().getSocketOptions()),
+ outSelector(*this, client.getClientConfig().getNetworkConfig().getSocketOptions()),
inSelectorThread(boost::shared_ptr(new util::RunnableDelegator(inSelector)), logger),
outSelectorThread(boost::shared_ptr(new util::RunnableDelegator(outSelector)), logger),
executionService(client.getClientExecutionService()),
diff --git a/hazelcast/src/hazelcast/client/connection/IOSelector.cpp b/hazelcast/src/hazelcast/client/connection/IOSelector.cpp
index fe40cf34cf..c21972fa16 100644
--- a/hazelcast/src/hazelcast/client/connection/IOSelector.cpp
+++ b/hazelcast/src/hazelcast/client/connection/IOSelector.cpp
@@ -38,9 +38,9 @@ namespace hazelcast {
namespace client {
namespace connection {
- IOSelector::IOSelector(ClientConnectionManagerImpl &connectionManager)
+ IOSelector::IOSelector(ClientConnectionManagerImpl &connectionManager, const config::SocketOptions &socketOptions)
: socketSet(connectionManager.getLogger()), connectionManager(connectionManager),
- logger(connectionManager.getLogger()) {
+ logger(connectionManager.getLogger()), socketOptions(socketOptions) {
t.tv_sec = 5;
t.tv_usec = 0;
}
@@ -83,7 +83,7 @@ namespace hazelcast {
else
localAddress = "::1";
- wakeUpSocket.reset(new internal::socket::TcpSocket(Address(localAddress, p)));
+ wakeUpSocket.reset(new internal::socket::TcpSocket(Address(localAddress, p), NULL));
int error = wakeUpSocket->connect(5000);
if (error == 0) {
sleepingSocket.reset(serverSocket.accept());
diff --git a/hazelcast/src/hazelcast/client/connection/InSelector.cpp b/hazelcast/src/hazelcast/client/connection/InSelector.cpp
index b5ed915ae8..ab39cbbab8 100644
--- a/hazelcast/src/hazelcast/client/connection/InSelector.cpp
+++ b/hazelcast/src/hazelcast/client/connection/InSelector.cpp
@@ -33,8 +33,8 @@
namespace hazelcast {
namespace client {
namespace connection {
- InSelector::InSelector(ClientConnectionManagerImpl& connectionManager)
- : IOSelector(connectionManager) {
+ InSelector::InSelector(ClientConnectionManagerImpl& connectionManager, const config::SocketOptions &socketOptions)
+ : IOSelector(connectionManager, socketOptions) {
}
bool InSelector::start() {
diff --git a/hazelcast/src/hazelcast/client/connection/OutSelector.cpp b/hazelcast/src/hazelcast/client/connection/OutSelector.cpp
index 8297309437..170c95493d 100644
--- a/hazelcast/src/hazelcast/client/connection/OutSelector.cpp
+++ b/hazelcast/src/hazelcast/client/connection/OutSelector.cpp
@@ -33,9 +33,8 @@ namespace hazelcast {
namespace client {
namespace connection {
- OutSelector::OutSelector(ClientConnectionManagerImpl &connectionManager)
- :IOSelector(connectionManager), wakeUpSocketSet(connectionManager.getLogger()) {
-
+ OutSelector::OutSelector(ClientConnectionManagerImpl &connectionManager, const config::SocketOptions &socketOptions)
+ :IOSelector(connectionManager, socketOptions), wakeUpSocketSet(connectionManager.getLogger()) {
}
bool OutSelector::start() {
diff --git a/hazelcast/src/hazelcast/client/internal/socket/SSLSocket.cpp b/hazelcast/src/hazelcast/client/internal/socket/SSLSocket.cpp
index b000acb4c5..509dd21aa4 100644
--- a/hazelcast/src/hazelcast/client/internal/socket/SSLSocket.cpp
+++ b/hazelcast/src/hazelcast/client/internal/socket/SSLSocket.cpp
@@ -38,9 +38,9 @@ namespace hazelcast {
namespace client {
namespace internal {
namespace socket {
- SSLSocket::SSLSocket(const client::Address &address, asio::ssl::context &context)
- : remoteEndpoint(address), sslContext(context),
- deadline(ioService), socketId(-1) {
+ SSLSocket::SSLSocket(const client::Address &address, asio::ssl::context &context,
+ client::config::SocketOptions &socketOptions) : remoteEndpoint(address),
+ sslContext(context), deadline(ioService), socketId(-1), socketOptions(socketOptions) {
socket = std::auto_ptr >(
new asio::ssl::stream(ioService, sslContext));
}
@@ -136,12 +136,7 @@ namespace hazelcast {
socket->handshake(asio::ssl::stream::client);
- int size = 32 * 1024;
- socket->lowest_layer().set_option(asio::socket_base::receive_buffer_size(size));
- socket->lowest_layer().set_option(asio::socket_base::send_buffer_size(size));
-
- // SO_NOSIGPIPE seems to be internally handled by asio on connect and accept. no such option
- // is defined at the api, hence not setting this option
+ setSocketOptions();
setBlocking(false);
socketId = socket->lowest_layer().native_handle();
@@ -243,6 +238,31 @@ namespace hazelcast {
return (int) numBytes;
}
+ void SSLSocket::setSocketOptions() {
+ asio::basic_socket > &lowestLayer =
+ socket->lowest_layer();
+
+ lowestLayer.set_option(asio::ip::tcp::no_delay(socketOptions.isTcpNoDelay()));
+
+ lowestLayer.set_option(asio::socket_base::keep_alive(socketOptions.isKeepAlive()));
+
+ lowestLayer.set_option(asio::socket_base::reuse_address(socketOptions.isReuseAddress()));
+
+ int lingerSeconds = socketOptions.getLingerSeconds();
+ if (lingerSeconds > 0) {
+ lowestLayer.set_option(asio::socket_base::linger(true, lingerSeconds));
+ }
+
+ int bufferSize = socketOptions.getBufferSizeInBytes();
+ if (bufferSize > 0) {
+ lowestLayer.set_option(asio::socket_base::receive_buffer_size(bufferSize));
+ lowestLayer.set_option(asio::socket_base::send_buffer_size(bufferSize));
+ }
+
+ // SO_NOSIGPIPE seems to be internally handled by asio on connect and accept. no such option
+ // is defined at the api, hence not setting this option
+ }
+
SSLSocket::ReadHandler::ReadHandler(size_t &numRead, asio::error_code &ec) : numRead(numRead),
errorCode(ec) {}
diff --git a/hazelcast/src/hazelcast/client/internal/socket/SocketFactory.cpp b/hazelcast/src/hazelcast/client/internal/socket/SocketFactory.cpp
index 228672fb06..4b996c2197 100644
--- a/hazelcast/src/hazelcast/client/internal/socket/SocketFactory.cpp
+++ b/hazelcast/src/hazelcast/client/internal/socket/SocketFactory.cpp
@@ -85,17 +85,20 @@ namespace hazelcast {
#else
(void) clientContext;
#endif
-
+
return true;
}
std::auto_ptr SocketFactory::create(const Address &address) const {
#ifdef HZ_BUILD_WITH_SSL
if (sslContext.get()) {
- return std::auto_ptr(new internal::socket::SSLSocket(address, *sslContext));
+ return std::auto_ptr(new internal::socket::SSLSocket(address, *sslContext,
+ clientContext.getClientConfig().getNetworkConfig().getSocketOptions()));
}
#endif
- return std::auto_ptr(new internal::socket::TcpSocket(address));
+
+ return std::auto_ptr(new internal::socket::TcpSocket(address,
+ &clientContext.getClientConfig().getNetworkConfig().getSocketOptions()));
}
}
}
diff --git a/hazelcast/src/hazelcast/client/internal/socket/TcpSocket.cpp b/hazelcast/src/hazelcast/client/internal/socket/TcpSocket.cpp
index 4346b8ca58..cc0ca685bd 100644
--- a/hazelcast/src/hazelcast/client/internal/socket/TcpSocket.cpp
+++ b/hazelcast/src/hazelcast/client/internal/socket/TcpSocket.cpp
@@ -32,9 +32,10 @@ namespace hazelcast {
namespace client {
namespace internal {
namespace socket {
- TcpSocket::TcpSocket(const client::Address &address) : configAddress(address) {
+ TcpSocket::TcpSocket(const client::Address &address, const client::config::SocketOptions *socketOptions)
+ : configAddress(address) {
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
- int n= WSAStartup(MAKEWORD(2, 0), &wsa_data);
+ int n = WSAStartup(MAKEWORD(2, 0), &wsa_data);
if(n == -1) throw exception::IOException("TcpSocket::TcpSocket ", "WSAStartup error");
#endif
struct addrinfo hints;
@@ -57,20 +58,12 @@ namespace hazelcast {
if (-1 == socketId) {
throwIOException("TcpSocket", "[TcpSocket::TcpSocket] Failed to obtain socket.");
}
- isOpen = true;
- int size = 32 * 1024;
- if (::setsockopt(socketId, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size))) {
- throwIOException("Socket", "Failed set socket receive buffer size.");
- }
- if (::setsockopt(socketId, SOL_SOCKET, SO_SNDBUF, (char *) &size, sizeof(size))) {
- throwIOException("TcpSocket", "Failed set socket send buffer size.");
- }
- #if defined(SO_NOSIGPIPE)
- int on = 1;
- if (setsockopt(socketId, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(int))) {
- throwIOException("TcpSocket", "Failed set socket option SO_NOSIGPIPE.");
+
+ if (socketOptions) {
+ setSocketOptions(*socketOptions);
}
- #endif
+
+ isOpen = true;
}
TcpSocket::TcpSocket(int socketId)
@@ -296,6 +289,50 @@ namespace hazelcast {
return std::auto_ptr();
}
}
+
+ void TcpSocket::setSocketOptions(const client::config::SocketOptions &socketOptions) {
+ int optionValue = socketOptions.getBufferSizeInBytes();
+ if (::setsockopt(socketId, SOL_SOCKET, SO_RCVBUF, (char *) &optionValue, sizeof(optionValue))) {
+ throwIOException("setSocketOptions", "Failed to set socket receive buffer size.");
+ }
+ if (::setsockopt(socketId, SOL_SOCKET, SO_SNDBUF, (char *) &optionValue, sizeof(optionValue))) {
+ throwIOException("setSocketOptions", "Failed to set socket send buffer size.");
+ }
+
+ optionValue = socketOptions.isTcpNoDelay();
+ if (::setsockopt(socketId, IPPROTO_TCP, TCP_NODELAY, (char *) &optionValue, sizeof(optionValue))) {
+ throwIOException("setSocketOptions", "Failed to set TCP_NODELAY option on the socket.");
+ }
+
+ optionValue = socketOptions.isKeepAlive();
+ if (::setsockopt(socketId, SOL_SOCKET, SO_KEEPALIVE, (char *) &optionValue, sizeof(optionValue))) {
+ throwIOException("setSocketOptions", "Failed to set SO_KEEPALIVE option on the socket.");
+ }
+
+ optionValue = socketOptions.isReuseAddress();
+ if (::setsockopt(socketId, SOL_SOCKET, SO_REUSEADDR, (char *) &optionValue, sizeof(optionValue))) {
+ throwIOException("setSocketOptions", "Failed to set SO_REUSEADDR option on the socket.");
+ }
+
+ optionValue = socketOptions.getLingerSeconds();
+ if (optionValue > 0) {
+ struct linger so_linger;
+ so_linger.l_onoff = 1;
+ so_linger.l_linger = optionValue;
+
+ if (::setsockopt(socketId, SOL_SOCKET, SO_LINGER, (char *) &so_linger, sizeof(so_linger))) {
+ throwIOException("setSocketOptions", "Failed to set SO_LINGER option on the socket.");
+ }
+ }
+
+ #if defined(SO_NOSIGPIPE)
+ optionValue = 1;
+ if (setsockopt(socketId, SOL_SOCKET, SO_NOSIGPIPE, (char *) &optionValue, sizeof(optionValue))) {
+ throwIOException("TcpSocket", "Failed to set socket option SO_NOSIGPIPE.");
+ }
+ #endif
+
+ }
}
}
}
diff --git a/hazelcast/test/src/cluster/SocketOptionsTest.cpp b/hazelcast/test/src/cluster/SocketOptionsTest.cpp
new file mode 100644
index 0000000000..f602002983
--- /dev/null
+++ b/hazelcast/test/src/cluster/SocketOptionsTest.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This has to be the first include, so that Python.h is the first include. Otherwise, compilation warning such as
+ * "_POSIX_C_SOURCE" redefined occurs.
+ */
+#include "HazelcastServerFactory.h"
+
+#include "ClientTestSupport.h"
+#include "HazelcastServer.h"
+#include "hazelcast/client/HazelcastClient.h"
+
+namespace hazelcast {
+ namespace client {
+ namespace test {
+ class SocketOptionsTest : public ClientTestSupport {
+ };
+
+ TEST_F(SocketOptionsTest, testConfiguration) {
+ HazelcastServer instance(*g_srvFactory);
+
+ const int bufferSize = 2 * 1024;
+ ClientConfig clientConfig;
+ clientConfig.getNetworkConfig().getSocketOptions().setKeepAlive(false).setReuseAddress(
+ true).setTcpNoDelay(false).setLingerSeconds(5).setBufferSizeInBytes(bufferSize);
+
+ HazelcastClient client(clientConfig);
+
+ config::SocketOptions &socketOptions = client.getClientConfig().getNetworkConfig().getSocketOptions();
+ ASSERT_FALSE(socketOptions.isKeepAlive());
+ ASSERT_FALSE(socketOptions.isTcpNoDelay());
+ ASSERT_EQ(5, socketOptions.getLingerSeconds());
+ ASSERT_EQ(bufferSize, socketOptions.getBufferSizeInBytes());
+ }
+ }
+ }
+}