package cmt::inet; 

=head1 NAME

cmt::inet - Internet Client Functions

=cut
use strict; 
use vars qw($LOGNAME $LOGLEVEL);
use cmt::ios; 
use cmt::log(2);
    $LOGNAME    = __PACKAGE__; 
    $LOGLEVEL   = 1;
use cmt::stream;
use cmt::util('get_named_args');
use cmt::vcs('parse_id'); 
    my %RCSID   = parse_id('$Id: inet.pm 872 2008-10-29 11:51:30Z lenik $'); 
    our $VER    = "0.$RCSID{rev}"; 
use Exporter; 
use IO::Socket;

our @ISA    = qw(Exporter); 
our @EXPORT = qw(tcp_connect
                 tcp_connect_http
                 tcp_connect_sock4
                 tcp_connect_sock5); 

# Not used.
our $PROTO_TCP  = getprotobyname("tcp"); 
our $PROTO_UDP  = getprotobyname("udp"); 

# INITIALIZORS

=head1 SYNOPSIS

    use cmt::inet;
    mysub(arguments...)

=head1 DESCRIPTION

B<cmt::inet> is a WHAT used for WHAT. It HOW-WORKS. 

BACKGROUND-PROBLEM. 

HOW-cmt::inet-RESOLVES. 

=head1 FUNCTIONS

=cut
=head2 mysub(arguments)

=cut
sub tcp_connect {
    my %props = get_named_args(@_); 
    my ($host, $port, $stream) = @_; 
    
    my $cont = $props{-cont}; 
    
    _log2 "tcp connect to $host:$port"; 
    
    my $sock = new IO::Socket::INET(
        PeerAddr    => $host, 
        PeerPort    => $port, 
        Type        => SOCK_STREAM, 
        Proto       => 'tcp', 
        # %props,     # interface-binding, etc..
    ); 
    if (! $sock) {
        _log2 "can't connect: $!"; 
        return undef; 
    }
    
    _log2 "connected."; 
    $sock->autoflush(1);            # as "$| = 1" does.
    $stream->bind($sock); 
    
    my $g = [ $sock ]; 
    my $ios = new cmt::ios(
        READ    => $g, 
        WRITE   => $g, 
        ERR     => $g, 
        -init   => sub { *__ANON__ = '<init>'; 
            my $ctx         = shift; 
            $stream->{ctx}  = $ctx; # convention, see also cmt::serv
        }, 
        -read   => sub { *__ANON__ = '<read>'; 
            my ($ctx, $fd)  = @_; 
            my $data        = $stream->read($fd); # non-block
            if (length($data) == 0) {
                # closed
                $stream->shutdown(2); 
                $stream->unbind;
                $ctx->exit unless $cont;
            } else {
                $stream->push($data); 
            }
        }, 
        -write  => sub { *__ANON__ = '<write>'; 
            my ($ctx, $fd)  = @_; 
            $stream->pull(); 
        }, 
        -err    => sub { *__ANON__ = '<err>'; 
            my ($ctx, $fd)  = @_; 
            $stream->shutdown(2); 
            $stream->unbind;
            unless ($cont) {
                $ctx->exit unless $stream->err($!); 
            }
        }, 
        ); 
    $ios->{HANDLE} = $sock; 
    $ios->{STREAM} = $stream; 
    return $ios; 
}

sub tcp_connect_http {
    my ($host, $port, $proxyhost, $proxyport, $stream, @props) = @_; 
    my ($ctx, $ios); 
    my $err; 
    my $s = new ios::stream(
        -init => sub { *__ANON__ = '<init>'; 
            ($ctx, $ios) = @_; 
        }, 
        -gotdata => sub { *__ANON__ = '<gotdata>'; 
            my $this = shift;       # assert $_[1] == $this->{IN/OUT}
            my $data = $this->sysread;
            1
        }, 
        -askdata => sub { *__ANON__ = '<askdata>'; 
            my $this = shift;       # assert $_[1] == $this->{IN/OUT}
        }, 
        -goterr => sub { *__ANON__ = '<goterr>'; 
            my $this = shift;       # assert $_[1] == $this->{IN/OUT}
            $this->log1("goterr: $!, going to shutdown"); 
            $ctx->exit; 
            $err = "Error when communicating with proxy server $proxyhost:$proxyhost"; 
        }, 
    ); 
    return tcp_connect($proxyhost, $proxyport, $s, @props); 
}

sub tcp_connect_sock4 {
}

sub tcp_connect_sock5 {
}

=head1 DIAGNOSTICS

(No Information)

=cut
# (HELPER FUNCTIONS)

=head1 HISTORY

=over

=item 0.x

The initial version. 

=back

=head1 SEE ALSO

The L<cmt/"Internet Client Functions">

=head1 AUTHOR

Xima Lenik <name@mail.box>

=cut
1