The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

=head1 NAME

Net::SIP::Dispatcher - dispatch SIP packets between legs and endpoint

=head1 SYNOPSIS

  my $disp = Net::SIP::Dispatcher->new( ... );
  $disp->deliver( $request );

=head1 DESCRIPTION

This module dispatches L<Net::SIP::Packet>s between L<Net::SIP::Leg>s
and endpoints like L<Net::SIP::Endpoint>, L<Net::SIP::Registrar> and
L<Net::SIP::StatelessProxy>.

It manages retransmission of outgoing packets and redelivery of responses
to incoming requests.

It is asssociated with an event handling like
L<Net::SIP::Dispatcher::Eventloop>.

=head1 CONSTRUCTOR

=over 4

=item new ( \@LEGS, EVENTLOOP, %ARGS )

Creates a new dispatcher object.

@LEGS is a list of legs or specification for legs. See B<add_leg> for
possible formats.

EVENTLOOP is a eventloop which provides handling of events on file
descriptors and timers. If not given a new L<Net::SIP::Dispatcher::Eventloop>
object will be created and used. See there how to define your own
event loop package.

%ARGS are parameters for the behavior of the dispatcher:

=over 8

=item outgoing_proxy

Specifies C<< "ip:port" >> of outgoing proxy, e.g the proxy which will
be used for all outgoing packets. A leg to reach this proxy need to exist.

=item do_retransmits

If TRUE retransmits will be done according to RFC3261. If FALSE no
retransmits will be done, which is used in the case of stateless
proxies.
Defaults to TRUE.

This is the default for the delivery and can be overwritten in
sub B<deliver>.

=item domain2proxy

Optional mapping between target SIP domain and proxy to use.
This is usually a hash of C<< ( domain, "ip_proxy:port_proxy" ) >>
pairs. Special domain '*' can be used to specify a fallback
and '*.domain' to include not only the domain but the subdomains
too.
See sub B<deliver> for more details.

=item dnsresolv

Optional function to be used for DNS resolving instead of Net::DNS. This is
intended for testing or for interfacing with own resolver code.
The function is called with C<< (type,name,callback) >> and is expected to
invoke the callback with the answer. C<type> can be SRV, A or AAAA and the
answer is expected to be a list consisting of C<< ['SRV',prio,host,port] >>,
C<< ['A',ip,host] >> and C<< ['AAAA',ip,host] >>.

=back

The constructor will create a timer using the eventloop which
will regularly (each second) call B<queue_expire>.

=back

=head1 METHODS

=over 4

=item set_receiver ( ENDPOINT )

This sets ENDPOINT as a receiver for incoming packets.
ENDPOINT is an object with a method B<receive> or
a callback usable by B<invoke_callback> in L<Net::SIP::Util>.

=item add_leg ( LEG )

Adds LEG as a leg to the dispatcher C<$self>. LEG can be either
a L<Net::SIP::Leg> object, a L<IO::Handle> or a hash reference
which is usable in the constructor of L<Net::SIP::Leg>.

The leg will be added to the dispatchers eventloop for receiving
incoming packets.

=item remove_leg ( LEG )

Removes L<Net::SIP::Leg> object LEG from the dispatcher.

=item get_legs ( %ARGS )

Get a list of all L<Net::SIP::Leg> objects matching the
criteria given by %ARGS. %ARGS can be a combination of:

=over 8

=item addr

Matches if given address matches the legs source address.

=item port

Matches if given port matches the legs source port.

=item proto

Matches if given proto ('udp','tcp') matches the legs protocol.

=item sub

Call given sub with the L<Net::SIP::Leg> as argument. Matches if
the sub returns TRUE.

=back

The leg matches %ARGS if the all conditions specified in %ARGS
match.

=item add_timer ( WHEN, CALLBACK, [ REPEAT ] )

Adds a timer using the eventloop.

WHEN is either an absolute or a relative time (what it is will
be decided based on the value of WHEN). Absolute times will be
specified in time_t (seconds since 1970-01-01 00:00:00) and
relative time will be specified in seconds.
WHEN can be floating point to specify subseconds.
WHEN can be C<0> to trigger the timer immediately.

CALLBACK is a callback usable by B<invoke_callback> in L<Net::SIP::Util>.

REPEAT is the optional repeat interval for the timer.

=item deliver ( PACKET, %ARGS )

Delivers B<Net::SIP::Packet> PACKET.
%ARGS can specify hints for delivery:

=over 8

=item id

ID for packet, used in B<cancel_delivery>. If not given the transaction
ID of PACKET given by method B<tid> will be used.

