diff --git a/clickhouse/base/socket.cpp b/clickhouse/base/socket.cpp index 7e08e06a..48e90c73 100644 --- a/clickhouse/base/socket.cpp +++ b/clickhouse/base/socket.cpp @@ -43,6 +43,21 @@ windowsErrorCategory const& windowsErrorCategory::category() { } #endif +#if defined(_unix_) +char const* getaddrinfoErrorCategory::name() const noexcept { + return "getaddrinfoError"; +} + +std::string getaddrinfoErrorCategory::message(int c) const { + return gai_strerror(c); +} + +getaddrinfoErrorCategory const& getaddrinfoErrorCategory::category() { + static getaddrinfoErrorCategory c; + return c; +} +#endif + namespace { class LocalNames : public std::unordered_set { @@ -265,6 +280,12 @@ NetworkAddress::NetworkAddress(const std::string& host, const std::string& port) const int error = getaddrinfo(host.c_str(), port.c_str(), &hints, &info_); +#if defined(_unix_) + if (error && error != EAI_SYSTEM) { + throw std::system_error(error, getaddrinfoErrorCategory::category()); + } +#endif + if (error) { throw std::system_error(getSocketErrorCode(), getErrorCategory()); } diff --git a/clickhouse/base/socket.h b/clickhouse/base/socket.h index 392fa824..694d0d69 100644 --- a/clickhouse/base/socket.h +++ b/clickhouse/base/socket.h @@ -60,6 +60,18 @@ class windowsErrorCategory : public std::error_category { #endif +#if defined(_unix_) + +class getaddrinfoErrorCategory : public std::error_category { +public: + char const* name() const noexcept override final; + std::string message(int c) const override final; + + static getaddrinfoErrorCategory const& category(); +}; + +#endif + class SocketBase { public: diff --git a/ut/socket_ut.cpp b/ut/socket_ut.cpp index 3ac1210f..ee531544 100644 --- a/ut/socket_ut.cpp +++ b/ut/socket_ut.cpp @@ -8,6 +8,13 @@ #include #include +// for EAI_* error codes +#if defined(_win_) +# include +#else +# include +#endif + using namespace clickhouse; TEST(Socketcase, connecterror) { @@ -63,6 +70,15 @@ TEST(Socketcase, timeoutrecv) { server.stop(); } +TEST(Socketcase, gaierror) { + try { + NetworkAddress addr("host.invalid", "80"); // never resolves + FAIL(); + } catch (const std::system_error& e) { + ASSERT_PRED1([](int error) { return error == EAI_NONAME || error == EAI_AGAIN || error == EAI_FAIL; }, e.code().value()); + } +} + TEST(Socketcase, connecttimeout) { using Clock = std::chrono::steady_clock;