Show Client.pm syntax highlighted
# This package provides a client the low level functions needed to communicate with the PsychoPatch server
# Who: Jason Morriss <stormtrooper@psychostats.com>
# Date: 2004-02-10
#
package Client;
use strict;
use IO::Socket;
use IO::Select;
sub new {
my ($proto, $socket) = @_;
my $class = ref($proto) || $proto;
my $self = {};
$self->{debug} = 0;
$self->{classname} = $class;
bless($self, $class);
$socket->autoflush(1);
$self->{socket} = $socket;
$self->{peername} = $socket->peername;
($self->{port}, $self->{packedip}) = sockaddr_in($self->{peername});
$self->{ip} = inet_ntoa($self->{packedip});
$self->{host} = gethostbyaddr($self->{packedip}, AF_INET) || $self->{ip};
$self->{authorized} = 0;
$self->{clientstr} = "$self->{host} [$self->{ip}]";
$self->{select} = new IO::Select($socket);
# $self->{magicnum} = sprintf("%u\n", ord("P") << 24 | ord("S") << 16 | ord('2') << 8 | ord('0'));
$self->{magicnum} = 0xFFFFFFFF;
return $self;
}
# receives the first 4 bytes (32bit int) from the beginning of a data buffer and returns true if the magic # found was the
# proper magic identifier
sub _getmagic {
my ($self) = @_;
my $int = '';
return 0 unless $self->can_read;
$int = $self->recv(4);
return undef unless length($int) == 4;
my $magic = unpack("N", $int);
return ($magic == $self->{magicnum});
}
# receives the first 4 bytes (32bit int) from the beginning of a data buffer, so we know how much data is expected
# in the current data stream
sub _getlen {
my ($self) = @_;
my $int = '';
return undef unless $self->can_read;
$int = $self->recv(4);
return undef unless length($int) == 4;
my $len = unpack("N", $int);
return $len >= 0 ? $len : 0; # never allow a negative
}
sub can_read {
my ($self, $timeout) = @_;
$timeout = 120 unless defined $timeout;
my ($s) = $self->{select}->can_read($timeout);
return (defined $s);
}
# returns an ACK packet.
# SCALAR context returns only the ack code.
# ARRAY context returns a 2 element array of the code and message string from the other end.
sub getack {
my ($self, $timeout) = @_;
$timeout = 120 unless defined $timeout;
my $msg = $self->getmsg($timeout);
$msg = '0 Remote end did not respond' unless defined $msg;
my @parts = split(/\s+/, $msg, 2);
return wantarray ? @parts : $parts[0];
}
sub sendack {
my ($self, $code, $msg) = @_;
return $self->sendmsg("$code $msg");
}
sub sendmsg {
my ($self, $msg, $encoding) = @_;
my $magic = pack("N", $self->{magicnum});
my $len = pack("N", length($msg));
$encoding ||= $self->{encoding} || 'none';
my $sent = $self->{socket}->send($magic . $len . $msg);
return length($msg); # we don't count the magic number or $length integer
}
sub getmsg {
my ($self,$timeout) = @_;
$timeout = 120 unless defined $timeout;
return undef unless $self->_getmagic;
my $expected = $self->_getlen($timeout);
my $msg = '';
my $total = 0;
return undef unless defined $expected;
while ($total < $expected && $self->can_read($timeout)) {
my $chunk = $self->recv($expected - $total);
$total += length($chunk);
$msg .= $chunk;
}
return $msg;
}
sub recv {
my ($self,$len) = @_;
my $buff = '';
return '' if $len <= 0;
$self->{socket}->recv($buff, $len);
return $buff;
}
sub connected {
my ($self) = @_;
my $sock = $self->{socket};
return ( defined $sock && $sock->connected );
}
sub DESTROY {
my $self = shift;
}
1;
See more files for this project here