Skip to content

Commit bac8186

Browse files
committed
Client: implement SSL connection
By default SSL is turned off. Enable it with -DTNTCXX_ENABLE_SSL. Closes #28
1 parent b348525 commit bac8186

12 files changed

+744
-60
lines changed

CMakeLists.txt

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,34 @@ ENDIF()
99
MESSAGE(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
1010
FIND_PACKAGE (benchmark QUIET)
1111

12+
SET(COMMON_LIB ev)
13+
14+
# OpenSSL
15+
IF (TNTCXX_ENABLE_SSL)
16+
FIND_PACKAGE(OpenSSL)
17+
IF (OPENSSL_FOUND)
18+
MESSAGE(STATUS "OpenSSL ${OPENSSL_VERSION} found")
19+
INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
20+
ELSE()
21+
MESSAGE(FATAL_ERROR "Could NOT find OpenSSL development files (libssl-dev/openssl-devel package)")
22+
ENDIF()
23+
24+
# OpenSSL can require Z library (depending on build time options), so we add
25+
# it to libraries list in case of static openssl linking.
26+
IF(OPENSSL_USE_STATIC_LIBS)
27+
SET(OPENSSL_LIBRARIES ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES})
28+
ENDIF()
29+
30+
SET(COMMON_LIB ${COMMON_LIB} ${OPENSSL_LIBRARIES})
31+
32+
ENDIF() # IF (TNTCXX_ENABLE_SSL)
33+
1234
SET(CMAKE_CXX_STANDARD 17)
1335
SET(CMAKE_C_STANDARD 11)
1436
ADD_COMPILE_OPTIONS(-Wall -Wextra -Werror)
1537
CONFIGURE_FILE(./test/cfg.lua test_cfg.lua COPYONLY)
38+
CONFIGURE_FILE(./test/cfg_ssl.lua test_cfg_ssl.lua COPYONLY)
39+
CONFIGURE_FILE(./test/gen_ssl.sh test_gen_ssl.sh COPYONLY)
1640

1741
INCLUDE_DIRECTORIES(.)
1842
INCLUDE_DIRECTORIES(./src)
@@ -36,9 +60,14 @@ ADD_EXECUTABLE(EncDecUnit.test src/mpp/mpp.hpp test/EncDecTest.cpp)
3660
ADD_EXECUTABLE(Client.test src/Client/Connector.hpp test/ClientTest.cpp)
3761
ADD_EXECUTABLE(ClientPerfTest.test src/Client/Connector.hpp test/ClientPerfTest.cpp)
3862
ADD_EXECUTABLE(SimpleExample examples/Simple.cpp)
39-
TARGET_LINK_LIBRARIES(SimpleExample ev)
40-
TARGET_LINK_LIBRARIES(ClientPerfTest.test ev)
41-
TARGET_LINK_LIBRARIES(Client.test ev)
63+
TARGET_LINK_LIBRARIES(SimpleExample ${COMMON_LIB})
64+
TARGET_LINK_LIBRARIES(ClientPerfTest.test ${COMMON_LIB})
65+
TARGET_LINK_LIBRARIES(Client.test ${COMMON_LIB})
66+
IF (TNTCXX_ENABLE_SSL)
67+
ADD_EXECUTABLE(ClientSSL.test src/Client/Connector.hpp test/ClientTest.cpp)
68+
TARGET_LINK_LIBRARIES(ClientSSL.test ${COMMON_LIB})
69+
TARGET_COMPILE_DEFINITIONS(ClientSSL.test PUBLIC TNTCXX_ENABLE_SSL)
70+
ENDIF()
4271

4372
IF (benchmark_FOUND)
4473
ADD_EXECUTABLE(BufferGPerf.test src/Buffer/Buffer.hpp test/BufferGPerfTest.cpp)
@@ -59,3 +88,6 @@ ADD_TEST(NAME ListUnit.test COMMAND ListUnit.test)
5988
ADD_TEST(NAME RulesUnit.test COMMAND RulesUnit.test)
6089
ADD_TEST(NAME EncDecUnit.test COMMAND EncDecUnit.test)
6190
ADD_TEST(NAME Client.test COMMAND Client.test)
91+
IF (TNTCXX_ENABLE_SSL)
92+
ADD_TEST(NAME ClientSSL.test COMMAND ClientSSL.test)
93+
ENDIF()

