1 /*
2   Copyright (c) DataStax, Inc.
3 
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7 
8   http://www.apache.org/licenses/LICENSE-2.0
9 
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15 */
16 
17 #include "address.hpp"
18 
19 #include "logger.hpp"
20 #include "macros.hpp"
21 #include "row.hpp"
22 #include "value.hpp"
23 
24 using namespace datastax;
25 using namespace datastax::internal::core;
26 
27 const Address Address::EMPTY_KEY(String(), 0);
28 const Address Address::DELETED_KEY(String(), 1);
29 
30 namespace {
31 
32 template <class T>
hash_combine(std::size_t & seed,const T & v)33 inline void hash_combine(std::size_t& seed, const T& v) {
34   SPARSEHASH_HASH<T> hasher;
35   seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
36 }
37 
38 } // namespace
39 
Address()40 Address::Address()
41     : family_(UNRESOLVED)
42     , port_(0) {}
43 
Address(const Address & other,const String & server_name)44 Address::Address(const Address& other, const String& server_name)
45     : hostname_or_address_(other.hostname_or_address_)
46     , server_name_(server_name)
47     , family_(other.family_)
48     , port_(other.port_) {}
49 
Address(const String & hostname,int port,const String & server_name)50 Address::Address(const String& hostname, int port, const String& server_name)
51     : server_name_(server_name)
52     , family_(UNRESOLVED)
53     , port_(port) {
54   char addr[16];
55   if (uv_inet_pton(AF_INET, hostname.c_str(), addr) == 0) {
56     hostname_or_address_.assign(addr, addr + 4);
57     family_ = IPv4;
58   } else if (uv_inet_pton(AF_INET6, hostname.c_str(), addr) == 0) {
59     hostname_or_address_.assign(addr, addr + 16);
60     family_ = IPv6;
61   } else {
62     hostname_or_address_ = hostname;
63   }
64 }
65 
Address(const uint8_t * address,uint8_t address_length,int port)66 Address::Address(const uint8_t* address, uint8_t address_length, int port)
67     : family_(UNRESOLVED)
68     , port_(port) {
69   if (address_length == 4) {
70     hostname_or_address_.assign(reinterpret_cast<const char*>(address), address_length);
71     family_ = IPv4;
72   } else if (address_length == 16) {
73     hostname_or_address_.assign(reinterpret_cast<const char*>(address), address_length);
74     family_ = IPv6;
75   }
76 }
77 
Address(const struct sockaddr * addr)78 Address::Address(const struct sockaddr* addr)
79     : family_(UNRESOLVED)
80     , port_(0) {
81   if (addr->sa_family == AF_INET) {
82     const struct sockaddr_in* addr_in = reinterpret_cast<const struct sockaddr_in*>(addr);
83     hostname_or_address_.assign(reinterpret_cast<const char*>(&addr_in->sin_addr), 4);
84     port_ = ntohs(addr_in->sin_port);
85     family_ = IPv4;
86   } else if (addr->sa_family == AF_INET6) {
87     const struct sockaddr_in6* addr_in6 = reinterpret_cast<const struct sockaddr_in6*>(addr);
88     hostname_or_address_.assign(reinterpret_cast<const char*>(&addr_in6->sin6_addr), 16);
89     port_ = ntohs(addr_in6->sin6_port);
90     family_ = IPv6;
91   }
92 }
93 
equals(const Address & other,bool with_port) const94 bool Address::equals(const Address& other, bool with_port) const {
95   if (family_ != other.family_) return false;
96   if (with_port && port_ != other.port_) return false;
97   if (server_name_ != other.server_name_) return false;
98   if (hostname_or_address_ != other.hostname_or_address_) return false;
99   return true;
100 }
101 
operator <(const Address & other) const102 bool Address::operator<(const Address& other) const {
103   if (family_ != other.family_) return family_ < other.family_;
104   if (port_ != other.port_) return port_ < other.port_;
105   if (server_name_ != other.server_name_) return server_name_ < other.server_name_;
106   return hostname_or_address_ < other.hostname_or_address_;
107 }
108 
hostname_or_address() const109 String Address::hostname_or_address() const {
110   if (family_ == IPv4) {
111     char name[INET_ADDRSTRLEN + 1] = { '\0' };
112     uv_inet_ntop(AF_INET, hostname_or_address_.data(), name, INET_ADDRSTRLEN);
113     return name;
114   } else if (family_ == IPv6) {
115     char name[INET6_ADDRSTRLEN + 1] = { '\0' };
116     uv_inet_ntop(AF_INET6, hostname_or_address_.data(), name, INET6_ADDRSTRLEN);
117     return name;
118   } else {
119     return hostname_or_address_;
120   }
121 }
122 
hash_code() const123 size_t Address::hash_code() const {
124   SPARSEHASH_HASH<Family> hasher;
125   size_t code = hasher(family_);
126   hash_combine(code, port_);
127   hash_combine(code, server_name_);
128   hash_combine(code, hostname_or_address_);
129   return code;
130 }
131 
to_inet(void * address) const132 uint8_t Address::to_inet(void* address) const {
133   if (family_ == IPv4 || family_ == IPv6) {
134     size_t size = hostname_or_address_.size();
135     assert((size == 4 || size == 16) && "Invalid size for address");
136     hostname_or_address_.copy(reinterpret_cast<char*>(address), size);
137     return static_cast<uint8_t>(size);
138   }
139   return 0;
140 }
141 
to_sockaddr(SocketStorage * storage) const142 const struct sockaddr* Address::to_sockaddr(SocketStorage* storage) const {
143   int rc = 0;
144   if (family_ == IPv4) {
145     char name[INET_ADDRSTRLEN + 1] = { '\0' };
146     rc = uv_inet_ntop(AF_INET, hostname_or_address_.data(), name, INET_ADDRSTRLEN);
147     if (rc != 0) return NULL;
148     rc = uv_ip4_addr(name, port_, storage->addr_in());
149   } else if (family_ == IPv6) {
150     char name[INET6_ADDRSTRLEN + 1] = { '\0' };
151     rc = uv_inet_ntop(AF_INET6, hostname_or_address_.data(), name, INET6_ADDRSTRLEN);
152     if (rc != 0) return NULL;
153     rc = uv_ip6_addr(name, port_, storage->addr_in6());
154   } else {
155     return NULL;
156   }
157   if (rc != 0) return NULL;
158   return storage->addr();
159 }
160 
to_string(bool with_port) const161 String Address::to_string(bool with_port) const {
162   OStringStream ss;
163   if (family_ == IPv6 && with_port) {
164     ss << "[" << hostname_or_address() << "]";
165   } else {
166     ss << hostname_or_address();
167   }
168   if (with_port) {
169     ss << ":" << port_;
170   }
171   if (!server_name_.empty()) {
172     ss << " (" << server_name_ << ")";
173   }
174   return ss.str();
175 }
176 
177 namespace datastax { namespace internal { namespace core {
178 
determine_listen_address(const Address & address,const Row * row)179 String determine_listen_address(const Address& address, const Row* row) {
180   const Value* v = row->get_by_name("peer");
181   if (v != NULL) {
182     Address listen_address;
183     if (v->decoder().as_inet(v->size(), address.port(), &listen_address)) {
184       return listen_address.to_string();
185     } else {
186       LOG_WARN("Invalid address format for listen address for host %s",
187                address.to_string().c_str());
188     }
189   }
190   return "";
191 }
192 
193 }}} // namespace datastax::internal::core
194