File Coverage

blib/lib/Net/SIP/Dispatcher.pm
Criterion Covered Total %
statement 379 583 65.0
branch 142 280 50.7
condition 60 136 44.1
subroutine 43 58 74.1
pod 12 17 70.5
total 636 1074 59.2


line stmt bran cond sub pod time code
1              
2             ###########################################################################
3             # package Net::SIP::Dispatcher
4             #
5             # Manages the sending of SIP packets to the legs (and finding out which
6             # leg can be used) and the receiving of SIP packets and forwarding to
7             # the upper layer.
8             # Handles retransmits
9             ###########################################################################
10              
11 41     41   269 use strict;
  41         85  
  41         1168  
12 41     41   195 use warnings;
  41         72  
  41         1932  
13              
14             package Net::SIP::Dispatcher;
15             use fields (
16             # interface to outside
17 41         186 'receiver', # callback into upper layer
18             'legs', # \@list of Net::SIP::Legs managed by dispatcher
19             'eventloop', # Net::SIP::Dispatcher::Eventloop or similar
20             'outgoing_proxy', # optional fixed outgoing proxy
21             'domain2proxy', # optional mapping between SIP domains and proxies (otherwise use DNS)
22             # internals
23             'do_retransmits', # flag if retransmits will be done (false for stateless proxy)
24             'queue', # \@list of outstanding Net::SIP::Dispatcher::Packet
25             'response_cache', # Cache of responses, used to reply to retransmits
26             'disp_expire', # expire/retransmit timer
27             'dnsresolv', # optional external DNS resolver
28 41     41   256 );
  41         70  
29              
30 41     41   23883 use Net::SIP::Leg;
  41         162  
  41         1471  
31 41     41   343 use Net::SIP::Util ':all';
  41         89  
  41         7917  
32 41     41   320 use Net::SIP::Dispatcher::Eventloop;
  41         81  
  41         1942  
33 41     41   341 use Errno qw(EHOSTUNREACH ETIMEDOUT ENOPROTOOPT);
  41         74  
  41         1899  
34 41     41   217 use IO::Socket;
  41         87  
  41         354  
35 41     41   18970 use List::Util 'first';
  41         119  
  41         2496  
36 41     41   258 use Hash::Util 'lock_ref_keys';
  41         129  
  41         182  
37 41     41   2254 use Carp 'croak';
  41         103  
  41         1768  
38 41     41   319 use Net::SIP::Debug;
  41         138  
  41         294  
39 41     41   287 use Scalar::Util 'weaken';
  41         146  
  41         2164  
40              
41             # The maximum priority value in SRV records is 0xffff and the lowest priority
42             # value is considered the best. Make undefined priority higher so that it gets
43             # considered as last option.
44 41     41   265 use constant SRV_PRIO_UNDEF => 0x10000;
  41         84  
  41         85812  
