Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented connecting to ClickHouse server over TLS #109

Merged
merged 4 commits into from
Nov 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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")
Enmk marked this conversation as resolved.
Show resolved Hide resolved
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