Skip to content

Commit b395cea

Browse files
authored
workaround botan backend init failure on MacOS (#303)
1 parent d596221 commit b395cea

File tree

3 files changed

+119
-25
lines changed

3 files changed

+119
-25
lines changed

.github/workflows/cmake.yml

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,22 @@ jobs:
6363
buildname: 'ubuntu-20.04/gcc - OpenSSL'
6464
triplet: x64-linux
6565
compiler: gcc_64
66+
tls_provider: openssl
6667
- os: ubuntu-20.04
6768
buildname: 'ubuntu-20.04/gcc'
6869
triplet: x64-linux
6970
compiler: gcc_64
71+
tls_provider: none
7072
- os: macos-latest
7173
buildname: 'macos/clang'
7274
triplet: x64-osx
7375
compiler: clang_64
76+
tls_provider: openssl
77+
- os: macos-latest
78+
buildname: 'macos/clang - Botan'
79+
triplet: x64-osx
80+
compiler: clang_64
81+
tls_provider: botan
7482

7583
steps:
7684
- name: Checkout Trantor source code
@@ -82,20 +90,14 @@ jobs:
8290
- name: (macOS) Install dependencies
8391
if: runner.os == 'macOS'
8492
run: |
85-
brew install c-ares openssl spdlog
93+
brew install c-ares openssl spdlog botan
8694
87-
- name: (Linux) Install dependencies - OpenSSL
88-
if: matrix.buildname == 'ubuntu-20.04/gcc - OpenSSL'
89-
run: |
90-
# Installing packages might fail as the github image becomes outdated
91-
sudo apt update
92-
sudo apt install openssl libssl-dev dos2unix libspdlog-dev libfmt-dev
9395
- name: (Linux) Install dependencies
94-
if: matrix.buildname == 'ubuntu-20.04/gcc'
96+
if: matrix.os == 'Linux'
9597
run: |
9698
# Installing packages might fail as the github image becomes outdated
9799
sudo apt update
98-
sudo apt install dos2unix libspdlog-dev libfmt-dev
100+
sudo apt install openssl libssl-dev dos2unix libspdlog-dev libfmt-dev
99101
- name: install gtest
100102
run: |
101103
wget https://github.com/google/googletest/archive/refs/tags/v1.13.0.tar.gz
@@ -113,7 +115,7 @@ jobs:
113115
run: |
114116
mkdir build
115117
cd build
116-
cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_TESTING=on -DUSE_SPDLOG=ON
118+
cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_TESTING=on -DUSE_SPDLOG=ON -DTRANTOR_USE_TLS=${{ matrix.tls_provider }}
117119
118120
- name: Build
119121
working-directory: ${{env.GITHUB_WORKSPACE}}

trantor/net/inner/tlsprovider/BotanTLSProvider.cc

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ static std::once_flag sessionManagerInitFlag;
2727
static std::shared_ptr<Botan::AutoSeeded_RNG> sessionManagerRng;
2828
static std::shared_ptr<Botan::TLS::Session_Manager_In_Memory> sessionManager;
2929
static thread_local std::shared_ptr<Botan::AutoSeeded_RNG> rng;
30-
static Botan::System_Certificate_Store certStore;
30+
static std::unique_ptr<Botan::System_Certificate_Store> systemCertStore;
31+
static std::once_flag systemCertStoreInitFlag;
3132

3233
using namespace trantor;
3334

@@ -231,15 +232,20 @@ struct BotanTLSProvider : public TLSProvider,
231232
if (channel_ && channel_->is_active())
232233
{
233234
channel_->close();
234-
channel_ = nullptr;
235235
}
236236
}
237237

