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 43     43   275 use strict;
  43         66  
  43         1006  
12 43     43   162 use warnings;
  43         62  
  43         2212  
13              
14             package Net::SIP::Simple;
15             use fields (
16 43         135 '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   17483 );
  43         62698  
30              
31 43     43   5195 use Carp qw(croak);
  43         66  
  43         1707  
32 43     43   21116 use Net::SIP::Dispatcher;
  43         113  
  43         1206  
33 43     43   253 use Net::SIP::Dispatcher::Eventloop;
  43         81  
  43         1625  
34 43     43   19289 use Net::SIP::Endpoint;
  43         103  
  43         1105  
35 43     43   16117 use Net::SIP::Redirect;
  43         90  
  43         1030  
36 43     43   15833 use Net::SIP::Registrar;
  43         101  
  43         1134  
37 43     43   18106 use Net::SIP::StatelessProxy;
  43         108  
  43         1236  
38 43     43   17068 use Net::SIP::Authorize;
  43         119  
  43         1067  
39 43     43   15027 use Net::SIP::ReceiveChain;
  43         100  
  43         1002  
40 43     43   232 use Net::SIP::Leg;
  43         78  
  43         766  
41             # crossref, because its derived from Net::SIP::Simple
42             # now load in Net::SIP
43             # use Net::SIP::Simple::Call;
44 43     43   17123 use Net::SIP::Simple::RTP;
  43         121  
  43         1282  
45 43     43   265 use Net::SIP::Util qw( :all );
  43         85  
  43         7400  
46 43     43   269 use List::Util 'first';
  43         113  
  43         2292  
47 43     43   211 use Net::SIP::Debug;
  43         80  
  43         189  
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 948 my ($class,%args) = @_;
83 54         220 my $auth = delete $args{auth};
84 54         138 my $registrar = delete $args{registrar};
85 54         125 my $tls = delete $args{tls};
86              
87 54         127 my $ua_cleanup = [];
88 54         412 my $self = fields::new( $class );
89              
90 54   50     10302 my $options = delete $args{options} || {};
91             {
92 54         160 @{$options}{ map { lc } keys(%$options) } = values(%$options); # lc keys
  54         181  
  54         156  
  0         0  
93 54         1875 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         464 while ( my ($k,$v) = each %default_options ) {
101 270 50       918 $options->{$k} = $v if ! defined $options->{$k};
102             }
103             }
104              
105 54         121 my $disp = delete $args{dispatcher};
106             my $loop = $disp && $disp->loop
107             || delete $args{loop}
108 54   33     2747 || Net::SIP::Dispatcher::Eventloop->new;
109 54   33     292 my $proxy = delete $args{outgoing_proxy} || delete $args{proxy};
110 54   66     400 my $d2p = delete $args{domain2proxy} || delete $args{d2p};
111 54   33     2419 $disp ||= Net::SIP::Dispatcher->new(
112             [],
113             $loop,
114             domain2proxy => $d2p,
115             );
116              
117 54   66     1180 my $legs = delete $args{legs} || delete $args{leg};
118 54 100 66     766 $legs = [ $legs ] if $legs && ref($legs) ne 'ARRAY';
119 54   50     174 $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         884 };
130              
131 54 50       270 foreach ($legs ? @$legs : ()) {
132 54 100       1549 if ( UNIVERSAL::isa( $_, 'Net::SIP::Leg' )) {
    50          
    0          
    0          
133             # keep
134             } elsif ( UNIVERSAL::isa( $_, 'IO::Handle' )) {
135             # socket
136 2         30 $_ = 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         389 for my $dst ($registrar, $proxy) {
159 108 50       316 $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       310 $disp->add_leg(@$legs) if @$legs;
176 54 50       920 $disp->outgoing_proxy($proxy) if $proxy;
177              
178             push @$ua_cleanup, [
179             sub {
180 53     53   147 my ($self,$legs) = @_;
181 53         393 $self->{dispatcher}->remove_leg(@$legs);
182             },
183 54 50       885 $self,$legs
184             ] if @$legs;
185              
186 54         1526 my $endpoint = Net::SIP::Endpoint->new( $disp );
187              
188 54   33     1317 my $routes = delete $args{routes} || delete $args{route};
189 54         215 my $from = delete $args{from};
190 54         92 my $contact = delete $args{contact};
191 54         474 my $domain = delete $args{domain};
192              
193 54 100       393 if ($from) {
194 38 100 66     787 if (!defined($domain) && $from =~m{\bsips?:[^@]+\@([\w\-\.]+)}) {
195 4         23 $domain = $1;
196             }
197 38 50 33     858 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       153 die "unhandled arguments: ".join(", ", keys %args) if %args;
204              
205 54         570 %$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         823 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 13275 my Net::SIP::Simple $self = shift;
228 53         109 while ( my $cb = shift @{ $self->{ua_cleanup} } ) {
  106         2321  
229 53         206 invoke_callback($cb,$self)
230             }
231 53         2328 %$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 5424 my Net::SIP::Simple $self = shift;
242 21 100       71 if ( @_ ) {
243 1         3 $self->{last_error} = shift;
244             $DEBUG && DEBUG(100,Net::SIP::Debug::stacktrace(
245 1 50       4 "set error to ".$self->{last_error}) );
246             }
247 21         116 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 7357 my Net::SIP::Simple $self = shift;
260 140         415 my ($timeout,@stopvar);
261 140         420 foreach (@_) {
262 218 100       33533 if ( ref($_) ) {
    50          
263 123         954 push @stopvar,$_
264             } elsif ( defined($_)) {
265 95         201 $timeout = $_
266             }
267             }
268 140         1024 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 24621 my Net::SIP::Simple $self = shift;
293 73         261 my ($method,@arg) = @_;
294 73   33     2303 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         859 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 10957 my Net::SIP::Simple $self = shift;
406 35         409 my ($ctx,%args) = @_;
407 35 50       169 (my $to,$ctx) = ref($ctx) ? ($ctx->{to},$ctx) : ($ctx,undef);
408 35 50       132 $to || croak( "need peer of call" );
409 35 50 33     693 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     1757 my $call = Net::SIP::Simple::Call->new( $self,$ctx||$to );
417 35         563 $call->reinvite(%args);
418 35         170 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 303 my Net::SIP::Simple $self = shift;
441 18         445 my %args = @_;
442 18         151 my $cb_create = delete $args{cb_create};
443              
444             # handle new requests
445             my $receive = sub {
446 18     18   69 my ($self,$args,$endpoint,$ctx,$request,$leg,$from) = @_;
447 18         134 my $method = $request->method;
448 18 50       130 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       125 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         782 my $call = Net::SIP::Simple::Call->new( $self,$ctx,{ %$args });
470 18   50     263 my $cb = UNIVERSAL::can( $call,'receive' ) || die;
471              
472             # notify caller about new call
473 18 100       98 if ($cb_create) {
474 12         95 my $cbx = invoke_callback($cb_create, $call, $request, $leg, $from);
475 12 50       7977 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 18         110 $ctx->set_callback([ $cb,$call ]);
486 18         205 $cb->( $call,$endpoint,$ctx,undef,undef,$request,$leg,$from );
487 18         463 };
488              
489 18         430 $self->{endpoint}->set_application( [ $receive,$self,\%args] );
490              
491             # in case listener should provide authorization put Authorizer in between
492 18 100       163 if ( my $auth = _make_auth_from_args($self,\%args) ) {
493 1         19 $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   122 my ($self,$args) = @_;
510              
511             my %auth =
512 19 100       116 map { m{^auth_(.+)} ? ($1 => delete $args->{$_}):() }
  39         430  
513             keys %$args;
514 19         1159 my $i_am_proxy = delete $auth{i_am_proxy};
515              
516 19   66     13903 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         40 %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         3 $args{auth_i_am_proxy} = 1;
577 1         3 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       2 if ( $auth ) {
584 0         0 $proxy = $self->create_chain([$auth,$proxy])
585             } else {
586 1         4 $self->{dispatcher}->set_receiver($proxy);
587             }
588 1         3 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         4 $self->{dispatcher}->set_receiver( $chain );
601 1         3 return $chain;
602             }
603              
604             1;