File Coverage

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


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 43     43   309 use strict;
  43         70  
  43         1335  
12 43     43   177 use warnings;
  43         60  
  43         1936  
13              
14             package Net::SIP::Dispatcher;
15             use fields (
16             # interface to outside
17 43         194 '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 43     43   183 );
  43         73  
29              
30 43     43   21677 use Net::SIP::Leg;
  43         135  
  43         1244  
31 43     43   540 use Net::SIP::Util ':all';
  43         274  
  43         7409  
32 43     43   260 use Net::SIP::Dispatcher::Eventloop;
  43         75  
  43         1756  
33 43     43   263 use Errno qw(EHOSTUNREACH ETIMEDOUT ENOPROTOOPT);
  43         67  
  43         1675  
34 43     43   206 use IO::Socket;
  43         69  
  43         336  
35 43     43   18076 use List::Util 'first';
  43         103  
  43         2269  
36 43     43   260 use Hash::Util 'lock_ref_keys';
  43         78  
  43         202  
37 43     43   1948 use Carp 'croak';
  43         68  
  43         1536  
38 43     43   229 use Net::SIP::Debug;
  43         81  
  43         356  
39 43     43   252 use Scalar::Util 'weaken';
  43         101  
  43         2012  
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 43     43   273 use constant SRV_PRIO_UNDEF => 0x10000;
  43         102  
  43         72729  
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 57     57 1 748 my ($class,$legs,$eventloop,%args) = @_;
68              
69             my ($outgoing_proxy,$do_retransmits,$domain2proxy,$dnsresolv) = delete
70 57         276 @args{qw( outgoing_proxy do_retransmits domain2proxy dnsresolv)};
71 57 50       264 die "bad args: ".join( ' ',keys %args ) if %args;
72              
73 57   33     248 $eventloop ||= Net::SIP::Dispatcher::Eventloop->new;
74              
75             # normalize domain2proxy so that its the same format one gets from
76             # the SRV record
77 57   100     572 $domain2proxy ||= {};
78 57         239 foreach ( values %$domain2proxy ) {
79 30 50       107 if ( ref($_) ) {
80             # should be \@list of [ prio,proto,ip,port,?family ]
81             } else {
82 30 50       134 my ($proto,$host,$port,$family) = sip_uri2sockinfo($_)
83             or croak( "invalid entry in domain2proxy: $_" );
84 30 0 0     111 $port ||= $proto && $proto eq 'tls' ? 5061:5060;
      33        
85 30 50       124 $_ = [ map { lock_ref_keys({
  48 100       974  
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 57         498 my $self = fields::new($class);
97 57 50       8024 %$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 57         1870 $self->add_leg( @$legs );
109              
110 57 50       217 $self->outgoing_proxy($outgoing_proxy) if $outgoing_proxy;
111              
112             # regularly prune queue
113             my $sub = sub {
114 174     174   790 my ($self,$timer) = @_;
115 174 50       1074 if ( $self ) {
116 174         1007 $self->queue_expire( $self->{eventloop}->looptime );
117             } else {
118 0         0 $timer->cancel;
119             }
120 57         1143 };
121 57         432 my $cb = [ $sub,$self ];
122 57         717 weaken( $cb->[1] );
123 57         1192 $self->{disp_expire} = $self->add_timer( 1,$cb,1,'disp_expire' );
124              
125 57         246 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 59     59 1 120 my Net::SIP::Dispatcher $self = shift;
170 59 50       247 if ( my $receiver = shift ) {
171 59 100       232 if ( my $sub = UNIVERSAL::can($receiver,'receive' )) {
172             # Object with method receive()
173 5         12 $receiver = [ $sub,$receiver ]
174             }
175 59         1096 $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 111     111 1 238 my Net::SIP::Dispatcher $self = shift;
192 111         275 my $legs = $self->{legs};
193 111         514 foreach my $arg (@_) {
194              
195 59         108 my $leg;
196             # if it is not a leg yet create one based
197             # on the arguments
198 59 50       1364 if ( UNIVERSAL::isa( $arg,'Net::SIP::Leg' )) {
    0          
    0          
199             # already a leg
200 59         136 $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 59         129 push @$legs, $leg;
214              
215 59 50       791 if (my $socketpool = $leg->socketpool) {
216             my $cb = sub {
217             # don't crash Dispatcher on bad or unexpected packets
218 209 50   209   452 eval {
219 209         592 my ($self,$leg,$packet,$from) = @_;
220 209 50       653 $self || return;
221              
222 209 50       1478 ($packet,$from) = $leg->receive($packet,$from) or return;
223              
224 209 100       1720 if ($packet->is_request) {
225             # add received and rport to top via
226             $packet->scan_header( via => [ sub {
227 70         184 my ($vref,$hdr) = @_;
228 70 50       313 return if $$vref++;
229 70         546 my ($d,$h) = sip_hdrval2parts(via => $hdr->{value});
230 70 50       1069 my ($host,$port) = $d =~m{^SIP/2\S+\s+(\S+)$}
231             ? ip_string2parts($1):();
232 70         162 my %nh;
233 70 50 33     423 if ( exists $h->{rport} and ! defined $h->{rport}) {
234 0         0 $nh{rport} = $from->{port};
235             }
236 70 50       794 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 70 50       429 if (%nh) {
245 0         0 $hdr->{value} = sip_parts2hdrval('via',$d,{ %$h,%nh});
246 0         0 $hdr->set_modified;
247             }
248 70         1673 }, \( my $cvia )]);
249             }
250              
251             # handle received packet
252 209         3376 $self->receive( $packet,$leg,$from );
253 209         2854 1;
254             } or DEBUG(1,"dispatcher croaked: $@");
255 59         1339 };
256 59         260 $cb = [ $cb,$self,$leg ];
257 59         282 weaken($cb->[1]);
258 59         150 weaken($cb->[2]);
259 59         375 $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 53     53 1 127 my Net::SIP::Dispatcher $self = shift;
272 53         137 my $legs = $self->{legs};
273 53         442 foreach my $leg (@_) {
274 53         180 @$legs = grep { $_ != $leg } @$legs;
  53         248  
275 53 50       248 if ( my $pool = $leg->socketpool ) {
276 53         338 $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 157     157 1 429 my Net::SIP::Dispatcher $self = shift;
296 157 100       436 return @{ $self->{legs} } if ! @_; # shortcut
  155         738  
297              
298 2         6 my %args = @_;
299 2         10 my @rv;
300 2         3 foreach my $leg (@{ $self->{legs} }) {
  2         4  
301 2 50       10 push @rv,$leg if $leg->match(\%args);
302             }
303 2         8 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 11 my Net::SIP::Dispatcher $self = shift;
319 7         10 my $legs = $self->{legs};
320 7 50       16 if (ref($_[-1]) eq 'SCALAR') {
321 7         19 my $dict = pop @_;
322 7         13 $$dict = join("|",map { $_->key } @$legs);
  19         57  
323             }
324 7         12 my @result;
325 7         15 for(@_) {
326 14         14 my $i;
327 14         28 for($i=$#$legs;$i>=0;$i--) {
328 31 100       71 last if $legs->[$i] == $_;
329             }
330 14         23 push @result,$i;
331             }
332 7         18 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 124     124 1 388 my Net::SIP::Dispatcher $self = shift;
366 124         1345 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 196     196 1 390 my Net::SIP::Dispatcher $self = shift;
387 196         1360 my ($packet,%more_args) = @_;
388 196         752 my $now = delete $more_args{now};
389 196         478 my $do_retransmits = delete $more_args{do_retransmits};
390 196 100       819 $do_retransmits = $self->{do_retransmits} if !defined $do_retransmits;
391              
392 196         1277 DEBUG( 100,"deliver $packet" );
393              
394 196 100       1904 if ( $packet->is_response ) {
395             # cache response for 32 sec (64*T1)
396 76 50       208 if ( $do_retransmits ) {
397             my $cid = join( "\0",
398 76         192 map { $packet->get_header($_) }
  304         788  
399             qw( cseq call-id from to )
400             );
401 76   33     1232 $self->{response_cache}{$cid} = {
402             packet => $packet,
403             expire => ( $now ||= time()) +32
404             };
405             }
406             }
407              
408 196         2627 my $new_entry = Net::SIP::Dispatcher::Packet->new(
409             packet => $packet,
410             %more_args
411             );
412              
413 196 100       1119 $new_entry->prepare_retransmits( $now ) if $do_retransmits;
414              
415 196         359 push @{ $self->{queue}}, $new_entry;
  196         629  
416 196         1106 $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 341     341 1 795 my Net::SIP::Dispatcher $self = shift;
429 341         676 my ($callid,$id,$qentry);
430 341 100       1027 if ( @_ == 2 ) {
431 48         322 my $typ = shift;
432 48 50       183 if ( $typ eq 'callid' ) { $callid = shift }
  48 0       127  
    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 293         525 $id = shift;
440 293 100       776 if ( ref($id)) {
441 133         267 $qentry = $id;
442 133         286 $id = undef;
443             }
444             }
445 341         621 my $q = $self->{queue};
446 341         634 my $qn = @$q;
447 341 100       1492 if ( $qentry ) {
    100          
    50          
448             # it's a *::Dispatcher::Packet
449 133         698 DEBUG( 100,"cancel packet id: $qentry->{id}" );
450 133         408 @$q = grep { $_ != $qentry } @$q;
  136         510  
451             } elsif ( defined $id ) {
452 43     43   324 no warnings; # $_->{id} can be undef
  43         103  
  43         3047  
453 160         1224 DEBUG( 100, "cancel packet id $id" );
454 160         417 @$q = grep { $_->{id} ne $id } @$q;
  59         752  
455             } elsif ( defined $callid ) {
456 43     43   249 no warnings; # $_->{callid} can be undef
  43         101  
  43         140737  
457 48         206 DEBUG( 100, "cancel packet callid $callid" );
458 48         119 @$q = grep { $_->{callid} ne $callid } @$q;
  4         23  
459             } else {
460 0         0 croak( "cancel_delivery w/o id" );
461             }
462 341         2747 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 216     216 1 436 my Net::SIP::Dispatcher $self = shift;
481 216         494 my ($packet,$leg,$from) = @_;
482              
483 216 100       592 if ( $packet->is_request ) {
484 77         181 my $cache = $self->{response_cache};
485 77 100       258 if ( %$cache ) {
486             my $cid = join( "\0",
487 47         138 map { $packet->get_header($_) }
  188         430  
488             qw( cseq call-id from to )
489             );
490              
491 47 100       221 if ( my $response = $cache->{$cid} ) {
492             # I have a cached response, use it
493             $self->deliver($response->{packet},
494 1         6 leg => $leg,
495             dst_addr => $from,
496             );
497 1         3 return;
498             }
499             }
500             }
501              
502 215         1027 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 174     174 1 353 my Net::SIP::Dispatcher $self = shift;
516 174   33     1323 my $now = shift || $self->{eventloop}->looptime;
517              
518             # expire queue
519 174         1059 my $queue = $self->{queue};
520 174         396 my (@nq,$changed,$min_expire);
521 174         1962 foreach my $qe (@$queue) {
522              
523 10         22 my $retransmit;
524 10 50       38 if ( my $retransmits = $qe->{retransmits} ) {
525 10   66     88 while ( @$retransmits && $retransmits->[0] < $now ) {
526 8         31 $retransmit = shift(@$retransmits);
527             }
528              
529 10 50       38 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       26 if ( $retransmit ) {
540             # need to retransmit the packet
541 5         23 $self->__deliver( $qe );
542             }
543              
544 10         27 my $next_retransmit = $retransmits->[0];
545 10 100 66     51 if ( !defined($min_expire) || $next_retransmit<$min_expire ) {
546 9         21 $min_expire = $next_retransmit
547             }
548             }
549 10         27 push @nq,$qe;
550              
551             }
552 174 50       720 $self->{queue} = \@nq if $changed;
553              
554             # expire response cache
555 174         455 my $cache = $self->{response_cache};
556 174         877 foreach my $cid ( keys %$cache ) {
557 83         251 my $expire = $cache->{$cid}{expire};
558 83 50 100     792 if ( $expire < $now ) {
    100          
559 0         0 delete $cache->{$cid};
560             } elsif ( !defined($min_expire) || $expire<$min_expire ) {
561 68         208 $min_expire = $expire
562             }
563             }
564              
565             # return time to next expire for optimizations
566 174         974 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 314     314   566 my Net::SIP::Dispatcher $self = shift;
585 314         450 my $qentry = shift;
586              
587             # loop until leg und dst_addr are known, when we call leg->deliver
588 314         590 my $leg = $qentry->{leg}[0];
589 314 50 66     1259 if ( $leg && @{ $qentry->{leg}}>1 ) {
  240         923  
590 0         0 DEBUG( 50,"picking first of multiple legs: ".join( " ", map { $_->dump } @{ $qentry->{leg}} ));
  0         0  
  0         0  
591             }
592 314         629 my $dst_addr = $qentry->{dst_addr}[0];
593              
594 314 100 66     1506 if ( ! $dst_addr || ! $leg) {
595              
596             # if explicit routes given use first route
597             # else resolve URI from request
598              
599 113         196 my $uri;
600 113         226 my $packet = $qentry->{packet};
601 113 50       380 if ( my ($route) = $packet->get_header( 'route' )) {
602 0         0 ($uri) = sip_hdrval2parts( route => $route );
603             } else {
604 113         534 $uri = $packet->uri;
605             }
606              
607 113         668 DEBUG( 100,"no dst_addr or leg yet, uri='$uri'" );
608              
609             my $callback = sub {
610 113     113   246 my ($self,$qentry,@error) = @_;
611 113 50       259 if ( @error ) {
612 0         0 $qentry->trigger_callback(@error);
613 0         0 return $self->cancel_delivery( $qentry );
614             } else {
615 113         575 $self->__deliver($qentry);
616             }
617 113         1012 };
618             return $self->resolve_uri(
619             $uri,
620             $qentry->{dst_addr},
621             $qentry->{leg},
622             [ $callback, $self,$qentry ],
623             $qentry->{proto},
624 113         968 );
625             }
626              
627 201 100 100     1044 if ($qentry->{retransmits} && ! $leg->do_retransmits) {
628 30         165 $qentry->{retransmits} = undef;
629             }
630              
631             # I have leg and addr, send packet thru leg to addr
632             my $cb = sub {
633 88     88   253 my ($self,$qentry,$error) = @_;
634 88 50       231 $self || return;
635 88 50 33     593 if ( !$error && $qentry->{retransmits} ) {
636             # remove from queue even if timeout
637 0         0 $self->cancel_delivery( $qentry );
638             }
639 88         418 $qentry->trigger_callback( $error );
640 201         1605 };
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 201 50       704 $DEBUG && DEBUG(50,"deliver through leg ".$leg->dump.' @'
646             .ip_parts2string($dst_addr));
647 201         932 weaken( my $rself = \$self );
648 201         523 $cb = [ $cb,$self,$qentry ];
649 201         662 weaken( $cb->[1] );
650 201         1559 $leg->deliver( $qentry->{packet},$dst_addr,$cb );
651              
652 201 100       3890 if ( !$qentry->{retransmits} ) {
653             # remove from queue if no timeout
654 133         731 $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 120     120 1 260 my Net::SIP::Dispatcher $self = shift;
675 120         574 my ($uri,$dst_addr,$legs,$callback,$allowed_proto,$allowed_legs) = @_;
676              
677             # packet should be a request packet (see constructor of *::Dispatcher::Packet)
678 120         518 my ($domain,$user,$sip_proto,$param) = sip_uri2parts($uri);
679 120 50       3120 $domain or do {
680 0         0 DEBUG( 50,"bad URI '$uri'" );
681 0         0 return invoke_callback($callback, EHOSTUNREACH );
682             };
683              
684 120         595 my @proto;
685 120         223 my $default_port = 5060;
686 120 100       583 if ( $sip_proto eq 'sips' ) {
    100          
687 10         34 $default_port = 5061;
688 10         60 @proto = 'tls';
689             } elsif ( my $p = $param->{transport} ) {
690             # explicit spec of proto
691 4         34 @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 106         737 @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 120 50 33     449 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 120   50     335 $dst_addr ||= [];
715 120   50     977 $allowed_legs ||= [ $self->get_legs ];
716 120 100       328 if ( @$legs ) {
717 39         107 my %allowed = map { $_ => 1 } @$legs;
  39         214  
718 39         112 @$allowed_legs = grep { $allowed{$_} } @$allowed_legs;
  39         200  
719             }
720 120 50       332 @$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 120         215 my $ip_addr = $param->{maddr};
726             {
727 120 100       185 my ($host,$port,$family) = ip_string2parts($domain, $ip_addr ? 1:0);
  120         593  
728 120 100       370 $default_port = $port if defined $port;
729 120 100       295 if ($family) {
730 68   33     2668 $ip_addr ||= $host;
731 68         263 $domain = ip_ptr($host,$family);
732             } else {
733 52         209 $domain = $host;
734             }
735             }
736 120         612 DEBUG( 100,"domain=$domain" );
737              
738             # do we have a fixed proxy for the domain or upper domain?
739 120 50       474 if ( ! @$dst_addr ) {
740 120         289 my $d2p = $self->{domain2proxy};
741 120 100 66     1109 if ( $d2p && %$d2p ) {
742 81         806 my $dom = $domain;
743 81         162 my $addr = $d2p->{$dom}; # exact match
744 81         240 while ( ! $addr) {
745 221 100       763 $dom =~s{^[^\.]+\.}{} or last;
746 183         403 $addr = $d2p->{ "*.$dom" };
747             }
748 81   100     310 $addr ||= $d2p->{ $dom = '*'}; # catch-all
749 81 100       192 if ( $addr ) {
750 45         231 DEBUG( 50,"setting dst_addr from domain specific proxy for domain $dom" );
751 45         126 @$dst_addr = @$addr;
752             }
753             }
754             }
755              
756             # do we have a global outgoing proxy?
757 120 50 66     939 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 120 100 66     560 if ( !@$dst_addr && $ip_addr ) {
766 75         245 DEBUG( 50,"setting dst_addr from URI because IP address given" );
767 75         169 @$dst_addr = ( $ip_addr );
768             }
769              
770             # is param maddr set?
771 120 100       362 if ( my $ip = $param->{maddr} ) {
772 7 50       130 @$dst_addr = ($ip) if ip_is_v46($ip);
773             }
774              
775              
776             # entries are hashes of prio,proto,host,addr,port,family
777 120         209 my @resp;
778 120         524 foreach my $addr ( @$dst_addr ) {
779 147 100       394 if ( ref($addr)) {
780 72         162 push @resp,$addr; # right format: see domain2proxy
781             } else {
782 75 50       301 my ($proto,$host,$port,$family) = sip_uri2sockinfo($addr)
783             or next;
784 75 50 33     1120 $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 75 50       846 push @resp, map { lock_ref_keys({
  139         1665  
792             %$addr,
793             proto => $_,
794             prio => SRV_PRIO_UNDEF,
795             }) } $proto ? ($proto) : @proto;
796             }
797             }
798              
799             # should we use a fixed transport?
800 120 100 66     1771 if (@resp and my $proto = $param->{transport} ) {
801 4         34 $proto = lc($proto);
802 4 50       80 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         34 @resp = grep { $_->{proto} ne 'udp' } @resp
  4         44  
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       44 return invoke_callback($callback, ENOPROTOOPT) if ! @resp;
814             }
815              
816 120         452 my @param = ( $dst_addr,$legs,$allowed_legs,$default_port,$callback );
817 120 50       378 if (@resp) {
818             # directly call __resolve_uri_final if all names are resolved
819             return __resolve_uri_final( @param,\@resp )
820 120 50       240 if ! grep { ! $_->{addr} } @resp;
  211         2566  
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 120     120   408 my ($dst_addr,$legs,$allowed_legs,$default_port,$callback,$resp) = @_;
837 120 50       355 $DEBUG && DEBUG_DUMP( 100,$resp );
838              
839 120 50 33     1056 return invoke_callback( $callback,EHOSTUNREACH )
840             unless $resp && @$resp;
841              
842             # for A|AAAA records we got no port, use default_port
843 120   33     624 $_->{port} ||= $default_port for(@$resp);
844              
845             # sort by prio
846             # FIXME: can contradict order in @proto
847 120         643 @$resp = sort { $a->{prio} <=> $b->{prio} } @$resp;
  91         1634  
848              
849 120         368 @$dst_addr = ();
850 120         210 @$legs = ();
851 120         332 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 211     223   1790 )} @$allowed_legs;
  223         1559  
859              
860 211 100       3439 if ( $leg ) {
861 126         238 push @$dst_addr, $r;
862 126         307 push @$legs,$leg;
863             } else {
864 85         534 DEBUG(50,"no leg with $r->{proto} to %s", ip_parts2string($r));
865             }
866             }
867              
868 120 50       355 return invoke_callback( $callback, EHOSTUNREACH ) if !@$dst_addr;
869 120         482 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 43         238 '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 43     43   388 );
  43         87  
1221              
1222 43     43   4879 use Net::SIP::Debug;
  43         102  
  43         196  
1223 43     43   264 use Net::SIP::Util ':all';
  43         85  
  43         7149  
1224 43     43   271 use Hash::Util 'lock_ref_keys';
  43         84  
  43         779  
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 196     196   1190 my ($class,%args) = @_;
1235 196         445 my $now = delete $args{now};
1236              
1237 196         602 my $self = fields::new( $class );
1238 196         19857 %$self = %args;
1239 196   66     1143 $self->{id} ||= $self->{packet}->tid;
1240 196   33     1764 $self->{callid} ||= $self->{packet}->callid;
1241              
1242 196         408 my $addr = $self->{dst_addr};
1243 196 100       21040 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 83         258 $self->{dst_addr} = [ $addr ];
1255             } else {
1256             # assume its already in the expected format, i.e. list of hashes
1257             }
1258 196 100       655 if ( my $leg = $self->{leg} ) {
1259 122 50       1021 $self->{leg} = [ $leg ] if UNIVERSAL::can( $leg,'deliver' );
1260             }
1261              
1262 196   100     1426 $self->{dst_addr} ||= [];
1263 196   100     805 $self->{leg} ||= [];
1264 196         597 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 189     189   362 my Net::SIP::Dispatcher::Packet $self = shift;
1275 189 100 100     1429 return if $self->{leg}[0] && ! $self->{leg}[0]->do_retransmits;
1276              
1277 137         276 my $now = shift;
1278 137         236 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 137         254 my ($t1,$t2);
1286 137 100       490 if ( $p->is_response ) {
    100          
    100          
1287 39 100 100     130 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 19         60 ($t1,$t2) = (0.500,4);
1292             }
1293             } elsif ( $p->method eq 'INVITE' ) {
1294             # INVITE request
1295 40         126 ($t1,$t2) = (0.500,undef);
1296             } elsif ( $p->method eq 'ACK' ) {
1297             # no retransmit of ACKs
1298             } else {
1299             # non-INVITE request
1300 34         106 ($t1,$t2) = (0.500,4);
1301             }
1302              
1303             # no retransmits?
1304 137 100       543 $t1 || return;
1305              
1306 93   66     923 $now ||= time();
1307 93         274 my $expire = $now + 64*$t1;
1308 93         213 my $to = $t1;
1309 93         317 my $rtm = $now + $to;
1310              
1311 93         158 my @retransmits;
1312 93         297 while ( $rtm < $expire ) {
1313 770         1138 push @retransmits, $rtm;
1314 770         1092 $to *= 2;
1315 770 100 100     2000 $to = $t2 if $t2 && $to>$t2;
1316 770         1233 $rtm += $to
1317             }
1318 93         388 DEBUG( 100,"retransmits $now + ".join( " ", map { $_ - $now } @retransmits ));
  770         3040  
1319 93         796 $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   161 my Net::SIP::Dispatcher::Packet $self = shift;
1349 88         144 my $error = shift;
1350 88   100     334 my $cb = $self->{callback} || return;
1351 45         256 invoke_callback( $cb,$error,$self);
1352 45         394 return 1;
1353             }
1354              
1355             ###########################################################################
1356             # return transaction id of packet
1357             # Args: $self
1358             # Returns: $tid
1359             ###########################################################################
1360             sub tid {
1361 45     45   76 my Net::SIP::Dispatcher::Packet $self = shift;
1362 45         169 return $self->{packet}->tid;
1363             }
1364             1;