Package org.gudy.azureus2.pluginsimpl.local.ddb

Source Code of org.gudy.azureus2.pluginsimpl.local.ddb.DDBaseTTTorrent

/*
* Created on 03-Mar-2005
* Created by Paul Gardner
* Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/

package org.gudy.azureus2.pluginsimpl.local.ddb;


import java.util.*;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.gudy.azureus2.core3.logging.LogAlert;
import org.gudy.azureus2.core3.logging.Logger;
import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.plugins.PluginInterface;
import org.gudy.azureus2.plugins.ddb.*;
import org.gudy.azureus2.plugins.download.Download;
import org.gudy.azureus2.plugins.torrent.Torrent;
import org.gudy.azureus2.plugins.torrent.TorrentAttribute;
import org.gudy.azureus2.pluginsimpl.local.PluginInitializer;

import com.aelitis.azureus.plugins.dht.DHTPluginProgressListener;

/**
* @author parg
*
*/

public class
DDBaseTTTorrent
  implements DistributedDatabaseTransferType, DistributedDatabaseTransferHandler
{
  private static final boolean  TRACE      = false;
 
  private static final byte  CRYPTO_VERSION  = 1;
 
  static{
    if ( TRACE ){
      System.out.println( "**** Torrent xfer tracing on ****" );
    }
  }
 
  private DDBaseImpl    ddb;
   
  private TorrentAttribute  ta_sha1;
 
  private boolean        crypto_tested;
  private boolean        crypto_available;
 
  private List        external_downloads;
 
  private Map  data_cache =
    new LinkedHashMap(5,0.75f,true)
    {
      protected boolean
      removeEldestEntry(
           Map.Entry eldest)
      {
        return size() > 5;
      }
    };
   
  protected
  DDBaseTTTorrent(
    DDBaseImpl    _ddb )
  {
    ddb          = _ddb;
  }
 
  public void
  addDownload(
    Download    download )
  {
    synchronized( this ){
     
      if ( external_downloads == null ){
       
        external_downloads = new ArrayList();
      }
     
      external_downloads.add( download );
    }
  }
 
  public void
  removeDownload(
    Download    download )
  {
    synchronized( this ){
     
      if ( external_downloads != null ){
       
        external_downloads.remove( download );
      }
     
      if ( external_downloads.size() == 0 ){
       
        external_downloads = null;
      }
    }
  }
 
    // server side read
 
  public DistributedDatabaseValue
  read(
    DistributedDatabaseContact      contact,
    DistributedDatabaseTransferType    type,
    DistributedDatabaseKey        key )
 
    throws DistributedDatabaseException
  {
      // We use sha1(hash) as the key for torrent downloads
      // and encrypt the torrent content using the hash as the basis for a key. This
      // prevents someone without the hash from downloading the torrent
   
    try{
      byte[]  search_key = ((DDBaseKeyImpl)key).getBytes();
     
      Download   download = null;
       
      PluginInterface pi = PluginInitializer.getDefaultInterface();
                 
      String  search_sha1 = pi.getUtilities().getFormatters().encodeBytesToString( search_key );
     
      if ( ta_sha1 == null ){
       
        ta_sha1 = pi.getTorrentManager().getPluginAttribute( "DDBaseTTTorrent::sha1");
      }
       
        // gotta look for the sha1(hash)
     
      Download[]  downloads = pi.getDownloadManager().getDownloads();
     
      for (int i=0;i<downloads.length;i++){
       
        Download  dl = downloads[i];
       
        if ( dl.getTorrent() == null ){
         
          continue;
        }
       
        String  sha1 = dl.getAttribute( ta_sha1 );
       
        if ( sha1 == null ){
         
          sha1 = pi.getUtilities().getFormatters().encodeBytesToString(
                new SHA1Simple().calculateHash( dl.getTorrent().getHash()));
         
          dl.setAttribute( ta_sha1, sha1 );
        }
       
        if ( sha1.equals( search_sha1 )){
         
          download  = dl;
                   
          break;
        }
      }
       
      if ( download == null ){
       
        synchronized( this ){
         
          if ( external_downloads != null ){
           
            for (int i=0;i<external_downloads.size();i++){
             
              Download  dl = (Download)external_downloads.get(i);
             
              if ( dl.getTorrent() == null ){
               
                continue;
              }
             
              String  sha1 = dl.getAttribute( ta_sha1 );
             
              if ( sha1 == null ){
               
                sha1 = pi.getUtilities().getFormatters().encodeBytesToString(
                      new SHA1Simple().calculateHash( dl.getTorrent().getHash()));
               
                dl.setAttribute( ta_sha1, sha1 );
              }
             
              if ( sha1.equals( search_sha1 )){
               
                download  = dl;
                         
                break;
              }
            }
          }
        }
      }
     
      String  originator = contact.getName();
     
      if ( download == null ){
       
        String msg = "TorrentDownload: request from " + originator + " for '" + pi.getUtilities().getFormatters().encodeBytesToString( search_key ) + "' not found";
       
        if ( TRACE ){
         
          System.out.println( msg );
        }
       
        ddb.log( msg );
       
          // torrent not found - probably been removed whilst info still published in DHT
       
        return( null );
       
      }
     
      Torrent  torrent = download.getTorrent();
     
      if ( torrent.isPrivate()){
       
        Debug.out( "Attempt to download private torrent" );
       
        ddb.log( "TorrentDownload: request from " + originator + "  for '" + download.getName() + "' denied as it is private" );
       
          // should never happen as private torrents are not tracked so they can't be found for
          // download
       
        return( null );
      }
     
      String  msg = "TorrentDownload: request from " + originator + "  for '" + download.getName() + "' OK";   

      if ( TRACE ){
       
        System.out.println( msg );
      }
     
      ddb.log( msg );
     
      HashWrapper  hw = new HashWrapper( torrent.getHash());
     
      synchronized( data_cache ){
       
        Object[]  data = (Object[])data_cache.get( hw );
       
        if ( data != null ){
                   
          data[1] = new Long( SystemTime.getCurrentTime());
         
          return( ddb.createValue((byte[])data[0]));
        }
      }
     
     
      torrent = torrent.removeAdditionalProperties();
     
        // when clients get a torrent from the DHT they take on
        // responsibility for tracking it too
     
      torrent.setDecentralisedBackupRequested( true );
     
      byte[] data = torrent.writeToBEncodedData();
             
      data = encrypt( torrent.getHash(), data );
       
      if ( data == null ){
         
        return( null );
      }
     
      synchronized( data_cache ){

        if ( data_cache.size() == 0 ){
         
          final TimerEventPeriodic[]pe = { null };
         
          pe[0] = SimpleTimer.addPeriodicEvent(
            "DDBTorrent:timeout",
            30*1000,
            new TimerEventPerformer()
            {
              public void
              perform(
                TimerEvent  event )
              {               
                long now = SystemTime.getCurrentTime();
               
                synchronized( data_cache ){

                  Iterator  it = data_cache.values().iterator();
                 
                  while( it.hasNext()){
                   
                    long  time = ((Long)((Object[])it.next())[1]).longValue();
               
                    if ( now < time || now - time > 120*1000 ){
                     
                      it.remove();
                    }
                  }
                 
                  if ( data_cache.size() == 0 ){
                   
                    pe[0].cancel();
                  }
                }
              } 
            });
        }
       
        data_cache.put( hw, new Object[]{ data, new Long( SystemTime.getCurrentTime())});
      }
       
      return( ddb.createValue( data ));
     
    }catch( Throwable e ){
     
      throw( new DistributedDatabaseException("Torrent write fails", e ));
    }
  }
 
    // server side write
 
  public void
  write(
    DistributedDatabaseContact      contact,
    DistributedDatabaseTransferType    type,
    DistributedDatabaseKey        key,
    DistributedDatabaseValue      value )
 
    throws DistributedDatabaseException
  {
    throw( new DistributedDatabaseException( "not supported" ));
  }
 
    // client side read
 
  protected DistributedDatabaseValue
  read(
    DDBaseContactImpl              contact,
    final DistributedDatabaseProgressListener  listener,
    DistributedDatabaseTransferType        type,
    DistributedDatabaseKey            key,
    long                    timeout )
 
    throws DistributedDatabaseException
  {
    byte[]  torrent_hash  = ((DDBaseKeyImpl)key).getBytes();
   
    byte[]  lookup_key  = new SHA1Simple().calculateHash( torrent_hash );
         
    if ( TRACE ){
      System.out.println( "TorrentXfer: sending via sha1(hash)" );
    }
   
    byte[]  data = contact.getContact().read(
              new DHTPluginProgressListener()
              {
                public void
                reportSize(
                  long  size )
                {
                  listener.reportSize( size );
                }
               
                public void
                reportActivity(
                  String  str )
                {
                  listener.reportActivity( str );
                }
               
                public void
                reportCompleteness(
                  int    percent )
                {
                  listener.reportCompleteness( percent );
                }
              },
              DDBaseHelpers.getKey(type.getClass()).getHash(),
              lookup_key,
              timeout );
             
    if ( data == null ){
     
      return( null );
    }
   
    data = decrypt( torrent_hash, data );
     
    if ( data == null ){
       
      return( null );
    }
   
    return( new DDBaseValueImpl( contact, data, SystemTime.getCurrentTime(), -1));
  }
 
  protected byte[]
     encrypt(
       byte[]    hash,
       byte[]    data )
     {
    if ( !testCrypto()){
     
      return( null );
    }
   
       byte[]  enc = doCrypt( Cipher.ENCRYPT_MODE, hash, data, 0 );
   
    if ( enc == null ){
     
      if ( TRACE ){
       
        System.out.println( "TorrentXfer: encryption failed, using plain" );
      }
     
      byte[]  res = new byte[data.length+2];
     
      res[0] = CRYPTO_VERSION;
      res[1] = 0// not encrypted

      System.arraycopy( data, 0, res, 2, data.length );
     
      return( res );
     
    }else{
   
      if ( TRACE ){
       
        System.out.println( "TorrentXfer: encryption ok" );
      }

      byte[]  res = new byte[enc.length+2];
     
      res[0] = CRYPTO_VERSION;
      res[1] = 1// encrypted

      System.arraycopy( enc, 0, res, 2, enc.length );

      return( res );
    }
     }
 
  protected byte[]
    decrypt(
      byte[]    hash,
      byte[]    data )
    {
    if ( !testCrypto()){
     
      return( null );
    }
   
    if ( data[0] != CRYPTO_VERSION ){
     
      Debug.out( "Invalid crypto version received" );
     
      return( data );
    }
   
    if ( data[1] == 0 ){
     
        // encryption failed, in plain
     
      if ( TRACE ){
        System.out.println( "TorrentXfer: encryption failed, retrieving plain" );
      }

      byte[]  res = new byte[data.length-2];
     
      System.arraycopy( data, 2, res, 0, res.length );
     
      return( res );
     
    }else{
     
      if ( TRACE ){
        System.out.println( "TorrentXfer: encryption ok, decrypting" );
      }

      byte[]  res =  doCrypt( Cipher.DECRYPT_MODE, hash, data, 2 );
     
      return( res );
    }
    }
 
  protected byte[]
  doCrypt(
    int      mode,
    byte[]    hash,
    byte[]    data,
    int      data_offset )
  {
    try{
      byte[]  key_data = new byte[24];
     
        // hash is 20 bytes so we've got 4 zeros at the end. tough
     
      System.arraycopy( hash, 0, key_data, 0, hash.length );
     
      SecretKey tdes_key = new SecretKeySpec( key_data, "DESede" );

      Cipher cipher = Cipher.getInstance("DESede")// Triple-DES encryption

      cipher.init(mode, tdes_key );
           
      return( cipher.doFinal(data, data_offset, data.length - data_offset ));
           
    }catch( Throwable e ){
     
      Debug.out( e );
     
      return( null );
    }
  }
 
  protected boolean
  testCrypto()
  {
    if ( !crypto_tested ){
     
      crypto_tested  = true;
   
      try{
        Cipher.getInstance("DESede")// Triple-DES encryption
 
        crypto_available  = true;
       
      }catch( Throwable e ){
       
        Logger.log(new LogAlert(LogAlert.UNREPEATABLE,
            "Unable to initialise cryptographic framework for magnet-based "
                + "torrent downloads, please re-install Java", e));
      }
    }
   
    return( crypto_available );
  }
}
TOP

Related Classes of org.gudy.azureus2.pluginsimpl.local.ddb.DDBaseTTTorrent

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.