diff --git a/polaris/grpc/http2.cpp b/polaris/grpc/http2.cpp index 12bf7cf..1388807 100644 --- a/polaris/grpc/http2.cpp +++ b/polaris/grpc/http2.cpp @@ -16,9 +16,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -347,6 +349,45 @@ Http2Client::~Http2Client() { } } +// TryLookup 尝试进行 host 解析 +// step 1. 判断当前的 host 是否是域名 +// step 2. 不是域名,则直接返回 +// step 3. 是域名,进行一次域名解析,然后从返回的IPList中随机选取一个IP进行链接 +static std::string TryLookup(const std::string& address) { + GRPC_LOG(LOG_DEBUG, "try lookup address=[%s]", address.c_str()); + + std::string domain_reg = + "^[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\\.?$"; + re2::RE2 domain(domain_reg.c_str()); + bool is_domain = domain.ok() && re2::RE2::PartialMatch(address.c_str(), domain); + + // 使用正则表达式判断是否是域名, 不是域名,直接返回 address + if (!is_domain) { + return address; + } + + struct hostent* host = gethostbyname(address.c_str()); + if (!host) { + GRPC_LOG(LOG_ERROR, "try lookup address=[%s] error, maybe address is ip", address.c_str()); + return address; + } + + GRPC_LOG(LOG_DEBUG, "address=[%s] type: [%s]", address.c_str(), + (host->h_addrtype == AF_INET) ? "AF_INET" : "AF_INET6"); + + int total = sizeof(host->h_addr_list); + if (total < 1) { + return address; + } + + std::string target_address = inet_ntoa(*(struct in_addr*)host->h_addr_list[0]); + + GRPC_LOG(LOG_TRACE, "address=[%s] select one by random [%s]", address.c_str(), + target_address.c_str()); + + return target_address; +} + // 向指定地址发起非阻塞连接 static int TryConnectTo(const std::string& host, int port, int& fd) { if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { @@ -368,6 +409,7 @@ static int TryConnectTo(const std::string& host, int port, int& fd) { bzero(static_cast(&addr), sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_port = htons(port); + if (inet_pton(AF_INET, host.c_str(), &addr.sin_addr) != 1) { return -1; } @@ -375,23 +417,26 @@ static int TryConnectTo(const std::string& host, int port, int& fd) { } bool Http2Client::ConnectTo(const std::string& host, int port) { + std::string server_ip = TryLookup(host); + POLARIS_ASSERT(state_ == kConnectionInit); - GRPC_LOG(LOG_INFO, "try to nonblocking connect to server[%s:%d]", host.c_str(), port); + GRPC_LOG(LOG_INFO, "try to nonblocking connect to server[%s:%d]", server_ip.c_str(), port); int retcode = TryConnectTo(host, port, fd_); if (retcode == 0) { // 异步连接立即成功了,一般本地连接才有可能发生。 - GRPC_LOG(LOG_TRACE, "nonblocking connect to service[%s:%d] success immediately", host.c_str(), - port); + GRPC_LOG(LOG_TRACE, "nonblocking connect to service[%s:%d] success immediately", + server_ip.c_str(), port); state_ = kConnectionConnecting; // 即使立刻连接成功了也放在epoll写事件中去更新状态 } else if (errno == EINPROGRESS) { // tcp connect return -1 state_ = kConnectionConnecting; GRPC_LOG(LOG_TRACE, "nonblocking connect to server[%s:%d] with connection in progress", - host.c_str(), port); + server_ip.c_str(), port); retcode = 0; } else { state_ = kConnectionDisconnected; - GRPC_LOG(LOG_ERROR, "nonblocking connect to %s:%d with error: %d", host.c_str(), port, errno); + GRPC_LOG(LOG_ERROR, "nonblocking connect to %s:%d with error: %d", server_ip.c_str(), port, + errno); } - current_server_ = host + ":" + StringUtils::TypeToStr(port); + current_server_ = server_ip + ":" + StringUtils::TypeToStr(port); return retcode == 0; } diff --git a/test/grpc/domain_test.cpp b/test/grpc/domain_test.cpp new file mode 100644 index 0000000..2fd0632 --- /dev/null +++ b/test/grpc/domain_test.cpp @@ -0,0 +1,49 @@ +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use +// this file +// except in compliance with the License. You may obtain a copy of the License +// at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software +// distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific +// language governing permissions and limitations under the License. +// + +#include "grpc/buffer.h" + +#include +#include +#include +#include + +namespace polaris { +namespace grpc { + +class GrpcDomainTest : public ::testing::Test { +protected: + virtual void SetUp() {} + + virtual void TearDown() {} + +protected: +}; + +TEST_F(GrpcDomainTest, DomainJudge) { + std::string domain_reg = "^[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\\.?$"; + re2::RE2 regex_(domain_reg.c_str()); + ASSERT_TRUE((regex_).ok()); + std::string str_1 = "baidu.com"; + ASSERT_TRUE(re2::RE2::PartialMatch(str_1.c_str(), regex_)); + + std::string str_2 = "polaris.default.svc.local"; + ASSERT_TRUE(re2::RE2::PartialMatch(str_2.c_str(), regex_)); +} + +} // namespace grpc +} // namespace polaris \ No newline at end of file diff --git a/test/grpc/grpc_client_test.cpp b/test/grpc/grpc_client_test.cpp index fc7ab29..038530a 100644 --- a/test/grpc/grpc_client_test.cpp +++ b/test/grpc/grpc_client_test.cpp @@ -15,9 +15,9 @@ // language governing permissions and limitations under the License. // -#include "grpc/client.h" - #include +#include "grpc/client.h" +#include "grpc/http2.cpp" #include "mock/fake_net_server.h" #include "reactor/reactor.h"