Skip to content

Commit 5cfda7f

Browse files
authored
Merge pull request #109 from Enmk/openssl
Implemented connecting to ClickHouse server over TLS
2 parents a0914ba + 61923c1 commit 5cfda7f

25 files changed

+1049
-244
lines changed

.github/workflows/linux.yml

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,24 @@ on:
55
branches: [ master ]
66
pull_request:
77
branches: [ master ]
8+
workflow_call:
9+
inputs:
10+
extra_cmake_flags:
11+
required: false
12+
type: string
13+
extra_install:
14+
required: false
15+
type: string
16+
gtest_args:
17+
required: false
18+
type: string
819

920
env:
10-
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
1121
BUILD_TYPE: Release
1222
CH_SERVER_VERSION: 21.3.17.2
1323

1424
jobs:
1525
build:
16-
# The CMake configure and build commands are platform agnostic and should work equally
17-
# well on Windows or Mac. You can convert this to a matrix build if you need
18-
# cross-platform coverage.
19-
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
2026
runs-on: ubuntu-latest
2127
strategy:
2228
matrix:
@@ -39,16 +45,16 @@ jobs:
3945

4046
- name: Install dependencies
4147
run: |
42-
sudo apt-get install -y ${{ matrix.INSTALL }}
48+
sudo apt-get install -y ${{ matrix.INSTALL }} ${{ inputs.extra_install }}
4349
4450
- name: Configure CMake
45-
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
46-
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
4751
run: |
4852
cmake \
49-
-D CMAKE_C_COMPILER=${{ matrix.C_COMPILER}} \
50-
-D CMAKE_CXX_COMPILER=${{ matrix.CXX_COMPILER}} \
51-
-B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_TESTS=ON
53+
-DCMAKE_C_COMPILER=${{ matrix.C_COMPILER}} \
54+
-DCMAKE_CXX_COMPILER=${{ matrix.CXX_COMPILER}} \
55+
-B ${{github.workspace}}/build \
56+
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_TESTS=ON \
57+
${{ inputs.extra_cmake_flags }}
5258
5359
5460
- name: Build
@@ -70,8 +76,4 @@ jobs:
7076
7177
- name: Test
7278
working-directory: ${{github.workspace}}/build/ut
73-
# Execute tests defined by the CMake configuration.
74-
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
75-
#run: ctest -C ${{env.BUILD_TYPE}}
76-
run: ./clickhouse-cpp-ut "${{env.GTEST_FILTER}}"
77-
79+
run: ./clickhouse-cpp-ut "${{ inputs.gtest_args }}"

.github/workflows/linux_ssl.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: Linux-ssl
2+
# Almost the same as regular Linux builds, BUT with enabled SSL support, requires OpenSSL installed
3+
4+
on:
5+
push:
6+
branches: [ master ]
7+
pull_request:
8+
branches: [ master ]
9+
10+
jobs:
11+
build-and-test:
12+
uses: Enmk/clickhouse-cpp/.github/workflows/linux.yml@master
13+
with:
14+
extra_cmake_flags: -DWITH_OPENSSL=ON
15+
extra_install: libssl-dev
16+
# gtest_args: --gtest_filter="-*LocalhostTLS*"

CMakeLists.txt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,32 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.0.2)
22

33
INCLUDE (cmake/cpp17.cmake)
44
INCLUDE (cmake/subdirs.cmake)
5+
INCLUDE (cmake/openssl.cmake)
56

6-
OPTION(BUILD_BENCHMARK "Build benchmark" OFF)
7-
OPTION(BUILD_TESTS "Build tests" OFF)
7+
OPTION (BUILD_BENCHMARK "Build benchmark" OFF)
8+
OPTION (BUILD_TESTS "Build tests" OFF)
9+
OPTION (WITH_OPENSSL "Use OpenSSL for TLS connections" OFF)
810

