LogCabin
|
00001 /* Copyright (c) 2012 Stanford University 00002 * Copyright (c) 2014 Diego Ongaro 00003 * 00004 * Permission to use, copy, modify, and distribute this software for any 00005 * purpose with or without fee is hereby granted, provided that the above 00006 * copyright notice and this permission notice appear in all copies. 00007 * 00008 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES 00009 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 00010 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR 00011 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 00012 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 00013 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 00014 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00015 */ 00016 00017 #include <arpa/inet.h> 00018 #include <netdb.h> 00019 #include <netinet/ip.h> 00020 #include <string.h> 00021 #include <sys/types.h> 00022 00023 #include <sstream> 00024 #include <vector> 00025 00026 #include "Core/Debug.h" 00027 #include "Core/Endian.h" 00028 #include "Core/Random.h" 00029 #include "Core/StringUtil.h" 00030 #include "RPC/Address.h" 00031 00032 namespace LogCabin { 00033 namespace RPC { 00034 00035 Address::Address(const std::string& str, uint16_t defaultPort) 00036 : originalString(str) 00037 , hosts() 00038 , storage() 00039 , len(0) 00040 { 00041 memset(&storage, 0, sizeof(storage)); 00042 00043 std::vector<std::string> hostsList = Core::StringUtil::split(str, ','); 00044 for (auto it = hostsList.begin(); it != hostsList.end(); ++it) { 00045 std::string host = *it; 00046 std::string port; 00047 if (host.empty()) 00048 continue; 00049 00050 size_t lastColon = host.rfind(':'); 00051 if (lastColon != host.npos && 00052 host.find(']', lastColon) == host.npos) { 00053 // following lastColon is a port number 00054 port = host.substr(lastColon + 1); 00055 host.erase(lastColon); 00056 } else { 00057 // use default port 00058 port = Core::StringUtil::toString(defaultPort); 00059 } 00060 00061 // IPv6 hosts are surrounded in brackets. These need to be stripped. 00062 if (host.at(0) == '[' && 00063 host.at(host.length() - 1) == ']') { 00064 host = host.substr(1, host.length() - 2); 00065 } 00066 00067 hosts.push_back({host, port}); 00068 } 00069 } 00070 00071 Address::Address() 00072 : originalString("") 00073 , hosts() 00074 , storage() 00075 , len(0) 00076 { 00077 } 00078 00079 Address::Address(const Address& other) 00080 : originalString(other.originalString) 00081 , hosts(other.hosts) 00082 , storage() 00083 , len(other.len) 00084 { 00085 memcpy(&storage, &other.storage, sizeof(storage)); 00086 } 00087 00088 Address& 00089 Address::operator=(const Address& other) 00090 { 00091 originalString = other.originalString; 00092 hosts = other.hosts; 00093 memcpy(&storage, &other.storage, sizeof(storage)); 00094 len = other.len; 00095 return *this; 00096 } 00097 00098 bool 00099 Address::isValid() const 00100 { 00101 return len > 0; 00102 } 00103 00104 const sockaddr* 00105 Address::getSockAddr() const 00106 { 00107 return reinterpret_cast<const sockaddr*>(&storage); 00108 } 00109 00110 socklen_t 00111 Address::getSockAddrLen() const 00112 { 00113 return len; 00114 } 00115 00116 std::string 00117 Address::getResolvedString() const 00118 { 00119 std::stringstream ret; 00120 switch (getSockAddr()->sa_family) { 00121 case AF_UNSPEC: 00122 return "Unspecified"; 00123 case AF_INET: { 00124 const sockaddr_in* addr = 00125 reinterpret_cast<const sockaddr_in*>(getSockAddr()); 00126 char ipBuf[INET_ADDRSTRLEN]; 00127 ret << inet_ntop(AF_INET, &addr->sin_addr, 00128 ipBuf, sizeof(ipBuf)); 00129 ret << ":"; 00130 ret << be16toh(addr->sin_port); 00131 break; 00132 } 00133 case AF_INET6: { 00134 const sockaddr_in6* addr = 00135 reinterpret_cast<const sockaddr_in6*>(getSockAddr()); 00136 char ipBuf[INET6_ADDRSTRLEN]; 00137 ret << "["; 00138 ret << inet_ntop(AF_INET6, &addr->sin6_addr, 00139 ipBuf, sizeof(ipBuf)); 00140 ret << "]:"; 00141 ret << be16toh(addr->sin6_port); 00142 break; 00143 } 00144 default: 00145 return "Unknown protocol"; 00146 } 00147 return ret.str(); 00148 } 00149 00150 std::string 00151 Address::toString() const 00152 { 00153 if (originalString.empty()) { 00154 return "No address given"; 00155 } else { 00156 return Core::StringUtil::format( 00157 "%s (resolved to %s)", 00158 originalString.c_str(), 00159 getResolvedString().c_str()); 00160 } 00161 } 00162 00163 void 00164 Address::refresh(TimePoint timeout) 00165 { 00166 if (hosts.empty()) 00167 return; 00168 size_t hostIdx = Core::Random::random32() % hosts.size(); 00169 const std::string& host = hosts.at(hostIdx).first; 00170 const std::string& port = hosts.at(hostIdx).second; 00171 VERBOSE("Running getaddrinfo for host %s with port %s", 00172 host.c_str(), port.c_str()); 00173 00174 addrinfo hints; 00175 memset(&hints, 0, sizeof(hints)); 00176 hints.ai_family = AF_UNSPEC; 00177 hints.ai_socktype = SOCK_STREAM; 00178 hints.ai_protocol = 0; 00179 hints.ai_flags = AI_NUMERICSERV | AI_V4MAPPED | AI_ADDRCONFIG; 00180 00181 addrinfo* result = NULL; 00182 int r = getaddrinfo(host.c_str(), port.c_str(), &hints, &result); 00183 switch (r) { 00184 // Success. 00185 case 0: { 00186 // Look for IPv4 and IPv6 addresses. 00187 std::vector<addrinfo*> candidates; 00188 for (addrinfo* addr = result; addr != NULL; addr = addr->ai_next) { 00189 if (addr->ai_family == AF_INET || 00190 addr->ai_family == AF_INET6) { 00191 candidates.push_back(addr); 00192 } 00193 } 00194 if (!candidates.empty()) { 00195 // Select one randomly and hope it works. 00196 size_t idx = Core::Random::random32() % candidates.size(); 00197 addrinfo* addr = candidates.at(idx); 00198 memcpy(&storage, addr->ai_addr, addr->ai_addrlen); 00199 len = addr->ai_addrlen; 00200 } 00201 break; 00202 } 00203 00204 // These are somewhat normal errors. 00205 case EAI_FAMILY: 00206 break; 00207 case EAI_NONAME: 00208 break; 00209 case EAI_NODATA: 00210 break; 00211 00212 // This is unexpected. 00213 default: 00214 WARNING("Unknown error from getaddrinfo(\"%s\", \"%s\"): %s", 00215 host.c_str(), port.c_str(), gai_strerror(r)); 00216 } 00217 if (result != NULL) 00218 freeaddrinfo(result); 00219 00220 VERBOSE("Result: %s", toString().c_str()); 00221 } 00222 00223 00224 } // namespace LogCabin::RPC 00225 } // namespace LogCabin