File Coverage

blib/lib/Net/SIP/Simple.pm
Criterion Covered Total %
statement 162 254 63.7
branch 39 110 35.4
condition 21 70 30.0
subroutine 30 37 81.0
pod 13 13 100.0
total 265 484 54.7


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 41     41   274 use strict;
  41         55  
  41         1153  
12 41     41   254 use warnings;
  41         70  
  41         2270  
13              
14             package Net::SIP::Simple;
15             use fields (
16 41         176 '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 41     41   19942 );
  41         67281  
30              
31 41     41   5814 use Carp qw(croak);
  41         79  
  41         1926  
32 41     41   22408 use Net::SIP::Dispatcher;
  41         140  
  41         1509  
33 41     41   271 use Net::SIP::Dispatcher::Eventloop;
  41         87  
  41         1952  
34 41     41   20573 use Net::SIP::Endpoint;
  41         120  
  41         1350  
35 41     41   17414 use Net::SIP::Redirect;
  41         112  
  41         1178  
36 41     41   17346 use Net::SIP::Registrar;
  41         119  
  41         1453  
37 41     41   19946 use Net::SIP::StatelessProxy;
  41         119  
  41         1358  
38 41     41   18706 use Net::SIP::Authorize;
  41         115  
  41         1253  
39 41     41   16615 use Net::SIP::ReceiveChain;
  41         119  
  41         1168  
40 41     41   258 use Net::SIP::Leg;
  41         103  
  41         870  
41             # crossref, because its derived from Net::SIP::Simple
42             # now load in Net::SIP
43             # use Net::SIP::Simple::Call;
44 41     41   19043 use Net::SIP::Simple::RTP;
  41         159  
  41         1444  
45 41     41   304 use Net::SIP::Util qw( :all );
  41         105  
  41         8159  
46 41     41   308 use List::Util 'first';
  41         91  
  41         2256  
47 41     41   243 use Net::SIP::Debug;
  41         85  
  41         258  
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 52     52 1 1167 my ($class,%args) = @_;
83 52         272 my $auth = delete $args{auth};
84 52         175 my $registrar = delete $args{registrar};
85 52         144 my $tls = delete $args{tls};
86              
87 52         132 my $ua_cleanup = [];
88 52         433 my $self = fields::new( $class );
89              
90 52   50     10273 my $options = delete $args{options} || {};
91             {
92 52         170 @{$options}{ map { lc } keys(%$options) } = values(%$options); # lc keys
  52         276  
  52         149  
  0         0  
93 52         1717 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 52         345 while ( my ($k,$v) = each %default_options ) {
101 260 50       1078 $options->{$k} = $v if ! defined $options->{$k};
102             }
103             }
104              
105 52         138 my $disp = delete $args{dispatcher};
106             my $loop = $disp && $disp->loop
107             || delete $args{loop}
108 52   33     3186 || Net::SIP::Dispatcher::Eventloop->new;
109 52   33     463 my $proxy = delete $args{outgoing_proxy} || delete $args{proxy};
110 52   66     494 my $d2p = delete $args{domain2proxy} || delete $args{d2p};
111 52   33     2413 $disp ||= Net::SIP::Dispatcher->new(
112             [],
113             $loop,
114             domain2proxy => $d2p,
115             );
116              
117 52   66     414 my $legs = delete $args{legs} || delete $args{leg};
118 52 100 66     895 $legs = [ $legs ] if $legs && ref($legs) ne 'ARRAY';
119 52   50     211 $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 52         2274 };
130              
131 52 50       345 foreach ($legs ? @$legs : ()) {
132 52 100       461 if ( UNIVERSAL::isa( $_, 'Net::SIP::Leg' )) {
    50          
    0          
    0          
133             # keep
134             } elsif ( UNIVERSAL::isa( $_, 'IO::Handle' )) {
135             # socket
136 2         35 $_ = 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 52         432 for my $dst ($registrar, $proxy) {
159 104 50       318 $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 52 50       1166 $disp->add_leg(@$legs) if @$legs;
176 52 50       212 $disp->outgoing_proxy($proxy) if $proxy;
177              
178             push @$ua_cleanup, [
179             sub {
180 51     51   166 my ($self,$legs) = @_;
181 51         492 $self->{dispatcher}->remove_leg(@$legs);
182             },
183 52 50       1002 $self,$legs
184             ] if @$legs;
185              
186 52         1706 my $endpoint = Net::SIP::Endpoint->new( $disp );
187              
188 52   33     771 my $routes = delete $args{routes} || delete $args{route};
189 52         449 my $from = delete $args{from};
190 52         122 my $contact = delete $args{contact};
191 52         114 my $domain = delete $args{domain};
192              
193 52 100       180 if ($from) {
194 36 100 66     875 if (!defined($domain) && $from =~m{\bsips?:[^@]+\@([\w\-\.]+)}) {
195 2         8 $domain = $1;
196             }
197 36 50 33     999 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 52 50       248 die "unhandled arguments: ".join(", ", keys %args) if %args;
204              
205 52         666 %$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 52         630 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 51     51 1 46423 my Net::SIP::Simple $self = shift;
228 51         130 while ( my $cb = shift @{ $self->{ua_cleanup} } ) {
  102         2730  
229 51         240 invoke_callback($cb,$self)
230             }
231 51         2312 %$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 2868 my Net::SIP::Simple $self = shift;
242 21 100       86 if ( @_ ) {
243 1         2 $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         133 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 130     130 1 3813 my Net::SIP::Simple $self = shift;
260 130         394 my ($timeout,@stopvar);
261 130         495 foreach (@_) {
262 204 100       990 if ( ref($_) ) {
    50          
263 115         432 push @stopvar,$_
264             } elsif ( defined($_)) {
265 89         316 $timeout = $_
266             }
267             }
268 130         949 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 67     67 1 8946 my Net::SIP::Simple $self = shift;
293 67         416 my ($method,@arg) = @_;
294 67   33     2358 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 67         912 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 9725 my Net::SIP::Simple $self = shift;
406 35         522 my ($ctx,%args) = @_;
407 35 50       216 (my $to,$ctx) = ref($ctx) ? ($ctx->{to},$ctx) : ($ctx,undef);
408 35 50       125 $to || croak( "need peer of call" );
409 35 50 33     880 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     1841 my $call = Net::SIP::Simple::Call->new( $self,$ctx||$to );
417 35         782 $call->reinvite(%args);
418 35         235 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 16     16 1 122 my Net::SIP::Simple $self = shift;
441 16         503 my %args = @_;
442 16         138 my $cb_create = delete $args{cb_create};
443              
444             # handle new requests
445             my $receive = sub {
446 16     16   64 my ($self,$args,$endpoint,$ctx,$request,$leg,$from) = @_;
447 16         82 my $method = $request->method;
448 16 50       142 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 16 50       109 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 16         628 my $call = Net::SIP::Simple::Call->new( $self,$ctx,{ %$args });
470 16   50     291 my $cb = UNIVERSAL::can( $call,'receive' ) || die;
471              
472             # notify caller about new call
473 16 100       85 if ($cb_create) {
474 12         155 my $cbx = invoke_callback($cb_create, $call, $request, $leg, $from);
475 12 50       7135 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         7 $cb = $cbx
481             }
482             }
483              
484             # setup callback on context and call it for this packet
485 16         121 $ctx->set_callback([ $cb,$call ]);
486 16         213 $cb->( $call,$endpoint,$ctx,undef,undef,$request,$leg,$from );
487 16         536 };
488              
489 16         412 $self->{endpoint}->set_application( [ $receive,$self,\%args] );
490              
491             # in case listener should provide authorization put Authorizer in between
492 16 100       213 if ( my $auth = _make_auth_from_args($self,\%args) ) {
493 1         12 $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 17     17   120 my ($self,$args) = @_;
510              
511             my %auth =
512 17 100       175 map { m{^auth_(.+)} ? ($1 => delete $args->{$_}):() }
  37         503  
513             keys %$args;
514 17         122 my $i_am_proxy = delete $auth{i_am_proxy};
515              
516 17   66     357 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 18 my ($self,%args) = @_;
527             return Net::SIP::Authorize->new(
528             dispatcher => $self->{dispatcher},
529 1         160 %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 6 my Net::SIP::Simple $self = shift;
574 1         2 my %args = @_;
575              
576 1         3 $args{auth_i_am_proxy} = 1;
577 1         5 my $auth = _make_auth_from_args($self,\%args);
578              
579             my $proxy = Net::SIP::StatelessProxy->new(
580             dispatcher => $self->{dispatcher},
581 1         9 %args
582             );
583 1 50       3 if ( $auth ) {
584 0         0 $proxy = $self->create_chain([$auth,$proxy])
585             } else {
586 1         4 $self->{dispatcher}->set_receiver($proxy);
587             }
588 1         4 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 4 my Net::SIP::Simple $self = shift;
599 1         61 my $chain = Net::SIP::ReceiveChain->new( @_ );
600 1         7 $self->{dispatcher}->set_receiver( $chain );
601 1         5 return $chain;
602             }
603              
604             1;