File Coverage

blib/lib/Net/DRI.pm
Criterion Covered Total %
statement 147 183 80.3
branch 43 92 46.7
condition 10 24 41.6
subroutine 23 30 76.6
pod 1 14 7.1
total 224 343 65.3


line stmt bran cond sub pod time code
1             ## Domain Registry Interface, Main entry point
2             ##
3             ## Copyright (c) 2005-2016 Patrick Mevzek . All rights reserved.
4             ##
5             ## This file is part of Net::DRI
6             ##
7             ## Net::DRI is free software; you can redistribute it and/or modify
8             ## it under the terms of the GNU General Public License as published by
9             ## the Free Software Foundation; either version 2 of the License, or
10             ## (at your option) any later version.
11             ##
12             ## See the LICENSE file that comes with this distribution for more details.
13             ####################################################################################################
14              
15             package Net::DRI;
16              
17 75     75   121039 use strict;
  75         75  
  75         3040  
18 75     75   205 use warnings;
  75         64  
  75         1347  
19              
20 75     75   22292 use Net::DRI::Cache;
  75         162  
  75         350  
21 75     75   31188 use Net::DRI::Registry;
  75         106  
  75         295  
22 75     75   1930 use Net::DRI::Util;
  75         78  
  75         1011  
23 75     75   213 use Net::DRI::Exception;
  75         65  
  75         1112  
24              
25 75     75   198 use base qw(Class::Accessor::Chained::Fast Net::DRI::BaseClass);
  75         64  
  75         90146  
