This file is indexed.

/usr/share/perl5/Net/SIP/Endpoint.pm is in libnet-sip-perl 0.66-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
############################################################################
# package Net::SIP::Endpoint
# implements the behavior of an endpoint (SIP phone).
# packet managment (lower layer) is done by Net::SIP::Dispatcher while
# call managment is done with Net::SIP::Endpoint::Context
############################################################################

use strict;
use warnings;
package Net::SIP::Endpoint;
use fields (
	'dispatcher',   # lower layer, delivers and receives packets through the legs
	'application',  # upper layer, e.g user interface..
	'ctx'           # hash of ( callid => Net::SIP::Endpoint::Context )
);

use Net::SIP::Debug;
use Net::SIP::Endpoint::Context;
use Net::SIP::Util qw(invoke_callback);
use Scalar::Util 'weaken';

############################################################################
# create a new endpoint
# Args: ($class,$dispatcher)
#  $dispatcher: lower layer which handles the delivery and receiving of packets
# Returns: $self
############################################################################
sub new {
	my ($class,$dispatcher) = @_;
	my $self = fields::new($class);

	$self->{dispatcher} = $dispatcher;
	$self->{ctx} = {}; # \%hash with ( callid => $ctx )

	# announce myself as upper layer for incoming packets to
	# the dispatcher
	my $cb = [ \&receive,$self ];
	weaken( $cb->[1] );
	$dispatcher->set_receiver( $cb );

	return $self;
}

############################################################################
# set upper layer (application)
# Args: ($self,$app)
#  $app: upper layer which needs to have method receive( $request )
#    to handle new request, which this layer cannot handle alone
#    (e.g INVITE to a new dialog)
#    or this can be \&sub, [ \&sub,@arg ]...
# Returns: NONE
############################################################################
sub set_application {
	my Net::SIP::Endpoint $self = shift;
	my $app = shift;
	my $cb;
	if ( my $sub = UNIVERSAL::can( $app,'receive' )) {
		$cb = [ $sub,$app ];
	} else {
		$cb = $app; # alreday callback
	}
	$self->{application} = $cb;
}

############################################################################
# create a new call or re-invite on a existing call
# wrapper around new_request()
# Args: ($self,$ctx;$callback,$body,%args)
#   $ctx: Context|\%args, see new_request()
#   $callback: optional Callback, see new_request()
#   $body: optional Body
#   %args: additional args for Net::SIP::Request::new
# Returns: $ctx
#   $ctx: see new_request()
############################################################################
sub invite {
	my Net::SIP::Endpoint $self = shift;
	my ($ctx,$callback,$body,%args) = @_;
	return $self->new_request( 'INVITE',$ctx,$callback,$body,%args );
}

############################################################################
# registers UAC
# Args: ($self,%args)
#  %args: at minimum there must be
#    from:    the sip-address to register
#    contact: to which local address should it registered
#    registrar: where it should be registered
#  there can be:
#    expires: Expires header, defaults to 900 if not given
#    callback: callback which will be called on response
#    callid: callid used for calling context
#  all other args will be used in creation of request
# Returns: NONE
############################################################################
sub register {
	my Net::SIP::Endpoint $self = shift;
	my %args = @_;

	my ($me,$registrar,$contact) =
		delete @args{qw( from registrar contact )};

	my $expires = delete $args{expires};
	$expires = 900 if !defined($expires);

	my %ctx = (
		to      => $me,
		from    => $me,
		contact => $contact,
		auth    => delete $args{auth},
		callid  => delete $args{callid},
	);
	return $self->new_request(
		'REGISTER',
		\%ctx,
		delete($args{callback}),
		undef,
		uri => "sip:$registrar",
		expires => $expires,
		%args,
	);
}


