2 * @brief Resolve hostnames and ip addresses
4 /* Copyright (C) 2017,2018,2024 Olly Betts
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #ifndef XAPIAN_INCLUDED_RESOLVER_H
22 #define XAPIAN_INCLUDED_RESOLVER_H
26 #include <string_view>
28 #include "safenetdb.h"
29 #include "safesyssocket.h"
31 #include "xapian/error.h"
34 struct addrinfo
* result
= NULL
;
36 int eai_to_xapian(int e
) {
37 // Under WIN32, the EAI_* constants are defined to be WSA_* constants
38 // with roughly equivalent meanings, so we can just let them be handled
39 // as any other WSA_* error codes would be.
41 // Ensure they all have the same sign - this switch will fail to
42 // compile if we bitwise-or some 1 and some 2 bits to get 3.
43 #define C(X) ((X) < 0 ? 2 : 1)
44 // Switch on a value there is a case for, to avoid clang warning: "no
45 // case matching constant switch condition '0'"
58 // In RFC 2553 but not RFC 3493 or POSIX:
62 // In RFC 2553 but not RFC 3493 or POSIX:
66 // In RFC 3493 and POSIX but not RFC 2553:
74 // EAI_SYSTEM means "look at errno".
77 // POSIX only says that EAI_* constants are "non-zero". On Linux they
78 // are negative, but allow for them being positive too.
86 class const_iterator
{
89 explicit const_iterator(struct addrinfo
* p_
) : p(p_
) { }
91 struct addrinfo
& operator*() const {
99 const_iterator
operator++(int) {
100 struct addrinfo
* old_p
= p
;
102 return const_iterator(old_p
);
105 bool operator==(const const_iterator
& o
) const {
109 bool operator!=(const const_iterator
& o
) const {
110 return !(*this == o
);
114 Resolver(std::string_view host
, int port
, int flags
= 0) {
115 using namespace std::string_literals
;
116 // RFC 3493 has an extra sentence in its definition of
117 // AI_ADDRCONFIG which POSIX doesn't:
119 // "The loopback address is not considered for this case as valid
120 // as a configured address."
122 // Some platforms implement this version rather than POSIX (notably
123 // glibc on Linux). Others implement POSIX (from looking at the
124 // man pages, these include FreeBSD 11.0).
126 // In most cases, this extra sentence is arguably helpful - e.g. it
127 // means that you won't get IPv6 addresses just because the system
128 // has IPv6 loopback (and similarly for IPv4).
130 // However, it behaves unhelpfully if the *only* interface
131 // configured is loopback - in this situation, AI_ADDRCONFIG means
132 // that you won't get an IPv4 address (as there's no IPv4 address
133 // configured ignoring loopback) and you won't get an IPv6 address
134 // (as there's no IPv6 address configured ignoring loopback).
136 // It's generally rare that systems with only loopback would want
137 // to use the remote backend, but a real example is testsuites
138 // (including our own) running on autobuilders which deliberately
139 // close off network access.
141 // To allow such cases to work on Linux (and other platforms which
142 // follow the RFC rather than POSIX in this detail) we avoid using
143 // AI_ADDRCONFIG for 127.0.0.1, ::1 and localhost. There are
144 // other ways to write these IP addresses and other hostnames may
145 // map onto them, but this just needs to work for the standard
146 // cases which a testsuite might use.
147 if (host
!= "::1" && host
!= "127.0.0.1" && host
!= "localhost") {
148 flags
|= AI_ADDRCONFIG
;
150 // Not defined on older macOS (such as 10.5 which Apple no longer
151 // support but newer versions no longer support PowerPC Macs).
152 #ifdef AI_NUMERICSERV
153 flags
|= AI_NUMERICSERV
;
156 struct addrinfo hints
;
157 std::memset(&hints
, 0, sizeof(struct addrinfo
));
158 hints
.ai_family
= AF_UNSPEC
;
159 hints
.ai_socktype
= SOCK_STREAM
;
160 hints
.ai_flags
= flags
;
161 hints
.ai_protocol
= 0;
163 int r
= getaddrinfo(host
.empty() ? nullptr : str(host
).c_str(),
164 str(port
).c_str(), &hints
, &result
);
166 throw Xapian::NetworkError("Couldn't resolve host "s
.append(host
),
172 if (result
) freeaddrinfo(result
);
175 const_iterator
begin() const {
176 return const_iterator(result
);
179 const_iterator
end() const {
180 return const_iterator(NULL
);
184 #endif // XAPIAN_INCLUDED_RESOLVER_H