/* * Created on 24-Apr-2006 * Created by Paul Gardner * Copyright (C) 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 com.aelitis.azureus.core.dht.netcoords; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.InetAddress; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.gudy.azureus2.core3.util.Debug; import com.aelitis.azureus.core.dht.DHTStorageAdapter; import com.aelitis.azureus.core.dht.impl.DHTLog; import com.aelitis.azureus.core.util.CopyOnWriteList; public class DHTNetworkPositionManager { private static DHTNetworkPositionProvider[] providers = new DHTNetworkPositionProvider[0]; private static DHTStorageAdapter storage_adapter = null; private static CopyOnWriteList<DHTNetworkPositionProviderListener> provider_listeners = new CopyOnWriteList<DHTNetworkPositionProviderListener>(); private static volatile CopyOnWriteList<DHTNetworkPositionListener> position_listeners; private static DHTNetworkPosition[] NP_EMPTY_ARRAY = {}; public static void initialise( DHTStorageAdapter adapter ) { synchronized( providers ){ if ( storage_adapter == null ){ storage_adapter = adapter; for (int i=0;i<providers.length;i++){ DHTNetworkPositionProvider provider = providers[i]; try{ startUp( provider ); }catch( Throwable e ){ Debug.printStackTrace(e); } } } } } private static void startUp( DHTNetworkPositionProvider provider ) { byte[] data = null; if ( storage_adapter != null ){ data = storage_adapter.getStorageForKey( "NPP:" + provider.getPositionType()); } if ( data == null ){ data = new byte[0]; } try{ provider.startUp( new DataInputStream( new ByteArrayInputStream( data ))); }catch( Throwable e ){ Debug.printStackTrace( e ); } } private static void shutDown( DHTNetworkPositionProvider provider ) { try{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream( baos ); provider.shutDown( dos ); dos.flush(); byte[] data = baos.toByteArray(); storage_adapter.setStorageForKey( "NPP:" + provider.getPositionType(), data ); }catch( Throwable e ){ Debug.printStackTrace( e ); } } public static void destroy( DHTStorageAdapter adapter ) { synchronized( providers ){ if ( storage_adapter == adapter ){ for (int i=0;i<providers.length;i++){ shutDown( providers[i] ); } storage_adapter = null; } } } public static DHTNetworkPositionProviderInstance registerProvider( final DHTNetworkPositionProvider provider ) { boolean fire_added = false; synchronized( providers ){ boolean found = false; DHTNetworkPositionProvider type_found = null; for ( DHTNetworkPositionProvider p: providers ){ if ( p == provider ){ found = true; break; }else if ( p.getPositionType() == provider.getPositionType()){ type_found = p; } } if ( !found ){ if ( type_found != null ){ Debug.out( "Registration of " + provider + " found previous provider for same position type, removing it" ); unregisterProviderSupport( type_found ); } DHTNetworkPositionProvider[] new_providers = new DHTNetworkPositionProvider[providers.length + 1 ]; System.arraycopy( providers, 0, new_providers, 0, providers.length ); new_providers[providers.length] = provider; providers = new_providers; if ( storage_adapter != null ){ startUp( provider ); } fire_added = true; } } if ( fire_added ){ for ( DHTNetworkPositionProviderListener l: provider_listeners ){ try{ l.providerAdded( provider ); }catch( Throwable e ){ Debug.out( e ); } } } return( new DHTNetworkPositionProviderInstance() { public void log( String log ) { DHTLog.log("NetPos " + provider.getPositionType() + ": " + log ); } }); } public static void unregisterProvider( DHTNetworkPositionProvider provider ) { if ( unregisterProviderSupport( provider )){ for ( DHTNetworkPositionProviderListener l: provider_listeners ){ try{ l.providerRemoved( provider ); }catch( Throwable e ){ Debug.out( e ); } } } } private static boolean unregisterProviderSupport( DHTNetworkPositionProvider provider ) { boolean removed = false; synchronized( providers ){ if ( providers.length == 0 ){ return( false ); } DHTNetworkPositionProvider[] new_providers = new DHTNetworkPositionProvider[providers.length - 1 ]; int pos = 0; for ( int i=0;i<providers.length;i++){ if ( providers[i] == provider ){ if ( storage_adapter != null ){ shutDown( provider ); } }else{ new_providers[pos++] = providers[i]; } } if ( pos == new_providers.length ){ providers = new_providers; removed = true; } } return( removed ); } public static DHTNetworkPositionProvider getProvider( byte type ) { synchronized( providers ){ for (int i=0;i<providers.length;i++){ if ( providers[i].getPositionType() == type ){ return( providers[i] ); } } } return( null ); } public static DHTNetworkPosition[] getLocalPositions() { DHTNetworkPositionProvider[] prov = providers; List<DHTNetworkPosition> res = new ArrayList<DHTNetworkPosition>(); for (int i=0;i<prov.length;i++){ try{ DHTNetworkPosition pos = prov[i].getLocalPosition(); if ( pos != null ){ res.add( pos ); } }catch( Throwable e ){ Debug.printStackTrace(e); } } return( res.toArray(new DHTNetworkPosition[res.size()])); } public static DHTNetworkPosition getBestLocalPosition() { DHTNetworkPosition best_position = null; DHTNetworkPosition[] positions = getLocalPositions(); byte best_provider = DHTNetworkPosition.POSITION_TYPE_NONE; for (int i=0;i<positions.length;i++){ DHTNetworkPosition position = positions[i]; int type = position.getPositionType(); if ( type > best_provider ){ best_position = position; } } return( best_position ); } public static DHTNetworkPosition[] createPositions( byte[] ID, boolean is_local ) { DHTNetworkPositionProvider[] prov = providers; if ( prov.length == 0 ){ return( NP_EMPTY_ARRAY ); }else{ DHTNetworkPosition[] res = new DHTNetworkPosition[prov.length]; int skipped = 0; for (int i=0;i<res.length;i++){ try{ res[i] = prov[i].create( ID, is_local ); }catch( Throwable e ){ Debug.printStackTrace(e); skipped++; } } if ( skipped > 0 ){ DHTNetworkPosition[] x = new DHTNetworkPosition[ res.length - skipped ]; int pos = 0; for (int i=0;i<res.length;i++){ if ( res[i] != null ){ x[pos++] = res[i]; } } res = x; if ( res.length == 0 ){ Debug.out( "hmm" ); } } return( res ); } } public static float estimateRTT( DHTNetworkPosition[] p1s, DHTNetworkPosition[] p2s ) { byte best_provider = DHTNetworkPosition.POSITION_TYPE_NONE; float best_result = Float.NaN; for (int i=0;i<p1s.length;i++){ DHTNetworkPosition p1 = p1s[i]; byte p1_type = p1.getPositionType(); for (int j=0;j<p2s.length;j++){ DHTNetworkPosition p2 = p2s[j]; if ( p1_type == p2.getPositionType()){ try{ float f = p1.estimateRTT( p2 ); if ( !Float.isNaN( f )){ if ( p1_type > best_provider ){ best_result = f; best_provider = p1_type; } } }catch( Throwable e ){ Debug.printStackTrace(e); } break; } } } return( best_result ); } public static void update( DHTNetworkPosition[] local_positions, byte[] remote_id, DHTNetworkPosition[] remote_positions, float rtt ) { for (int i=0;i<local_positions.length;i++){ DHTNetworkPosition p1 = local_positions[i]; for (int j=0;j<remote_positions.length;j++){ DHTNetworkPosition p2 = remote_positions[j]; if ( p1.getPositionType() == p2.getPositionType()){ try{ p1.update( remote_id, p2, rtt ); }catch( Throwable e ){ Debug.printStackTrace(e); } break; } } } } public static byte[] serialisePosition( DHTNetworkPosition pos ) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream( baos ); dos.writeByte( 1 ); // version dos.writeByte( pos.getPositionType()); pos.serialise( dos ); dos.close(); return( baos.toByteArray()); } public static DHTNetworkPosition deserialisePosition( InetAddress originator, byte[] bytes ) throws IOException { ByteArrayInputStream bais = new ByteArrayInputStream( bytes ); DataInputStream dis = new DataInputStream( bais ); dis.readByte(); // version byte position_type = dis.readByte(); return( deserialise( originator, position_type, dis )); } public static DHTNetworkPosition deserialise( InetAddress originator, byte position_type, DataInputStream is ) throws IOException { DHTNetworkPositionProvider[] prov = providers; is.mark( 512 ); for (int i=0;i<prov.length;i++){ if ( prov[i].getPositionType() == position_type ){ DHTNetworkPositionProvider provider = prov[i]; try{ DHTNetworkPosition np = provider.deserialisePosition( is ); CopyOnWriteList<DHTNetworkPositionListener> listeners = position_listeners; if ( listeners != null ){ Iterator<DHTNetworkPositionListener> it = listeners.iterator(); while( it.hasNext()){ try{ it.next().positionFound( provider, originator, np ); }catch( Throwable e ){ Debug.printStackTrace(e); } } } return( np ); }catch( Throwable e ){ Debug.printStackTrace(e); is.reset(); } break; } } return( null ); } public static void addPositionListener( DHTNetworkPositionListener listener ) { synchronized( DHTNetworkPositionManager.class ){ if ( position_listeners == null ){ position_listeners = new CopyOnWriteList<DHTNetworkPositionListener>(); } position_listeners.add( listener ); } } public static void removePositionListener( DHTNetworkPositionListener listener ) { synchronized( DHTNetworkPositionManager.class ){ if ( position_listeners != null ){ position_listeners.remove( listener ); if ( position_listeners.size() == 0 ){ position_listeners = null; } } } } public static void addProviderListener( DHTNetworkPositionProviderListener listener ) { provider_listeners.add( listener ); } public static void removeProviderListener( DHTNetworkPositionProviderListener listener ) { provider_listeners.remove( listener ); } }