############################################################################
# starts new request, e.g creates request packet and delivers it
# Args: ($self,$method,$ctx;$callback,$body,%args)
#   $method: method name, e.g. 'INVITE','REGISTER',..
#     can also be a full Net::SIP::Request already (used for retries after
#     302,305 responses)
#   $ctx: already established context (Net::SIP::Endpoint::Context)
#     or \%hash to create a new one (see Net::SIP::Endpoint::Context->new)
#   $callback: [ \&sub,@arg ] which will be called if the layer receives
#     responses important to the upper layer (e.g 180 Ringing, 200 Ok,
#     401/407 Authorization required...)
#     if callback is ommitted the callback from the context is used,
#     if callback is set it will be the new callback for the context
#   $body: optional Body, either scalar or smth with method as_string
#     (like Net::SIP::SDP)
#   %args: additional args for Net::SIP::Endpoint::Context::new_request
# Returns: $ctx
#    $ctx: context, eg the original one or newly created
# Comment: if it cannot create a new context (because of missing args)
#   or something else fatal happens it will die()
############################################################################
sub new_request {
	my Net::SIP::Endpoint $self = shift;
	my ($method,$ctx,$callback,$body,%args) = @_;

	die "cannot redefine call-id" if delete $args{ 'call-id' };
	my ($leg,$dst_addr) = delete @args{qw(leg dst_addr)};

	if ( ! UNIVERSAL::isa( $ctx,'Net::SIP::Endpoint::Context' )) {
		$ctx = Net::SIP::Endpoint::Context->new(%$ctx, method => $method);
		$self->{ctx}{ $ctx->callid } = $ctx; # make sure we manage the context
		DEBUG( 10,"create new request for $method within new call ".$ctx->callid );
	} else {
		DEBUG( 10,"create new request for $method within existing call ".$ctx->callid );
	}

	$ctx->set_callback( $callback ) if $callback;

	my $request = $ctx->new_request( $method,$body,%args );
	DEBUG( 50,"request=".$request->as_string );

	my $tid = $request->tid;
	$self->{dispatcher}->deliver( $request,
		id => $tid,
		callback => [ \&_request_delivery_callback, $self,$ctx ],
		leg => $leg,
		dst_addr => $dst_addr,
	);

	return $ctx;
}

############################################################################
# Cancel last pending INVITE request
# Args: ($self,$ctx,$request,$cb)
#   $ctx: context for call
#   $request: request to cancel, will only cancel it, if request is
#     outstanding in context, will cancel latest INVITE if not given
#   $cb: callback for generated CANCEL request
# Returns: number of requests canceled (e.g 0 if no outstanding INVITE)
############################################################################
sub cancel_invite {
	my Net::SIP::Endpoint $self = shift;
	my Net::SIP::Endpoint::Context $ctx = shift;
	my ($request,$callback) = @_;
	my ($pkt) = $ctx->find_outstanding_requests(
		$request ? ( request => $request ) : ( method => 'INVITE' )
	) or return;
	$self->new_request( $pkt->create_cancel, $ctx, $callback );
	return 1;
}

############################################################################
# internal callback used for delivery
# will be called from dispatcher if the request was definitly successfully
# delivered (tcp only) or an error occurred
# Args: ($self,$ctx,$error,$delivery_packet)
#   $ctx: Net::SIP::Endpoint::Context
#   $error: errno if error occured
#   $delivery_packet: Net::SIP::Dispatcher::Packet which encapsulates
#     the original request and information about leg, dst_addr...
#     and has method use_next_dstaddr to try the next dstaddr if for the
#     current no (more) retries are possible
# Returns: NONE
############################################################################
sub _request_delivery_callback {
	my Net::SIP::Endpoint $self = shift;
	my ($ctx,$error,$delivery_packet) = @_;

	my $tid = $delivery_packet->tid;

	# either successfully send over reliable transport
	# or permanently failed, e.g no (more) retries possible
	$ctx->request_delivery_done( $self,$tid,$error )
}

############################################################################
# remove context from Endpoint and cancel all outstanding deliveries
# Args: ($self,$id)
#  $id: either id for ctx or context object or SIP packet
# Returns: $ctx
#  $ctx: removed context object
############################################################################
sub close_context {
	my Net::SIP::Endpoint $self = shift;
	my $id = shift;
	$id = $id->callid if ref($id);
	DEBUG( 10,"close context call-id $id " );
	my $ctx = delete $self->{ctx}{$id} || do {
		DEBUG( 50,"no context for call-id $id found" );
		return;
	};
	# cancel all outstanding deliveries
	$self->{dispatcher}->cancel_delivery( callid => $id );
	return $ctx;
}


