2 # Copyright (C) 2006-2008 Georgia Public Library Service
4 # Author: David J. Fiander
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of version 2 of the GNU General Public
8 # License as published by the Free Software Foundation.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public
16 # License along with this program; if not, write to the Free
17 # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 package Sip::Checksum;
25 use integer; # important
28 our @EXPORT_OK = qw(checksum verify_cksum);
29 our @ISA = qw(Exporter);
35 printf STDERR "# %16s: %016s %4.4s %6s\n",
37 substr(sprintf("%b", $var), -16),
38 uc substr(sprintf("%4.4x",$var), -4),
42 sub debug_split_print {
46 foreach(split('', $line)) {
49 if (scalar(@row) == 10) {
54 scalar(@row) and push @rows, \@row;
57 print map {" $_ "} @$_;
58 printf "\n%-50s", join '', map {sprintf " %3d ", $_} map {$subtotal += ord($_); ord($_)} @$_;
59 printf "= %4d\n\n", $subtotal;
61 printf "%56d\n", $total;
68 my $u = unpack('%16C*', $pkt);
69 my $check = ($u * -1) & 0xFFFF;
71 my $total = debug_split_print($pkt);
72 $total == $u or warn "Internal error: mismatch between $total and $u";
73 printf STDERR "# checksum('$pkt')\n# %34s HEX DECIMAL\n", 'BINARY';
74 debug_print("ascii sum", $u );
75 debug_print("binary invert", ~$u );
76 debug_print("add one", ~$u+1);
77 printf STDERR "# %39s\n", $check;
80 return sprintf("%4.4X", $check);
88 return 0 if (not defined($pkt) or substr($pkt, -6, 2) ne "AZ"); # No checksum at end
90 # Convert the checksum back to hex and calculate the sum of the
91 # pack without the checksum.
92 $cksum = hex(substr($pkt, -4));
93 $shortsum = unpack("%16C*", substr($pkt, 0, -4));
95 # The checksum is valid if the hex sum, plus the checksum of the
96 # base packet short when truncated to 16 bits.
97 return (($cksum + $shortsum) & 0xFFFF) == 0;
105 # Some simple test data
109 my $cksum = checksum($testpkt);
110 my $fullpkt = sprintf("%s%4X", $testpkt, $cksum);
112 print $fullpkt, "\n";