Skip to content

Commit afdb9d2

Browse files
committed
Add support for Microsoft Visual C++
1 parent b36c87f commit afdb9d2

File tree

8 files changed

+158
-34
lines changed

8 files changed

+158
-34
lines changed

.github/workflows/windows_msvc.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: Windows
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
branches: [ master ]
8+
9+
env:
10+
BUILD_TYPE: Release
11+
GTEST_FILTER: --gtest_filter=-"*"
12+
CLICKHOUSE_USER: clickhouse_cpp_cicd
13+
CLICKHOUSE_PASSWORD: clickhouse_cpp_cicd
14+
#
15+
# CLICKHOUSE_HOST: localhost
16+
# CLICKHOUSE_PORT: 9000
17+
# CLICKHOUSE_USER: default
18+
# CLICKHOUSE_PASSWORD:
19+
# CLICKHOUSE_DB: default
20+
#
21+
# CLICKHOUSE_SECURE_HOST: github.demo.trial.altinity.cloud
22+
# CLICKHOUSE_SECURE_PORT: 9440
23+
# CLICKHOUSE_SECURE_USER: demo
24+
# CLICKHOUSE_SECURE_PASSWORD: demo
25+
# CLICKHOUSE_SECURE_DB: default
26+
#
27+
# CLICKHOUSE_SECURE2_HOST: gh-api.clickhouse.tech
28+
# CLICKHOUSE_SECURE2_PORT: 9440
29+
# CLICKHOUSE_SECURE2_USER: explorer
30+
# CLICKHOUSE_SECURE2_PASSWORD:
31+
# CLICKHOUSE_SECURE2_DB: default
32+
33+
jobs:
34+
build:
35+
runs-on: windows-latest
36+
37+
steps:
38+
- uses: actions/checkout@v2
39+
- uses: ilammy/msvc-dev-cmd@v1
40+
41+
- name: Configure CMake
42+
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_TESTS=ON
43+
44+
- name: Build
45+
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
46+
47+
- name: Start tls offoader proxy
48+
shell: bash
49+
# that mimics non-secure clickhouse running on localhost
50+
# by tunneling queries to remote tls server
51+
# (needed because we can't start real clickhouse instance on windows)
52+
run: |
53+
choco install wget
54+
wget https://github.com/filimonov/go-tlsoffloader/releases/download/v0.1.2/go-tlsoffloader_0.1.2_Windows_x86_64.tar.gz
55+
tar -xvzf go-tlsoffloader_0.1.2_Windows_x86_64.tar.gz
56+
./go-tlsoffloader.exe -l localhost:9000 -b github.demo.trial.altinity.cloud:9440 &
57+
58+
- name: Test
59+
working-directory: ${{github.workspace}}/build/ut
60+
run: Release\clickhouse-cpp-ut.exe "${{env.GTEST_FILTER}}"

clickhouse/base/platform.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
#if defined(_win32_) || defined(_win64_)
1515
# define _win_
16+
# define _WIN32_WINNT 0x0600 // The WSAPoll function is defined on Windows Vista and later.
17+
# define WIN32_LEAN_AND_MEAN 1 // don't include too much header automatically
1618
#endif
1719

1820
#if defined(_linux_) || defined (_darwin_)

clickhouse/base/socket.cpp

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,33 @@
1414
# include <netinet/tcp.h>
1515
# include <signal.h>
1616
# include <unistd.h>
17-
# include <netinet/tcp.h>
1817
#endif
1918

