Skip to content

Instantly share code, notes, and snippets.

@afeinberg
Created December 9, 2011 07:51
Show Gist options
  • Save afeinberg/1450668 to your computer and use it in GitHub Desktop.
Save afeinberg/1450668 to your computer and use it in GitHub Desktop.
Quick and dirty transliteration of the libevent2 book async DNS example to C++ -- based on http://www.wangafu.net/~nickm/libevent-book/Ref9_dns.html
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <string>
#include <iostream>
#include <sys/socket.h>
#include <event2/dns.h>
#include <event2/util.h>
#include <event2/event.h>
namespace {
class Resolver {
public:
Resolver();
virtual ~Resolver();
void submit(const std::string &name);
int pending_requests() const { return pending_requests_; }
void start() { event_base_dispatch(base_); }
void stop() { event_base_loopexit(base_, NULL); }
protected:
static void callback(int errcode, struct evutil_addrinfo *addr, void *ptr);
struct RequestContext {
Resolver *resolver_;
std::string name_;
};
void request_finished() { --pending_requests_; }
private:
int pending_requests_;
struct event_base *base_;
struct evdns_base *dns_base_;
};
Resolver::Resolver()
:base_(event_base_new()),
dns_base_(evdns_base_new(base_, 1)) { }
Resolver::~Resolver() {
if (dns_base_ != NULL) {
evdns_base_free(dns_base_, 0);
}
if (base_ != NULL) {
event_base_free(base_);
}
}
void Resolver::submit(const std::string &name) {
assert(base_ != NULL);
assert(dns_base_ != NULL);
struct evutil_addrinfo hints;
struct evdns_getaddrinfo_request *req;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = EVUTIL_AI_CANONNAME;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
RequestContext *ctx = new RequestContext;
ctx->resolver_ = this;
ctx->name_ = name;
++pending_requests_;
req = evdns_getaddrinfo(dns_base_,
name.c_str(),
NULL,
&hints,
callback,
ctx);
if (req == NULL) {
std::cerr << "Request for " << name << " returned immediately " << std::endl;
}
}
void Resolver::callback(int errcode, struct evutil_addrinfo *addr, void *ptr) {
RequestContext *ctx = static_cast<RequestContext *>(ptr);
if (errcode != 0) {
std::cerr << ctx->name_ << " -> " << evutil_gai_strerror(errcode)
<< std::endl;
goto cleanup;
}
struct evutil_addrinfo *ai;
std::cout << ctx->name_;
if (addr->ai_canonname) {
std::cout << "[" << addr->ai_canonname << "]";
}
for (ai = addr; ai != NULL; ai = ai->ai_next) {
char buf[128];
const char *s = NULL;
if (ai->ai_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
s = evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, 128);
} else if (ai->ai_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
s = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 128);
}
if (s != NULL) {
std::cout << " -> " << s;
}
}
std::cout << std::endl;
evutil_freeaddrinfo(addr);
cleanup:
ctx->resolver_->request_finished();
if (ctx->resolver_->pending_requests() == 0) {
ctx->resolver_->stop();
}
delete ctx;
}
} // namespace
int main(int /*argc*/, char /***argv*/) {
Resolver resolver;
std::string line;
while (std::getline(std::cin, line)) {
resolver.submit(line);
}
resolver.start();
return 0;
}
# -*- python -*-
env = Environment()
env.Append(CPPFLAGS='-g -Wall -Wextra')
env.Program(target='resolver',
source=['resolver.cc'],
LIBS=['event'])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment