File Coverage

blib/lib/RPC/PlServer/Comm.pm
Criterion Covered Total %
statement 43 70 61.4
branch 17 38 44.7
condition 3 9 33.3
subroutine 4 5 80.0
pod 0 4 0.0
total 67 126 53.1


line stmt bran cond sub pod time code
1             # -*- perl -*-
2             #
3             #
4             # PlRPC - Perl RPC, package for writing simple, RPC like clients and
5             # servers
6             #
7             #
8             # Copyright (c) 1997,1998 Jochen Wiedmann
9             #
10             # You may distribute under the terms of either the GNU General Public
11             # License or the Artistic License, as specified in the Perl README file.
12             #
13             # Author: Jochen Wiedmann
14             # Email: jochen.wiedmann at freenet.de
15             #
16              
17             require 5.004;
18 4     4   710 use strict;
  4         8  
  4         3873  
19              
20             require Storable;
21              
22              
23             package RPC::PlServer::Comm;
24              
25              
26             $RPC::PlServer::Comm::VERSION = '0.1003';
27              
28              
29             ############################################################################
30             #
31             # Name: new (Class method)
32             #
33             # Purpose: Constructor
34             #
35             # Inputs: $class - This class
36             # $attr - Hash ref of attributes
37             #
38             # Result: Server object for success, error message otherwise
39             #
40             ############################################################################
41              
42             sub new ($) {
43 5     5 0 20 my($class, $attr) = @_;
44 5         20 my $self = {};
45 5   33     70 bless($self, (ref($class) || $class));
46              
47 5 100       150 if (my $comp = $attr->{'compression'}) {
48 2 50       52 if ($comp eq 'off') {
    50          
49 0         0 $self->{'compression'} = undef;
50             } elsif ($comp eq 'gzip') {
51 2         34 require Compress::Zlib;
52 2         15 $self->{'compression'} = 'gzip';
53             } else {
54 0         0 die "Unknown compression type ($comp), use 'off' or 'gzip'";
55             }
56             }
57 5 50       32 if (my $cipher = $attr->{'cipher'}) {
58 0         0 $self->{'cipher'} = $cipher;
59             }
60 5 50       24 if (my $maxmessage = $attr->{'maxmessage'}) {
61 0         0 $self->{'maxmessage'} = $maxmessage;
62             }
63              
64 5         28 $self;
65             }
66              
67              
68             ############################################################################
69             #
70             # Name: Write
71             #
72             # Purpose: Writing to a PlRPC socket; used by both the client (when
73             # sending a method name and arguments) and the server (for
74             # sending the result list). Communication occurrs in packets.
75             # Each packet is preceeded by 4 bytes with the true packet
76             # size. If encryption happens, then the packet is padded with
77             # NUL bytes to a multiple of blocksize bytes. However, the
78             # stored size remains unchanged.
79             #
80             # Inputs: $self - Instance of RPC::PlServer or RPC::PlClient
81             # $socket - The socket to write to
82             # $args - Reference to array of arguments being sent
83             #
84             # Result: Nothing; dies in case of errors.
85             #
86             ############################################################################
87              
88             sub Write ($$$) {
89 42     42 0 90 my($self, $socket, $msg) = @_;
90              
91 42         147 my $encodedMsg = Storable::nfreeze($msg);
92 42 100       2341 $encodedMsg = Compress::Zlib::compress($encodedMsg)
93             if ($self->{'compression'});
94              
95 42         10754 my($encodedSize) = length($encodedMsg);
96 42 50       137 if (my $cipher = $self->{'cipher'}) {
97 0         0 my $size = $cipher->blocksize;
98 0 0       0 if (my $addSize = length($encodedMsg) % $size) {
99 0         0 $encodedMsg .= chr(0) x ($size - $addSize);
100             }
101 0         0 $msg = '';
102 0         0 for (my $i = 0; $i < length($encodedMsg); $i += $size) {
103 0         0 $msg .= $cipher->encrypt(substr($encodedMsg, $i, $size));
104             }
105 0         0 $encodedMsg = $msg;
106             }
107              
108 42         162 local $\;
109 42 50 33     8449 if (!$socket->print(pack("N", $encodedSize), $encodedMsg) ||
110             !$socket->flush()) {
111 0         0 die "Error while writing socket: $!";
112             }
113             }
114              
115              
116             ############################################################################
117             #
118             # Name: Read
119             #
120             # Purpose: Reading from a PlRPC socket; used by both the client (when
121             # receiving a result list) and the server (for receiving the
122             # method name and arguments). Counterpart of Write, see
123             # above for specs.
124             #
125             # Inputs: $self - Instance of RPC::PlServer or RPC::PlClient
126             # $socket - The socket to read from
127             #
128             # Result: Array ref to result list; dies in case of errors.
129             #
130             ############################################################################
131              
132             sub Read($$) {
133 42     42 0 72 my($self, $socket) = @_;
134 42         42 my $result;
135              
136 42         50 my($encodedSize, $readSize, $blockSize);
137 42         60 $readSize = 4;
138 42         64 $encodedSize = '';
139 42         115 while ($readSize > 0) {
140 42         184 my $result = $socket->read($encodedSize, $readSize,
141             length($encodedSize));
142 42 50       5817 if (!$result) {
143 0 0       0 return undef if defined($result);
144 0         0 die "Error while reading socket: $!";
145             }
146 42         152 $readSize -= $result;
147             }
148 42         110 $encodedSize = unpack("N", $encodedSize);
149 42         142 my $max = $self->getMaxMessage();
150 42 50 33     199 die "Maximum message size of $max exceeded, use option 'maxmessage' to"
151             . " increase" if $max && $encodedSize > $max;
152 42         53 $readSize = $encodedSize;
153 42 50       97 if ($self->{'cipher'}) {
154 0         0 $blockSize = $self->{'cipher'}->blocksize;
155 0 0       0 if (my $addSize = ($encodedSize % $blockSize)) {
156 0         0 $readSize += ($blockSize - $addSize);
157             }
158             }
159 42         75 my $msg = '';
160 42         49 my $rs = $readSize;
161 42         118 while ($rs > 0) {
162 42         143 my $result = $socket->read($msg, $rs, length($msg));
163 42 50       311 if (!$result) {
164 0 0       0 die "Unexpected EOF" if defined $result;
165 0         0 die "Error while reading socket: $!";
166             }
167 42         157 $rs -= $result;
168             }
169 42 50       104 if ($self->{'cipher'}) {
170 0         0 my $cipher = $self->{'cipher'};
171 0         0 my $encodedMsg = $msg;
172 0         0 $msg = '';
173 0         0 for (my $i = 0; $i < $readSize; $i += $blockSize) {
174 0         0 $msg .= $cipher->decrypt(substr($encodedMsg, $i, $blockSize));
175             }
176 0         0 $msg = substr($msg, 0, $encodedSize);
177             }
178 42 100       149 $msg = Compress::Zlib::uncompress($msg) if ($self->{'compression'});
179 42         958 Storable::thaw($msg);
180             }
181              
182              
183             ############################################################################
184             #
185             # Name: Init
186             #
187             # Purpose: Initialize an object for using RPC::PlServer::Comm methods
188             #
189             # Input: $self - Instance
190             #
191             # Returns: The instance in case of success, dies in case of trouble.
192             #
193             ############################################################################
194              
195             ############################################################################
196             #
197             # Name: getMaxMessage
198             #
199             # Purpose: Returns the maximum size of a message
200             #
201             # Inputs: None
202             #
203             # Returns: Maximum message size or 65536, if none specified
204             #
205             ############################################################################
206              
207             sub getMaxMessage() {
208 0     0 0   my $self = shift;
209 0 0         return defined($self->{'maxmessage'}) ?
210             $self->{'maxmessage'} : 65536;
211             }
212              
213              
214             1;