E-MailRelay

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

gresolverfuture.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2018 Graeme Walker <graeme_walker@users.sourceforge.net>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gresolverfuture.cpp
19 //
20
21 #include "gdef.h"
22 #include "gresolverfuture.h"
23 #include "gtest.h"
24 #include "gstr.h"
25 #include "gsleep.h"
26 #include "gdebug.h"
27 #include "gassert.h"
28 #include "glog.h"
29 #include <cstring>
30 #include <cstdio>
31
32 #ifndef AI_ADDRCONFIG
33 #define AI_ADDRCONFIG 0
34 #endif
35
36 GNet::ResolverFuture::ResolverFuture( const std::string & host , const std::string & service , int family ,
37 bool dgram , bool for_async_hint ) :
38 m_numeric_service(false) ,
39 m_socktype(dgram?SOCK_DGRAM:SOCK_STREAM) ,
40 m_host(host) ,
41 m_host_p(m_host.c_str()) ,
42 m_service(service) ,
43 m_service_p(m_service.c_str()) ,
44 m_family(family) ,
45 m_test_mode(for_async_hint&&G::Test::enabled("getaddrinfo-slow")) ,
46 m_rc(0) ,
47 m_ai(nullptr)
48 {
49 m_numeric_service = !service.empty() && G::Str::isNumeric(service) ;
50 std::memset( &m_ai_hint , 0 , sizeof(m_ai_hint) ) ;
51 m_ai_hint.ai_flags = AI_CANONNAME |
52 ( family == AF_UNSPEC ? AI_ADDRCONFIG : 0 ) |
53 ( m_numeric_service ? AI_NUMERICSERV : 0 ) ;
54 m_ai_hint.ai_family = family ;
55 m_ai_hint.ai_socktype = m_socktype ;
56 }
57
58 GNet::ResolverFuture::~ResolverFuture()
59 {
60 if( m_ai )
61 ::freeaddrinfo( m_ai ) ; // documented as "thread-safe"
62 }
63
64 void GNet::ResolverFuture::run()
65 {
66 // worker thread - as simple as possible
67 if( m_test_mode ) sleep( 10 ) ;
68 m_rc = ::getaddrinfo( m_host_p , m_service_p , &m_ai_hint , &m_ai ) ;
69 }
70
71 std::string GNet::ResolverFuture::failure() const
72 {
73 std::stringstream ss ;
74 if( m_numeric_service )
75 ss << "no such " << ipvx() << "host: \"" << m_host << "\"" ;
76 else
77 ss << "no such " << ipvx() << "host or service: \"" << m_host << ":" << m_service << "\"" ;
78 //ss << " (" << G::Str::lower(gai_strerror(m_rc)) << ")" ; // not portable
79 return ss.str() ;
80 }
81
82 std::string GNet::ResolverFuture::ipvx() const
83 {
84 if( m_family == AF_UNSPEC ) return std::string() ;
85 if( m_family == AF_INET ) return "ipv4 " ;
86 return "ipv6 " ; // AF_INET6 possibly undefined
87 }
88
89 bool GNet::ResolverFuture::failed() const
90 {
91 return m_rc != 0 || m_ai == nullptr || m_ai->ai_addr == nullptr || m_ai->ai_addrlen == 0 ;
92 }
93
94 std::string GNet::ResolverFuture::none() const
95 {
96 return "no usable addresses returned for \"" + m_host + "\"" ;
97 }
98
99 bool GNet::ResolverFuture::fetch( Pair & pair ) const
100 {
101 // fetch the first valid address/name pair
102 for( const struct addrinfo * p = m_ai ; p ; p = p->ai_next )
103 {
104 socklen_t addrlen = static_cast<socklen_t>(p->ai_addrlen) ;
105 if( Address::validData( p->ai_addr , addrlen ) )
106 {
107 Address address( p->ai_addr , addrlen ) ;
108 std::string name( p->ai_canonname ? p->ai_canonname : "" ) ;
109 pair = std::make_pair( address , name ) ;
110 return true ;
111 }
112 }
113 return false ;
114 }
115
116 bool GNet::ResolverFuture::fetch( List & list ) const
117 {
118 // fetch all valid addresses
119 for( const struct addrinfo * p = m_ai ; p ; p = p->ai_next )
120 {
121 socklen_t addrlen = static_cast<socklen_t>(p->ai_addrlen) ;
122 if( Address::validData( p->ai_addr , addrlen ) )
123 list.push_back( Address( p->ai_addr , addrlen ) ) ;
124 }
125 return !list.empty() ;
126 }
127
128 void GNet::ResolverFuture::get( List & list )
129 {
130 if( failed() )
131 m_reason = failure() ;
132 else if( !fetch(list) )
133 m_reason = none() ;
134 }
135
136 GNet::ResolverFuture::Pair GNet::ResolverFuture::get()
137 {
138 Pair result( Address::defaultAddress() , std::string() ) ;
139 if( failed() )
140 m_reason = failure() ;
141 else if( !fetch(result) )
142 m_reason = none() ;
143 return result ;
144 }
145
146 bool GNet::ResolverFuture::error() const
147 {
148 return !m_reason.empty() ;
149 }
150
151 std::string GNet::ResolverFuture::reason() const
152 {
153 return m_reason ;
154 }
155
156 /// \file gresolverfuture.cpp
gsleep.h
GNet::ResolverFuture::ResolverFuture
ResolverFuture(const std::string &host, const std::string &service, int family, bool dgram, bool for_async_hint=false)
Constructor for resolving the given host and service names.
Definition: gresolverfuture.cpp:36
GNet::Address::validData
static bool validData(const sockaddr *, socklen_t len)
Returns true if the sockaddr data is valid.
Definition: gaddress_ipv4.cpp:179
glog.h
GNet::ResolverFuture::reason
std::string reason() const
Returns the reason for the error().
Definition: gresolverfuture.cpp:151
G::Str::isNumeric
static bool isNumeric(const std::string &s, bool allow_minus_sign=false)
Returns true if every character is a decimal digit.
Definition: gstr.cpp:266
gtest.h
GNet::Address::defaultAddress
static Address defaultAddress()
Returns a default address, being the IPv4 wildcard address with a zero port number.
Definition: gaddress_ipv4.cpp:41
gstr.h
gassert.h
G
Low-level classes.
Definition: garg.h:29
GNet::ResolverFuture::error
bool error() const
Returns true if name resolution failed or no suitable address was returned.
Definition: gresolverfuture.cpp:146
GNet::ResolverFuture::~ResolverFuture
~ResolverFuture()
Destructor.
Definition: gresolverfuture.cpp:58
GNet::ResolverFuture::get
Pair get()
Returns the resolved address/name pair.
Definition: gresolverfuture.cpp:136
gresolverfuture.h
GNet::ResolverFuture::run
void run()
Does the name resolution.
Definition: gresolverfuture.cpp:64
gdebug.h