45              
46             ###########################################################################
47             # create new dispatcher
48             # Args: ($class,$legs,$eventloop;%args)
49             # $legs: \@array, see add_leg()
50             # $eventloop: Net::SIP::Dispatcher::Eventloop or similar
51             # %args:
52             # outgoing_proxy: optional outgoing proxy (ip:port)
53             # do_retransmits: set if the dispatcher has to handle retransmits by itself
54             # defaults to true
55             # domain2proxy: mappings { domain => proxy } if a fixed proxy is used
56             # for specific domains, otherwise lookup will be done per DNS
57             # proxy can be ip,ip:port or \@list of hash with keys prio, proto, host,
58             # port and family like in the DNS SRV record
59             # with special domain '*' a default can be specified, so that DNS
60             # will not be used at all
61             # dnsresolv: DNS resolver function with interface sub->(type,domain,callback)
62             # which then calls callback->(\@result) with @result being a list of
63             # [ 'SRV',prio,target,port], ['A',ip,name], ['AAAA',ip,name]
64             # Returns: $self
65             ###########################################################################
66             sub new {
67 55     55 1 587 my ($class,$legs,$eventloop,%args) = @_;
68              
69             my ($outgoing_proxy,$do_retransmits,$domain2proxy,$dnsresolv) = delete
70 55         449 @args{qw( outgoing_proxy do_retransmits domain2proxy dnsresolv)};
71 55 50       327 die "bad args: ".join( ' ',keys %args ) if %args;
72              
73 55   33     204 $eventloop ||= Net::SIP::Dispatcher::Eventloop->new;
74              
75             # normalize domain2proxy so that its the same format one gets from
76             # the SRV record
77 55   100     560 $domain2proxy ||= {};
78 55         256 foreach ( values %$domain2proxy ) {
79 30 50       161 if ( ref($_) ) {
80             # should be \@list of [ prio,proto,ip,port,?family ]
81             } else {
82 30 50       152 my ($proto,$host,$port,$family) = sip_uri2sockinfo($_)
83             or croak( "invalid entry in domain2proxy: $_" );
84 30 0 0     135 $port ||= $proto && $proto eq 'tls' ? 5061:5060;
      33        
85 30 50       127 $_ = [ map { lock_ref_keys({
  48 100       967  
86             prio => SRV_PRIO_UNDEF,
87             proto => $_,
88             host => $host,
89             addr => $family ? $host : undef,
90             port => $port,
91             family => $family
92             }) } $proto ? ($proto) : ('udp','tcp') ];
93             }
94             }
95              
96 55         580 my $self = fields::new($class);
97 55 50       7982 %$self = (
98             legs => [],
99             queue => [],
100             outgoing_proxy => undef,
101             response_cache => {},
102             do_retransmits => defined( $do_retransmits ) ? $do_retransmits : 1,
103             eventloop => $eventloop,
104             domain2proxy => $domain2proxy,
105             dnsresolv => $dnsresolv,
106             );
107              
108 55         1782 $self->add_leg( @$legs );
109              
110 55 50       239 $self->outgoing_proxy($outgoing_proxy) if $outgoing_proxy;
111              
112             # regularly prune queue
113             my $sub = sub {
114 168     168   868 my ($self,$timer) = @_;
115 168 50       1342 if ( $self ) {
116 168         1254 $self->queue_expire( $self->{eventloop}->looptime );
117             } else {
118 0         0 $timer->cancel;
119             }
120 55         1564 };
121 55         280 my $cb = [ $sub,$self ];
122 55         686 weaken( $cb->[1] );
123 55         744 $self->{disp_expire} = $self->add_timer( 1,$cb,1,'disp_expire' );
124              
125 55         316 return $self;
126             }
127              
128             ###########################################################################
129             # get or set outgoing proxy
130             # Args: ($self;$proxy)
131             # $proxy: optional new proxy or undef if proxy should be none
132             # Returns:
133             # $proxy: current setting, i.e. after possible update
134             ###########################################################################
135             sub outgoing_proxy {
136 0     0 1 0 my Net::SIP::Dispatcher $self = shift;
137 0 0       0 return $self->{outgoing_proxy} if ! @_;
138 0         0 my $outgoing_proxy = shift;
139 0   0     0 my $leg = $self->_find_leg4addr( $outgoing_proxy )
140             || die "cannot find leg for destination $outgoing_proxy";
141 0         0 $self->{outgoing_proxy} = $outgoing_proxy;
142             }
143              
144              
145             ###########################################################################
146             # get or set the event loop
147             # Args: ($self;$loop)
148             # $loop: optional new loop
149             # Returns:
150             # $loop: current setting, i.e. after possible update
151             ###########################################################################
152             sub loop {
153 0     0 0 0 my Net::SIP::Dispatcher $self = shift;
154 0 0       0 return $self->{eventloop} if ! @_;
155 0         0 $self->{eventloop} = shift;
156             }
157              
158              
159             ###########################################################################
160             # set receiver, e.g the upper layer which gets the incoming packets
161             # received by the dispatcher
162             # Args: ($self,$receiver)
163             # $receiver: object which has receive( Net::SIP::Leg,Net::SIP::Packet )
164             # method to handle incoming SIP packets or callback
165             # might be undef - in this case the existing receiver will be removed
166             # Returns: NONE
167             ###########################################################################
168             sub set_receiver {
169 57     57 1 282 my Net::SIP::Dispatcher $self = shift;
170 57 50       1274 if ( my $receiver = shift ) {
171 57 100       378 if ( my $sub = UNIVERSAL::can($receiver,'receive' )) {
172             # Object with method receive()
173 5         29 $receiver = [ $sub,$receiver ]
174             }
175 57         203 $self->{receiver} = $receiver;
176             } else {
177             # remove receiver
178             $self->{receiver} = undef
179 0         0 }
180              
181             }
182              
183             ###########################################################################
184             # adds a leg to the dispatcher
185             # Args: ($self,@legs)
186             # @legs: can be sockets, \%args for constructing or already
187             # objects of class Net::SIP::Leg
188             # Returns: NONE
189             ###########################################################################
190             sub add_leg {
191 107     107 1 391 my Net::SIP::Dispatcher $self = shift;
192 107         311 my $legs = $self->{legs};
193 107         598 foreach my $arg (@_) {
194              
195 57         126 my $leg;
196             # if it is not a leg yet create one based
197             # on the arguments
198 57 50       312 if ( UNIVERSAL::isa( $arg,'Net::SIP::Leg' )) {
    0          
    0          
199             # already a leg
200 57         183 $leg = $arg;
201              
202             } elsif ( UNIVERSAL::isa( $arg,'IO::Handle' )) {
203             # create from socket
204 0         0 $leg = Net::SIP::Leg->new( sock => $arg );
205              
206             } elsif ( UNIVERSAL::isa( $arg,'HASH' )) {
207             # create from %args
208 0         0 $leg = Net::SIP::Leg->new( %$arg );
209             } else {
210 0         0 croak "invalid spec for leg: $arg";
211             }
212              
213 57         150 push @$legs, $leg;
214              
215 57 50       1229 if (my $socketpool = $leg->socketpool) {
216             my $cb = sub {
217             # don't crash Dispatcher on bad or unexpected packets
218 204 50   204   481 eval {
219 204         675 my ($self,$leg,$packet,$from) = @_;
220 204 50       598 $self || return;
221              
222 204 50       1344 ($packet,$from) = $leg->receive($packet,$from) or return;
223              
224 204 100       1064 if ($packet->is_request) {
225             # add received and rport to top via
226             $packet->scan_header( via => [ sub {
227 65         208 my ($vref,$hdr) = @_;
228 65 50       378 return if $$vref++;
229 65         576 my ($d,$h) = sip_hdrval2parts(via => $hdr->{value});
230 65 50       938 my ($host,$port) = $d =~m{^SIP/2\S+\s+(\S+)$}
231             ? ip_string2parts($1):();
232 65         156 my %nh;
233 65 50 33     311 if ( exists $h->{rport} and ! defined $h->{rport}) {
234 0         0 $nh{rport} = $from->{port};
235             }
236 65 50       377 if ($host ne $from->{addr}) {
    50          
237             # either from.addr is the addr for host or we
238             # had a different IP address in the via header
239 0         0 $nh{received} = $from->{addr};
240             } elsif ($nh{rport}) {
241             # required because rport was set
242 0         0 $nh{received} = $from->{addr};
243             }
244 65 50       542 if (%nh) {
245 0         0 $hdr->{value} = sip_parts2hdrval('via',$d,{ %$h,%nh});
246 0         0 $hdr->set_modified;
247             }
248 65         2033 }, \( my $cvia )]);
249             }
250              
251             # handle received packet
252 204         1892 $self->receive( $packet,$leg,$from );
253 204         2835 1;
254             } or DEBUG(1,"dispatcher croaked: $@");
255 57         1216 };
256 57         268 $cb = [ $cb,$self,$leg ];
257 57         344 weaken($cb->[1]);
258 57         216 weaken($cb->[2]);
259 57         421 $socketpool->attach_eventloop($self->{eventloop}, $cb);
260             }
261             }
262             }
263              
264             ###########################################################################
265             # remove a leg from the dispatcher
266             # Args: ($self,@legs)
267             # @legs: Net::SIP::Leg objects
268             # Returns: NONE
269             ###########################################################################
270             sub remove_leg {
271 51     51 1 132 my Net::SIP::Dispatcher $self = shift;
272 51         144 my $legs = $self->{legs};
273 51         585 foreach my $leg (@_) {
274 51         217 @$legs = grep { $_ != $leg } @$legs;
  51         300  
275 51 50       285 if ( my $pool = $leg->socketpool ) {
276 51         291 $pool->attach_eventloop();
277             }
278             }
279             }
280              
281             ###########################################################################
282             # find legs matching specific criterias
283             # Args: ($self,%args)
284             # %args: Hash with some of these keys
285             # addr: leg must match addr
286             # port: leg must match port
287             # proto: leg must match proto
288             # sub: $sub->($leg) must return true
289             # Returns: @legs
290             # @legs: all Legs matching the criteria
291             # Comment:
292             # if no criteria given it will return all legs
293             ###########################################################################
294             sub get_legs {
295 153     153 1 409 my Net::SIP::Dispatcher $self = shift;
296 153 100       458 return @{ $self->{legs} } if ! @_; # shortcut
  151         792  
297              
298 2         8 my %args = @_;
299 2         3 my @rv;
300 2         2 foreach my $leg (@{ $self->{legs} }) {
  2         6  
301 2 50       23 push @rv,$leg if $leg->match(\%args);
302             }
303 2         9 return @rv;
304             }
305              
306              
307             ###########################################################################
308             # map leg to index in list of legs
309             # Args: @legs,[\$dict]
310             # @legs: list of legs
311             # $dict: string representation of dictionary, used in i2leg and others
312             # to make sure that it the indices come from the same list of legs.
313             # Will be set if given
314             # Returns: @ilegs
315             # @ilegs: index of each of @legs in dispatcher, -1 if not found
316             ###########################################################################
317             sub legs2i {
318 7     7 0 12 my Net::SIP::Dispatcher $self = shift;
319 7         14 my $legs = $self->{legs};
320 7 50       22 if (ref($_[-1]) eq 'SCALAR') {
321 7         24 my $dict = pop @_;
322 7         17 $$dict = join("|",map { $_->key } @$legs);
  19         58  
323             }
324 7         17 my @result;
325 7         16 for(@_) {
326 14         20 my $i;
327 14         54 for($i=$#$legs;$i>=0;$i--) {
328 31 100       91 last if $legs->[$i] == $_;
329             }
330 14         28 push @result,$i;
331             }
332 7         21 return @result;
333             }
334              
335             ###########################################################################
336             # map index to leg in list of legs
337             # Args: @ilegs,[\$dict]
338             # @ilegs: list of leg indices
339             # $dict: optional string representation of dictionary, will return ()
340             # if $dict does not match current legs and order in dispatcher
341             # Returns: @legs
342             # @legs: list of legs matching indices
343             ###########################################################################
344             sub i2legs {
345 0     0 0 0 my Net::SIP::Dispatcher $self = shift;
346 0         0 my $legs = $self->{legs};
347 0 0       0 if (ref($_[-1])) {
348 0 0       0 return if ${pop(@_)} ne join("|",map { $_->key } @$legs);
  0         0  
  0         0  
349             }
350 0         0 return @{$legs}[@_];
  0         0  
351             }
352              
353             ###########################################################################
354             # add timer
355             # propagates to add_timer of eventloop
356             # Args: ($self,$when,$cb,$repeat)
357             # $when: when callback gets called, can be absolute time (epoch, time_t)
358             # or relative time (seconds)
359             # $cb: callback
360             # $repeat: after how much seconds it gets repeated (default 0, e.g never)
361             # Returns: $timer
362             # $timer: Timer object, has method cancel for canceling timer
363             ###########################################################################
364             sub add_timer {
365 116     116 1 393 my Net::SIP::Dispatcher $self = shift;
366 116         1642 return $self->{eventloop}->add_timer( @_ );
367             }
368              
369             ###########################################################################
370             # initiate delivery of a packet, e.g. put packet into delivery queue
371             # Args: ($self,$packet,%more_args)
372             # $packet: Net::SIP::Packet which needs to be delivered
373             # %more_args: hash with some of the following keys
374             # id: id for packet, used in cancel_delivery
375             # callback: [ \&sub,@arg ] for calling back on definite delivery
376             # success (tcp only) or error (timeout,no route,...)
377             # leg: specify outgoing leg, needed for responses
378             # dst_addr: specify outgoing addr as hash with keys
379             # proto,addr,port,family,host. Needed for responses.
380             # do_retransmits: if retransmits should be done, default from
381             # global value (see new())
382             # Returns: NONE
383             # Comment: no return value, but die()s on errors
384             ###########################################################################
385             sub deliver {
386 187     187 1 383 my Net::SIP::Dispatcher $self = shift;
387 187         1448 my ($packet,%more_args) = @_;
388 187         600 my $now = delete $more_args{now};
389 187         446 my $do_retransmits = delete $more_args{do_retransmits};
390 187 100       890 $do_retransmits = $self->{do_retransmits} if !defined $do_retransmits;
391              
392 187         1213 DEBUG( 100,"deliver $packet" );
393              
394 187 100       1575 if ( $packet->is_response ) {
395             # cache response for 32 sec (64*T1)
396 71 50       202 if ( $do_retransmits ) {
397             my $cid = join( "\0",
398 71         197 map { $packet->get_header($_) }
  284         708  
399             qw( cseq call-id from to )
400             );
401 71   33     1367 $self->{response_cache}{$cid} = {
402             packet => $packet,
403             expire => ( $now ||= time()) +32
404             };
405             }
406             }
407              
408 187         2787 my $new_entry = Net::SIP::Dispatcher::Packet->new(
409             packet => $packet,
410             %more_args
411             );
412              
413 187 100       1324 $new_entry->prepare_retransmits( $now ) if $do_retransmits;
414              
415 187         388 push @{ $self->{queue}}, $new_entry;
  187         700  
416 187         1348 $self->__deliver( $new_entry );
417             }
418              
419             ###########################################################################
420             # cancel delivery of all packets with specific id
421             # Args: ($self,$typ?,$id)
422             # $typ: what to cancel, e.g. 'id','callid' or 'qentry', optional,
423             # defaults to 'id' if $id is not ref or 'qentry' if $id is ref
424             # $id: id to cancel, can also be queue entry
425             # Returns: bool, true if the was something canceled
426             ###########################################################################
427             sub cancel_delivery {
428 332     332 1 767 my Net::SIP::Dispatcher $self = shift;
429 332         692 my ($callid,$id,$qentry);
430 332 100       989 if ( @_ == 2 ) {
431 46         335 my $typ = shift;
432 46 50       208 if ( $typ eq 'callid' ) { $callid = shift }
  46 0       133  
    0          
433 0         0 elsif ( $typ eq 'id' ) { $id = shift }
434 0         0 elsif ( $typ eq 'qentry' ) { $qentry = shift }
435             else {
436 0         0 croak( "bad typ '$typ', should be id|callid|qentry" );
437             }
438             } else {
439 286         535 $id = shift;
440 286 100       803 if ( ref($id)) {
441 128         283 $qentry = $id;
442 128         253 $id = undef;
443             }
444             }
445 332         740 my $q = $self->{queue};
446 332         606 my $qn = @$q;
447 332 100       1095 if ( $qentry ) {
    100          
    50          
448             # it's a *::Dispatcher::Packet
449 128         720 DEBUG( 100,"cancel packet id: $qentry->{id}" );
450 128         382 @$q = grep { $_ != $qentry } @$q;
  131         611  
451             } elsif ( defined $id ) {
452 41     41   365 no warnings; # $_->{id} can be undef
  41         84  
  41         3443  
453 158         765 DEBUG( 100, "cancel packet id $id" );
454 158         430 @$q = grep { $_->{id} ne $id } @$q;
  56         671  
455             } elsif ( defined $callid ) {
456 41     41   297 no warnings; # $_->{callid} can be undef
  41         97  
  41         164078  
457 46         268 DEBUG( 100, "cancel packet callid $callid" );
458 46         134 @$q = grep { $_->{callid} ne $callid } @$q;
  4         22  
459             } else {
460 0         0 croak( "cancel_delivery w/o id" );
461             }
462 332         2656 return @$q < $qn; # true if items got deleted
463             }
464              
465              
466              
467             ###########################################################################
468             # Receive a packet from a leg and forward it to the upper layer
469             # if the packet is a request and I have a cached response resend it
470             # w/o involving the upper layer
471             # Args: ($self,$packet,$leg,$from)
472             # $packet: Net::SIP::Packet
473             # $leg: through which leg it was received
474             # $from: where the packet comes from: [proto,ip,from,family]
475             # Returns: NONE
476             # Comment: if no receiver is defined using set_receiver the packet
477             # will be silently dropped
478             ###########################################################################
479             sub receive {
480 211     211 1 463 my Net::SIP::Dispatcher $self = shift;
481 211         522 my ($packet,$leg,$from) = @_;
482              
483 211 100       666 if ( $packet->is_request ) {
484 72         223 my $cache = $self->{response_cache};
485 72 100       247 if ( %$cache ) {
486             my $cid = join( "\0",
487 44         130 map { $packet->get_header($_) }
  176         554  
488             qw( cseq call-id from to )
489             );
490              
491 44 100       263 if ( my $response = $cache->{$cid} ) {
492             # I have a cached response, use it
493             $self->deliver($response->{packet},
494 2         9 leg => $leg,
495             dst_addr => $from,
496             );
497 2         9 return;
498             }
499             }
500             }
501              
502 209         936 invoke_callback( $self->{receiver},$packet,$leg,$from );
503             }
504              
505             ###########################################################################
506             # expire the entries on the queue, eg removes expired entries and
507             # calls callback if necessary
508             # expires also the response cache
509             # Args: ($self;$time)
510             # $time: expire regarding $time, if not given use time()
511             # Returns: undef|$min_expire
512             # $min_expire: time when next thing expires (undef if nothing to expire)
513             ###########################################################################
514             sub queue_expire {
515 168     168 1 1357 my Net::SIP::Dispatcher $self = shift;
516 168   33     705 my $now = shift || $self->{eventloop}->looptime;
517              
518             # expire queue
519 168         574 my $queue = $self->{queue};
520 168         442 my (@nq,$changed,$min_expire);
521 168         778 foreach my $qe (@$queue) {
522              
523 10         25 my $retransmit;
524 10 50       48 if ( my $retransmits = $qe->{retransmits} ) {
525 10   66     118 while ( @$retransmits && $retransmits->[0] < $now ) {
526 8         44 $retransmit = shift(@$retransmits);
527             }
528              
529 10 50       32 if ( !@$retransmits ) {
530             # completely expired
531 0         0 DEBUG( 50,"entry %s expired because expire=%.2f but now=%d", $qe->tid,$retransmit,$now );
532 0         0 $changed++;
533 0         0 $qe->trigger_callback( ETIMEDOUT );
534              
535             # don't put into new queue
536 0         0 next;
537             }
538              
539 10 100       37 if ( $retransmit ) {
540             # need to retransmit the packet
541 8         34 $self->__deliver( $qe );
542             }
543              
544 10         76 my $next_retransmit = $retransmits->[0];
545 10 50 66     75 if ( !defined($min_expire) || $next_retransmit<$min_expire ) {
546 10         27 $min_expire = $next_retransmit
547             }
548             }
549 10         37 push @nq,$qe;
550              
551             }
552 168 50       623 $self->{queue} = \@nq if $changed;
553              
554             # expire response cache
555 168         572 my $cache = $self->{response_cache};
556 168         1312 foreach my $cid ( keys %$cache ) {
557 75         314 my $expire = $cache->{$cid}{expire};
558 75 50 100     925 if ( $expire < $now ) {
    100          
559 0         0 delete $cache->{$cid};
560             } elsif ( !defined($min_expire) || $expire<$min_expire ) {
561 61         203 $min_expire = $expire
562             }
563             }
564              
565             # return time to next expire for optimizations
566 168         770 return $min_expire;
567             }
568              
569              
570             ###########################################################################
571             # the real delivery of a queue entry:
572             # if no leg,addr try to determine them from request-URI
573             # prepare timeout handling
574             # Args: ($self,$qentry)
575             # $qentry: Net::SIP::Dispatcher::Packet
576             # Returns: NONE
577             # Comment:
578             # this might be called several times for a queue entry, eg as a callback
579             # at the various stages (find leg,addr for URI needs DNS lookup which
580             # might be done asynchronous, eg callback driven, send might be callback
581             # driven for tcp connections which need connect, multiple writes...)
582             ###########################################################################
583             sub __deliver {
584 304     304   656 my Net::SIP::Dispatcher $self = shift;
585 304         495 my $qentry = shift;
586              
587             # loop until leg und dst_addr are known, when we call leg->deliver
588 304         722 my $leg = $qentry->{leg}[0];
589 304 50 66     1386 if ( $leg && @{ $qentry->{leg}}>1 ) {
  232         988  
590 0         0 DEBUG( 50,"picking first of multiple legs: ".join( " ", map { $_->dump } @{ $qentry->{leg}} ));
  0         0  
  0         0  
591             }
592 304         774 my $dst_addr = $qentry->{dst_addr}[0];
593              
594 304 100 66     1651 if ( ! $dst_addr || ! $leg) {
595              
596             # if explicit routes given use first route
597             # else resolve URI from request
598              
599 109         194 my $uri;
600 109         316 my $packet = $qentry->{packet};
601 109 50       552 if ( my ($route) = $packet->get_header( 'route' )) {
602 0         0 ($uri) = sip_hdrval2parts( route => $route );
603             } else {
604 109         431 $uri = $packet->uri;
605             }
606              
607 109         727 DEBUG( 100,"no dst_addr or leg yet, uri='$uri'" );
608              
609             my $callback = sub {
610 109     109   314 my ($self,$qentry,@error) = @_;
611 109 50       269 if ( @error ) {
612 0         0 $qentry->trigger_callback(@error);
613 0         0 return $self->cancel_delivery( $qentry );
614             } else {
615 109         670 $self->__deliver($qentry);
616             }
617 109         1178 };
618             return $self->resolve_uri(
619             $uri,
620             $qentry->{dst_addr},
621             $qentry->{leg},
622             [ $callback, $self,$qentry ],
623             $qentry->{proto},
624 109         1219 );
625             }
626              
627 195 100 100     1232 if ($qentry->{retransmits} && ! $leg->do_retransmits) {
628 30         166 $qentry->{retransmits} = undef;
629             }
630              
631             # I have leg and addr, send packet thru leg to addr
632             my $cb = sub {
633 88     88   284 my ($self,$qentry,$error) = @_;
634 88 50       267 $self || return;
635 88 50 33     617 if ( !$error && $qentry->{retransmits} ) {
636             # remove from queue even if timeout
637 0         0 $self->cancel_delivery( $qentry );
638             }
639 88         373 $qentry->trigger_callback( $error );
640 195         1635 };
641              
642             # adds via on cloned packet, calls cb if definite success (tcp)
643             # or error
644             #Carp::confess("expected reference, got $dst_addr") if !ref($dst_addr);
645 195 50       666 $DEBUG && DEBUG(50,"deliver through leg ".$leg->dump.' @'
646             .ip_parts2string($dst_addr));
647 195         950 weaken( my $rself = \$self );
648 195         549 $cb = [ $cb,$self,$qentry ];
649 195         647 weaken( $cb->[1] );
650 195         1473 $leg->deliver( $qentry->{packet},$dst_addr,$cb );
651              
652 195 100       2318 if ( !$qentry->{retransmits} ) {
653             # remove from queue if no timeout
654 128         620 $self->cancel_delivery( $qentry );
655             }
656             }
657              
658              
659              
660             ###########################################################################
661             # resolve URI, determine dst_addr and outgoing leg
662             # Args: ($self,$uri,$dst_addr,$legs,$callback;$allowed_proto,$allowed_legs)
663             # $uri: URI to resolve
664             # $dst_addr: reference to list where to put dst_addr
665             # $legs: reference to list where to put leg
666             # $callback: called with () if resolved successfully, else called
667             # with @error
668             # $allowed_proto: optional \@list of protocols (default udp, tcp, tls).
669             # If given only only these protocols will be considered and in this order.
670             # $allowed_legs: optional list of legs which are allowed
671             # Returns: NONE
672             ###########################################################################
673             sub resolve_uri {
674 116     116 1 322 my Net::SIP::Dispatcher $self = shift;
675 116         687 my ($uri,$dst_addr,$legs,$callback,$allowed_proto,$allowed_legs) = @_;
676              
677             # packet should be a request packet (see constructor of *::Dispatcher::Packet)
678 116         633 my ($domain,$user,$sip_proto,$param) = sip_uri2parts($uri);
679 116 50       461 $domain or do {
680 0         0 DEBUG( 50,"bad URI '$uri'" );
681 0         0 return invoke_callback($callback, EHOSTUNREACH );
682             };
683              
684 116         271 my @proto;
685 116         277 my $default_port = 5060;
686 116 100       599 if ( $sip_proto eq 'sips' ) {
    100          
687 10         49 $default_port = 5061;
688 10         88 @proto = 'tls';
689             } elsif ( my $p = $param->{transport} ) {
690             # explicit spec of proto
691 4         62 @proto = lc($p)
692             } else {
693             # XXXX maybe we should use tcp first if the packet has a specific
694             # minimum length, udp should not be used at all if the packet size is > 2**16
695 102         591 @proto = ( 'udp','tcp' );
696             }
697              
698             # change @proto so that only the protocols from $allowed_proto are ini it
699             # and that they are tried in the order from $allowed_proto
700 116 50 33     476 if ( $allowed_proto && @$allowed_proto ) {
701 0         0 my @proto_new;
702 0         0 foreach my $ap ( @$allowed_proto ) {
703 0     0   0 my $p = first { $ap eq $_ } @proto;
  0         0  
704 0 0       0 push @proto_new,$p if $p;
705             }
706 0         0 @proto = @proto_new;
707 0 0       0 @proto or do {
708 0         0 DEBUG( 50,"no protocols allowed for $uri" );
709 0         0 @$dst_addr = ();
710 0         0 return invoke_callback( $callback, ENOPROTOOPT ); # no proto available
711             };
712             }
713              
714 116   50     331 $dst_addr ||= [];
715 116   50     1026 $allowed_legs ||= [ $self->get_legs ];
716 116 100       615 if ( @$legs ) {
717 37         139 my %allowed = map { $_ => 1 } @$legs;
  37         207  
718 37         154 @$allowed_legs = grep { $allowed{$_} } @$allowed_legs;
  37         178  
719             }
720 116 50       386 @$allowed_legs or do {
721 0         0 DEBUG( 50,"no legs allowed for '$uri'" );
722 0         0 return invoke_callback($callback, EHOSTUNREACH );
723             };
724              
725 116         282 my $ip_addr = $param->{maddr};
726             {
727 116 100       211 my ($host,$port,$family) = ip_string2parts($domain, $ip_addr ? 1:0);
  116         580  
728 116 100       458 $default_port = $port if defined $port;
729 116 100       330 if ($family) {
730 64   33     746 $ip_addr ||= $host;
731 64         338 $domain = ip_ptr($host,$family);
732             } else {
733 52         132 $domain = $host;
734             }
735             }
736 116         684 DEBUG( 100,"domain=$domain" );
737              
738             # do we have a fixed proxy for the domain or upper domain?
739 116 50       388 if ( ! @$dst_addr ) {
740 116         319 my $d2p = $self->{domain2proxy};
741 116 100 66     1010 if ( $d2p && %$d2p ) {
742 81         293 my $dom = $domain;
743 81         221 my $addr = $d2p->{$dom}; # exact match
744 81         246 while ( ! $addr) {
745 221 100       989 $dom =~s{^[^\.]+\.}{} or last;
746 183         539 $addr = $d2p->{ "*.$dom" };
747             }
748 81   100     599 $addr ||= $d2p->{ $dom = '*'}; # catch-all
749 81 100       243 if ( $addr ) {
750 45         195 DEBUG( 50,"setting dst_addr from domain specific proxy for domain $dom" );
751 45         159 @$dst_addr = @$addr;
752             }
753             }
754             }
755              
756             # do we have a global outgoing proxy?
757 116 50 66     800 if ( !@$dst_addr
758             && ( my $addr = $self->{outgoing_proxy} )) {
759             # if we have a fixed outgoing proxy use it
760 0         0 DEBUG( 50,"setting dst_addr+leg to $addr from outgoing_proxy" );
761 0         0 @$dst_addr = ( $addr );
762             }
763              
764             # is it an IP address?
765 116 100 66     709 if ( !@$dst_addr && $ip_addr ) {
766 71         290 DEBUG( 50,"setting dst_addr from URI because IP address given" );
767 71         233 @$dst_addr = ( $ip_addr );
768             }
769              
770             # is param maddr set?
771 116 100       378 if ( my $ip = $param->{maddr} ) {
772 7 50       33 @$dst_addr = ($ip) if ip_is_v46($ip);
773             }
774              
775              
776             # entries are hashes of prio,proto,host,addr,port,family
777 116         224 my @resp;
778 116         511 foreach my $addr ( @$dst_addr ) {
779 143 100       411 if ( ref($addr)) {
780 72         227 push @resp,$addr; # right format: see domain2proxy
781             } else {
782 71 50       310 my ($proto,$host,$port,$family) = sip_uri2sockinfo($addr)
783             or next;
784 71 50 33     1285 $addr = lock_ref_keys({
785             proto => $proto,
786             host => $host,
787             addr => $family ? $host : undef,
788             port => $port || $default_port,
789             family => $family
790             });
791 71 50       993 push @resp, map { lock_ref_keys({
  131         1779  
792             %$addr,
793             proto => $_,
794             prio => SRV_PRIO_UNDEF,
795             }) } $proto ? ($proto) : @proto;
796             }
797             }
798              
799             # should we use a fixed transport?
800 116 100 66     1852 if (@resp and my $proto = $param->{transport} ) {
801 4         52 $proto = lc($proto);
802 4 50       130 if ($proto eq 'udp') {
    50          
    0          
803 0         0 @resp = grep { $_->{proto} eq 'udp' } @resp
  0         0  
804             } elsif ($proto eq 'tcp') {
805             # accept proto tcp and tls
806 4         48 @resp = grep { $_->{proto} ne 'udp' } @resp
  4         84  
807             } elsif ($proto eq 'tls') {
808 0         0 @resp = grep { $_->{proto} eq 'tls' } @resp
  0         0  
809             } else {
810             # no matching proto available
811 0         0 @resp = ();
812             }
813 4 50       72 return invoke_callback($callback, ENOPROTOOPT) if ! @resp;
814             }
815              
816 116         550 my @param = ( $dst_addr,$legs,$allowed_legs,$default_port,$callback );
817 116 50       335 if (@resp) {
818             # directly call __resolve_uri_final if all names are resolved
819             return __resolve_uri_final( @param,\@resp )
820 116 50       283 if ! grep { ! $_->{addr} } @resp;
  203         1193  
821 0         0 return $self->dns_host2ip(\@resp,
822             [ \&__resolve_uri_final, @param ]);
823             }
824              
825             # If no fixed mapping DNS needs to be used
826              
827             # XXXX no full support for RFC3263, eg we don't support NAPTR
828             # but query instead directly for _sip._udp.domain.. like in
829             # RFC2543 specified
830              
831 0         0 return $self->dns_domain2srv($domain, \@proto,
832             [ \&__resolve_uri_final, @param ]);
833             }
834              
835             sub __resolve_uri_final {
836 116     116   458 my ($dst_addr,$legs,$allowed_legs,$default_port,$callback,$resp) = @_;
837 116 50       378 $DEBUG && DEBUG_DUMP( 100,$resp );
838              
839 116 50 33     923 return invoke_callback( $callback,EHOSTUNREACH )
840             unless $resp && @$resp;
841              
842             # for A|AAAA records we got no port, use default_port
843 116   33     699 $_->{port} ||= $default_port for(@$resp);
844              
845             # sort by prio
846             # FIXME: can contradict order in @proto
847 116         744 @$resp = sort { $a->{prio} <=> $b->{prio} } @$resp;
  87         439  
848              
849 116         378 @$dst_addr = ();
850 116         284 @$legs = ();
851 116         350 foreach my $r ( @$resp ) {
852             my $leg = first { $_->can_deliver_to(
853             proto => $r->{proto},
854             host => $r->{host},
855             addr => $r->{addr},
856             port => $r->{port},
857             family => $r->{family},
858 203     215   1936 )} @$allowed_legs;
  215         1617  
859              
860 203 100       1100 if ( $leg ) {
861 122         286 push @$dst_addr, $r;
862 122         316 push @$legs,$leg;
863             } else {
864 81         558 DEBUG(50,"no leg with $r->{proto} to %s", ip_parts2string($r));
865             }
866             }
867              
868 116 50       379 return invoke_callback( $callback, EHOSTUNREACH ) if !@$dst_addr;
869 116         429 invoke_callback( $callback );
870             }
871              
872              
873             sub _find_leg4addr {
874 0     0   0 my Net::SIP::Dispatcher $self = shift;
875 0         0 my $dst_addr = shift;
876 0 0       0 if (!ref($dst_addr)) {
877 0         0 my @si = sip_uri2sockinfo($dst_addr);
878 0 0       0 $dst_addr = lock_ref_keys({
879             proto => $si[0],
880             host => $si[1],
881             addr => $si[3] ? $si[1] : undef,
882             port => $si[2],
883             family => $si[3],
884             });
885             }
886 0         0 return grep { $_->can_deliver_to(%$dst_addr) } @{ $self->{legs} };
  0         0  
  0         0  
887             }
888              
889             ###########################################################################
890             # resolve hostname to IP using DNS
891             # Args: ($self,$host,$callback)
892             # $host: hostname or hash with hostname as keys or list of hashes which have
893             # a host value but miss an addr value
894             # $callback: gets called with (result)|() once finished
895             # result is @IP for single hosts or the input hash ref where the
896             # IPs are filled in as values or the list filled with addr, family
897             # Returns: NONE
898             ###########################################################################
899             sub dns_host2ip {
900 0     0 0 0 my Net::SIP::Dispatcher $self = shift;
901 0         0 my ($host,$callback) = @_;
902              
903 0         0 my (@rec,$cb);
904 0 0       0 if (!ref($host)) {
    0          
905             # scalar: return ip(s)
906 0         0 @rec = { host => $host };
907             my $transform = sub {
908 0     0   0 my ($callback,$res) = @_;
909             invoke_callback($callback,
910 0         0 grep { $_ } map { $_->{addr} } @$res);
  0         0  
  0         0  
911 0         0 };
912 0         0 $cb = [ $transform, $callback ];
913              
914             } elsif (ref($host) eq 'HASH') {
915             # hash: fill hash values
916 0         0 @rec = map { (host => $_) } keys(%$host);
  0         0  
917 0 0       0 return invoke_callback($callback, $host) if ! @rec;
918             my $transform = sub {
919 0     0   0 my ($host,$callback,$res) = @_;
920 0         0 $host->{$_->{host}} = $_->{addr} for @$res;
921 0         0 invoke_callback($callback, $host);
922 0         0 };
923 0         0 $cb = [ $transform, $host, $callback ];
924              
925             } else {
926             # list of hashes: fill in addr and family in place
927 0         0 my @hasip;
928 0         0 for(@$host) {
929 0 0       0 if ($_->{addr}) {
930 0         0 push @hasip, $_;
931             } else {
932 0         0 push @rec, $_;
933             }
934             }
935 0 0       0 return invoke_callback($callback, $host) if ! @rec;
936              
937             my $transform = sub {
938 0     0   0 my ($hasip,$callback,$res) = @_;
939             # original order might be changed !!!
940 0         0 push @$res, @$hasip;
941 0         0 invoke_callback($callback, $res);
942 0         0 };
943 0         0 $cb = [ $transform, \@hasip, $callback ];
944             }
945              
946 0         0 my @queries;
947 0         0 for (@rec) {
948 0         0 my %q = (name => $_->{host}, rec => $_);
949 0         0 push @queries, { type => 'AAAA', %q } if CAN_IPV6;
950 0         0 push @queries, { type => 'A', %q };
951             }
952              
953 0   0     0 my $res = $self->{dnsresolv} || __net_dns_resolver($self->{eventloop});
954 0         0 __generic_resolver({
955             queries => \@queries,
956             callback => $cb,
957             resolver => $res,
958             });
959             }
960              
961             ###########################################################################
962             # get SRV records using DNS
963             # Args: ($self,$domain,$proto,$sip_proto,$callback)
964             # $domain: domain for SRV query
965             # $proto: which protocols to check: list of udp|tcp|tls
966             # $callback: gets called with result once finished
967             # result is \@list of hashes with prio, proto, host ,port, family
968             # Returns: NONE
969             ###########################################################################
970             sub dns_domain2srv {
971 0     0 0 0 my Net::SIP::Dispatcher $self = shift;
972 0         0 my ($domain,$protos,$callback) = @_;
973              
974             # Try to get SRV records for _sip._udp.domain or _sip._tcp.domain
975 0         0 my @queries;
976 0         0 for(@$protos) {
977 0 0       0 push @queries, {
978             type => 'SRV',
979             name => $_ eq 'tls' ? "_sips._tcp.$domain" : "_sip._$_.$domain",
980             rec => { host => $domain, proto => $_ },
981             }
982             }
983              
984             # If we have any results for SRV we can break,
985             # otherwise continue with with A|AAAA
986 0         0 push @queries, { type => 'BREAK-IF-RESULTS' };
987 0         0 for(@$protos) {
988 0         0 my %r = (
989             name => $domain,
990             rec => {
991             prio => SRV_PRIO_UNDEF,
992             host => $domain,
993             proto => $_,
994             port => undef,
995             }
996             );
997 0         0 push @queries, { type => 'AAAA', %r } if CAN_IPV6;
998 0         0 push @queries, { type => 'A', %r };
999             }
1000              
1001 0   0     0 my $res = $self->{dnsresolv} || __net_dns_resolver($self->{eventloop});
1002 0         0 __generic_resolver({
1003             queries => \@queries,
1004             callback => $callback,
1005             resolver => $res,
1006             });
1007             }
1008              
1009              
1010             # generic internal resolver helper
1011             # expects to be initially called as
1012             # __generic_resolver({
1013             # queries => \@queries,
1014             # callback => $callback,
1015             # resolver => $res,
1016             # });
1017             #
1018             # where queries are a list of tasks for DNS lookup with
1019             # type: SRV|A|AAAA
1020             # name: the name to lookup
1021             # rec: the record to enrich with
1022             # SRV: prio, proto, host, addr, port, family
1023             # A|AAAA: addr, family
1024             #
1025             # resolver is a function to do the actual resolving.
1026             # An implementation using Net::DNS is done in __net_dns_resolver.
1027             # It will be called as
1028             # resolver->(type,name,callback) where
1029             # type: SRV|A|AAAA
1030             # name: the name to lookup
1031             # callback: callback to invoke after lookup is done with the list of
1032             # answers, i.e. list-ref containing
1033             # [ 'SRV', prio, proto, host, port ]
1034             # [ 'A', addr, name ]
1035             # [ 'AAAA', addr, name ]
1036             #
1037             # callback is invoked when all queries are done with the list of
1038             # enriched records
1039              
1040             sub __generic_resolver {
1041 0     0   0 my ($state,$qid,$ans) = @_;
1042 0 0 0     0 $DEBUG && DEBUG_DUMP(100,[$qid,$ans]) if $qid;
1043              
1044 0         0 my $queries = $state->{queries};
1045 0   0     0 my $results = $state->{results} ||= [];
1046 0 0       0 goto after_answers if !$qid;
1047              
1048 0         0 for(my $i=0; $i<@$queries; $i++) {
1049 0         0 my $q = $queries->[$i];
1050 0 0       0 if ($q->{type} eq 'BREAK-IF-RESULTS') {
1051 0 0       0 if (@$results) {
1052             # skip remaining queries
1053 0         0 @$queries = ();
1054 0         0 last;
1055             }
1056 0 0       0 if ($i==0) {
1057             # remove if top query
1058 0         0 shift(@$queries);
1059 0         0 $i--;
1060             }
1061 0         0 next;
1062             }
1063              
1064 0 0       0 "$q->{type}:$q->{name}" eq $qid or next;
1065              
1066             # query matches qid of answer, remove from @$queries
1067 0         0 splice(@$queries,$i,1);
1068 0         0 $i--;
1069              
1070 0 0 0     0 if ($q->{type} eq 'SRV') {
    0          
1071 0         0 my (%addr2ip,@res);
1072 0         0 for(@$ans) {
1073 0         0 my $type = shift(@$_);
1074 0 0 0     0 if ($type eq 'A' or CAN_IPV6 ? $type eq 'AAAA' : 0) {
1075             # supplemental data
1076 0         0 my ($ip,$name) = @_;
1077 0         0 push @{ $addr2ip{$name}}, [$ip, $type];
  0         0  
1078 0         0 next;
1079             }
1080 0 0       0 next if $type ne 'SRV';
1081 0         0 my ($prio,$host,$port) = @$_;
1082 0         0 my $family = ip_is_v46($host);
1083             push @res, lock_ref_keys({
1084 0 0       0 %{$q->{rec}},
  0         0  
1085             prio => $prio,
1086             host => $host,
1087             addr => $family ? $host : undef,
1088             port => $port,
1089             family => $family,
1090             });
1091             }
1092 0         0 for(my $i=0; $i<@res; $i++) {
1093 0 0       0 $res[$i]{family} and next;
1094 0 0       0 my $ipt = $addr2ip{$res[$i]{host}} or next;
1095 0         0 my $r = splice(@res,$i,1);
1096 0         0 for(@$ipt) {
1097 0         0 my ($ip,$type) = @$_;
1098 0 0       0 splice(@res,$i,0, lock_ref_keys({
1099             %$r,
1100             addr => $ip,
1101             family => $type eq 'A' ? AF_INET : AF_INET6,
1102             }));
1103 0         0 $i++;
1104             }
1105 0         0 $i--;
1106             }
1107 0         0 for my $r (@res) {
1108 0 0       0 if ($_->{family}) {
1109             # done: host in SRV record is already IP address
1110 0         0 push @$results, $r;
1111 0         0 next;
1112             }
1113              
1114             # need to resolve host in SRV record - put queries on top
1115 0         0 for my $type (CAN_IPV6 ? qw(AAAA A) : qw(A)) {
1116             unshift @$queries, {
1117             type => $type,
1118             name => $r->{host},
1119 0 0       0 rec => lock_ref_keys({
1120             %$r,
1121             family => $type eq 'A' ? AF_INET : AF_INET6,
1122             })
1123             };
1124             }
1125             }
1126              
1127             } elsif ($q->{type} eq 'AAAA' || $q->{type} eq 'A') {
1128 0         0 for(@$ans) {
1129 0         0 my ($type,$ip) = @$_;
1130             push @$results, lock_ref_keys({
1131 0 0       0 %{$q->{rec}},
  0         0  
1132             addr => $ip,
1133             family => $type eq 'A' ? AF_INET : AF_INET6,
1134             });
1135             }
1136             } else {
1137 0         0 die "unknown type $q->{type}";
1138             }
1139             }
1140              
1141             after_answers:
1142 0 0       0 if (!@$queries) {
1143             # no more queries -> done
1144 0   0     0 invoke_callback($state->{callback}, @$results && $results);
1145 0         0 return;
1146             }
1147              
1148             # still queries -> send next to resolver
1149 0         0 my $q = $queries->[0];
1150 0         0 DEBUG(52,'issue lookup for %s %s',$q->{type}, $q->{name});
1151             $state->{resolver}($q->{type}, $q->{name}, [
1152 0         0 \&__generic_resolver,
1153             $state,
1154             "$q->{type}:$q->{name}"
1155             ]);
1156             }
1157              
1158             my $NetDNSResolver;
1159             sub __net_dns_resolver {
1160 0     0   0 my $eventloop = shift;
1161              
1162             # Create only a single resolver.
1163 0   0     0 $NetDNSResolver ||= eval {
      0        
1164             require Net::DNS;
1165             Net::DNS->VERSION >= 0.56 or die "version too old, need 0.56+";
1166             Net::DNS::Resolver->new;
1167             } || die "cannot create resolver: Net::DNS not available?: $@";
1168              
1169             my $dnsread = sub {
1170 0     0   0 my ($sock,$callback) = @_;
1171 0         0 my $q = $NetDNSResolver->bgread($sock);
1172 0         0 $eventloop->delFD($sock);
1173 0         0 my @ans;
1174 0         0 for my $rr ( $q->answer ) {
1175 0 0 0     0 if ($rr->type eq 'SRV' ) {
    0          
1176 0         0 push @ans, [
1177             'SRV',
1178             $rr->priority,
1179             $rr->target,
1180             $rr->port,
1181             ];
1182             } elsif ($rr->type eq 'A' || $rr->type eq 'AAAA') {
1183 0         0 push @ans, [ $rr->type, $rr->address, $rr->name ];
1184             }
1185             }
1186 0         0 invoke_callback($callback,\@ans);
1187 0         0 };
1188              
1189             return sub {
1190 0     0   0 my ($type,$name,$callback) = @_;
1191 0         0 my $sock = $NetDNSResolver->bgsend($name,$type);
1192 0         0 $eventloop->addFD($sock, EV_READ,
1193             [$dnsread, $sock, $callback],
1194             'dns'
1195             );
1196 0         0 };
1197             }
1198              
1199              
1200             ###########################################################################
1201             # Net::SIP::Dispatcher::Packet
1202             # Container for Queue entries in Net::SIP::Dispatchers queue
1203             ###########################################################################
1204             package Net::SIP::Dispatcher::Packet;
1205             use fields (
1206 41         275 'id', # transaction id, used for canceling delivery if response came in
1207             'callid', # callid, used for canceling all deliveries for this call
1208             'packet', # the packet which nees to be delivered
1209             'dst_addr', # to which adress the packet gets delivered, is array-ref because
1210             # the DNS/SRV lookup might return multiple addresses and protocols:
1211             # [ { hash: proto, addr, port, family, host }, { ... }, ...]
1212             'leg', # through which leg the packet gets delivered, same number
1213             # of items like dst_addr
1214             'retransmits', # array of retransmit time stamps, if undef no retransmit will be
1215             # done, if [] no more retransmits can be done (trigger ETIMEDOUT)
1216             # the last element in this array will not used for retransmit, but
1217             # is the timestamp, when the delivery fails permanently
1218             'callback', # callback for DSN (success, ETIMEDOUT...)
1219             'proto', # list of possible protocols, default tcp and udp for sip:
1220 41     41   588 );
  41         149  
1221              
1222 41     41   4741 use Net::SIP::Debug;
  41         140  
  41         214  
1223 41     41   317 use Net::SIP::Util ':all';
  41         85  
  41         7736  
1224 41     41   306 use Hash::Util 'lock_ref_keys';
  41         90  
  41         949  
1225              
1226             ###########################################################################
1227             # create new Dispatcher::Packet
1228             # Args: ($class,%args)
1229             # %args: hash with values according to fields
1230             # for response packets leg and dst_addr must be set
1231             # Returns: $self
1232             ###########################################################################
1233             sub new {
1234 187     187   1281 my ($class,%args) = @_;
1235 187         530 my $now = delete $args{now};
1236              
1237 187         695 my $self = fields::new( $class );
1238 187         18713 %$self = %args;
1239 187   66     1215 $self->{id} ||= $self->{packet}->tid;
1240 187   33     1875 $self->{callid} ||= $self->{packet}->callid;
1241              
1242 187         582 my $addr = $self->{dst_addr};
1243 187 100       977 if (!$addr) {
    50          
    50          
1244             } elsif (!ref($addr)) {
1245 0         0 my @si = sip_uri2sockinfo($addr);
1246 0 0       0 $self->{dst_addr} = [ lock_ref_keys({
1247             proto => $si[0],
1248             host => $si[1],
1249             addr => $si[3] ? $si[1] : undef,
1250             port => $si[2],
1251             family => $si[3],
1252             }) ];
1253             } elsif (ref($addr) eq 'HASH') {
1254 78         248 $self->{dst_addr} = [ $addr ];
1255             } else {
1256             # assume its already in the expected format, i.e. list of hashes
1257             }
1258 187 100       712 if ( my $leg = $self->{leg} ) {
1259 115 50       898 $self->{leg} = [ $leg ] if UNIVERSAL::can( $leg,'deliver' );
1260             }
1261              
1262 187   100     1241 $self->{dst_addr} ||= [];
1263 187   100     770 $self->{leg} ||= [];
1264 187         647 return $self;
1265             }
1266              
1267             ###########################################################################
1268             # prepare retransmit infos if dispatcher handles retransmits itself
1269             # Args: ($self;$now)
1270             # $now: current time
1271             # Returns: NONE
1272             ###########################################################################
1273             sub prepare_retransmits {
1274 180     180   413 my Net::SIP::Dispatcher::Packet $self = shift;
1275 180 100 100     1492 return if $self->{leg}[0] && ! $self->{leg}[0]->do_retransmits;
1276              
1277 128         272 my $now = shift;
1278 128         276 my $p = $self->{packet};
1279              
1280             # RFC3261, 17.1.1.2 (final response to INVITE) -> T1=0.5, T2=4
1281             # RFC3261, 17.1.2.2 (non-INVITE requests) -> T1=0.5, T2=4
1282             # RFC3261, 17.1.1.2 (INVITE request) -> T1=0.5, T2=undef
1283             # no retransmit -> T1=undef
1284              
1285 128         292 my ($t1,$t2);
1286 128 100       472 if ( $p->is_response ) {
    100          
    100          
1287 34 100 100     115 if ( $p->code > 100 && $p->cseq =~m{\sINVITE$} ) {
1288             # this is a final response to an INVITE
1289             # this is the only type of response which gets retransmitted
1290             # (until I get an ACK)
1291 17         58 ($t1,$t2) = (0.500,4);
1292             }
1293             } elsif ( $p->method eq 'INVITE' ) {
1294             # INVITE request
1295 38         135 ($t1,$t2) = (0.500,undef);
1296             } elsif ( $p->method eq 'ACK' ) {
1297             # no retransmit of ACKs
1298             } else {
1299             # non-INVITE request
1300 34         125 ($t1,$t2) = (0.500,4);
1301             }
1302              
1303             # no retransmits?
1304 128 100       462 $t1 || return;
1305              
1306 89   66     787 $now ||= time();
1307 89         309 my $expire = $now + 64*$t1;
1308 89         174 my $to = $t1;
1309 89         187 my $rtm = $now + $to;
1310              
1311 89         216 my @retransmits;
1312 89         322 while ( $rtm < $expire ) {
1313 738         1278 push @retransmits, $rtm;
1314 738         1090 $to *= 2;
1315 738 100 100     2262 $to = $t2 if $t2 && $to>$t2;
1316 738         1453 $rtm += $to
1317             }
1318 89         453 DEBUG( 100,"retransmits $now + ".join( " ", map { $_ - $now } @retransmits ));
  738         3102  
1319 89         819 $self->{retransmits} = \@retransmits;
1320             }
1321              
1322              
1323              
1324             ###########################################################################
1325             # use next dst_addr (eg if previous failed)
1326             # Args: $self
1327             # Returns: $addr
1328             # $addr: new address it will use or undef if no more addresses available
1329             ###########################################################################
1330             sub use_next_dstaddr {
1331 0     0   0 my Net::SIP::Dispatcher::Packet $self = shift;
1332 0   0     0 my $addr = $self->{dst_addr} || return;
1333 0         0 shift(@$addr);
1334 0   0     0 my $leg = $self->{leg} || return;
1335 0         0 shift(@$leg);
1336 0   0     0 return @$addr && $addr->[0];
1337             }
1338              
1339             ###########################################################################
1340             # trigger callback to upper layer
1341             # Args: ($self;$errno)
1342             # $errno: Errno
1343             # Returns: $callback_done
1344             # $callback_done: true if callback was triggered, if no callback existed
1345             # returns false
1346             ###########################################################################
1347             sub trigger_callback {
1348 88     88   228 my Net::SIP::Dispatcher::Packet $self = shift;
1349 88         180 my $error = shift;
1350 88   100     426 my $cb = $self->{callback} || return;
1351 45         274 invoke_callback( $cb,$error,$self);
1352 45         339 return 1;
1353             }
1354              
1355             ###########################################################################
1356             # return transaction id of packet
1357             # Args: $self
1358             # Returns: $tid
1359             ###########################################################################
1360             sub tid {
1361 45     45   86 my Net::SIP::Dispatcher::Packet $self = shift;
1362 45         214 return $self->{packet}->tid;
1363             }
1364             1;