Net-DirectConnect

 view release on metacpan or  search on metacpan

lib/Net/DirectConnect.pm  view on Meta::CPAN

sub connect {    #$self->{'connect'} ||= sub {
  my $self = shift;
  #$self->log( 'c', 'connect0 inited', "MT:$self->{'message_type'}", ' with', $self->{'host'} );
  if ( $_[0] or $self->{'host'} =~ /:/ ) {
    $self->{'host'} = $_[0] if $_[0];
    $self->{'host'} =~ s{^(.*?)://}{};
    my $p = lc $1;
    $self->module_load('adcs') if $p eq 'adcs';
    #$self->protocol_init($p) if $p =~ /^adc/;
    $self->{'host'} =~ s{/.*}{}g;
    ( $self->{'host'}, $self->{'port'} ) = ( $1, $2 ) if $self->{'host'} =~ m{^\[(\S+)\]:(\d+)};     # [::1]:411
    ( $self->{'host'}, $self->{'port'} ) = ( $1, $2 ) if $self->{'host'} =~ s{^([^:]+):(\d+)$}{};    # 1.2.3.4:411
  }
  #$self->log('dev', 'host, port =', $self->{'host'}, $self->{'port'} );
  #$self->log( 'H:', ((),$self->{'host'} =~ /(:)/g)>1 );
  #$self->module_load('ipv6') if @{ [ $self->{'host'} =~ /(:)/g ] } > 1;
  #$self->{'port'} = $_[1] if $_[1];
  #print "Hhohohhhh" ,$self->{'protocol'},$self->{'host'};
  return 0
    if ( $self->{'socket'} and $self->{'socket'}->connected() )
    or grep { $self->{'status'} eq $_ } qw(destroy);    #connected
  $self->log(
    'info',
    "connecting to $self->{'protocol'}://[$self->{'host'}]:$self->{'port'} via $self->{'Proto'} class $self->{'socket_class'}",
    %{ $self->{'socket_options'} || {} }
  );
  #$self->{'status'}   = 'connecting';
  $self->{'status'}   = 'connecting_tcp';
  $self->{'outgoing'} = 1;
  #$self->{'port'}     = $1 if $self->{'host'} =~ s/:(\d+)//;
  delete $self->{'recv_buf'};
  #$self->log('dev', 'conn strt', $self->{'Timeout'}, $self->{'Proto'}, Socket::SOCK_STREAM);
  eval {
    $self->{'socket'} ||= $self->{'socket_class'}->new(
      'PeerAddr' => $self->{'host'},
      ( $self->{'port'}  ? ( 'PeerPort' => $self->{'port'} )  : () ),
      ( $self->{'Proto'} ? ( 'Proto'    => $self->{'Proto'} ) : () ),
      #( $self->{'Proto'} eq 'sctp' ? ( 'Type' => Socket::SOCK_STREAM ) : () ),
      #'Timeout'  => $self->{'Timeout'},
      #(
      #$self->{'nonblocking'} ? (
      'Blocking'   => 0,
      #'MultiHomed' => 1,    #del
                            #) : ()
                            #),
      %{ $self->{'socket_options'} },
      %{ $self->{'socket_options_connect'} },
    );
  };
  #$self->log('dev', 'connect end');
  $self->log(
    'err',
    "connect socket  error: $@,",
    Encode::decode( $self->{charset_fs}, $!, Encode::FB_WARN ),
    "[$self->{'socket'}]"
    ),
    return 1
    if !$self->{'socket'};
  #$self->log( 'dev',  'timeout to', $self->{'Timeout'});
  $self->{'socket'}->timeout( $self->{'Timeout'} ) if $self->{'Timeout'};    #timeout must be after new, ifyou want nonblocking
       #$self->log( 'dev',  'ssltry'), IO::Socket::SSL->start_SSL($self->{'socket'}) if $self->{'protocol'} eq 'adcs';
       #$self->log( 'err', "connect socket  error: $@, $! [$self->{'socket'}]" ), return 1 if !$self->{'socket'};
       #$self->{'socket'}->binmode(":encoding($self->{charset_protocol})");
       #$self->{charset_protocol} = 'utf8';
       #$self->log( 'dev', "set encoding of socket to [$self->{charset_protocol}]");
       #    binmode($self->{'socket'}, ":encoding($self->{charset_protocol})");
       #    binmode($self->{'socket'}, ":raw:encoding($self->{charset_protocol})");
       #    binmode($self->{'socket'}, ":encoding($self->{charset_protocol}):bytes");
       #    binmode($self->{'socket'}, ":$self->{charset_protocol}");
       #eval {$self->{'socket'}->fcntl( Fcntl::O_ASYNC,1);};    $self->log('warn', "cant Fcntl::O_ASYNC : $@") if $@;
       #eval {$self->{'socket'}->fcntl( Fcntl::O_NONBLOCK,1);};    $self->log('warn', "cant Fcntl::O_NONBLOCK : $@") if $@;
  $self->select_add();
  $self->{time_start} = time;
  #$self->log($self, 'connected2 inited',"MT:$self->{'message_type'}", ' with');
  #$self->log( 'dev', "connect_aft after", );
  #!!$self->select();
  #$self->log( 'dev', "connect after", );
  return 0;
}

sub connected {    #$self->{'connected'} ||= sub {
  my $self = shift;
  $self->get_my_addr();
  #$self->log( 'info', 'broken socket, cant get my ip'),
  #$self->destroy(),
  return unless $self->{'myip'};
  $self->{'status'} = 'connecting';
#$self->log( 'dev', "connected0", "[$self->{'socket'}] c=", $self->{'socket'}->connected(), 'p=', $self->{'socket'}->protocol() );
#$self->log( 'dev',  'timeout to', $self->{'Timeout_connected'});
  $self->{'socket'}->timeout( $self->{'Timeout_connected'} ) if $self->{'Timeout_connected'};
  $self->get_peer_addr();
  #$self->get_my_addr();
  #!$self->{'hostip'} ||= $self->{'host'};
  #my $localmask ||= join '|', @{ $self->{'local_mask_rfc'} || [] }, @{ $self->{'local_mask'} || [] };
  my $localmask ||= join '|', map { ref $_ eq 'ARRAY' ? @$_ : $_ }
    grep { $_ } $self->{'local_mask_rfc'},
    $self->{'local_mask'};
  my $is_local_ip = sub ($) {
    #$self->log( 'info', "test ip [$_[0]] in [$localmask] ");
    return $_[0] =~ /^(?:$localmask)\./;
  };
  $self->log( 'info', "my internal ip detected, using passive mode", $self->{'myip'}, $self->{'hostip'}, $localmask ),
    $self->{'M'} = 'P'
    if !$self->{'M'}
    and $is_local_ip->( $self->{'myip'} )
    and !$is_local_ip->( $self->{'hostip'} );
  $self->{'M'} ||= 'A';
  #$self->log( 'info', "mode set [$self->{'M'}] ");
  $self->log( 'info', "connect to $self->{'host'}($self->{'hostip'}):$self->{'port'} [me=$self->{'myip'}] ok ", );
  #$self->log( $self, 'connected1 inited', "MT:$self->{'message_type'}", ' with' );
  #$self->log( 'dev',  'ssltry'),IO::Socket::SSL->start_SSL($self->{'socket'}) if $self->{'protocol'} eq 'adcs';
  $self->connect_aft();
}

sub reconnect {    #$self->{'reconnect'} ||= sub {
  my $self = shift;
  #$self->log(          'dev', 'reconnect');
  $self->disconnect();
  $self->{'status'} = 'reconnecting';
  #!sleep $self->{'reconnect_sleep'};
  #!$self->connect();
}

sub listen {    #$self->{'listen'} ||= sub {
  my $self = shift;
  $self->log( 'err', 'listen off', "[$self->{'Listen'}] [$self->{'M'}] [$self->{'allow_passive_ConnectToMe'}]" ), return
    if !$self->{'Listen'};
  #or ( $self->{'M'} eq 'P' and !$self->{'allow_passive_ConnectToMe'} );    #RENAME
  $self->{'listener'} = 1;
  $self->myport_generate();
  #$self->log( 'dev', 'listen', "p=$self->{'myport'}; proto=$self->{'Proto'} cl=$self->{'socket_class'}",'sockopts', Dumper $self->{'socket_options'}, $self->{'socket_options_listen'} );
  for ( 1 .. $self->{'myport_tries'} ) {
    local @_ = (
      'LocalPort' => $self->{'myport'},
      #'Proto'     => $self->{'Proto'} || 'tcp',
      ( $self->{'Proto'} ? ( 'Proto' => $self->{'Proto'} ) : () ),
      (
        $self->{'Proto'} ne 'udp'
        ? ( 'Listen' => $self->{'Listen'} )
        : ()
      ),
      #( $self->{'Proto'} eq 'sctp' ? ( 'Type' => Socket::SOCK_STREAM ) : () ),
      #( $self->{'nonblocking'} ? ( 'Blocking' => 0 ) : () ),
      Blocking  => 0,
      #ReuseAddr => 1,
      %{ $self->{'socket_options'} },
      %{ $self->{'socket_options_listen'} },
    );
    #$self->log( 'dev', 'listen', $self->{'socket_class'}, @_);
    eval { $self->{'socket'} ||= $self->{'socket_class'}->new(@_); };
    $self->select_add(), last if $self->{'socket'};
    $self->log( 'err', "listen [$_/$self->{'myport_tries'}] ($self->{'Listen'}) $self->{'myport'} socket error: $@" ),
      $self->myport_generate(1),
      unless $self->{'socket'};
  }
  $self->log( 'err', 'cant listen' ), return unless $self->{'socket'};
  eval { $self->{'listener'} = $self->{'socket'}->sockhost; };
  $self->log( 'info', "listening", $self->{'listener'}, "$self->{'myport'} $self->{'Proto'} with $self->{'socket_class'}" );
  $self->{'accept'} = 1 if $self->{'Proto'} ne 'udp';
  $self->{'status'} = 'listening';
  #$self->select();
}

sub disconnect {    #$self->{'disconnect'} ||= sub {
  my $self = shift;
  #$self->log('dev', 'in disconnect', $self->{'status'}, caller);
  #$self->log( 'dev', "[$self->{'number'}] status=",$self->{'status'}, $self->{'destroying'});
  $self->handler('disconnect_bef');
  $self->{'status'} = 'disconnected';
  if ( $self->{'socket'} ) {
    #$self->log( 'dev', "[$self->{'number'}] Closing socket",

lib/Net/DirectConnect.pm  view on Meta::CPAN

}

sub nick_generate {    #'nick_generate' => sub {
  my $self = shift if ref $_[0];
  $self->{'nick_base'} ||= $self->{'Nick'};
  $self->{'Nick'} = $self->{'nick_base'} . int( rand( $self->{'nick_random'} || 100 ) );
}

sub clients_my {       #'clients_my' => sub {
  my $self = shift if ref $_[0];
  grep { $self->{'clients'}{$_} and $self->{'clients'}{$_}{parent} eq $self }
    keys %{ $self->{'clients'} };
}
#);
#$self->{$_} = $_{$_} for keys %_;
#}
#print "N:DC:CALLER=", caller, "\n";
do {
  use lib '../';
  __PACKAGE__->new( auto_work => 1, @ARGV ),;
} unless caller;
1;
__END__

=head1 NAME

Net::DirectConnect - Perl Direct Connect protocol implementation

=head1 SYNOPSIS

  use Net::DirectConnect;
  my $dc = Net::DirectConnect->new(
    'host' => 'dc.mynet.com:4111', #if not 411
    'Nick' => 'Bender', 
    'description' => 'kill all humans',
     #'M'           => 'P', #passive mode, autodetect by default
     #'local_mask'       => [qw(80.240)], #mode=active if hub in this nets and your ip in gray
  );
  $dc->wait_connect();
  $dc->chatline( 'hi all' );

  while ( $dc->active() ) {
    $dc->work();    
  }
  $dc->destroy();

look at examples for handlers


=head1 DESCRIPTION

 Currently NOT supported:
 segmented, multisource download;
 async connect;


=head1 INSTALLATION

 To install this module type the following:

   cpan DBD::SQLite IO::Socket::IP IO::Socket::INET6 IO::Socket::SSL
   perl Makefile.PL && make install clean

 debian:
 apt-get install libdbd-sqlite3-perl libio-socket-ip-perl libjson-xs-perl libjson-perl libmime-base32-perl liblib-abs-perl

=head1 SEE ALSO

 latest snapshot
 svn co svn://svn.setun.net/dcppp/trunk/ dcppp

 http://svn.setun.net/dcppp/timeline/browser/trunk

 usage example:
 used in [and created for] http://sourceforge.net/projects/pro-search http://pro.setun.net/search/
 ( http://svn.setun.net/search/trac.cgi/browser/trunk/crawler.pl )


 protocol info:
 http://en.wikipedia.org/wiki/Direct_Connect_network
 http://www.teamfair.info/DC-Protocol.htm
 http://adc.sourceforge.net/ADC.html

 also useful for creating links from web:
 http://magnet-uri.sourceforge.net/
 http://en.wikipedia.org/wiki/Magnet:_URI_scheme

=head1 TODO
 
 CGET file files.xml.bz2 0 -1 ZL1<<<

 Rewrite better

=head1 AUTHOR

Oleg Alexeenkov, E<lt>pro@cpan.orgE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2005-2011 Oleg Alexeenkov

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.


=cut



( run in 0.735 second using v1.01-cache-2.11-cpan-39bf76dae61 )