-
Notifications
You must be signed in to change notification settings - Fork 857
Expand file tree
/
Copy pathHostDBProcessor.h
More file actions
830 lines (676 loc) · 25 KB
/
HostDBProcessor.h
File metadata and controls
830 lines (676 loc) · 25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
/** @file
A brief file description
@section license License
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#include <chrono>
#include <atomic>
#include <cstdint>
#include <utility>
#include "tscore/HashFNV.h"
#include "tscore/ink_time.h"
#include "tscore/CryptoHash.h"
#include "tscore/ink_align.h"
#include "tscore/ink_inet.h"
#include "tscore/ink_resolver.h"
#include "tscore/HTTPVersion.h"
#include "swoc/MemSpan.h"
#include "iocore/eventsystem/EventSystem.h"
#include "iocore/dns/SRV.h"
// Event returned on a lookup
#define EVENT_HOST_DB_LOOKUP (HOSTDB_EVENT_EVENTS_START + 0)
#define EVENT_HOST_DB_IP_REMOVED (HOSTDB_EVENT_EVENTS_START + 1)
#define EVENT_HOST_DB_GET_RESPONSE (HOSTDB_EVENT_EVENTS_START + 2)
#define EVENT_SRV_LOOKUP (SRV_EVENT_EVENTS_START + 0)
#define EVENT_SRV_IP_REMOVED (SRV_EVENT_EVENTS_START + 1)
#define EVENT_SRV_GET_RESPONSE (SRV_EVENT_EVENTS_START + 2)
//
// Data
//
struct HostDBContinuation;
struct ResolveInfo;
//
// The host database stores host information, most notably the
// IP address.
//
// Since host information is relatively small, we can afford to have
// a reasonable size memory cache, and use a (relatively) sparse
// disk representation to decrease # of seeks.
//
extern int hostdb_enable;
/** Epoch timestamp of the current hosts file check.
*
* This also functions as a cached version of ts_clock::now(). Since it is
* updated in backgroundEvent which runs every second, it should be
* approximately accurate to a second.
*/
extern std::atomic<ts_time> hostdb_current_timestamp;
/** How long before any DNS response is consided stale, regardless of DNS TTL.
* This corresponds to proxy.config.hostdb.verify_after.
*/
extern unsigned int hostdb_ip_stale_interval;
extern unsigned int hostdb_ip_timeout_interval;
extern unsigned int hostdb_ip_fail_timeout_interval;
extern unsigned int hostdb_serve_stale_but_revalidate;
extern unsigned int hostdb_round_robin_max_count;
extern int hostdb_max_iobuf_index;
static inline unsigned int
makeHostHash(const char *string)
{
ink_assert(string && *string);
if (string && *string) {
ATSHash32FNV1a fnv;
fnv.update(string, strlen(string), ATSHash::nocase());
fnv.final();
return fnv.get();
}
return 0;
}
//
// Types
//
class HostDBRecord;
/// Information for an SRV record.
struct SRVInfo {
unsigned int srv_offset : 16; ///< Memory offset from @c HostDBInfo to name.
unsigned int srv_weight : 16;
unsigned int srv_priority : 16;
unsigned int srv_port : 16;
unsigned int key;
};
/// Type of data stored.
enum class HostDBType : uint8_t {
UNSPEC, ///< No valid data.
ADDR, ///< IP address.
SRV, ///< SRV record.
HOST ///< Hostname (reverse DNS)
};
/** Information about a single target.
*
* Each instance tracks the health state of one upstream address. The state is derived from @c _last_failure and the caller-supplied
* @a fail_window:
*
* | State | Description |
* |---------|-----------------------------------------------------------------------------------|
* | Up | No known failure; eligible for normal selection. |
* | Down | Blocked; no connections permitted until @c _last_failure + @a fail_window elapses |
* | Suspect | Fail window has elapsed; connections are permitted. |
* | | On success transitions to Up (@c mark_up); on failure returns to Down. |
*
* State transition diagram:
*
* @startuml
* hide empty description
*
* [*] --> Up
* Up --> Down : connect failure\n(mark_down)
* Down --> Suspect : fail_window elapses
* Suspect --> Up : connect success\n(mark_up)
* Suspect --> Down : connect failure\n(mark_down)
* @enduml
*
* State transition and `fail_window` time chart:
*
* @code
* |<-- fail_window -->|
* -+----------+--------------------+--------------------+----------+----> time
* | Up | Down | Suspect | Up |
* -+----------+--------------------+--------------------+----------+---->
* ^ ^ ^
* \ \ \
* (_last_failure) (_last_failure + fail_window) (connect success)
* @endcode
*/
class HostDBInfo
{
public:
using self_type = HostDBInfo; ///< Self reference type.
/// Health state of this target.
enum class State {
UP,
DOWN,
SUSPECT,
};
/// Default constructor.
HostDBInfo() = default;
HostDBInfo &operator=(HostDBInfo const &that);
/// Absolute time of when this target failed.
/// A value of zero (@c TS_TIME_ZERO ) indicates no failure.
ts_time last_fail_time() const;
uint8_t fail_count() const;
char const *srvname() const;
/// Return the current health state of this target.
State state(ts_time now, ts_seconds fail_window) const;
// Sugars of checking state
bool is_up() const;
bool is_down(ts_time now, ts_seconds fail_window) const;
bool is_suspect(ts_time now, ts_seconds fail_window) const;
// State controllers
bool mark_up();
bool mark_down(ts_time now, ts_seconds fail_window);
std::pair<bool, uint8_t> increment_fail_count(ts_time now, uint8_t max_retries, ts_seconds fail_window);
void migrate_from(self_type const &that);
/// A target is either an IP address or an SRV record.
/// The type should be indicated by @c flags.f.is_srv;
union {
IpAddr ip; ///< IP address / port data.
SRVInfo srv; ///< SRV record.
} data{IpAddr{}};
/// Expected HTTP version of the target based on earlier transactions.
HTTPVersion http_version = HTTP_INVALID;
self_type &assign(IpAddr const &addr);
protected:
self_type &assign(sa_family_t af, void const *addr);
self_type &assign(SRV const *srv, char const *name);
HostDBType type = HostDBType::UNSPEC; ///< Invalid data.
friend HostDBContinuation;
private:
std::atomic<ts_time> _last_failure{TS_TIME_ZERO}; ///< Last time a failure was recorded
std::atomic<uint8_t> _fail_count{0}; ///< Count of connection failures
};
// ----
/** Root item for HostDB.
* This is the container for HostDB data. It is always an array of @c HostDBInfo instances plus metadata.
* All strings are C-strings and therefore don't need a distinct size.
*
*/
class HostDBRecord : public RefCountObj
{
friend struct HostDBContinuation;
using self_type = HostDBRecord;
/// Size of the IO buffer block owned by @a this.
/// If negative @a this is in not allocated memory.
int _iobuffer_index{-1};
/// Actual size of the data.
unsigned _record_size = sizeof(self_type);
public:
HostDBRecord() = default;
HostDBRecord(self_type const &that) = delete;
using Handle = Ptr<HostDBRecord>; ///< Shared pointer type to hold an instance.
/** Allocate an instance from the IOBuffers.
*
* @param query_name Name of the query for the record.
* @param rr_count Number of info instances.
* @param srv_name_size Storage for SRV names, if any.
* @param port Port Number, if any.
*
* @return An instance sufficient to hold the specified data.
*
* The query name will stored and initialized, and the info instances initialized.
*/
static self_type *alloc(swoc::TextView query_name, unsigned rr_count, size_t srv_name_size = 0, in_port_t port = 0);
/// Type of data stored in this record.
HostDBType record_type = HostDBType::UNSPEC;
/// IP family of this record.
sa_family_t af_family = AF_UNSPEC;
/// Offset from @a this to the VLA.
unsigned short rr_offset = 0;
/// Number of @c HostDBInfo instances.
unsigned short rr_count = 0;
/// Timing data for switch records in the RR.
std::atomic<ts_time> rr_ctime{TS_TIME_ZERO};
/// Hash key.
uint64_t key{0};
/// When the DNS response was received.
ts_time ip_timestamp;
/// Valid duration of the DNS response data.
/// In the code this functions as the TTL in HostDB calculations, but may not
/// be the response's TTL based upon configuration such as
/// proxy.config.hostdb.ttl_mode.
ts_seconds ip_timeout_interval;
/** Atomically advance the round robin index.
*
* If multiple threads call this simultaneously each thread will get a distinct return value.
*
* @return The new round robin index.
*/
unsigned next_rr();
/** Pick the next round robin and update the record atomically.
*
* @note This may select a suspect server. The caller must attempt to connect to the selected
* target if possible.
*
* @param[in] now Current time to use for HostDBInfo state calculations.
* @param[in] fail_window Blackout time for down servers.
* @return The selected target, or @c nullptr if all targets are down.
*
* @note Concurrency - this is not done under lock and depends on the caller for correct use.
* For strict round robin, it is a feature that every call will get a distinct index. For
* timed round robin, the caller must arrange to have only one thread call this per time interval.
*/
HostDBInfo *select_next_rr(ts_time now, ts_seconds fail_window);
/// Check if this record is of SRV targets.
bool is_srv() const;
/** Query name for the record.
* @return A C-string.
* If this is a @c HOST record, this is the resolved named and the query was based on the IP address.
* Otherwise this is the name used in the DNS query.
*/
char const *name() const;
/** Query name for the record.
* @return A view.
* If this is a @c HOST record, this is the resolved named and the query was based on the IP address.
* Otherwise this is the name used in the DNS query.
* @note Although not included in the view, the name is always nul terminated and the string can
* be used as a C-string.
*/
swoc::TextView name_view() const;
/**
@return Port Number
*/
in_port_t port() const;
/// Get the array of info instances.
swoc::MemSpan<HostDBInfo> rr_info();
/// Get the array of info instances to read
swoc::MemSpan<const HostDBInfo> rr_info() const;
/** Find a host record by IP address.
*
* @param addr Address key.
* @return A pointer to the info instance if a match is found, @c nullptr if not.
*/
HostDBInfo *find(sockaddr const *addr);
/** Select an upstream target.
*
* @param now Current time.
* @param fail_window Down server blackout time.
* @param hash_addr Inbound remote IP address.
* @return A selected target, or @c nullptr if there are no valid targets.
*
* This accounts for the round robin setting. The default is to use "client affinity" in
* which case @a hash_addr is as a hash seed to select the target.
*
* This may select a suspect target (fail window elapsed, connections permitted again), which can
* be detected by checking the target's last failure time. If it is not @c TS_TIME_ZERO the target
* is a suspect. Multiple threads may concurrently select the same suspect target.
*
* In cases other than strict round robin, a base target is selected. If valid, that is returned,
* but if not then the targets in this record are searched until a valid one is found. The result
* is this can be called to select a target for failover when a previous target fails.
*/
HostDBInfo *select_best_http(ts_time now, ts_seconds fail_window, sockaddr const *hash_addr);
HostDBInfo *select_best_srv(char *target, InkRand *rand, ts_time now, ts_seconds fail_window);
bool is_failed() const;
void set_failed();
/// @return The time point when the item expires.
ts_time expiry_time() const;
/// @return The age of the DNS response.
ts_seconds ip_age() const;
/// @return How long before the DNS response becomes stale (i.e., exceeds @a
/// ip_timeout_interval from the time of the response).
ts_seconds ip_time_remaining() const;
/// @return Whether the age of the DNS response exceeds @a the user's
/// configured proxy.config.hostdb.verify_after value.
bool is_ip_configured_stale() const;
/** Whether we have exceeded the DNS response's TTL (i.e., whether the DNS
* response is stale). */
bool is_ip_timeout() const;
bool is_ip_fail_timeout() const;
void refresh_ip();
/** Whether the DNS response can still be used per
* proxy.config.hostdb.serve_stale_for configuration.
*
* @return False if serve_stale_for is not configured or if the DNS
* response's age is less than TTL + the serve_stale_for value. Note that
* this function will return true for DNS responses whose age is less than
* TTL (i.e., for responses that are not yet stale).
*/
bool serve_stale_but_revalidate() const;
/// Deallocate @a this.
void free() override;
/** The current round robin index.
*
* @return The current index.
*
* @note The internal index may be out of range due to concurrency constraints - this insures the
* returned value is in range.
*/
unsigned short rr_idx() const;
/** Offset from the current round robin index.
*
* @param delta Distance from the current index.
* @return The effective index.
*/
unsigned short rr_idx(unsigned short delta) const;
/// The index of @a target in this record.
int index_of(HostDBInfo const *target) const;
protected:
/// Current active info.
/// @note This value may be out of range due to the difficulty of synchronization, therefore
/// must always be taken modulus @c rr_count when used. Use the @c rr_idx() method unless
/// raw access is required.
std::atomic<unsigned short> _rr_idx = 0;
/** Access an internal object at @a offset.
*
* @tparam T Type of object.
* @param offset Offset of object.
* @return A pointer to the object of type @a T.
*
* @a offset is applied to @a this record and the result cast to a pointer to @a T.
*
* @note @a offset based at @a this.
*/
template <typename T>
T *
apply_offset(unsigned offset)
{
return reinterpret_cast<T *>(reinterpret_cast<char *>(this) + offset);
}
template <typename T>
T const *
apply_offset(unsigned offset) const
{
return reinterpret_cast<T const *>(reinterpret_cast<char const *>(this) + offset);
}
union {
uint16_t all;
struct {
unsigned failed_p : 1; ///< DNS error.
} f;
} flags{0};
private:
/// Port Number if hash key includes it.
in_port_t _port = 0;
};
struct HostDBCache;
struct HostDBHash;
// Prototype for inline completion function or
// getbyname_imm()
using cb_process_result_pfn = void (Continuation::*)(HostDBRecord *r);
/** Information for doing host resolution for a request.
*
* This is effectively a state object for a request attempting to connect upstream. Information about its attempt
* that are local to the request are kept here, while shared data is accessed via the @c HostDBInfo pointers.
*
* A primitive version of the IP address generator concept.
*/
struct ResolveInfo {
using self_type = ResolveInfo; ///< Self reference type.
/// Not quite sure what this is for.
enum UpstreamResolveStyle { UNDEFINED_LOOKUP, ORIGIN_SERVER, PARENT_PROXY, HOST_NONE };
/** Origin server address source selection.
If config says to use CTA (client target addr) state is TRY_CLIENT, otherwise it
remains the default. If the connect fails then we switch to a USE. We go to USE_HOSTDB if (1)
the HostDB lookup is successful and (2) some address other than the CTA is available to try.
Otherwise we keep retrying on the CTA (USE_CLIENT) up to the max retry value. In essence we
try to treat the CTA as if it were another RR value in the HostDB record.
*/
enum class OS_Addr {
TRY_DEFAULT, ///< Initial state, use what config says.
TRY_HOSTDB, ///< Try HostDB data.
TRY_CLIENT, ///< Try client target addr.
USE_HOSTDB, ///< Force use of HostDB target address.
USE_CLIENT, ///< Force client target addr.
USE_API ///< Use the API provided address.
};
ResolveInfo() = default;
~ResolveInfo() = default;
/// Keep a reference to the base HostDB object, so it doesn't get GC'd.
Ptr<HostDBRecord> record;
HostDBInfo *active = nullptr; ///< Active HostDBInfo
/// Working address. The meaning / source of the value depends on other elements.
/// This is the "resolved" address if @a resolved_p is @c true.
IpEndpoint addr;
int attempts = 0; ///< Number of connection attempts.
char const *lookup_name = nullptr;
char srv_hostname[MAXDNAME] = {0};
const sockaddr *inbound_remote_addr = nullptr; ///< Remote address of inbound client - used for hashing.
in_port_t srv_port = 0; ///< Port from SRV lookup or API call.
OS_Addr os_addr_style = OS_Addr::TRY_DEFAULT;
HostResStyle host_res_style = HOST_RES_IPV4;
UpstreamResolveStyle looking_up = UNDEFINED_LOOKUP;
HTTPVersion http_version = HTTP_INVALID;
bool resolved_p = false; ///< If there is a valid, resolved address in @a addr.
/// Flag for @a addr being set externally.
// bool api_addr_set_p = false;
/*** Set to true by default. If use_client_target_address is set
* to 1, this value will be set to false if the client address is
* not in the DNS pool */
bool cta_validated_p = true;
bool set_active(HostDBInfo *info);
bool set_active(sockaddr const *s);
bool set_active(std::nullptr_t);
/** Force a resolved address.
*
* @param sa Address to use for the upstream.
* @return @c true if successful, @c false if error.
*
* This fails if @a sa isn't a valid IP address.
*/
bool set_upstream_address(const sockaddr *sa);
bool set_upstream_address(IpAddr const &ip_addr);
void set_upstream_port(in_port_t port);
/** Check and (if possible) immediately resolve the upstream address without consulting the HostDB.
* The cases where this is successful are
* - The address is already resolved (@a resolved_p is @c true).
* - The upstream was set explicitly.
* - The hostname is a valid IP address.
*
* @return @c true if the upstream address was resolved, @c false if not.
*/
bool resolve_immediate();
/** Mark the active target as DOWN.
*
* @param[in] now Time of failure.
* @param[in] fail_window The fail window duration (proxy.config.http.down_server.cache_time).
* @return @c true if the server was marked as down, @c false if not.
*
*/
bool mark_active_server_down(ts_time now, ts_seconds fail_window);
/** Mark the active target as UP.
*
* @return @c true if the target changed state.
*/
bool mark_active_server_up();
/// Select / resolve to the next RR entry for the record.
bool select_next_rr(ts_time now, ts_seconds fail_window);
bool is_srv() const;
};
/** The Host Database access interface. */
struct HostDBProcessor : public Processor {
// Public Interface
// Lookup Hostinfo by name
// cont->handleEvent( EVENT_HOST_DB_LOOKUP, HostDBInfo * ); on success
// cont->handleEVent( EVENT_HOST_DB_LOOKUP, 0); on failure
// Failure occurs when the host cannot be DNS-ed
// NOTE: Will call the continuation back before returning if data is in the
// cache. The HostDBInfo * becomes invalid when the callback returns.
// The HostDBInfo may be changed during the callback.
enum {
HOSTDB_DO_NOT_FORCE_DNS = 0,
HOSTDB_ROUND_ROBIN = 0,
HOSTDB_FORCE_DNS_RELOAD = 1,
HOSTDB_FORCE_DNS_ALWAYS = 2,
HOSTDB_DO_NOT_ROUND_ROBIN = 4
};
/// Optional parameters for getby...
struct Options {
using self = Options; ///< Self reference type.
int port = 0; ///< Target service port (default 0 -> don't care)
int flags = HOSTDB_DO_NOT_FORCE_DNS; ///< Processing flags (default HOSTDB_DO_NOT_FORCE_DNS)
int timeout = 0; ///< Timeout value (default 0 -> default timeout)
HostResStyle host_res_style = HOST_RES_IPV4; ///< How to query host (default HOST_RES_IPV4)
Options() {}
/// Set the flags.
self &
setFlags(int f)
{
flags = f;
return *this;
}
};
/// Default options.
static Options const DEFAULT_OPTIONS;
HostDBProcessor() {}
Action *getbyname_re(Continuation *cont, const char *hostname, int len, Options const &opt = DEFAULT_OPTIONS);
Action *getbynameport_re(Continuation *cont, const char *hostname, int len, Options const &opt = DEFAULT_OPTIONS);
Action *getSRVbyname_imm(Continuation *cont, cb_process_result_pfn process_srv_info, const char *hostname, int len,
Options const &opt = DEFAULT_OPTIONS);
Action *getbyname_imm(Continuation *cont, cb_process_result_pfn process_hostdb_info, const char *hostname, int len,
Options const &opt = DEFAULT_OPTIONS);
/** Lookup Hostinfo by addr */
Action *getbyaddr_re(Continuation *cont, sockaddr const *aip);
/** Configuration. */
static int hostdb_strict_round_robin;
static int hostdb_timed_round_robin;
// Processor Interface
/* hostdb does not use any dedicated event threads
* currently. Dont pass any value to start
*/
int start(int no_of_additional_event_threads = 0, size_t stacksize = DEFAULT_STACKSIZE) override;
// Private
HostDBCache *cache();
private:
int init();
Action *getby(Continuation *cont, cb_process_result_pfn cb_process_result, HostDBHash &hash, Options const &opt);
};
inline bool
HostDBRecord::is_srv() const
{
return HostDBType::SRV == record_type;
}
inline char const *
HostDBRecord::name() const
{
return this->apply_offset<char const>(sizeof(self_type));
}
inline swoc::TextView
HostDBRecord::name_view() const
{
return {this->name(), swoc::TextView::npos};
}
inline in_port_t
HostDBRecord::port() const
{
return _port;
}
inline ts_time
HostDBRecord::expiry_time() const
{
return ip_timestamp + ip_timeout_interval + ts_seconds(hostdb_serve_stale_but_revalidate);
}
inline ts_seconds
HostDBRecord::ip_age() const
{
static constexpr ts_seconds ZERO{0};
static constexpr ts_seconds MAX{0x7FFFFFFF};
return std::clamp(std::chrono::duration_cast<ts_seconds>(hostdb_current_timestamp.load() - ip_timestamp), ZERO, MAX);
}
inline ts_seconds
HostDBRecord::ip_time_remaining() const
{
static constexpr ts_seconds ZERO{0};
static constexpr ts_seconds MAX{0x7FFFFFFF};
return std::clamp(std::chrono::duration_cast<ts_seconds>(ip_timeout_interval - this->ip_age()), ZERO, MAX);
}
inline bool
HostDBRecord::is_ip_configured_stale() const
{
return (
((ip_timeout_interval >= ts_seconds(2 * hostdb_ip_stale_interval)) && (ip_age() >= ts_seconds(hostdb_ip_stale_interval))));
}
inline bool
HostDBRecord::is_ip_timeout() const
{
return ip_age() >= ip_timeout_interval;
}
inline bool
HostDBRecord::is_ip_fail_timeout() const
{
return ip_age() >= ts_seconds(hostdb_ip_fail_timeout_interval);
}
inline void
HostDBRecord::refresh_ip()
{
ip_timestamp = hostdb_current_timestamp;
}
inline swoc::MemSpan<HostDBInfo>
HostDBRecord::rr_info()
{
return {this->apply_offset<HostDBInfo>(rr_offset), rr_count};
}
inline swoc::MemSpan<const HostDBInfo>
HostDBRecord::rr_info() const
{
return {this->apply_offset<const HostDBInfo>(rr_offset), rr_count};
}
inline bool
HostDBRecord::is_failed() const
{
return flags.f.failed_p;
}
inline void
HostDBRecord::set_failed()
{
flags.f.failed_p = true;
}
inline unsigned short
HostDBRecord::rr_idx() const
{
return _rr_idx % rr_count;
}
inline unsigned short
HostDBRecord::rr_idx(unsigned short delta) const
{
return (_rr_idx + delta) % rr_count;
}
inline int
HostDBRecord::index_of(HostDBInfo const *target) const
{
return target ? target - this->apply_offset<HostDBInfo>(rr_offset) : -1;
}
// --
inline bool
ResolveInfo::set_active(sockaddr const *s)
{
return this->set_active(record->find(s));
}
inline bool
ResolveInfo::mark_active_server_up()
{
return active->mark_up();
}
inline bool
ResolveInfo::mark_active_server_down(ts_time now, ts_seconds fail_window)
{
return active != nullptr && active->mark_down(now, fail_window);
}
inline bool
ResolveInfo::set_active(std::nullptr_t)
{
active = nullptr;
resolved_p = false;
return false;
}
inline bool
ResolveInfo::set_upstream_address(sockaddr const *sa)
{
resolved_p = addr.assign(sa).isValid();
return resolved_p;
}
inline void
ResolveInfo::set_upstream_port(in_port_t port)
{
srv_port = port;
}
inline bool
ResolveInfo::is_srv() const
{
return record && record->is_srv();
}
// ---
void run_HostDBTest();
extern HostDBProcessor hostDBProcessor;
void ink_hostdb_init(ts::ModuleVersion version);