Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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