=item callid

Call-ID for packet, used in B<cancel_delivery> to cancel all deliveries for
a specific call. If not given the Call-Id of PACKET given by method B<callid>
will be used.

=item callback

callback which will be called on definite delivery of packet (only possible
for TCP) or on definite failure. Callback will be invoked using B<invoke_callback>
from B<Net::SIP::Util> with the additional argument of C<$!>.
See sub B<deliver> in L<Net::SIP::Leg>.

=item leg

Specifies outgoing L<Net::SIP::Leg> object. For responses created by the
endpoint the outgoing leg is usually known, because it's the same as the
incoming leg for the request.

=item dst_addr

Destination, i.e. where to deliver the packet.  This should be given as a hash
with the keys C<proto> (udp|tcp|tls), C<host>, C<addr>, C<port> and C<family>.
This is necessary for responses, for requests it can be found out based on the
requests URI.

=item do_retransmits

Specifies if retransmits should be done according to RFC3261. This is
usually the case, except for stateless proxies. Overwrites the global parameter
with the same name from the constructor for the delivery of the
specific packet.

=back

Delivery of the packet itself will be handled in multiple steps (in the
code done mainly by sub B<__deliver>:

=over 8

=item *

If a leg is specified it will be used for delivery. B<dst_addr> needs to
be specified in this case too.
This is usually the case for locally generated responses.

=item *

Otherwise leg and dst_addr will be retrieved using B<resolve_uri>.
See there.


=back

If the packets could be retransmitted appropriate setups
will be done. Retransmission will be done until final failure
or until B<cancel_delivery> will be called for the packet, which
usually means, that the packet was successfully delivered because
a response to the packet was received.

=item resolve_uri ( URI, ADDR, LEGS, CALLBACK, [ ALLOWED_PROTO, ALLOWED_LEGS ] )

Resolves URI to get the destination address and the outgoing leg.
ADDR and LEGS are references to lists which will get filled with
the computed values.

If ALLOWED_PROTO is given it will be interpreted as a \@list of protocols.
Only the protocols given in the list will be considered and the
it will try them in the order from the list, e.g. C<< ('tcp','udp') >>
means that tcp is tried first and only if there is no way to do tcp
it will try udp. Default is to first try udp and then tcp.

If ALLOWED_LEGS is given it will be interpreted as a \@list of L<Net::SIP::Leg>
objects and only these legs are allowed.

Because the method can be asynchronous (DNS lookups can be involved)
it will call CALLBACK once it is done. If no errors occurred
CALLBACK will be invoked without additional arguments, otherwise
with the errno as additional argument.

Resolving will be done as follows:

=over 8

=item *

If B<domain2proxy> is given it will try to get the dst_addr
from this, e.g. the address of the proxy responsable for the domain
(if any). From dst_addr it will then get the leg.

=item *

If still no dst_addr is known it will use B<outgoing_proxy>
as the dst_addr.

=item *

If still no dst_addr is known but the SIP domain is an
IP address this will be used as dst_addr.

=item *

The last effort will be made by looking up the SIP domain using
DNS with a partial implementation of RFC3263, e.g. it looks at
the DNS SRV records but not at NAPTR records.

=item *

For each destination address (e.g. proto,addr,port) the outgoing
leg will be computed.
This will be done in sub B<__find_leg4addr> by going through
all legs and checking, if the leg could deliver to this
address by calling B<can_deliver_to> on the leg (see L<Net::SIP::Leg>).

=back

=item cancel_delivery ( TYP?,ID )

Cancels retransmission of packet with id ID. Called from endpoint
if response to packet came in, which means that the packet was
successfully delivered.

If TYP given packets can be canceled by something else. TYP can be
C<callid>, in which case all deliveries for a specific call will be
canceled. It can be C<id> which will cancel the packet with id ID.
Or it can be C<qentry> in which case ID will be interpreted as
the L<Net::SIP::Dispatcher::Packet> object in the queue and it will
cancel this packet.

Will return true if the item was canceled, false if no such item
was found in delivery queue.

=item receive ( PACKET, LEG, FROM )

Called from the eventloop (e.g was setup as a callback) for
incoming packets. The new L<Net::SIP::Packet> is PACKET,
LEG is the L<Net::SIP::Leg> where the packet came in and
FROM is C<< "ip:port" >> of the sender.

=item queue_expire ( [ NOW ] )

Expires retransmission queue, e.g. deletes packet where retransmissions
failed permanently (and calls appropriate callbacks) and initiates
pending retransmissions. Called from a timer setup in the constructor.

=back