911
PROJECT (CLICKHOUSE-CLIENT)
1012

1113
USE_CXX17()
14+
USE_OPENSSL()
1215

13-
IF ("${CMAKE_BUILD_TYPE}" STREQUAL "")
14-
set(CMAKE_BUILD_TYPE "Debug")
15-
ENDIF()
16+
IF ("${CMAKE_BUILD_TYPE}" STREQUAL "")
17+
SET (CMAKE_BUILD_TYPE "Debug")
18+
ENDIF()
1619

1720
IF (UNIX)
1821
IF (APPLE)
1922
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall -Wextra -Werror")
2023
ELSE ()
21-
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -pthread -Wall -Wextra -Werror")
24+
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -Wall -Wextra -Werror")
2225
ENDIF ()
2326
SET (CMAKE_EXE_LINKER_FLAGS, "${CMAKE_EXE_LINKER_FLAGS} -lpthread")
2427
ENDIF ()
2528

26-
INCLUDE_DIRECTORIES(.)
27-
INCLUDE_DIRECTORIES(contrib)
29+
INCLUDE_DIRECTORIES (.)
30+
INCLUDE_DIRECTORIES (contrib)
2831

2932
SUBDIRS (
3033
clickhouse
@@ -43,4 +46,4 @@ PROJECT (CLICKHOUSE-CLIENT)
4346
tests/simple
4447
ut
4548
)
46-
ENDIF (BUILD_TESTS)
49+
ENDIF (BUILD_TESTS)

clickhouse/CMakeLists.txt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ SET ( clickhouse-cpp-lib-src
3131
query.cpp
3232
)
3333

