Skip to content

Commit

Permalink
feat(shell): support resolve IP address in dsn/utility (#337)
Browse files Browse the repository at this point in the history
  • Loading branch information
Smityz authored Nov 19, 2019
1 parent a15faf6 commit 7e3b042
Show file tree
Hide file tree
Showing 7 changed files with 310 additions and 146 deletions.
24 changes: 4 additions & 20 deletions include/dsn/dist/replication/replication_ddl_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,16 @@

#pragma once

#include <dsn/dist/replication.h>

#include <cctype>
#include <string>
#include <map>
#include <dsn/dist/replication.h>
#include <vector>

#include <dsn/tool-api/task_tracker.h>
#include <dsn/tool-api/async_calls.h>
#include <dsn/utility/errors.h>
#include <vector>

namespace dsn {
namespace replication {
Expand Down Expand Up @@ -117,24 +119,6 @@ class replication_ddl_client
change_dup_status(std::string app_name, int dupid, duplication_status::type status);
error_with<duplication_query_response> query_dup(std::string app_name);

// get host name from ip series
// if can't get a hostname from ip(maybe no hostname or other errors), return UNRESOLVABLE
// if multiple hostname got, return <host1,host2> ...
// we only support ipv4 currently

// ip_network_order -> hostname
static std::string hostname_from_ip(uint32_t ip);
// a.b.c.d -> hostname
static std::string hostname_from_ip(const char *ip);
// a.b.c.d:port1 -> hostname:port1
static std::string hostname_from_ip_port(const char *ip_port);
// ipv4_rpc_address -> hostname:port | non_ipv4 -> "invalid"
static std::string hostname(const dsn::rpc_address &address);
// a.b.c.d,e.f.g.h -> hostname1,hostname2
static std::string list_hostname_from_ip(const char *ip_list);
// a.b.c.d:port1,e.f.g.h:port2 -> hostname1:port2,hostname2:port2
static std::string list_hostname_from_ip_port(const char *ip_port_list);

dsn::error_code do_restore(const std::string &backup_provider_name,
const std::string &cluster_name,
const std::string &policy_name,
Expand Down
38 changes: 38 additions & 0 deletions include/dsn/utility/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <functional>
#include <memory>

#include <dsn/tool-api/rpc_address.h>
#include <dsn/utility/string_view.h>

#define TIME_MS_MAX 0xffffffff
Expand Down Expand Up @@ -77,5 +78,42 @@ int hh_mm_to_seconds(dsn::string_view hhmm);
// eg. `18:10` => `1525947000` when called on May 10, 2018, CST
// Return: -1 when invalid
int64_t hh_mm_today_to_unix_sec(string_view hhmm_of_day);

// get host name from ip series
// if can't get a hostname from ip(maybe no hostname or other errors), return false, and
// hostname_result will be invalid value
// if multiple hostname got and all of them are resolvable return true, otherwise return false.
// and the hostname_result will be "hostname1,hostname2(or ip_address or )..."
// we only support ipv4 currently
// check if a.b.c.d:port can be resolved to hostname:port. If it can be resolved, return true
// and hostname_result
// will be the hostname, or it will be ip address or error message

// valid a.b.c.d -> return TRUE && hostname_result=hostname | invalid a.b.c.d:port1 -> return
// FALSE
// && hostname_result=a.b.c.d
bool hostname_from_ip(const char *ip, std::string *hostname_result);

// valid a.b.c.d:port -> return TRUE && hostname_result=hostname:port | invalid a.b.c.d:port1
// ->
// return FALSE && hostname_result=a.b.c.d:port
bool hostname_from_ip_port(const char *ip_port, std::string *hostname_result);

// valid a.b.c.d,e.f.g.h -> return TRUE && hostname_result_list=hostname1,hostname2 | invalid
// a.b.c.d,e.f.g.h -> return TRUE && hostname_result_list=a.b.c.d,e.f.g.h
bool list_hostname_from_ip(const char *ip_port_list, std::string *hostname_result_list);

// valid a.b.c.d:port1,e.f.g.h:port2 -> return TRUE &&
// hostname_result_list=hostname1:port1,hostname2:port2 | invalid a.b.c.d:port1,e.f.g.h:port2 ->
// return TRUE && hostname_result_list=a.b.c.d:port1,e.f.g.h:port2
bool list_hostname_from_ip_port(const char *ip_port_list, std::string *hostname_result_list);

// valid_ipv4_rpc_address return TRUE && hostname_result=hostname:port | invalid_ipv4 -> return
// FALSE
bool hostname(const dsn::rpc_address &address, std::string *hostname_result);

// valid_ip_network_order -> return TRUE && hostname_result=hostname |
// invalid_ip_network_order -> return FALSE
bool hostname_from_ip(uint32_t ip, std::string *hostname_result);
}
}
148 changes: 141 additions & 7 deletions src/core/core/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,24 @@
*/

#include <dsn/utility/utils.h>
#include <dsn/utility/singleton.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <random>
#include <iostream>
#include <fstream>
#include <memory>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>

#include <array>
#include <chrono>
#include <fstream>
#include <iostream>
#include <memory>
#include <random>

#include <dsn/service_api_cpp.h>
#include <dsn/utility/singleton.h>
#include <sys/stat.h>
#include <sys/types.h>

#if defined(__linux__)
#include <sys/syscall.h>
Expand Down Expand Up @@ -140,5 +148,131 @@ int64_t hh_mm_today_to_unix_sec(string_view hhmm_of_day)

return get_unix_sec_today_midnight() + sec_of_day;
}
bool hostname_from_ip(uint32_t ip, std::string *hostname_result)
{
struct sockaddr_in addr_in;
addr_in.sin_family = AF_INET;
addr_in.sin_port = 0;
addr_in.sin_addr.s_addr = ip;
char hostname[256];
int err = getnameinfo((struct sockaddr *)(&addr_in),
sizeof(struct sockaddr),
hostname,
sizeof(hostname),
nullptr,
0,
NI_NAMEREQD);
if (err != 0) {
struct in_addr net_addr;
net_addr.s_addr = ip;
char ip_str[256];
inet_ntop(AF_INET, &net_addr, ip_str, sizeof(ip_str));
if (err == EAI_SYSTEM) {
dwarn("got error %s when try to resolve %s", strerror(errno), ip_str);
} else {
dwarn("return error(%s) when try to resolve %s", gai_strerror(err), ip_str);
}
return false;
} else {
*hostname_result = std::string(hostname);
return true;
}
}

bool hostname_from_ip(const char *ip, std::string *hostname_result)
{
uint32_t ip_addr;
if (inet_pton(AF_INET, ip, &ip_addr) != 1) {
// inet_pton() returns 1 on success (network address was successfully converted)
*hostname_result = ip;
return false;
}
if (!hostname_from_ip(ip_addr, hostname_result)) {
*hostname_result = ip;
return false;
}
return true;
}

bool hostname_from_ip_port(const char *ip_port, std::string *hostname_result)
{
dsn::rpc_address addr;
if (!addr.from_string_ipv4(ip_port)) {
dwarn("invalid ip_port(%s)", ip_port);
*hostname_result = ip_port;
return false;
}
if (!hostname(addr, hostname_result)) {
*hostname_result = ip_port;
return false;
}
return true;
}

bool hostname(const rpc_address &address, std::string *hostname_result)
{
if (address.type() != HOST_TYPE_IPV4) {
return false;
}
if (hostname_from_ip(htonl(address.ip()), hostname_result)) {
*hostname_result += ":" + std::to_string(address.port());
return true;
}
return false;
}

bool list_hostname_from_ip(const char *ip_list, std::string *hostname_result_list)
{
std::vector<std::string> splitted_ip;
dsn::utils::split_args(ip_list, splitted_ip, ',');

if (splitted_ip.empty()) {
dwarn("invalid ip_list(%s)", ip_list);
*hostname_result_list = *ip_list;
return false;
}

std::string temp;
std::stringstream result;
bool all_ok = true;
for (int i = 0; i < splitted_ip.size(); ++i) {
result << (i ? "," : "");
if (hostname_from_ip(splitted_ip[i].c_str(), &temp)) {
result << temp;
} else {
result << splitted_ip[i].c_str();
all_ok = false;
}
}
*hostname_result_list = result.str();
return all_ok;
}

bool list_hostname_from_ip_port(const char *ip_port_list, std::string *hostname_result_list)
{
std::vector<std::string> splitted_ip_port;
dsn::utils::split_args(ip_port_list, splitted_ip_port, ',');

if (splitted_ip_port.empty()) {
dwarn("invalid ip_list(%s)", ip_port_list);
*hostname_result_list = *ip_port_list;
return false;
}

std::string temp;
std::stringstream result;
bool all_ok = true;
for (int i = 0; i < splitted_ip_port.size(); ++i) {
result << (i ? "," : "");
if (hostname_from_ip_port(splitted_ip_port[i].c_str(), &temp)) {
result << temp;
} else {
result << splitted_ip_port[i].c_str();
all_ok = false;
}
}
*hostname_result_list = result.str();
return all_ok;
}
}
}
86 changes: 86 additions & 0 deletions src/core/tests/hostname.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) 2017-present, Xiaomi, Inc. All rights reserved.
// This source code is licensed under the Apache License Version 2.0, which
// can be found in the LICENSE file in the root directory of this source tree.

#include <dsn/utility/utils.h>

#include <dsn/tool-api/rpc_address.h>
#include <gtest/gtest.h>

namespace dsn {
namespace replication {

TEST(ip_to_hostname, localhost)
{
std::string hostname_result;

const std::string success_ip = "127.0.0.1";
const std::string expected_hostname = "localhost";

const std::string success_ip_port = "127.0.0.1:23010";
const std::string expected_hostname_port = "localhost:23010";

const std::string failed_ip = "123.456.789.111";
const std::string failed_ip_port = "123.456.789.111:23010";

const std::string success_ip_list = "127.0.0.1,127.0.0.1,127.0.0.1";
const std::string expected_hostname_list = "localhost,localhost,localhost";

const std::string success_ip_port_list = "127.0.0.1:8080,127.0.0.1:8080,127.0.0.1:8080";
const std::string expected_hostname_port_list = "localhost:8080,localhost:8080,localhost:8080";

rpc_address rpc_example_success, rpc_example_failed;
rpc_example_success.assign_ipv4(success_ip.c_str(), 23010);
rpc_example_failed.assign_ipv4(failed_ip.c_str(), 23010);

// static bool hostname(const rpc_address &address,std::string *hostname_result);
ASSERT_TRUE(dsn::utils::hostname(rpc_example_success, &hostname_result));
ASSERT_STREQ(expected_hostname_port.c_str(), hostname_result.c_str());

ASSERT_FALSE(dsn::utils::hostname(rpc_example_failed, &hostname_result));

// static bool hostname_from_ip(uint32_t ip, std::string* hostname_result);
ASSERT_TRUE(dsn::utils::hostname_from_ip(htonl(rpc_example_success.ip()), &hostname_result));
ASSERT_STREQ(expected_hostname.c_str(), hostname_result.c_str());

ASSERT_FALSE(dsn::utils::hostname_from_ip(htonl(rpc_example_failed.ip()), &hostname_result));

// static bool hostname_from_ip(const char *ip,std::string *hostname_result);
ASSERT_TRUE(dsn::utils::hostname_from_ip(success_ip.c_str(), &hostname_result));
ASSERT_STREQ(expected_hostname.c_str(), hostname_result.c_str());

ASSERT_FALSE(dsn::utils::hostname_from_ip(failed_ip.c_str(), &hostname_result));
ASSERT_STREQ(failed_ip.c_str(), hostname_result.c_str());

// static bool hostname_from_ip_port(const char *ip_port,std::string *hostname_result);
ASSERT_TRUE(dsn::utils::hostname_from_ip_port(success_ip_port.c_str(), &hostname_result));
ASSERT_STREQ(expected_hostname_port.c_str(), hostname_result.c_str());

ASSERT_FALSE(dsn::utils::hostname_from_ip_port(failed_ip_port.c_str(), &hostname_result));
ASSERT_STREQ(failed_ip_port.c_str(), hostname_result.c_str());

// static bool list_hostname_from_ip(const char *ip_port_list,std::string
// *hostname_result_list);
ASSERT_TRUE(dsn::utils::list_hostname_from_ip(success_ip_list.c_str(), &hostname_result));
ASSERT_STREQ(expected_hostname_list.c_str(), hostname_result.c_str());

ASSERT_FALSE(dsn::utils::list_hostname_from_ip("127.0.0.1,127.0.0.23323,111127.0.0.3",
&hostname_result));
ASSERT_STREQ("localhost,127.0.0.23323,111127.0.0.3", hostname_result.c_str());

ASSERT_FALSE(dsn::utils::list_hostname_from_ip("123.456.789.111,127.0.0.1", &hostname_result));
ASSERT_STREQ("123.456.789.111,localhost", hostname_result.c_str());

// static bool list_hostname_from_ip_port(const char *ip_port_list,std::string
// *hostname_result_list);
ASSERT_TRUE(
dsn::utils::list_hostname_from_ip_port(success_ip_port_list.c_str(), &hostname_result));
ASSERT_STREQ(expected_hostname_port_list.c_str(), hostname_result.c_str());

ASSERT_FALSE(dsn::utils::list_hostname_from_ip_port(
"127.0.3333.1:23456,1127.0.0.2:22233,127.0.0.1:8080", &hostname_result));
ASSERT_STREQ("127.0.3333.1:23456,1127.0.0.2:22233,localhost:8080", hostname_result.c_str());
}

} // namespace replication
} // namespace dsn
Loading

0 comments on commit 7e3b042

Please sign in to comment.