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 44     44   55662 use strict;
  44         86  
  44         1040  
7 44     44   178 use warnings;
  44         75  
  44         1215  
8              
9             package Net::SIP::Packet;
10              
11 44     44   525 use Net::SIP::Debug;
  44         65  
  44         277  
12 44     44   24520 use Storable;
  44         118696  
  44         2184  
13 44     44   18926 use Net::SIP::SDP;
  44         140  
  44         1709  
14 44     44   311 use Carp 'croak';
  44         94  
  44         2098  
15              
16 44     44   653 use fields qw( code method text header lines body as_string );
  44         1320  
  44         285  
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 593     593 1 7518 my $class = shift;
45 593 100       2647 return $class->new_from_parts(@_) if @_>1;
46 407 100 66     2281 return $class->new_from_string(@_) if @_ && !ref($_[0]);
47 398         1470 my $self = fields::new($class);
48 398 50       54945 %$self = %{$_[0]} if @_;
  398         1784  
49 398         1844 return $self;
50             }
51              
52             sub _new_request {
53 189     189   362 shift;
54 189         14876 return Net::SIP::Request->new(@_);
55             }
56              
57             sub _new_response {
58 209     209   399 shift;
59 209         1289 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 186     186 1 836 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 186 50       932 if ( UNIVERSAL::isa( $header,'HASH' )) {
85 186         394 my @hnew;
86 186         1356 foreach my $key ( sort keys %$header ) {
87 1044         1621 my $v = $header->{$key};
88 1044 100       1980 foreach my $value ( ref($v) ? @$v : ($v) ) {
89 884         8850 push @hnew,[ $key,$value ];
90             }
91             }
92 186         488 $header = \@hnew;
93             }
94              
95 186 100       2359 my $self = $code =~m{^\d}
96             ? $class->_new_response({ code => $code })
97             : $class->_new_request({ method => uc($code) });
98 186 50       897 $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 186         331 my @hnew;
105 186         420 my $normalized = 0;
106 186         966 for( my $i=0;$i<@$header;$i++ ) {
107 884         1316 my $h = $header->[$i];
108 884 50       2125 if ( UNIVERSAL::isa($h,'Net::SIP::HeaderPair')) {
109             # already normalized
110 0         0 $normalized = 1;
111 0         0 push @hnew,$h;
112             } else {
113 884         1612 my ($key,$value) = @$h;
114 884 50       1687 defined($value) || next;
115 884 50       1502 croak( "mix between normalized and not normalized data in header" ) if $normalized;
116 884         2432 push @hnew, Net::SIP::HeaderPair->new( $key,$value ) ;
117             }
118             }
119              
120 186         415 $self->{header} = \@hnew;
121             # as_string is still undef, it will be evaluated once we call as_string()
122              
123 186 100       505 if ( ref($body)) {
124 56 50       695 if ( !$self->get_header( 'content-type' )) {
125 56         298 my $sub = UNIVERSAL::can( $body, 'content_type' );
126 56 50       489 $self->set_header( 'content-type' => $sub->($body) ) if $sub;
127             }
128 56         264 $body = $body->as_string;
129             }
130 186         387 $self->{body} = $body;
131              
132 186         1808 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 218     218 1 1110 my ($class,$string) = @_;
145 218         1555 my $data = _string2parts($string);
146             return $data->{method}
147 212 100       1337 ? $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 1127     1127 1 1818 my Net::SIP::Packet $self = shift;
184 1127         2964 $self->get_header( 'cseq' ) =~m{^(\d+)};
185 1127         5139 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 396     396 1 973 sub cseq { scalar( shift->get_header('cseq')) }
198              
199             ###########################################################################
200             # Access call-id Header
201             # Args: $self
202             # Returns: $callid
203             ###########################################################################
204 196     196 1 692 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 6181     6181 1 12866 my ($self,$key) = @_;
218 6181         11623 my $hdr = ($self->as_parts)[2];
219 6181 50       10600 if ( $key ) {
220 6181         9478 $key = _normalize_hdrkey($key);
221 6181         9171 my @v;
222 6181         14367 foreach my $h (@$hdr) {
223 44688 100       88983 push @v,$h->{value} if $h->{key} eq $key;
224             }
225 6181 100       14769 return @v if wantarray;
226 4140 50       7483 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 4140         19739 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 17 my ($self,$key) = @_;
258 9         116 my $hdr = ($self->as_parts)[2];
259 9 50       19 if ( $key ) {
260 9         18 $key = _normalize_hdrkey($key);
261 9         16 my @v;
262 9         14 foreach my $h (@$hdr) {
263             push @v,Net::SIP::HeaderVal->new( $h )
264 59 100       107 if $h->{key} eq $key;
265             }
266 9 50       43 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 8 my ($self,$key,$val) = @_;
287 3         10 my $hdr = ($self->as_parts)[2];
288 3 50       11 foreach my $v ( ref($val) ? @$val:$val ) {
289             ### TODO: should add quoting to $v if necessary
290 3         10 push @$hdr, Net::SIP::HeaderPair->new( $key,$v );
291             }
292 3         8 $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 315     315 1 1273 my ($self,$key,$val) = @_;
303 315         700 my $hdr = ($self->as_parts)[2];
304 315 50       1161 foreach my $v ( ref($val) ? @$val:$val ) {
305             ### TODO: should add quoting to $v if necessary
306 315         992 unshift @$hdr, Net::SIP::HeaderPair->new( $key,$v );
307             }
308 315         700 $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 95     95 1 337 my ($self,$key,$val) = @_;
331 95         217 $key = _normalize_hdrkey($key);
332             # del_header
333 95         347 my $hdr = ($self->as_parts)[2];
334 95         313 @$hdr = grep { $_->{key} ne $key } @$hdr;
  695         1328  
335             # add_header
336 95 100       808 foreach my $v ( ref($val) ? @$val:$val ) {
337             ### TODO: should add quoting to $v if necessary
338 90         324 push @$hdr, Net::SIP::HeaderPair->new( $key,$v );
339             }
340 95         763 $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 71     71 1 180 my Net::SIP::Packet $self = shift;
375 71 50       328 my $key = @_>1 ? _normalize_hdrkey(shift) : undef;
376 71         267 my $sub = shift;
377              
378 71 50       593 ($sub, my @args) = ref($sub) eq 'CODE' ? ($sub):@$sub;
379              
380 71         381 my $hdr = ($self->as_parts)[2];
381 71         277 foreach my $h (@$hdr) {
382 698 100 66     2049 next if $key && $h->{key} ne $key;
383             # in-place modify or delete (set key to undef)
384 72         249 $sub->(@args,$h);
385             }
386             # remove deleted entries ( !key ) from @$hdr
387 71         179 @$hdr = grep { $_->{key} } @$hdr;
  698         1106  
388 71         399 $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 328     328 1 698 my $self = shift;
400              
401             # check if content-length header is up-to-date
402 328   100     1723 my $body = $self->{body} || '';
403 328         754 my $cl = $self->get_header( 'content-length' );
404 328 50 33     1094 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 328 100       795 return $self->{as_string} if $self->{as_string};
410              
411 317         522 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 317         391 my @result;
416 317 50       831 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 317         843 foreach my $hi ( grep { !defined( $header->[$_]{line} ) } (0..$#$header) ) {
  1928         3398  
445              
446 1928         2900 my $v = $header->[$hi]{value};
447 1928         2892 $v =~s{\r?\n\s*}{\r\n }g; # \r?\n\s* -> \r\n + space for continuation lines
448 1928         5355 $result[$hi] = ucfirst($header->[$hi]{key}).": ".$v;
449             }
450              
451             # (re)build packet
452             my $hdr_string = $self->{method}
453 317 100       2487 ? "$self->{method} $self->{text} SIP/2.0\r\n" # Request
454             : "SIP/2.0 $self->{code} $self->{text}\r\n"; # Response
455              
456 317         1072 $hdr_string .= join( "\r\n", grep { $_ } @result )."\r\n";
  1928         3160  
457              
458             # add content-length header if there was none
459 317 50       18310 $hdr_string .= sprintf( "Content-length: %d\r\n", length( $body ))
460             if !defined($cl);
461              
462 317         2012 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 153     153 1 289 my Net::SIP::Packet $self = shift;
473 153         302 my $level = shift;
474 153 100       358 if ( !$level ) {
475 150 50       606 if ( $self->is_request ) {
476 150         430 my ($method,$text,$header,$body) = $self->as_parts;
477 150 100       2217 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         8 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 8278     8278 1 28220 my $self = shift;
503              
504             # if parts are up to date return immediately
505 8278 50       15194 if ( ! $self->{header} ) {
506 0         0 my $data = _string2parts( $self->{as_string} );
507 0         0 %$self = ( %$self,%$data );
508             }
509 8278 100       15007 return @{$self}{qw(method text header body)} if $self->{method};
  5256         24781  
510 3022         3617 return @{$self}{qw(code text header body)};
  3022         10251  
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 508     508   1204 sub _hdrkey_parse_keep { return $_[0] };
594             sub _hdrkey_parse_num {
595 261     261   759 my ($v,$k) = @_;
596 261 50       1182 $v =~m{^(\d+)\s*$} || die "invalid $k, should be number\n";
597 261         1343 return $1;
598             };
599              
600             sub _hdrkey_parse_comma_seperated {
601 388     388   939 my ($v,$k) = @_;
602 388         1278 my @v = ( '' );
603 388         902 my $quote = '';
604             # split on komma (but not if quoted)
605 388         510 while (1) {
606 635 100       3800 if ( $quote ) {
    100          
607 5 50       86 if ( $v =~m{\G(.*?)(\\|$quote)}gc ) {
608 5 50       14 if ( $2 eq "\\" ) {
609 0         0 $v[-1].=$1.$2.substr( $v,pos($v),1 );
610 0         0 pos($v)++;
611             } else {
612 5         23 $v[-1].=$1.$2;
613 5         10 $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 242 100       726 if ( $2 eq "\\" ) {
    100          
621 5         19 $v[-1].=$1.$2.substr( $v,pos($v),1 );
622 5         17 pos($v)++;
623             } elsif ( $2 eq ',' ) {
624             # next item if not quoted
625 232         590 ( $v[-1].=$1 ) =~s{\s+$}{}; # strip trailing space
626 232 50       573 push @v,'' if !$quote;
627 232         602 $v =~m{\G\s+}gc; # skip space after ','
628             } else {
629 5         12 $v[-1].=$1.$2;
630 5 50       10 $quote = $2 eq '<' ? '>':$2;
631             }
632             } else {
633             # add rest to last from @v
634 388   100     2194 $v[-1].= substr($v,pos($v)||0 );
635 388         1099 last;
636             }
637             }
638 388         1038 return @v;
639             }
640              
641             sub _string2parts {
642 218     218   686 my $string = shift;
643 218         1057 my %result = ( as_string => $string );
644              
645             # otherwise parse request
646 218         3616 my ($header,$body) = split( m{\r?\n\r?\n}, $string,2 );
647 218         3003 my @header = split( m{\r?\n}, $header );
648              
649 218         793 my $key2check;
650 218 100       2228 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         671 $result{code} = $1;
653 139         450 $result{text} = $2;
654 139         463 $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 79         614 $result{method} = $1;
658 79         519 $result{text} = $2;
659 79         397 $key2check = $key2check{req};
660             } else {
661 0         0 die "bad request: starts with '$header[0]'\n";
662             }
663 218         530 shift(@header);
664              
665 218         870 $result{body} = $body;
666              
667 218         885 my @hdr;
668             my @lines;
669 218         0 my @check;
670 218         0 my %check_once;
671 218         605 while (@header) {
672 1595 50       11461 my ($k,$v) = $header[0] =~m{^([^\s:]+)\s*:\s*(.*)}
673             or die "bad header line $header[0]\n";
674 1595         2809 my $line = shift(@header);
675 1595   66     8066 while ( @header && $header[0] =~m{^\s+(.*)} ) {
676             # continuation line
677 0         0 $v .= "\n$1";
678 0         0 $line .= shift(@header);
679             }
680 1595         3332 my $nk = _normalize_hdrkey($k);
681              
682 1595         3448 my $parse = $key2parser{$nk};
683 1595 100       5243 my @v = $parse ? $parse->($v,$nk) : _hdrkey_parse_keep($v,$nk);
684 1595 100       2974 if ( @v>1 ) {
685 58         209 for( my $i=0;$i<@v;$i++ ) {
686 290         641 push @hdr, Net::SIP::HeaderPair->new( $k,$v[$i],scalar(@lines),$i );
687             }
688             } else {
689 1537         4189 push @hdr, Net::SIP::HeaderPair->new( $k,$v[0],scalar(@lines) );
690             }
691 1595 100       3572 if (my $k2c = $key2check->{$nk}) {
692 80         316 push @check, [ $k2c, $_ ] for @v;
693             }
694 1595 100       3865 if ($once{$nk}) {
695             ($check_once{$nk} //= $_) eq $_ or
696             die "conflicting definition of $nk\n"
697 1151   100     5748 for @v;
      100        
698             }
699 1590         6213 push @lines, [ $line, int(@v) ];
700             }
701 213         710 $result{header} = \@hdr;
702 213         741 $result{lines} = \@lines;
703 213         508 for(@check) {
704 74         193 my ($sub,$v) = @$_;
705 74         266 $sub->($v,\%result);
706             }
707 212         1279 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 66     66 1 167 my Net::SIP::Packet $self = shift;
720 66         259 my $ct = $self->get_header( 'content-type' );
721 66 50 66     533 return if $ct && lc($ct) ne 'application/sdp';
722 66   100     233 my $body = ($self->as_parts)[3] || return;
723 48         622 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 117     117 1 15857 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 514     514   803 my $self = shift;
754 514 50       1766 $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 7951     7951   17390 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 44     44   163754 use fields qw( key value orig_key line pos );
  44         98  
  44         1979  
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 3119     3119   5838 my ($class,$key,$value,$line,$pos) = @_;
793 3119         7699 my $self = fields::new( $class );
794 3119         211779 $self->{key} = _normalize_hdrkey( $key);
795 3119         6411 $self->{value} = $value;
796 3119         4627 $self->{orig_key} = $key;
797 3119         4222 $self->{line} = $line;
798 3119         3956 $self->{pos} = $pos;
799 3119         7762 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   2 }
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 11070     11070   18942 my $key = lc(shift);
839 11070   33     36652 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 44     44   11853 use Net::SIP::Util qw(sip_hdrval2parts);
  44         120  
  44         2365  
852 44     44   319 use fields qw( data parameter );
  44         82  
  44         224  
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   7 my $class = shift;
871 3         5 my Net::SIP::HeaderPair $pair = shift;
872 3         7 my $key = $pair->{key};
873 3         5 my $v = $pair->{value};
874              
875 3         10 my $self = fields::new($class);
876 3         207 ($self->{data}, $self->{parameter}) = sip_hdrval2parts( $key,$v );
877              
878 3         9 return $self;
879             }
880              
881              
882              
883              
884             1;