238238
virtual void startEncryption() override
239239
{
240240
auto certStorePtr = contextPtr_->certStore.get();
241241
if (certStorePtr == nullptr)
242-
certStorePtr = &certStore;
242+
{
243+
std::call_once(systemCertStoreInitFlag, []() {
244+
systemCertStore =
245+
std::make_unique<Botan::System_Certificate_Store>();
246+
});
247+
certStorePtr = systemCertStore.get();
248+
}
243249
credsPtr_ = std::make_shared<Credentials>(contextPtr_->key,
244250
contextPtr_->cert.get(),
245251
certStorePtr);
@@ -255,12 +261,14 @@ struct BotanTLSProvider : public TLSProvider,
255261
});
256262
if (rng == nullptr)
257263
rng = std::make_shared<Botan::AutoSeeded_RNG>();
264+
265+
auto fakeThis = std::shared_ptr<BotanTLSProvider>(this, [](auto) {});
258266
if (contextPtr_->isServer)
259267
{
260268
// TODO: Need a more scalable way to manage session validation rules
261269
validationPolicy_->requireClientCert_ =
262270
contextPtr_->requireClientCert;
263-
channel_ = std::make_unique<Botan::TLS::Server>(shared_from_this(),
271+
channel_ = std::make_unique<Botan::TLS::Server>(std::move(fakeThis),
264272
sessionManager,
265273
credsPtr_,
266274
validationPolicy_,
@@ -275,7 +283,7 @@ struct BotanTLSProvider : public TLSProvider,
275283
if (policyPtr_->getUseOldTLS())
276284
LOG_WARN << "Old TLS not supported by Botan (only >= TLS 1.2)";
277285
channel_ = std::make_unique<Botan::TLS::Client>(
278-
shared_from_this(),
286+
std::move(fakeThis),
279287
sessionManager,
280288
credsPtr_,
281289
validationPolicy_,

trantor/utils/Utilities.cc

Lines changed: 94 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,98 @@
5858
#include <memory>
5959
#include <trantor/utils/Logger.h>
6060

61+
#if __cplusplus < 201103L || __cplusplus >= 201703L
62+
static std::wstring utf8Toutf16(const std::string &utf8Str)
63+
{
64+
std::wstring utf16Str;
65+
utf16Str.reserve(utf8Str.length()); // Reserve space to avoid reallocations
66+
67+
for (size_t i = 0; i < utf8Str.length();)
68+
{
69+
wchar_t unicode_char;
70+
71+
// Check the first byte
72+
if ((utf8Str[i] & 0b10000000) == 0)
73+
{
74+
// Single-byte character (ASCII)
75+
unicode_char = utf8Str[i++];
76+
}
77+
else if ((utf8Str[i] & 0b11100000) == 0b11000000)
78+
{
79+
if (i + 1 >= utf8Str.length())
80+
{
81+
// Invalid UTF-8 sequence
82+
// Handle the error as needed
83+
return L"";
84+
}
85+
// Two-byte character
86+
unicode_char = ((utf8Str[i] & 0b00011111) << 6) |
87+
(utf8Str[i + 1] & 0b00111111);
88+
i += 2;
89+
}
90+
else if ((utf8Str[i] & 0b11110000) == 0b11100000)
91+
{
92+
if (i + 2 >= utf8Str.length())
93+
{
94+
// Invalid UTF-8 sequence
95+
// Handle the error as needed
96+
return L"";
97+
}
98+
// Three-byte character
99+
unicode_char = ((utf8Str[i] & 0b00001111) << 12) |
100+
((utf8Str[i + 1] & 0b00111111) << 6) |
101+
(utf8Str[i + 2] & 0b00111111);
102+
i += 3;
103+
}
104+
else
105+
{
106+
// Invalid UTF-8 sequence
107+
// Handle the error as needed
108+
return L"";
109+
}
110+
111+
utf16Str.push_back(unicode_char);
112+
}
113+
114+
return utf16Str;
115+
}
116+
117+
static std::string utf16Toutf8(const std::wstring &utf16Str)
118+
{
119+
std::string utf8Str;
120+
utf8Str.reserve(utf16Str.length() * 3);
121+
122+
for (size_t i = 0; i < utf16Str.length(); ++i)
123+
{
124+
wchar_t unicode_char = utf16Str[i];
125+
126+
if (unicode_char <= 0x7F)
127+
{
128+
// Single-byte character (ASCII)
129+
utf8Str.push_back(static_cast<char>(unicode_char));
130+
}
131+
else if (unicode_char <= 0x7FF)
132+
{
133+
// Two-byte character
134+
utf8Str.push_back(
135+
static_cast<char>(0xC0 | ((unicode_char >> 6) & 0x1F)));
136+
utf8Str.push_back(static_cast<char>(0x80 | (unicode_char & 0x3F)));
137+
}
138+
else
139+
{
140+
// Three-byte character
141+
utf8Str.push_back(
142+
static_cast<char>(0xE0 | ((unicode_char >> 12) & 0x0F)));
143+
utf8Str.push_back(
144+
static_cast<char>(0x80 | ((unicode_char >> 6) & 0x3F)));
145+
utf8Str.push_back(static_cast<char>(0x80 | (unicode_char & 0x3F)));
146+
}
147+
}
148+
149+
return utf8Str;
150+
}
151+
#endif // __cplusplus
152+
61153
namespace trantor
62154
{
63155
namespace utils
@@ -81,11 +173,7 @@ std::string toUtf8(const std::wstring &wstr)
81173
NULL,
82174
NULL);
83175
#elif __cplusplus < 201103L || __cplusplus >= 201703L
84-
// Note: Introduced in c++11 and deprecated with c++17.
85-
// Revert to C99 code since there no replacement yet
86-
strTo.resize(3 * wstr.length(), 0);
87-
auto nLen = wcstombs(&strTo[0], wstr.c_str(), strTo.length());
88-
strTo.resize(nLen);
176+
strTo = utf16Toutf8(wstr);
89177
#else // c++11 to c++14
90178
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> utf8conv;
91179
strTo = utf8conv.to_bytes(wstr);
@@ -104,11 +192,7 @@ std::wstring fromUtf8(const std::string &str)
104192
::MultiByteToWideChar(
105193
CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], nSizeNeeded);
106194
#elif __cplusplus < 201103L || __cplusplus >= 201703L
107-
// Note: Introduced in c++11 and deprecated with c++17.
108-
// Revert to C99 code since there no replacement yet
109-
wstrTo.resize(str.length(), 0);
110-
auto nLen = mbstowcs(&wstrTo[0], str.c_str(), wstrTo.length());
111-
wstrTo.resize(nLen);
195+
wstrTo = utf8Toutf16(str);
112196
#else // c++11 to c++14
113197
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> utf8conv;
114198
try

0 commit comments

Comments
 (0)