LogCabin
RPC/Address.cc
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines