Skip to content

Commit

Permalink
Client: implement SSL connection
Browse files Browse the repository at this point in the history
By default SSL is turned off.
Enable it with -DTNTCXX_ENABLE_SSL.

Closes #28
  • Loading branch information
alyapunov committed Aug 31, 2022
1 parent b348525 commit 6b19c27
Show file tree
Hide file tree
Showing 12 changed files with 744 additions and 60 deletions.
38 changes: 35 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,34 @@ ENDIF()
MESSAGE(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
FIND_PACKAGE (benchmark QUIET)

SET(COMMON_LIB ev)

# OpenSSL
IF (TNTCXX_ENABLE_SSL)
FIND_PACKAGE(OpenSSL)
IF (OPENSSL_FOUND)
MESSAGE(STATUS "OpenSSL ${OPENSSL_VERSION} found")
INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
ELSE()
MESSAGE(FATAL_ERROR "Could NOT find OpenSSL development files (libssl-dev/openssl-devel package)")
ENDIF()

# OpenSSL can require Z library (depending on build time options), so we add
# it to libraries list in case of static openssl linking.
IF(OPENSSL_USE_STATIC_LIBS)
SET(OPENSSL_LIBRARIES ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES})
ENDIF()

SET(COMMON_LIB ${COMMON_LIB} ${OPENSSL_LIBRARIES})

ENDIF() # IF (TNTCXX_ENABLE_SSL)

SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_C_STANDARD 11)
ADD_COMPILE_OPTIONS(-Wall -Wextra -Werror)
CONFIGURE_FILE(./test/cfg.lua test_cfg.lua COPYONLY)
CONFIGURE_FILE(./test/cfg_ssl.lua test_cfg_ssl.lua COPYONLY)
CONFIGURE_FILE(./test/gen_ssl.sh test_gen_ssl.sh COPYONLY)

INCLUDE_DIRECTORIES(.)
INCLUDE_DIRECTORIES(./src)
Expand All @@ -36,9 +60,14 @@ ADD_EXECUTABLE(EncDecUnit.test src/mpp/mpp.hpp test/EncDecTest.cpp)
ADD_EXECUTABLE(Client.test src/Client/Connector.hpp test/ClientTest.cpp)
ADD_EXECUTABLE(ClientPerfTest.test src/Client/Connector.hpp test/ClientPerfTest.cpp)
ADD_EXECUTABLE(SimpleExample examples/Simple.cpp)
TARGET_LINK_LIBRARIES(SimpleExample ev)
TARGET_LINK_LIBRARIES(ClientPerfTest.test ev)
TARGET_LINK_LIBRARIES(Client.test ev)
TARGET_LINK_LIBRARIES(SimpleExample ${COMMON_LIB})
TARGET_LINK_LIBRARIES(ClientPerfTest.test ${COMMON_LIB})
TARGET_LINK_LIBRARIES(Client.test ${COMMON_LIB})
IF (TNTCXX_ENABLE_SSL)
ADD_EXECUTABLE(ClientSSL.test src/Client/Connector.hpp test/ClientTest.cpp)
TARGET_LINK_LIBRARIES(ClientSSL.test ${COMMON_LIB})
TARGET_COMPILE_DEFINITIONS(ClientSSL.test PUBLIC TNTCXX_ENABLE_SSL)
ENDIF()