26             __PACKAGE__->mk_ro_accessors(qw/trid_factory logging cache/);
27              
28             our $AUTOLOAD;
29             our $VERSION='0.96_09';
30              
31             =pod
32              
33             =head1 NAME
34              
35             Net::DRI - Interface to Domain Name Registries/Registrars/Resellers
36              
37             =head1 VERSION
38              
39             This documentation refers to Net::DRI version 0.96_08
40              
41             =head1 SYNOPSIS
42              
43             use Net::DRI;
44             my $dri=Net::DRI->new({ cache_ttl => 10, trid_factory => ..., logging => .... });
45              
46             ... various operations ...
47              
48             $dri->end();
49              
50             =head1 DESCRIPTION
51              
52             Net::DRI is a Perl library to access services offered by domain name
53             providers, such as registries or registrars. DRI stands for
54             Domain Registration Interface and it aims to be
55             for domain name registries/registrars/resellers what DBI is for databases:
56             an abstraction over multiple providers, with multiple policies, transports
57             and protocols all used through a uniform API.
58              
59             It is an object-oriented framework implementing RRP (RFC 2832/3632),
60             EPP (core EPP in RFC 5730/5731/5732/5733/5734 aka STD69, extensions in
61             RFC 3915/4114/4310/5076 and various extensions of ccTLDs/gTLDs
62             - currently more than 60 TLDs are directly supported with extensions),
63             RRI (.DE registration protocol), Whois, DAS (Domain Availability Service used by .BE, .EU, .AU, .NL),
64             IRIS (RFC3981) DCHK (RFC5144) over LWZ (RFC4993) for .DE currently and XCP (RFC4992),
65             .FR/.RE email and webservices interface, and resellers interface of some registrars
66             (Gandi, OpenSRS, etc.).
67             It has transports for connecting with UDP/TCP/TLS, HTTP/HTTPS,
68             Web Services (XML-RPC and SOAP with/without WSDL),
69             or SMTP-based registries/registrars.
70              
71             It is not limited to handling of domain names, it can be easily extended.
72             For example, it supports ENUM registrations and validations, or DNSSEC provisioning.
73              
74             A shell is included for easy prototyping and debugging, see L.
75             Caching and logging features are also included by default.
76              
77             Please see the included README file for full details.
78              
79             =head1 EXAMPLES
80              
81             Please see the C subdirectory of the distribution, it contains various
82             examples. Please also see all unit tests under C, they show all parts of the API.
83              
84             =head1 SUBROUTINES/METHODS
85              
86             After having used Net::DRI (which is the only module you should need to C from
87             this distribution), you create an object as instance of this class,
88             and every operation will be carried through it.
89              
90             =head2 trid_factory()
91              
92             This is an accessor to the trid factory (code reference) used to generate client
93             transaction identificators, that are useful for logging and asynchronous operations.
94              
95             During the C call, a C is initialized to a default safe value
96             (being Net::DRI::Util::create_trid_1).
97              
98             You need to call this method only if you wish to use another function to generate transaction identificators.
99              
100             All other objects (registry profiles and transports)
101             created after that will inherit this value. If you call again C
102             the change will only apply to new objects (registry profiles and transports) created after the change,
103             it will not apply to already existing objects (registry profiles and transports).
104              
105             =head2 logging()
106              
107             This is an accessor to the underlying Logging object. During the C call you can
108             provide the object, or just a string ("null", "stderr", "files" or "syslog" which are the
109             current logging modules available in Net::DRI), or a reference to an array
110             with the first parameter a string (same as previously) and the second parameter a reference to
111             an hash with data needed by the logging class used (see for example L).
112              
113             If you want to log the application data (what is exchanged with remote server, such as EPP XML streams),
114             you need to use logging level of 'notice', or higher.
115              
116             =head2 cache()
117              
118             This is an accessor to the underlying Cache object. See L.
119             This object has a C method to access and change the current time to live
120             for cached data.
121              
122             =head1 SUPPORT
123              
124             For now, support questions should be sent to:
125              
126             Enetdri@dotandco.comE
127              
128             Please also see the SUPPORT file in the distribution.
129              
130             =head1 SEE ALSO
131              
132             L
133              
134             =head1 AUTHOR
135              
136             Patrick Mevzek, Enetdri@dotandco.comE
137             and various contributors (see Changes file and web page above)
138              
139             =head1 COPYRIGHT
140              
141             Copyright (c) 2005-2016 Patrick Mevzek .
142             All rights reserved.
143              
144             =head1 LICENSE
145              
146             This program is free software; you can redistribute it and/or modify
147             it under the terms of the GNU General Public License as published by
148             the Free Software Foundation; either version 2 of the License, or
149             (at your option) any later version.
150              
151             See the LICENSE file that comes with this distribution for more details.
152              
153             =cut
154              
155             ####################################################################################################
156              
157             sub new
158             {
159 68     68 1 121107 my ($class,$rh)=@_;
160              
161             my $self={ cache => Net::DRI::Cache->new(Net::DRI::Util::has_key($rh,'cache_ttl') ? $rh->{cache_ttl} : 0),
162             current_registry => undef, ## registry name (key of following hash)
163             registries => {}, ## registry name => Net::DRI::Registry object
164             tlds => {}, ## tld => [ registries name ]
165             time_created => time(),
166 68 100 66     365 trid_factory => (Net::DRI::Util::has_key($rh,'trid_factory') && ref $rh->{trid_factory} eq 'CODE')? $rh->{trid_factory} : \&Net::DRI::Util::create_trid_1,
    100          
167             };
168              
169 68         117 my ($logname,@logdata);
170 68 100       177 if (Net::DRI::Util::has_key($rh,'logging'))
171             {
172 5 50       22 ($logname,@logdata)=ref $rh->{logging} eq 'ARRAY' ? @{$rh->{logging}} : ($rh->{logging});
  0         0  
173             } else
174             {
175 63         119 $logname='null';
176             }
177 68 50       262 if ($logname !~ s/^\+//) { $logname='Net::DRI::Logging::'.ucfirst($logname); }
  68         225  
178 68         268 Net::DRI::Util::load_module($logname,'DRI');
179 68         532 $self->{logging}=$logname->new(@logdata);
180              
181 68         172 bless($self,$class);
182 68         408 $self->logging()->setup_channel(__PACKAGE__,'core');
183 68         507 $self->log_output('notice','core','Successfully created Net::DRI object with logging='.$logname);
184 68         165 return $self;
185             }
186              
187             sub add_current_registry
188             {
189 36     36 0 320 my ($self,@p)=@_;
190 36         103 $self->add_registry(@p);
191 36         134 $self->target($self->{last_registry});
192 36         87 return $self;
193             }
194              
195             sub add_registry
196             {
197 68     68 0 154 my ($self,$reg,@data)=@_;
198 68 50       215 Net::DRI::Exception::usererr_insufficient_parameters('add_registry needs a registry name') unless Net::DRI::Util::all_valid($reg);
199 68 50       291 $reg='Net::DRI::DRD::'.$reg unless $reg=~m/^\+/;
200 68         196 Net::DRI::Util::load_module($reg,'DRI');
201              
202 66         407 my $drd=$reg->new(@data);
203 66 50 33     486 Net::DRI::Exception->die(1,'DRI',9,'Failed to initialize registry '.$reg) unless ($drd && ref $drd);
204              
205 66 50       516 Net::DRI::Exception::method_not_implemented('name',$reg) unless $drd->can('name');
206 66         195 my $regname=$drd->name();
207 66 50       347 Net::DRI::Exception->die(1,'DRI',10,'No dot allowed in registry name: '.$regname) unless index($regname,'.') == -1;
208 66 50       282 Net::DRI::Exception->die(1,'DRI',11,'New registry name already in use') if exists $self->{registries}->{$regname};
209              
210 66         630 my $ndr=Net::DRI::Registry->new($regname,$drd,$self->{cache},$self->{trid_factory},$self->{logging});
211 66 50       279 Net::DRI::Exception::method_not_implemented('tlds',$reg) unless $drd->can('tlds');
212 66         204 foreach my $tld ($drd->tlds())
213             {
214 410         425 $tld=lc($tld);
215 410 50       954 $self->{tlds}->{$tld}=[] unless exists $self->{tlds}->{$tld};
216 410         288 push @{$self->{tlds}->{$tld}},$regname;
  410         751  
217             }
218              
219 66         409 $self->log_output('notice','core','Successfully added registry "'.$regname.'"');
220 66         186 $self->{registries}->{$regname}=$ndr;
221 66         229 $self->{last_registry}=$regname;
222 66         164 return $self;
223             }
224              
225             sub del_registry
226             {
227 0     0 0 0 my ($self,$name)=@_;
228 0 0       0 if (defined $name)
229             {
230 0 0       0 err_registry_name_does_not_exist($name) unless exists $self->{registries}->{$name};
231             } else
232             {
233 0 0       0 err_no_current_registry() unless defined $self->{current_registry};
234 0         0 $name=$self->{current_registry};
235             }
236 0         0 $self->{registries}->{$name}->end();
237 0         0 delete($self->{registries}->{$name});
238 0 0       0 $self->{current_registry}=undef if $self->{current_registry} eq $name;
239 0         0 $self->log_output('notice','core','Successfully deleted registry "'.$name.'"');
240 0         0 return $self;
241             }
242              
243             ####################################################################################################
244              
245 0     0 0 0 sub err_no_current_registry { Net::DRI::Exception->die(0,'DRI',1,'No current registry available'); } ## no critic (Subroutines::RequireArgUnpacking Subroutines::RequireFinalReturn)
246 0     0 0 0 sub err_registry_name_does_not_exist { Net::DRI::Exception->die(0,'DRI',2,'Registry name '.$_[0].' does not exist'); } ## no critic (Subroutines::RequireArgUnpacking Subroutines::RequireFinalReturn)
247              
248             ####################################################################################################
249             ## Accessor functions
250              
251 0     0 0 0 sub available_registries { my ($self)=@_; my @r=sort { $a cmp $b } keys %{$self->{registries}}; return @r; }
  0         0  
  0         0  
  0         0  
  0         0  
252             sub available_registries_profiles
253             {
254 0     0 0 0 my ($self,$full)=@_;
255 0         0 my %r;
256 0         0 foreach my $reg (keys(%{$self->{registries}}))
  0         0  
257             {
258 0         0 $r{$reg}=[ $self->{registries}->{$reg}->available_profiles($full) ];
259             }
260 0         0 return \%r;
261             }
262 108     108 0 228 sub registry_name { return shift->{current_registry}; }
263              
264             sub registry
265             {
266 108     108 0 149 my ($self)=@_;
267 108         332 my $regname=$self->registry_name();
268 108 50 33     578 err_no_current_registry() unless (defined($regname) && $regname);
269 108 50       315 err_registry_name_does_not_exist($regname) unless (exists($self->{registries}->{$regname}));
270 108         165 my $ndr=$self->{registries}->{$regname};
271 108 50       461 return wantarray? ($regname,$ndr) : $ndr;
272             }
273              
274             sub tld2reg
275             {
276 2     2 0 2 my ($self,$tld)=@_;
277 2 50 33     9 return unless defined($tld) && $tld;
278 2         4 $tld=lc($tld);
279 2 50       7 $tld=$1 if ($tld=~m/\.([a-z0-9]+)$/);
280 2 50       15 return unless exists($self->{tlds}->{$tld});
281 2         4 my @t=@{$self->{tlds}->{$tld}};
  2         4  
282 2         5 return @t;
283             }
284              
285             sub installed_registries
286             {
287 0     0 0 0 return qw/AdamsNames Afilias AFNIC ARNES auDA BelizeNIC BookMyName CentralNic CGIBR CIRA CoCCA CZNIC Datacom DENIC DNSBelgium DNSPT doMEn Domicilium DotAsia DotCooperation dotMOBI EURid Gandi GDI ICMRegistry IENUMAT IRegistry ISPAPI IIS IITCNR IUSN NASK Neustar::BIZ Neustar::US NicAT NicLC Nominet NORID OpenSRS OVH PANDI PIR puntCAT RDS RegistryPro RESTENA SaintVincentGrenadines SIDN SITA SONIC SWITCH TCI TELEGreenland Telnic TRA Tralliance UHSA UPU VCS VeriSign::COM_NET VeriSign::NAME VeriSign::NameStore ZACR/;
288             }
289              
290             ####################################################################################################
291              
292             sub target
293             {
294 66     66 0 134 my ($self,$driver,$profile)=@_;
295              
296             ## Try to convert if given a domain name or a tld instead of a driver's name
297 66 100 66     488 if (defined $driver && ! exists $self->{registries}->{$driver})
298             {
299 2         10 my @t=$self->tld2reg($driver);
300 2 50       6 Net::DRI::Exception->die(0,'DRI',7,'Registry not found for domain name/TLD '.$driver) unless (@t==1);
301 2         3 $driver=$t[0];
302             }
303              
304 66 50       249 $driver=$self->registry_name() unless defined $driver;
305 66 50 33     444 err_registry_name_does_not_exist($driver) unless defined $driver && $driver;
306              
307 66 50       359 if (defined $profile)
308             {
309 0         0 $self->{registries}->{$driver}->target($profile);
310             }
311              
312 66         130 $self->{current_registry}=$driver;
313 66         198 return $self;
314             }
315              
316             ####################################################################################################
317             ## The meat of everything
318             ## See Cookbook, page 468
319             sub AUTOLOAD
320             {
321 108     108   686 my ($self,@args)=@_;
322 108         150 my $attr=$AUTOLOAD;
323 108         693 $attr=~s/.*:://;
324 108 50       506 return unless $attr=~m/[^A-Z]/; ## skip DESTROY and all-cap methods
325              
326 108         354 my ($name,$ndr)=$self->registry();
327 108 50 33     647 Net::DRI::Exception::method_not_implemented($attr,$ndr) unless ref $ndr && $ndr->can($attr);
328 108         562 $self->log_output('debug','core','Calling '.$attr.' from Net::DRI');
329 108         432 return $ndr->$attr(@args); ## is goto beter here ?
330             }
331              
332             sub end
333             {
334 68     68 0 113 my $self=shift;
335 68         112 while(my ($name,$v)=each(%{$self->{registries}}))
  134         635  
336             {
337 66 50 33     397 $v->end() if (ref($v) && $v->can('end'));
338 66         408 $self->log_output('notice','core','Successfully ended registry "'.$name.'"');
339 66         157 $v={};
340             }
341 68         163 $self->{tlds}={};
342 68         355 $self->{registries}={};
343 68         914 $self->{current_registry}=undef;
344 68 50       292 if (defined $self->{logging})
345             {
346 68         220 $self->log_output('notice','core','Successfully ended Net::DRI object');
347 68         114 $self->{logging}=undef;
348             }
349              
350 68         1057 return 1; ## this makes it easy to test if everything before was ok or not, if we are inside an eval {} and $dri->end() is the last operation inside the eval block
351             }
352              
353 68     68   774 sub DESTROY { my $self=shift; return $self->end(); }
  68         239  
354              
355             ####################################################################################################
356              
357             package Net::DRI::TrapExceptions; ## no critic (Modules::ProhibitMultiplePackages)
358              
359 75     75   363 use base qw/Net::DRI/;
  75         77  
  75         26185  
360              
361             our $AUTOLOAD;
362              
363             ## Some methods may die in Net::DRI, we specifically trap them
364 58 100   58   236 sub add_registry { my ($self,@p)=@_; my $r; my $ok=eval { $r=$self->SUPER::add_registry(@p); 1; }; return $r if $ok; die(ref $@ ? $@->as_string() : $@); }
  58 50       69  
  58         72  
  58         278  
  56         103  
  58         249  
  2         12  
365 0 0   0   0 sub del_registry { my ($self,@p)=@_; my $r; my $ok=eval { $r=$self->SUPER::del_registry(@p); 1; }; return $r if $ok; die(ref $@ ? $@->as_string() : $@); }
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
366 94 50   94   142 sub registry { my ($self,@p)=@_; my @r; my $ok=eval { @r=$self->SUPER::registry(@p); 1; }; if ($ok) { return wantarray ? @r : $r[0]; } die(ref $@ ? $@->as_string() : $@); }
  94 50       104  
  94 0       111  
  94         337  
  94         142  
  94         215  
  94         312  
  0         0  
367 56 50   56   182 sub target { my ($self,@p)=@_; my $r; my $ok=eval { $r=$self->SUPER::target(@p); 1; }; return $r if $ok; die(ref $@ ? $@->as_string() : $@); }
  56 0       77  
  56         77  
  56         363  
  56         126  
  56         510  
  0         0  
368 58 50   58   120 sub end { my ($self,@p)=@_; my $r; my $ok=eval { $r=$self->SUPER::end(@p); 1; }; return $r if $ok; die(ref $@ ? $@->as_string() : $@); }
  58 0       87  
  58         89  
  58         619  
  58         110  
  58         2188  
  0         0  
369              
370             sub AUTOLOAD
371             {
372 94     94   7455 my $self=shift;
373 94         123 my @r;
374 94         138 $Net::DRI::AUTOLOAD=$AUTOLOAD;
375 94         119 my $ok=eval { @r=$self->SUPER::AUTOLOAD(@_); 1; };
  94         376  
  39         64  
376 94 100       275 if (! $ok)
377             {
378 55         82 my $err=$@;
379 55 50       333 die(ref $err ? $err->as_string() : $err);
380             }
381 39 50       153 return wantarray ? @r : $r[0];
382             }
383              
384             ####################################################################################################
385             1;