Skip to content

Commit

Permalink
Merge pull request #109 from Enmk/openssl
Browse files Browse the repository at this point in the history
Implemented connecting to ClickHouse server over TLS
  • Loading branch information
traceon authored Nov 11, 2021
2 parents a0914ba + 61923c1 commit 5cfda7f
Show file tree
Hide file tree
Showing 25 changed files with 1,049 additions and 244 deletions.
34 changes: 18 additions & 16 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,24 @@ on:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_call:
inputs:
extra_cmake_flags:
required: false
type: string
extra_install:
required: false
type: string
gtest_args:
required: false
type: string

env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
CH_SERVER_VERSION: 21.3.17.2

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

- name: Install dependencies
run: |
sudo apt-get install -y ${{ matrix.INSTALL }}
sudo apt-get install -y ${{ matrix.INSTALL }} ${{ inputs.extra_install }}
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: |
cmake \
-D CMAKE_C_COMPILER=${{ matrix.C_COMPILER}} \
-D CMAKE_CXX_COMPILER=${{ matrix.CXX_COMPILER}} \
-B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_TESTS=ON
-DCMAKE_C_COMPILER=${{ matrix.C_COMPILER}} \
-DCMAKE_CXX_COMPILER=${{ matrix.CXX_COMPILER}} \
-B ${{github.workspace}}/build \
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_TESTS=ON \
${{ inputs.extra_cmake_flags }}
- name: Build
Expand All @@ -70,8 +76,4 @@ jobs:
- name: Test
working-directory: ${{github.workspace}}/build/ut
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
#run: ctest -C ${{env.BUILD_TYPE}}
run: ./clickhouse-cpp-ut "${{env.GTEST_FILTER}}"

run: ./clickhouse-cpp-ut "${{ inputs.gtest_args }}"
16 changes: 16 additions & 0 deletions .github/workflows/linux_ssl.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Linux-ssl
# Almost the same as regular Linux builds, BUT with enabled SSL support, requires OpenSSL installed

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build-and-test:
uses: Enmk/clickhouse-cpp/.github/workflows/linux.yml@master
with:
extra_cmake_flags: -DWITH_OPENSSL=ON
extra_install: libssl-dev
# gtest_args: --gtest_filter="-*LocalhostTLS*"
21 changes: 12 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,32 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.0.2)

INCLUDE (cmake/cpp17.cmake)
INCLUDE (cmake/subdirs.cmake)
INCLUDE (cmake/openssl.cmake)

OPTION(BUILD_BENCHMARK "Build benchmark" OFF)
OPTION(BUILD_TESTS "Build tests" OFF)
OPTION (BUILD_BENCHMARK "Build benchmark" OFF)
OPTION (BUILD_TESTS "Build tests" OFF)
OPTION (WITH_OPENSSL "Use OpenSSL for TLS connections" OFF)

PROJECT (CLICKHOUSE-CLIENT)

USE_CXX17()
USE_OPENSSL()

IF ("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE "Debug")
ENDIF()
IF ("${CMAKE_BUILD_TYPE}" STREQUAL "")
SET (CMAKE_BUILD_TYPE "Debug")
ENDIF()

IF (UNIX)
IF (APPLE)
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall -Wextra -Werror")
ELSE ()
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -pthread -Wall -Wextra -Werror")
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -Wall -Wextra -Werror")
ENDIF ()
SET (CMAKE_EXE_LINKER_FLAGS, "${CMAKE_EXE_LINKER_FLAGS} -lpthread")
ENDIF ()

INCLUDE_DIRECTORIES(.)
INCLUDE_DIRECTORIES(contrib)
INCLUDE_DIRECTORIES (.)
INCLUDE_DIRECTORIES (contrib)

SUBDIRS (
clickhouse
Expand All @@ -43,4 +46,4 @@ PROJECT (CLICKHOUSE-CLIENT)
tests/simple
ut
)
ENDIF (BUILD_TESTS)
ENDIF (BUILD_TESTS)
13 changes: 11 additions & 2 deletions clickhouse/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ SET ( clickhouse-cpp-lib-src
query.cpp
)

IF (WITH_OPENSSL)
LIST(APPEND clickhouse-cpp-lib-src base/sslsocket.cpp)
ENDIF ()

ADD_LIBRARY (clickhouse-cpp-lib SHARED ${clickhouse-cpp-lib-src})
SET_TARGET_PROPERTIES(clickhouse-cpp-lib PROPERTIES LINKER_LANGUAGE CXX)
TARGET_LINK_LIBRARIES (clickhouse-cpp-lib
Expand All @@ -52,7 +56,7 @@ IF (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
TARGET_LINK_LIBRARIES (clickhouse-cpp-lib-static gcc_s)
ENDIF ()

INSTALL(TARGETS clickhouse-cpp-lib clickhouse-cpp-lib-static
INSTALL (TARGETS clickhouse-cpp-lib clickhouse-cpp-lib-static
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
)
Expand All @@ -67,8 +71,8 @@ INSTALL(FILES protocol.h DESTINATION include/clickhouse/)
INSTALL(FILES query.h DESTINATION include/clickhouse/)

# base
INSTALL(FILES base/buffer.h DESTINATION include/clickhouse/base/)
INSTALL(FILES base/coded.h DESTINATION include/clickhouse/base/)
INSTALL(FILES base/buffer.h DESTINATION include/clickhouse/base/)
INSTALL(FILES base/compressed.h DESTINATION include/clickhouse/base/)
INSTALL(FILES base/input.h DESTINATION include/clickhouse/base/)
INSTALL(FILES base/output.h DESTINATION include/clickhouse/base/)
Expand Down Expand Up @@ -100,3 +104,8 @@ INSTALL(FILES columns/uuid.h DESTINATION include/clickhouse/columns/)
# types
INSTALL(FILES types/type_parser.h DESTINATION include/clickhouse/types/)
INSTALL(FILES types/types.h DESTINATION include/clickhouse/types/)

IF (WITH_OPENSSL)
TARGET_LINK_LIBRARIES (clickhouse-cpp-lib OpenSSL::SSL)
TARGET_LINK_LIBRARIES (clickhouse-cpp-lib-static OpenSSL::SSL)
ENDIF ()
171 changes: 83 additions & 88 deletions clickhouse/base/socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,66 @@ void SetNonBlock(SOCKET fd, bool value) {
#endif
}

ssize_t Poll(struct pollfd* fds, int nfds, int timeout) noexcept {
#if defined(_win_)
return WSAPoll(fds, nfds, timeout);
#else
return poll(fds, nfds, timeout);
#endif
}

SOCKET SocketConnect(const NetworkAddress& addr) {
int last_err = 0;
for (auto res = addr.Info(); res != nullptr; res = res->ai_next) {
SOCKET s(socket(res->ai_family, res->ai_socktype, res->ai_protocol));

if (s == -1) {
continue;
}

SetNonBlock(s, true);

if (connect(s, res->ai_addr, (int)res->ai_addrlen) != 0) {
int err = errno;
if (err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK) {
pollfd fd;
fd.fd = s;
fd.events = POLLOUT;
fd.revents = 0;
ssize_t rval = Poll(&fd, 1, 5000);

if (rval == -1) {
throw std::system_error(errno, std::system_category(), "fail to connect");
}
if (rval > 0) {
socklen_t len = sizeof(err);
getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&err, &len);

if (!err) {
SetNonBlock(s, false);
return s;
}
last_err = err;
}
}
} else {
SetNonBlock(s, false);
return s;
}
}
if (last_err > 0) {
throw std::system_error(last_err, std::system_category(), "fail to connect");
}
throw std::system_error(
errno, std::system_category(), "fail to connect"
);
}

} // namespace

NetworkAddress::NetworkAddress(const std::string& host, const std::string& port)
: info_(nullptr)
: host_(host)
, info_(nullptr)
{
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
Expand Down Expand Up @@ -112,29 +168,37 @@ NetworkAddress::~NetworkAddress() {
const struct addrinfo* NetworkAddress::Info() const {
return info_;
}


SocketHolder::SocketHolder()
: handle_(-1)
{
const std::string & NetworkAddress::Host() const {
return host_;
}

SocketHolder::SocketHolder(SOCKET s)
: handle_(s)
{
}

SocketHolder::SocketHolder(SocketHolder&& other) noexcept
Socket::Socket(const NetworkAddress& addr)
: handle_(SocketConnect(addr))
{}

Socket::Socket(Socket&& other) noexcept
: handle_(other.handle_)
{
other.handle_ = -1;
}

SocketHolder::~SocketHolder() {
Socket& Socket::operator=(Socket&& other) noexcept {
if (this != &other) {
Close();

handle_ = other.handle_;
other.handle_ = -1;
}

return *this;
}

Socket::~Socket() {
Close();
}

void SocketHolder::Close() noexcept {
void Socket::Close() {
if (handle_ != -1) {
#if defined(_win_)
closesocket(handle_);
Expand All @@ -145,11 +209,7 @@ void SocketHolder::Close() noexcept {
}
}

bool SocketHolder::Closed() const noexcept {
return handle_ == -1;
}

void SocketHolder::SetTcpKeepAlive(int idle, int intvl, int cnt) noexcept {
void Socket::SetTcpKeepAlive(int idle, int intvl, int cnt) noexcept {
int val = 1;

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

void SocketHolder::SetTcpNoDelay(bool nodelay) noexcept {
void Socket::SetTcpNoDelay(bool nodelay) noexcept {
int val = nodelay;
#if defined(_unix_)
setsockopt(handle_, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
Expand All @@ -178,22 +238,14 @@ void SocketHolder::SetTcpNoDelay(bool nodelay) noexcept {
#endif
}

SocketHolder& SocketHolder::operator = (SocketHolder&& other) noexcept {
if (this != &other) {
Close();

handle_ = other.handle_;
other.handle_ = -1;
}

return *this;
std::unique_ptr<InputStream> Socket::makeInputStream() const {
return std::make_unique<SocketInput>(handle_);
}

SocketHolder::operator SOCKET () const noexcept {
return handle_;
std::unique_ptr<OutputStream> Socket::makeOutputStream() const {
return std::make_unique<SocketOutput>(handle_);
}


SocketInput::SocketInput(SOCKET s)
: s_(s)
{
Expand Down Expand Up @@ -262,61 +314,4 @@ NetrworkInitializer::NetrworkInitializer() {
(void)Singleton<NetrworkInitializerImpl>();
}


SOCKET SocketConnect(const NetworkAddress& addr) {
int last_err = 0;
for (auto res = addr.Info(); res != nullptr; res = res->ai_next) {
SOCKET s(socket(res->ai_family, res->ai_socktype, res->ai_protocol));

if (s == -1) {
continue;
}

SetNonBlock(s, true);

if (connect(s, res->ai_addr, (int)res->ai_addrlen) != 0) {
int err = errno;
if (err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK) {
pollfd fd;
fd.fd = s;
fd.events = POLLOUT;
fd.revents = 0;
ssize_t rval = Poll(&fd, 1, 5000);

if (rval == -1) {
throw std::system_error(errno, std::system_category(), "fail to connect");
}
if (rval > 0) {
socklen_t len = sizeof(err);
getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&err, &len);

if (!err) {
SetNonBlock(s, false);
return s;
}
last_err = err;
}
}
} else {
SetNonBlock(s, false);
return s;
}
}
if (last_err > 0) {
throw std::system_error(last_err, std::system_category(), "fail to connect");
}
throw std::system_error(
errno, std::system_category(), "fail to connect"
);
}


ssize_t Poll(struct pollfd* fds, int nfds, int timeout) noexcept {
#if defined(_win_)
return WSAPoll(fds, nfds, timeout);
#else
return poll(fds, nfds, timeout);
#endif
}

}
Loading

0 comments on commit 5cfda7f

Please sign in to comment.