#!/usr/bin/perl -w
use strict;
use warnings;
use threads;
use threads::shared;
use IO::Socket;

package tcpSocket;

sub new {
    my $class=shift;
    my $self={@_};
    my $sckt=''; 
    my $thrd=0;
    
    $self->{Mode}='C' unless defined($self->{Mode});
    $self->{Port}=80 unless defined($self->{Port});
    $self->{Addr}='localhost' unless defined($self->{Addr});
    $self->{TOut}=5 unless defined($self->{TOut});
    
    if (! ($self->{Addr} =~ m/([0-9]{1,3}\.){3}[0-9]{1,3}/)) {    
        $self->{Addr}=tcpSocket->hostbyname($self->{Addr},$self->{TOut});
    }
    if ($self->{Addr} ne '') {
        if ($self->{Mode} eq 'C') {
            $sckt=IO::Socket::INET->new(PeerAddr=>$self->{Addr},PeerPort=>$self->{Port},Proto=>'tcp',Blocking=>1,Timeout=>$self->{TOut});
        }
        else {
        }
        $self->{SCK}=$sckt;
        if ($sckt) {
            my $slct=select($sckt);
            my $msqe='';
            vec($msqe,fileno($sckt),1)=1;
            select($msqe,undef,undef,0.1);
            select($slct);        
        }    
    }
    bless($self,$class);
    return $self;
}

sub hostbyname() {
    my $self=shift;
    my $name=shift;
    my $tout=(@_) ? shift : 5;
    my $addr:shared='';
    my $thr=threads->new(sub {
        eval {
            local $SIG{'USR1'}=sub { die "TOut\n" };
            my ($host, $aliases, $addrtype, $length, @addrs) = gethostbyname($name);
            my ($a, $b, $c, $d) = unpack ('C4', $addrs[0]);
            $addr=sprintf("%d.%d.%d.%d\n", $a, $b, $c, $d);
        };
        die if $@ && $@ ne "TOut\n"; 
    });  
    while (($addr eq '') && $tout) {
        sleep(1);
        $tout--;
    }
    $thr->kill('SIGUSR1');
    return $addr;
}

sub connected() {
    my $self=shift;
    return $self->{SCK};    
}

sub readbyte() {
    my $self=shift;
    my $size=shift;
    my $sckt=$self->{SCK};

    $size=4096 unless defined($size);    
    my $buff;
    my $wait=$self->{TOut};
    do {
        recv($sckt,$buff,$size,0);
        $wait--;
    } until (($buff) || ($wait));
    return $buff;
}

sub read() {
    my $self=shift;
    my $buff;
    my $blck;
    do {
        $blck=$self->readbyte();
        $buff=$buff.$blck;
    } until ($blck eq '');
    return $buff;
}

sub write() {
    my $self=shift;
    my $buff=shift;
    my $sckt=$self->{SCK};
    print $sckt $buff;
    $self->{SCK}->flush;
}

sub close() {
    my $self=shift;
    $self->{SCK}->close();
}

1;

__END__
#!/usr/bin/perl -w
use strict;
use warnings;

use caLib::tcpSocket;

print "- B -\n";
my $tcp=tcpSocket->new(Mode=>'C', Port=>80, Addr=>'www.pinailleur.info', TOut=>5);
print "- C -\n";
if ($tcp->connected()) {
    $tcp->write("GET / HTTP/1.1\n");
    $tcp->write("Host: www.pinailleur.info\n\n");
    print $tcp->read();
    $tcp->close();
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

use strict; use warnings;
use IO::Socket;
my $server = IO::Socket::INET->new(
    LocalAddr => 'localhost',
    Proto => "tcp",
    LocalPort => 9000,
    Listen => SOMAXCONN,
    Reuse => 1,
) or die "Can't setup server\n";
my $client = $server->accept();
$client->autoflush(1);
print $client "Hello bob\n";
while( <$client> ) {
print;
}
$client->close();
print "A connection was accepted (press Enter to quit).\n";
<STDIN>;
$server->close();
