2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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.
9 #ifndef _SQUID_IPCACHE_H
10 #define _SQUID_IPCACHE_H
12 #include "base/CbcPointer.h"
13 #include "dns/forward.h"
14 #include "ip/Address.h"
18 // The IPs the caller should not connect to are "bad". Other IPs are "good".
22 /// a CachedIps element
26 explicit CachedIp(const Ip::Address
&anIp
): ip(anIp
) {}
28 /// whether the address is currently deemed problematic for any reason
29 bool bad() const { return bad_
; }
31 /// mark the address as problematic; it might already be marked
32 void markAsBad() { bad_
= true; }
35 void forgetMarking() { bad_
= false; }
40 bool bad_
= false; ///< whether the address is currently deemed problematic
44 class GoodIpsIterator
;
45 template <class Iterator
>
48 /// A small container of IP addresses with a "current good address" getter API.
49 /// Ignores Ip::Address port.
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;
57 /// \returns a good address
58 /// does not auto-rotate IPs but calling markAsBad() may change the answer
59 const Ip::Address
¤t() const { return ips
.at(goodPosition
).ip
; }
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
65 inline IpsSelector
<GoodIpsIterator
> good() const; ///< good IPs
66 inline IpsSelector
<IpsIterator
> goodAndBad() const; ///< all IPs
68 typedef std::vector
<CachedIp
> Storage
;
69 const Storage
&raw() const { return ips
; } ///< all cached entries
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
);
77 /// undo successful markAsBad()
78 void forgetMarking(const char *name
, const Ip::Address
&ip
);
80 /// appends an IP address if we do not have() it already
81 /// invalidates all iterators
82 void pushUnique(const Ip::Address
&ip
);
84 /// replace all info with the given (presumed good) IP address
85 void reset(const Ip::Address
&ip
);
87 /// prints current IP and other debugging information
88 void reportCurrent(std::ostream
&os
) const;
91 bool seekNewGood(const char *name
);
92 void restoreGoodness(const char *name
);
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
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
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().
110 /// Iterates over any (good and/or bad) IPs in CachedIps, in unspecified order.
114 typedef std::vector
<CachedIp
> Raw
;
115 typedef Raw::const_iterator RawIterator
;
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
&;
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()) {}
127 reference
operator *() const { return position_
->ip
; }
128 pointer
operator ->() const { return &position_
->ip
; }
130 IpsIterator
& operator++() { ++position_
; return *this; }
131 IpsIterator
operator++(int) { const auto oldMe
= *this; ++(*this); return oldMe
; }
133 bool operator ==(const IpsIterator them
) const { return position_
== them
.position_
; }
134 bool operator !=(const IpsIterator them
) const { return !(*this == them
); }
137 RawIterator position_
; ///< current iteration location
140 /// Iterates over good IPs in CachedIps, starting at the so called current one.
141 class GoodIpsIterator
144 typedef std::vector
<CachedIp
> Raw
;
145 typedef Raw::const_iterator RawIterator
;
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
&;
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()) {}
157 reference
operator *() const { return current().ip
; }
158 pointer
operator ->() const { return ¤t().ip
; }
160 GoodIpsIterator
& operator++() { next(); sync(); return *this; }
161 GoodIpsIterator
operator++(int) { const auto oldMe
= *this; ++(*this); return oldMe
; }
163 bool operator ==(const GoodIpsIterator them
) const { return processed_
== them
.processed_
; }
164 bool operator !=(const GoodIpsIterator them
) const { return !(*this == them
); }
167 const CachedIp
¤t() const { return raw_
[position_
% raw_
.size()]; }
168 void next() { ++position_
; ++processed_
; }
169 void sync() { while (processed_
< raw_
.size() && current().bad()) next(); }
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
176 /// Makes "which IPs to iterate" decision explicit in range-based for loops.
177 /// Supported Iterator types are IpsIterator and GoodIpsIterator.
178 template <class Iterator
>
182 explicit IpsSelector(const CachedIps
&ips
): ips_(ips
) {}
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(); }
190 const CachedIps
&ips_
; ///< master IP storage we are wrapping
193 /// an interface for receiving IP::Addresses from nbgethostbyname()
194 class IpReceiver
: public virtual CbdataParent
197 ~IpReceiver() override
{}
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;
204 /// Called when/if nbgethostbyname() discovers a new good IP address.
205 virtual void noteIp(const Ip::Address
&) {}
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
&) {}
212 /// initiate an (often) asynchronous DNS lookup; the `receiver` gets the results
213 void nbgethostbyname(const char *name
, const CbcPointer
<IpReceiver
> &receiver
);
215 inline std::ostream
&
216 operator <<(std::ostream
&os
, const CachedIps
&ips
)
218 ips
.reportCurrent(os
);
224 typedef Dns::CachedIps ipcache_addrs
; ///< deprecated alias
226 typedef void IPH(const ipcache_addrs
*, const Dns::LookupDetails
&details
, void *);
228 void ipcache_purgelru(void *);
229 void ipcache_nbgethostbyname(const char *name
, IPH
* handler
, void *handlerData
);
230 const ipcache_addrs
*ipcache_gethostbyname(const char *, int flags
);
231 void ipcacheInvalidate(const char *);
232 void ipcacheInvalidateNegative(const char *);
233 void ipcache_init(void);
234 void ipcacheMarkBadAddr(const char *name
, const Ip::Address
&);
235 void ipcacheMarkGoodAddr(const char *name
, const Ip::Address
&);
236 void ipcache_restart(void);
237 int ipcacheAddEntryFromHosts(const char *name
, const char *ipaddr
);
239 /* inlined implementations */
241 inline Dns::IpsSelector
<Dns::GoodIpsIterator
>
242 Dns::CachedIps::good() const
244 return IpsSelector
<GoodIpsIterator
>(*this);
247 inline Dns::IpsSelector
<Dns::IpsIterator
>
248 Dns::CachedIps::goodAndBad() const
250 return IpsSelector
<IpsIterator
>(*this);
253 #endif /* _SQUID_IPCACHE_H */