Skip to content

Commit

Permalink
Merge pull request #27 from chuntaojun/main
Browse files Browse the repository at this point in the history
[ISSUE #28]: 支持域名解析
  • Loading branch information
lambdaliu authored Jun 20, 2022
2 parents 8cc3a6d + 2e54e95 commit 66f3357
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 8 deletions.
57 changes: 51 additions & 6 deletions polaris/grpc/http2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <poll.h>
#include <re2/re2.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
Expand Down Expand Up @@ -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) {
Expand All @@ -368,30 +409,34 @@ static int TryConnectTo(const std::string& host, int port, int& fd) {
bzero(static_cast<void*>(&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;
}
return connect(fd, (struct sockaddr*)&addr, sizeof(addr));
}

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<int>(port);
current_server_ = server_ip + ":" + StringUtils::TypeToStr<int>(port);
return retcode == 0;
}

Expand Down
49 changes: 49 additions & 0 deletions test/grpc/domain_test.cpp
Original file line number Diff line number Diff line change
@@ -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 <gtest/gtest.h>
#include <pthread.h>
#include <re2/re2.h>
#include <unistd.h>

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
4 changes: 2 additions & 2 deletions test/grpc/grpc_client_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
// language governing permissions and limitations under the License.
//

#include "grpc/client.h"

#include <gtest/gtest.h>
#include "grpc/client.h"
#include "grpc/http2.cpp"

#include "mock/fake_net_server.h"
#include "reactor/reactor.h"
Expand Down

0 comments on commit 66f3357

Please sign in to comment.