blob: a725b73686d4190d83c2a45d52eb75952c6c44e3 [file] [log] [blame]
/*
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.
*/
#ifndef DATASTAX_INTERNAL_NAME_RESOLVER_HPP
#define DATASTAX_INTERNAL_NAME_RESOLVER_HPP
#include "address.hpp"
#include "callback.hpp"
#include "ref_counted.hpp"
#include "string.hpp"
#include "timer.hpp"
#include <uv.h>
namespace datastax { namespace internal { namespace core {
class NameResolver : public RefCounted<NameResolver> {
public:
typedef SharedRefPtr<NameResolver> Ptr;
typedef internal::Callback<void, NameResolver*> Callback;
enum Status {
NEW,
RESOLVING,
FAILED_BAD_PARAM,
FAILED_UNABLE_TO_RESOLVE,
FAILED_TIMED_OUT,
CANCELED,
SUCCESS
};
NameResolver(const Address& address, const Callback& callback)
: address_(address)
, status_(NEW)
, uv_status_(-1)
, callback_(callback) {
req_.data = this;
}
uv_loop_t* loop() { return req_.loop; }
bool is_success() { return status_ == SUCCESS; }
bool is_canceled() { return status_ == CANCELED; }
bool is_timed_out() { return status_ == FAILED_TIMED_OUT; }
Status status() { return status_; }
int uv_status() { return uv_status_; }
const Address& address() const { return address_; }
const String& hostname() const { return hostname_; }
const String& service() const { return service_; }
void resolve(uv_loop_t* loop, uint64_t timeout, int flags = 0) {
status_ = RESOLVING;
inc_ref(); // For the event loop
if (timeout > 0) {
timer_.start(loop, timeout, bind_callback(&NameResolver::on_timeout, this));
}
Address::SocketStorage storage;
int rc = uv_getnameinfo(loop, &req_, on_resolve, address_.to_sockaddr(&storage), flags);
if (rc != 0) {
status_ = FAILED_BAD_PARAM;
timer_.stop();
uv_status_ = rc;
callback_(this);
dec_ref();
}
}
void cancel() {
if (status_ == RESOLVING) {
uv_cancel(reinterpret_cast<uv_req_t*>(&req_));
timer_.stop();
status_ = CANCELED;
}
}
private:
static void on_resolve(uv_getnameinfo_t* req, int status, const char* hostname,
const char* service) {
NameResolver* resolver = static_cast<NameResolver*>(req->data);
if (resolver->status_ == RESOLVING) { // A timeout may have happened
resolver->timer_.stop();
if (status != 0) {
resolver->status_ = FAILED_UNABLE_TO_RESOLVE;
} else {
if (hostname != NULL) {
resolver->hostname_ = hostname;
}
if (service != NULL) {
resolver->service_ = service;
}
resolver->status_ = SUCCESS;
}
}
resolver->uv_status_ = status;
resolver->callback_(resolver);
resolver->dec_ref();
}
void on_timeout(Timer* timer) {
status_ = FAILED_TIMED_OUT;
uv_cancel(reinterpret_cast<uv_req_t*>(&req_));
}
private:
uv_getnameinfo_t req_;
Timer timer_;
Address address_;
Status status_;
int uv_status_;
String hostname_;
String service_;
Callback callback_;
};
}}} // namespace datastax::internal::core
#endif