examples/Simple.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,9 @@ main()
125125
* exception free, so we rely only on return codes.
126126
*/
127127
//doclabel06-1
128-
int rc = client.connect(conn, address, port);
128+
int rc = client.connect(conn, {.address = address,
129+
.service = std::to_string(port),
130+
/* .transport = STREAM_SSL, */});
129131
//doclabel06-2
130132
if (rc != 0) {
131133
//assert(conn.getError().saved_errno != 0);
@@ -217,7 +219,9 @@ main()
217219
//doclabel11-3
218220
/* Let's create another connection. */
219221
Connection<Buf_t, Net_t> another(client);
220-
if (client.connect(another, address, port) != 0) {
222+
if (client.connect(another, {.address = address,
223+
.service = std::to_string(port),
224+
/* .transport = STREAM_SSL, */}) != 0) {
221225
std::cerr << conn.getError().msg << std::endl;
222226
return -1;
223227
}

src/Client/Connector.hpp

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,22 @@
3030
* SUCH DAMAGE.
3131
*/
3232
#include "Connection.hpp"
33+
34+
#ifdef TNTCXX_ENABLE_SSL
35+
#include "UnixSSLStream.hpp"
36+
#else
3337
#include "UnixPlainStream.hpp"
38+
#endif
39+
3440
#include "../Utils/Timer.hpp"
3541

3642
#include <set>
3743

44+
#ifdef TNTCXX_ENABLE_SSL
45+
using DefaultStream = UnixSSLStream;
46+
#else
3847
using DefaultStream = UnixPlainStream;
48+
#endif
3949

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

@@ -94,19 +106,33 @@ Connector<BUFFER, NetProvider>::~Connector()
94106
template<class BUFFER, class NetProvider>
95107
int
96108
Connector<BUFFER, NetProvider>::connect(Connection<BUFFER, NetProvider> &conn,
97-
const std::string& addr,
98-
unsigned port)
109+
const ConnectOptions &opts)
99110
{
100111
//Make sure that connection is not yet established.
101112
assert(conn.get_strm().has_status(SS_DEAD));
102-
if (m_NetProvider.connect(conn, addr, port) != 0) {
103-
LOG_ERROR("Failed to connect to ", addr, ':', port);
113+
if (m_NetProvider.connect(conn, opts) != 0) {
114+
LOG_ERROR("Failed to connect to ",
115+
opts.address, ':', opts.service);
104116
return -1;
105117
}
106-
LOG_DEBUG("Connection to ", addr, ':', port, " has been established");
118+
LOG_DEBUG("Connection to ", opts.address, ':', opts.service,
119+
" has been established");
107120
return 0;
108121
}
109122

123+
template<class BUFFER, class NetProvider>
124+
int
125+
Connector<BUFFER, NetProvider>::connect(Connection<BUFFER, NetProvider> &conn,
126+
const std::string& addr,
127+
unsigned port)
128+
{
129+
std::string service = port == 0 ? std::string{} : std::to_string(port);
130+
return connect(conn, {
131+
.address = addr,
132+
.service = service,
133+
});
134+
}
135+
110136
template<class BUFFER, class NetProvider>
111137
void
112138
Connector<BUFFER, NetProvider>::close(Connection<BUFFER, NetProvider> &conn)

src/Client/EpollNetProvider.hpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class EpollNetProvider {
5858
using Connector_t = Connector<BUFFER, NetProvider_t >;
5959
EpollNetProvider(Connector_t &connector);
6060
~EpollNetProvider();
61-
int connect(Conn_t &conn, const std::string& addr, uint16_t port);
61+
int connect(Conn_t &conn, const ConnectOptions &opts);
6262
void close(Conn_t &conn);
6363
/** Read and write to sockets; polling using epoll. */
6464
int wait(int timeout);
@@ -135,21 +135,16 @@ EpollNetProvider<BUFFER, Stream>::setPollSetting(Conn_t &conn, int setting) {
135135

136136
template<class BUFFER, class Stream>
137137
int
138-
EpollNetProvider<BUFFER, Stream>::connect(Conn_t &conn, const std::string &addr,
139-
uint16_t port)
138+
EpollNetProvider<BUFFER, Stream>::connect(Conn_t &conn,
139+
const ConnectOptions &opts)
140140
{
141141
auto &strm = conn.get_strm();
142-
std::string service = port == 0 ? std::string{} : std::to_string(port);
143-
if (strm.connect({
144-
.address = addr,
145-
.service = service,
146-
}) < 0) {
147-
conn.setError(
148-
std::string("Failed to establish connection to ") +
149-
std::string(addr));
142+
if (strm.connect(opts) < 0) {
143+
conn.setError("Failed to establish connection to " +
144+
opts.address);
150145
return -1;
151146
}
152-
LOG_DEBUG("Connected to ", addr, ", socket is ", strm.get_fd());
147+
LOG_DEBUG("Connected to ", opts.address, ", socket is ", strm.get_fd());
153148
conn.getImpl()->is_greeting_received = false;
154149

155150
registerEpoll(conn);

src/Client/LibevNetProvider.hpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class LibevNetProvider {
9090
using Connector_t = Connector<BUFFER, NetProvider_t >;
9191

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

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

286286
template<class BUFFER, class Stream>
287287
int
288-
LibevNetProvider<BUFFER, Stream>::connect(Conn_t &conn, const std::string &addr,
289-
uint16_t port)
288+
LibevNetProvider<BUFFER, Stream>::connect(Conn_t &conn,
289+
const ConnectOptions &opts)
290290
{
291291
auto &strm = conn.get_strm();
292-
std::string service = port == 0 ? std::string{} : std::to_string(port);
293-
if (strm.connect({
294-
.address = addr,
295-
.service = service,
296-
}) < 0) {
297-
conn.setError(
298-
std::string("Failed to establish connection to ") +
299-
std::string(addr));
292+
if (strm.connect(opts) < 0) {
293+
conn.setError("Failed to establish connection to " +
294+
opts.address);
300295
return -1;
301296
}
302-
LOG_DEBUG("Connected to ", addr, ", socket is ", strm.get_fd());
297+
LOG_DEBUG("Connected to ", opts.address, ", socket is ", strm.get_fd());
303298
conn.getImpl()->is_greeting_received = false;
304299

305300
registerWatchers(conn, strm.get_fd());

src/Client/Stream.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,14 @@ struct ConnectOptions {
9898
/** Time span limit for connection establishment. */
9999
size_t connect_timeout = DEFAULT_CONNECT_TIMEOUT;
100100

101+
/** SSL settings. */
102+
std::string ssl_cert_file{};
103+
std::string ssl_key_file{};
104+
std::string ssl_ca_file{};
105+
std::string ssl_ciphers{};
106+
std::string ssl_passwd{};
107+
std::string ssl_passwd_file{};
108+
101109
/** Standard output. */
102110
friend inline std::ostream &
103111
operator<<(std::ostream &strm, const ConnectOptions &opts);

0 commit comments

Comments
 (0)