xapian-core  2.0.0
resolver.h
Go to the documentation of this file.
1 
4 /* Copyright (C) 2017,2018,2024 Olly Betts
5  *
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.
10  *
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.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see
18  * <https://www.gnu.org/licenses/>.
19  */
20 
21 #ifndef XAPIAN_INCLUDED_RESOLVER_H
22 #define XAPIAN_INCLUDED_RESOLVER_H
23 
24 #include <cerrno>
25 #include <cstring>
26 #include <string_view>
27 
28 #include "safenetdb.h"
29 #include "safesyssocket.h"
30 #include "str.h"
31 #include "xapian/error.h"
32 
33 class Resolver {
34  struct addrinfo* result = NULL;
35 
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.
40 #ifndef __WIN32__
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'"
46  switch (3) {
47  case
48  C(EAI_AGAIN)|
49  C(EAI_BADFLAGS)|
50  C(EAI_FAIL)|
51  C(EAI_FAMILY)|
52  C(EAI_MEMORY)|
53  C(EAI_NONAME)|
54  C(EAI_SERVICE)|
55  C(EAI_SOCKTYPE)|
56  C(EAI_SYSTEM)|
57 #ifdef EAI_ADDRFAMILY
58  // In RFC 2553 but not RFC 3493 or POSIX:
59  C(EAI_ADDRFAMILY)|
60 #endif
61 #ifdef EAI_NODATA
62  // In RFC 2553 but not RFC 3493 or POSIX:
63  C(EAI_NODATA)|
64 #endif
65 #ifdef EAI_OVERFLOW
66  // In RFC 3493 and POSIX but not RFC 2553:
67  C(EAI_OVERFLOW)|
68 #endif
69  0: break;
70  case 3: break;
71  }
72 #undef C
73 
74  // EAI_SYSTEM means "look at errno".
75  if (e == EAI_SYSTEM)
76  return errno;
77  // POSIX only says that EAI_* constants are "non-zero". On Linux they
78  // are negative, but allow for them being positive too.
79  if (EAI_FAIL > 0)
80  return -e;
81 #endif
82  return e;
83  }
84 
85  public:
87  struct addrinfo* p;
88  public:
89  explicit const_iterator(struct addrinfo* p_) : p(p_) { }
90 
91  struct addrinfo& operator*() const {
92  return *p;
93  }
94 
95  void operator++() {
96  p = p->ai_next;
97  }
98 
100  struct addrinfo* old_p = p;
101  operator++();
102  return const_iterator(old_p);
103  }
104 
105  bool operator==(const const_iterator& o) const {
106  return p == o.p;
107  }
108 
109  bool operator!=(const const_iterator& o) const {
110  return !(*this == o);
111  }
112  };
113 
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:
118  //
119  // "The loopback address is not considered for this case as valid
120  // as a configured address."
121  //
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).
125  //
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).
129  //
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).
135  //
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.
140  //
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;
149  }
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;
154 #endif
155 
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;
162 
163  int r = getaddrinfo(host.empty() ? nullptr : str(host).c_str(),
164  str(port).c_str(), &hints, &result);
165  if (r != 0) {
166  throw Xapian::NetworkError("Couldn't resolve host "s.append(host),
167  eai_to_xapian(r));
168  }
169  }
170 
172  if (result) freeaddrinfo(result);
173  }
174 
176  return const_iterator(result);
177  }
178 
179  const_iterator end() const {
180  return const_iterator(NULL);
181  }
182 };
183 
184 #endif // XAPIAN_INCLUDED_RESOLVER_H
bool operator!=(const const_iterator &o) const
Definition: resolver.h:109
bool operator==(const const_iterator &o) const
Definition: resolver.h:105
const_iterator operator++(int)
Definition: resolver.h:99
const_iterator(struct addrinfo *p_)
Definition: resolver.h:89
struct addrinfo * p
Definition: resolver.h:87
struct addrinfo & operator*() const
Definition: resolver.h:91
const_iterator end() const
Definition: resolver.h:179
int eai_to_xapian(int e)
Definition: resolver.h:36
Resolver(std::string_view host, int port, int flags=0)
Definition: resolver.h:114
const_iterator begin() const
Definition: resolver.h:175
struct addrinfo * result
Definition: resolver.h:34
~Resolver()
Definition: resolver.h:171
Indicates a problem communicating with a remote database.
Definition: error.h:791
Hierarchy of classes which Xapian can throw as exceptions.
string str(int value)
Convert int to std::string.
Definition: str.cc:91
#define C(X)
include <netdb.h>, with portability workarounds.
include <sys/socket.h> with portability workarounds.
Convert types to std::string.