34+
IF (WITH_OPENSSL)
35+
LIST(APPEND clickhouse-cpp-lib-src base/sslsocket.cpp)
36+
ENDIF ()
37+
3438
ADD_LIBRARY (clickhouse-cpp-lib SHARED ${clickhouse-cpp-lib-src})
3539
SET_TARGET_PROPERTIES(clickhouse-cpp-lib PROPERTIES LINKER_LANGUAGE CXX)
3640
TARGET_LINK_LIBRARIES (clickhouse-cpp-lib
@@ -52,7 +56,7 @@ IF (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
5256
TARGET_LINK_LIBRARIES (clickhouse-cpp-lib-static gcc_s)
5357
ENDIF ()
5458

55-
INSTALL(TARGETS clickhouse-cpp-lib clickhouse-cpp-lib-static
59+
INSTALL (TARGETS clickhouse-cpp-lib clickhouse-cpp-lib-static
5660
ARCHIVE DESTINATION lib
5761
LIBRARY DESTINATION lib
5862
)
@@ -67,8 +71,8 @@ INSTALL(FILES protocol.h DESTINATION include/clickhouse/)
6771
INSTALL(FILES query.h DESTINATION include/clickhouse/)
6872

6973
# base
70-
INSTALL(FILES base/buffer.h DESTINATION include/clickhouse/base/)
7174
INSTALL(FILES base/coded.h DESTINATION include/clickhouse/base/)
75+
INSTALL(FILES base/buffer.h DESTINATION include/clickhouse/base/)
7276
INSTALL(FILES base/compressed.h DESTINATION include/clickhouse/base/)
7377
INSTALL(FILES base/input.h DESTINATION include/clickhouse/base/)
7478
INSTALL(FILES base/output.h DESTINATION include/clickhouse/base/)
@@ -100,3 +104,8 @@ INSTALL(FILES columns/uuid.h DESTINATION include/clickhouse/columns/)
100104
# types
101105
INSTALL(FILES types/type_parser.h DESTINATION include/clickhouse/types/)
102106
INSTALL(FILES types/types.h DESTINATION include/clickhouse/types/)
107+
108+
IF (WITH_OPENSSL)
109+
TARGET_LINK_LIBRARIES (clickhouse-cpp-lib OpenSSL::SSL)
110+
TARGET_LINK_LIBRARIES (clickhouse-cpp-lib-static OpenSSL::SSL)
111+
ENDIF ()

clickhouse/base/socket.cpp

Lines changed: 83 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,66 @@ void SetNonBlock(SOCKET fd, bool value) {
7373
#endif
7474
}
7575

76+
ssize_t Poll(struct pollfd* fds, int nfds, int timeout) noexcept {
77+
#if defined(_win_)
78+
return WSAPoll(fds, nfds, timeout);
79+
#else
80+
return poll(fds, nfds, timeout);
81+
#endif
82+
}
83+
84+
SOCKET SocketConnect(const NetworkAddress& addr) {
85+
int last_err = 0;
86+
for (auto res = addr.Info(); res != nullptr; res = res->ai_next) {
87+
SOCKET s(socket(res->ai_family, res->ai_socktype, res->ai_protocol));
88+
89+
if (s == -1) {
90+
continue;
91+
}
92+
93+
SetNonBlock(s, true);
94+
95+
if (connect(s, res->ai_addr, (int)res->ai_addrlen) != 0) {
96+
int err = errno;
97+
if (err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK) {
98+
pollfd fd;
99+
fd.fd = s;
100+
fd.events = POLLOUT;
101+
fd.revents = 0;
102+
ssize_t rval = Poll(&fd, 1, 5000);
103+
104+
if (rval == -1) {
105+
throw std::system_error(errno, std::system_category(), "fail to connect");
106+
}
107+
if (rval > 0) {
108+
socklen_t len = sizeof(err);
109+
getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&err, &len);
110+
111+
if (!err) {
112+
SetNonBlock(s, false);
113+
return s;
114+
}
115+
last_err = err;
116+
}
117+
}
118+
} else {
119+
SetNonBlock(s, false);
120+
return s;
121+
}
122+
}
123+
if (last_err > 0) {
124+
throw std::system_error(last_err, std::system_category(), "fail to connect");
125+
}
126+
throw std::system_error(
127+
errno, std::system_category(), "fail to connect"
128+
);
129+
}
130+
76131
} // namespace
77132

78133
NetworkAddress::NetworkAddress(const std::string& host, const std::string& port)
79-
: info_(nullptr)
134+
: host_(host)
135+
, info_(nullptr)
80136
{
81137
struct addrinfo hints;
82138
memset(&hints, 0, sizeof(hints));
@@ -112,29 +168,37 @@ NetworkAddress::~NetworkAddress() {
112168
const struct addrinfo* NetworkAddress::Info() const {
113169
return info_;
114170
}
115-
116-
117-
SocketHolder::SocketHolder()
118-
: handle_(-1)
119-
{
171+
const std::string & NetworkAddress::Host() const {
172+
return host_;
120173
}
121174

122-
SocketHolder::SocketHolder(SOCKET s)
123-
: handle_(s)
124-
{
125-
}
126175

127-
SocketHolder::SocketHolder(SocketHolder&& other) noexcept
176+
Socket::Socket(const NetworkAddress& addr)
177+
: handle_(SocketConnect(addr))
178+
{}
179+
180+
Socket::Socket(Socket&& other) noexcept
128181
: handle_(other.handle_)
129182
{
130183
other.handle_ = -1;
131184
}
132185

133-
SocketHolder::~SocketHolder() {
186+
Socket& Socket::operator=(Socket&& other) noexcept {
187+
if (this != &other) {
188+
Close();
189+
190+
handle_ = other.handle_;
191+
other.handle_ = -1;
192+
}
193+
194+
return *this;
195+
}
196+
197+
Socket::~Socket() {
134198
Close();
135199
}
136200

137-
void SocketHolder::Close() noexcept {
201+
void Socket::Close() {
138202
if (handle_ != -1) {
139203
#if defined(_win_)
140204
closesocket(handle_);
@@ -145,11 +209,7 @@ void SocketHolder::Close() noexcept {
145209
}
146210
}
147211

148-
bool SocketHolder::Closed() const noexcept {
149-
return handle_ == -1;
150-
}
151-
152-
void SocketHolder::SetTcpKeepAlive(int idle, int intvl, int cnt) noexcept {
212+
void Socket::SetTcpKeepAlive(int idle, int intvl, int cnt) noexcept {
153213
int val = 1;
154214

155215
#if defined(_unix_)
@@ -169,7 +229,7 @@ void SocketHolder::SetTcpKeepAlive(int idle, int intvl, int cnt) noexcept {
169229
#endif
170230
}
171231

172-
void SocketHolder::SetTcpNoDelay(bool nodelay) noexcept {
232+
void Socket::SetTcpNoDelay(bool nodelay) noexcept {
173233
int val = nodelay;
174234
#if defined(_unix_)
175235
setsockopt(handle_, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
@@ -178,22 +238,14 @@ void SocketHolder::SetTcpNoDelay(bool nodelay) noexcept {
178238
#endif
179239
}
180240

181-
SocketHolder& SocketHolder::operator = (SocketHolder&& other) noexcept {
182-
if (this != &other) {
183-
Close();
184-
185-
handle_ = other.handle_;
186-
other.handle_ = -1;
187-
}
188-
189-
return *this;
241+
std::unique_ptr<InputStream> Socket::makeInputStream() const {
242+
return std::make_unique<SocketInput>(handle_);
190243
}
191244

192-
SocketHolder::operator SOCKET () const noexcept {
193-
return handle_;
245+
std::unique_ptr<OutputStream> Socket::makeOutputStream() const {
246+
return std::make_unique<SocketOutput>(handle_);
194247
}
195248

196-
197249
SocketInput::SocketInput(SOCKET s)
198250
: s_(s)
199251
{
@@ -262,61 +314,4 @@ NetrworkInitializer::NetrworkInitializer() {
262314
(void)Singleton<NetrworkInitializerImpl>();
263315
}
264316

265-
266-
SOCKET SocketConnect(const NetworkAddress& addr) {
267-
int last_err = 0;
268-
for (auto res = addr.Info(); res != nullptr; res = res->ai_next) {
269-
SOCKET s(socket(res->ai_family, res->ai_socktype, res->ai_protocol));
270-
271-
if (s == -1) {
272-
continue;
273-
}
274-
275-
SetNonBlock(s, true);
276-
277-
if (connect(s, res->ai_addr, (int)res->ai_addrlen) != 0) {
278-
int err = errno;
279-
if (err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK) {
280-
pollfd fd;
281-
fd.fd = s;
282-
fd.events = POLLOUT;
283-
fd.revents = 0;
284-
ssize_t rval = Poll(&fd, 1, 5000);
285-
286-
if (rval == -1) {
287-
throw std::system_error(errno, std::system_category(), "fail to connect");
288-
}
289-
if (rval > 0) {
290-
socklen_t len = sizeof(err);
291-
getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&err, &len);
292-
293-
if (!err) {
294-
SetNonBlock(s, false);
295-
return s;
296-
}
297-
last_err = err;
298-
}
299-
}
300-
} else {
301-
SetNonBlock(s, false);
302-
return s;
303-
}
304-
}
305-
if (last_err > 0) {
306-
throw std::system_error(last_err, std::system_category(), "fail to connect");
307-
}
308-
throw std::system_error(
309-
errno, std::system_category(), "fail to connect"
310-
);
311-
}
312-
313-
314-
ssize_t Poll(struct pollfd* fds, int nfds, int timeout) noexcept {
315-
#if defined(_win_)
316-
return WSAPoll(fds, nfds, timeout);
317-
#else
318-
return poll(fds, nfds, timeout);
319-
#endif
320-
}
321-
322317
}

0 commit comments

Comments
 (0)