class ResolverNSASCallback : public isc::nsas::AddressRequestCallback {
public:
ResolverNSASCallback(RunningQuery* rq) : rq_(rq) {}
-
+
void success(const isc::nsas::NameserverAddress& address) {
// Success callback, send query to found namesever
LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CB, RESLIB_RUNQ_SUCCESS)
rq_->nsasCallbackCalled();
rq_->sendTo(address);
}
-
+
void unreachable() {
// Nameservers unreachable: drop query or send servfail?
LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CB, RESLIB_RUNQ_FAIL);
bool done_;
// If we have a client timeout, we call back with a failure message,
- // but we do not stop yet. We use this variable to make sure we
+ // but we do not stop yet. We use this variable to make sure we
// don't call back a second time later
bool callback_called_;
// Reference to our cache
isc::cache::ResolverCache& cache_;
-
+
// the 'current' zone we are in (i.e.) we start out at the root,
// and for each delegation this gets updated with the zone the
// delegation points to.
// of the call we use it in take a string, we need update those
// too).
std::string cur_zone_;
-
+
// This is the handler we pass on to the NSAS; it is called when
// the NSAS has an address for us to query
boost::shared_ptr<ResolverNSASCallback> nsas_callback_;
// The moment in time we sent a query to the nameserver above.
struct timeval current_ns_qsent_time;
-
+
// RunningQuery deletes itself when it is done. In order for us
// to do this safely, we must make sure that there are no events
// that might call back to it. There are two types of events in
io_.get_io_service().post(query);
}
}
-
+
// 'general' send, ask the NSAS to give us an address.
void send(IOFetch::Protocol protocol = IOFetch::UDP, bool edns = true) {
protocol_ = protocol; // Store protocol being used for this
nsas_.lookup(cur_zone_, question_.getClass(), nsas_callback_);
}
}
-
+
// Called by our NSAS callback handler so we know we do not have
// an outstanding NSAS call anymore.
void nsasCallbackCalled() {
// here (classify() will set it when it walks through
// the cname chain to verify it).
Name cname_target(question_.getName());
-
+
isc::resolve::ResponseClassifier::Category category =
isc::resolve::ResponseClassifier::classify(
question_, incoming, cname_target, cname_count_);
bool found_ns = false;
-
+
switch (category) {
case isc::resolve::ResponseClassifier::ANSWER:
case isc::resolve::ResponseClassifier::ANSWERCNAME:
// SERVFAIL if we get FORMERR instead
}
goto SERVFAIL;
-
+
default:
SERVFAIL:
// Some error in received packet it. Report it and return SERVFAIL
++outstanding_events_;
lookup_timer.async_wait(boost::bind(&RunningQuery::lookupTimeout, this));
}
-
+
// Setup the timer to send an answer (client_timeout)
if (client_timeout >= 0) {
client_timer.expires_from_now(
++outstanding_events_;
client_timer.async_wait(boost::bind(&RunningQuery::clientTimeout, this));
}
-
+
doLookup();
}
--outstanding_events_;
stop();
}
-
+
// called if we have a client timeout; if our callback has
// not been called, call it now. But do not stop.
void clientTimeout() {
// XXX is this the place for TCP retry?
assert(outstanding_events_ > 0);
--outstanding_events_;
-
+
if (!done_ && result != IOFetch::TIME_OUT) {
// we got an answer
stop();
}
}
-
+
// Clear the answer parts of answer_message, and set the rcode
// to servfail
void makeSERVFAIL() {
// Message found, return that
LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_CACHE, RESLIB_RECQ_CACHE_FIND)
.arg(questionText(*question)).arg(1);
-
+
// TODO: err, should cache set rcode as well?
answer_message->setRcode(Rcode::NOERROR());
callback->success(answer_message);
// TODO: general 'prepareinitialanswer'
answer_message->setOpcode(isc::dns::Opcode::QUERY());
answer_message->addQuestion(question);
-
+
// First try to see if we have something cached in the messagecache
LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RESOLVE)
.arg(questionText(question)).arg(2);
-
+
if (cache_.lookup(question.getName(), question.getType(),
question.getClass(), *answer_message) &&
answer_message->getRRCount(Message::SECTION_ANSWER) > 0) {
// delete itself when it is done
LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_RECQ_CACHE_NO_FIND)
.arg(questionText(question)).arg(2);
- new RunningQuery(io, question, answer_message,
+ new RunningQuery(io, question, answer_message,
test_server_, buffer, crs, query_timeout_,
client_timeout_, lookup_timeout_, retries_,
nsas_, cache_, rtt_recorder_);
}
// Receive a UDP packet from a mock server; used for testing
- // recursive lookup. The caller must place a RecursiveQuery
+ // recursive lookup. The caller must place a RecursiveQuery
// on the IO Service queue before running this routine.
void recvUDP(const int family, void* buffer, size_t& size) {
ScopedAddrInfo sai(resolveAddress(family, IPPROTO_UDP, true));
if (ret < 0) {
isc_throw(IOError, "recvfrom failed: " << strerror(errno));
}
-
+
// Pass the message size back via the size parameter
size = ret;
}
return (sock.release());
}
-int
-setSocketTimeout(int sock, size_t tv_sec, size_t tv_usec) {
- const struct timeval timeo = { tv_sec, tv_usec };
- int recv_options = 0;
- if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo))) {
- if (errno == ENOPROTOOPT) { // see RecursiveQueryTest::recvUDP()
- recv_options = MSG_DONTWAIT;
- } else {
- isc_throw(IOError, "set RCVTIMEO failed: " << strerror(errno));
- }
- }
- return (recv_options);
-}
-
-// try to read from the socket max time
-// *num is incremented for every succesfull read
-// returns true if it can read max times, false otherwise
-bool tryRead(int sock, int recv_options, size_t max, int* num) {
- size_t i = 0;
- do {
- char inbuff[512];
- if (recv(sock, inbuff, sizeof(inbuff), recv_options) < 0) {
- return false;
- } else {
- ++i;
- ++*num;
- }
- } while (i < max);
- return true;
-}
-
// Mock resolver callback for testing forward query.
class MockResolverCallback : public isc::resolve::ResolverInterface::Callback {
public:
TEST_F(RecursiveQueryTest, DISABLED_recursiveSendOk) {
setDNSService(true, false);
bool done;
-
+
MockServerStop server(io_service_, &done);
vector<pair<string, uint16_t> > empty_vector;
RecursiveQuery rq(*dns_service_, *nsas_, cache_, empty_vector,
TEST_F(RecursiveQueryTest, DISABLED_recursiveSendNXDOMAIN) {
setDNSService(true, false);
bool done;
-
+
MockServerStop server(io_service_, &done);
vector<pair<string, uint16_t> > empty_vector;
RecursiveQuery rq(*dns_service_, *nsas_, cache_, empty_vector,