]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ipcache.h
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / ipcache.h
CommitLineData
bbc27441 1/*
f70aedc4 2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
bbc27441
AJ
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
714e68b7
AJ
9#ifndef _SQUID_IPCACHE_H
10#define _SQUID_IPCACHE_H
11
fd9c47d1 12#include "base/CbcPointer.h"
4a3b98d7 13#include "dns/forward.h"
fd9c47d1
AR
14#include "ip/Address.h"
15#include <iosfwd>
85e82959 16#include <vector>
4a3b98d7 17
fd9c47d1
AR
18// The IPs the caller should not connect to are "bad". Other IPs are "good".
19
20namespace Dns {
21
22/// a CachedIps element
23class CachedIp
dc49061a 24{
3c670b50 25public:
fd9c47d1
AR
26 explicit CachedIp(const Ip::Address &anIp): ip(anIp) {}
27
28 /// whether the address is currently deemed problematic for any reason
29 bool bad() const { return bad_; }
30
31 /// mark the address as problematic; it might already be marked
32 void markAsBad() { bad_ = true; }
33
34 /// undo markAsBad()
35 void forgetMarking() { bad_ = false; }
714e68b7 36
fd9c47d1
AR
37 Ip::Address ip;
38
39private:
40 bool bad_ = false; ///< whether the address is currently deemed problematic
3c670b50 41};
714e68b7 42
fd9c47d1
AR
43class IpsIterator;
44class GoodIpsIterator;
45template <class Iterator>
46class IpsSelector;
47
48/// A small container of IP addresses with a "current good address" getter API.
49/// Ignores Ip::Address port.
50class CachedIps
51{
52public:
53 /// whether we have at least one of the given IP addresses (ignoring ports)
54 /// upon success, also sets *position if the `position` is not nil
55 bool have(const Ip::Address &ip, size_t *position = nullptr) const;
56
57 /// \returns a good address
58 /// does not auto-rotate IPs but calling markAsBad() may change the answer
59 const Ip::Address &current() const { return ips.at(goodPosition).ip; }
60
61 bool empty() const noexcept { return ips.empty(); } ///< whether we cached no IPs at all
62 size_t size() const noexcept { return ips.size(); } ///< all cached IPs
63 size_t badCount() const noexcept { return badCount_; } ///< bad IPs
64
65 inline IpsSelector<GoodIpsIterator> good() const; ///< good IPs
66 inline IpsSelector<IpsIterator> goodAndBad() const; ///< all IPs
67
68 typedef std::vector<CachedIp> Storage;
69 const Storage &raw() const { return ips; } ///< all cached entries
70
71 /// Finds and marks the given address as bad, adjusting current() if needed.
72 /// Has no effect if the search fails or the found address is already bad.
73 /// XXX: An attempt to mark the last good address erases all marks instead.
74 /// XXX: It is impossible to successfully mark a single address as bad.
75 void markAsBad(const char *name, const Ip::Address &ip);
76
77 /// undo successful markAsBad()
78 void forgetMarking(const char *name, const Ip::Address &ip);
79
80 /// appends an IP address if we do not have() it already
81 /// invalidates all iterators
82 void pushUnique(const Ip::Address &ip);
83
84 /// replace all info with the given (presumed good) IP address
85 void reset(const Ip::Address &ip);
86
87 /// prints current IP and other debugging information
88 void reportCurrent(std::ostream &os) const;
89
90private:
91 bool seekNewGood(const char *name);
92 void restoreGoodness(const char *name);
93
94 // Memory- and speed-optimized for "a few (and usually just one)" IPs,
95 // the vast majority of which are "good". The current implementation
96 // does linear searches and often reallocs when adding IPs.
97 Storage ips; ///< good and bad IPs
98
99 template <class Iterator> friend class IpsSelector;
100 size_t goodPosition = 0; ///< position of the IP returned by current()
101 size_t badCount_ = 0; ///< number of IPs that are currently marked as bad
102};
103
104// The CachedIps class keeps meta information about individual IP addresses
105// together with those IPs. CachedIps users do not care about caching details;
106// they just want to iterate (a subset of) cached IPs. The IpsIterator and
107// IpsSelector classes below are minimal helper classes that make cached IPs
108// iteration easier, safer, and copy-free. See also: CachedIps::good().
109
110/// Iterates over any (good and/or bad) IPs in CachedIps, in unspecified order.
111class IpsIterator
112{
113public:
114 typedef std::vector<CachedIp> Raw;
115 typedef Raw::const_iterator RawIterator;
116
117 // some of the standard iterator traits
118 using iterator_category = std::forward_iterator_tag;
119 using value_type = const Ip::Address;
120 using pointer = value_type *;
121 using reference = value_type &;
122
123 IpsIterator(const Raw &raw, const size_t): position_(raw.cbegin()) {}
124 // special constructor for end() iterator
125 explicit IpsIterator(const Raw &raw): position_(raw.cend()) {}
126
127 reference operator *() const { return position_->ip; }
128 pointer operator ->() const { return &position_->ip; }
129
130 IpsIterator& operator++() { ++position_; return *this; }
131 IpsIterator operator++(int) { const auto oldMe = *this; ++(*this); return oldMe; }
132
133 bool operator ==(const IpsIterator them) const { return position_ == them.position_; }
134 bool operator !=(const IpsIterator them) const { return !(*this == them); }
135
136private:
137 RawIterator position_; ///< current iteration location
138};
139
140/// Iterates over good IPs in CachedIps, starting at the so called current one.
141class GoodIpsIterator
142{
143public:
144 typedef std::vector<CachedIp> Raw;
145 typedef Raw::const_iterator RawIterator;
146
147 // some of the standard iterator traits
148 using iterator_category = std::forward_iterator_tag;
149 using value_type = const Ip::Address;
150 using pointer = value_type *;
151 using reference = value_type &;
152
153 GoodIpsIterator(const Raw &raw, const size_t currentPos): raw_(raw), position_(currentPos), processed_(0) { sync(); }
154 // special constructor for end() iterator
155 explicit GoodIpsIterator(const Raw &raw): raw_(raw), position_(0), processed_(raw.size()) {}
156
157 reference operator *() const { return current().ip; }
158 pointer operator ->() const { return &current().ip; }
159
160 GoodIpsIterator& operator++() { next(); sync(); return *this; }
161 GoodIpsIterator operator++(int) { const auto oldMe = *this; ++(*this); return oldMe; }
162
163 bool operator ==(const GoodIpsIterator them) const { return processed_ == them.processed_; }
164 bool operator !=(const GoodIpsIterator them) const { return !(*this == them); }
165
166private:
167 const CachedIp &current() const { return raw_[position_ % raw_.size()]; }
168 void next() { ++position_; ++processed_; }
169 void sync() { while (processed_ < raw_.size() && current().bad()) next(); }
170
171 const Raw &raw_; ///< CachedIps being iterated
172 size_t position_; ///< current iteration location, modulo raw.size()
173 size_t processed_; ///< number of visited positions, including skipped ones
174};
175
176/// Makes "which IPs to iterate" decision explicit in range-based for loops.
177/// Supported Iterator types are IpsIterator and GoodIpsIterator.
178template <class Iterator>
179class IpsSelector
180{
181public:
182 explicit IpsSelector(const CachedIps &ips): ips_(ips) {}
183
184 Iterator cbegin() const noexcept { return Iterator(ips_.raw(), ips_.goodPosition); }
185 Iterator cend() const noexcept { return Iterator(ips_.raw()); }
186 Iterator begin() const noexcept { return cbegin(); }
187 Iterator end() const noexcept { return cend(); }
188
189private:
190 const CachedIps &ips_; ///< master IP storage we are wrapping
191};
192
193/// an interface for receiving IP::Addresses from nbgethostbyname()
194class IpReceiver: public virtual CbdataParent
195{
196public:
197 virtual ~IpReceiver() {}
198
199 /// Called when nbgethostbyname() fully resolves the name.
200 /// The `ips` may contain both bad and good IP addresses, but each good IP
201 /// (if any) is guaranteed to had been previously reported via noteIp().
202 virtual void noteIps(const CachedIps *ips, const LookupDetails &details) = 0;
203
204 /// Called when/if nbgethostbyname() discovers a new good IP address.
205 virtual void noteIp(const Ip::Address &) {}
206
207 /// Called when/if nbgethostbyname() completes a single DNS lookup
208 /// if called, called before all the noteIp() calls for that DNS lookup.
209 virtual void noteLookup(const Dns::LookupDetails &) {}
210};
211
212/// initiate an (often) asynchronous DNS lookup; the `receiver` gets the results
213void nbgethostbyname(const char *name, const CbcPointer<IpReceiver> &receiver);
214
215} // namespace Dns
216
217typedef Dns::CachedIps ipcache_addrs; ///< deprecated alias
218
4a3b98d7 219typedef void IPH(const ipcache_addrs *, const Dns::LookupDetails &details, void *);
714e68b7 220
8a648e8d
FC
221void ipcache_purgelru(void *);
222void ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData);
223const ipcache_addrs *ipcache_gethostbyname(const char *, int flags);
224void ipcacheInvalidate(const char *);
225void ipcacheInvalidateNegative(const char *);
226void ipcache_init(void);
8a648e8d
FC
227void ipcacheMarkBadAddr(const char *name, const Ip::Address &);
228void ipcacheMarkGoodAddr(const char *name, const Ip::Address &);
8a648e8d 229void ipcacheFreeMemory(void);
8a648e8d
FC
230void ipcache_restart(void);
231int ipcacheAddEntryFromHosts(const char *name, const char *ipaddr);
714e68b7 232
fd9c47d1
AR
233inline std::ostream &
234operator <<(std::ostream &os, const Dns::CachedIps &ips)
235{
236 ips.reportCurrent(os);
237 return os;
238}
239
240/* inlined implementations */
241
242inline Dns::IpsSelector<Dns::GoodIpsIterator>
243Dns::CachedIps::good() const
244{
245 return IpsSelector<GoodIpsIterator>(*this);
246}
247
248inline Dns::IpsSelector<Dns::IpsIterator>
249Dns::CachedIps::goodAndBad() const
250{
251 return IpsSelector<IpsIterator>(*this);
252}
f53969cc 253
fd9c47d1 254#endif /* _SQUID_IPCACHE_H */
fbe83113 255