Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
added basic support for pluggable resolvers
  • Loading branch information
kraih committed Dec 11, 2014
1 parent 3f7dc3f commit 49acb93
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 3 deletions.
22 changes: 19 additions & 3 deletions lib/Mojo/IOLoop/Client.pm
Expand Up @@ -4,6 +4,7 @@ use Mojo::Base 'Mojo::EventEmitter';
use Errno 'EINPROGRESS';
use IO::Socket::IP;
use Mojo::IOLoop;
use Mojo::IOLoop::Resolver::Dummy;
use Scalar::Util 'weaken';
use Socket qw(IPPROTO_TCP TCP_NODELAY);

Expand All @@ -22,6 +23,8 @@ use constant SOCKS_READ => SOCKS ? IO::Socket::Socks::SOCKS_WANT_READ() : 0;
use constant SOCKS_WRITE => SOCKS ? IO::Socket::Socks::SOCKS_WANT_WRITE() : 0;

has reactor => sub { Mojo::IOLoop->singleton->reactor };
has resolver =>
sub { ($ENV{MOJO_RESOLVER} || 'Mojo::IOLoop::Resolver::Dummy')->new };

sub DESTROY { shift->_cleanup }

Expand All @@ -36,7 +39,19 @@ sub connect {
sub { $self->emit(error => 'Connect timeout') });

$_ && s/[[\]]//g for @$args{qw(address socks_address)};
$reactor->next_tick(sub { $self && $self->_connect($args) });
my $address = $args->{socks_address} || ($args->{address} ||= 'localhost');
return $reactor->next_tick(sub { $self && $self->_connect($args) })
if $address eq 'localhost' || $args->{handle};

$self->resolver->getaddrinfo(
$address => _port($args) => sub {
my ($resolver, $err, $addr_info) = @_;
return unless $self;
return $self->emit(error => "Can't resolve: $err") if $err;
$args->{addr_info} = $addr_info if $addr_info;
$self->_connect($args);
}
);
}

sub _cleanup {
Expand All @@ -50,13 +65,14 @@ sub _connect {
my ($self, $args) = @_;

my $handle;
my $address = $args->{socks_address} || ($args->{address} ||= 'localhost');
my $address = $args->{socks_address} || $args->{address};
unless ($handle = $self->{handle} = $args->{handle}) {
my %options = (
Blocking => 0,
PeerAddr => $address eq 'localhost' ? '127.0.0.1' : $address,
PeerPort => _port($args)
);
%options = (PeerAddrInfo => $args->{addr_info}) if $args->{addr_info};
$options{Blocking} = 0;
$options{LocalAddr} = $args->{local_address} if $args->{local_address};
return $self->emit(error => "Can't connect: $@")
unless $self->{handle} = $handle = IO::Socket::IP->new(%options);
Expand Down
11 changes: 11 additions & 0 deletions lib/Mojo/IOLoop/Resolver.pm
@@ -0,0 +1,11 @@
package Mojo::IOLoop::Resolver;
use Mojo::Base -base;

use Carp 'croak';
use Mojo::IOLoop;

has reactor => sub { Mojo::IOLoop->singleton->reactor };

sub getaddrinfo { croak 'Method "getaddrinfo" not implemented by subclass' }

1;
12 changes: 12 additions & 0 deletions lib/Mojo/IOLoop/Resolver/Dummy.pm
@@ -0,0 +1,12 @@
package Mojo::IOLoop::Resolver::Dummy;
use Mojo::Base 'Mojo::IOLoop::Resolver';

use Scalar::Util 'weaken';

sub getaddrinfo {
my ($self, $address, $port, $cb) = @_;
weaken $self;
$self->reactor->next_tick(sub { $self->$cb(undef, undef) });
}

1;
37 changes: 37 additions & 0 deletions lib/Mojo/IOLoop/Resolver/NDN.pm
@@ -0,0 +1,37 @@
package Mojo::IOLoop::Resolver::NDN;
use Mojo::Base 'Mojo::IOLoop::Resolver';

use Net::DNS::Native 0.13;
use Scalar::Util 'weaken';
use Socket 'IPPROTO_TCP';

has ndn => sub { Net::DNS::Native->new(pool => 5, extra_thread => 1) };

$ENV{MOJO_RESOLVER} ||= 'Mojo::IOLoop::Resolver::NDN';

sub DESTROY {
my $self = shift;
return unless my $reactor = $self->reactor;
if (my $dns = delete $self->{dns}) { $reactor->remove($dns) }
}

sub getaddrinfo {
my ($self, $address, $port, $cb) = @_;

my $handle = $self->{dns}
= $self->ndn->getaddrinfo($address, $port, {protocol => IPPROTO_TCP});

weaken $self;
$self->reactor->io(
$handle => sub {
my $reactor = shift;

$reactor->remove($self->{dns});
my ($err, @res) = $self->ndn->get_result(delete $self->{dns});

$self->$cb($err, \@res);
}
)->watch($handle, 1, 0);
}

1;

0 comments on commit 49acb93

Please sign in to comment.