FileDocCategorySizeDatePackage
DDBaseTTTorrent.javaAPI DocAzureus 3.0.3.411814Mon Jan 22 16:29:04 GMT 2007org.gudy.azureus2.pluginsimpl.local.ddb

DDBaseTTTorrent

public class DDBaseTTTorrent extends Object implements org.gudy.azureus2.plugins.ddb.DistributedDatabaseTransferType, org.gudy.azureus2.plugins.ddb.DistributedDatabaseTransferHandler
author
parg

Fields Summary
private static final boolean
TRACE
private static final byte
CRYPTO_VERSION
private com.aelitis.azureus.core.AzureusCore
azureus_core
private DDBaseImpl
ddb
private org.gudy.azureus2.plugins.torrent.TorrentAttribute
ta_sha1
private boolean
crypto_tested
private boolean
crypto_available
private Map
data_cache
Constructors Summary
protected DDBaseTTTorrent(com.aelitis.azureus.core.AzureusCore _azureus_core, DDBaseImpl _ddb)

		
	
	
				
				 
	
		azureus_core		= _azureus_core;
		ddb					= _ddb;
	
Methods Summary
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 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 );
		}
   	
public org.gudy.azureus2.plugins.ddb.DistributedDatabaseValueread(org.gudy.azureus2.plugins.ddb.DistributedDatabaseContact contact, org.gudy.azureus2.plugins.ddb.DistributedDatabaseTransferType type, org.gudy.azureus2.plugins.ddb.DistributedDatabaseKey key)

			// 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 = azureus_core.getPluginManager().getDefaultPluginInterface();
									
			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 ){
				
				String msg = "TorrentDownload: request 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 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 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 ));
		}
	
protected org.gudy.azureus2.plugins.ddb.DistributedDatabaseValueread(DDBaseContactImpl contact, org.gudy.azureus2.plugins.ddb.DistributedDatabaseProgressListener listener, org.gudy.azureus2.plugins.ddb.DistributedDatabaseTransferType type, org.gudy.azureus2.plugins.ddb.DistributedDatabaseKey key, long timeout)

		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 = ddb.getDHT().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 );
								}
							},
							contact.getContact(),
							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 booleantestCrypto()

		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 );
	
public voidwrite(org.gudy.azureus2.plugins.ddb.DistributedDatabaseContact contact, org.gudy.azureus2.plugins.ddb.DistributedDatabaseTransferType type, org.gudy.azureus2.plugins.ddb.DistributedDatabaseKey key, org.gudy.azureus2.plugins.ddb.DistributedDatabaseValue value)

		throw( new DistributedDatabaseException( "not supported" ));