| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | ########################################################################### | 
| 2 |  |  |  |  |  |  | # package Net::SIP::Leg | 
| 3 |  |  |  |  |  |  | # a leg is a special kind of socket, which can send and receive SIP packets | 
| 4 |  |  |  |  |  |  | # and manipulate transport relevant SIP header (Via,Record-Route) | 
| 5 |  |  |  |  |  |  | ########################################################################### | 
| 6 |  |  |  |  |  |  |  | 
| 7 | 43 |  |  | 43 |  | 236 | use strict; | 
|  | 43 |  |  |  |  | 78 |  | 
|  | 43 |  |  |  |  | 995 |  | 
| 8 | 43 |  |  | 43 |  | 173 | use warnings; | 
|  | 43 |  |  |  |  | 63 |  | 
|  | 43 |  |  |  |  | 1357 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | package Net::SIP::Leg; | 
| 11 | 43 |  |  | 43 |  | 232 | use Digest::MD5 'md5_hex'; | 
|  | 43 |  |  |  |  | 104 |  | 
|  | 43 |  |  |  |  | 2284 |  | 
| 12 | 43 |  |  | 43 |  | 18951 | use Socket; | 
|  | 43 |  |  |  |  | 128808 |  | 
|  | 43 |  |  |  |  | 15409 |  | 
| 13 | 43 |  |  | 43 |  | 15118 | use Net::SIP::Debug; | 
|  | 43 |  |  |  |  | 102 |  | 
|  | 43 |  |  |  |  | 221 |  | 
| 14 | 43 |  |  | 43 |  | 18406 | use Net::SIP::Util ':all'; | 
|  | 43 |  |  |  |  | 125 |  | 
|  | 43 |  |  |  |  | 9684 |  | 
| 15 | 43 |  |  | 43 |  | 19371 | use Net::SIP::SocketPool; | 
|  | 43 |  |  |  |  | 105 |  | 
|  | 43 |  |  |  |  | 188 |  | 
| 16 | 43 |  |  | 43 |  | 271 | use Net::SIP::Packet; | 
|  | 43 |  |  |  |  | 86 |  | 
|  | 43 |  |  |  |  | 823 |  | 
| 17 | 43 |  |  | 43 |  | 17181 | use Net::SIP::Request; | 
|  | 43 |  |  |  |  | 108 |  | 
|  | 43 |  |  |  |  | 1097 |  | 
| 18 | 43 |  |  | 43 |  | 16941 | use Net::SIP::Response; | 
|  | 43 |  |  |  |  | 110 |  | 
|  | 43 |  |  |  |  | 1180 |  | 
| 19 | 43 |  |  | 43 |  | 231 | use Errno qw(EHOSTUNREACH EINVAL); | 
|  | 43 |  |  |  |  | 79 |  | 
|  | 43 |  |  |  |  | 1905 |  | 
| 20 | 43 |  |  | 43 |  | 207 | use Hash::Util 'lock_ref_keys'; | 
|  | 43 |  |  |  |  | 74 |  | 
|  | 43 |  |  |  |  | 274 |  | 
| 21 | 43 |  |  | 43 |  | 1844 | use Carp; | 
|  | 43 |  |  |  |  | 79 |  | 
|  | 43 |  |  |  |  | 1872 |  | 
| 22 |  |  |  |  |  |  |  | 
| 23 | 43 |  |  | 43 |  | 200 | use fields qw(contact branch via proto src socketpool); | 
|  | 43 |  |  |  |  | 63 |  | 
|  | 43 |  |  |  |  | 250 |  | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | # sock: the socket for the leg | 
| 26 |  |  |  |  |  |  | # src: hash addr,port,family where it receives data and sends data from | 
| 27 |  |  |  |  |  |  | # proto: udp|tcp | 
| 28 |  |  |  |  |  |  | # contact: to identify myself (default from addr:port) | 
| 29 |  |  |  |  |  |  | # branch: base for branch-tag for via header | 
| 30 |  |  |  |  |  |  | # via: precomputed part of via value | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | ########################################################################### | 
| 33 |  |  |  |  |  |  | # create a new leg | 
| 34 |  |  |  |  |  |  | # Args: ($class,%args) | 
| 35 |  |  |  |  |  |  | #   %args: hash, the following keys will be used and deleted from hash | 
| 36 |  |  |  |  |  |  | #      proto: udp|tcp|tls. If not given will be determined from 'sock' or will | 
| 37 |  |  |  |  |  |  | #        default to 'udp' or 'tls' (if 'tls' arg is used) | 
| 38 |  |  |  |  |  |  | #      host,addr,port,family: source of outgoing and destination of | 
| 39 |  |  |  |  |  |  | #        incoming data. | 
| 40 |  |  |  |  |  |  | #        If IP address addr not given these values will be determined from | 
| 41 |  |  |  |  |  |  | #        'sock'. Otherwise port will default to 5060 or 5061 (tls) and family | 
| 42 |  |  |  |  |  |  | #        will be determined from addr syntax. host will default to addr | 
| 43 |  |  |  |  |  |  | #      dst: destination for this leg in case a fixed destination is used | 
| 44 |  |  |  |  |  |  | #        if not given 'sock' will be checked if connected | 
| 45 |  |  |  |  |  |  | #      sock: socket which can just be used | 
| 46 |  |  |  |  |  |  | #        if not given will create new socket based on proto, addr, port | 
| 47 |  |  |  |  |  |  | #        if dst is given this new socket will be connected (udp only) | 
| 48 |  |  |  |  |  |  | #      socketpool: socketpool which can just be used | 
| 49 |  |  |  |  |  |  | #        if not given a new SocketPool object will be created based on the given | 
| 50 |  |  |  |  |  |  | #        'sock' or the created socket (addr, port...). 'sock' and 'socketpool' | 
| 51 |  |  |  |  |  |  | #        must not be given both. | 
| 52 |  |  |  |  |  |  | #      tls: optional configuration parameters for IO::Socket::SSL. Implies | 
| 53 |  |  |  |  |  |  | #        use of proto 'tls'. | 
| 54 |  |  |  |  |  |  | #      contact: contact information | 
| 55 |  |  |  |  |  |  | #        default will be based on addr and port | 
| 56 |  |  |  |  |  |  | #      branch: branch informaton | 
| 57 |  |  |  |  |  |  | #        default will be based on proto, addr, port | 
| 58 |  |  |  |  |  |  | # Returns: $self - new leg object | 
| 59 |  |  |  |  |  |  | ########################################################################### | 
| 60 |  |  |  |  |  |  | sub new { | 
| 61 | 143 |  |  | 143 | 1 | 43435 | my ($class,%args) = @_; | 
| 62 | 143 |  |  |  |  | 1844 | my $self = fields::new($class); | 
| 63 |  |  |  |  |  |  |  | 
| 64 | 143 |  |  |  |  | 24598 | my $proto = delete $args{proto}; | 
| 65 | 143 |  |  |  |  | 427 | my $dst = delete $args{dst}; | 
| 66 | 143 |  |  |  |  | 413 | my $tls = delete $args{tls}; | 
| 67 | 143 | 100 | 50 |  |  | 1298 | $proto ||= 'tls' if $tls; | 
| 68 |  |  |  |  |  |  |  | 
| 69 | 143 | 100 | 100 |  |  | 1257 | my ($sip_proto,$default_port) = $proto && $proto eq 'tls' | 
| 70 |  |  |  |  |  |  | ? ('sips',5061) : ('sip',5060); | 
| 71 |  |  |  |  |  |  |  | 
| 72 | 143 |  |  |  |  | 395 | my $family; | 
| 73 | 143 |  |  |  |  | 328 | my $host = delete $args{host}; | 
| 74 | 143 | 100 |  |  |  | 629 | if (my $addr = delete $args{addr}) { | 
| 75 | 4 |  |  |  |  | 7 | my $port = delete $args{port}; | 
| 76 | 4 |  |  |  |  | 6 | my $family = delete $args{family}; | 
| 77 | 4 | 50 |  |  |  | 11 | if (!$family) { | 
| 78 | 4 |  |  |  |  | 12 | ($addr,my $port_a, $family) = ip_string2parts($addr); | 
| 79 | 4 | 50 | 66 |  |  | 14 | die "port given both as argument and contained in address" | 
|  |  |  | 33 |  |  |  |  | 
| 80 |  |  |  |  |  |  | if $port && $port_a && $port != $port_a; | 
| 81 | 4 | 50 |  |  |  | 7 | $port = $port_a if $port_a; | 
| 82 |  |  |  |  |  |  | } | 
| 83 |  |  |  |  |  |  | # port defined and 0 -> get port from system | 
| 84 | 4 | 50 |  |  |  | 10 | $port = $default_port if ! defined $port; | 
| 85 | 4 |  | 33 |  |  | 36 | $self->{src} = lock_ref_keys({ | 
| 86 |  |  |  |  |  |  | host   => $host || $addr, | 
| 87 |  |  |  |  |  |  | addr   => $addr, | 
| 88 |  |  |  |  |  |  | port   => $port, | 
| 89 |  |  |  |  |  |  | family => $family | 
| 90 |  |  |  |  |  |  | }); | 
| 91 |  |  |  |  |  |  | } | 
| 92 |  |  |  |  |  |  |  | 
| 93 | 143 | 50 | 33 |  |  | 1017 | if ($dst && !ref($dst)) { | 
| 94 | 0 |  |  |  |  | 0 | my ($ip,$port,$family) = ip_string2parts($dst); | 
| 95 | 0 | 0 |  |  |  | 0 | $family or die "destination must contain IP address"; | 
| 96 | 0 |  |  |  |  | 0 | $dst = lock_ref_keys({ | 
| 97 |  |  |  |  |  |  | host   => $ip, | 
| 98 |  |  |  |  |  |  | addr   => $ip, | 
| 99 |  |  |  |  |  |  | port   => $port, | 
| 100 |  |  |  |  |  |  | family => $family, | 
| 101 |  |  |  |  |  |  | }); | 
| 102 |  |  |  |  |  |  | } | 
| 103 |  |  |  |  |  |  |  | 
| 104 | 143 |  |  |  |  | 388 | my $sock = delete $args{sock}; | 
| 105 | 143 |  |  |  |  | 398 | my $socketpool = delete $args{socketpool}; | 
| 106 | 143 | 50 | 66 |  |  | 1154 | die "only socketpool or sock should be given" if $sock && $socketpool; | 
| 107 | 143 |  | 33 |  |  | 547 | $sock ||= $socketpool && $socketpool->master; | 
|  |  |  | 66 |  |  |  |  | 
| 108 |  |  |  |  |  |  |  | 
| 109 | 143 |  |  |  |  | 372 | my $sockpeer = undef; | 
| 110 | 143 | 100 |  |  |  | 477 | if (!$sock) { | 
| 111 |  |  |  |  |  |  | # create new socket | 
| 112 | 3 |  | 50 |  |  | 17 | $proto ||= 'udp'; | 
| 113 | 3 |  |  |  |  | 6 | my $src = $self->{src}; | 
| 114 | 3 | 50 |  |  |  | 5 | if (!$src) { | 
| 115 |  |  |  |  |  |  | # no src given, try to get useable soure from dst | 
| 116 | 0 | 0 |  |  |  | 0 | die "neither source, destination nor socket given" if !$dst; | 
| 117 | 0 | 0 |  |  |  | 0 | my $srcip = laddr4dst($dst->{addr}) or die | 
| 118 |  |  |  |  |  |  | "cannot find local IP when connecting to $dst->{addr}"; | 
| 119 |  |  |  |  |  |  | $src = $self->{src} = lock_ref_keys({ | 
| 120 |  |  |  |  |  |  | host   => $host || $srcip, | 
| 121 |  |  |  |  |  |  | addr   => $srcip, | 
| 122 |  |  |  |  |  |  | port   => 0, | 
| 123 |  |  |  |  |  |  | family => $dst->{family}, | 
| 124 | 0 |  | 0 |  |  | 0 | }); | 
| 125 |  |  |  |  |  |  | } | 
| 126 |  |  |  |  |  |  |  | 
| 127 | 3 | 50 |  |  |  | 9 | croak("addr must be IP address") if ! ip_is_v46($src->{addr}); | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | my %sockargs = ( | 
| 130 |  |  |  |  |  |  | Proto     => $proto eq 'tls' ? 'tcp' : $proto, | 
| 131 |  |  |  |  |  |  | Family    => $src->{family}, | 
| 132 |  |  |  |  |  |  | LocalAddr => $src->{addr}, | 
| 133 | 3 | 50 |  |  |  | 15 | Reuse     => 1, ReuseAddr => 1, | 
| 134 |  |  |  |  |  |  | ); | 
| 135 | 3 | 50 | 33 |  |  | 14 | if ($proto eq 'tcp' or $proto eq 'tls') { | 
|  |  | 50 |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | # with TCP we create a listening socket | 
| 137 | 0 |  |  |  |  | 0 | $sockargs{Listen} = 100; | 
| 138 |  |  |  |  |  |  | } elsif ($dst) { | 
| 139 |  |  |  |  |  |  | # with UDP we can create a connected socket if dst is given | 
| 140 | 0 |  |  |  |  | 0 | $sockargs{PeerAddr} = $dst->{addr}; | 
| 141 | 0 |  |  |  |  | 0 | $sockargs{PeerPort} = $dst->{port}; | 
| 142 | 0 |  |  |  |  | 0 | $sockpeer = $dst; | 
| 143 |  |  |  |  |  |  | } | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | # create a socket with the given local port | 
| 146 |  |  |  |  |  |  | # if no port is given try 5060,5062.. or let the system pick one | 
| 147 | 3 | 50 |  |  |  | 9 | for my $port ($src->{port} | 
| 148 |  |  |  |  |  |  | ? $src->{port} | 
| 149 |  |  |  |  |  |  | : ($default_port, 5062..5100, 0)) { | 
| 150 | 3 | 50 |  |  |  | 11 | last if $sock = INETSOCK(%sockargs, LocalPort => $port); | 
| 151 |  |  |  |  |  |  | } | 
| 152 |  |  |  |  |  |  |  | 
| 153 | 3 | 50 |  |  |  | 1429 | $sock or die "failed to bind to " . ip_parts2string($src).": $!"; | 
| 154 | 3 |  | 33 |  |  | 16 | $src->{port} ||= $sock->sockport; | 
| 155 | 3 |  |  |  |  | 125 | DEBUG(90,"created socket on ".ip_parts2string($src)); | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | } else { | 
| 158 |  |  |  |  |  |  | # get proto from socket | 
| 159 | 140 | 100 | 66 |  |  | 1987 | $proto ||= $sock->socktype == SOCK_DGRAM ? 'udp':'tcp'; | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | # get src from socket | 
| 162 | 140 | 100 |  |  |  | 2748 | if (!$self->{src}) { | 
| 163 | 139 | 50 |  |  |  | 1671 | my $saddr = getsockname($sock) or die | 
| 164 |  |  |  |  |  |  | "cannot get local name from provided socket: $!"; | 
| 165 | 139 |  |  |  |  | 1349 | $self->{src} = ip_sockaddr2parts($saddr); | 
| 166 | 139 | 50 |  |  |  | 488 | $self->{src}{host} = $host if $host; | 
| 167 |  |  |  |  |  |  | } | 
| 168 | 140 | 50 | 33 |  |  | 2050 | if (!$dst and my $saddr = getpeername($sock)) { | 
| 169 |  |  |  |  |  |  | # set dst from connected socket | 
| 170 | 0 |  |  |  |  | 0 | $sockpeer = $dst = ip_sockaddr2parts($saddr); | 
| 171 |  |  |  |  |  |  | } | 
| 172 |  |  |  |  |  |  | } | 
| 173 |  |  |  |  |  |  |  | 
| 174 |  |  |  |  |  |  | # create socketpool and add primary socket of leg to it if needed | 
| 175 | 143 |  | 33 |  |  | 3070 | $self->{socketpool} = $socketpool ||= Net::SIP::SocketPool->new( | 
| 176 |  |  |  |  |  |  | $proto, $sock, $dst, $sockpeer, $tls); | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | my $leg_addr = ip_parts2string({ | 
| 179 | 143 |  |  |  |  | 296 | %{$self->{src}}, | 
|  | 143 |  |  |  |  | 1565 |  | 
| 180 |  |  |  |  |  |  | use_host => 1, # prefer hostname | 
| 181 |  |  |  |  |  |  | default_port => $default_port, | 
| 182 |  |  |  |  |  |  | }, 1);  # use "[ipv6]" even if no port is given | 
| 183 | 143 |  | 33 |  |  | 1166 | $self->{contact}  = delete $args{contact} || "$sip_proto:$leg_addr"; | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | $self->{branch} = 'z9hG4bK'. ( | 
| 186 |  |  |  |  |  |  | delete $args{branch} | 
| 187 | 143 |  | 33 |  |  | 801 | || md5_hex(@{$self->{src}}{qw(addr port)}, $proto)  # ip, port, proto | 
| 188 |  |  |  |  |  |  | ); | 
| 189 |  |  |  |  |  |  |  | 
| 190 | 143 |  |  |  |  | 918 | $self->{via} =  sprintf( "SIP/2.0/%s %s;branch=", | 
| 191 |  |  |  |  |  |  | uc($proto),$leg_addr ); | 
| 192 | 143 |  |  |  |  | 347 | $self->{proto} = $proto; | 
| 193 |  |  |  |  |  |  |  | 
| 194 | 143 | 50 |  |  |  | 445 | die "unhandled arguments: ".join(", ", keys %args) if %args; | 
| 195 |  |  |  |  |  |  |  | 
| 196 | 143 |  |  |  |  | 2358 | return $self; | 
| 197 |  |  |  |  |  |  | } | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | ########################################################################### | 
| 200 |  |  |  |  |  |  | # do we need retransmits on this leg? | 
| 201 |  |  |  |  |  |  | # Args: $self | 
| 202 |  |  |  |  |  |  | # Returns: 1|0 | 
| 203 |  |  |  |  |  |  | #   1: need retransmits (UDP) | 
| 204 |  |  |  |  |  |  | #   0: don't need retransmits (TCP, TLS) | 
| 205 |  |  |  |  |  |  | ########################################################################### | 
| 206 |  |  |  |  |  |  | sub do_retransmits { | 
| 207 | 215 |  |  | 215 | 0 | 436 | my Net::SIP::Leg $self = shift; | 
| 208 | 215 | 100 |  |  |  | 1206 | return $self->{proto} eq 'udp' ? 1 : 0; | 
| 209 |  |  |  |  |  |  | } | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | ########################################################################### | 
| 212 |  |  |  |  |  |  | # prepare incoming packet for forwarding | 
| 213 |  |  |  |  |  |  | # Args: ($self,$packet) | 
| 214 |  |  |  |  |  |  | #   $packet: incoming Net::SIP::Packet, gets modified in-place | 
| 215 |  |  |  |  |  |  | # Returns: undef | [code,text] | 
| 216 |  |  |  |  |  |  | #   code: error code (can be empty if just drop packet on error) | 
| 217 |  |  |  |  |  |  | #   text: error description (e.g max-forwards reached..) | 
| 218 |  |  |  |  |  |  | ########################################################################### | 
| 219 |  |  |  |  |  |  | sub forward_incoming { | 
| 220 | 7 |  |  | 7 | 1 | 9 | my Net::SIP::Leg $self = shift; | 
| 221 | 7 |  |  |  |  | 13 | my ($packet) = @_; | 
| 222 |  |  |  |  |  |  |  | 
| 223 | 7 | 50 |  |  |  | 13 | if ( $packet->is_response ) { | 
| 224 |  |  |  |  |  |  | # remove top via | 
| 225 | 0 |  |  |  |  | 0 | my $via; | 
| 226 |  |  |  |  |  |  | $packet->scan_header( via => [ sub { | 
| 227 | 0 |  |  | 0 |  | 0 | my ($vref,$hdr) = @_; | 
| 228 | 0 | 0 |  |  |  | 0 | if ( !$$vref ) { | 
| 229 | 0 |  |  |  |  | 0 | $$vref = $hdr->{value}; | 
| 230 | 0 |  |  |  |  | 0 | $hdr->remove; | 
| 231 |  |  |  |  |  |  | } | 
| 232 | 0 |  |  |  |  | 0 | }, \$via ]); | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | } else { | 
| 235 |  |  |  |  |  |  | # Request | 
| 236 |  |  |  |  |  |  |  | 
| 237 |  |  |  |  |  |  | # Max-Fowards | 
| 238 | 7 |  |  |  |  | 26 | my $maxf = $packet->get_header( 'max-forwards' ); | 
| 239 |  |  |  |  |  |  | # we don't want to put somebody Max-Forwards: 7363535353 into the header | 
| 240 |  |  |  |  |  |  | # and then crafting a loop, so limit it to the default value | 
| 241 | 7 | 100 | 66 |  |  | 34 | $maxf = 70 if !$maxf || $maxf>70; | 
| 242 | 7 |  |  |  |  | 15 | $maxf--; | 
| 243 | 7 | 50 |  |  |  | 18 | if ( $maxf <= 0 ) { | 
| 244 |  |  |  |  |  |  | # just drop | 
| 245 | 0 |  |  |  |  | 0 | DEBUG( 10,'reached max-forwards. DROP' ); | 
| 246 | 0 |  |  |  |  | 0 | return [ undef,'max-forwards reached 0, dropping' ]; | 
| 247 |  |  |  |  |  |  | } | 
| 248 | 7 |  |  |  |  | 26 | $packet->set_header( 'max-forwards',$maxf ); | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  | # check if last hop was strict router | 
| 251 |  |  |  |  |  |  | # remove myself from route | 
| 252 | 7 |  |  |  |  | 17 | my $uri = $packet->uri; | 
| 253 | 7 | 50 |  |  |  | 20 | $uri = $1 if $uri =~m{^<(.*)>}; | 
| 254 | 7 |  |  |  |  | 23 | ($uri) = sip_hdrval2parts( route => $uri ); | 
| 255 | 7 |  |  |  |  | 12 | my $remove_route; | 
| 256 | 7 | 50 |  |  |  | 23 | if ( $uri eq $self->{contact} ) { | 
| 257 |  |  |  |  |  |  | # last router placed myself into URI -> strict router | 
| 258 |  |  |  |  |  |  | # get original URI back from last Route-header | 
| 259 | 0 |  |  |  |  | 0 | my @route = $packet->get_header( 'route' ); | 
| 260 | 0 | 0 |  |  |  | 0 | if ( !@route ) { | 
| 261 |  |  |  |  |  |  | # ooops, no route headers? -> DROP | 
| 262 | 0 |  |  |  |  | 0 | return [ '','request from strict router contained no route headers' ]; | 
| 263 |  |  |  |  |  |  | } | 
| 264 | 0 |  |  |  |  | 0 | $remove_route = $#route; | 
| 265 | 0 |  |  |  |  | 0 | $uri = $route[-1]; | 
| 266 | 0 | 0 |  |  |  | 0 | $uri = $1 if $uri =~m{^<(.*)>}; | 
| 267 | 0 |  |  |  |  | 0 | $packet->set_uri($uri); | 
| 268 |  |  |  |  |  |  |  | 
| 269 |  |  |  |  |  |  | } else { | 
| 270 |  |  |  |  |  |  | # last router was loose,remove top route if it is myself | 
| 271 | 7 |  |  |  |  | 17 | my @route = $packet->get_header( 'route' ); | 
| 272 | 7 | 100 |  |  |  | 16 | if ( @route ) { | 
| 273 | 1 |  |  |  |  | 2 | my $route = $route[0]; | 
| 274 | 1 | 50 |  |  |  | 7 | $route = $1 if $route =~m{^<(.*)>}; | 
| 275 | 1 |  |  |  |  | 3 | ($route) = sip_hdrval2parts( route => $route ); | 
| 276 | 1 | 50 |  |  |  | 6 | if ( sip_uri_eq( $route,$self->{contact}) ) { | 
| 277 |  |  |  |  |  |  | # top route was me | 
| 278 | 1 |  |  |  |  | 3 | $remove_route = 0; | 
| 279 |  |  |  |  |  |  | } | 
| 280 |  |  |  |  |  |  | } | 
| 281 |  |  |  |  |  |  | } | 
| 282 | 7 | 100 |  |  |  | 14 | if ( defined $remove_route ) { | 
| 283 |  |  |  |  |  |  | $packet->scan_header( route => [ sub { | 
| 284 | 2 |  |  | 2 |  | 4 | my ($rr,$hdr) = @_; | 
| 285 | 2 | 100 |  |  |  | 6 | $hdr->remove if $$rr-- == 0; | 
| 286 | 1 |  |  |  |  | 10 | }, \$remove_route]); | 
| 287 |  |  |  |  |  |  | } | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | # Add Record-Route to request, except | 
| 290 |  |  |  |  |  |  | # to REGISTER (RFC3261, 10.2) | 
| 291 | 7 | 50 |  |  |  | 17 | $packet->insert_header( 'record-route', '<'.$self->{contact}.';lr>' ) | 
| 292 |  |  |  |  |  |  | if $packet->method ne 'REGISTER'; | 
| 293 |  |  |  |  |  |  | } | 
| 294 |  |  |  |  |  |  |  | 
| 295 | 7 |  |  |  |  | 34 | return; | 
| 296 |  |  |  |  |  |  | } | 
| 297 |  |  |  |  |  |  |  | 
| 298 |  |  |  |  |  |  | ########################################################################### | 
| 299 |  |  |  |  |  |  | # prepare packet which gets forwarded through this leg | 
| 300 |  |  |  |  |  |  | # packet was processed before by forward_incoming on (usually) another | 
| 301 |  |  |  |  |  |  | # leg on the same dispatcher. | 
| 302 |  |  |  |  |  |  | # Args: ($self,$packet,$incoming_leg) | 
| 303 |  |  |  |  |  |  | #   $packet: outgoing Net::SIP::Packet, gets modified in-place | 
| 304 |  |  |  |  |  |  | #   $incoming_leg: leg where packet came in | 
| 305 |  |  |  |  |  |  | # Returns: undef | [code,text] | 
| 306 |  |  |  |  |  |  | #   code: error code (can be empty if just drop packet on error) | 
| 307 |  |  |  |  |  |  | #   text: error description (e.g max-forwards reached..) | 
| 308 |  |  |  |  |  |  | ########################################################################### | 
| 309 |  |  |  |  |  |  | sub forward_outgoing { | 
| 310 | 7 |  |  | 7 | 1 | 8 | my Net::SIP::Leg $self = shift; | 
| 311 | 7 |  |  |  |  | 17 | my ($packet,$incoming_leg) = @_; | 
| 312 |  |  |  |  |  |  |  | 
| 313 | 7 | 50 |  |  |  | 15 | if ( $packet->is_request ) { | 
| 314 |  |  |  |  |  |  | # check if myself is already in Via-path | 
| 315 |  |  |  |  |  |  | # in this case drop the packet, because a loop is detected | 
| 316 | 7 | 50 |  |  |  | 14 | if ( my @via = $packet->get_header( 'via' )) { | 
| 317 | 7 |  |  |  |  | 19 | my $branch = $self->via_branch($packet,3); | 
| 318 | 7 |  |  |  |  | 14 | foreach my $via ( @via ) { | 
| 319 | 7 |  |  |  |  | 12 | my (undef,$param) = sip_hdrval2parts( via => $via ); | 
| 320 |  |  |  |  |  |  | # ignore via header w/o branch, although these don't conform to | 
| 321 |  |  |  |  |  |  | # RFC 3261, sect 8.1.1.7 | 
| 322 | 7 | 50 |  |  |  | 18 | defined $param->{branch} or next; | 
| 323 | 7 | 50 |  |  |  | 24 | if ( substr( $param->{branch},0,length($branch) ) eq $branch ) { | 
| 324 | 0 |  |  |  |  | 0 | DEBUG( 10,'loop detected because outgoing leg is in Via. DROP' ); | 
| 325 | 0 |  |  |  |  | 0 | return [ undef,'loop detected on outgoing leg, dropping' ]; | 
| 326 |  |  |  |  |  |  | } | 
| 327 |  |  |  |  |  |  | } | 
| 328 |  |  |  |  |  |  | } | 
| 329 |  |  |  |  |  |  |  | 
| 330 |  |  |  |  |  |  | # Add Record-Route to request, except | 
| 331 |  |  |  |  |  |  | # to REGISTER (RFC3261, 10.2) | 
| 332 |  |  |  |  |  |  | # This is necessary, because these information are used in in new requests | 
| 333 |  |  |  |  |  |  | # from UAC to UAS, but also from UAS to UAC and UAS should talk to this leg | 
| 334 |  |  |  |  |  |  | # and not to the leg, where the request came in. | 
| 335 |  |  |  |  |  |  | # don't add if the upper record-route is already me, this is the case | 
| 336 |  |  |  |  |  |  | # when incoming and outgoing leg are the same | 
| 337 | 7 | 50 |  |  |  | 17 | if ( $packet->method ne 'REGISTER' ) { | 
| 338 | 7 |  |  |  |  | 9 | my $rr; | 
| 339 | 7 | 50 | 33 |  |  | 20 | unless ( (($rr) = $packet->get_header( 'record-route' )) | 
| 340 |  |  |  |  |  |  | and sip_uri_eq( $rr,$self->{contact} )) { | 
| 341 | 0 |  |  |  |  | 0 | $packet->insert_header( 'record-route', '<'.$self->{contact}.';lr>' ) | 
| 342 |  |  |  |  |  |  | } | 
| 343 |  |  |  |  |  |  | } | 
| 344 |  |  |  |  |  |  |  | 
| 345 |  |  |  |  |  |  | # strip myself from route header, because I'm done | 
| 346 | 7 | 100 |  |  |  | 22 | if ( my @route = $packet->get_header( 'route' ) ) { | 
| 347 | 1 |  |  |  |  | 2 | my $route = $route[0]; | 
| 348 | 1 | 50 |  |  |  | 13 | $route = $1 if $route =~m{^<(.*)>}; | 
| 349 | 1 |  |  |  |  | 4 | ($route) = sip_hdrval2parts( route => $route ); | 
| 350 | 1 | 50 |  |  |  | 4 | if ( sip_uri_eq( $route,$self->{contact} )) { | 
| 351 |  |  |  |  |  |  | # top route was me, remove it | 
| 352 | 0 |  |  |  |  | 0 | my $remove_route = 0; | 
| 353 |  |  |  |  |  |  | $packet->scan_header( route => [ sub { | 
| 354 | 0 |  |  | 0 |  | 0 | my ($rr,$hdr) = @_; | 
| 355 | 0 | 0 |  |  |  | 0 | $hdr->remove if $$rr-- == 0; | 
| 356 | 0 |  |  |  |  | 0 | }, \$remove_route]); | 
| 357 |  |  |  |  |  |  | } | 
| 358 |  |  |  |  |  |  | } | 
| 359 |  |  |  |  |  |  | } | 
| 360 | 7 |  |  |  |  | 22 | return; | 
| 361 |  |  |  |  |  |  | } | 
| 362 |  |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  |  | 
| 364 |  |  |  |  |  |  | ########################################################################### | 
| 365 |  |  |  |  |  |  | # deliver packet through this leg to specified addr | 
| 366 |  |  |  |  |  |  | # add local Via header to requests | 
| 367 |  |  |  |  |  |  | # Args: ($self,$packet,$dst;$callback) | 
| 368 |  |  |  |  |  |  | #   $packet: Net::SIP::Packet | 
| 369 |  |  |  |  |  |  | #   $dst:    target for delivery as hash host,addr,port,family | 
| 370 |  |  |  |  |  |  | #   $callback: optional callback, if an error occurred the callback will | 
| 371 |  |  |  |  |  |  | #      be called with $! as argument. If no error occurred and the | 
| 372 |  |  |  |  |  |  | #      proto is tcp the callback will be called with error=0 to show | 
| 373 |  |  |  |  |  |  | #      that the packet was definitely delivered (and there's no need to retry) | 
| 374 |  |  |  |  |  |  | ########################################################################### | 
| 375 |  |  |  |  |  |  | sub deliver { | 
| 376 | 197 |  |  | 197 | 1 | 444 | my Net::SIP::Leg $self = shift; | 
| 377 | 197 |  |  |  |  | 481 | my ($packet,$dst,$callback) = @_; | 
| 378 |  |  |  |  |  |  |  | 
| 379 | 197 |  |  |  |  | 1076 | my $isrq = $packet->is_request; | 
| 380 | 197 | 100 |  |  |  | 569 | if ( $isrq ) { | 
| 381 |  |  |  |  |  |  | # add via, | 
| 382 |  |  |  |  |  |  | # clone packet, because I don't want to change the original | 
| 383 |  |  |  |  |  |  | # one because it might be retried later | 
| 384 |  |  |  |  |  |  | # (could skip this for tcp?) | 
| 385 | 119 |  |  |  |  | 831 | $packet = $packet->clone; | 
| 386 | 119 |  |  |  |  | 730 | $self->add_via($packet); | 
| 387 |  |  |  |  |  |  | } | 
| 388 |  |  |  |  |  |  |  | 
| 389 |  |  |  |  |  |  | # 2xx responses to INVITE requests and the request itself must have a | 
| 390 |  |  |  |  |  |  | # Contact, Allow and Supported header, 2xx Responses to OPTIONS need | 
| 391 |  |  |  |  |  |  | # Allow and Supported, 405 Responses should have Allow and Supported | 
| 392 |  |  |  |  |  |  |  | 
| 393 | 197 |  |  |  |  | 477 | my ($need_contact,$need_allow,$need_supported); | 
| 394 | 197 |  |  |  |  | 644 | my $method = $packet->method; | 
| 395 | 197 |  | 66 |  |  | 842 | my $code = ! $isrq && $packet->code; | 
| 396 | 197 | 100 | 100 |  |  | 2235 | if ( $method eq 'INVITE' and ( $isrq or $code =~m{^2} )) { | 
|  |  | 100 | 100 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 397 | 62 |  |  |  |  | 178 | $need_contact = $need_allow = $need_supported =1; | 
| 398 |  |  |  |  |  |  | } elsif ( !$isrq and ( | 
| 399 |  |  |  |  |  |  | $code == 405 or | 
| 400 |  |  |  |  |  |  | ( $method eq 'OPTIONS'  and $code =~m{^2} ))) { | 
| 401 | 1 |  |  |  |  | 4 | $need_allow = $need_supported =1; | 
| 402 |  |  |  |  |  |  | } | 
| 403 | 197 | 100 | 66 |  |  | 1174 | if ( $need_contact && ! ( my @a = $packet->get_header( 'contact' ))) { | 
| 404 |  |  |  |  |  |  | # needs contact header, create from this leg and user part of from/to | 
| 405 | 62 | 100 |  |  |  | 255 | my ($user) = sip_hdrval2parts( $isrq | 
| 406 |  |  |  |  |  |  | ? ( from => scalar($packet->get_header('from')) ) | 
| 407 |  |  |  |  |  |  | : ( to   => scalar($packet->get_header('to')) ) | 
| 408 |  |  |  |  |  |  | ); | 
| 409 | 62 |  |  |  |  | 892 | my ($proto,$addr) = $self->{contact} =~m{^(\w+):(?:.*\@)?(.*)$}; | 
| 410 | 62 | 50 |  |  |  | 774 | my $contact = ( $user =~m{([^<>\@\s]+)\@} ? $1 : $user ). | 
| 411 |  |  |  |  |  |  | "\@$addr"; | 
| 412 | 62 | 100 |  |  |  | 444 | $contact = $proto.':'.$contact if $contact !~m{^\w+:}; | 
| 413 | 62 | 50 |  |  |  | 210 | $contact = "<$contact>" if $contact =~m{;}; | 
| 414 | 62 |  |  |  |  | 852 | $packet->insert_header( contact => $contact ); | 
| 415 |  |  |  |  |  |  | } | 
| 416 | 197 | 100 | 66 |  |  | 835 | if ( $need_allow && ! ( my @a = $packet->get_header( 'allow' ))) { | 
| 417 |  |  |  |  |  |  | # insert default methods | 
| 418 | 63 |  |  |  |  | 183 | $packet->insert_header( allow => 'INVITE, ACK, OPTIONS, CANCEL, BYE' ); | 
| 419 |  |  |  |  |  |  | } | 
| 420 | 197 | 100 | 66 |  |  | 882 | if ( $need_supported && ! ( my @a = $packet->get_header( 'supported' ))) { | 
| 421 |  |  |  |  |  |  | # set as empty | 
| 422 | 63 |  |  |  |  | 171 | $packet->insert_header( supported => '' ); | 
| 423 |  |  |  |  |  |  | } | 
| 424 |  |  |  |  |  |  |  | 
| 425 |  |  |  |  |  |  | die "target protocol $dst->{proto} does not match leg $self->{proto}" | 
| 426 | 197 | 50 | 33 |  |  | 1352 | if exists $dst->{proto} && $dst->{proto} ne $self->{proto}; | 
| 427 | 197 | 0 | 33 |  |  | 615 | $dst->{port} ||= $self->{proto} eq 'tls' ? 5061 : 5060; | 
| 428 |  |  |  |  |  |  |  | 
| 429 |  |  |  |  |  |  | $DEBUG && DEBUG( 2, "delivery with %s from %s to %s:\n%s", | 
| 430 |  |  |  |  |  |  | $self->{proto}, | 
| 431 | 197 | 50 |  |  |  | 515 | ip_parts2string($self->{src}), | 
| 432 |  |  |  |  |  |  | ip_parts2string($dst), | 
| 433 |  |  |  |  |  |  | $packet->dump( Net::SIP::Debug->level -2 ) ); | 
| 434 |  |  |  |  |  |  |  | 
| 435 | 197 |  |  |  |  | 850 | return $self->sendto($packet,$dst,$callback); | 
| 436 |  |  |  |  |  |  | } | 
| 437 |  |  |  |  |  |  |  | 
| 438 |  |  |  |  |  |  | ########################################################################### | 
| 439 |  |  |  |  |  |  | # send data to peer | 
| 440 |  |  |  |  |  |  | # Args: ($self,$packet,$dst,$callback) | 
| 441 |  |  |  |  |  |  | #   $packet: SIP packet object | 
| 442 |  |  |  |  |  |  | #   $dst:   target as hash host,addr,port,family | 
| 443 |  |  |  |  |  |  | #   $callback: callback for error|success, see method deliver | 
| 444 |  |  |  |  |  |  | # Returns: $success | 
| 445 |  |  |  |  |  |  | #   $success: true if no problems occurred while sending (this does not | 
| 446 |  |  |  |  |  |  | #     mean that the packet was delivered reliable!) | 
| 447 |  |  |  |  |  |  | ########################################################################### | 
| 448 |  |  |  |  |  |  | sub sendto { | 
| 449 | 196 |  |  | 196 | 0 | 405 | my Net::SIP::Leg $self = shift; | 
| 450 | 196 |  |  |  |  | 459 | my ($packet,$dst,$callback) = @_; | 
| 451 |  |  |  |  |  |  |  | 
| 452 | 196 | 50 |  |  |  | 1323 | $self->{socketpool}->sendto($packet,$dst,$callback) | 
| 453 |  |  |  |  |  |  | && return 1; | 
| 454 | 196 |  |  |  |  | 1734 | return; | 
| 455 |  |  |  |  |  |  | } | 
| 456 |  |  |  |  |  |  |  | 
| 457 |  |  |  |  |  |  | ########################################################################### | 
| 458 |  |  |  |  |  |  | # Handle newly received packet. | 
| 459 |  |  |  |  |  |  | # Currently just passes through the packet | 
| 460 |  |  |  |  |  |  | # Args: ($self,$packet,$from) | 
| 461 |  |  |  |  |  |  | #   $packet: packet object | 
| 462 |  |  |  |  |  |  | #   $from: hash with proto,addr,port,family where the packet came from | 
| 463 |  |  |  |  |  |  | # Returns: ($packet,$from)|() | 
| 464 |  |  |  |  |  |  | #   $packet: packet object | 
| 465 |  |  |  |  |  |  | #   $from: hash with proto,ip,port,family where the packet came from | 
| 466 |  |  |  |  |  |  | ########################################################################### | 
| 467 |  |  |  |  |  |  | sub receive { | 
| 468 | 209 |  |  | 209 | 1 | 403 | my Net::SIP::Leg $self = shift; | 
| 469 | 209 |  |  |  |  | 507 | my ($packet,$from) = @_; | 
| 470 |  |  |  |  |  |  |  | 
| 471 |  |  |  |  |  |  | $DEBUG && DEBUG( 2,"received packet on %s from %s:\n%s", | 
| 472 | 0 |  |  |  |  | 0 | sip_sockinfo2uri($self->{proto},@{$self->{src}}{qw(addr port family)}), | 
| 473 | 209 | 50 |  |  |  | 574 | sip_sockinfo2uri(@{$from}{qw(proto addr port family)}), | 
|  | 0 |  |  |  |  | 0 |  | 
| 474 |  |  |  |  |  |  | $packet->dump( Net::SIP::Debug->level -2 ) | 
| 475 |  |  |  |  |  |  | ); | 
| 476 | 209 |  |  |  |  | 833 | return ($packet,$from); | 
| 477 |  |  |  |  |  |  | } | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  |  | 
| 480 |  |  |  |  |  |  | ########################################################################### | 
| 481 |  |  |  |  |  |  | # check if the top via header matches the transport of this call through | 
| 482 |  |  |  |  |  |  | # this leg. Used to strip Via header in response. | 
| 483 |  |  |  |  |  |  | # Args: ($self,$packet) | 
| 484 |  |  |  |  |  |  | #  $packet: Net::SIP::Packet (usually Net::SIP::Response) | 
| 485 |  |  |  |  |  |  | # Returns: $bool | 
| 486 |  |  |  |  |  |  | #  $bool: true if the packets via matches this leg, else false | 
| 487 |  |  |  |  |  |  | ########################################################################### | 
| 488 |  |  |  |  |  |  | sub check_via { | 
| 489 | 136 |  |  | 136 | 1 | 451 | my ($self,$packet) = @_; | 
| 490 | 136 |  |  |  |  | 393 | my ($via) = $packet->get_header( 'via' ); | 
| 491 | 136 |  |  |  |  | 533 | my ($data,$param) = sip_hdrval2parts( via => $via ); | 
| 492 | 136 |  |  |  |  | 543 | my $cmp_branch = $self->via_branch($packet,2); | 
| 493 | 136 |  |  |  |  | 1024 | return substr( $param->{branch},0,length($cmp_branch)) eq $cmp_branch; | 
| 494 |  |  |  |  |  |  | } | 
| 495 |  |  |  |  |  |  |  | 
| 496 |  |  |  |  |  |  | ########################################################################### | 
| 497 |  |  |  |  |  |  | # add myself as Via header to packet | 
| 498 |  |  |  |  |  |  | # Args: ($self,$packet) | 
| 499 |  |  |  |  |  |  | #  $packet: Net::SIP::Packet (usually Net::SIP::Request) | 
| 500 |  |  |  |  |  |  | # Returns: NONE | 
| 501 |  |  |  |  |  |  | # modifies packet in-place | 
| 502 |  |  |  |  |  |  | ########################################################################### | 
| 503 |  |  |  |  |  |  | sub add_via { | 
| 504 | 125 |  |  | 125 | 1 | 265 | my Net::SIP::Leg $self = shift; | 
| 505 | 125 |  |  |  |  | 229 | my $packet = shift; | 
| 506 | 125 |  |  |  |  | 572 | $packet->insert_header( via => $self->{via}.$self->via_branch($packet,3)); | 
| 507 |  |  |  |  |  |  | } | 
| 508 |  |  |  |  |  |  |  | 
| 509 |  |  |  |  |  |  | ########################################################################### | 
| 510 |  |  |  |  |  |  | # computes branch tag for via header | 
| 511 |  |  |  |  |  |  | # Args: ($self,$packet,$level) | 
| 512 |  |  |  |  |  |  | #  $packet: Net::SIP::Packet (usually Net::SIP::Request) | 
| 513 |  |  |  |  |  |  | #  $level: level of detail: 1:leg, 2:call, 3:path | 
| 514 |  |  |  |  |  |  | # Returns: $value | 
| 515 |  |  |  |  |  |  | ########################################################################### | 
| 516 |  |  |  |  |  |  | sub via_branch { | 
| 517 | 268 |  |  | 268 | 0 | 419 | my Net::SIP::Leg $self = shift; | 
| 518 | 268 |  |  |  |  | 596 | my ($packet,$level) = @_; | 
| 519 | 268 |  |  |  |  | 540 | my $val = $self->{branch}; | 
| 520 | 268 | 50 |  |  |  | 1071 | $val .= substr( md5_hex( $packet->tid ),0,15 ) if $level>1; | 
| 521 | 268 | 100 |  |  |  | 778 | if ($level>2) { | 
| 522 | 132 |  |  |  |  | 241 | my @parts; | 
| 523 |  |  |  |  |  |  | # RT#120816 -  take only known constant values from proxy-authorization | 
| 524 | 132 |  |  |  |  | 388 | for(sort $packet->get_header('proxy-authorization')) { | 
| 525 | 0 |  |  |  |  | 0 | my ($typ,$param) = sip_hdrval2parts('proxy-authorization' => $_); | 
| 526 | 0 |  |  |  |  | 0 | push @parts,$typ; | 
| 527 | 0 |  |  |  |  | 0 | for(qw(realm username domain qop algorithm)) { | 
| 528 | 0 | 0 |  |  |  | 0 | push @parts,"$_=$param->{$_}" if exists $param->{$_}; | 
| 529 |  |  |  |  |  |  | } | 
| 530 |  |  |  |  |  |  | } | 
| 531 |  |  |  |  |  |  |  | 
| 532 |  |  |  |  |  |  | # RT#120816 - include only the branch from via header if possible | 
| 533 | 132 | 100 |  |  |  | 544 | if (my $via = ($packet->get_header('via'))[0]) { | 
| 534 | 8 |  |  |  |  | 19 | my (undef,$param) = sip_hdrval2parts(via => $via); | 
| 535 | 8 |  | 33 |  |  | 39 | push @parts, $param && $param->{branch} || $via; | 
| 536 |  |  |  |  |  |  | } | 
| 537 |  |  |  |  |  |  |  | 
| 538 | 132 |  |  |  |  | 369 | push @parts, | 
| 539 |  |  |  |  |  |  | ( sort $packet->get_header('proxy-require')), | 
| 540 |  |  |  |  |  |  | $packet->get_header('route'), | 
| 541 |  |  |  |  |  |  | $packet->get_header('from'), | 
| 542 |  |  |  |  |  |  | ($packet->as_parts())[1]; # URI | 
| 543 | 132 |  |  |  |  | 665 | $val .= substr(md5_hex(@parts),0,15); | 
| 544 |  |  |  |  |  |  | } | 
| 545 | 268 |  |  |  |  | 1462 | return $val; | 
| 546 |  |  |  |  |  |  | } | 
| 547 |  |  |  |  |  |  |  | 
| 548 |  |  |  |  |  |  | ########################################################################### | 
| 549 |  |  |  |  |  |  | # check if the leg could deliver to the specified addr | 
| 550 |  |  |  |  |  |  | # Args: ($self,($addr|%spec)) | 
| 551 |  |  |  |  |  |  | #  $addr: addr|proto:addr|addr:port|proto:addr:port | 
| 552 |  |  |  |  |  |  | #  %spec: hash with keys addr,proto,port | 
| 553 |  |  |  |  |  |  | # Returns: $bool | 
| 554 |  |  |  |  |  |  | #  $bool: true if we can deliver to $ip with $proto | 
| 555 |  |  |  |  |  |  | ########################################################################### | 
| 556 |  |  |  |  |  |  | sub can_deliver_to { | 
| 557 | 199 |  |  | 199 | 1 | 356 | my Net::SIP::Leg $self = shift; | 
| 558 | 199 |  |  |  |  | 298 | my %spec; | 
| 559 | 199 | 50 |  |  |  | 550 | if (@_>1) { | 
| 560 | 199 |  |  |  |  | 960 | %spec = @_; | 
| 561 |  |  |  |  |  |  | } else { | 
| 562 | 0 |  |  |  |  | 0 | @spec{ qw(proto host port family) } = sip_uri2sockinfo(shift()); | 
| 563 | 0 | 0 |  |  |  | 0 | $spec{addr} = $spec{family} ? $spec{host} : undef; | 
| 564 |  |  |  |  |  |  | } | 
| 565 |  |  |  |  |  |  |  | 
| 566 |  |  |  |  |  |  | # return false if proto or family don't match | 
| 567 | 199 | 100 | 66 |  |  | 1544 | return if $spec{proto} && $spec{proto} ne $self->{proto}; | 
| 568 |  |  |  |  |  |  | return if $spec{family} && $self->{src} | 
| 569 | 114 | 50 | 33 |  |  | 972 | && $self->{src}{family} != $spec{family}; | 
|  |  |  | 33 |  |  |  |  | 
| 570 |  |  |  |  |  |  |  | 
| 571 |  |  |  |  |  |  | # XXXXX dont know how to find out if I can deliver to this addr from this | 
| 572 |  |  |  |  |  |  | # leg without lookup up route | 
| 573 |  |  |  |  |  |  | # therefore just return true and if you have more than one leg you have | 
| 574 |  |  |  |  |  |  | # to figure out yourself where to send it | 
| 575 | 114 |  |  |  |  | 486 | return 1 | 
| 576 |  |  |  |  |  |  | } | 
| 577 |  |  |  |  |  |  |  | 
| 578 |  |  |  |  |  |  | ########################################################################### | 
| 579 |  |  |  |  |  |  | # check if this leg matches given criteria (used in Dispatcher) | 
| 580 |  |  |  |  |  |  | # Args: ($self,$args) | 
| 581 |  |  |  |  |  |  | #   $args: hash with any of 'addr', 'port', 'proto', 'sub' | 
| 582 |  |  |  |  |  |  | # Returns: true if leg fits all args | 
| 583 |  |  |  |  |  |  | ########################################################################### | 
| 584 |  |  |  |  |  |  | sub match { | 
| 585 | 2 |  |  | 2 | 1 | 2 | my Net::SIP::Leg $self = shift; | 
| 586 | 2 |  |  |  |  | 3 | my $args = shift; | 
| 587 |  |  |  |  |  |  | return if $args->{addr} | 
| 588 |  |  |  |  |  |  | && $args->{addr} ne $self->{src}{addr} | 
| 589 | 2 | 50 | 33 |  |  | 15 | && $args->{addr} ne $self->{src}{host}; | 
|  |  |  | 33 |  |  |  |  | 
| 590 | 0 | 0 | 0 |  |  | 0 | return if $args->{port}  && $args->{port}  != $self->{src}{port}; | 
| 591 | 0 | 0 | 0 |  |  | 0 | return if $args->{proto} && $args->{proto} ne $self->{proto}; | 
| 592 | 0 | 0 | 0 |  |  | 0 | return if $args->{sub}   && !invoke_callback($args->{sub},$self); | 
| 593 | 0 |  |  |  |  | 0 | return 1; | 
| 594 |  |  |  |  |  |  | } | 
| 595 |  |  |  |  |  |  |  | 
| 596 |  |  |  |  |  |  | ########################################################################### | 
| 597 |  |  |  |  |  |  | # returns SocketPool object on Leg | 
| 598 |  |  |  |  |  |  | # Args: $self | 
| 599 |  |  |  |  |  |  | # Returns: $socketpool | 
| 600 |  |  |  |  |  |  | ########################################################################### | 
| 601 |  |  |  |  |  |  | sub socketpool { | 
| 602 | 112 |  |  | 112 | 1 | 292 | my Net::SIP::Leg $self = shift; | 
| 603 | 112 |  |  |  |  | 801 | return $self->{socketpool}; | 
| 604 |  |  |  |  |  |  | } | 
| 605 |  |  |  |  |  |  |  | 
| 606 |  |  |  |  |  |  | ########################################################################### | 
| 607 |  |  |  |  |  |  | # local address of the leg | 
| 608 |  |  |  |  |  |  | # Args: $self;$parts | 
| 609 |  |  |  |  |  |  | #  $parts: number of parts to include | 
| 610 |  |  |  |  |  |  | #     0 -> address only | 
| 611 |  |  |  |  |  |  | #     1 -> address[:non_default_port] | 
| 612 |  |  |  |  |  |  | #     2 -> host[:non_default_port] | 
| 613 |  |  |  |  |  |  | # Returns: string | 
| 614 |  |  |  |  |  |  | ########################################################################### | 
| 615 |  |  |  |  |  |  | sub laddr { | 
| 616 | 57 |  |  | 57 | 1 | 135 | my Net::SIP::Leg $self = shift; | 
| 617 | 57 |  |  |  |  | 121 | my $parts = shift; | 
| 618 | 57 | 100 |  |  |  | 350 | ! $parts and return $self->{src}{addr}; | 
| 619 |  |  |  |  |  |  | return ip_parts2string({ | 
| 620 | 1 |  |  |  |  | 8 | %{ $self->{src} }, | 
| 621 | 1 | 50 |  |  |  | 2 | default_port => $self->{proto} eq 'tls' ? 5061 : 5060, | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 622 |  |  |  |  |  |  | $parts == 1 ? () : | 
| 623 |  |  |  |  |  |  | $parts == 2 ? (use_host => 1) : | 
| 624 |  |  |  |  |  |  | die "invalid parts specification $parts", | 
| 625 |  |  |  |  |  |  | }); | 
| 626 |  |  |  |  |  |  | } | 
| 627 |  |  |  |  |  |  |  | 
| 628 |  |  |  |  |  |  | ########################################################################### | 
| 629 |  |  |  |  |  |  | # some info about the Leg for debugging | 
| 630 |  |  |  |  |  |  | # Args: $self | 
| 631 |  |  |  |  |  |  | # Returns: string | 
| 632 |  |  |  |  |  |  | ########################################################################### | 
| 633 |  |  |  |  |  |  | sub dump { | 
| 634 | 0 |  |  | 0 | 1 | 0 | my Net::SIP::Leg $self = shift; | 
| 635 |  |  |  |  |  |  | return ref($self)." $self->{proto}:" | 
| 636 | 0 |  |  |  |  | 0 | . ip_parts2string($self->{src}); | 
| 637 |  |  |  |  |  |  | } | 
| 638 |  |  |  |  |  |  |  | 
| 639 |  |  |  |  |  |  |  | 
| 640 |  |  |  |  |  |  | ########################################################################### | 
| 641 |  |  |  |  |  |  | # returns key for leg | 
| 642 |  |  |  |  |  |  | # Args: $self | 
| 643 |  |  |  |  |  |  | # Returns: key (string) | 
| 644 |  |  |  |  |  |  | ########################################################################### | 
| 645 |  |  |  |  |  |  | sub key { | 
| 646 | 19 |  |  | 19 | 0 | 21 | my Net::SIP::Leg $self = shift; | 
| 647 |  |  |  |  |  |  | return ref($self).' '.join(':',$self->{proto}, | 
| 648 | 19 |  |  |  |  | 31 | @{$self->{src}}{qw(addr port)}); | 
|  | 19 |  |  |  |  | 67 |  | 
| 649 |  |  |  |  |  |  | } | 
| 650 |  |  |  |  |  |  |  | 
| 651 |  |  |  |  |  |  | 1; |