1 // ***************************************************************************
2 // HostInfo_p.cpp (c) 2011 Derek Barnett
3 // Marth Lab, Department of Biology, Boston College
4 // ---------------------------------------------------------------------------
5 // Last modified: 8 December 2011 (DB)
6 // ---------------------------------------------------------------------------
7 // Provides DNS lookup functionality for hostname & its discovered addresses
8 // ***************************************************************************
10 #include "api/internal/io/HostInfo_p.h"
11 using namespace BamTools;
12 using namespace BamTools::Internal;
16 # include "api/internal/io/NetWin_p.h"
18 # include "api/internal/io/NetUnix_p.h"
21 // standard C++ includes
27 // -------------------------
28 // HostInfo implementation
29 // -------------------------
31 HostInfo::HostInfo(void)
32 : m_error(HostInfo::NoError)
35 HostInfo::HostInfo(const HostInfo& other)
36 : m_hostName(other.m_hostName)
37 , m_addresses(other.m_addresses)
38 , m_error(other.m_error)
39 , m_errorString(other.m_errorString)
42 HostInfo::~HostInfo(void) { }
44 vector<HostAddress> HostInfo::Addresses(void) const {
48 HostInfo::ErrorType HostInfo::GetError(void) const {
52 string HostInfo::GetErrorString(void) const {
56 string HostInfo::HostName(void) const {
60 void HostInfo::SetAddresses(const std::vector<HostAddress>& addresses) {
61 m_addresses = addresses;
64 void HostInfo::SetError(const HostInfo::ErrorType error) {
68 void HostInfo::SetErrorString(const std::string& errorString) {
69 m_errorString = errorString;
72 void HostInfo::SetHostName(const string& name) {
76 // ---------------------------------
77 // HostInfo::Lookup(host, port)
78 // - the real "heavy-lifter" here
79 // ---------------------------------
81 HostInfo HostInfo::Lookup(const string& hostname, const string& port) {
84 result.SetHostName(hostname);
85 set<HostAddress> uniqueAddresses;
92 address.SetAddress(hostname);
94 // if hostname is an IP string ('0.0.0.0' or IPv6 format)
95 // do reverse lookup for host domain name
97 // TODO: might just remove this... not sure if proper 'hostname' from IP string is needed
99 // so far, haven't been able to successfully fetch a domain name with reverse DNS
100 // getnameinfo() on test sites just returns original IP string. BUT this is likely a rare
101 // case that client code tries to use an IP string and the connection should work fine
102 // anyway. GetHostName() just won't quite show what I was hoping for. :(
103 if ( address.HasIPAddress() ) {
105 const uint16_t portNum = static_cast<uint16_t>( atoi(port.c_str()) );
110 BT_SOCKLEN_T saSize = 0;
113 if ( address.GetProtocol() == HostAddress::IPv4Protocol ) {
114 sa = (sockaddr*)&sa4;
115 saSize = sizeof(sa4);
116 memset(&sa4, 0, sizeof(sa4));
117 sa4.sin_family = AF_INET;
118 sa4.sin_addr.s_addr = htonl(address.GetIPv4Address());
119 sa4.sin_port = htons(portNum);
123 else if ( address.GetProtocol() == HostAddress::IPv4Protocol ){
124 sa = (sockaddr*)&sa6;
125 saSize = sizeof(sa6);
126 memset(&sa6, 0, sizeof(sa6));
127 sa6.sin6_family = AF_INET6;
128 memcpy(sa6.sin6_addr.s6_addr, address.GetIPv6Address().data, sizeof(sa6.sin6_addr.s6_addr));
129 sa6.sin6_port = htons(portNum);
132 // unknown (should be unreachable)
133 else BT_ASSERT_X(false, "HostInfo::Lookup: unknown network protocol");
135 // lookup name for IP
136 char hbuf[NI_MAXHOST];
137 char serv[NI_MAXSERV];
138 if ( sa && (getnameinfo(sa, saSize, hbuf, sizeof(hbuf), serv, sizeof(serv), 0) == 0) )
139 result.SetHostName(string(hbuf));
141 // if no domain name found, just use the original address's IP string
142 if ( result.HostName().empty() )
143 result.SetHostName(address.GetIPString());
145 // store address in HostInfo
146 uniqueAddresses.insert(address);
149 // otherwise, hostname is a domain name ('www.foo.bar')
150 // do 'normal' lookup
153 // setup address lookup 'hints'
155 memset(&hints, 0, sizeof(hints));
156 hints.ai_family = AF_UNSPEC; // allow either IPv4 or IPv6
157 hints.ai_socktype = SOCK_STREAM; // for TCP
158 hints.ai_protocol = IPPROTO_TCP;
160 // fetch addresses for requested hostname/port
162 int status = getaddrinfo(hostname.c_str(), port.c_str(), &hints, &res );
167 // iterate over all IP addresses found
169 for ( ; p != NULL; p = p->ai_next ) {
172 if ( p->ai_family == AF_INET ) {
173 sockaddr_in* ipv4 = (sockaddr_in*)p->ai_addr;
174 HostAddress a( ntohl(ipv4->sin_addr.s_addr) );
175 uniqueAddresses.insert(a);
179 else if ( p->ai_family == AF_INET6 ) {
180 sockaddr_in6* ipv6 = (sockaddr_in6*)p->ai_addr;
181 HostAddress a(ipv6->sin6_addr.s6_addr);
182 uniqueAddresses.insert(a);
186 // if we iterated, but no addresses were stored
187 if ( uniqueAddresses.empty() && (p == NULL) ) {
188 result.SetError(HostInfo::UnknownError);
189 result.SetErrorString("HostInfo: unknown address types found");
193 // handle error cases
197 || status == EAI_FAIL
199 || status == EAI_NODATA // officially deprecated, but just in case we happen to hit it
200 # endif // EAI_NODATA
203 WSAGetLastError() == WSAHOST_NOT_FOUND
204 || WSAGetLastError() == WSANO_DATA
205 || WSAGetLastError() == WSANO_RECOVERY
209 result.SetError(HostInfo::HostNotFound);
210 result.SetErrorString("HostInfo: host not found");
213 result.SetError(HostInfo::UnknownError);
214 result.SetErrorString("HostInfo: unknown error encountered");
221 // store fetched addresses (converting set -> vector) in result & return
222 result.SetAddresses( vector<HostAddress>(uniqueAddresses.begin(), uniqueAddresses.end()) );