This is an automated email from the ASF dual-hosted git repository.

gehafearless pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pegasus.git


The following commit(s) were added to refs/heads/master by this push:
     new af256941f refactor(rpc_address): Simple refactor on rpc_address (#1897)
af256941f is described below

commit af256941f4062c77377d05d379ebd7f9b4a327ee
Author: Yingchun Lai <[email protected]>
AuthorDate: Thu Feb 22 14:02:59 2024 +0800

    refactor(rpc_address): Simple refactor on rpc_address (#1897)
    
    This patch is mainly refactor the rpc_address class.
    
    1.Remove the constructor rpc_address(const char *host, uint16_t port) and
    add a corresponding variants static rpc_address from_host_port(...).
    Because there is a DNS resolve procedure which may be slow, avoid to do it
    in constructor.
    2.New variants static rpc_address from_ip_port(...) are introduced to
    distinguish the input parameter is hostname or IPv4 address, it would be
    much faster if we know it's a IPv4 address.
    3.Remove std::string to_std_string(), void assign_ipv4*(...) and
    bool from_string_ipv4() because they're duplicate.
    4.Add operator bool() const for convenient use.
---
 src/client/replication_ddl_client.cpp              |  11 +-
 src/client/test/ddl_client_test.cpp                |   2 +-
 src/common/json_helper.h                           |   4 +-
 src/common/replication_common.cpp                  |  33 +--
 src/common/serialization_helper/thrift_helper.h    |   2 +-
 src/failure_detector/failure_detector.cpp          |   6 +-
 src/failure_detector/test/failure_detector.cpp     |  23 ++-
 src/meta/duplication/meta_duplication_service.cpp  |   6 +-
 src/meta/meta_http_service.cpp                     |  16 +-
 src/meta/meta_server_failure_detector.cpp          |  45 ++--
 src/meta/meta_service.cpp                          |   2 +-
 src/meta/partition_guardian.cpp                    |  13 +-
 src/meta/test/balancer_validator.cpp               |  13 +-
 src/meta/test/meta_backup_test.cpp                 |   6 +-
 src/meta/test/meta_bulk_load_ingestion_test.cpp    |  10 +-
 src/meta/test/meta_bulk_load_service_test.cpp      |   8 +-
 src/meta/test/meta_service_test.cpp                |   6 +-
 src/meta/test/meta_split_service_test.cpp          |   2 +-
 src/meta/test/misc/misc.cpp                        |   7 +-
 src/meta/test/misc/misc.h                          |   5 +-
 src/nfs/test/main.cpp                              |  97 ++++-----
 src/redis_protocol/proxy_ut/redis_proxy_test.cpp   |   4 +-
 .../bulk_load/test/replica_bulk_loader_test.cpp    |   6 +-
 src/replica/duplication/replica_follower.cpp       |   4 +-
 .../duplication/test/replica_follower_test.cpp     |   8 +-
 src/replica/split/test/replica_split_test.cpp      |   6 +-
 .../storage/simple_kv/simple_kv.app.example.h      |   3 +-
 src/replica/test/mock_utils.h                      |   5 +-
 src/replica/test/open_replica_test.cpp             |   5 +-
 src/runtime/rpc/asio_net_provider.cpp              |  14 +-
 src/runtime/rpc/network.cpp                        |  12 +-
 src/runtime/rpc/network.sim.cpp                    |   7 +-
 src/runtime/rpc/rpc_address.cpp                    | 226 ++++++++++++++-------
 src/runtime/rpc/rpc_address.h                      |  79 +++----
 src/runtime/rpc/rpc_holder.h                       |   2 +-
 src/runtime/rpc/rpc_host_port.cpp                  |  12 +-
 src/runtime/rpc/rpc_host_port.h                    |  13 +-
 src/runtime/test/address_test.cpp                  | 216 ++++++++++++++++++--
 src/runtime/test/async_call.cpp                    |   6 +-
 src/runtime/test/corrupt_message.cpp               |  10 +-
 src/runtime/test/host_port_test.cpp                |  16 +-
 src/runtime/test/lpc.cpp                           |   2 +-
 src/runtime/test/main.cpp                          |   2 +-
 src/runtime/test/netprovider.cpp                   |  12 +-
 src/runtime/test/rpc.cpp                           |  50 ++---
 src/runtime/test/rpc_holder_test.cpp               |   8 +-
 src/runtime/test/rpc_message.cpp                   |   4 +-
 src/runtime/test_utils.h                           |  10 +-
 src/security/test/client_negotiation_test.cpp      |   3 +-
 src/security/test/main.cpp                         |   2 +-
 src/security/test/meta_access_controller_test.cpp  |   3 +-
 src/security/test/negotiation_manager_test.cpp     |   8 +-
 .../test/replica_access_controller_test.cpp        |   3 +-
 src/security/test/server_negotiation_test.cpp      |   4 +-
 src/shell/command_utils.cpp                        |   3 +-
 src/shell/commands/node_management.cpp             |   6 +-
 src/shell/commands/rebalance.cpp                   |  13 +-
 src/shell/commands/recovery.cpp                    |  16 +-
 src/test/function_test/recovery/test_recovery.cpp  |   8 +-
 src/test/function_test/utils/global_env.cpp        |  15 +-
 src/test/function_test/utils/global_env.h          |   3 +-
 src/test/kill_test/kill_testor.cpp                 |   6 +-
 src/utils/errors.h                                 |   6 +
 src/utils/test/hostname_test.cpp                   |  31 +--
 src/utils/utils.cpp                                |   4 +-
 src/zookeeper/zookeeper_session.cpp                |   3 +-
 66 files changed, 692 insertions(+), 504 deletions(-)

diff --git a/src/client/replication_ddl_client.cpp 
b/src/client/replication_ddl_client.cpp
index a98dcbf8e..cbdb1ee92 100644
--- a/src/client/replication_ddl_client.cpp
+++ b/src/client/replication_ddl_client.cpp
@@ -535,7 +535,7 @@ dsn::error_code replication_ddl_client::list_nodes(const 
dsn::replication::node_
         status_str = status_str.substr(status_str.find("NS_") + 3);
         tmp_map.emplace(
             kv.first,
-            list_nodes_helper(host_name_resolve(resolve_ip, 
kv.first.to_std_string()), status_str));
+            list_nodes_helper(host_name_resolve(resolve_ip, 
kv.first.to_string()), status_str));
     }
 
     if (detailed) {
@@ -772,16 +772,15 @@ dsn::error_code replication_ddl_client::list_app(const 
std::string &app_name,
             std::stringstream oss;
             oss << replica_count << "/" << p.max_replica_count;
             tp_details.append_data(oss.str());
-            tp_details.append_data(
-                (p.primary.is_invalid() ? "-" : host_name_resolve(resolve_ip,
-                                                                  
p.primary.to_std_string())));
+            tp_details.append_data(p.primary ? host_name_resolve(resolve_ip, 
p.primary.to_string())
+                                             : "-");
             oss.str("");
             oss << "[";
             // TODO (yingchun) join
             for (int j = 0; j < p.secondaries.size(); j++) {
                 if (j != 0)
                     oss << ",";
-                oss << host_name_resolve(resolve_ip, 
p.secondaries[j].to_std_string());
+                oss << host_name_resolve(resolve_ip, 
p.secondaries[j].to_string());
                 node_stat[p.secondaries[j]].second++;
             }
             oss << "]";
@@ -796,7 +795,7 @@ dsn::error_code replication_ddl_client::list_app(const 
std::string &app_name,
         tp_nodes.add_column("secondary");
         tp_nodes.add_column("total");
         for (auto &kv : node_stat) {
-            tp_nodes.add_row(host_name_resolve(resolve_ip, 
kv.first.to_std_string()));
+            tp_nodes.add_row(host_name_resolve(resolve_ip, 
kv.first.to_string()));
             tp_nodes.append_data(kv.second.first);
             tp_nodes.append_data(kv.second.second);
             tp_nodes.append_data(kv.second.first + kv.second.second);
diff --git a/src/client/test/ddl_client_test.cpp 
b/src/client/test/ddl_client_test.cpp
index 1240caf9b..0659cf7b3 100644
--- a/src/client/test/ddl_client_test.cpp
+++ b/src/client/test/ddl_client_test.cpp
@@ -103,7 +103,7 @@ TEST(DDLClientTest, RetryMetaRequest)
          dsn::ERR_BUSY_CREATING},
     };
 
-    std::vector<rpc_address> meta_list = {{"127.0.0.1", 34601}};
+    const std::vector<rpc_address> meta_list = 
{rpc_address::from_ip_port("127.0.0.1", 34601)};
     auto req = std::make_shared<configuration_create_app_request>();
     for (const auto &test : tests) {
         fail::setup();
diff --git a/src/common/json_helper.h b/src/common/json_helper.h
index 72d982f2f..648928f7b 100644
--- a/src/common/json_helper.h
+++ b/src/common/json_helper.h
@@ -421,7 +421,9 @@ inline bool json_decode(const dsn::json::JsonObject &in, 
dsn::rpc_address &addre
     if (rpc_address_string == "invalid address") {
         return true;
     }
-    return address.from_string_ipv4(rpc_address_string.c_str());
+
+    address = dsn::rpc_address::from_host_port(rpc_address_string);
+    return !address.is_invalid();
 }
 
 // json serialization for rpc host_port, we use the string representation of a 
host_port
diff --git a/src/common/replication_common.cpp 
b/src/common/replication_common.cpp
index 93fbe2290..66f1eeb91 100644
--- a/src/common/replication_common.cpp
+++ b/src/common/replication_common.cpp
@@ -41,7 +41,6 @@
 #include "utils/filesystem.h"
 #include "utils/flags.h"
 #include "utils/fmt_logging.h"
-#include "utils/string_conv.h"
 #include "utils/strings.h"
 
 DSN_DEFINE_bool(replication, duplication_enabled, true, "is duplication 
enabled");
@@ -201,34 +200,18 @@ bool replica_helper::load_meta_servers(/*out*/ 
std::vector<dsn::rpc_address> &se
 {
     servers.clear();
     std::string server_list = dsn_config_get_value_string(section, key, "", 
"");
-    std::vector<std::string> lv;
-    ::dsn::utils::split_args(server_list.c_str(), lv, ',');
-    for (auto &s : lv) {
-        ::dsn::rpc_address addr;
-        std::vector<std::string> hostname_port;
-        uint32_t ip = 0;
-        utils::split_args(s.c_str(), hostname_port, ':');
-        CHECK_EQ_MSG(2,
-                     hostname_port.size(),
-                     "invalid address '{}' specified in config [{}].{}",
-                     s,
-                     section,
-                     key);
-        uint32_t port_num = 0;
-        CHECK(dsn::internal::buf2unsigned(hostname_port[1], port_num) && 
port_num < UINT16_MAX,
-              "invalid address '{}' specified in config [{}].{}",
-              s,
-              section,
-              key);
-        if (0 != (ip = 
::dsn::rpc_address::ipv4_from_host(hostname_port[0].c_str()))) {
-            addr.assign_ipv4(ip, static_cast<uint16_t>(port_num));
-        } else if (!addr.from_string_ipv4(s.c_str())) {
-            LOG_ERROR("invalid address '{}' specified in config [{}].{}", s, 
section, key);
+    std::vector<std::string> host_ports;
+    ::dsn::utils::split_args(server_list.c_str(), host_ports, ',');
+    for (const auto &host_port : host_ports) {
+        auto addr = dsn::rpc_address::from_host_port(host_port);
+        if (!addr) {
+            LOG_ERROR("invalid address '{}' specified in config [{}]{}", 
host_port, section, key);
             return false;
         }
-        // TODO(yingchun): check there is no duplicates
         servers.push_back(addr);
     }
+
+    // TODO(yingchun): check there is no duplicates
     if (servers.empty()) {
         LOG_ERROR("no meta server specified in config [{}].{}", section, key);
         return false;
diff --git a/src/common/serialization_helper/thrift_helper.h 
b/src/common/serialization_helper/thrift_helper.h
index 368a2bb27..c3e2bbfb0 100644
--- a/src/common/serialization_helper/thrift_helper.h
+++ b/src/common/serialization_helper/thrift_helper.h
@@ -237,7 +237,7 @@ inline uint32_t 
rpc_address::read(apache::thrift::protocol::TProtocol *iprot)
         xfer += iprot->readStructEnd();
 
         // currently only support ipv4 format
-        this->assign_ipv4(host.c_str(), port);
+        *this = from_host_port(host, static_cast<uint16_t>(port));
 
         return xfer;
     }
diff --git a/src/failure_detector/failure_detector.cpp 
b/src/failure_detector/failure_detector.cpp
index af264d21f..f76e3adc0 100644
--- a/src/failure_detector/failure_detector.cpp
+++ b/src/failure_detector/failure_detector.cpp
@@ -319,9 +319,9 @@ void failure_detector::set_allow_list(const 
std::vector<std::string> &replica_ad
     CHECK(!_is_started, "FD is already started, the allow list should really 
not be modified");
 
     std::vector<rpc_address> nodes;
-    for (auto &addr : replica_addrs) {
-        rpc_address node;
-        if (!node.from_string_ipv4(addr.c_str())) {
+    for (const auto &addr : replica_addrs) {
+        const auto node = dsn::rpc_address::from_host_port(addr);
+        if (!node) {
             LOG_WARNING("replica_white_list has invalid ip {}, the allow list 
won't be modified",
                         addr);
             return;
diff --git a/src/failure_detector/test/failure_detector.cpp 
b/src/failure_detector/test/failure_detector.cpp
index 1a726a82d..d2bc55f6a 100644
--- a/src/failure_detector/test/failure_detector.cpp
+++ b/src/failure_detector/test/failure_detector.cpp
@@ -189,7 +189,7 @@ public:
     {
         std::vector<rpc_address> master_group;
         for (int i = 0; i < 3; ++i)
-            master_group.push_back(rpc_address("localhost", MPORT_START + i));
+            master_group.push_back(rpc_address::from_host_port("localhost", 
MPORT_START + i));
         _worker_fd = new worker_fd_test(nullptr, master_group);
         _worker_fd->start(1, 1, 9, 10);
         ++started_apps;
@@ -235,8 +235,7 @@ public:
             std::vector<std::string> ports;
             utils::split_args(args[2].c_str(), ports, ',');
             for (auto &port : ports) {
-                rpc_address addr;
-                addr.assign_ipv4(network::get_local_ipv4(), std::stoi(port));
+                rpc_address addr(network::get_local_ipv4(), std::stoi(port));
                 _master_fd->add_allow_list(addr);
             }
             use_allow_list = true;
@@ -306,7 +305,8 @@ bool get_worker_and_master(test_worker *&worker, 
std::vector<test_master *> &mas
 
 void master_group_set_leader(std::vector<test_master *> &master_group, int 
leader_index)
 {
-    rpc_address leader_addr("localhost", MPORT_START + leader_index);
+    const auto leader_addr =
+        rpc_address::from_host_port("localhost", 
static_cast<uint16_t>(MPORT_START + leader_index));
     int i = 0;
     for (test_master *&master : master_group) {
         master->fd()->set_leader_for_test(leader_addr, leader_index == i);
@@ -316,15 +316,16 @@ void master_group_set_leader(std::vector<test_master *> 
&master_group, int leade
 
 void worker_set_leader(test_worker *worker, int leader_contact)
 {
-    worker->fd()->set_leader_for_test(rpc_address("localhost", MPORT_START + 
leader_contact));
+    worker->fd()->set_leader_for_test(
+        rpc_address::from_host_port("localhost", MPORT_START + 
leader_contact));
 
     config_master_message msg;
-    msg.master = rpc_address("localhost", MPORT_START + leader_contact);
+    msg.master = rpc_address::from_host_port("localhost", MPORT_START + 
leader_contact);
     msg.is_register = true;
     error_code err;
     bool response;
     std::tie(err, response) = rpc::call_wait<bool>(
-        rpc_address("localhost", WPORT), dsn::task_code(RPC_MASTER_CONFIG), 
msg);
+        rpc_address::from_host_port("localhost", WPORT), 
dsn::task_code(RPC_MASTER_CONFIG), msg);
     ASSERT_EQ(err, ERR_OK);
 }
 
@@ -338,7 +339,7 @@ void clear(test_worker *worker, std::vector<test_master *> 
masters)
     error_code err;
     bool response;
     std::tie(err, response) = rpc::call_wait<bool>(
-        rpc_address("localhost", WPORT), dsn::task_code(RPC_MASTER_CONFIG), 
msg);
+        rpc_address::from_host_port("localhost", WPORT), 
dsn::task_code(RPC_MASTER_CONFIG), msg);
     ASSERT_EQ(err, ERR_OK);
 
     worker->fd()->toggle_send_ping(false);
@@ -611,7 +612,7 @@ TEST(fd, worker_died_when_switch_master)
         });
 
     /* we assume the worker is alive */
-    tst_master->fd()->test_register_worker(rpc_address("localhost", WPORT));
+    
tst_master->fd()->test_register_worker(rpc_address::from_host_port("localhost", 
WPORT));
     master_group_set_leader(masters, index);
 
     /* then stop the worker*/
@@ -651,8 +652,8 @@ TEST(fd, update_stability)
 
     dsn::rpc_replier<beacon_ack> r(create_fake_rpc_response());
     beacon_msg msg;
-    msg.from_addr = rpc_address("localhost", 123);
-    msg.to_addr = rpc_address("localhost", MPORT_START);
+    msg.from_addr = rpc_address::from_host_port("localhost", 123);
+    msg.to_addr = rpc_address::from_host_port("localhost", MPORT_START);
     msg.time = dsn_now_ms();
     msg.__isset.start_time = true;
     msg.start_time = 1000;
diff --git a/src/meta/duplication/meta_duplication_service.cpp 
b/src/meta/duplication/meta_duplication_service.cpp
index 235cfdb94..e5cf61d0d 100644
--- a/src/meta/duplication/meta_duplication_service.cpp
+++ b/src/meta/duplication/meta_duplication_service.cpp
@@ -424,9 +424,9 @@ void 
meta_duplication_service::check_follower_app_if_create_completed(
                       int count = dup->partition_count;
                       while (count-- > 0) {
                           partition_configuration p;
-                          p.primary = rpc_address("127.0.0.1", 34801);
-                          p.secondaries.emplace_back(rpc_address("127.0.0.2", 
34801));
-                          p.secondaries.emplace_back(rpc_address("127.0.0.3", 
34801));
+                          p.primary = rpc_address::from_ip_port("127.0.0.1", 
34801);
+                          
p.secondaries.emplace_back(rpc_address::from_ip_port("127.0.0.2", 34801));
+                          
p.secondaries.emplace_back(rpc_address::from_ip_port("127.0.0.3", 34801));
                           resp.partitions.emplace_back(p);
                       }
                   });
diff --git a/src/meta/meta_http_service.cpp b/src/meta/meta_http_service.cpp
index 8ccbc8229..f93d869c3 100644
--- a/src/meta/meta_http_service.cpp
+++ b/src/meta/meta_http_service.cpp
@@ -158,13 +158,13 @@ void meta_http_service::get_app_handler(const 
http_request &req, http_response &
             std::stringstream oss;
             oss << replica_count << "/" << p.max_replica_count;
             tp_details.append_data(oss.str());
-            tp_details.append_data((p.primary.is_invalid() ? "-" : 
p.primary.to_std_string()));
+            tp_details.append_data((p.primary.is_invalid() ? "-" : 
p.primary.to_string()));
             oss.str("");
             oss << "[";
             for (int j = 0; j < p.secondaries.size(); j++) {
                 if (j != 0)
                     oss << ",";
-                oss << p.secondaries[j].to_std_string();
+                oss << p.secondaries[j];
                 node_stat[p.secondaries[j]].second++;
             }
             oss << "]";
@@ -179,7 +179,7 @@ void meta_http_service::get_app_handler(const http_request 
&req, http_response &
         tp_nodes.add_column("secondary");
         tp_nodes.add_column("total");
         for (auto &kv : node_stat) {
-            tp_nodes.add_row(kv.first.to_std_string());
+            tp_nodes.add_row(kv.first.to_string());
             tp_nodes.append_data(kv.second.first);
             tp_nodes.append_data(kv.second.second);
             tp_nodes.append_data(kv.second.first + kv.second.second);
@@ -386,10 +386,10 @@ void meta_http_service::list_node_handler(const 
http_request &req, http_response
 
     std::map<dsn::rpc_address, list_nodes_helper> tmp_map;
     for (const auto &node : _service->_alive_set) {
-        tmp_map.emplace(node, list_nodes_helper(node.to_std_string(), 
"ALIVE"));
+        tmp_map.emplace(node, list_nodes_helper(node.to_string(), "ALIVE"));
     }
     for (const auto &node : _service->_dead_set) {
-        tmp_map.emplace(node, list_nodes_helper(node.to_std_string(), 
"UNALIVE"));
+        tmp_map.emplace(node, list_nodes_helper(node.to_string(), "UNALIVE"));
     }
     int alive_node_count = (_service->_alive_set).size();
     int unalive_node_count = (_service->_dead_set).size();
@@ -469,13 +469,13 @@ void meta_http_service::get_cluster_info_handler(const 
http_request &req, http_r
     std::string meta_servers_str;
     int ms_size = _service->_opts.meta_servers.size();
     for (int i = 0; i < ms_size; i++) {
-        meta_servers_str += _service->_opts.meta_servers[i].to_std_string();
+        meta_servers_str += _service->_opts.meta_servers[i].to_string();
         if (i != ms_size - 1) {
             meta_servers_str += ",";
         }
     }
     tp.add_row_name_and_data("meta_servers", meta_servers_str);
-    tp.add_row_name_and_data("primary_meta_server", 
dsn_primary_address().to_std_string());
+    tp.add_row_name_and_data("primary_meta_server", 
dsn_primary_address().to_string());
     tp.add_row_name_and_data("zookeeper_hosts", FLAGS_hosts_list);
     tp.add_row_name_and_data("zookeeper_root", _service->_cluster_root);
     tp.add_row_name_and_data(
@@ -852,7 +852,7 @@ bool meta_http_service::redirect_if_not_primary(const 
http_request &req, http_re
     }
 
     // set redirect response
-    resp.location = "http://"; + leader.to_std_string() + '/' + req.path;
+    resp.location = fmt::format("http://{}/{}";, leader, req.path);
     if (!req.query_args.empty()) {
         resp.location += '?';
         for (const auto &i : req.query_args) {
diff --git a/src/meta/meta_server_failure_detector.cpp 
b/src/meta/meta_server_failure_detector.cpp
index 1d20912b3..36fa56818 100644
--- a/src/meta/meta_server_failure_detector.cpp
+++ b/src/meta/meta_server_failure_detector.cpp
@@ -111,9 +111,8 @@ bool meta_server_failure_detector::get_leader(rpc_address 
*leader)
         auto pos = str.find("#");
         // get leader addr
         auto addr_part = str.substr(pos + 1, str.length() - pos - 1);
-        if (!leader->from_string_ipv4(addr_part.data())) {
-            CHECK(false, "parse {} to rpc_address failed", addr_part);
-        }
+        *leader = dsn::rpc_address::from_host_port(addr_part);
+        CHECK(*leader, "parse {} to rpc_address failed", addr_part);
 
         // get the return value which implies whether the current node is 
primary or not
         bool is_leader = true;
@@ -132,21 +131,29 @@ bool meta_server_failure_detector::get_leader(rpc_address 
*leader)
     if (_is_leader.load()) {
         *leader = dsn_primary_address();
         return true;
-    } else if (_lock_svc == nullptr) {
+    }
+
+    if (_lock_svc == nullptr) {
         leader->set_invalid();
         return false;
-    } else {
-        std::string lock_owner;
-        uint64_t version;
-        error_code err = _lock_svc->query_cache(_primary_lock_id, lock_owner, 
version);
-        if (err == dsn::ERR_OK && 
leader->from_string_ipv4(lock_owner.c_str())) {
-            return (*leader) == dsn_primary_address();
-        } else {
-            LOG_WARNING("query leader from cache got error({})", err);
-            leader->set_invalid();
-            return false;
-        }
     }
+
+    std::string lock_owner;
+    uint64_t version;
+    error_code err = _lock_svc->query_cache(_primary_lock_id, lock_owner, 
version);
+    if (err != dsn::ERR_OK) {
+        LOG_WARNING("query leader from cache got error({})", err);
+        leader->set_invalid();
+        return false;
+    }
+
+    *leader = rpc_address::from_host_port(lock_owner);
+    if (!(*leader)) {
+        leader->set_invalid();
+        return false;
+    }
+
+    return (*leader) == dsn_primary_address();
 }
 
 DEFINE_TASK_CODE(LPC_META_SERVER_LEADER_LOCK_CALLBACK, TASK_PRIORITY_COMMON, 
fd::THREAD_POOL_FD)
@@ -160,7 +167,7 @@ void meta_server_failure_detector::acquire_leader_lock()
         error_code err;
         auto tasks = _lock_svc->lock(
             _primary_lock_id,
-            dsn_primary_address().to_std_string(),
+            dsn_primary_address().to_string(),
             // lock granted
             LPC_META_SERVER_LEADER_LOCK_CALLBACK,
             [this, &err](error_code ec, const std::string &owner, uint64_t 
version) {
@@ -217,10 +224,8 @@ void 
meta_server_failure_detector::reset_stability_stat(const rpc_address &node)
 
 void meta_server_failure_detector::leader_initialize(const std::string 
&lock_service_owner)
 {
-    dsn::rpc_address addr;
-    CHECK(addr.from_string_ipv4(lock_service_owner.c_str()),
-          "parse {} to rpc_address failed",
-          lock_service_owner);
+    const auto addr = rpc_address::from_host_port(lock_service_owner);
+    CHECK(addr, "parse {} to rpc_address failed", lock_service_owner);
     CHECK_EQ_MSG(addr, dsn_primary_address(), "acquire leader return success, 
but owner not match");
     _is_leader.store(true);
     _election_moment.store(dsn_now_ms());
diff --git a/src/meta/meta_service.cpp b/src/meta/meta_service.cpp
index d5ef94280..3f556a4cf 100644
--- a/src/meta/meta_service.cpp
+++ b/src/meta/meta_service.cpp
@@ -726,7 +726,7 @@ void 
meta_service::on_query_cluster_info(configuration_cluster_info_rpc rpc)
 
     response.values.push_back(oss.str());
     response.keys.push_back("primary_meta_server");
-    response.values.push_back(dsn_primary_address().to_std_string());
+    response.values.push_back(dsn_primary_address().to_string());
     response.keys.push_back("zookeeper_hosts");
     response.values.push_back(FLAGS_hosts_list);
     response.keys.push_back("zookeeper_root");
diff --git a/src/meta/partition_guardian.cpp b/src/meta/partition_guardian.cpp
index fdc531fcc..92a4c167d 100644
--- a/src/meta/partition_guardian.cpp
+++ b/src/meta/partition_guardian.cpp
@@ -17,6 +17,7 @@
 
 #include "meta/partition_guardian.h"
 
+#include <fmt/core.h>
 // IWYU pragma: no_include <ext/alloc_traits.h>
 #include <inttypes.h>
 #include <stdio.h>
@@ -360,8 +361,8 @@ pc_status partition_guardian::on_missing_primary(meta_view 
&view, const dsn::gpi
                 node_state *ns = get_node_state(*view.nodes, nodes[i], false);
                 if (ns == nullptr || !ns->alive()) {
                     ready = false;
-                    reason = "the last dropped node(" + 
nodes[i].to_std_string() +
-                             ") haven't come back yet";
+                    reason =
+                        fmt::format("the last dropped node({}) hasn't come 
back yet", nodes[i]);
                     LOG_WARNING("{}: don't select primary: {}", gpid_name, 
reason);
                 } else {
                     std::vector<dropped_replica>::iterator it = 
cc.find_from_dropped(nodes[i]);
@@ -374,8 +375,8 @@ pc_status partition_guardian::on_missing_primary(meta_view 
&view, const dsn::gpi
                             collected_info[i] = {nodes[i], 0, -1, -1, -1};
                         } else {
                             ready = false;
-                            reason = "the last dropped node(" + 
nodes[i].to_std_string() +
-                                     ") is unavailable because ";
+                            reason = fmt::format(
+                                "the last dropped node({}) is unavailable 
because ", nodes[i]);
                             if (it == cc.dropped.end()) {
                                 reason += "the node is not exist in 
dropped_nodes";
                             } else {
@@ -739,8 +740,8 @@ partition_guardian::ctrl_assign_secondary_black_list(const 
std::vector<std::stri
 
     std::set<dsn::rpc_address> addr_list;
     for (const std::string &s : ip_ports) {
-        dsn::rpc_address addr;
-        if (!addr.from_string_ipv4(s.c_str())) {
+        const auto addr = rpc_address::from_host_port(s);
+        if (!addr) {
             return invalid_arguments;
         }
         addr_list.insert(addr);
diff --git a/src/meta/test/balancer_validator.cpp 
b/src/meta/test/balancer_validator.cpp
index 8e1d45654..81091c6be 100644
--- a/src/meta/test/balancer_validator.cpp
+++ b/src/meta/test/balancer_validator.cpp
@@ -172,13 +172,6 @@ void meta_service_test_app::balancer_validator()
     check_cure(apps, nodes, pc);
 }
 
-dsn::rpc_address get_rpc_address(const std::string &ip_port)
-{
-    int splitter = ip_port.find_first_of(':');
-    return rpc_address(ip_port.substr(0, splitter).c_str(),
-                       boost::lexical_cast<int>(ip_port.substr(splitter + 1)));
-}
-
 static void load_apps_and_nodes(const char *file, app_mapper &apps, 
node_mapper &nodes)
 {
     apps.clear();
@@ -192,7 +185,7 @@ static void load_apps_and_nodes(const char *file, 
app_mapper &apps, node_mapper
     std::vector<dsn::rpc_address> node_list;
     for (int i = 0; i < total_nodes; ++i) {
         infile >> ip_port;
-        node_list.push_back(get_rpc_address(ip_port));
+        node_list.push_back(rpc_address::from_ip_port(ip_port));
     }
 
     int total_apps;
@@ -212,10 +205,10 @@ static void load_apps_and_nodes(const char *file, 
app_mapper &apps, node_mapper
             int n;
             infile >> n;
             infile >> ip_port;
-            app->partitions[j].primary = get_rpc_address(ip_port);
+            app->partitions[j].primary = rpc_address::from_ip_port(ip_port);
             for (int k = 1; k < n; ++k) {
                 infile >> ip_port;
-                
app->partitions[j].secondaries.push_back(get_rpc_address(ip_port));
+                
app->partitions[j].secondaries.push_back(rpc_address::from_ip_port(ip_port));
             }
         }
     }
diff --git a/src/meta/test/meta_backup_test.cpp 
b/src/meta/test/meta_backup_test.cpp
index da74bc7bf..3fdf84c5f 100644
--- a/src/meta/test/meta_backup_test.cpp
+++ b/src/meta/test/meta_backup_test.cpp
@@ -250,7 +250,8 @@ public:
                               int32_t progress)
     {
         gpid pid = gpid(_app_id, partition_index);
-        rpc_address mock_primary_address = rpc_address("127.0.0.1", 10000 + 
partition_index);
+        const auto mock_primary_address =
+            rpc_address::from_ip_port("127.0.0.1", 10000 + partition_index);
 
         backup_response resp;
         resp.backup_id = _backup_engine->_cur_backup.backup_id;
@@ -264,7 +265,8 @@ public:
     void mock_on_backup_reply_when_timeout(int32_t partition_index, error_code 
rpc_err)
     {
         gpid pid = gpid(_app_id, partition_index);
-        rpc_address mock_primary_address = rpc_address("127.0.0.1", 10000 + 
partition_index);
+        const auto mock_primary_address =
+            rpc_address::from_ip_port("127.0.0.1", 10000 + partition_index);
         backup_response resp;
         _backup_engine->on_backup_reply(rpc_err, resp, pid, 
mock_primary_address);
     }
diff --git a/src/meta/test/meta_bulk_load_ingestion_test.cpp 
b/src/meta/test/meta_bulk_load_ingestion_test.cpp
index 73bb93ae6..41a9db01b 100644
--- a/src/meta/test/meta_bulk_load_ingestion_test.cpp
+++ b/src/meta/test/meta_bulk_load_ingestion_test.cpp
@@ -88,7 +88,7 @@ public:
 
 public:
     ingestion_context::node_context _context;
-    const rpc_address NODE = rpc_address("127.0.0.1", 10086);
+    const rpc_address NODE = rpc_address::from_ip_port("127.0.0.1", 10086);
     const std::string TAG = "default";
     const std::string TAG2 = "tag2";
 };
@@ -313,10 +313,10 @@ public:
     const uint32_t PARTITION_COUNT = 4;
     const uint32_t MAX_NODE_COUNT = 2;
     const uint32_t MIN_DISK_COUNT = 2;
-    const rpc_address NODE1 = rpc_address("127.0.0.1", 10086);
-    const rpc_address NODE2 = rpc_address("127.0.0.1", 10085);
-    const rpc_address NODE3 = rpc_address("127.0.0.1", 10087);
-    const rpc_address NODE4 = rpc_address("127.0.0.1", 10088);
+    const rpc_address NODE1 = rpc_address::from_ip_port("127.0.0.1", 10086);
+    const rpc_address NODE2 = rpc_address::from_ip_port("127.0.0.1", 10085);
+    const rpc_address NODE3 = rpc_address::from_ip_port("127.0.0.1", 10087);
+    const rpc_address NODE4 = rpc_address::from_ip_port("127.0.0.1", 10088);
     const std::string TAG1 = "tag1";
     const std::string TAG2 = "tag2";
 };
diff --git a/src/meta/test/meta_bulk_load_service_test.cpp 
b/src/meta/test/meta_bulk_load_service_test.cpp
index d3ae38a1e..41f84f866 100644
--- a/src/meta/test/meta_bulk_load_service_test.cpp
+++ b/src/meta/test/meta_bulk_load_service_test.cpp
@@ -502,10 +502,10 @@ public:
     std::string PROVIDER = "local_service";
     std::string ROOT_PATH = "bulk_load_root";
     int64_t BALLOT = 4;
-    const rpc_address PRIMARY = rpc_address("127.0.0.1", 10086);
-    const rpc_address SECONDARY1 = rpc_address("127.0.0.1", 10085);
-    const rpc_address SECONDARY2 = rpc_address("127.0.0.1", 10087);
-    const rpc_address SECONDARY3 = rpc_address("127.0.0.1", 10080);
+    const rpc_address PRIMARY = rpc_address::from_ip_port("127.0.0.1", 10086);
+    const rpc_address SECONDARY1 = rpc_address::from_ip_port("127.0.0.1", 
10085);
+    const rpc_address SECONDARY2 = rpc_address::from_ip_port("127.0.0.1", 
10087);
+    const rpc_address SECONDARY3 = rpc_address::from_ip_port("127.0.0.1", 
10080);
 };
 
 /// start bulk load unit tests
diff --git a/src/meta/test/meta_service_test.cpp 
b/src/meta/test/meta_service_test.cpp
index 44fc1ea62..8e4752517 100644
--- a/src/meta/test/meta_service_test.cpp
+++ b/src/meta/test/meta_service_test.cpp
@@ -54,7 +54,7 @@ public:
             rpc.dsn_request()->header->context.u.is_forward_supported = false;
             ASSERT_FALSE(_ms->check_status_and_authz(rpc, &leader));
             ASSERT_EQ(ERR_FORWARD_TO_OTHERS, rpc.response().err);
-            ASSERT_EQ(leader.to_std_string(), "1.2.3.4:10086");
+            ASSERT_STREQ("1.2.3.4:10086", leader.to_string());
             ASSERT_EQ(app_env_rpc::forward_mail_box().size(), 0);
         }
 
@@ -64,8 +64,8 @@ public:
             auto rpc = create_fake_rpc();
             ASSERT_FALSE(_ms->check_status_and_authz(rpc));
             ASSERT_EQ(app_env_rpc::forward_mail_box().size(), 1);
-            
ASSERT_EQ(app_env_rpc::forward_mail_box()[0].remote_address().to_std_string(),
-                      "1.2.3.4:10086");
+            ASSERT_STREQ("1.2.3.4:10086",
+                         
app_env_rpc::forward_mail_box()[0].remote_address().to_string());
         }
 
         fail::teardown();
diff --git a/src/meta/test/meta_split_service_test.cpp 
b/src/meta/test/meta_split_service_test.cpp
index 12cb81e20..07d0210b7 100644
--- a/src/meta/test/meta_split_service_test.cpp
+++ b/src/meta/test/meta_split_service_test.cpp
@@ -377,7 +377,7 @@ public:
     const int32_t PARENT_BALLOT = 3;
     const int32_t PARENT_INDEX = 0;
     const int32_t CHILD_INDEX = 4;
-    const rpc_address NODE = rpc_address("127.0.0.1", 10086);
+    const rpc_address NODE = rpc_address::from_ip_port("127.0.0.1", 10086);
     std::shared_ptr<app_state> app;
 };
 
diff --git a/src/meta/test/misc/misc.cpp b/src/meta/test/misc/misc.cpp
index 500c7aaf1..11570913a 100644
--- a/src/meta/test/misc/misc.cpp
+++ b/src/meta/test/misc/misc.cpp
@@ -60,10 +60,11 @@ uint32_t random32(uint32_t min, uint32_t max)
 
 void generate_node_list(std::vector<dsn::rpc_address> &output_list, int 
min_count, int max_count)
 {
-    int count = random32(min_count, max_count);
+    const auto count = random32(min_count, max_count);
     output_list.resize(count);
-    for (int i = 0; i < count; ++i)
-        output_list[i].assign_ipv4("127.0.0.1", i + 1);
+    for (auto i = 0; i < count; ++i) {
+        output_list[i] = dsn::rpc_address::from_ip_port("127.0.0.1", i + 1);
+    }
 }
 
 void verbose_apps(const app_mapper &input_apps)
diff --git a/src/meta/test/misc/misc.h b/src/meta/test/misc/misc.h
index 8fef86fe6..15643fbc5 100644
--- a/src/meta/test/misc/misc.h
+++ b/src/meta/test/misc/misc.h
@@ -26,6 +26,7 @@
 
 #pragma once
 
+// IWYU pragma: no_include <ext/alloc_traits.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <algorithm>
@@ -40,6 +41,7 @@
 
 namespace dsn {
 class gpid;
+
 namespace replication {
 class configuration_proposal_action;
 class fs_manager;
@@ -72,7 +74,8 @@ inline std::vector<dsn::rpc_address> 
generate_node_list(size_t size, int start_p
     std::vector<dsn::rpc_address> result;
     result.resize(size);
     for (int i = 0; i < size; ++i)
-        result[i].assign_ipv4("127.0.0.1", static_cast<uint16_t>(start_port + 
i + 1));
+        result[i] =
+            dsn::rpc_address::from_ip_port("127.0.0.1", 
static_cast<uint16_t>(start_port + i + 1));
     return result;
 }
 
diff --git a/src/nfs/test/main.cpp b/src/nfs/test/main.cpp
index c66501624..2994345e8 100644
--- a/src/nfs/test/main.cpp
+++ b/src/nfs/test/main.cpp
@@ -109,22 +109,23 @@ TEST_P(nfs_test, basic)
         ASSERT_TRUE(dst_filenames.empty());
 
         aio_result r;
-        dsn::aio_task_ptr t = 
nfs->copy_remote_files(dsn::rpc_address("localhost", 20101),
-                                                     "default",
-                                                     ".",
-                                                     kSrcFilenames,
-                                                     "default",
-                                                     kDstDir,
-                                                     fake_pid,
-                                                     false,
-                                                     false,
-                                                     LPC_AIO_TEST_NFS,
-                                                     nullptr,
-                                                     [&r](dsn::error_code err, 
size_t sz) {
-                                                         r.err = err;
-                                                         r.sz = sz;
-                                                     },
-                                                     0);
+        dsn::aio_task_ptr t =
+            
nfs->copy_remote_files(dsn::rpc_address::from_host_port("localhost", 20101),
+                                   "default",
+                                   ".",
+                                   kSrcFilenames,
+                                   "default",
+                                   kDstDir,
+                                   fake_pid,
+                                   false,
+                                   false,
+                                   LPC_AIO_TEST_NFS,
+                                   nullptr,
+                                   [&r](dsn::error_code err, size_t sz) {
+                                       r.err = err;
+                                       r.sz = sz;
+                                   },
+                                   0);
         ASSERT_NE(nullptr, t);
         ASSERT_TRUE(t->wait(20000));
         ASSERT_EQ(r.err, t->error());
@@ -151,22 +152,23 @@ TEST_P(nfs_test, basic)
     // copy files to the destination directory, files will be overwritten.
     {
         aio_result r;
-        dsn::aio_task_ptr t = 
nfs->copy_remote_files(dsn::rpc_address("localhost", 20101),
-                                                     "default",
-                                                     ".",
-                                                     kSrcFilenames,
-                                                     "default",
-                                                     kDstDir,
-                                                     fake_pid,
-                                                     true,
-                                                     false,
-                                                     LPC_AIO_TEST_NFS,
-                                                     nullptr,
-                                                     [&r](dsn::error_code err, 
size_t sz) {
-                                                         r.err = err;
-                                                         r.sz = sz;
-                                                     },
-                                                     0);
+        dsn::aio_task_ptr t =
+            
nfs->copy_remote_files(dsn::rpc_address::from_host_port("localhost", 20101),
+                                   "default",
+                                   ".",
+                                   kSrcFilenames,
+                                   "default",
+                                   kDstDir,
+                                   fake_pid,
+                                   true,
+                                   false,
+                                   LPC_AIO_TEST_NFS,
+                                   nullptr,
+                                   [&r](dsn::error_code err, size_t sz) {
+                                       r.err = err;
+                                       r.sz = sz;
+                                   },
+                                   0);
         ASSERT_NE(nullptr, t);
         ASSERT_TRUE(t->wait(20000));
         ASSERT_EQ(r.err, t->error());
@@ -203,21 +205,22 @@ TEST_P(nfs_test, basic)
         ASSERT_FALSE(utils::filesystem::directory_exists(kNewDstDir));
 
         aio_result r;
-        dsn::aio_task_ptr t = 
nfs->copy_remote_directory(dsn::rpc_address("localhost", 20101),
-                                                         "default",
-                                                         kDstDir,
-                                                         "default",
-                                                         kNewDstDir,
-                                                         fake_pid,
-                                                         false,
-                                                         false,
-                                                         LPC_AIO_TEST_NFS,
-                                                         nullptr,
-                                                         [&r](dsn::error_code 
err, size_t sz) {
-                                                             r.err = err;
-                                                             r.sz = sz;
-                                                         },
-                                                         0);
+        dsn::aio_task_ptr t =
+            
nfs->copy_remote_directory(dsn::rpc_address::from_host_port("localhost", 20101),
+                                       "default",
+                                       kDstDir,
+                                       "default",
+                                       kNewDstDir,
+                                       fake_pid,
+                                       false,
+                                       false,
+                                       LPC_AIO_TEST_NFS,
+                                       nullptr,
+                                       [&r](dsn::error_code err, size_t sz) {
+                                           r.err = err;
+                                           r.sz = sz;
+                                       },
+                                       0);
         ASSERT_NE(nullptr, t);
         ASSERT_TRUE(t->wait(20000));
         ASSERT_EQ(r.err, t->error());
diff --git a/src/redis_protocol/proxy_ut/redis_proxy_test.cpp 
b/src/redis_protocol/proxy_ut/redis_proxy_test.cpp
index 2b76fd6e9..5d88285c1 100644
--- a/src/redis_protocol/proxy_ut/redis_proxy_test.cpp
+++ b/src/redis_protocol/proxy_ut/redis_proxy_test.cpp
@@ -187,7 +187,7 @@ public:
     {
         dsn::message_ex *msg = dsn::message_ex::create_received_request(
             RPC_CALL_RAW_MESSAGE, dsn::DSF_THRIFT_BINARY, nullptr, 0);
-        msg->header->from_address = dsn::rpc_address("127.0.0.1", 123);
+        msg->header->from_address = 
dsn::rpc_address::from_ip_port("127.0.0.1", 123);
         _parser.reset(new redis_test_parser(nullptr, msg));
     }
 
@@ -528,7 +528,7 @@ TEST_F(proxy_test, test_parse_parameters)
 
 TEST(proxy, connection)
 {
-    ::dsn::rpc_address redis_address("127.0.0.1", 12345);
+    const auto redis_address = dsn::rpc_address::from_ip_port("127.0.0.1", 
12345);
     ip::tcp::endpoint redis_endpoint(ip::address_v4(redis_address.ip()), 
redis_address.port());
 
     io_service ios;
diff --git a/src/replica/bulk_load/test/replica_bulk_loader_test.cpp 
b/src/replica/bulk_load/test/replica_bulk_loader_test.cpp
index 94a80bfb8..a0c963a57 100644
--- a/src/replica/bulk_load/test/replica_bulk_loader_test.cpp
+++ b/src/replica/bulk_load/test/replica_bulk_loader_test.cpp
@@ -410,9 +410,9 @@ public:
     std::string ROOT_PATH = "bulk_load_root";
     gpid PID = gpid(1, 0);
     ballot BALLOT = 3;
-    rpc_address PRIMARY = rpc_address("127.0.0.2", 34801);
-    rpc_address SECONDARY = rpc_address("127.0.0.3", 34801);
-    rpc_address SECONDARY2 = rpc_address("127.0.0.4", 34801);
+    rpc_address PRIMARY = rpc_address::from_ip_port("127.0.0.2", 34801);
+    rpc_address SECONDARY = rpc_address::from_ip_port("127.0.0.3", 34801);
+    rpc_address SECONDARY2 = rpc_address::from_ip_port("127.0.0.4", 34801);
     int32_t MAX_DOWNLOADING_COUNT = 5;
     std::string LOCAL_DIR = bulk_load_constant::BULK_LOAD_LOCAL_ROOT_DIR;
     std::string METADATA = bulk_load_constant::BULK_LOAD_METADATA;
diff --git a/src/replica/duplication/replica_follower.cpp 
b/src/replica/duplication/replica_follower.cpp
index 10a09c783..636dd1aec 100644
--- a/src/replica/duplication/replica_follower.cpp
+++ b/src/replica/duplication/replica_follower.cpp
@@ -73,8 +73,8 @@ void replica_follower::init_master_info()
     dsn::utils::split_args(meta_list_str.c_str(), metas, ',');
     CHECK(!metas.empty(), "master cluster meta list is invalid!");
     for (const auto &meta : metas) {
-        dsn::rpc_address node;
-        CHECK(node.from_string_ipv4(meta.c_str()), "{} is invalid meta 
address", meta);
+        const auto node = rpc_address::from_host_port(meta);
+        CHECK(node, "{} is invalid meta address", meta);
         _master_meta_list.emplace_back(std::move(node));
     }
 }
diff --git a/src/replica/duplication/test/replica_follower_test.cpp 
b/src/replica/duplication/test/replica_follower_test.cpp
index e952f115b..211a4d722 100644
--- a/src/replica/duplication/test/replica_follower_test.cpp
+++ b/src/replica/duplication/test/replica_follower_test.cpp
@@ -219,9 +219,9 @@ TEST_P(replica_follower_test, 
test_update_master_replica_config)
 
     resp.partitions.clear();
     p.pid = gpid(2, 1);
-    p.primary = rpc_address("127.0.0.1", 34801);
-    p.secondaries.emplace_back(rpc_address("127.0.0.2", 34801));
-    p.secondaries.emplace_back(rpc_address("127.0.0.3", 34801));
+    p.primary = rpc_address::from_ip_port("127.0.0.1", 34801);
+    p.secondaries.emplace_back(rpc_address::from_ip_port("127.0.0.2", 34801));
+    p.secondaries.emplace_back(rpc_address::from_ip_port("127.0.0.3", 34801));
     resp.partitions.emplace_back(p);
     ASSERT_EQ(update_master_replica_config(follower, resp), ERR_OK);
     ASSERT_EQ(master_replica_config(follower).primary, p.primary);
@@ -240,7 +240,7 @@ TEST_P(replica_follower_test, test_nfs_copy_checkpoint)
     ASSERT_EQ(nfs_copy_checkpoint(follower, ERR_CORRUPTION, learn_response()), 
ERR_CORRUPTION);
 
     auto resp = learn_response();
-    resp.address = rpc_address("127.0.0.1", 34801);
+    resp.address = rpc_address::from_ip_port("127.0.0.1", 34801);
 
     std::string dest = utils::filesystem::path_combine(
         _mock_replica->dir(), 
duplication_constants::kDuplicationCheckpointRootDir);
diff --git a/src/replica/split/test/replica_split_test.cpp 
b/src/replica/split/test/replica_split_test.cpp
index 4d7acae74..ddc455f13 100644
--- a/src/replica/split/test/replica_split_test.cpp
+++ b/src/replica/split/test/replica_split_test.cpp
@@ -525,9 +525,9 @@ public:
     const int32_t APP_ID = 2;
     const int32_t OLD_PARTITION_COUNT = 8;
     const int32_t NEW_PARTITION_COUNT = 16;
-    const rpc_address PRIMARY = rpc_address("127.0.0.1", 18230);
-    const rpc_address SECONDARY = rpc_address("127.0.0.2", 10058);
-    const rpc_address SECONDARY2 = rpc_address("127.0.0.3", 10805);
+    const rpc_address PRIMARY = rpc_address::from_ip_port("127.0.0.1", 18230);
+    const rpc_address SECONDARY = rpc_address::from_ip_port("127.0.0.2", 
10058);
+    const rpc_address SECONDARY2 = rpc_address::from_ip_port("127.0.0.3", 
10805);
     const gpid PARENT_GPID = gpid(APP_ID, 1);
     const gpid CHILD_GPID = gpid(APP_ID, 9);
     const ballot INIT_BALLOT = 3;
diff --git a/src/replica/storage/simple_kv/simple_kv.app.example.h 
b/src/replica/storage/simple_kv/simple_kv.app.example.h
index ade5b496c..5c6c1f0e5 100644
--- a/src/replica/storage/simple_kv/simple_kv.app.example.h
+++ b/src/replica/storage/simple_kv/simple_kv.app.example.h
@@ -45,8 +45,7 @@ public:
             return ::dsn::ERR_INVALID_PARAMETERS;
 
         printf("%s %s %s\n", args[1].c_str(), args[2].c_str(), 
args[3].c_str());
-        dsn::rpc_address meta;
-        meta.from_string_ipv4(args[2].c_str());
+        const auto meta = rpc_address::from_host_port(args[2]);
         _simple_kv_client.reset(new simple_kv_client(args[1].c_str(), {meta}, 
args[3].c_str()));
 
         _timer = ::dsn::tasking::enqueue_timer(LPC_SIMPLE_KV_TEST_TIMER,
diff --git a/src/replica/test/mock_utils.h b/src/replica/test/mock_utils.h
index 878df2559..7a051813b 100644
--- a/src/replica/test/mock_utils.h
+++ b/src/replica/test/mock_utils.h
@@ -275,7 +275,10 @@ public:
 
     void set_state_connected() { _state = replica_node_state::NS_Connected; }
 
-    rpc_address get_meta_server_address() const override { return 
rpc_address("127.0.0.2", 12321); }
+    rpc_address get_meta_server_address() const override
+    {
+        return rpc_address::from_ip_port("127.0.0.2", 12321);
+    }
 
     std::map<gpid, mock_replica *> mock_replicas;
 
diff --git a/src/replica/test/open_replica_test.cpp 
b/src/replica/test/open_replica_test.cpp
index 2c0d63984..626bb9541 100644
--- a/src/replica/test/open_replica_test.cpp
+++ b/src/replica/test/open_replica_test.cpp
@@ -60,13 +60,12 @@ TEST_P(open_replica_test, 
open_replica_add_decree_and_ballot_check)
         decree last_committed_decree;
         bool expect_crash;
     } tests[] = {{0, 0, false}, {5, 5, true}};
-    int i = 0;
+    uint16_t i = 0;
     for (auto test : tests) {
         gpid pid(ai.app_id, i);
         stub->_opening_replicas[pid] = task_ptr(nullptr);
 
-        dsn::rpc_address node;
-        node.assign_ipv4("127.0.0.11", static_cast<uint16_t>(12321 + i + 1));
+        const auto node = rpc_address::from_ip_port("127.0.0.11", 12321 + i + 
1);
 
         _replica->register_service();
 
diff --git a/src/runtime/rpc/asio_net_provider.cpp 
b/src/runtime/rpc/asio_net_provider.cpp
index 70f5d71da..74d3fcb31 100644
--- a/src/runtime/rpc/asio_net_provider.cpp
+++ b/src/runtime/rpc/asio_net_provider.cpp
@@ -145,7 +145,7 @@ error_code asio_network_provider::start(rpc_channel 
channel, int port, bool clie
           "invalid given channel {}",
           channel);
 
-    _address.assign_ipv4(get_local_ipv4(), port);
+    _address = rpc_address(get_local_ipv4(), port);
 
     if (!client_only) {
         auto v4_addr = boost::asio::ip::address_v4::any(); 
//(ntohl(_address.ip));
@@ -376,11 +376,11 @@ error_code asio_udp_provider::start(rpc_channel channel, 
int port, bool client_o
         do {
             // FIXME: we actually do not need to set a random port for client 
if the rpc_engine is
             // refactored
-            _address.assign_ipv4(get_local_ipv4(),
-                                 std::numeric_limits<uint16_t>::max() -
-                                     
rand::next_u64(std::numeric_limits<uint64_t>::min(),
-                                                    
std::numeric_limits<uint64_t>::max()) %
-                                         5000);
+            _address = rpc_address(get_local_ipv4(),
+                                   std::numeric_limits<uint16_t>::max() -
+                                       
rand::next_u64(std::numeric_limits<uint64_t>::min(),
+                                                      
std::numeric_limits<uint64_t>::max()) %
+                                           5000);
             ::boost::asio::ip::udp::endpoint 
endpoint(boost::asio::ip::address_v4::any(),
                                                       _address.port());
             boost::system::error_code ec;
@@ -402,7 +402,7 @@ error_code asio_udp_provider::start(rpc_channel channel, 
int port, bool client_o
             break;
         } while (true);
     } else {
-        _address.assign_ipv4(get_local_ipv4(), port);
+        _address = rpc_address(get_local_ipv4(), port);
         ::boost::asio::ip::udp::endpoint 
endpoint(boost::asio::ip::address_v4::any(),
                                                   _address.port());
         boost::system::error_code ec;
diff --git a/src/runtime/rpc/network.cpp b/src/runtime/rpc/network.cpp
index 48103bfbf..f16940971 100644
--- a/src/runtime/rpc/network.cpp
+++ b/src/runtime/rpc/network.cpp
@@ -41,6 +41,7 @@
 #include "runtime/task/task_code.h"
 #include "utils/blob.h"
 #include "utils/customizable_id.h"
+#include "utils/errors.h"
 #include "utils/flags.h"
 #include "utils/fmt_logging.h"
 #include "utils/ports.h"
@@ -579,21 +580,22 @@ message_parser 
*network::new_message_parser(network_header_format hdr_format)
 uint32_t network::get_local_ipv4()
 {
     uint32_t ip = 0;
+    error_s s;
     if (!utils::is_empty(FLAGS_explicit_host_address)) {
-        ip = rpc_address::ipv4_from_host(FLAGS_explicit_host_address);
+        s = rpc_address::ipv4_from_host(FLAGS_explicit_host_address, &ip);
     }
 
-    if (0 == ip) {
+    if (!s || 0 == ip) {
         ip = rpc_address::ipv4_from_network_interface(FLAGS_primary_interface);
     }
 
     if (0 == ip) {
-        char name[128];
-        CHECK_EQ_MSG(gethostname(name, sizeof(name)),
+        char name[128] = {0};
+        CHECK_EQ_MSG(::gethostname(name, sizeof(name)),
                      0,
                      "gethostname failed, err = {}",
                      utils::safe_strerror(errno));
-        ip = rpc_address::ipv4_from_host(name);
+        CHECK_OK(rpc_address::ipv4_from_host(name, &ip), "ipv4_from_host for 
'{}' failed", name);
     }
 
     return ip;
diff --git a/src/runtime/rpc/network.sim.cpp b/src/runtime/rpc/network.sim.cpp
index 1fe00ad8a..d97d857ee 100644
--- a/src/runtime/rpc/network.sim.cpp
+++ b/src/runtime/rpc/network.sim.cpp
@@ -159,7 +159,7 @@ void sim_server_session::send(uint64_t sig)
 sim_network_provider::sim_network_provider(rpc_engine *rpc, network 
*inner_provider)
     : connection_oriented_network(rpc, inner_provider)
 {
-    _address.assign_ipv4("localhost", 1);
+    _address = rpc_address::from_host_port("localhost", 1);
 }
 
 error_code sim_network_provider::start(rpc_channel channel, int port, bool 
client_only)
@@ -168,13 +168,12 @@ error_code sim_network_provider::start(rpc_channel 
channel, int port, bool clien
           "invalid given channel {}",
           channel);
 
-    _address = ::dsn::rpc_address("localhost", port);
+    _address = dsn::rpc_address::from_host_port("localhost", port);
     auto hostname = boost::asio::ip::host_name();
     if (!client_only) {
         for (int i = NET_HDR_INVALID + 1; i <= 
network_header_format::max_value(); i++) {
             if (s_switch[channel][i].put(_address, this)) {
-                auto ep2 = ::dsn::rpc_address(hostname.c_str(), port);
-                s_switch[channel][i].put(ep2, this);
+                
s_switch[channel][i].put(dsn::rpc_address::from_host_port(hostname, port), 
this);
             } else {
                 return ERR_ADDRESS_ALREADY_USED;
             }
diff --git a/src/runtime/rpc/rpc_address.cpp b/src/runtime/rpc/rpc_address.cpp
index 75173bbfb..f8d02d7c6 100644
--- a/src/runtime/rpc/rpc_address.cpp
+++ b/src/runtime/rpc/rpc_address.cpp
@@ -33,6 +33,7 @@
 #include <netinet/in.h>
 #include <string.h>
 #include <sys/socket.h>
+#include <string>
 
 #include "absl/strings/string_view.h"
 #include "runtime/rpc/group_address.h"
@@ -46,10 +47,10 @@
 
 namespace dsn {
 /*static*/
-error_s rpc_address::GetAddrInfo(const std::string &hostname, const addrinfo 
&hints, AddrInfo *info)
+error_s rpc_address::GetAddrInfo(std::string_view hostname, const addrinfo 
&hints, AddrInfo *info)
 {
     addrinfo *res = nullptr;
-    const int rc = getaddrinfo(hostname.c_str(), nullptr, &hints, &res);
+    const int rc = ::getaddrinfo(hostname.data(), nullptr, &hints, &res);
     const int err = errno; // preserving the errno from the getaddrinfo() call
     AddrInfo result(res, ::freeaddrinfo);
     if (dsn_unlikely(rc != 0)) {
@@ -68,23 +69,65 @@ error_s rpc_address::GetAddrInfo(const std::string 
&hostname, const addrinfo &hi
     return error_s::ok();
 }
 
+bool extract_host_port(const std::string_view &host_port, std::string_view 
&host, uint16_t &port)
+{
+    // Check the port field is present.
+    const auto pos = host_port.find_last_of(':');
+    if (dsn_unlikely(pos == std::string::npos)) {
+        LOG_ERROR("bad format, should be in the form of <ip|host>:port, but 
got '{}'", host_port);
+        return false;
+    }
+
+    // Check port.
+    const auto port_str = host_port.substr(pos + 1);
+    if (dsn_unlikely(!dsn::buf2uint16(port_str, port))) {
+        LOG_ERROR("bad port, should be an uint16_t integer, but got '{}'", 
port_str);
+        return false;
+    }
+
+    host = host_port.substr(0, pos);
+    return true;
+}
+
 const rpc_address rpc_address::s_invalid_address;
 
+rpc_address::rpc_address(uint32_t ip, uint16_t port)
+{
+    _addr.v4.type = HOST_TYPE_IPV4;
+    _addr.v4.ip = ip;
+    _addr.v4.port = port;
+    static_assert(sizeof(rpc_address) == sizeof(uint64_t),
+                  "make sure rpc_address does not add new payload to "
+                  "rpc_address to keep it sizeof(uint64_t)");
+}
+
+rpc_address::rpc_address(const struct sockaddr_in &addr)
+{
+    _addr.v4.type = HOST_TYPE_IPV4;
+    _addr.v4.ip = static_cast<uint32_t>(ntohl(addr.sin_addr.s_addr));
+    _addr.v4.port = ntohs(addr.sin_port);
+}
+
+rpc_address::rpc_address(const rpc_address &another) { *this = another; }
+
+rpc_address::~rpc_address() { set_invalid(); }
+
 /*static*/
-uint32_t rpc_address::ipv4_from_host(const char *name)
+error_s rpc_address::ipv4_from_host(std::string_view hostname, uint32_t *ip)
 {
     struct addrinfo hints;
     memset(&hints, 0, sizeof(hints));
     hints.ai_family = AF_INET;
     hints.ai_socktype = SOCK_STREAM;
     AddrInfo result;
-    if (dsn_unlikely(!GetAddrInfo(name, hints, &result).is_ok())) {
-        return 0;
-    }
+    RETURN_NOT_OK(GetAddrInfo(hostname, hints, &result));
     CHECK_EQ(result.get()->ai_family, AF_INET);
     auto *ipv4 = reinterpret_cast<struct sockaddr_in *>(result.get()->ai_addr);
     // converts from network byte order to host byte order
-    return ntohl(ipv4->sin_addr.s_addr);
+    if (ip != nullptr) {
+        *ip = ntohl(ipv4->sin_addr.s_addr);
+    }
+    return error_s::ok();
 }
 
 /*static*/
@@ -110,50 +153,50 @@ bool rpc_address::is_docker_netcard(const char 
*netcard_interface, uint32_t ip_n
 /*static*/
 uint32_t rpc_address::ipv4_from_network_interface(const char 
*network_interface)
 {
-    uint32_t ret = 0;
-
+    // Get the network interface list.
     struct ifaddrs *ifa = nullptr;
-    if (getifaddrs(&ifa) == 0) {
-        struct ifaddrs *i = ifa;
-        while (i != nullptr) {
-            if (i->ifa_name != nullptr && i->ifa_addr != nullptr &&
-                i->ifa_addr->sa_family == AF_INET) {
-                uint32_t ip_val = ((struct sockaddr_in 
*)i->ifa_addr)->sin_addr.s_addr;
-                if (utils::equals(i->ifa_name, network_interface) ||
-                    (network_interface[0] == '\0' && 
!is_docker_netcard(i->ifa_name, ip_val) &&
-                     is_site_local_address(ip_val))) {
-                    ret = (uint32_t)ntohl(ip_val);
-                    break;
-                }
-                LOG_DEBUG("skip interface({}), address({})",
-                          i->ifa_name,
-                          rpc_address(ip_val, 0).ipv4_str());
-            }
-            i = i->ifa_next;
-        }
+    if (::getifaddrs(&ifa) != 0) {
+        LOG_ERROR("{}: fail to getifaddrs", utils::safe_strerror(errno));
+        return 0;
+    }
 
-        if (i == nullptr) {
-            LOG_ERROR("get local ip from network interfaces failed, 
network_interface = {}",
-                      network_interface);
-        } else {
-            LOG_INFO("get ip address from network interface({}), addr({}), 
input interface({})",
-                     i->ifa_name,
-                     rpc_address(ret, 0).ipv4_str(),
-                     network_interface);
+    uint32_t ret = 0;
+    struct ifaddrs *i = ifa;
+    for (; i != nullptr; i = i->ifa_next) {
+        // Skip non-IPv4 network interface.
+        if (i->ifa_name == nullptr || i->ifa_addr == nullptr || 
i->ifa_addr->sa_family != AF_INET) {
+            continue;
         }
 
-        if (ifa != nullptr) {
-            // remember to free it
-            freeifaddrs(ifa);
+        uint32_t ip_val = ((struct sockaddr_in *)i->ifa_addr)->sin_addr.s_addr;
+        // Get the specified network interface, or the first internal network 
interface if not
+        // specified.
+        if (utils::equals(i->ifa_name, network_interface) ||
+            (utils::is_empty(network_interface) && 
!is_docker_netcard(i->ifa_name, ip_val) &&
+             is_site_local_address(ip_val))) {
+            ret = static_cast<uint32_t>(ntohl(ip_val));
+            break;
         }
+
+        LOG_DEBUG(
+            "skip interface({}), address({})", i->ifa_name, 
rpc_address(ip_val, 0).ipv4_str());
     }
 
-    return ret;
-}
+    if (i == nullptr) {
+        LOG_ERROR("get ip address from network interface({}) failed", 
network_interface);
+    } else {
+        LOG_INFO("get ip address from network interface({}), addr({}), input 
interface({})",
+                 i->ifa_name,
+                 rpc_address(ret, 0).ipv4_str(),
+                 network_interface);
+    }
 
-rpc_address::~rpc_address() { set_invalid(); }
+    if (ifa != nullptr) {
+        ::freeifaddrs(ifa);
+    }
 
-rpc_address::rpc_address(const rpc_address &another) { *this = another; }
+    return ret;
+}
 
 rpc_address &rpc_address::operator=(const rpc_address &another)
 {
@@ -177,7 +220,7 @@ void rpc_address::assign_group(const char *name)
 {
     set_invalid();
     _addr.group.type = HOST_TYPE_GROUP;
-    rpc_group_address *addr = new rpc_group_address(name);
+    auto *addr = new rpc_group_address(name);
     // take the lifetime of rpc_uri_address, release_ref when change value or 
call destructor
     addr->add_ref();
     _addr.group.group = (uint64_t)addr;
@@ -205,51 +248,86 @@ const char *rpc_address::ipv4_str() const
 
     if (_addr.v4.type == HOST_TYPE_IPV4) {
         net_addr.s_addr = htonl(ip());
-        inet_ntop(AF_INET, &net_addr, p, sz);
+        ::inet_ntop(AF_INET, &net_addr, p, sz);
     } else {
         p = (char *)"invalid_ipv4";
     }
     return p;
 }
 
-bool rpc_address::from_string_ipv4(const char *s)
+rpc_address rpc_address::from_ip_port(std::string_view ip_port)
 {
-    set_invalid();
-    std::string ip_port(s);
-    auto pos = ip_port.find_last_of(':');
-    if (pos == std::string::npos) {
-        return false;
+    std::string_view ip;
+    uint16_t port;
+    if (dsn_unlikely(!extract_host_port(ip_port, ip, port))) {
+        return {};
     }
-    std::string ip = ip_port.substr(0, pos);
-    std::string port = ip_port.substr(pos + 1);
-    // check port
-    unsigned int port_num;
-    if (!internal::buf2unsigned(port, port_num) || port_num > UINT16_MAX) {
-        return false;
+
+    // Use std::string(ip) to add a null terminator.
+    return from_ip_port(std::string(ip), port);
+}
+
+rpc_address rpc_address::from_ip_port(std::string_view ip, uint16_t port)
+{
+    // Check is IPv4 integer.
+    uint32_t ip_num;
+    int ret = ::inet_pton(AF_INET, ip.data(), &ip_num);
+    switch (ret) {
+    case 1:
+        // ::inet_pton() returns 1 on success (network address was 
successfully converted)
+        return {ntohl(ip_num), port};
+    case -1:
+        LOG_ERROR(
+            "{}: fail to convert '{}:{}' to rpc_address", 
utils::safe_strerror(errno), ip, port);
+        break;
+    default:
+        LOG_ERROR("'{}' does not contain a character string representing a 
valid network address",
+                  ip);
+        break;
     }
-    // check localhost & IP
-    uint32_t ip_addr;
-    if (ip == "localhost" || inet_pton(AF_INET, ip.c_str(), &ip_addr)) {
-        assign_ipv4(ip.c_str(), (uint16_t)port_num);
-        return true;
+    return {};
+}
+
+rpc_address rpc_address::from_host_port(std::string_view host_port)
+{
+    std::string_view host;
+    uint16_t port;
+    if (dsn_unlikely(!extract_host_port(host_port, host, port))) {
+        return {};
     }
-    return false;
+
+    // Use std::string(host) to add a null terminator.
+    return from_host_port(std::string(host), port);
 }
 
-const char *rpc_address::to_string() const
+rpc_address rpc_address::from_host_port(std::string_view hostname, uint16_t 
port)
 {
-    char *p = bf.next();
-    auto sz = bf.get_chunk_size();
-    struct in_addr net_addr;
-    int ip_len;
+    uint32_t ip = 0;
+    if (!ipv4_from_host(hostname, &ip)) {
+        return {};
+    }
+
+    rpc_address addr;
+    addr._addr.v4.type = HOST_TYPE_IPV4;
+    addr._addr.v4.ip = ip;
+    addr._addr.v4.port = port;
+    return addr;
+}
 
+const char *rpc_address::to_string() const
+{
+    char *p = nullptr;
     switch (_addr.v4.type) {
-    case HOST_TYPE_IPV4:
+    case HOST_TYPE_IPV4: {
+        const auto sz = bf.get_chunk_size();
+        struct in_addr net_addr;
         net_addr.s_addr = htonl(ip());
-        inet_ntop(AF_INET, &net_addr, p, sz);
-        ip_len = strlen(p);
+        p = bf.next();
+        ::inet_ntop(AF_INET, &net_addr, p, sz);
+        const auto ip_len = strlen(p);
         snprintf_p(p + ip_len, sz - ip_len, ":%hu", port());
         break;
+    }
     case HOST_TYPE_GROUP:
         p = (char *)group_address()->name();
         break;
@@ -261,12 +339,4 @@ const char *rpc_address::to_string() const
     return (const char *)p;
 }
 
-rpc_address::rpc_address(const struct sockaddr_in &addr)
-{
-    set_invalid();
-    _addr.v4.type = HOST_TYPE_IPV4;
-    _addr.v4.ip = static_cast<uint32_t>(ntohl(addr.sin_addr.s_addr));
-    _addr.v4.port = ntohs(addr.sin_port);
-}
-
 } // namespace dsn
diff --git a/src/runtime/rpc/rpc_address.h b/src/runtime/rpc/rpc_address.h
index a2d002a5d..ef7072615 100644
--- a/src/runtime/rpc/rpc_address.h
+++ b/src/runtime/rpc/rpc_address.h
@@ -33,7 +33,6 @@
 #include <functional>
 #include <memory>
 #include <sstream>
-#include <string>
 #include <string_view>
 
 #include "utils/errors.h"
@@ -66,56 +65,40 @@ class rpc_address
 {
 public:
     static const rpc_address s_invalid_address;
-    static bool is_docker_netcard(const char *netcard_interface, uint32_t 
ip_net);
-    static bool is_site_local_address(uint32_t ip_net);
-    static uint32_t ipv4_from_host(const char *hostname);
-    static uint32_t ipv4_from_network_interface(const char *network_interface);
-    static error_s GetAddrInfo(const std::string &hostname, const addrinfo 
&hints, AddrInfo *info);
 
-    ~rpc_address();
+    // Convert IPv4:port to rpc_address, e.g. "192.168.0.1:12345" or 
"localhost:54321".
+    // NOTE:
+    //   - IP address without port (e.g. "127.0.0.1") is considered as invalid.
+    static rpc_address from_ip_port(std::string_view ip_port);
 
-    constexpr rpc_address() = default;
-
-    rpc_address(const rpc_address &another);
+    // Similar to the above, but specify the 'ip' and 'port' separately.
+    static rpc_address from_ip_port(std::string_view ip, uint16_t port);
 
-    rpc_address &operator=(const rpc_address &another);
+    // Convert hostname:port to rpc_address, e.g. "192.168.0.1:12345", 
"localhost:54321" or
+    // "host1:12345".
+    // NOTE:
+    //   - Hostname without port (e.g. "host1") is considered as invalid.
+    //   - It contains a hostname resolve produce, so typically it's slower 
than from_ip_port().
+    //   - It requires 'hostname' is a null terminate string which only 
contains hostname.
+    static rpc_address from_host_port(std::string_view host_port);
 
-    rpc_address(uint32_t ip, uint16_t port)
-    {
-        assign_ipv4(ip, port);
-        static_assert(sizeof(rpc_address) == sizeof(uint64_t),
-                      "make sure rpc_address does not "
-                      "add new payload to rpc_address "
-                      "to keep it sizeof(uint64_t)");
-    }
+    // Similar to the above, but specify the 'host' and 'port' separately.
+    static rpc_address from_host_port(std::string_view host, uint16_t port);
 
-    rpc_address(const char *host, uint16_t port) { assign_ipv4(host, port); }
+    static bool is_docker_netcard(const char *netcard_interface, uint32_t 
ip_net);
+    static bool is_site_local_address(uint32_t ip_net);
+    // TODO(yingchun): Use dsn_resolver to resolve hostname.
+    static error_s ipv4_from_host(std::string_view hostname, uint32_t *ip);
+    static uint32_t ipv4_from_network_interface(const char *network_interface);
+    static error_s GetAddrInfo(std::string_view hostname, const addrinfo 
&hints, AddrInfo *info);
 
+    constexpr rpc_address() = default;
+    rpc_address(uint32_t ip, uint16_t port);
     explicit rpc_address(const struct sockaddr_in &addr);
+    rpc_address(const rpc_address &another);
+    ~rpc_address();
 
-    void assign_ipv4(uint32_t ip, uint16_t port)
-    {
-        set_invalid();
-        _addr.v4.type = HOST_TYPE_IPV4;
-        _addr.v4.ip = ip;
-        _addr.v4.port = port;
-    }
-
-    void assign_ipv4(const char *host, uint16_t port)
-    {
-        set_invalid();
-        _addr.v4.type = HOST_TYPE_IPV4;
-        _addr.v4.ip = rpc_address::ipv4_from_host(host);
-        _addr.v4.port = port;
-    }
-
-    void assign_ipv4_local_address(const char *network_interface, uint16_t 
port)
-    {
-        set_invalid();
-        _addr.v4.type = HOST_TYPE_IPV4;
-        _addr.v4.ip = 
rpc_address::ipv4_from_network_interface(network_interface);
-        _addr.v4.port = port;
-    }
+    rpc_address &operator=(const rpc_address &another);
 
     void assign_group(const char *name);
 
@@ -124,13 +107,6 @@ public:
     // return a.b.c.d if address is ipv4
     const char *ipv4_str() const;
 
-    std::string to_std_string() const { return std::string(to_string()); }
-
-    // This function is used for validating the format of ipv4 like 
"192.168.0.1:12345"
-    // Due to historical legacy, we also consider "localhost:8080" is in a 
valid format
-    // IP address without port like "127.0.0.1" is invalid here
-    bool from_string_ipv4(const char *s);
-
     uint64_t &value() { return _addr.value; }
 
     dsn_host_type_t type() const { return (dsn_host_type_t)_addr.v4.type; }
@@ -147,6 +123,7 @@ public:
     }
 
     bool is_invalid() const { return _addr.v4.type == HOST_TYPE_INVALID; }
+    operator bool() const { return !is_invalid(); }
 
     // before you assign new value, must call set_invalid() to release 
original value
     // and you MUST ensure that _addr is INITIALIZED before you call this 
function
@@ -199,6 +176,8 @@ public:
     uint32_t write(::apache::thrift::protocol::TProtocol *oprot) const;
 
 private:
+    friend class test_client;
+
     union
     {
         struct
diff --git a/src/runtime/rpc/rpc_holder.h b/src/runtime/rpc/rpc_holder.h
index 096618b8b..eefb4c564 100644
--- a/src/runtime/rpc/rpc_holder.h
+++ b/src/runtime/rpc/rpc_holder.h
@@ -63,7 +63,7 @@ using literals::chrono_literals::operator"" _ms;
 //       request->data = "abc";
 //       request->timestamp = 12;
 //       write_rpc rpc(std::move(request), RPC_WRITE);
-//       rpc.call(rpc_address("10.57.223.31", 12321), nullptr, 
on_write_rpc_reply);
+//       rpc.call(rpc_address::from_ip_port("10.57.223.31", 12321), nullptr, 
on_write_rpc_reply);
 //       ...
 //   }
 //
diff --git a/src/runtime/rpc/rpc_host_port.cpp 
b/src/runtime/rpc/rpc_host_port.cpp
index a00265adc..91ed9f01b 100644
--- a/src/runtime/rpc/rpc_host_port.cpp
+++ b/src/runtime/rpc/rpc_host_port.cpp
@@ -43,7 +43,7 @@ host_port::host_port(std::string host, uint16_t port)
     : _host(std::move(host)), _port(port), _type(HOST_TYPE_IPV4)
 {
     // ipv4_from_host may be slow, just call it in DEBUG version.
-    DCHECK_NE_MSG(rpc_address::ipv4_from_host(_host.c_str()), 0, "invalid 
hostname: {}", _host);
+    DCHECK_OK(rpc_address::ipv4_from_host(_host, nullptr), "invalid hostname: 
{}", _host);
 }
 
 host_port host_port::from_address(rpc_address addr)
@@ -86,7 +86,8 @@ host_port host_port::from_string(const std::string 
&host_port_str)
         return hp;
     }
 
-    if (dsn_unlikely(rpc_address::ipv4_from_host(hp._host.c_str()) == 0)) {
+    // Validate the hostname.
+    if (dsn_unlikely(!rpc_address::ipv4_from_host(hp._host, nullptr))) {
         return hp;
     }
 
@@ -168,13 +169,14 @@ error_s 
host_port::resolve_addresses(std::vector<rpc_address> &addresses) const
         __builtin_unreachable();
     }
 
-    rpc_address rpc_addr;
-    // Resolve hostname like "localhost:80" or "192.168.0.1:8080".
-    if (rpc_addr.from_string_ipv4(this->to_string().c_str())) {
+    // 1. Try to resolve hostname in the form of "localhost:80" or 
"192.168.0.1:8080".
+    const auto rpc_addr = rpc_address::from_ip_port(this->to_string());
+    if (rpc_addr) {
         addresses.emplace_back(rpc_addr);
         return error_s::ok();
     }
 
+    // 2. Try to resolve hostname in the form of "host1:80".
     struct addrinfo hints;
     memset(&hints, 0, sizeof(hints));
     hints.ai_family = AF_INET;
diff --git a/src/runtime/rpc/rpc_host_port.h b/src/runtime/rpc/rpc_host_port.h
index cd8df1fe6..4bec096c1 100644
--- a/src/runtime/rpc/rpc_host_port.h
+++ b/src/runtime/rpc/rpc_host_port.h
@@ -29,6 +29,8 @@
 #include <string_view>
 #include <vector>
 
+#include <gtest/gtest_prod.h>
+
 #include "runtime/rpc/rpc_address.h"
 #include "utils/errors.h"
 #include "utils/fmt_logging.h"
@@ -79,10 +81,6 @@ public:
     }
     void assign_group(const char *name);
 
-    // Resolve host_port to rpc_addresses.
-    // Trere may be multiple rpc_addresses for one host_port.
-    error_s resolve_addresses(std::vector<rpc_address> &addresses) const;
-
     // Construct a host_port object from 'addr'
     static host_port from_address(rpc_address addr);
 
@@ -97,6 +95,13 @@ public:
     uint32_t write(::apache::thrift::protocol::TProtocol *oprot) const;
 
 private:
+    friend class dns_resolver;
+    FRIEND_TEST(host_port_test, transfer_rpc_address);
+
+    // Resolve host_port to rpc_addresses.
+    // There may be multiple rpc_addresses for one host_port.
+    error_s resolve_addresses(std::vector<rpc_address> &addresses) const;
+
     std::string _host;
     uint16_t _port = 0;
     dsn_host_type_t _type = HOST_TYPE_INVALID;
diff --git a/src/runtime/test/address_test.cpp 
b/src/runtime/test/address_test.cpp
index 838a74791..74f56c7a3 100644
--- a/src/runtime/test/address_test.cpp
+++ b/src/runtime/test/address_test.cpp
@@ -24,14 +24,21 @@
  * THE SOFTWARE.
  */
 
+#include <fmt/core.h>
+#include <netdb.h>
 #include <netinet/in.h>
 #include <stdint.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "gtest/gtest.h"
 #include "runtime/rpc/group_address.h"
 #include "runtime/rpc/rpc_address.h"
+#include "utils/errors.h"
 
 namespace dsn {
 
@@ -47,13 +54,46 @@ static inline uint32_t host_ipv4(uint8_t sec1, uint8_t 
sec2, uint8_t sec3, uint8
 
 TEST(rpc_address_test, rpc_address_ipv4_from_host)
 {
-    // localhost --> 127.0.0.1
-    // on some systems "localhost" could be "127.0.1.1" (debian)
-    ASSERT_TRUE(host_ipv4(127, 0, 0, 1) == 
rpc_address::ipv4_from_host("localhost") ||
-                host_ipv4(127, 0, 1, 1) == 
rpc_address::ipv4_from_host("localhost"));
-
-    // 127.0.0.1 --> 127.0.0.1
-    ASSERT_EQ(host_ipv4(127, 0, 0, 1), 
rpc_address::ipv4_from_host("127.0.0.1"));
+    struct resolve_test
+    {
+        std::string hostname;
+        bool valid;
+        std::set<uint32_t> expect_ips;
+
+        resolve_test(std::string hn, bool v, std::set<uint32_t> expects)
+            : hostname(std::move(hn)), valid(v), expect_ips(std::move(expects))
+        {
+        }
+    };
+
+    const resolve_test tests[] = {
+        {"127.0.0.1", true, {host_ipv4(127, 0, 0, 1)}},
+        {"0.0.0.0", true, {host_ipv4(0, 0, 0, 0)}},
+        // on some systems "localhost" could be "127.0.1.1" (debian)
+        {"localhost", true, {host_ipv4(127, 0, 0, 1), host_ipv4(127, 0, 1, 
1)}},
+        {"whatthefuckyoucanhavesuchahostname", false, {}}};
+
+    struct addrinfo hints;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_INET;
+    hints.ai_socktype = SOCK_STREAM;
+    for (const auto &test : tests) {
+        // Check ipv4_from_host()
+        uint32_t ip;
+        ASSERT_EQ(test.valid, rpc_address::ipv4_from_host(test.hostname, 
&ip).is_ok());
+
+        // Check GetAddrInfo()
+        AddrInfo result;
+        ASSERT_EQ(test.valid, rpc_address::GetAddrInfo(test.hostname, hints, 
&result).is_ok())
+            << test.hostname;
+        if (test.valid) {
+            ASSERT_GT(test.expect_ips.count(ip), 0) << test.hostname;
+
+            ASSERT_EQ(result.get()->ai_family, AF_INET);
+            auto *ipv4 = reinterpret_cast<struct sockaddr_in 
*>(result.get()->ai_addr);
+            ASSERT_GT(test.expect_ips.count(ntohl(ipv4->sin_addr.s_addr)), 0) 
<< test.hostname;
+        }
+    }
 }
 
 TEST(rpc_address_test, rpc_address_ipv4_from_network_interface)
@@ -86,36 +126,36 @@ TEST(rpc_address_test, is_docker_netcard)
 TEST(rpc_address_test, rpc_address_to_string)
 {
     {
-        rpc_address addr;
-        addr.assign_ipv4(host_ipv4(127, 0, 0, 1), 8080);
-        ASSERT_EQ(std::string("127.0.0.1:8080"), addr.to_std_string());
+        rpc_address addr(host_ipv4(127, 0, 0, 1), 8080);
+        ASSERT_STREQ("127.0.0.1:8080", addr.to_string());
     }
 
     {
         const char *name = "test_group";
         rpc_address addr;
         addr.assign_group(name);
-        ASSERT_EQ(std::string(name), addr.to_std_string());
+        ASSERT_STREQ(name, addr.to_string());
     }
 
     {
         rpc_address addr;
-        ASSERT_EQ(std::string("invalid address"), addr.to_std_string());
+        ASSERT_STREQ("invalid address", addr.to_string());
     }
 }
 
 TEST(rpc_address_test, dsn_address_build)
 {
     {
-        rpc_address addr;
-        addr.assign_ipv4(host_ipv4(127, 0, 0, 1), 8080);
+        rpc_address addr(host_ipv4(127, 0, 0, 1), 8080);
         ASSERT_EQ(HOST_TYPE_IPV4, addr.type());
         ASSERT_EQ(host_ipv4(127, 0, 0, 1), addr.ip());
         ASSERT_EQ(8080, addr.port());
 
-        ASSERT_TRUE(rpc_address("127.0.0.1", 8080) == rpc_address("localhost", 
8080) ||
-                    rpc_address("127.0.1.1", 8080) == rpc_address("localhost", 
8080));
-        ASSERT_EQ(addr, rpc_address("127.0.0.1", 8080));
+        ASSERT_TRUE(rpc_address::from_ip_port("127.0.0.1", 8080) ==
+                        rpc_address::from_host_port("localhost", 8080) ||
+                    rpc_address::from_ip_port("127.0.1.1", 8080) ==
+                        rpc_address::from_host_port("localhost", 8080));
+        ASSERT_EQ(addr, rpc_address::from_ip_port("127.0.0.1", 8080));
         ASSERT_EQ(addr, rpc_address(host_ipv4(127, 0, 0, 1), 8080));
     }
 
@@ -161,9 +201,9 @@ TEST(rpc_address_test, operators)
 
 TEST(rpc_address_test, rpc_group_address)
 {
-    rpc_address addr("127.0.0.1", 8080);
+    const auto addr = rpc_address::from_ip_port("127.0.0.1", 8080);
     rpc_address invalid_addr;
-    rpc_address addr2("127.0.0.1", 8081);
+    const auto addr2 = rpc_address::from_ip_port("127.0.0.1", 8081);
 
     rpc_address t;
     t.assign_group("test_group");
@@ -247,4 +287,142 @@ TEST(rpc_address_test, rpc_group_address)
     ASSERT_EQ(invalid_addr, g->leader());
 }
 
+TEST(rpc_address_test, from_host_port)
+{
+    struct resolve_test
+    {
+        std::string host_port;
+        std::set<std::string> expect_ip_ports;
+        bool valid_ip_port;
+        bool valid_host_port;
+
+        resolve_test(std::string test, std::set<std::string> expects, bool 
v_ip, bool v_hp)
+            : host_port(std::move(test)),
+              expect_ip_ports(std::move(expects)),
+              valid_ip_port(v_ip),
+              valid_host_port(v_hp)
+        {
+        }
+
+        resolve_test(std::string test, bool val)
+            : host_port(std::move(test)),
+              expect_ip_ports({host_port}),
+              valid_ip_port(val),
+              valid_host_port(val)
+        {
+        }
+    };
+
+    const resolve_test tests[] = {
+        {"127.0.0.1:8080", true},
+        {"127.0.0.1:", false},
+        {"172.16.254.1:1234", true},
+        {"0.0.0.0:1234", {"0.0.0.0:1234"}, true, true},
+        {"172.16.254.1:222222", false},
+        {"172.16.254.1", false},
+        {"2222,123,33,1:8080", false},
+        {"123.456.789.1:8080", false},
+        // "001.223.110.002" can be resolved by host, but not by IP.
+        {"001.223.110.002:8080", {"1.223.110.2:8080"}, false, true},
+        {"172.16.254.1.8080", false},
+        {"172.16.254.1:8080.", false},
+        {"127.0.0.11:123!", false},
+        {"127.0.0.11:123", true},
+        {"localhost:34601", {"127.0.0.1:34601", "127.0.1.1:34601"}, false, 
true},
+        {"localhost:3460100022212312312213", false},
+        {"localhost:-12", false},
+        {"localhost", false},
+        {"localhost:", false},
+        {"whatthefuckyoucanhavesuchahostname", false},
+        {"localhost:1@2", false}};
+
+    for (const auto &test : tests) {
+        // Check from_host_port().
+        const auto host_port_result = 
dsn::rpc_address::from_host_port(test.host_port);
+        ASSERT_EQ(test.valid_host_port, !host_port_result.is_invalid()) << 
test.host_port;
+        if (!host_port_result.is_invalid()) {
+            
ASSERT_GT(test.expect_ip_ports.count(host_port_result.to_string()), 0);
+        }
+
+        // Check from_ip_port().
+        const auto ip_port_result = 
dsn::rpc_address::from_ip_port(test.host_port);
+        ASSERT_EQ(test.valid_ip_port, !ip_port_result.is_invalid());
+        if (!ip_port_result.is_invalid()) {
+            ASSERT_GT(test.expect_ip_ports.count(ip_port_result.to_string()), 
0);
+        }
+
+        // Check they are equal.
+        if (test.valid_host_port && test.valid_ip_port) {
+            ASSERT_EQ(host_port_result, ip_port_result);
+        }
+    }
+}
+
+TEST(rpc_address_test, from_host_port2)
+{
+    struct resolve_test
+    {
+        std::string host;
+        uint16_t port;
+        std::set<std::string> expect_ip_ports;
+        bool valid_ip_port;
+        bool valid_host_port;
+
+        resolve_test(
+            std::string test, uint16_t p, std::set<std::string> expects, bool 
v_ip, bool v_hp)
+            : host(std::move(test)),
+              port(p),
+              expect_ip_ports(std::move(expects)),
+              valid_ip_port(v_ip),
+              valid_host_port(v_hp)
+        {
+        }
+
+        resolve_test(std::string test, uint16_t p, bool val)
+            : host(std::move(test)),
+              port(p),
+              expect_ip_ports({fmt::format("{}:{}", host, port)}),
+              valid_ip_port(val),
+              valid_host_port(val)
+        {
+        }
+    };
+
+    const resolve_test tests[] = {
+        {"127.0.0.1", 8080, true},
+        {"172.16.254.1", 1234, true},
+        {"172.16.254.1:", 1234, false},
+        {"2222,123,33,1", 8080, false},
+        {"123.456.789.1", 8080, false},
+        {"0.0.0.0", 1234, {"0.0.0.0:1234"}, true, true},
+        // "001.223.110.002" can be resolved by host, but not by IP.
+        {"001.223.110.002", 8080, {"1.223.110.2:8080"}, false, true},
+        {"127.0.0.11", 123, true},
+        {"localhost", 34601, {"127.0.0.1:34601", "127.0.1.1:34601"}, false, 
true},
+        {"localhost:", 34601, false},
+        {"whatthefuckyoucanhavesuchahostname", 34601, false}};
+
+    for (const auto &test : tests) {
+        // Check from_host_port().
+        const auto host_port_result = 
dsn::rpc_address::from_host_port(test.host, test.port);
+        ASSERT_EQ(test.valid_host_port, !host_port_result.is_invalid()) << 
test.host;
+        if (!host_port_result.is_invalid()) {
+            
ASSERT_GT(test.expect_ip_ports.count(host_port_result.to_string()), 0)
+                << test.host << " " << host_port_result.to_string();
+        }
+
+        // Check from_ip_port().
+        const auto ip_port_result = dsn::rpc_address::from_ip_port(test.host, 
test.port);
+        ASSERT_EQ(test.valid_ip_port, !ip_port_result.is_invalid());
+        if (!ip_port_result.is_invalid()) {
+            ASSERT_GT(test.expect_ip_ports.count(ip_port_result.to_string()), 
0);
+        }
+
+        // Check they are equal.
+        if (test.valid_host_port && test.valid_ip_port) {
+            ASSERT_EQ(host_port_result, ip_port_result);
+        }
+    }
+}
+
 } // namespace dsn
diff --git a/src/runtime/test/async_call.cpp b/src/runtime/test/async_call.cpp
index 0a266cbcf..38398fd18 100644
--- a/src/runtime/test/async_call.cpp
+++ b/src/runtime/test/async_call.cpp
@@ -122,9 +122,9 @@ TEST(async_call, task_call)
 
 TEST(async_call, rpc_call)
 {
-    rpc_address addr("localhost", 20101);
-    rpc_address addr2("localhost", TEST_PORT_END);
-    rpc_address addr3("localhost", 32767);
+    const auto addr = rpc_address::from_host_port("localhost", 20101);
+    const auto addr2 = rpc_address::from_host_port("localhost", TEST_PORT_END);
+    const auto addr3 = rpc_address::from_host_port("localhost", 32767);
 
     tracker_class *tc = new tracker_class();
     rpc::call_one_way_typed(addr, RPC_TEST_STRING_COMMAND, 
std::string("expect_no_reply"), 0);
diff --git a/src/runtime/test/corrupt_message.cpp 
b/src/runtime/test/corrupt_message.cpp
index 1db983b25..6b1200fa6 100644
--- a/src/runtime/test/corrupt_message.cpp
+++ b/src/runtime/test/corrupt_message.cpp
@@ -39,21 +39,21 @@
 TEST(core, corrupt_message)
 {
     int req = 0;
-    ::dsn::rpc_address server("localhost", 20101);
+    const auto server = dsn::rpc_address::from_host_port("localhost", 20101);
 
     auto result = ::dsn::rpc::call_wait<std::string>(
         server, RPC_TEST_HASH1, req, std::chrono::milliseconds(0), 1);
-    ASSERT_EQ(result.first, ERR_TIMEOUT);
+    ASSERT_EQ(result.first, dsn::ERR_TIMEOUT);
 
     result = ::dsn::rpc::call_wait<std::string>(
         server, RPC_TEST_HASH2, req, std::chrono::milliseconds(0), 1);
-    ASSERT_EQ(result.first, ERR_TIMEOUT);
+    ASSERT_EQ(result.first, dsn::ERR_TIMEOUT);
 
     result = ::dsn::rpc::call_wait<std::string>(
         server, RPC_TEST_HASH3, req, std::chrono::milliseconds(0), 1);
-    ASSERT_EQ(result.first, ERR_TIMEOUT);
+    ASSERT_EQ(result.first, dsn::ERR_TIMEOUT);
 
     result = ::dsn::rpc::call_wait<std::string>(
         server, RPC_TEST_HASH4, req, std::chrono::milliseconds(0), 1);
-    ASSERT_EQ(result.first, ERR_TIMEOUT);
+    ASSERT_EQ(result.first, dsn::ERR_TIMEOUT);
 }
diff --git a/src/runtime/test/host_port_test.cpp 
b/src/runtime/test/host_port_test.cpp
index 0ab4f1f2e..722ea5e2f 100644
--- a/src/runtime/test/host_port_test.cpp
+++ b/src/runtime/test/host_port_test.cpp
@@ -62,7 +62,7 @@ TEST(host_port_test, host_port_build)
     ASSERT_EQ("localhost", hp.host());
 
     {
-        rpc_address addr = rpc_address("localhost", 8080);
+        const auto addr = rpc_address::from_host_port("localhost", 8080);
         host_port hp1 = host_port::from_address(addr);
         ASSERT_EQ(hp, hp1);
     }
@@ -180,8 +180,8 @@ TEST(host_port_test, rpc_group_host_port)
     }
 
     // address_group -> host_port_group
-    rpc_address addr("127.0.0.1", 8080);
-    rpc_address addr2("127.0.0.1", 8081);
+    const auto addr = rpc_address::from_ip_port("127.0.0.1", 8080);
+    const auto addr2 = rpc_address::from_ip_port("127.0.0.1", 8081);
 
     rpc_address addr_grp;
     addr_grp.assign_group("test_group");
@@ -211,8 +211,8 @@ TEST(host_port_test, transfer_rpc_address)
         std::vector<rpc_address> addresses;
         host_port hp("localhost", 8080);
         ASSERT_EQ(hp.resolve_addresses(addresses), error_s::ok());
-        ASSERT_TRUE(rpc_address("127.0.0.1", 8080) == addresses[0] ||
-                    rpc_address("127.0.1.1", 8080) == addresses[0]);
+        ASSERT_TRUE(rpc_address::from_ip_port("127.0.0.1", 8080) == 
addresses[0] ||
+                    rpc_address::from_ip_port("127.0.1.1", 8080) == 
addresses[0]);
     }
     {
         std::vector<rpc_address> addresses;
@@ -233,8 +233,8 @@ TEST(host_port_test, dns_resolver)
     {
         host_port hp("localhost", 8080);
         const auto &addr = dns_resolver::instance().resolve_address(hp);
-        ASSERT_TRUE(rpc_address("127.0.0.1", 8080) == addr ||
-                    rpc_address("127.0.1.1", 8080) == addr);
+        ASSERT_TRUE(rpc_address::from_ip_port("127.0.0.1", 8080) == addr ||
+                    rpc_address::from_ip_port("127.0.1.1", 8080) == addr);
     }
 
     {
@@ -260,7 +260,7 @@ TEST(host_port_test, dns_resolver)
 void send_and_check_host_port_by_serialize(const host_port &hp, 
dsn_msg_serialize_format t)
 {
     const auto &hp_str = hp.to_string();
-    ::dsn::rpc_address server("localhost", 20101);
+    const auto server = ::dsn::rpc_address::from_host_port("localhost", 20101);
 
     dsn::message_ptr msg_ptr = 
dsn::message_ex::create_request(RPC_TEST_THRIFT_HOST_PORT_PARSER);
     msg_ptr->header->context.u.serialize_format = t;
diff --git a/src/runtime/test/lpc.cpp b/src/runtime/test/lpc.cpp
index c0d63b3a8..0f6d7e2ba 100644
--- a/src/runtime/test/lpc.cpp
+++ b/src/runtime/test/lpc.cpp
@@ -46,7 +46,7 @@ void on_lpc_test(void *p)
 TEST(core, lpc)
 {
     std::string result = "heheh";
-    dsn::task_ptr t(new raw_task(LPC_TEST_HASH, std::bind(&on_lpc_test, (void 
*)&result), 1));
+    dsn::task_ptr t(new dsn::raw_task(LPC_TEST_HASH, std::bind(&on_lpc_test, 
(void *)&result), 1));
     t->enqueue();
     t->wait();
     EXPECT_TRUE(result.substr(0, result.length() - 2) == 
"client.THREAD_POOL_TEST_SERVER");
diff --git a/src/runtime/test/main.cpp b/src/runtime/test/main.cpp
index 23b64deb6..7b7bddff9 100644
--- a/src/runtime/test/main.cpp
+++ b/src/runtime/test/main.cpp
@@ -45,7 +45,7 @@ GTEST_API_ int main(int argc, char **argv)
     testing::InitGoogleTest(&argc, argv);
 
     // register all possible services
-    dsn::service_app::register_factory<test_client>("test");
+    dsn::service_app::register_factory<dsn::test_client>("test");
 
     // specify what services and tools will run in config file, then run
     dsn_run(argc, argv, false);
diff --git a/src/runtime/test/netprovider.cpp b/src/runtime/test/netprovider.cpp
index 820cd3b34..4de70ed00 100644
--- a/src/runtime/test/netprovider.cpp
+++ b/src/runtime/test/netprovider.cpp
@@ -170,7 +170,7 @@ TEST(tools_common, asio_net_provider)
     LOG_INFO("result: {}", start_result);
 
     rpc_session_ptr client_session =
-        asio_network->create_client_session(rpc_address("localhost", 
TEST_PORT));
+        
asio_network->create_client_session(rpc_address::from_host_port("localhost", 
TEST_PORT));
     client_session->connect();
 
     rpc_client_session_send(client_session);
@@ -243,7 +243,7 @@ TEST(tools_common, sim_net_provider)
     ASSERT_TRUE(ans == ERR_ADDRESS_ALREADY_USED);
 
     rpc_session_ptr client_session =
-        sim_net->create_client_session(rpc_address("localhost", TEST_PORT));
+        
sim_net->create_client_session(rpc_address::from_host_port("localhost", 
TEST_PORT));
     client_session->connect();
 
     rpc_client_session_send(client_session);
@@ -278,8 +278,8 @@ TEST(tools_common, 
asio_network_provider_connection_threshold)
     // not exceed threshold
     for (int count = 0; count < CONN_THRESHOLD + 2; count++) {
         LOG_INFO("client # {}", count);
-        rpc_session_ptr client_session =
-            asio_network->create_client_session(rpc_address("localhost", 
TEST_PORT));
+        rpc_session_ptr client_session = asio_network->create_client_session(
+            rpc_address::from_host_port("localhost", TEST_PORT));
         client_session->connect();
 
         rpc_client_session_send(client_session);
@@ -292,8 +292,8 @@ TEST(tools_common, 
asio_network_provider_connection_threshold)
     bool reject = false;
     for (int count = 0; count < CONN_THRESHOLD + 2; count++) {
         LOG_INFO("client # {}", count);
-        rpc_session_ptr client_session =
-            asio_network->create_client_session(rpc_address("localhost", 
TEST_PORT));
+        rpc_session_ptr client_session = asio_network->create_client_session(
+            rpc_address::from_host_port("localhost", TEST_PORT));
         client_session->connect();
 
         if (count >= CONN_THRESHOLD)
diff --git a/src/runtime/test/rpc.cpp b/src/runtime/test/rpc.cpp
index 17c95fb5f..b9e2804d8 100644
--- a/src/runtime/test/rpc.cpp
+++ b/src/runtime/test/rpc.cpp
@@ -24,9 +24,6 @@
  * THE SOFTWARE.
  */
 
-#include <boost/cstdint.hpp>
-#include <boost/lexical_cast.hpp>
-#include <stddef.h>
 #include <stdint.h>
 #include <algorithm>
 #include <chrono>
@@ -47,6 +44,7 @@
 #include "utils/fmt_logging.h"
 #include "utils/priority_queue.h"
 
+namespace dsn {
 typedef std::function<void(error_code, dsn::message_ex *, dsn::message_ex *)> 
rpc_reply_handler;
 
 static dsn::rpc_address build_group()
@@ -55,30 +53,17 @@ static dsn::rpc_address build_group()
     server_group.assign_group("server_group.test");
     dsn::rpc_group_address *g = server_group.group_address();
     for (uint16_t p = TEST_PORT_BEGIN; p <= TEST_PORT_END; ++p) {
-        CHECK(g->add(dsn::rpc_address("localhost", p)), "");
+        CHECK(g->add(dsn::rpc_address::from_host_port("localhost", p)), "");
     }
 
-    g->set_leader(dsn::rpc_address("localhost", TEST_PORT_BEGIN));
+    g->set_leader(dsn::rpc_address::from_host_port("localhost", 
TEST_PORT_BEGIN));
     return server_group;
 }
 
-static ::dsn::rpc_address dsn_address_from_string(const std::string &str)
-{
-    size_t pos = str.find(":");
-    if (pos != std::string::npos) {
-        std::string host = str.substr(0, pos);
-        uint16_t port = boost::lexical_cast<uint16_t>(str.substr(pos + 1));
-        return ::dsn::rpc_address(host.c_str(), port);
-    } else {
-        // invalid address
-        return ::dsn::rpc_address();
-    }
-}
-
 TEST(core, rpc)
 {
     int req = 0;
-    ::dsn::rpc_address server("localhost", 20101);
+    const auto server = ::dsn::rpc_address::from_host_port("localhost", 20101);
 
     auto result = ::dsn::rpc::call_wait<std::string>(
         server, RPC_TEST_HASH, req, std::chrono::milliseconds(0), 1);
@@ -94,9 +79,9 @@ TEST(core, group_address_talk_to_others)
 
     auto typed_callback = [addr](error_code err_code, const std::string 
&result) {
         EXPECT_EQ(ERR_OK, err_code);
-        dsn::rpc_address addr_got;
         LOG_INFO("talk to others callback, result: {}", result);
-        EXPECT_TRUE(addr_got.from_string_ipv4(result.c_str()));
+        const auto addr_got = rpc_address::from_ip_port(result);
+        EXPECT_TRUE(addr_got);
         EXPECT_EQ(TEST_PORT_END, addr_got.port());
     };
     ::dsn::task_ptr resp = ::dsn::rpc::call(addr,
@@ -115,9 +100,9 @@ TEST(core, group_address_change_leader)
     auto typed_callback = [addr, &rpc_err](error_code err_code, const 
std::string &result) -> void {
         rpc_err = err_code;
         if (ERR_OK == err_code) {
-            ::dsn::rpc_address addr_got;
             LOG_INFO("talk to others callback, result: {}", result);
-            EXPECT_TRUE(addr_got.from_string_ipv4(result.c_str()));
+            const auto addr_got = rpc_address::from_ip_port(result);
+            EXPECT_TRUE(addr_got);
             EXPECT_EQ(TEST_PORT_END, addr_got.port());
         }
     };
@@ -126,7 +111,8 @@ TEST(core, group_address_change_leader)
 
     // not update leader on forwarding
     addr.group_address()->set_update_leader_automatically(false);
-    addr.group_address()->set_leader(dsn::rpc_address("localhost", 
TEST_PORT_BEGIN));
+    addr.group_address()->set_leader(
+        dsn::rpc_address::from_host_port("localhost", TEST_PORT_BEGIN));
     resp_task = ::dsn::rpc::call(addr,
                                  RPC_TEST_STRING_COMMAND,
                                  std::string("expect_talk_to_others"),
@@ -134,13 +120,14 @@ TEST(core, group_address_change_leader)
                                  typed_callback);
     resp_task->wait();
     if (rpc_err == ERR_OK) {
-        EXPECT_EQ(dsn::rpc_address("localhost", TEST_PORT_BEGIN),
+        EXPECT_EQ(dsn::rpc_address::from_host_port("localhost", 
TEST_PORT_BEGIN),
                   dsn::rpc_address(addr.group_address()->leader()));
     }
 
     // update leader on forwarding
     addr.group_address()->set_update_leader_automatically(true);
-    addr.group_address()->set_leader(dsn::rpc_address("localhost", 
TEST_PORT_BEGIN));
+    addr.group_address()->set_leader(
+        dsn::rpc_address::from_host_port("localhost", TEST_PORT_BEGIN));
     resp_task = dsn::rpc::call(addr,
                                RPC_TEST_STRING_COMMAND,
                                std::string("expect_talk_to_others"),
@@ -217,17 +204,17 @@ TEST(core, group_address_no_response_2)
     ::dsn::rpc_address addr = build_group();
     rpc_reply_handler action_on_succeed =
         [](error_code err, dsn::message_ex *, dsn::message_ex *resp) {
-            EXPECT_TRUE(err == ERR_OK);
+            EXPECT_EQ(ERR_OK, err);
             std::string result;
             ::dsn::unmarshall(resp, result);
-            ::dsn::rpc_address a = dsn_address_from_string(result);
-            EXPECT_TRUE(a.port() == TEST_PORT_END);
+            const auto addr = ::dsn::rpc_address::from_ip_port(result);
+            EXPECT_EQ(TEST_PORT_END, addr.port());
         };
 
     rpc_reply_handler action_on_failure =
         [](error_code err, dsn::message_ex *req, dsn::message_ex *) {
             if (err == ERR_TIMEOUT) {
-                EXPECT_TRUE(((dsn::message_ex *)req)->to_address.port() != 
TEST_PORT_END);
+                EXPECT_NE(TEST_PORT_END, ((dsn::message_ex 
*)req)->to_address.port());
             }
         };
 
@@ -238,7 +225,7 @@ TEST(core, send_to_invalid_address)
 {
     ::dsn::rpc_address group = build_group();
     /* here we assume 10.255.254.253:32766 is not assigned */
-    group.group_address()->set_leader(dsn::rpc_address("10.255.254.253", 
32766));
+    
group.group_address()->set_leader(dsn::rpc_address::from_ip_port("10.255.254.253",
 32766));
 
     rpc_reply_handler action_on_succeed =
         [](error_code err, dsn::message_ex *, dsn::message_ex *resp) {
@@ -253,3 +240,4 @@ TEST(core, send_to_invalid_address)
 
     send_message(group, std::string("echo hehehe"), 1, action_on_succeed, 
action_on_failure);
 }
+} // namespace dsn
diff --git a/src/runtime/test/rpc_holder_test.cpp 
b/src/runtime/test/rpc_holder_test.cpp
index 8d1b838d8..88eb3b31e 100644
--- a/src/runtime/test/rpc_holder_test.cpp
+++ b/src/runtime/test/rpc_holder_test.cpp
@@ -99,7 +99,7 @@ TEST(rpc_holder, mock_rpc_call)
         for (int i = 0; i < 10; i++) {
             auto request = std::make_unique<query_cfg_request>();
             t_rpc rpc(std::move(request), 
RPC_CM_QUERY_PARTITION_CONFIG_BY_INDEX);
-            rpc.call(rpc_address("127.0.0.1", 12321), nullptr, [](error_code) 
{});
+            rpc.call(rpc_address::from_ip_port("127.0.0.1", 12321), nullptr, 
[](error_code) {});
         }
 
         ASSERT_EQ(mail_box.size(), 10);
@@ -114,7 +114,7 @@ TEST(rpc_holder, mock_rpc_call)
             auto request = std::make_unique<query_cfg_request>();
             t_rpc rpc(std::move(request), 
RPC_CM_QUERY_PARTITION_CONFIG_BY_INDEX);
             rpc.error() = ERR_BUSY;
-            rpc.call(rpc_address("127.0.0.1", 12321), nullptr, [](error_code) 
{});
+            rpc.call(rpc_address::from_ip_port("127.0.0.1", 12321), nullptr, 
[](error_code) {});
         }
 
         ASSERT_EQ(mail_box.size(), 10);
@@ -133,7 +133,7 @@ TEST(rpc_holder, mock_rpc_call)
         for (int i = 0; i < 10; i++) {
             auto request = std::make_unique<query_cfg_request>();
             t_rpc rpc(std::move(request), 
RPC_CM_QUERY_PARTITION_CONFIG_BY_INDEX);
-            rpc.call(rpc_address("127.0.0.1", 12321), nullptr, [](error_code) 
{});
+            rpc.call(rpc_address::from_ip_port("127.0.0.1", 12321), nullptr, 
[](error_code) {});
         }
 
         ASSERT_EQ(mail_box.size(), 10);
@@ -166,7 +166,7 @@ TEST(rpc_holder, mock_rpc_forward)
     {
         auto &mail_box = t_rpc::mail_box();
         auto &forward_mail_box = t_rpc::forward_mail_box();
-        rpc_address forward_addr("127.0.0.1", 10086);
+        const auto forward_addr = rpc_address::from_ip_port("127.0.0.1", 
10086);
 
         for (int i = 0; i < 10; i++) {
             query_cfg_request request;
diff --git a/src/runtime/test/rpc_message.cpp b/src/runtime/test/rpc_message.cpp
index a596b2cd2..3c8791393 100644
--- a/src/runtime/test/rpc_message.cpp
+++ b/src/runtime/test/rpc_message.cpp
@@ -93,8 +93,8 @@ TEST(core, message_ex)
 
     { // create_response
         message_ex *request = message_ex::create_request(RPC_CODE_FOR_TEST, 0, 
0);
-        request->header->from_address = rpc_address("127.0.0.1", 8080);
-        request->to_address = rpc_address("127.0.0.1", 9090);
+        request->header->from_address = rpc_address::from_ip_port("127.0.0.1", 
8080);
+        request->to_address = rpc_address::from_ip_port("127.0.0.1", 9090);
         request->header->trace_id = 123456;
 
         message_ex *response = request->create_response();
diff --git a/src/runtime/test_utils.h b/src/runtime/test_utils.h
index 29520eee9..5d06cc587 100644
--- a/src/runtime/test_utils.h
+++ b/src/runtime/test_utils.h
@@ -45,8 +45,6 @@
 #include <gtest/gtest.h>
 #include <iostream>
 
-using namespace ::dsn;
-
 #ifndef TEST_PORT_BEGIN
 #define TEST_PORT_BEGIN 20201
 #define TEST_PORT_END 20203
@@ -74,6 +72,7 @@ inline void exec_tests()
     g_test_count++;
 }
 
+namespace dsn {
 class test_client : public ::dsn::serverlet<test_client>, public 
::dsn::service_app
 {
 public:
@@ -96,18 +95,18 @@ public:
         if (command == "expect_talk_to_others") {
             dsn::rpc_address next_addr = dsn::service_app::primary_address();
             if (next_addr.port() != TEST_PORT_END) {
-                next_addr.assign_ipv4(next_addr.ip(), next_addr.port() + 1);
+                next_addr._addr.v4.port++;
                 LOG_INFO("test_client_server, talk_to_others: {}", next_addr);
                 dsn_rpc_forward(message, next_addr);
             } else {
                 LOG_INFO("test_client_server, talk_to_me: {}", next_addr);
-                reply(message, next_addr.to_std_string());
+                reply(message, std::string(next_addr.to_string()));
             }
         } else if (command == "expect_no_reply") {
             if (dsn::service_app::primary_address().port() == TEST_PORT_END) {
                 LOG_INFO("test_client_server, talk_with_reply: {}",
                          dsn::service_app::primary_address());
-                reply(message, 
dsn::service_app::primary_address().to_std_string());
+                reply(message, 
std::string(dsn::service_app::primary_address().to_string()));
             }
         } else if (command.substr(0, 5) == "echo ") {
             reply(message, command.substr(5));
@@ -158,3 +157,4 @@ public:
 
     ::dsn::error_code stop(bool cleanup = false) { return ERR_OK; }
 };
+} // namespace dsn
diff --git a/src/security/test/client_negotiation_test.cpp 
b/src/security/test/client_negotiation_test.cpp
index a22a1d171..fcfaf6122 100644
--- a/src/security/test/client_negotiation_test.cpp
+++ b/src/security/test/client_negotiation_test.cpp
@@ -40,7 +40,8 @@ public:
     {
         std::unique_ptr<tools::sim_network_provider> sim_net(
             new tools::sim_network_provider(nullptr, nullptr));
-        _sim_session = sim_net->create_client_session(rpc_address("localhost", 
10086));
+        _sim_session =
+            
sim_net->create_client_session(rpc_address::from_host_port("localhost", 10086));
         _client_negotiation = 
std::make_unique<client_negotiation>(_sim_session);
     }
 
diff --git a/src/security/test/main.cpp b/src/security/test/main.cpp
index 0edcfcaa1..e43ee68ee 100644
--- a/src/security/test/main.cpp
+++ b/src/security/test/main.cpp
@@ -30,7 +30,7 @@ GTEST_API_ int main(int argc, char **argv)
 {
     testing::InitGoogleTest(&argc, argv);
 
-    dsn::service_app::register_factory<test_client>("test");
+    dsn::service_app::register_factory<dsn::test_client>("test");
     dsn_run(argc, argv, false);
     while (g_test_count == 0) {
         std::this_thread::sleep_for(std::chrono::seconds(1));
diff --git a/src/security/test/meta_access_controller_test.cpp 
b/src/security/test/meta_access_controller_test.cpp
index 2816d359d..11fc1c588 100644
--- a/src/security/test/meta_access_controller_test.cpp
+++ b/src/security/test/meta_access_controller_test.cpp
@@ -98,7 +98,8 @@ TEST_F(meta_access_controller_test, allowed)
 
     std::unique_ptr<tools::sim_network_provider> sim_net(
         new tools::sim_network_provider(nullptr, nullptr));
-    auto sim_session = sim_net->create_client_session(rpc_address("localhost", 
10086));
+    auto sim_session =
+        
sim_net->create_client_session(rpc_address::from_host_port("localhost", 10086));
     for (const auto &test : tests) {
         dsn::message_ptr msg = message_ex::create_request(test.rpc_code);
         msg->io_session = sim_session;
diff --git a/src/security/test/negotiation_manager_test.cpp 
b/src/security/test/negotiation_manager_test.cpp
index 7030e8711..dbf79db51 100644
--- a/src/security/test/negotiation_manager_test.cpp
+++ b/src/security/test/negotiation_manager_test.cpp
@@ -45,8 +45,8 @@ public:
     {
         std::unique_ptr<tools::sim_network_provider> sim_net(
             new tools::sim_network_provider(nullptr, nullptr));
-        auto sim_session =
-            sim_net->create_server_session(rpc_address("localhost", 10086), 
rpc_session_ptr());
+        auto sim_session = sim_net->create_server_session(
+            rpc_address::from_host_port("localhost", 10086), 
rpc_session_ptr());
         auto rpc = negotiation_rpc(std::make_unique<negotiation_request>(), 
RPC_NEGOTIATION);
         rpc.dsn_request()->io_session = sim_session;
         return rpc;
@@ -57,9 +57,9 @@ public:
         std::unique_ptr<tools::sim_network_provider> sim_net(
             new tools::sim_network_provider(nullptr, nullptr));
         if (is_client) {
-            return sim_net->create_client_session(rpc_address("localhost", 
10086));
+            return 
sim_net->create_client_session(rpc_address::from_host_port("localhost", 10086));
         } else {
-            return sim_net->create_server_session(rpc_address("localhost", 
10086),
+            return 
sim_net->create_server_session(rpc_address::from_host_port("localhost", 10086),
                                                   rpc_session_ptr());
         }
     }
diff --git a/src/security/test/replica_access_controller_test.cpp 
b/src/security/test/replica_access_controller_test.cpp
index 1b2d45c5a..998d828b9 100644
--- a/src/security/test/replica_access_controller_test.cpp
+++ b/src/security/test/replica_access_controller_test.cpp
@@ -73,7 +73,8 @@ TEST_F(replica_access_controller_test, allowed)
 
     std::unique_ptr<tools::sim_network_provider> sim_net(
         new tools::sim_network_provider(nullptr, nullptr));
-    auto sim_session = sim_net->create_client_session(rpc_address("localhost", 
10086));
+    auto sim_session =
+        
sim_net->create_client_session(rpc_address::from_host_port("localhost", 10086));
     dsn::message_ptr msg = message_ex::create_request(RPC_CM_LIST_APPS);
     msg->io_session = sim_session;
 
diff --git a/src/security/test/server_negotiation_test.cpp 
b/src/security/test/server_negotiation_test.cpp
index 99e57145a..92b5b0b18 100644
--- a/src/security/test/server_negotiation_test.cpp
+++ b/src/security/test/server_negotiation_test.cpp
@@ -39,8 +39,8 @@ public:
     {
         std::unique_ptr<tools::sim_network_provider> sim_net(
             new tools::sim_network_provider(nullptr, nullptr));
-        _sim_session =
-            sim_net->create_server_session(rpc_address("localhost", 10086), 
rpc_session_ptr());
+        _sim_session = sim_net->create_server_session(
+            rpc_address::from_host_port("localhost", 10086), 
rpc_session_ptr());
         _srv_negotiation = std::make_unique<server_negotiation>(_sim_session);
     }
 
diff --git a/src/shell/command_utils.cpp b/src/shell/command_utils.cpp
index acc5604f4..afe08ffe8 100644
--- a/src/shell/command_utils.cpp
+++ b/src/shell/command_utils.cpp
@@ -30,7 +30,8 @@ bool validate_ip(shell_context *sc,
                  dsn::rpc_address &target_address,
                  std::string &err_info)
 {
-    if (!target_address.from_string_ipv4(ip_str.c_str())) {
+    target_address = dsn::rpc_address::from_ip_port(ip_str);
+    if (!target_address) {
         err_info = fmt::format("invalid ip:port={}, can't transform it into 
rpc_address", ip_str);
         return false;
     }
diff --git a/src/shell/commands/node_management.cpp 
b/src/shell/commands/node_management.cpp
index 49a95c416..17a02be6e 100644
--- a/src/shell/commands/node_management.cpp
+++ b/src/shell/commands/node_management.cpp
@@ -317,7 +317,7 @@ bool ls_nodes(command_executor *e, shell_context *sc, 
arguments args)
             alive_node_count++;
         std::string status_str = dsn::enum_to_string(kv.second);
         status_str = status_str.substr(status_str.find("NS_") + 3);
-        std::string node_name = kv.first.to_std_string();
+        std::string node_name = kv.first.to_string();
         if (resolve_ip) {
             // TODO: put hostname_from_ip_port into common utils
             dsn::utils::hostname_from_ip_port(node_name.c_str(), &node_name);
@@ -631,8 +631,8 @@ bool remote_command(command_executor *e, shell_context *sc, 
arguments args)
         }
 
         for (std::string &token : tokens) {
-            dsn::rpc_address node;
-            if (!node.from_string_ipv4(token.c_str())) {
+            const auto node = dsn::rpc_address::from_host_port(token);
+            if (!node) {
                 fprintf(stderr, "parse %s as a ip:port node failed\n", 
token.c_str());
                 return true;
             }
diff --git a/src/shell/commands/rebalance.cpp b/src/shell/commands/rebalance.cpp
index 519fd9da6..5fb68ed8f 100644
--- a/src/shell/commands/rebalance.cpp
+++ b/src/shell/commands/rebalance.cpp
@@ -112,11 +112,12 @@ bool propose(command_executor *e, shell_context *sc, 
arguments args)
             proposal_type += optarg;
             break;
         case 't':
-            verify_logged(
-                target.from_string_ipv4(optarg), "parse %s as target_address 
failed\n", optarg);
+            target = dsn::rpc_address::from_host_port(optarg);
+            verify_logged(target, "parse %s as target_address failed\n", 
optarg);
             break;
         case 'n':
-            verify_logged(node.from_string_ipv4(optarg), "parse %s as node 
failed\n", optarg);
+            node = dsn::rpc_address::from_host_port(optarg);
+            verify_logged(node, "parse %s as node failed\n", optarg);
             break;
         default:
             return false;
@@ -173,13 +174,15 @@ bool balance(command_executor *e, shell_context *sc, 
arguments args)
             balance_type = optarg;
             break;
         case 'f':
-            if (!from.from_string_ipv4(optarg)) {
+            from = dsn::rpc_address::from_host_port(optarg);
+            if (!from) {
                 fprintf(stderr, "parse %s as from_address failed\n", optarg);
                 return false;
             }
             break;
         case 't':
-            if (!to.from_string_ipv4(optarg)) {
+            to = dsn::rpc_address::from_host_port(optarg);
+            if (!to) {
                 fprintf(stderr, "parse %s as target_address failed\n", optarg);
                 return false;
             }
diff --git a/src/shell/commands/recovery.cpp b/src/shell/commands/recovery.cpp
index a308d1907..13f262dc5 100644
--- a/src/shell/commands/recovery.cpp
+++ b/src/shell/commands/recovery.cpp
@@ -116,8 +116,8 @@ bool recover(command_executor *e, shell_context *sc, 
arguments args)
         }
 
         for (std::string &token : tokens) {
-            dsn::rpc_address node;
-            if (!node.from_string_ipv4(token.c_str())) {
+            const auto node = dsn::rpc_address::from_host_port(token);
+            if (!node) {
                 fprintf(stderr, "parse %s as a ip:port node failed\n", 
token.c_str());
                 return true;
             }
@@ -137,8 +137,8 @@ bool recover(command_executor *e, shell_context *sc, 
arguments args)
             boost::trim(str);
             if (str.empty() || str[0] == '#' || str[0] == ';')
                 continue;
-            dsn::rpc_address node;
-            if (!node.from_string_ipv4(str.c_str())) {
+            const auto node = dsn::rpc_address::from_host_port(str);
+            if (!node) {
                 fprintf(stderr,
                         "parse %s at file %s line %d as ip:port failed\n",
                         str.c_str(),
@@ -360,12 +360,12 @@ bool ddd_diagnose(command_executor *e, shell_context *sc, 
arguments args)
                     std::cout << "    > Please input the primary node: ";
                     std::string addr;
                     std::cin >> addr;
-                    if (primary.from_string_ipv4(addr.c_str())) {
+                    primary = dsn::rpc_address::from_host_port(addr);
+                    if (primary) {
                         break;
-                    } else {
-                        std::cout << "    > Sorry, you have input an invalid 
node address."
-                                  << std::endl;
                     }
+                    std::cout << "    > Sorry, you have input an invalid node 
address."
+                              << std::endl;
                 } while (true);
             }
 
diff --git a/src/test/function_test/recovery/test_recovery.cpp 
b/src/test/function_test/recovery/test_recovery.cpp
index 479449884..9bfdfd993 100644
--- a/src/test/function_test/recovery/test_recovery.cpp
+++ b/src/test/function_test/recovery/test_recovery.cpp
@@ -19,6 +19,7 @@
 
 #include <fmt/core.h>
 #include <chrono>
+#include <cstdint>
 #include <iostream>
 #include <map>
 #include <memory>
@@ -70,13 +71,12 @@ public:
     // cluster has only one meta server, while "onebox" means the cluster has 
3 meta servers.
     recovery_test() : test_util(std::map<std::string, std::string>(), 
"single_master_cluster") {}
 
-    std::vector<dsn::rpc_address> get_rpc_address_list(const std::vector<int> 
ports)
+    std::vector<dsn::rpc_address> get_rpc_address_list(const 
std::vector<uint16_t> &ports)
     {
         std::vector<dsn::rpc_address> result;
         result.reserve(ports.size());
-        for (const int &p : ports) {
-            dsn::rpc_address address(global_env::instance()._host_ip.c_str(), 
p);
-            result.push_back(address);
+        for (const auto &port : ports) {
+            
result.emplace_back(dsn::rpc_address(global_env::instance()._host_ip, port));
         }
         return result;
     }
diff --git a/src/test/function_test/utils/global_env.cpp 
b/src/test/function_test/utils/global_env.cpp
index 7f7e64b9a..a703fefd2 100644
--- a/src/test/function_test/utils/global_env.cpp
+++ b/src/test/function_test/utils/global_env.cpp
@@ -19,12 +19,7 @@
 
 #include "global_env.h"
 
-#include <arpa/inet.h>
 #include <libgen.h>
-#include <netinet/in.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/socket.h>
 #include <unistd.h>
 #include <iostream>
 #include <sstream> // IWYU pragma: keep
@@ -61,12 +56,4 @@ void global_env::get_dirs()
     std::cout << "working dir: " << _working_dir << std::endl;
 }
 
-void global_env::get_hostip()
-{
-    uint32_t ip = dsn::rpc_address::ipv4_from_network_interface("lo");
-    uint32_t ipnet = htonl(ip);
-    char buffer[512] = {0};
-    memset(buffer, 0, sizeof(buffer));
-    CHECK(inet_ntop(AF_INET, &ipnet, buffer, sizeof(buffer)), "");
-    _host_ip = buffer;
-}
+void global_env::get_hostip() { _host_ip = 
dsn::rpc_address::ipv4_from_network_interface("lo"); }
diff --git a/src/test/function_test/utils/global_env.h 
b/src/test/function_test/utils/global_env.h
index 25d694848..b7313384b 100644
--- a/src/test/function_test/utils/global_env.h
+++ b/src/test/function_test/utils/global_env.h
@@ -19,6 +19,7 @@
 
 #pragma once
 
+#include <stdint.h>
 #include <string>
 
 #include "utils/singleton.h"
@@ -28,7 +29,7 @@ class global_env : public dsn::utils::singleton<global_env>
 public:
     std::string _pegasus_root;
     std::string _working_dir;
-    std::string _host_ip;
+    uint32_t _host_ip;
 
 private:
     global_env();
diff --git a/src/test/kill_test/kill_testor.cpp 
b/src/test/kill_test/kill_testor.cpp
index 7c01eb142..b10abbe5f 100644
--- a/src/test/kill_test/kill_testor.cpp
+++ b/src/test/kill_test/kill_testor.cpp
@@ -122,13 +122,13 @@ dsn::error_code kill_testor::get_partition_info(bool 
debug_unhealthy,
             } else {
                 std::stringstream info;
                 info << "gpid=" << p.pid.get_app_id() << "." << 
p.pid.get_partition_index() << ", ";
-                info << "primay=" << p.primary.to_std_string() << ", ";
+                info << "primay=" << p.primary << ", ";
                 info << "secondaries=[";
                 for (int idx = 0; idx < p.secondaries.size(); idx++) {
                     if (idx != 0)
-                        info << "," << p.secondaries[idx].to_std_string();
+                        info << "," << p.secondaries[idx];
                     else
-                        info << p.secondaries[idx].to_std_string();
+                        info << p.secondaries[idx];
                 }
                 info << "], ";
                 info << "last_committed_decree=" << p.last_committed_decree;
diff --git a/src/utils/errors.h b/src/utils/errors.h
index 369eef662..342621151 100644
--- a/src/utils/errors.h
+++ b/src/utils/errors.h
@@ -245,3 +245,9 @@ USER_DEFINED_STRUCTURE_FORMATTER(::dsn::error_s);
             return dsn::error_s::make(code, fmt::format(__VA_ARGS__));         
                    \
         }                                                                      
                    \
     } while (false)
+
+#ifndef NDEBUG
+#define DCHECK_OK CHECK_OK
+#else
+#define DCHECK_OK(s, ...)
+#endif
diff --git a/src/utils/test/hostname_test.cpp b/src/utils/test/hostname_test.cpp
index 87489bdd9..3a2f3e11e 100644
--- a/src/utils/test/hostname_test.cpp
+++ b/src/utils/test/hostname_test.cpp
@@ -25,34 +25,6 @@
 namespace dsn {
 namespace replication {
 
-TEST(ip_to_hostname, ipv4_validate)
-{
-    rpc_address rpc_test_ipv4;
-    struct ip_test
-    {
-        std::string ip;
-        bool result;
-    } tests[] = {{"127.0.0.1:8080", true},
-                 {"172.16.254.1:1234", true},
-                 {"172.16.254.1:222222", false},
-                 {"172.16.254.1", false},
-                 {"2222,123,33,1:8080", false},
-                 {"123.456.789.1:8080", false},
-                 {"001.223.110.002:8080", false},
-                 {"172.16.254.1.8080", false},
-                 {"172.16.254.1:8080.", false},
-                 {"127.0.0.11:123!", false},
-                 {"127.0.0.11:123", true},
-                 {"localhost:34601", true},
-                 {"localhost:3460100022212312312213", false},
-                 {"localhost:-12", false},
-                 {"localhost:1@2", false}};
-
-    for (auto test : tests) {
-        ASSERT_EQ(rpc_test_ipv4.from_string_ipv4(test.ip.c_str()), 
test.result);
-    }
-}
-
 TEST(ip_to_hostname, localhost)
 {
     std::string hostname_result;
@@ -69,8 +41,7 @@ TEST(ip_to_hostname, localhost)
     const std::string valid_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_valid;
-    rpc_example_valid.assign_ipv4(valid_ip.c_str(), 23010);
+    const auto rpc_example_valid = rpc_address::from_ip_port(valid_ip, 23010);
 
     // static bool hostname(const rpc_address &address,std::string 
*hostname_result);
     ASSERT_TRUE(dsn::utils::hostname(rpc_example_valid, &hostname_result));
diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp
index c3ebb8c9f..be0d92e18 100644
--- a/src/utils/utils.cpp
+++ b/src/utils/utils.cpp
@@ -98,8 +98,8 @@ bool hostname_from_ip(const char *ip, std::string 
*hostname_result)
 
 bool hostname_from_ip_port(const char *ip_port, std::string *hostname_result)
 {
-    dsn::rpc_address addr;
-    if (!addr.from_string_ipv4(ip_port)) {
+    const auto addr = dsn::rpc_address::from_ip_port(ip_port);
+    if (!addr) {
         LOG_WARNING("invalid ip_port({})", ip_port);
         *hostname_result = ip_port;
         return false;
diff --git a/src/zookeeper/zookeeper_session.cpp 
b/src/zookeeper/zookeeper_session.cpp
index 18ed6ea83..ae3618795 100644
--- a/src/zookeeper/zookeeper_session.cpp
+++ b/src/zookeeper/zookeeper_session.cpp
@@ -162,8 +162,7 @@ int zookeeper_session::attach(void *callback_owner, const 
state_callback &cb)
             zoo_sasl_params_t sasl_params = {0};
             sasl_params.service = FLAGS_zookeeper_kerberos_service_name;
             sasl_params.mechlist = "GSSAPI";
-            rpc_address addr;
-            CHECK(addr.from_string_ipv4(FLAGS_zookeeper_sasl_service_fqdn),
+            
CHECK(dsn::rpc_address::from_host_port(FLAGS_zookeeper_sasl_service_fqdn),
                   "zookeeper_sasl_service_fqdn {} is invalid",
                   FLAGS_zookeeper_sasl_service_fqdn);
             sasl_params.host = FLAGS_zookeeper_sasl_service_fqdn;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to