| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | ######################################################################### | 
| 2 |  |  |  |  |  |  | # Net::SIP::Simple | 
| 3 |  |  |  |  |  |  | # simple methods for creation of UAC,UAS | 
| 4 |  |  |  |  |  |  | # - register    register Address | 
| 5 |  |  |  |  |  |  | # - invite      create new call | 
| 6 |  |  |  |  |  |  | # - listen      UAS, wait for incoming requests | 
| 7 |  |  |  |  |  |  | # - create_registrar - create a simple registrar | 
| 8 |  |  |  |  |  |  | # - create_stateless_proxy - create a simple stateless proxy | 
| 9 |  |  |  |  |  |  | ########################################################################### | 
| 10 |  |  |  |  |  |  |  | 
| 11 | 43 |  |  | 43 |  | 233 | use strict; | 
|  | 43 |  |  |  |  | 69 |  | 
|  | 43 |  |  |  |  | 1040 |  | 
| 12 | 43 |  |  | 43 |  | 166 | use warnings; | 
|  | 43 |  |  |  |  | 65 |  | 
|  | 43 |  |  |  |  | 2134 |  | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | package Net::SIP::Simple; | 
| 15 |  |  |  |  |  |  | use fields ( | 
| 16 | 43 |  |  |  |  | 149 | 'endpoint',           # Net::SIP::Endpoint | 
| 17 |  |  |  |  |  |  | 'dispatcher',         # Net::SIP::Dispatcher | 
| 18 |  |  |  |  |  |  | 'loop',               # Net::SIP::Dispatcher::Eventloop or similar | 
| 19 |  |  |  |  |  |  | 'outgoing_proxy',     # optional outgoing proxy (SIP URL) | 
| 20 |  |  |  |  |  |  | 'route',              # more routes | 
| 21 |  |  |  |  |  |  | 'registrar',          # optional registrar (addr:port) | 
| 22 |  |  |  |  |  |  | 'auth',               # Auth data, see Net::SIP::Endpoint | 
| 23 |  |  |  |  |  |  | 'from',               # SIP address of caller | 
| 24 |  |  |  |  |  |  | 'contact',            # optional local contact address | 
| 25 |  |  |  |  |  |  | 'domain',             # default domain for SIP addresses | 
| 26 |  |  |  |  |  |  | 'last_error',         # last error | 
| 27 |  |  |  |  |  |  | 'options',            # hash with field,values for response to OPTIONS request | 
| 28 |  |  |  |  |  |  | 'ua_cleanup',         # cleanup callbacks | 
| 29 | 43 |  |  | 43 |  | 16960 | ); | 
|  | 43 |  |  |  |  | 58536 |  | 
| 30 |  |  |  |  |  |  |  | 
| 31 | 43 |  |  | 43 |  | 5075 | use Carp qw(croak); | 
|  | 43 |  |  |  |  | 73 |  | 
|  | 43 |  |  |  |  | 1776 |  | 
| 32 | 43 |  |  | 43 |  | 19028 | use Net::SIP::Dispatcher; | 
|  | 43 |  |  |  |  | 125 |  | 
|  | 43 |  |  |  |  | 1244 |  | 
| 33 | 43 |  |  | 43 |  | 253 | use Net::SIP::Dispatcher::Eventloop; | 
|  | 43 |  |  |  |  | 88 |  | 
|  | 43 |  |  |  |  | 1870 |  | 
| 34 | 43 |  |  | 43 |  | 18530 | use Net::SIP::Endpoint; | 
|  | 43 |  |  |  |  | 114 |  | 
|  | 43 |  |  |  |  | 1161 |  | 
| 35 | 43 |  |  | 43 |  | 15780 | use Net::SIP::Redirect; | 
|  | 43 |  |  |  |  | 101 |  | 
|  | 43 |  |  |  |  | 1058 |  | 
| 36 | 43 |  |  | 43 |  | 14809 | use Net::SIP::Registrar; | 
|  | 43 |  |  |  |  | 101 |  | 
|  | 43 |  |  |  |  | 1149 |  | 
| 37 | 43 |  |  | 43 |  | 18437 | use Net::SIP::StatelessProxy; | 
|  | 43 |  |  |  |  | 106 |  | 
|  | 43 |  |  |  |  | 1203 |  | 
| 38 | 43 |  |  | 43 |  | 15455 | use Net::SIP::Authorize; | 
|  | 43 |  |  |  |  | 107 |  | 
|  | 43 |  |  |  |  | 1133 |  | 
| 39 | 43 |  |  | 43 |  | 14146 | use Net::SIP::ReceiveChain; | 
|  | 43 |  |  |  |  | 103 |  | 
|  | 43 |  |  |  |  | 1013 |  | 
| 40 | 43 |  |  | 43 |  | 243 | use Net::SIP::Leg; | 
|  | 43 |  |  |  |  | 68 |  | 
|  | 43 |  |  |  |  | 748 |  | 
| 41 |  |  |  |  |  |  | # crossref, because its derived from Net::SIP::Simple | 
| 42 |  |  |  |  |  |  | # now load in Net::SIP | 
| 43 |  |  |  |  |  |  | # use Net::SIP::Simple::Call; | 
| 44 | 43 |  |  | 43 |  | 16260 | use Net::SIP::Simple::RTP; | 
|  | 43 |  |  |  |  | 142 |  | 
|  | 43 |  |  |  |  | 1241 |  | 
| 45 | 43 |  |  | 43 |  | 267 | use Net::SIP::Util qw( :all ); | 
|  | 43 |  |  |  |  | 75 |  | 
|  | 43 |  |  |  |  | 6701 |  | 
| 46 | 43 |  |  | 43 |  | 257 | use List::Util 'first'; | 
|  | 43 |  |  |  |  | 78 |  | 
|  | 43 |  |  |  |  | 2012 |  | 
| 47 | 43 |  |  | 43 |  | 223 | use Net::SIP::Debug; | 
|  | 43 |  |  |  |  | 70 |  | 
|  | 43 |  |  |  |  | 177 |  | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | ########################################################################### | 
| 50 |  |  |  |  |  |  | # create UA | 
| 51 |  |  |  |  |  |  | # Args: ($class;%args) | 
| 52 |  |  |  |  |  |  | #   %args: misc args, all args are optional | 
| 53 |  |  |  |  |  |  | #     legs|leg       - \@list of legs or single leg. | 
| 54 |  |  |  |  |  |  | #                      leg can be (derived from) Net::SIP::Leg, a IO::Handle (socket), | 
| 55 |  |  |  |  |  |  | #                      a hash reference for constructing Net::SIP::Leg or a string | 
| 56 |  |  |  |  |  |  | #                      with a SIP address (i.e. sip:ip:port;transport=TCP) | 
| 57 |  |  |  |  |  |  | #     tls            - common TLS settings used when creating a leg | 
| 58 |  |  |  |  |  |  | #     outgoing_proxy - specify outgoing proxy, will create leg if necessary | 
| 59 |  |  |  |  |  |  | #     proxy          - alias to outgoing_proxy | 
| 60 |  |  |  |  |  |  | #     route|routes   - \@list with SIP routes in right syntax ""... | 
| 61 |  |  |  |  |  |  | #     registrar      - use registrar for registration | 
| 62 |  |  |  |  |  |  | #     auth           - auth data: see Request->authorize for format | 
| 63 |  |  |  |  |  |  | #     from           - myself, used for calls and registration | 
| 64 |  |  |  |  |  |  | #     contact        - optional local contact address | 
| 65 |  |  |  |  |  |  | #     options        - hash with fields,values for reply to OPTIONS request | 
| 66 |  |  |  |  |  |  | #     loop           - predefined Net::SIP::Dispatcher::Eventloop, used if | 
| 67 |  |  |  |  |  |  | #                      shared between UAs | 
| 68 |  |  |  |  |  |  | #     dispatcher     - predefined Net::SIP::Dispatcher, used if | 
| 69 |  |  |  |  |  |  | #                      shared between UAs | 
| 70 |  |  |  |  |  |  | #     domain         - domain used if from/to.. do not contain domain | 
| 71 |  |  |  |  |  |  | #     domain2proxy   - hash of { domain => proxy } | 
| 72 |  |  |  |  |  |  | #                      used to find proxy for domain. If nothing matches here | 
| 73 |  |  |  |  |  |  | #                      DNS need to be used. Special domain '*' catches all | 
| 74 |  |  |  |  |  |  | #     d2p            - alias for domain2proxy | 
| 75 |  |  |  |  |  |  | # Returns: $self | 
| 76 |  |  |  |  |  |  | # Comment: | 
| 77 |  |  |  |  |  |  | # FIXME | 
| 78 |  |  |  |  |  |  | # If more than one leg is given (e.g. legs+outgoing_proxy) than you have | 
| 79 |  |  |  |  |  |  | # to provide a function to find out, which leg is used to send out a request | 
| 80 |  |  |  |  |  |  | ########################################################################### | 
| 81 |  |  |  |  |  |  | sub new { | 
| 82 | 54 |  |  | 54 | 1 | 1121 | my ($class,%args) = @_; | 
| 83 | 54 |  |  |  |  | 247 | my $auth = delete $args{auth}; | 
| 84 | 54 |  |  |  |  | 134 | my $registrar = delete $args{registrar}; | 
| 85 | 54 |  |  |  |  | 136 | my $tls = delete $args{tls}; | 
| 86 |  |  |  |  |  |  |  | 
| 87 | 54 |  |  |  |  | 251 | my $ua_cleanup = []; | 
| 88 | 54 |  |  |  |  | 281 | my $self = fields::new( $class ); | 
| 89 |  |  |  |  |  |  |  | 
| 90 | 54 |  | 50 |  |  | 8969 | my $options = delete $args{options} || {}; | 
| 91 |  |  |  |  |  |  | { | 
| 92 | 54 |  |  |  |  | 150 | @{$options}{ map { lc } keys(%$options) } = values(%$options); # lc keys | 
|  | 54 |  |  |  |  | 192 |  | 
|  | 54 |  |  |  |  | 149 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 93 | 54 |  |  |  |  | 1538 | my %default_options = ( | 
| 94 |  |  |  |  |  |  | allow => 'INVITE, ACK, CANCEL, OPTIONS, BYE', | 
| 95 |  |  |  |  |  |  | accept => 'application/sdp', | 
| 96 |  |  |  |  |  |  | 'accept-encoding' => '', | 
| 97 |  |  |  |  |  |  | 'accept-language' => 'en', | 
| 98 |  |  |  |  |  |  | supported => '', | 
| 99 |  |  |  |  |  |  | ); | 
| 100 | 54 |  |  |  |  | 430 | while ( my ($k,$v) = each %default_options ) { | 
| 101 | 270 | 50 |  |  |  | 1147 | $options->{$k} = $v if ! defined $options->{$k}; | 
| 102 |  |  |  |  |  |  | } | 
| 103 |  |  |  |  |  |  | } | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 54 |  |  |  |  | 123 | my $disp = delete $args{dispatcher}; | 
| 106 |  |  |  |  |  |  | my $loop = $disp && $disp->loop | 
| 107 |  |  |  |  |  |  | || delete $args{loop} | 
| 108 | 54 |  | 33 |  |  | 2551 | || Net::SIP::Dispatcher::Eventloop->new; | 
| 109 | 54 |  | 33 |  |  | 287 | my $proxy = delete $args{outgoing_proxy} || delete $args{proxy}; | 
| 110 | 54 |  | 66 |  |  | 413 | my $d2p   = delete $args{domain2proxy}   || delete $args{d2p}; | 
| 111 | 54 |  | 33 |  |  | 2439 | $disp ||= Net::SIP::Dispatcher->new( | 
| 112 |  |  |  |  |  |  | [], | 
| 113 |  |  |  |  |  |  | $loop, | 
| 114 |  |  |  |  |  |  | domain2proxy => $d2p, | 
| 115 |  |  |  |  |  |  | ); | 
| 116 |  |  |  |  |  |  |  | 
| 117 | 54 |  | 66 |  |  | 1232 | my $legs = delete $args{legs} || delete $args{leg}; | 
| 118 | 54 | 100 | 66 |  |  | 674 | $legs = [ $legs ] if $legs && ref($legs) ne 'ARRAY'; | 
| 119 | 54 |  | 50 |  |  | 230 | $legs ||= []; | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | my $host2ip = sub { | 
| 122 | 0 |  |  | 0 |  | 0 | my $host = shift; | 
| 123 | 0 |  |  |  |  | 0 | my $ip; | 
| 124 | 0 |  | 0 |  |  | 0 | $disp->dns_host2ip($host,sub { $ip = shift // \0 }); | 
|  | 0 |  |  |  |  | 0 |  | 
| 125 | 0 |  |  |  |  | 0 | $loop->loop(15,\$ip); | 
| 126 | 0 | 0 | 0 |  |  | 0 | die "failed to resolve $host".($ip ? '':' - timed out') | 
|  |  | 0 |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | if ! defined $ip || ref($ip); | 
| 128 | 0 |  |  |  |  | 0 | return ($ip,ip_is_v46($ip)); | 
| 129 | 54 |  |  |  |  | 904 | }; | 
| 130 |  |  |  |  |  |  |  | 
| 131 | 54 | 50 |  |  |  | 338 | foreach ($legs ? @$legs : ()) { | 
| 132 | 54 | 100 |  |  |  | 1520 | if ( UNIVERSAL::isa( $_, 'Net::SIP::Leg' )) { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | # keep | 
| 134 |  |  |  |  |  |  | } elsif ( UNIVERSAL::isa( $_, 'IO::Handle' )) { | 
| 135 |  |  |  |  |  |  | # socket | 
| 136 | 2 |  |  |  |  | 24 | $_ = Net::SIP::Leg->new( | 
| 137 |  |  |  |  |  |  | sock => $_, | 
| 138 |  |  |  |  |  |  | tls => $tls | 
| 139 |  |  |  |  |  |  | ) | 
| 140 |  |  |  |  |  |  | } elsif ( UNIVERSAL::isa( $_, 'HASH' )) { | 
| 141 |  |  |  |  |  |  | # create leg from hash | 
| 142 | 0 |  |  |  |  | 0 | $_ = Net::SIP::Leg->new(tls => $tls, %$_) | 
| 143 |  |  |  |  |  |  | } elsif (my ($proto,$host,$port,$family) = sip_uri2sockinfo($_)) { | 
| 144 | 0 | 0 |  |  |  | 0 | (my $addr,$family) = $family ? ($host,$family) : $host2ip->($host); | 
| 145 | 0 |  |  |  |  | 0 | $_ = Net::SIP::Leg->new( | 
| 146 |  |  |  |  |  |  | proto  => $proto, | 
| 147 |  |  |  |  |  |  | tls    => $tls, | 
| 148 |  |  |  |  |  |  | host   => $host, | 
| 149 |  |  |  |  |  |  | addr   => $addr, | 
| 150 |  |  |  |  |  |  | port   => $port, | 
| 151 |  |  |  |  |  |  | family => $family | 
| 152 |  |  |  |  |  |  | ); | 
| 153 |  |  |  |  |  |  | } else { | 
| 154 | 0 |  |  |  |  | 0 | die "invalid leg specification: $_"; | 
| 155 |  |  |  |  |  |  | } | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  |  | 
| 158 | 54 |  |  |  |  | 381 | for my $dst ($registrar, $proxy) { | 
| 159 | 108 | 50 |  |  |  | 312 | $dst or next; | 
| 160 | 0 | 0 |  | 0 |  | 0 | first { $_->can_deliver_to($dst) } @$legs and next; | 
|  | 0 |  |  |  |  | 0 |  | 
| 161 | 0 |  |  |  |  | 0 | my ($proto,$host,$port,$family) = sip_uri2sockinfo($dst); | 
| 162 | 0 | 0 |  |  |  | 0 | (my $addr,$family) = $family ? ($host,$family) : $host2ip->($host); | 
| 163 | 0 |  |  |  |  | 0 | push @$legs, Net::SIP::Leg->new( | 
| 164 |  |  |  |  |  |  | proto  => $proto, | 
| 165 |  |  |  |  |  |  | tls    => $tls, | 
| 166 |  |  |  |  |  |  | dst    => { | 
| 167 |  |  |  |  |  |  | host   => $host, | 
| 168 |  |  |  |  |  |  | addr   => $addr, | 
| 169 |  |  |  |  |  |  | port   => $port, | 
| 170 |  |  |  |  |  |  | family => $family, | 
| 171 |  |  |  |  |  |  | } | 
| 172 |  |  |  |  |  |  | ); | 
| 173 |  |  |  |  |  |  | } | 
| 174 |  |  |  |  |  |  |  | 
| 175 | 54 | 50 |  |  |  | 374 | $disp->add_leg(@$legs) if @$legs; | 
| 176 | 54 | 50 |  |  |  | 894 | $disp->outgoing_proxy($proxy) if $proxy; | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | push @$ua_cleanup, [ | 
| 179 |  |  |  |  |  |  | sub { | 
| 180 | 53 |  |  | 53 |  | 130 | my ($self,$legs) = @_; | 
| 181 | 53 |  |  |  |  | 545 | $self->{dispatcher}->remove_leg(@$legs); | 
| 182 |  |  |  |  |  |  | }, | 
| 183 | 54 | 50 |  |  |  | 907 | $self,$legs | 
| 184 |  |  |  |  |  |  | ] if @$legs; | 
| 185 |  |  |  |  |  |  |  | 
| 186 | 54 |  |  |  |  | 1412 | my $endpoint = Net::SIP::Endpoint->new( $disp ); | 
| 187 |  |  |  |  |  |  |  | 
| 188 | 54 |  | 33 |  |  | 572 | my $routes = delete $args{routes} || delete $args{route}; | 
| 189 | 54 |  |  |  |  | 167 | my $from = delete $args{from}; | 
| 190 | 54 |  |  |  |  | 97 | my $contact = delete $args{contact}; | 
| 191 | 54 |  |  |  |  | 370 | my $domain = delete $args{domain}; | 
| 192 |  |  |  |  |  |  |  | 
| 193 | 54 | 100 |  |  |  | 174 | if ($from) { | 
| 194 | 38 | 100 | 66 |  |  | 761 | if (!defined($domain) && $from =~m{\bsips?:[^@]+\@([\w\-\.]+)}) { | 
| 195 | 4 |  |  |  |  | 18 | $domain = $1; | 
| 196 |  |  |  |  |  |  | } | 
| 197 | 38 | 50 | 33 |  |  | 829 | if ($from !~m{\s} && $from !~m{\@}) { | 
| 198 | 0 | 0 |  |  |  | 0 | my $sip_proto = $disp->get_legs(proto => 'tls') ? 'sips' : 'sip'; | 
| 199 | 0 |  |  |  |  | 0 | $from = "$from <$sip_proto:$from\@$domain>"; | 
| 200 |  |  |  |  |  |  | } | 
| 201 |  |  |  |  |  |  | } | 
| 202 |  |  |  |  |  |  |  | 
| 203 | 54 | 50 |  |  |  | 181 | die "unhandled arguments: ".join(", ", keys %args) if %args; | 
| 204 |  |  |  |  |  |  |  | 
| 205 | 54 |  |  |  |  | 487 | %$self = ( | 
| 206 |  |  |  |  |  |  | auth => $auth, | 
| 207 |  |  |  |  |  |  | from => $from, | 
| 208 |  |  |  |  |  |  | contact => $contact, | 
| 209 |  |  |  |  |  |  | domain => $domain, | 
| 210 |  |  |  |  |  |  | endpoint => $endpoint, | 
| 211 |  |  |  |  |  |  | registrar => $registrar, | 
| 212 |  |  |  |  |  |  | dispatcher => $disp, | 
| 213 |  |  |  |  |  |  | loop => $loop, | 
| 214 |  |  |  |  |  |  | route => $routes, | 
| 215 |  |  |  |  |  |  | options => $options, | 
| 216 |  |  |  |  |  |  | ua_cleanup => $ua_cleanup, | 
| 217 |  |  |  |  |  |  | ); | 
| 218 | 54 |  |  |  |  | 599 | return $self; | 
| 219 |  |  |  |  |  |  | } | 
| 220 |  |  |  |  |  |  |  | 
| 221 |  |  |  |  |  |  | ########################################################################### | 
| 222 |  |  |  |  |  |  | # cleanup object, e.g. remove legs it added to dispatcher | 
| 223 |  |  |  |  |  |  | # Args: ($self) | 
| 224 |  |  |  |  |  |  | # Returns: NONE | 
| 225 |  |  |  |  |  |  | ########################################################################### | 
| 226 |  |  |  |  |  |  | sub cleanup { | 
| 227 | 53 |  |  | 53 | 1 | 13114 | my Net::SIP::Simple $self = shift; | 
| 228 | 53 |  |  |  |  | 121 | while ( my $cb = shift @{ $self->{ua_cleanup} } ) { | 
|  | 106 |  |  |  |  | 2174 |  | 
| 229 | 53 |  |  |  |  | 243 | invoke_callback($cb,$self) | 
| 230 |  |  |  |  |  |  | } | 
| 231 | 53 |  |  |  |  | 3048 | %$self = (); | 
| 232 |  |  |  |  |  |  | } | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | ########################################################################### | 
| 235 |  |  |  |  |  |  | # get last error or set it | 
| 236 |  |  |  |  |  |  | # Args: ($self;$err) | 
| 237 |  |  |  |  |  |  | #  $err: if given will set error | 
| 238 |  |  |  |  |  |  | # Returns: $last_error | 
| 239 |  |  |  |  |  |  | ########################################################################### | 
| 240 |  |  |  |  |  |  | sub error { | 
| 241 | 21 |  |  | 21 | 1 | 2963 | my Net::SIP::Simple $self = shift; | 
| 242 | 21 | 100 |  |  |  | 82 | if ( @_ ) { | 
| 243 | 1 |  |  |  |  | 3 | $self->{last_error} = shift; | 
| 244 |  |  |  |  |  |  | $DEBUG && DEBUG(100,Net::SIP::Debug::stacktrace( | 
| 245 | 1 | 50 |  |  |  | 3 | "set error to ".$self->{last_error}) ); | 
| 246 |  |  |  |  |  |  | } | 
| 247 | 21 |  |  |  |  | 114 | return $self->{last_error}; | 
| 248 |  |  |  |  |  |  | } | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  |  | 
| 251 |  |  |  |  |  |  | ########################################################################### | 
| 252 |  |  |  |  |  |  | # mainloop | 
| 253 |  |  |  |  |  |  | # Args: (;$timeout,@stopvar) | 
| 254 |  |  |  |  |  |  | #  $timeout: timeout, undef for no timeout. argument can be omitted | 
| 255 |  |  |  |  |  |  | #  @stopvar: @array of Scalar-REF, loop stops if one scalar is true | 
| 256 |  |  |  |  |  |  | # Returns: NONE | 
| 257 |  |  |  |  |  |  | ########################################################################### | 
| 258 |  |  |  |  |  |  | sub loop { | 
| 259 | 140 |  |  | 140 | 1 | 4757 | my Net::SIP::Simple $self = shift; | 
| 260 | 140 |  |  |  |  | 375 | my ($timeout,@stopvar); | 
| 261 | 140 |  |  |  |  | 457 | foreach (@_) { | 
| 262 | 218 | 100 |  |  |  | 893 | if ( ref($_) ) { | 
|  |  | 50 |  |  |  |  |  | 
| 263 | 123 |  |  |  |  | 406 | push @stopvar,$_ | 
| 264 |  |  |  |  |  |  | } elsif ( defined($_)) { | 
| 265 | 95 |  |  |  |  | 249 | $timeout = $_ | 
| 266 |  |  |  |  |  |  | } | 
| 267 |  |  |  |  |  |  | } | 
| 268 | 140 |  |  |  |  | 837 | return $self->{loop}->loop( $timeout,@stopvar ); | 
| 269 |  |  |  |  |  |  | } | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | ########################################################################### | 
| 272 |  |  |  |  |  |  | # add timer | 
| 273 |  |  |  |  |  |  | # propagates to add_timer of wNet::SIP::Dispatcher, see there for detailed | 
| 274 |  |  |  |  |  |  | # explanation of args | 
| 275 |  |  |  |  |  |  | # Args: ($self,$when,$cb,$repeat) | 
| 276 |  |  |  |  |  |  | # Returns: $timer | 
| 277 |  |  |  |  |  |  | ########################################################################### | 
| 278 |  |  |  |  |  |  | sub add_timer { | 
| 279 | 0 |  |  | 0 | 1 | 0 | my Net::SIP::Simple $self = shift; | 
| 280 | 0 |  |  |  |  | 0 | $self->{dispatcher}->add_timer( @_ ); | 
| 281 |  |  |  |  |  |  | } | 
| 282 |  |  |  |  |  |  |  | 
| 283 |  |  |  |  |  |  | ########################################################################### | 
| 284 |  |  |  |  |  |  | # control RTP behavior | 
| 285 |  |  |  |  |  |  | # Args: ($self,$method,@arg) | 
| 286 |  |  |  |  |  |  | #  $method: Method name for behavior, e.g. calls Net::SIP::Simple::RTP::$method | 
| 287 |  |  |  |  |  |  | #  @arg: Arguments for method | 
| 288 |  |  |  |  |  |  | # Returns: $cb | 
| 289 |  |  |  |  |  |  | #  $cb: callback structure | 
| 290 |  |  |  |  |  |  | ########################################################################### | 
| 291 |  |  |  |  |  |  | sub rtp { | 
| 292 | 73 |  |  | 73 | 1 | 7673 | my Net::SIP::Simple $self = shift; | 
| 293 | 73 |  |  |  |  | 287 | my ($method,@arg) = @_; | 
| 294 | 73 |  | 33 |  |  | 2067 | my $sub = UNIVERSAL::can( 'Net::SIP::Simple::RTP',$method ) | 
| 295 |  |  |  |  |  |  | || UNIVERSAL::can( 'Net::SIP::Simple::RTP','media_'.$method ) | 
| 296 |  |  |  |  |  |  | || croak( "no such method '$method' in Net::SIP::Simple::RTP" ); | 
| 297 | 73 |  |  |  |  | 745 | return $sub->( @arg ); | 
| 298 |  |  |  |  |  |  | } | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  |  | 
| 301 |  |  |  |  |  |  | ########################################################################### | 
| 302 |  |  |  |  |  |  | # Register UA at registrar | 
| 303 |  |  |  |  |  |  | # waits until final response is received | 
| 304 |  |  |  |  |  |  | # Args: ($self,%args) | 
| 305 |  |  |  |  |  |  | #  %args: Hash with keys.. | 
| 306 |  |  |  |  |  |  | #    registrar: Register there, default $self->{registrar} | 
| 307 |  |  |  |  |  |  | #    from:      use 'from' as lokal address, default $self->{from} | 
| 308 |  |  |  |  |  |  | #    leg:       use given Net::SIP::Leg object for registration, default first leg | 
| 309 |  |  |  |  |  |  | #    cb_final:  user defined callback when final response is received | 
| 310 |  |  |  |  |  |  | #    more args (expire...) will be forwarded to Net::SIP::Endpoint::register | 
| 311 |  |  |  |  |  |  | # Returns: expires | 
| 312 |  |  |  |  |  |  | #   if user defined callback or failed expires will be undef | 
| 313 |  |  |  |  |  |  | #   otherwise it will be the expires value from the registrars response | 
| 314 |  |  |  |  |  |  | ########################################################################### | 
| 315 |  |  |  |  |  |  | sub register { | 
| 316 | 0 |  |  | 0 | 1 | 0 | my Net::SIP::Simple $self = shift; | 
| 317 | 0 |  |  |  |  | 0 | my %args = @_; | 
| 318 |  |  |  |  |  |  |  | 
| 319 |  |  |  |  |  |  | my $registrar = delete $args{registrar} || $self->{registrar} | 
| 320 | 0 |  | 0 |  |  | 0 | || croak( "no registrar" ); | 
| 321 | 0 |  |  |  |  | 0 | $registrar = sip_parts2uri(sip_uri2parts($registrar)); # normalize | 
| 322 | 0 |  |  |  |  | 0 | my $leg = delete $args{leg}; | 
| 323 | 0 | 0 |  |  |  | 0 | if ( !$leg ) { | 
| 324 |  |  |  |  |  |  | # use first leg which can deliver to registrar | 
| 325 |  |  |  |  |  |  | ($leg) = $self->{dispatcher}->get_legs( sub => [ | 
| 326 |  |  |  |  |  |  | sub { | 
| 327 | 0 |  |  | 0 |  | 0 | my ($addr,$leg) = @_; | 
| 328 | 0 |  |  |  |  | 0 | return $leg->can_deliver_to($addr); | 
| 329 |  |  |  |  |  |  | }, | 
| 330 | 0 |  |  |  |  | 0 | $registrar | 
| 331 |  |  |  |  |  |  | ]); | 
| 332 |  |  |  |  |  |  | } | 
| 333 |  |  |  |  |  |  |  | 
| 334 |  |  |  |  |  |  | my $from = delete $args{from} || $self->{from} | 
| 335 | 0 |  | 0 |  |  | 0 | || croak( "unknown from" ); | 
| 336 |  |  |  |  |  |  |  | 
| 337 | 0 |  | 0 |  |  | 0 | my $contact = delete $args{contact} || $self->{contact}; | 
| 338 | 0 | 0 |  |  |  | 0 | if ( ! $contact) { | 
| 339 | 0 |  |  |  |  | 0 | $contact = $from; | 
| 340 | 0 |  |  |  |  | 0 | my $local = $leg->laddr(2); | 
| 341 | 0 | 0 |  |  |  | 0 | $contact.= '@'.$local unless $contact =~s{\@([^\s;,>]+)}{\@$local}; | 
| 342 |  |  |  |  |  |  | } | 
| 343 |  |  |  |  |  |  |  | 
| 344 |  |  |  |  |  |  | my %rarg = ( | 
| 345 |  |  |  |  |  |  | from => $from, | 
| 346 |  |  |  |  |  |  | registrar => $registrar, | 
| 347 |  |  |  |  |  |  | contact => $contact, | 
| 348 |  |  |  |  |  |  | auth => delete $args{auth} || $self->{auth}, | 
| 349 | 0 |  | 0 |  |  | 0 | ); | 
| 350 | 0 | 0 |  |  |  | 0 | %rarg = ( %rarg, %args ) if %args; | 
| 351 |  |  |  |  |  |  |  | 
| 352 | 0 |  |  |  |  | 0 | my $cb_final = delete $rarg{cb_final}; | 
| 353 | 0 |  |  |  |  | 0 | my $stopvar = 0; | 
| 354 | 0 |  | 0 |  |  | 0 | $cb_final ||= \$stopvar; | 
| 355 |  |  |  |  |  |  |  | 
| 356 |  |  |  |  |  |  | my $cb = sub { | 
| 357 | 0 |  |  | 0 |  | 0 | my ($self,$cb_final,$expires,$endpoint,$ctx,$errno,$code,$packet,$leg,$from) = @_; | 
| 358 | 0 | 0 | 0 |  |  | 0 | if ( $code && $code =~m{^2\d\d} ) { | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 359 |  |  |  |  |  |  | # use expires info on contact | 
| 360 |  |  |  |  |  |  | # if none given use global expires header | 
| 361 |  |  |  |  |  |  | # see rfc3261 10.3.8,10.2.4 | 
| 362 | 0 |  |  |  |  | 0 | my $exp; | 
| 363 | 0 |  |  |  |  | 0 | for my $c ( $packet->get_header( 'contact' ) ) { | 
| 364 | 0 |  |  |  |  | 0 | my ($addr,$p) = sip_hdrval2parts( contact => $c ); | 
| 365 | 0 | 0 |  |  |  | 0 | defined( my $e = $p->{expires} ) or next; | 
| 366 | 0 | 0 |  |  |  | 0 | sip_uri_eq($addr,$contact) or next; # not me | 
| 367 | 0 | 0 | 0 |  |  | 0 | $exp = $e if ! defined($exp) || $e < $exp; | 
| 368 |  |  |  |  |  |  | } | 
| 369 | 0 | 0 |  |  |  | 0 | $exp = $packet->get_header( 'Expires' ) if ! defined $exp; | 
| 370 | 0 |  |  |  |  | 0 | $$expires = $exp; | 
| 371 | 0 |  |  |  |  | 0 | invoke_callback( $cb_final, 'OK', expires => $exp, packet => $packet ); | 
| 372 |  |  |  |  |  |  |  | 
| 373 |  |  |  |  |  |  | } elsif ( $code ) { | 
| 374 | 0 |  |  |  |  | 0 | $self->error( "Failed with code $code" ); | 
| 375 | 0 |  |  |  |  | 0 | invoke_callback( $cb_final, 'FAIL', code => $code, packet => $packet ); | 
| 376 |  |  |  |  |  |  | } elsif ( $errno ) { | 
| 377 | 0 |  |  |  |  | 0 | $self->error( "Failed with error $errno" ); | 
| 378 | 0 |  |  |  |  | 0 | invoke_callback( $cb_final, 'FAIL', errno => $errno ); | 
| 379 |  |  |  |  |  |  | } else { | 
| 380 | 0 |  |  |  |  | 0 | $self->error( "Unknown failure" ); | 
| 381 | 0 |  |  |  |  | 0 | invoke_callback( $cb_final, 'FAIL' ); | 
| 382 |  |  |  |  |  |  | } | 
| 383 | 0 |  |  |  |  | 0 | }; | 
| 384 |  |  |  |  |  |  |  | 
| 385 | 0 |  |  |  |  | 0 | my $expires; | 
| 386 | 0 |  |  |  |  | 0 | $self->{endpoint}->register( %rarg, callback => [ $cb,$self,$cb_final,\$expires ] ); | 
| 387 |  |  |  |  |  |  |  | 
| 388 |  |  |  |  |  |  | # if cb_final is local stopvar wait until it got set | 
| 389 | 0 | 0 |  |  |  | 0 | if ( \$stopvar == $cb_final ) { | 
| 390 | 0 |  |  |  |  | 0 | $self->loop( \$stopvar ); | 
| 391 | 0 | 0 |  |  |  | 0 | return $stopvar eq 'OK' ? $expires: undef; | 
| 392 |  |  |  |  |  |  | } | 
| 393 |  |  |  |  |  |  | } | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | ########################################################################### | 
| 396 |  |  |  |  |  |  | # create new call | 
| 397 |  |  |  |  |  |  | # and waits until the INVITE is completed (e.g final response received) | 
| 398 |  |  |  |  |  |  | # Args: ($self,$ctx;%args) | 
| 399 |  |  |  |  |  |  | #   $ctx: \%ctx context describing the call or sip address of peer | 
| 400 |  |  |  |  |  |  | #   %args: see Net::SIP::Simple::Call::invite | 
| 401 |  |  |  |  |  |  | # Returns: $call | 
| 402 |  |  |  |  |  |  | #   $call: Net::SIP::Simple::Call | 
| 403 |  |  |  |  |  |  | ########################################################################### | 
| 404 |  |  |  |  |  |  | sub invite { | 
| 405 | 35 |  |  | 35 | 1 | 11077 | my Net::SIP::Simple $self = shift; | 
| 406 | 35 |  |  |  |  | 357 | my ($ctx,%args) = @_; | 
| 407 | 35 | 50 |  |  |  | 180 | (my $to,$ctx) = ref($ctx) ? ($ctx->{to},$ctx) : ($ctx,undef); | 
| 408 | 35 | 50 |  |  |  | 140 | $to || croak( "need peer of call" ); | 
| 409 | 35 | 50 | 33 |  |  | 748 | if ( $to !~m{\s} && $to !~m{\@} ) {; | 
| 410 | 0 | 0 |  |  |  | 0 | croak( "no domain and no fully qualified to" ) if ! $self->{domain}; | 
| 411 | 0 | 0 |  |  |  | 0 | my $sip_proto = $self->{dispatcher}->get_legs(proto => 'tls') | 
| 412 |  |  |  |  |  |  | ? 'sips' : 'sip'; | 
| 413 | 0 |  |  |  |  | 0 | $to = "$to <$sip_proto:$to\@$self->{domain}>"; | 
| 414 | 0 | 0 |  |  |  | 0 | $ctx->{to} = $to if $ctx; | 
| 415 |  |  |  |  |  |  | } | 
| 416 | 35 |  | 33 |  |  | 1380 | my $call = Net::SIP::Simple::Call->new( $self,$ctx||$to ); | 
| 417 | 35 |  |  |  |  | 404 | $call->reinvite(%args); | 
| 418 | 35 |  |  |  |  | 178 | return $call; | 
| 419 |  |  |  |  |  |  | } | 
| 420 |  |  |  |  |  |  |  | 
| 421 |  |  |  |  |  |  | ########################################################################### | 
| 422 |  |  |  |  |  |  | # listen for and accept new calls | 
| 423 |  |  |  |  |  |  | # Args: ($self,%args) | 
| 424 |  |  |  |  |  |  | #  %args: | 
| 425 |  |  |  |  |  |  | #    filter: optional sub or regex to filter which incoming calls gets accepted | 
| 426 |  |  |  |  |  |  | #      if not given all calls will be accepted | 
| 427 |  |  |  |  |  |  | #      if regex only from matching regex gets accepted | 
| 428 |  |  |  |  |  |  | #      if sub and sub returns 1 call gets accepted, if sub returns 0 it gets rejected | 
| 429 |  |  |  |  |  |  | #    cb_create: optional callback called on creation of newly created | 
| 430 |  |  |  |  |  |  | #      Net::SIP::Simple::Call. If returns false the call will be closed. | 
| 431 |  |  |  |  |  |  | #      If returns a callback (e.g some ref) it will be used instead of | 
| 432 |  |  |  |  |  |  | #      Net::SIP::Simple::Call to handle the data | 
| 433 |  |  |  |  |  |  | #    cb_established: callback called after receiving ACK | 
| 434 |  |  |  |  |  |  | #    cb_cleanup: called on destroy of call object | 
| 435 |  |  |  |  |  |  | #    auth_whatever: will require authorization, see whatever in Net::SIP::Authorize | 
| 436 |  |  |  |  |  |  | #    for all other args see Net::SIP::Simple::Call.... | 
| 437 |  |  |  |  |  |  | # Returns: NONE | 
| 438 |  |  |  |  |  |  | ########################################################################### | 
| 439 |  |  |  |  |  |  | sub listen { | 
| 440 | 18 |  |  | 18 | 1 | 210 | my Net::SIP::Simple $self = shift; | 
| 441 | 18 |  |  |  |  | 473 | my %args = @_; | 
| 442 | 18 |  |  |  |  | 165 | my $cb_create = delete $args{cb_create}; | 
| 443 |  |  |  |  |  |  |  | 
| 444 |  |  |  |  |  |  | # handle new requests | 
| 445 |  |  |  |  |  |  | my $receive = sub { | 
| 446 | 18 |  |  | 18 |  | 70 | my ($self,$args,$endpoint,$ctx,$request,$leg,$from) = @_; | 
| 447 | 18 |  |  |  |  | 88 | my $method = $request->method; | 
| 448 | 18 | 50 |  |  |  | 257 | if ( $method eq 'OPTIONS' ) { | 
|  |  | 50 |  |  |  |  |  | 
| 449 | 0 |  |  |  |  | 0 | my $response = $request->create_response( '200','OK',$self->{options} ); | 
| 450 | 0 |  |  |  |  | 0 | $self->{endpoint}->new_response( $ctx,$response,$leg,$from ); | 
| 451 | 0 |  |  |  |  | 0 | $self->{endpoint}->close_context( $ctx ); | 
| 452 | 0 |  |  |  |  | 0 | return; | 
| 453 |  |  |  |  |  |  | } elsif ( $method ne 'INVITE' ) { | 
| 454 | 0 |  |  |  |  | 0 | DEBUG( 10,"drop non-INVITE request: ".$request->dump ); | 
| 455 | 0 |  |  |  |  | 0 | $self->{endpoint}->close_context( $ctx ); | 
| 456 | 0 |  |  |  |  | 0 | return; | 
| 457 |  |  |  |  |  |  | } | 
| 458 |  |  |  |  |  |  |  | 
| 459 | 18 | 50 |  |  |  | 124 | if ( my $filter = $args->{filter} ) { | 
| 460 | 0 |  |  |  |  | 0 | my $rv = invoke_callback( $filter, $ctx->{from},$request ); | 
| 461 | 0 | 0 |  |  |  | 0 | if ( !$rv ) { | 
| 462 | 0 |  |  |  |  | 0 | DEBUG( 1, "call from '$ctx->{from}' rejected" ); | 
| 463 | 0 |  |  |  |  | 0 | $self->{endpoint}->close_context( $ctx ); | 
| 464 | 0 |  |  |  |  | 0 | return; | 
| 465 |  |  |  |  |  |  | } | 
| 466 |  |  |  |  |  |  | } | 
| 467 |  |  |  |  |  |  |  | 
| 468 |  |  |  |  |  |  | # new invite, create call | 
| 469 | 18 |  |  |  |  | 635 | my $call = Net::SIP::Simple::Call->new( $self,$ctx,{ %$args }); | 
| 470 | 18 |  | 50 |  |  | 420 | my $cb = UNIVERSAL::can( $call,'receive' ) || die; | 
| 471 |  |  |  |  |  |  |  | 
| 472 |  |  |  |  |  |  | # notify caller about new call | 
| 473 | 18 | 100 |  |  |  | 100 | if ($cb_create) { | 
| 474 | 12 |  |  |  |  | 128 | my $cbx = invoke_callback($cb_create, $call, $request, $leg, $from); | 
| 475 | 12 | 50 |  |  |  | 7939 | if ( ! $cbx ) { | 
|  |  | 100 |  |  |  |  |  | 
| 476 | 0 |  |  |  |  | 0 | DEBUG( 1, "call from '$ctx->{from}' rejected in cb_create" ); | 
| 477 | 0 |  |  |  |  | 0 | $self->{endpoint}->close_context( $ctx ); | 
| 478 | 0 |  |  |  |  | 0 | return; | 
| 479 |  |  |  |  |  |  | } elsif ( ref($cbx) ) { | 
| 480 | 3 |  |  |  |  | 14 | $cb = $cbx | 
| 481 |  |  |  |  |  |  | } | 
| 482 |  |  |  |  |  |  | } | 
| 483 |  |  |  |  |  |  |  | 
| 484 |  |  |  |  |  |  | # setup callback on context and call it for this packet | 
| 485 | 18 |  |  |  |  | 157 | $ctx->set_callback([ $cb,$call ]); | 
| 486 | 18 |  |  |  |  | 141 | $cb->( $call,$endpoint,$ctx,undef,undef,$request,$leg,$from ); | 
| 487 | 18 |  |  |  |  | 552 | }; | 
| 488 |  |  |  |  |  |  |  | 
| 489 | 18 |  |  |  |  | 319 | $self->{endpoint}->set_application( [ $receive,$self,\%args] ); | 
| 490 |  |  |  |  |  |  |  | 
| 491 |  |  |  |  |  |  | # in case listener should provide authorization put Authorizer in between | 
| 492 | 18 | 100 |  |  |  | 144 | if ( my $auth = _make_auth_from_args($self,\%args) ) { | 
| 493 | 1 |  |  |  |  | 11 | $self->create_chain([$auth,$self->{endpoint}]); | 
| 494 |  |  |  |  |  |  | } | 
| 495 |  |  |  |  |  |  | } | 
| 496 |  |  |  |  |  |  |  | 
| 497 |  |  |  |  |  |  |  | 
| 498 |  |  |  |  |  |  | ########################################################################### | 
| 499 |  |  |  |  |  |  | # create authorization if args say so | 
| 500 |  |  |  |  |  |  | # Args: ($self,$args) | 
| 501 |  |  |  |  |  |  | #   %$args: | 
| 502 |  |  |  |  |  |  | #     auth_user2pass: see user2pass in Net::SIP::Authorize | 
| 503 |  |  |  |  |  |  | #     auth_user2a1:   see user2a1 in Net::SIP::Authorize | 
| 504 |  |  |  |  |  |  | #     auth_realm:     see realm in Net::SIP::Authorize | 
| 505 |  |  |  |  |  |  | #     auth_.... :     see Net::SIP::Authorize | 
| 506 |  |  |  |  |  |  | # Returns: authorizer if auth_* args given, removes auth_ args from hash | 
| 507 |  |  |  |  |  |  | ########################################################################## | 
| 508 |  |  |  |  |  |  | sub _make_auth_from_args { | 
| 509 | 19 |  |  | 19 |  | 87 | my ($self,$args) = @_; | 
| 510 |  |  |  |  |  |  |  | 
| 511 |  |  |  |  |  |  | my %auth = | 
| 512 | 19 | 100 |  |  |  | 153 | map { m{^auth_(.+)} ? ($1 => delete $args->{$_}):() } | 
|  | 39 |  |  |  |  | 392 |  | 
| 513 |  |  |  |  |  |  | keys %$args; | 
| 514 | 19 |  |  |  |  | 101 | my $i_am_proxy = delete $auth{i_am_proxy}; | 
| 515 |  |  |  |  |  |  |  | 
| 516 | 19 |  | 66 |  |  | 212 | return %auth && $self->create_auth(%auth); | 
| 517 |  |  |  |  |  |  | } | 
| 518 |  |  |  |  |  |  |  | 
| 519 |  |  |  |  |  |  | ########################################################################### | 
| 520 |  |  |  |  |  |  | # setup authorization for use in chain | 
| 521 |  |  |  |  |  |  | # Args: ($self,%args) | 
| 522 |  |  |  |  |  |  | #   %args:  see Net::SIP::Authorize | 
| 523 |  |  |  |  |  |  | # Returns: authorizer object | 
| 524 |  |  |  |  |  |  | ########################################################################## | 
| 525 |  |  |  |  |  |  | sub create_auth { | 
| 526 | 1 |  |  | 1 | 1 | 3 | my ($self,%args) = @_; | 
| 527 |  |  |  |  |  |  | return Net::SIP::Authorize->new( | 
| 528 |  |  |  |  |  |  | dispatcher => $self->{dispatcher}, | 
| 529 | 1 |  |  |  |  | 49 | %args, | 
| 530 |  |  |  |  |  |  | ); | 
| 531 |  |  |  |  |  |  | } | 
| 532 |  |  |  |  |  |  |  | 
| 533 |  |  |  |  |  |  |  | 
| 534 |  |  |  |  |  |  | ########################################################################### | 
| 535 |  |  |  |  |  |  | # setup a simple registrar | 
| 536 |  |  |  |  |  |  | # Args: ($self,%args) | 
| 537 |  |  |  |  |  |  | #   %args: | 
| 538 |  |  |  |  |  |  | #     max_expires: maximum expires time accepted fro registration, default 300 | 
| 539 |  |  |  |  |  |  | #     min_expires: minimum expires time accepted, default 30 | 
| 540 |  |  |  |  |  |  | #     domains|domain: domain or \@list of domains the registrar is responsable | 
| 541 |  |  |  |  |  |  | #       for. special domain '*' catches all | 
| 542 |  |  |  |  |  |  | #    auth_whatever: will require authorization, see whatever in Net::SIP::Authorize | 
| 543 |  |  |  |  |  |  | # Returns: $registrar | 
| 544 |  |  |  |  |  |  | ########################################################################### | 
| 545 |  |  |  |  |  |  | sub create_registrar { | 
| 546 | 0 |  |  | 0 | 1 | 0 | my Net::SIP::Simple $self = shift; | 
| 547 | 0 |  |  |  |  | 0 | my %args = @_; | 
| 548 | 0 |  |  |  |  | 0 | my $auth = _make_auth_from_args($self,\%args); | 
| 549 |  |  |  |  |  |  |  | 
| 550 |  |  |  |  |  |  | my $registrar = Net::SIP::Registrar->new( | 
| 551 |  |  |  |  |  |  | dispatcher => $self->{dispatcher}, | 
| 552 | 0 |  |  |  |  | 0 | %args | 
| 553 |  |  |  |  |  |  | ); | 
| 554 | 0 | 0 |  |  |  | 0 | if ( $auth ) { | 
| 555 | 0 |  |  |  |  | 0 | $registrar = $self->create_chain( | 
| 556 |  |  |  |  |  |  | [$auth,$registrar], | 
| 557 |  |  |  |  |  |  | methods => ['REGISTER'] | 
| 558 |  |  |  |  |  |  | ) | 
| 559 |  |  |  |  |  |  | } else { | 
| 560 | 0 |  |  |  |  | 0 | $self->{dispatcher}->set_receiver( $registrar ); | 
| 561 |  |  |  |  |  |  | } | 
| 562 | 0 |  |  |  |  | 0 | return $registrar; | 
| 563 |  |  |  |  |  |  | } | 
| 564 |  |  |  |  |  |  |  | 
| 565 |  |  |  |  |  |  | ########################################################################### | 
| 566 |  |  |  |  |  |  | # setup a stateless proxy | 
| 567 |  |  |  |  |  |  | # Args: ($self,%args) | 
| 568 |  |  |  |  |  |  | #   %args: see Net::SIP::StatelessProxy, for auth_whatever see whatever | 
| 569 |  |  |  |  |  |  | #      in Net::SIP::Authorize | 
| 570 |  |  |  |  |  |  | # Returns: $proxy | 
| 571 |  |  |  |  |  |  | ########################################################################### | 
| 572 |  |  |  |  |  |  | sub create_stateless_proxy { | 
| 573 | 1 |  |  | 1 | 1 | 5 | my Net::SIP::Simple $self = shift; | 
| 574 | 1 |  |  |  |  | 2 | my %args = @_; | 
| 575 |  |  |  |  |  |  |  | 
| 576 | 1 |  |  |  |  | 2 | $args{auth_i_am_proxy} = 1; | 
| 577 | 1 |  |  |  |  | 4 | my $auth = _make_auth_from_args($self,\%args); | 
| 578 |  |  |  |  |  |  |  | 
| 579 |  |  |  |  |  |  | my $proxy = Net::SIP::StatelessProxy->new( | 
| 580 |  |  |  |  |  |  | dispatcher => $self->{dispatcher}, | 
| 581 | 1 |  |  |  |  | 8 | %args | 
| 582 |  |  |  |  |  |  | ); | 
| 583 | 1 | 50 |  |  |  | 2 | if ( $auth ) { | 
| 584 | 0 |  |  |  |  | 0 | $proxy = $self->create_chain([$auth,$proxy]) | 
| 585 |  |  |  |  |  |  | } else { | 
| 586 | 1 |  |  |  |  | 3 | $self->{dispatcher}->set_receiver($proxy); | 
| 587 |  |  |  |  |  |  | } | 
| 588 | 1 |  |  |  |  | 2 | return $proxy; | 
| 589 |  |  |  |  |  |  | } | 
| 590 |  |  |  |  |  |  |  | 
| 591 |  |  |  |  |  |  | ########################################################################### | 
| 592 |  |  |  |  |  |  | # setup chain of handlers, e.g. first authorize all requests, everything | 
| 593 |  |  |  |  |  |  | # else gets handled by stateless proxy etc | 
| 594 |  |  |  |  |  |  | # Args: ($self,$objects,%args) | 
| 595 |  |  |  |  |  |  | # Returns: $chain | 
| 596 |  |  |  |  |  |  | ########################################################################### | 
| 597 |  |  |  |  |  |  | sub create_chain { | 
| 598 | 1 |  |  | 1 | 1 | 2 | my Net::SIP::Simple $self = shift; | 
| 599 | 1 |  |  |  |  | 34 | my $chain = Net::SIP::ReceiveChain->new( @_ ); | 
| 600 | 1 |  |  |  |  | 5 | $self->{dispatcher}->set_receiver( $chain ); | 
| 601 | 1 |  |  |  |  | 2 | return $chain; | 
| 602 |  |  |  |  |  |  | } | 
| 603 |  |  |  |  |  |  |  | 
| 604 |  |  |  |  |  |  | 1; |