File Coverage

blib/lib/Net/SIP/Packet.pm
Criterion Covered Total %
statement 244 312 78.2
branch 80 136 58.8
condition 21 34 61.7
subroutine 39 45 86.6
pod 21 21 100.0
total 405 548 73.9


line stmt bran cond sub pod time code
1             ###########################################################################
2             # Net::SIP::Packet
3             # parsing, creating and manipulating of SIP packets
4             ###########################################################################
5              
6 42     42   70804 use strict;
  42         87  
  42         1202  
7 42     42   197 use warnings;
  42         82  
  42         1384  
8              
9             package Net::SIP::Packet;
10              
11 42     42   673 use Net::SIP::Debug;
  42         77  
  42         348  
12 42     42   28806 use Storable;
  42         135310  
  42         2459  
13 42     42   21186 use Net::SIP::SDP;
  42         120  
  42         1551  
14 42     42   288 use Carp 'croak';
  42         100  
  42         2210  
15              
16 42     42   831 use fields qw( code method text header lines body as_string );
  42         1792  
  42         265  
17              
18             # code: numeric response code in responses
19             # method request method in requests
20             # text: response text or request URI
21             # body: scalar with body
22             # as_string: string representation
23             # lines: array-ref or [ original_header_lines, number_of_parts ]
24             # header: array-ref of Net::SIP::HeaderPair
25              
26              
27              
28              
29             ###########################################################################
30             # Constructor - Creates new object.
31             # If there are more than one argument it will forward to new_from_parts.
32             # If the only argument is a scalar it will forward to new_from_string.
33             # Otherwise it will just create the object of the given class and if
34             # there is an argument treat is as a hash to fill the new object.
35             #
36             # Apart from new there are also _new_request and _new_response.
37             # These can be overridden so that application specific classes for
38             # request and response will be used for the new object.
39             #
40             # Args: see new_from_parts(..)|new_from_string($scalar)|\%hash|none
41             # Returns: $self
42             ###########################################################################
43             sub new {
44 568     568 1 8974 my $class = shift;
45 568 100       2720 return $class->new_from_parts(@_) if @_>1;
46 392 100 66     2406 return $class->new_from_string(@_) if @_ && !ref($_[0]);
47 383         1403 my $self = fields::new($class);
48 383 50       52546 %$self = %{$_[0]} if @_;
  383         2044  
49 383         2022 return $self;
50             }
51              
52             sub _new_request {
53 180     180   444 shift;
54 180         1374 return Net::SIP::Request->new(@_);
55             }
56              
57             sub _new_response {
58 203     203   377 shift;
59 203         1291 return Net::SIP::Response->new(@_);
60             }
61              
62             ###########################################################################
63             # create new object from parts
64             # Args: ($class,$code_or_method,$text,$header,$body)
65             # $code_or_method: Response code or request method
66             # $text: Response text or request URI
67             # $header: Header representation as array or hash
68             # either [ [key1 => val2],[key2 => val2],... ] where the same
69             # key can occure multiple times
70             # or { key1 => val1, key2 => val2 } where val can be either
71             # a scalar or an array-ref (if the same key has multiple values)
72             # $body: Body as string
73             # Returns: $self
74             # Comment:
75             # the actual object will be created with _new_request and _new_response and
76             # thus will usually be a subclass of Net::SIP::Packet
77             ###########################################################################
78             sub new_from_parts {
79 176     176 1 947 my ($class,$code,$text,$header,$body) = @_;
80              
81             # header can be hash-ref or array-ref
82             # if hash-ref convert it to array-ref sorted by key
83             # (sort just to make the result predictable)
84 176 50       845 if ( UNIVERSAL::isa( $header,'HASH' )) {
85 176         367 my @hnew;
86 176         1875 foreach my $key ( sort keys %$header ) {
87 986         1751 my $v = $header->{$key};
88 986 100       2281 foreach my $value ( ref($v) ? @$v : ($v) ) {
89 836         2492 push @hnew,[ $key,$value ];
90             }
91             }
92 176         552 $header = \@hnew;
93             }
94              
95 176 100       2396 my $self = $code =~m{^\d}
96             ? $class->_new_response({ code => $code })
97             : $class->_new_request({ method => uc($code) });
98 176 50       882 $self->{text} = defined($text) ? $text:'';
99              
100             # $self->{header} is list of Net::SIP::HeaderPair which cares about normalized
101             # keys while maintaining the original key, so that one can restore header
102             # the elements from @$header can be either [ key,value ] or Net::SIP::HeaderPair's
103             # but have to be all from the same type
104 176         364 my @hnew;
105 176         340 my $normalized = 0;
106 176         704 for( my $i=0;$i<@$header;$i++ ) {
107 836         1435 my $h = $header->[$i];
108 836 50       2141 if ( UNIVERSAL::isa($h,'Net::SIP::HeaderPair')) {
109             # already normalized
110 0         0 $normalized = 1;
111 0         0 push @hnew,$h;
112             } else {
113 836         1667 my ($key,$value) = @$h;
114 836 50       1624 defined($value) || next;
115 836 50       1497 croak( "mix between normalized and not normalized data in header" ) if $normalized;
116 836         2489 push @hnew, Net::SIP::HeaderPair->new( $key,$value ) ;
117             }
118             }
119              
120 176         890 $self->{header} = \@hnew;
121             # as_string is still undef, it will be evaluated once we call as_string()
122              
123 176 100       619 if ( ref($body)) {
124 52 50       845 if ( !$self->get_header( 'content-type' )) {
125 52         378 my $sub = UNIVERSAL::can( $body, 'content_type' );
126 52 50       500 $self->set_header( 'content-type' => $sub->($body) ) if $sub;
127             }
128 52         692 $body = $body->as_string;
129             }
130 176         452 $self->{body} = $body;
131              
132 176         1142 return $self;
133             }
134              
135             ###########################################################################
136             # Create new packet from string
137             # Args: ($class,$string)
138             # $string: String representation of packet
139             # Returns: $self
140             # Comment:
141             # for the class of $self see comment in new_from_parts above
142             ###########################################################################
143             sub new_from_string {
144 213     213 1 1034 my ($class,$string) = @_;
145 213         1410 my $data = _string2parts($string);
146             return $data->{method}
147 207 100       1334 ? $class->_new_request($data)
148             : $class->_new_response($data);
149             }
150              
151             ###########################################################################
152             # Find out if it is a request
153             # Args: $self
154             # Returns: true if it's a request
155             ###########################################################################
156             sub is_request {
157 0     0 1 0 my $self = shift;
158 0 0       0 $self->{header} || $self->as_parts();
159 0   0     0 return $self->{method} && 1;
160             }
161              
162             ###########################################################################
163             # Find out if it is a response
164             # Args: $self
165             # Returns: true if it's a response
166             ###########################################################################
167             sub is_response {
168 0     0 1 0 my $self = shift;
169 0 0       0 $self->{header} || $self->as_parts();
170 0         0 return ! $self->{method};
171             }
172              
173              
174             ###########################################################################
175             # Return transaction Id of packet, consisting of the call-id and
176             # the CSeq num. Method is not included because ACK or CANCEL requests
177             # belong to the same transaction as the INVITE
178             # Responses have the same TID as the request
179             # Args: $self
180             # Returns: $tid
181             ###########################################################################
182             sub tid {
183 1109     1109 1 1871 my Net::SIP::Packet $self = shift;
184 1109         2810 $self->get_header( 'cseq' ) =~m{^(\d+)};
185 1109         2564 return $self->get_header( 'call-id' ).' '.$1;
186             }
187              
188             ###########################################################################
189             # Accessors for Headerelements
190             ###########################################################################
191              
192             ###########################################################################
193             # Access cseq Header
194             # Args: $self
195             # Returns: $cseq_value
196             ###########################################################################
197 377     377 1 968 sub cseq { scalar( shift->get_header('cseq')) }
198              
199             ###########################################################################
200             # Access call-id Header
201             # Args: $self
202             # Returns: $callid
203             ###########################################################################
204 187     187 1 586 sub callid { scalar( shift->get_header('call-id')) }
205              
206             ###########################################################################
207             # Access header
208             # Args: ($self; $key)
209             # $key: (optional) which headerkey to access
210             # Returns: @val|\%header
211             # @val: if key given returns all values for this key
212             # croak()s if in scalar context and I've more then one value for the key
213             # \%header: if no key given returns hash with
214             # { key1 => \@val1, key2 => \@val2,.. }
215             ###########################################################################
216             sub get_header {
217 5960     5960 1 14839 my ($self,$key) = @_;
218 5960         12010 my $hdr = ($self->as_parts)[2];
219 5960 50       12003 if ( $key ) {
220 5960         9873 $key = _normalize_hdrkey($key);
221 5960         9132 my @v;
222 5960         9885 foreach my $h (@$hdr) {
223 42778 100       79171 push @v,$h->{value} if $h->{key} eq $key;
224             }
225 5960 100       15895 return @v if wantarray;
226 4003 50       7166 if (@v>1) {
227             # looks like we have multiple headers but expect only
228             # one. Because we've seen bad client which issue multiple
229             # content-length header we try if all in @v are the same
230 0         0 my %v = map { $_ => 1 } @v;
  0         0  
231 0 0       0 return $v[0] if keys(%v) == 1; # ok, only one
232 0         0 croak( "multiple values for $key in packet:\n".$self->as_string );
233             }
234 4003         21580 return $v[0];
235             } else {
236 0         0 my %result;
237 0         0 foreach my $h (@$hdr) {
238 0         0 push @{ $result{$h->{key}} }, $h->{value};
  0         0  
239             }
240 0         0 return \%result;
241             }
242             }
243              
244             ###########################################################################
245             # get header as Net::SIP::HeaderVal
246             # like get_header, but instead of giving scalar values gives Net::SIP::HeaderVal
247             # objects which have various accessors, like extracting the parameters
248             # Args: ($self; $key)
249             # $key: (optional) which headerkey to access
250             # Returns: @val|\%header
251             # @val: if key given returns all values (Net::SIP::HeaderVal) for this key
252             # croak()s if in scalar context and I've more then one value for the key
253             # \%header: if no key given returns hash with
254             # { key1 => \@val1, key2 => \@val2,.. } where val are Net::SIP::HeaderVal
255             ###########################################################################
256             sub get_header_hashval {
257 9     9 1 29 my ($self,$key) = @_;
258 9         28 my $hdr = ($self->as_parts)[2];
259 9 50       28 if ( $key ) {
260 9         21 $key = _normalize_hdrkey($key);
261 9         21 my @v;
262 9         39 foreach my $h (@$hdr) {
263             push @v,Net::SIP::HeaderVal->new( $h )
264 59 100       162 if $h->{key} eq $key;
265             }
266 9 50       75 return @v if wantarray;
267 0 0       0 croak( "multiple values for $key" ) if @v>1;
268 0         0 return $v[0];
269             } else {
270 0         0 my %result;
271 0         0 foreach my $h (@$hdr) {
272 0         0 push @{ $result{$h->{key}} },
  0         0  
273             Net::SIP::HeaderVal->new( $h );
274             }
275 0         0 return \%result;
276             }
277             }
278              
279             ###########################################################################
280             # Add header to SIP packet, headers gets added after all other headers
281             # Args: ($self,$key,$val)
282             # $key: Header key
283             # $val: scalar or \@array which contains value(s)
284             ###########################################################################
285             sub add_header {
286 3     3 1 13 my ($self,$key,$val) = @_;
287 3         12 my $hdr = ($self->as_parts)[2];
288 3 50       17 foreach my $v ( ref($val) ? @$val:$val ) {
289             ### TODO: should add quoting to $v if necessary
290 3         13 push @$hdr, Net::SIP::HeaderPair->new( $key,$v );
291             }
292 3         10 $self->_update_string();
293             }
294              
295             ###########################################################################
296             # Add header to SIP packet, header gets added before all other headers
297             # Args: ($self,$key,$val)
298             # $key: Header key
299             # $val: scalar or \@array which contains value(s)
300             ###########################################################################
301             sub insert_header {
302 304     304 1 1141 my ($self,$key,$val) = @_;
303 304         792 my $hdr = ($self->as_parts)[2];
304 304 50       1268 foreach my $v ( ref($val) ? @$val:$val ) {
305             ### TODO: should add quoting to $v if necessary
306 304         1301 unshift @$hdr, Net::SIP::HeaderPair->new( $key,$v );
307             }
308 304         827 $self->_update_string();
309             }
310              
311             ###########################################################################
312             # Delete all headers for a key
313             # Args: ($self,$key)
314             ###########################################################################
315             sub del_header {
316 0     0 1 0 my ($self,$key) = @_;
317 0         0 $key = _normalize_hdrkey($key);
318 0         0 my $hdr = ($self->as_parts)[2];
319 0         0 @$hdr = grep { $_->{key} ne $key } @$hdr;
  0         0  
320 0         0 $self->_update_string();
321             }
322              
323             ###########################################################################
324             # Set header for key to val, e.g. delete all remaining headers for key
325             # Args: ($self,$key,$val)
326             # $key: Header key
327             # $val: scalar or \@array which contains value(s)
328             ###########################################################################
329             sub set_header {
330 89     89 1 462 my ($self,$key,$val) = @_;
331 89         273 $key = _normalize_hdrkey($key);
332             # del_header
333 89         352 my $hdr = ($self->as_parts)[2];
334 89         300 @$hdr = grep { $_->{key} ne $key } @$hdr;
  645         1598  
335             # add_header
336 89 100       883 foreach my $v ( ref($val) ? @$val:$val ) {
337             ### TODO: should add quoting to $v if necessary
338 84         383 push @$hdr, Net::SIP::HeaderPair->new( $key,$v );
339             }
340 89         851 $self->_update_string();
341             }
342              
343             ###########################################################################
344             # set the body
345             # Args: ($self,$body)
346             # $body: string or object with method as_string (like Net::SIP::SDP)
347             # Returns: NONE
348             ###########################################################################
349             sub set_body {
350 0     0 1 0 my ($self,$body) = @_;
351 0 0       0 if ( ref($body)) {
352 0 0       0 if ( !$self->get_header( 'content-type' )) {
353 0         0 my $sub = UNIVERSAL::can( $body, 'content_type' );
354 0 0       0 $self->set_header( 'content-type' => $sub->($body) ) if $sub;
355             }
356 0         0 $body = $body->as_string;
357             }
358 0         0 $self->as_parts;
359 0         0 $self->{body} = $body;
360 0         0 $self->_update_string();
361             }
362              
363             ###########################################################################
364             # Iterate over all headers with sup and remove or manipulate them
365             # Args: ($self,@arg)
366             # @arg: either $key => $sub or only $sub
367             # if $key is given only headers for this key gets modified
368             # $sub is either \&code or [ \&code, @args ]
369             # code gets $pair (Net::SIP::HeaderPair) as last parameter
370             # to remove header it should call $pair->remove, if it modify
371             # header it should call $pair->set_modified
372             ###########################################################################
373             sub scan_header {
374 66     66 1 221 my Net::SIP::Packet $self = shift;
375 66 50       381 my $key = @_>1 ? _normalize_hdrkey(shift) : undef;
376 66         214 my $sub = shift;
377              
378 66 50       354 ($sub, my @args) = ref($sub) eq 'CODE' ? ($sub):@$sub;
379              
380 66         353 my $hdr = ($self->as_parts)[2];
381 66         387 foreach my $h (@$hdr) {
382 649 100 66     2573 next if $key && $h->{key} ne $key;
383             # in-place modify or delete (set key to undef)
384 67         300 $sub->(@args,$h);
385             }
386             # remove deleted entries ( !key ) from @$hdr
387 66         255 @$hdr = grep { $_->{key} } @$hdr;
  649         1388  
388 66         458 $self->_update_string();
389             }
390              
391             ###########################################################################
392             # Return packet as string
393             # tries to restore as much as possible from original packet (if created
394             # from string)
395             # Args: $self
396             # Returns: $packet_as_string
397             ###########################################################################
398             sub as_string {
399 316     316 1 642 my $self = shift;
400              
401             # check if content-length header is up-to-date
402 316   100     1749 my $body = $self->{body} || '';
403 316         932 my $cl = $self->get_header( 'content-length' );
404 316 50 33     1215 if ( defined($cl) && $cl != length($body) ) {
405 0         0 $self->set_header( 'content-length',length($body))
406             }
407              
408             # return immediately if request is up to date
409 316 100       852 return $self->{as_string} if $self->{as_string};
410              
411 303         665 my $header = $self->{header};
412              
413             # check if the lines from the original packet (if created
414             # from string, see as_parts) are up-to-date
415 303         488 my @result;
416 303 50       871 if ( my $lines = $self->{lines} ) {
417 0         0 for (my $i=0;$i<@$lines;$i++ ) {
418 0 0       0 my ($line,$count) = @{ $lines->[$i] || next };
  0         0  
419              
420             # check if $count entries for line-index $i in headers
421             my @hi = grep {
422 0         0 my $line = $header->[$_]{line};
  0         0  
423 0 0 0     0 ( defined($line) && $line == $i ) ? 1:0;
424             } (0..$#$header);
425 0 0       0 if ( @hi == $count ) {
    0          
426             # assume that line wasn't changed because the count is right
427 0         0 $result[ $hi[0] ] = $line;
428             } elsif ( @hi ) {
429             # some parts from this line have been modified
430             # place remaining parts back to same line
431 0         0 my $v = join( ", ", map { $header->[$_]{value} } @hi );
  0         0  
432 0         0 $v =~s{\r?\n\s*}{\r\n }g; # \r?\n\s* -> \r\n + space for continuation lines
433 0         0 my $r = $result[ $hi[0] ] = $header->[ $hi[0] ]{orig_key}.": ".$v;
434 0         0 $lines->[$i] = [ $r,int(@hi) ]; # and update $lines
435             } else {
436             # nothing remaining from line $i, update lines
437 0         0 delete $lines->[$i];
438             }
439             }
440             }
441              
442             # all lines from $header which had a defined line index should have been
443             # handled by the code above, now care about the lines w/o defined line
444 303         975 foreach my $hi ( grep { !defined( $header->[$_]{line} ) } (0..$#$header) ) {
  1844         3823  
445              
446 1844         3046 my $v = $header->[$hi]{value};
447 1844         2977 $v =~s{\r?\n\s*}{\r\n }g; # \r?\n\s* -> \r\n + space for continuation lines
448 1844         5326 $result[$hi] = ucfirst($header->[$hi]{key}).": ".$v;
449             }
450              
451             # (re)build packet
452             my $hdr_string = $self->{method}
453 303 100       1593 ? "$self->{method} $self->{text} SIP/2.0\r\n" # Request
454             : "SIP/2.0 $self->{code} $self->{text}\r\n"; # Response
455              
456 303         748 $hdr_string .= join( "\r\n", grep { $_ } @result )."\r\n";
  1844         3560  
457              
458             # add content-length header if there was none
459 303 50       2016 $hdr_string .= sprintf( "Content-length: %d\r\n", length( $body ))
460             if !defined($cl);
461              
462 303         2534 return ( $self->{as_string} = $hdr_string."\r\n".$body );
463             }
464              
465             ###########################################################################
466             # packet dump in long or short form, used mainly for debuging
467             # Args: ($self,?$level)
468             # $level: level of details: undef|0 -> one line, else -> as_string
469             # Returns: $dump_as_string
470             ###########################################################################
471             sub dump {
472 152     152 1 701 my Net::SIP::Packet $self = shift;
473 152         290 my $level = shift;
474 152 100       417 if ( !$level ) {
475 149 50       488 if ( $self->is_request ) {
476 149         394 my ($method,$text,$header,$body) = $self->as_parts;
477 149 100       1238 return "REQ $method $text ".( $body ? 'with body' :'' );
478             } else {
479 0         0 my ($code,$text,$header,$body) = $self->as_parts;
480 0 0       0 return "RESP $code '$text' ".( $body ? 'with body' :'' );
481             }
482             } else {
483 3         11 return $self->as_string
484             }
485             }
486              
487              
488             ###########################################################################
489             # Return parts
490             # Args: ($self)
491             # Returns: ($code_or_method,$text,$header,$body)
492             # $code_or_method: Response code or request method
493             # $text: Response text or request URI
494             # $header: Header representation as array
495             # [ [key1 => val2],[key2 => val2],... ] where the same
496             # key can occure multiple times
497             # $body: Body as string
498             # Comment:
499             # Output from this method is directly usable as input to new_from_parts
500             ###########################################################################
501             sub as_parts {
502 7977     7977 1 11809 my $self = shift;
503              
504             # if parts are up to date return immediately
505 7977 50       15830 if ( ! $self->{header} ) {
506 0         0 my $data = _string2parts( $self->{as_string} );
507 0         0 %$self = ( %$self,%$data );
508             }
509 7977 100       14885 return @{$self}{qw(method text header body)} if $self->{method};
  5041         17507  
510 2936         3915 return @{$self}{qw(code text header body)};
  2936         8777  
511             }
512              
513             {
514             my $word_rx = qr{[\w\-\.!%\*+`'~()<>:"/?{}\x1c\x1b\x1d]+};
515             my $callid_rx = qr{^$word_rx(?:\@$word_rx)?$};
516             my %key2parser = (
517              
518             # FIXME: More of these should be more strict to filter out invalid values
519             # for now they are only given here to distinguish them from the keys, which
520             # can be given multiple times either on different lines or on the same delimited
521             # by comma
522              
523             'www-authenticate' => \&_hdrkey_parse_keep,
524             'authorization' => \&_hdrkey_parse_keep,
525             'proxy-authenticate' => \&_hdrkey_parse_keep,
526             'proxy-authorization' => \&_hdrkey_parse_keep,
527             'date' => \&_hdrkey_parse_keep,
528             'content-disposition' => \&_hdrkey_parse_keep,
529             'content-type' => \&_hdrkey_parse_keep,
530             'mime-version' => \&_hdrkey_parse_keep,
531             'organization' => \&_hdrkey_parse_keep,
532             'priority' => \&_hdrkey_parse_keep,
533             'reply-to' => \&_hdrkey_parse_keep,
534             'retry-after' => \&_hdrkey_parse_keep,
535             'server' => \&_hdrkey_parse_keep,
536             'to' => \&_hdrkey_parse_keep,
537             'user-agent' => \&_hdrkey_parse_keep,
538              
539             'content-length' => \&_hdrkey_parse_num,
540             'expires' => \&_hdrkey_parse_num,
541             'max-forwards' => \&_hdrkey_parse_num,
542             'min-expires' => \&_hdrkey_parse_num,
543              
544             'via' => \&_hdrkey_parse_comma_seperated,
545             'contact' => \&_hdrkey_parse_comma_seperated,
546             'record-route' => \&_hdrkey_parse_comma_seperated,
547             'route' => \&_hdrkey_parse_comma_seperated,
548             'allow' => \&_hdrkey_parse_comma_seperated,
549             'supported' => \&_hdrkey_parse_comma_seperated,
550             'unsupported' => \&_hdrkey_parse_comma_seperated,
551              
552             'in-reply-to' => \&_hdrkey_parse_comma_seperated,
553             'accept' => \&_hdrkey_parse_comma_seperated,
554             'accept-encoding' => \&_hdrkey_parse_comma_seperated,
555             'accept-language' => \&_hdrkey_parse_comma_seperated,
556             'proxy-require' => \&_hdrkey_parse_comma_seperated,
557             'require' => \&_hdrkey_parse_comma_seperated,
558             'content-encoding' => \&_hdrkey_parse_comma_seperated,
559             'content-language' => \&_hdrkey_parse_comma_seperated,
560             'alert-info' => \&_hdrkey_parse_comma_seperated,
561             'call-info' => \&_hdrkey_parse_comma_seperated,
562             'error-info' => \&_hdrkey_parse_comma_seperated,
563             'error-info' => \&_hdrkey_parse_comma_seperated,
564             'warning' => \&_hdrkey_parse_comma_seperated,
565              
566             'call-id' => sub {
567             $_[0] =~ $callid_rx or
568             die "invalid callid, should be 'word [@ word]'\n";
569             return $_[0];
570             },
571             'cseq' => sub {
572             $_[0] =~ m{^\d+\s+\w+\s*$} or
573             die "invalid cseq, should be 'number method'\n";
574             return $_[0];
575             },
576             );
577              
578             my %once = map { ($_ => 1) }
579             qw(cseq content-type from to call-id content-length);
580             my %key2check = (
581             rsp => undef,
582             req => {
583             cseq => sub {
584             my ($v,$result) = @_;
585             $v =~ m{^\d+\s+(\w+)\s*$} or
586             die "invalid cseq, should be 'number method'\n";
587             $result->{method} eq $1 or
588             die "method in cseq does not match method of request\n";
589             },
590             }
591             );
592              
593 495     495   1116 sub _hdrkey_parse_keep { return $_[0] };
594             sub _hdrkey_parse_num {
595 253     253   747 my ($v,$k) = @_;
596 253 50       1285 $v =~m{^(\d+)\s*$} || die "invalid $k, should be number\n";
597 253         1067 return $1;
598             };
599              
600             sub _hdrkey_parse_comma_seperated {
601 371     371   969 my ($v,$k) = @_;
602 371         1093 my @v = ( '' );
603 371         865 my $quote = '';
604             # split on komma (but not if quoted)
605 371         648 while (1) {
606 602 100       3810 if ( $quote ) {
    100          
607 5 50       106 if ( $v =~m{\G(.*?)(\\|$quote)}gc ) {
608 5 50       29 if ( $2 eq "\\" ) {
609 0         0 $v[-1].=$1.$2.substr( $v,pos($v),1 );
610 0         0 pos($v)++;
611             } else {
612 5         18 $v[-1].=$1.$2;
613 5         14 $quote = '';
614             }
615             } else {
616             # missing end-quote
617 0         0 die "missing '$quote' in '$v'\n";
618             }
619             } elsif ( $v =~m{\G(.*?)([\\"<,])}gc ) {
620 226 100       845 if ( $2 eq "\\" ) {
    100          
621 5         23 $v[-1].=$1.$2.substr( $v,pos($v),1 );
622 5         20 pos($v)++;
623             } elsif ( $2 eq ',' ) {
624             # next item if not quoted
625 216         664 ( $v[-1].=$1 ) =~s{\s+$}{}; # strip trailing space
626 216 50       807 push @v,'' if !$quote;
627 216         624 $v =~m{\G\s+}gc; # skip space after ','
628             } else {
629 5         15 $v[-1].=$1.$2;
630 5 50       23 $quote = $2 eq '<' ? '>':$2;
631             }
632             } else {
633             # add rest to last from @v
634 371   100     2318 $v[-1].= substr($v,pos($v)||0 );
635 371         775 last;
636             }
637             }
638 371         1255 return @v;
639             }
640              
641             sub _string2parts {
642 213     213   544 my $string = shift;
643 213         1127 my %result = ( as_string => $string );
644              
645             # otherwise parse request
646 213         3515 my ($header,$body) = split( m{\r?\n\r?\n}, $string,2 );
647 213         2635 my @header = split( m{\r?\n}, $header );
648              
649 213         581 my $key2check;
650 213 100       2453 if ( $header[0] =~m{^SIP/2.0\s+(\d+)\s+(\S.*?)\s*$} ) {
    50          
651             # Response, e.g. SIP/2.0 407 Authorization required
652 139         727 $result{code} = $1;
653 139         476 $result{text} = $2;
654 139         386 $key2check = $key2check{rsp};
655             } elsif ( $header[0] =~m{^(\w+)\s+(\S.*?)\s+SIP/2\.0\s*$} ) {
656             # Request, e.g. INVITE SIP/2.0
657 74         663 $result{method} = $1;
658 74         541 $result{text} = $2;
659 74         335 $key2check = $key2check{req};
660             } else {
661 0         0 die "bad request: starts with '$header[0]'\n";
662             }
663 213         441 shift(@header);
664              
665 213         751 $result{body} = $body;
666              
667 213         1007 my @hdr;
668             my @lines;
669 213         0 my @check;
670 213         0 my %check_once;
671 213         699 while (@header) {
672 1547 50       11703 my ($k,$v) = $header[0] =~m{^([^\s:]+)\s*:\s*(.*)}
673             or die "bad header line $header[0]\n";
674 1547         3194 my $line = shift(@header);
675 1547   66     6992 while ( @header && $header[0] =~m{^\s+(.*)} ) {
676             # continuation line
677 0         0 $v .= "\n$1";
678 0         0 $line .= shift(@header);
679             }
680 1547         3486 my $nk = _normalize_hdrkey($k);
681              
682 1547         3834 my $parse = $key2parser{$nk};
683 1547 100       5187 my @v = $parse ? $parse->($v,$nk) : _hdrkey_parse_keep($v,$nk);
684 1547 100       3404 if ( @v>1 ) {
685 54         252 for( my $i=0;$i<@v;$i++ ) {
686 270         768 push @hdr, Net::SIP::HeaderPair->new( $k,$v[$i],scalar(@lines),$i );
687             }
688             } else {
689 1493         4448 push @hdr, Net::SIP::HeaderPair->new( $k,$v[0],scalar(@lines) );
690             }
691 1547 100       3809 if (my $k2c = $key2check->{$nk}) {
692 75         322 push @check, [ $k2c, $_ ] for @v;
693             }
694 1547 100       3740 if ($once{$nk}) {
695             ($check_once{$nk} //= $_) eq $_ or
696             die "conflicting definition of $nk\n"
697 1122   100     6287 for @v;
      100        
698             }
699 1542         5944 push @lines, [ $line, int(@v) ];
700             }
701 208         670 $result{header} = \@hdr;
702 208         613 $result{lines} = \@lines;
703 208         543 for(@check) {
704 69         247 my ($sub,$v) = @$_;
705 69         293 $sub->($v,\%result);
706             }
707 207         1023 return \%result;
708             }
709             }
710              
711             ###########################################################################
712             # return SDP body
713             # Args: $self
714             # Returns: $body
715             # $body: Net::SIP::SDP object if body exists and content-type is
716             # application/sdp (or not defined)
717             ###########################################################################
718             sub sdp_body {
719 60     60 1 165 my Net::SIP::Packet $self = shift;
720 60         189 my $ct = $self->get_header( 'content-type' );
721 60 50 66     827 return if $ct && lc($ct) ne 'application/sdp';
722 60   100     244 my $body = ($self->as_parts)[3] || return;
723 44         636 return Net::SIP::SDP->new( $body );
724             }
725              
726             ###########################################################################
727             # clone packet, so that modification does not affect the original
728             # Args: $self
729             # Returns: $clone
730             ###########################################################################
731             sub clone {
732 115     115 1 17438 return Storable::dclone( shift );
733             }
734              
735             ###########################################################################
736             # Trigger updating parts, e.g. code, method, header...
737             # done by setting header as undef if as_string is set, so the next time
738             # I'll try to access code it will be recalculated from string
739             # Args: $self
740             ###########################################################################
741             sub _update_parts {
742 0     0   0 my $self = shift;
743 0 0       0 $self->{header} = undef if $self->{as_string};
744             }
745              
746             ###########################################################################
747             # Trigger updating string
748             # done by setting as_string as undef if header is set, so the next time
749             # I'll try to access as_string it will be recalculated from the parts
750             # Args: $self
751             ###########################################################################
752             sub _update_string {
753 490     490   920 my $self = shift;
754 490 50       2072 $self->{as_string} = undef if $self->{header};
755             }
756              
757             ###########################################################################
758             # access _normalize_hdrkey function from Net::SIP::HeaderPair
759             # Args: $key
760             # Returns: $key_normalized
761             ###########################################################################
762             sub _normalize_hdrkey {
763 7671     7671   18345 goto &Net::SIP::HeaderPair::_normalize_hdrkey
764             }
765              
766             ###########################################################################
767             # Net::SIP::HeaderPair
768             # container for normalized key,value and some infos to restore
769             # string representation
770             ###########################################################################
771              
772             package Net::SIP::HeaderPair;
773 42     42   186811 use fields qw( key value orig_key line pos );
  42         1941  
  42         308  
774              
775             # key: normalized key: lower case, not compact
776             # value: value
777             # orig_key: original key: can be mixed case and compact
778             # line: index of header line within original request
779             # pos: relativ position in line (starting with 0) if multiple
780             # values are given in one line
781              
782             ###########################################################################
783             # Create new HeaderPair
784             # Args: ($class,$key,$value,$line,$pos)
785             # $key: original key
786             # $value: value
787             # $line: index of header line in original header
788             # $pos: index within header line if multiple values are in line
789             # Returns: $self
790             ###########################################################################
791             sub new {
792 2990     2990   6866 my ($class,$key,$value,$line,$pos) = @_;
793 2990         7159 my $self = fields::new( $class );
794 2990         191832 $self->{key} = _normalize_hdrkey( $key);
795 2990         6338 $self->{value} = $value;
796 2990         4787 $self->{orig_key} = $key;
797 2990         4297 $self->{line} = $line;
798 2990         4265 $self->{pos} = $pos;
799 2990         8090 return $self;
800             }
801              
802             ###########################################################################
803             # Mark HeaderPair as removed by setting key to undef
804             # used from Net::SIP:Packet::scan_header
805             # Args: $self
806             ###########################################################################
807             sub remove {
808             # mark es removed
809             shift->{key} = undef
810 1     1   4 }
811              
812             ###########################################################################
813             # Mark HeaderPair as modified by setting line to undef and thus deassociating
814             # it from the original header line
815             # Args: $self
816             ###########################################################################
817             sub set_modified {
818             # mark as modified
819 0     0   0 my $self = shift;
820 0         0 $self->{line} = $self->{pos} = undef;
821             }
822              
823              
824             {
825             my %alias = (
826             i => 'call-id',
827             m => 'contact',
828             e => 'content-encoding',
829             l => 'content-length',
830             c => 'content-type',
831             f => 'from',
832             s => 'subject',
833             k => 'supported',
834             t => 'to',
835             v => 'via',
836             );
837             sub _normalize_hdrkey {
838 10661     10661   19720 my $key = lc(shift);
839 10661   33     40345 return $alias{$key} || $key;
840             }
841             }
842              
843              
844             ###########################################################################
845             # Net::SIP::HeaderVal;
846             # gives string representation and hash representation
847             # (split by ';' or ',') of header value
848             ###########################################################################
849              
850             package Net::SIP::HeaderVal;
851 42     42   13558 use Net::SIP::Util qw(sip_hdrval2parts);
  42         131  
  42         2705  
852 42     42   359 use fields qw( data parameter );
  42         82  
  42         231  
853              
854             # WWW-Authenticate: Digest method="md5",qop="auth",...
855             # To: Bob Example ;tag=2626262;...
856             #
857             # data: the part before the first argument, e.g. "Digest" or
858             # "Bob Example "
859             # parameter: hash of parameters, e.g { method => md5, qop => auth }
860             # or { tag => 2626262, ... }
861              
862             ###########################################################################
863             # create new object from string
864             # knows which headers have ',' as delimiter and the rest uses ';'
865             # Args: ($class,$pair)
866             # $pair: Net::SIP::HeaderPair
867             # Returns: $self
868             ###########################################################################
869             sub new {
870 3     3   9 my $class = shift;
871 3         6 my Net::SIP::HeaderPair $pair = shift;
872 3         8 my $key = $pair->{key};
873 3         8 my $v = $pair->{value};
874              
875 3         12 my $self = fields::new($class);
876 3         267 ($self->{data}, $self->{parameter}) = sip_hdrval2parts( $key,$v );
877              
878 3         14 return $self;
879             }
880              
881              
882              
883              
884             1;