blob: 9abc1d71ab0dd24c4b060f21484686db36114116 [file] [log] [blame]
/** @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 "I_EventSystem.h"
#include "tscore/PendingAction.h"
#define MAX_NAMED 32
#define DEFAULT_DNS_RETRIES 5
#define MAX_DNS_RETRIES 9
#define DEFAULT_DNS_TIMEOUT 30
#define MAX_DNS_IN_FLIGHT 2048
#define MAX_DNS_TCP_CONTINUOUS_FAILURES 10
#define DEFAULT_FAILOVER_NUMBER (DEFAULT_DNS_RETRIES + 1)
#define DEFAULT_FAILOVER_PERIOD (DEFAULT_DNS_TIMEOUT + 30)
// how many seconds before FAILOVER_PERIOD to try the primary with
// a well known address
#define DEFAULT_FAILOVER_TRY_PERIOD (DEFAULT_DNS_TIMEOUT + 1)
#define DEFAULT_DNS_SEARCH 1
#define FAILOVER_SOON_RETRY 5
#define NO_NAMESERVER_SELECTED -1
//
// Config
//
extern int dns_timeout;
extern int dns_retries;
extern int dns_search;
extern int dns_failover_number;
extern int dns_failover_period;
extern int dns_failover_try_period;
extern int dns_max_dns_in_flight;
extern int dns_max_tcp_continuous_failures;
extern unsigned int dns_sequence_number;
//
// Constants
//
#define DNS_PERIOD HRTIME_MSECONDS(100)
#define DNS_DELAY_PERIOD HRTIME_MSECONDS(10)
#define DNS_SEQUENCE_NUMBER_RESTART_OFFSET 4000
#define DNS_PRIMARY_RETRY_PERIOD HRTIME_SECONDS(5)
#define DNS_PRIMARY_REOPEN_PERIOD HRTIME_SECONDS(60)
#define BAD_DNS_RESULT (reinterpret_cast<HostEnt *>((uintptr_t)-1))
#define DEFAULT_NUM_TRY_SERVER 8
// these are from nameser.h
#ifndef HFIXEDSZ
#define HFIXEDSZ 12
#endif
#ifndef QFIXEDSZ
#define QFIXEDSZ 4
#endif
// Stats
enum DNS_Stats {
dns_total_lookups_stat,
dns_response_time_stat,
dns_success_time_stat,
dns_lookup_success_stat,
dns_lookup_fail_stat,
dns_fail_time_stat,
dns_retries_stat,
dns_max_retries_exceeded_stat,
dns_in_flight_stat,
dns_tcp_retries_stat,
dns_tcp_reset_stat,
DNS_Stat_Count
};
struct HostEnt;
struct DNSHandler;
struct RecRawStatBlock;
extern RecRawStatBlock *dns_rsb;
// Stat Macros
#define DNS_INCREMENT_DYN_STAT(_x) RecIncrRawStatSum(dns_rsb, mutex->thread_holding, (int)_x, 1)
#define DNS_DECREMENT_DYN_STAT(_x) RecIncrRawStatSum(dns_rsb, mutex->thread_holding, (int)_x, -1)
#define DNS_SUM_DYN_STAT(_x, _r) RecIncrRawStatSum(dns_rsb, mutex->thread_holding, (int)_x, _r)
/**
One DNSEntry is allocated per outstanding request. This continuation
handles TIMEOUT events for the request as well as storing all
information about the request and its status.
*/
struct DNSEntry : public Continuation {
int id[MAX_DNS_RETRIES];
int qtype = 0; ///< Type of query to send.
HostResStyle host_res_style = HOST_RES_NONE; ///< Preferred IP address family.
int retries = DEFAULT_DNS_RETRIES;
int which_ns = NO_NAMESERVER_SELECTED;
ink_hrtime submit_time = 0;
ink_hrtime send_time = 0;
char qname[MAXDNAME + 1];
int qname_len = 0;
int orig_qname_len = 0;
char **domains = nullptr;
EThread *submit_thread = nullptr;
Action action;
Event *timeout = nullptr;
Ptr<HostEnt> result_ent;
DNSHandler *dnsH = nullptr;
bool written_flag = false;
bool once_written_flag = false;
bool last = false;
LINK(DNSEntry, dup_link);
Que(DNSEntry, dup_link) dups;
int mainEvent(int event, Event *e);
int delayEvent(int event, Event *e);
int postAllEvent(int event, Event *e);
int post(DNSHandler *h, HostEnt *ent);
int postOneEvent(int event, Event *e);
void init(DNSQueryData target, int qtype_arg, Continuation *acont, DNSProcessor::Options const &opt);
DNSEntry()
{
for (int &i : id)
i = -1;
memset(qname, 0, MAXDNAME);
}
};
typedef int (DNSEntry::*DNSEntryHandler)(int, void *);
struct DNSEntry;
/**
One DNSHandler is allocated to handle all DNS traffic by polling a
UDP port.
*/
struct DNSHandler : public Continuation {
/// This is used as the target if round robin isn't set.
IpEndpoint ip;
IpEndpoint local_ipv6; ///< Local V6 address if set.
IpEndpoint local_ipv4; ///< Local V4 address if set.
int ifd[MAX_NAMED];
int n_con = 0;
DNSConnection tcpcon[MAX_NAMED];
DNSConnection udpcon[MAX_NAMED];
Queue<DNSEntry> entries;
Queue<DNSConnection> triggered;
int in_flight = 0;
int name_server = 0;
int in_write_dns = 0;
HostEnt *hostent_cache = nullptr;
int ns_down[MAX_NAMED];
int failover_number[MAX_NAMED];
int failover_soon_number[MAX_NAMED];
int tcp_continuous_failures[MAX_NAMED];
ink_hrtime crossed_failover_number[MAX_NAMED];
ink_hrtime last_primary_retry = 0;
ink_hrtime last_primary_reopen = 0;
ink_res_state m_res = nullptr;
int txn_lookup_timeout = 0;
InkRand generator;
// bitmap of query ids in use
uint64_t qid_in_flight[(USHRT_MAX + 1) / 64];
void
received_one(int i)
{
failover_number[i] = failover_soon_number[i] = crossed_failover_number[i] = 0;
}
void
sent_one()
{
++failover_number[name_server];
Debug("dns", "sent_one: failover_number for resolver %d is %d", name_server, failover_number[name_server]);
if (failover_number[name_server] >= dns_failover_number && !crossed_failover_number[name_server])
crossed_failover_number[name_server] = Thread::get_hrtime();
}
bool
failover_now(int i)
{
if (is_debug_tag_set("dns")) {
Debug("dns", "failover_now: Considering immediate failover, target time is %" PRId64 "",
(ink_hrtime)HRTIME_SECONDS(dns_failover_period));
Debug("dns", "\tdelta time is %" PRId64 "", (Thread::get_hrtime() - crossed_failover_number[i]));
}
return ns_down[i] || (crossed_failover_number[i] &&
((Thread::get_hrtime() - crossed_failover_number[i]) > HRTIME_SECONDS(dns_failover_period)));
}
bool
failover_soon(int i)
{
return ns_down[i] || (crossed_failover_number[i] &&
((Thread::get_hrtime() - crossed_failover_number[i]) >
(HRTIME_SECONDS(dns_failover_try_period + failover_soon_number[i] * FAILOVER_SOON_RETRY))));
}
void recv_dns(int event, Event *e);
int startEvent(int event, Event *e);
int startEvent_sdns(int event, Event *e);
int mainEvent(int event, Event *e);
void open_cons(sockaddr const *addr, bool failed = false, int icon = 0);
bool open_con(sockaddr const *addr, bool failed = false, int icon = 0, bool over_tcp = false);
void failover();
void rr_failure(int ndx);
void recover();
void retry_named(int ndx, ink_hrtime t, bool reopen = true);
void try_primary_named(bool reopen = true);
void switch_named(int ndx);
uint16_t get_query_id();
void
release_query_id(uint16_t qid)
{
qid_in_flight[qid >> 6] &= (uint64_t) ~(0x1ULL << (qid & 0x3F));
};
void
set_query_id_in_use(uint16_t qid)
{
qid_in_flight[qid >> 6] |= (uint64_t)(0x1ULL << (qid & 0x3F));
};
bool
query_id_in_use(uint16_t qid)
{
return (qid_in_flight[(uint16_t)(qid) >> 6] & (uint64_t)(0x1ULL << ((uint16_t)(qid)&0x3F))) != 0;
};
DNSHandler();
private:
// Check the IP address and switch to default if needed.
void validate_ip();
// Check tcp connection for TCP_RETRY mode
void check_and_reset_tcp_conn();
bool reset_tcp_conn(int ndx);
/** The event used for the periodic retry of connectivity to any down name
* servers. */
PendingAction _dns_retry_event;
};
/* --------------------------------------------------------------
** struct DNSServer
A record for an single server
-------------------------------------------------------------- */
struct DNSServer {
IpEndpoint x_server_ip[MAXNS];
char x_dns_ip_line[MAXDNAME * 2];
char x_def_domain[MAXDNAME];
char x_domain_srch_list[MAXDNAME];
DNSHandler *x_dnsH = nullptr;
DNSServer()
{
memset(x_server_ip, 0, sizeof(x_server_ip));
memset(x_def_domain, 0, MAXDNAME);
memset(x_domain_srch_list, 0, MAXDNAME);
memset(x_dns_ip_line, 0, MAXDNAME * 2);
}
};
TS_INLINE
DNSHandler::DNSHandler()
: Continuation(nullptr),
generator((uint32_t)((uintptr_t)time(nullptr) ^ (uintptr_t)this))
{
ats_ip_invalidate(&ip);
for (int i = 0; i < MAX_NAMED; i++) {
ifd[i] = -1;
failover_number[i] = 0;
failover_soon_number[i] = 0;
crossed_failover_number[i] = 0;
tcp_continuous_failures[i] = 0;
ns_down[i] = 1;
tcpcon[i].handler = this;
udpcon[i].handler = this;
}
memset(&qid_in_flight, 0, sizeof(qid_in_flight));
SET_HANDLER(&DNSHandler::startEvent);
Debug("net_epoll", "inline DNSHandler::DNSHandler()");
}