IF (benchmark_FOUND)
ADD_EXECUTABLE(BufferGPerf.test src/Buffer/Buffer.hpp test/BufferGPerfTest.cpp)
Expand All @@ -59,3 +88,6 @@ ADD_TEST(NAME ListUnit.test COMMAND ListUnit.test)
ADD_TEST(NAME RulesUnit.test COMMAND RulesUnit.test)
ADD_TEST(NAME EncDecUnit.test COMMAND EncDecUnit.test)
ADD_TEST(NAME Client.test COMMAND Client.test)
IF (TNTCXX_ENABLE_SSL)
ADD_TEST(NAME ClientSSL.test COMMAND ClientSSL.test)
ENDIF()
8 changes: 6 additions & 2 deletions examples/Simple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ main()
* exception free, so we rely only on return codes.
*/
//doclabel06-1
int rc = client.connect(conn, address, port);
int rc = client.connect(conn, {.address = address,
.service = std::to_string(port),
/* .transport = STREAM_SSL, */});
//doclabel06-2
if (rc != 0) {
//assert(conn.getError().saved_errno != 0);
Expand Down Expand Up @@ -217,7 +219,9 @@ main()
//doclabel11-3
/* Let's create another connection. */
Connection<Buf_t, Net_t> another(client);
if (client.connect(another, address, port) != 0) {
if (client.connect(another, {.address = address,
.service = std::to_string(port),
/* .transport = STREAM_SSL, */}) != 0) {
std::cerr << conn.getError().msg << std::endl;
return -1;
}
Expand Down
36 changes: 31 additions & 5 deletions src/Client/Connector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,22 @@
* SUCH DAMAGE.
*/
#include "Connection.hpp"

#ifdef TNTCXX_ENABLE_SSL
#include "UnixSSLStream.hpp"
#else
#include "UnixPlainStream.hpp"
#endif

#include "../Utils/Timer.hpp"

#include <set>

#ifdef TNTCXX_ENABLE_SSL
using DefaultStream = UnixSSLStream;
#else
using DefaultStream = UnixPlainStream;
#endif

/**
* MacOS does not have epoll so let's use Libev as default network provider.
Expand All @@ -59,6 +69,8 @@ class Connector
Connector(const Connector& connector) = delete;
Connector& operator = (const Connector& connector) = delete;
//////////////////////////////Main API//////////////////////////////////
int connect(Connection<BUFFER, NetProvider> &conn,
const ConnectOptions &opts);
int connect(Connection<BUFFER, NetProvider> &conn,
const std::string& addr, unsigned port);

Expand Down Expand Up @@ -94,19 +106,33 @@ Connector<BUFFER, NetProvider>::~Connector()
template<class BUFFER, class NetProvider>
int
Connector<BUFFER, NetProvider>::connect(Connection<BUFFER, NetProvider> &conn,
const std::string& addr,
unsigned port)
const ConnectOptions &opts)
{
//Make sure that connection is not yet established.
assert(conn.get_strm().has_status(SS_DEAD));
if (m_NetProvider.connect(conn, addr, port) != 0) {
LOG_ERROR("Failed to connect to ", addr, ':', port);
if (m_NetProvider.connect(conn, opts) != 0) {
LOG_ERROR("Failed to connect to ",
opts.address, ':', opts.service);
return -1;
}
LOG_DEBUG("Connection to ", addr, ':', port, " has been established");
LOG_DEBUG("Connection to ", opts.address, ':', opts.service,
" has been established");
return 0;
}

template<class BUFFER, class NetProvider>
int
Connector<BUFFER, NetProvider>::connect(Connection<BUFFER, NetProvider> &conn,
const std::string& addr,
unsigned port)
{
std::string service = port == 0 ? std::string{} : std::to_string(port);
return connect(conn, {
.address = addr,
.service = service,
});
}

template<class BUFFER, class NetProvider>
void
Connector<BUFFER, NetProvider>::close(Connection<BUFFER, NetProvider> &conn)
Expand Down
19 changes: 7 additions & 12 deletions src/Client/EpollNetProvider.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class EpollNetProvider {
using Connector_t = Connector<BUFFER, NetProvider_t >;
EpollNetProvider(Connector_t &connector);
~EpollNetProvider();
int connect(Conn_t &conn, const std::string& addr, uint16_t port);
int connect(Conn_t &conn, const ConnectOptions &opts);
void close(Conn_t &conn);
/** Read and write to sockets; polling using epoll. */
int wait(int timeout);
Expand Down Expand Up @@ -135,21 +135,16 @@ EpollNetProvider<BUFFER, Stream>::setPollSetting(Conn_t &conn, int setting) {

template<class BUFFER, class Stream>
int
EpollNetProvider<BUFFER, Stream>::connect(Conn_t &conn, const std::string &addr,
uint16_t port)
EpollNetProvider<BUFFER, Stream>::connect(Conn_t &conn,
const ConnectOptions &opts)
{
auto &strm = conn.get_strm();
std::string service = port == 0 ? std::string{} : std::to_string(port);
if (strm.connect({
.address = addr,
.service = service,
}) < 0) {
conn.setError(
std::string("Failed to establish connection to ") +
std::string(addr));
if (strm.connect(opts) < 0) {
conn.setError("Failed to establish connection to " +
opts.address);
return -1;
}
LOG_DEBUG("Connected to ", addr, ", socket is ", strm.get_fd());
LOG_DEBUG("Connected to ", opts.address, ", socket is ", strm.get_fd());
conn.getImpl()->is_greeting_received = false;

registerEpoll(conn);
Expand Down
19 changes: 7 additions & 12 deletions src/Client/LibevNetProvider.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class LibevNetProvider {
using Connector_t = Connector<BUFFER, NetProvider_t >;

LibevNetProvider(Connector_t &connector, struct ev_loop *loop = nullptr);
int connect(Conn_t &conn, const std::string& addr, uint16_t port);
int connect(Conn_t &conn, const ConnectOptions &opts);
void close(Conn_t &conn);
int wait(int timeout);

Expand Down Expand Up @@ -285,21 +285,16 @@ LibevNetProvider<BUFFER, Stream>::registerWatchers(Conn_t &conn, int fd)

template<class BUFFER, class Stream>
int
LibevNetProvider<BUFFER, Stream>::connect(Conn_t &conn, const std::string &addr,
uint16_t port)
LibevNetProvider<BUFFER, Stream>::connect(Conn_t &conn,
const ConnectOptions &opts)
{
auto &strm = conn.get_strm();
std::string service = port == 0 ? std::string{} : std::to_string(port);
if (strm.connect({
.address = addr,
.service = service,
}) < 0) {
conn.setError(
std::string("Failed to establish connection to ") +
std::string(addr));
if (strm.connect(opts) < 0) {
conn.setError("Failed to establish connection to " +
opts.address);
return -1;
}
LOG_DEBUG("Connected to ", addr, ", socket is ", strm.get_fd());
LOG_DEBUG("Connected to ", opts.address, ", socket is ", strm.get_fd());
conn.getImpl()->is_greeting_received = false;

registerWatchers(conn, strm.get_fd());
Expand Down
8 changes: 8 additions & 0 deletions src/Client/Stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ struct ConnectOptions {
/** Time span limit for connection establishment. */
size_t connect_timeout = DEFAULT_CONNECT_TIMEOUT;

/** SSL settings. */
std::string ssl_cert_file{};
std::string ssl_key_file{};
std::string ssl_ca_file{};
std::string ssl_ciphers{};
std::string ssl_passwd{};
std::string ssl_passwd_file{};

/** Standard output. */
friend inline std::ostream &
operator<<(std::ostream &strm, const ConnectOptions &opts);
Expand Down
Loading

0 comments on commit 6b19c27

Please sign in to comment.