2019
namespace clickhouse {
2120

21+
#if defined(_win_)
22+
char const* windowsErrorCategory::name() const noexcept {
23+
return "WindowsSocketError";
24+
}
25+
26+
std::string windowsErrorCategory::message(int c) const {
27+
char error[UINT8_MAX];
28+
auto len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, static_cast<DWORD>(c), 0, error, sizeof(error), nullptr);
29+
if (len == 0) {
30+
return "unknown";
31+
}
32+
while (len && (error[len - 1] == '\r' || error[len - 1] == '\n')) {
33+
--len;
34+
}
35+
return std::string(error, len);
36+
}
37+
38+
windowsErrorCategory const& windowsErrorCategory::category() {
39+
static windowsErrorCategory c;
40+
return c;
41+
}
42+
#endif
43+
2244
namespace {
2345

2446
class LocalNames : public std::unordered_set<std::string> {
@@ -37,6 +59,22 @@ class LocalNames : public std::unordered_set<std::string> {
3759
}
3860
};
3961

62+
inline int getSocketErrorCode() {
63+
#if defined(_win_)
64+
return WSAGetLastError();
65+
#else
66+
return errno;
67+
#endif
68+
}
69+
70+
const std::error_category& getErrorCategory() noexcept {
71+
#if defined(_win_)
72+
return windowsErrorCategory::category();
73+
#else
74+
return std::system_category();
75+
#endif
76+
}
77+
4078
void SetNonBlock(SOCKET fd, bool value) {
4179
#if defined(_unix_)
4280
int flags;
@@ -55,8 +93,7 @@ void SetNonBlock(SOCKET fd, bool value) {
5593
return ioctl(fd, FIOBIO, &flags);
5694
#endif
5795
if (ret == -1) {
58-
throw std::system_error(
59-
errno, std::system_category(), "fail to set nonblocking mode");
96+
throw std::system_error(getSocketErrorCode(), getErrorCategory(), "fail to set nonblocking mode");
6097
}
6198
#elif defined(_win_)
6299
unsigned long inbuf = value;
@@ -68,8 +105,7 @@ void SetNonBlock(SOCKET fd, bool value) {
68105
}
69106

70107
if (WSAIoctl(fd, FIONBIO, &inbuf, sizeof(inbuf), &outbuf, sizeof(outbuf), &written, 0, 0) == SOCKET_ERROR) {
71-
throw std::system_error(
72-
errno, std::system_category(), "fail to set nonblocking mode");
108+
throw std::system_error(getSocketErrorCode(), getErrorCategory(), "fail to set nonblocking mode");
73109
}
74110
#endif
75111
}
@@ -94,16 +130,21 @@ SOCKET SocketConnect(const NetworkAddress& addr) {
94130
SetNonBlock(s, true);
95131

96132
if (connect(s, res->ai_addr, (int)res->ai_addrlen) != 0) {
97-
int err = errno;
98-
if (err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK) {
133+
int err = getSocketErrorCode();
134+
if (
135+
err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK
136+
#if defined(_win_)
137+
|| err == WSAEWOULDBLOCK || err == WSAEINPROGRESS
138+
#endif
139+
) {
99140
pollfd fd;
100141
fd.fd = s;
101142
fd.events = POLLOUT;
102143
fd.revents = 0;
103144
ssize_t rval = Poll(&fd, 1, 5000);
104145

105146
if (rval == -1) {
106-
throw std::system_error(errno, std::system_category(), "fail to connect");
147+
throw std::system_error(getSocketErrorCode(), getErrorCategory(), "fail to connect");
107148
}
108149
if (rval > 0) {
109150
socklen_t len = sizeof(err);
@@ -122,11 +163,9 @@ SOCKET SocketConnect(const NetworkAddress& addr) {
122163
}
123164
}
124165
if (last_err > 0) {
125-
throw std::system_error(last_err, std::system_category(), "fail to connect");
166+
throw std::system_error(last_err, getErrorCategory(), "fail to connect");
126167
}
127-
throw std::system_error(
128-
errno, std::system_category(), "fail to connect"
129-
);
168+
throw std::system_error(getSocketErrorCode(), getErrorCategory(), "fail to connect");
130169
}
131170

132171
} // namespace
@@ -156,7 +195,7 @@ NetworkAddress::NetworkAddress(const std::string& host, const std::string& port)
156195
const int error = getaddrinfo(host.c_str(), port.c_str(), &hints, &info_);
157196

158197
if (error) {
159-
throw std::system_error(errno, std::system_category());
198+
throw std::system_error(getSocketErrorCode(), getErrorCategory());
160199
}
161200
}
162201

@@ -262,14 +301,10 @@ size_t SocketInput::DoRead(void* buf, size_t len) {
262301
}
263302

264303
if (ret == 0) {
265-
throw std::system_error(
266-
errno, std::system_category(), "closed"
267-
);
304+
throw std::system_error(getSocketErrorCode(), getErrorCategory(), "closed");
268305
}
269306

270-
throw std::system_error(
271-
errno, std::system_category(), "can't receive string data"
272-
);
307+
throw std::system_error(getSocketErrorCode(), getErrorCategory(), "can't receive string data");
273308
}
274309

275310
bool SocketInput::Skip(size_t /*bytes*/) {
@@ -292,9 +327,7 @@ size_t SocketOutput::DoWrite(const void* data, size_t len) {
292327
#endif
293328

294329
if (::send(s_, (const char*)data, (int)len, flags) != (int)len) {
295-
throw std::system_error(
296-
errno, std::system_category(), "fail to send " + std::to_string(len) + " bytes of data"
297-
);
330+
throw std::system_error(getSocketErrorCode(), getErrorCategory(), "fail to send " + std::to_string(len) + " bytes of data");
298331
}
299332

300333
return len;

clickhouse/base/socket.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#pragma once
22

3+
#include "platform.h"
34
#include "input.h"
45
#include "output.h"
5-
#include "platform.h"
66

77
#include <cstddef>
88
#include <string>
@@ -24,7 +24,7 @@
2424
#endif
2525

2626
#include <memory>
27-
27+
#include <system_error>
2828

2929
struct addrinfo;
3030

@@ -47,6 +47,17 @@ class NetworkAddress {
4747
struct addrinfo* info_;
4848
};
4949

50+
#if defined(_win_)
51+
52+
class windowsErrorCategory : public std::error_category {
53+
public:
54+
char const* name() const noexcept override final;
55+
std::string message(int c) const override final;
56+
57+
static windowsErrorCategory const& category();
58+
};
59+
60+
#endif
5061

5162
class Socket {
5263
public:

tests/simple/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ ADD_EXECUTABLE (simple-test
33
)
44

55
TARGET_LINK_LIBRARIES (simple-test
6-
clickhouse-cpp-lib
6+
clickhouse-cpp-lib-static
77
)
88

99
IF (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")

ut/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ ADD_EXECUTABLE (clickhouse-cpp-ut
2525
)
2626

2727
TARGET_LINK_LIBRARIES (clickhouse-cpp-ut
28-
clickhouse-cpp-lib
28+
clickhouse-cpp-lib-static
2929
gtest-lib
3030
)
3131
IF (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")

ut/tcp_server.cpp

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
#include "tcp_server.h"
22

33
#include <iostream>
4-
#include <netinet/in.h>
54
#include <stdio.h>
65
#include <stdlib.h>
76
#include <string.h>
8-
#include <sys/socket.h>
7+
8+
#if defined(__WIN32__) || defined(_WIN32) || defined(_WIN64)
9+
# include <winsock2.h>
10+
#else
11+
# include <netinet/in.h>
12+
# include <sys/socket.h>
13+
# include <unistd.h>
14+
#endif
15+
916
#include <thread>
10-
#include <unistd.h>
1117

1218
namespace clickhouse {
1319

@@ -23,7 +29,7 @@ LocalTcpServer::~LocalTcpServer() {
2329
void LocalTcpServer::start() {
2430
//setup a socket
2531
sockaddr_in servAddr;
26-
bzero((char*)&servAddr, sizeof(servAddr));
32+
memset((char*)&servAddr, 0, sizeof(servAddr));
2733
servAddr.sin_family = AF_INET;
2834
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
2935
servAddr.sin_port = htons(port_);
@@ -33,7 +39,14 @@ void LocalTcpServer::start() {
3339
throw std::runtime_error("Error establishing server socket");
3440
}
3541
int enable = 1;
36-
if (setsockopt(serverSd_, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
42+
43+
#if defined(__WIN32__) || defined(_WIN32) || defined(_WIN64)
44+
auto res = setsockopt(serverSd_, SOL_SOCKET, SO_REUSEADDR, (const char*)&enable, sizeof(enable));
45+
#else
46+
auto res = setsockopt(serverSd_, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
47+
#endif
48+
49+
if (res < 0) {
3750
std::cerr << "setsockopt(SO_REUSEADDR) failed" << std::endl;
3851
}
3952
//bind the socket to its local address
@@ -47,8 +60,14 @@ void LocalTcpServer::start() {
4760

4861
void LocalTcpServer::stop() {
4962
if(serverSd_ > 0) {
63+
64+
#if defined(__WIN32__) || defined(_WIN32) || defined(_WIN64)
65+
shutdown(serverSd_, SD_BOTH);
66+
closesocket(serverSd_);
67+
#else
5068
shutdown(serverSd_, SHUT_RDWR);
5169
close(serverSd_);
70+
#endif
5271
serverSd_ = -1;
5372
}
5473
}

ut/utils.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,8 @@ struct Timer
3939
private:
4040
static auto Now()
4141
{
42-
struct timespec ts;
43-
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
44-
return std::chrono::nanoseconds(ts.tv_sec * 1000000000LL + ts.tv_nsec);
42+
std::chrono::nanoseconds ns = std::chrono::high_resolution_clock::now().time_since_epoch();
43+
return ns;
4544
}
4645

4746
private:

0 commit comments

Comments
 (0)