############################################################################
# receive packet from dispatcher and forwards it to receive_response
# or receive_request depending on type of packet
# Args: ($self,$packet,$leg,$from)
#   $packet: Net::SIP::Packet
#   $leg: Net::SIP::Leg through which the packets was received
#   $from: ip:port where it got packet from
# Returns: NONE
############################################################################
sub receive {
	my Net::SIP::Endpoint $self = shift || return;
	my ($packet,$leg,$from) = @_;
	return $packet->is_response
		? $self->receive_response( $packet,$leg,$from )
		: $self->receive_request( $packet,$leg,$from )
		;
}

############################################################################
# Handle incoming response packet
# Args: ($self,$response,$leg,$from)
#  $response: incoming Net::SIP::Response packet
#  $leg: where response came in
#  $from: ip:port where it got response from
# Returns: NONE
############################################################################
sub receive_response {
	my Net::SIP::Endpoint $self = shift;
	my ($response,$leg,$from) = @_;

	# find context for response or drop
	my $callid = $response->get_header( 'call-id' );
	my $ctx = $self->{ctx}{$callid} || do {
		DEBUG( 50,"cannot find context for packet with callid=$callid. DROP");
		return;
	};

	DEBUG( 10,"received reply for tid=".$response->tid );
	$self->{dispatcher}->cancel_delivery( $response->tid );
	$ctx->handle_response( $response,$leg,$from,$self );
}

############################################################################
# Handle incoming request packet
# Args: ($self,$request,$leg,$from)
#  $request: incoming Net::SIP::Request packet
#  $leg: where response came in
#  $from: ip:port where it got response from
# Returns: NONE
############################################################################
sub receive_request {
	my Net::SIP::Endpoint $self = shift;
	my ($request,$leg,$from) = @_;

	# this might be a request for an existing context or for a new context
	my $callid = $request->get_header( 'call-id' );
	my $ctx = $self->{ctx}{$callid};

	my $method = $request->method;
	if ( ! $ctx ) {
		if ( $method eq 'BYE' || $method eq 'CANCEL' ) {
			# no context for this call, reply with 481 call does not exist
			# (RFC3261 15.1.2)
			$self->new_response(
				undef,
				$request->create_response( 481,'call does not exist' ),
				$leg,  # send back thru same leg
				$from, # and back to the sender
			);
			return;
		} elsif ( $method eq 'ACK' ) {
			# call not exists (maybe closed because of CANCEL)
			DEBUG(99,'ignoring ACK for non-existing call');
			return;
		}

		# create a new context;
		$ctx = Net::SIP::Endpoint::Context->new(
			incoming => 1,
			method => $method,
			from => scalar( $request->get_header( 'from' )),
			to   => scalar( $request->get_header( 'to' )),
			remote_contact => scalar( $request->get_header( 'contact' )),
			callid => scalar( $request->get_header( 'call-id' )),
			via  => [ $request->get_header( 'via' ) ],
		);

		$ctx->set_callback( sub {
			my ($self,$ctx,undef,undef,$request,$leg,$from) = @_;
			invoke_callback( $self->{application}, $self,$ctx,$request,$leg,$from );
		});
	}

	# if I got an ACK cancel delivery of Response to INVITE
	if ( $method eq 'ACK' ) {
		$self->{dispatcher}->cancel_delivery( $request->tid );
	}

	$ctx->handle_request( $request,$leg,$from,$self );
}

############################################################################
# deliver a response packet
# Args: ($self,$ctx,$response,$leg,$addr)
#   $ctx     : Net::SIP::Endpoint::Context which generated response
#   $response: Net::SIP::Response packet
#   $leg     : leg to send out response, eg where the request came in
#   $addr    : where to send respone (ip:port), eg where the request came from
# Returns: NONE
############################################################################
sub new_response {
	my Net::SIP::Endpoint $self = shift;
	my ($ctx,$response,$leg,$addr) = @_;

	$self->{ctx}{ $ctx->callid } = $ctx if $ctx; # keep context
	$self->{dispatcher}->deliver( $response,
		leg      => $leg,
		dst_addr => $addr,
	);
}


1;