/*
* Created on 20-Dec-2005
* Created by Paul Gardner
* Copyright (C) 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 com.aelitis.azureus.core.instancemanager.impl;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.gudy.azureus2.core3.config.COConfigurationListener;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.util.*;
import com.aelitis.azureus.core.instancemanager.AZInstanceManagerAdapter;
import com.aelitis.azureus.core.networkmanager.admin.NetworkAdmin;
import com.aelitis.azureus.plugins.dht.DHTPlugin;
import com.aelitis.azureus.plugins.dht.DHTPluginContact;
import com.aelitis.azureus.plugins.dht.DHTPluginListener;
import com.aelitis.azureus.plugins.upnp.UPnPPlugin;
public class
AZMyInstanceImpl
extends AZInstanceImpl
{
public static final long FORCE_READ_EXT_MIN = 8*60*60*1000;
public static final long UPNP_READ_MIN = 5*60*1000;
private AZInstanceManagerAdapter adapter;
private AZInstanceManagerImpl manager;
private String id;
private InetAddress internal_address;
private int tcp_port;
private int udp_port;
private int udp_non_data_port;
private long last_upnp_read;
private InetAddress dht_address;
private long dht_address_time;
private long last_force_read_ext;
private InetAddress last_external_address;
protected
AZMyInstanceImpl(
AZInstanceManagerAdapter _adapter,
AZInstanceManagerImpl _manager )
{
adapter = _adapter;
manager = _manager;
id = adapter.getID();
if ( id.length() == 0 ){
id = "" + SystemTime.getCurrentTime();
}
id = ByteFormatter.encodeString( new SHA1Simple().calculateHash( id.getBytes()));
COConfigurationManager.addListener(
new COConfigurationListener()
{
public void
configurationSaved()
{
readConfig( false );
}
});
readConfig( true );
adapter.addListener(
new AZInstanceManagerAdapter.StateListener()
{
public void
started()
{
DHTPlugin dht = adapter.getDHTPlugin();
if ( dht != null ){
dht.addListener(
new DHTPluginListener()
{
public void
localAddressChanged(
DHTPluginContact local_contact )
{
InetAddress latest_dht_address = local_contact.getAddress().getAddress();
if ( sameFamily( internal_address, latest_dht_address )){
dht_address = latest_dht_address;
dht_address_time = SystemTime.getCurrentTime();
manager.informChanged( AZMyInstanceImpl.this );
}
}
});
}
}
public void
stopped()
{
}
});
}
private void
readConfig(
boolean first_time )
{
InetAddress new_internal_address = NetworkAdmin.getSingleton().getSingleHomedServiceBindAddress();
if ( new_internal_address == null ){
try{
new_internal_address = InetAddress.getByName( "0.0.0.0" );
}catch( Throwable e ){
}
}
int[] ports = adapter.getPorts();
int new_tcp_port = ports[0];
int new_udp_port = ports[1];
int new_udp_non_data_port = ports[2];
boolean same = true;
if ( !first_time ){
same = internal_address.equals( new_internal_address) &&
tcp_port == new_tcp_port &&
udp_port == new_udp_port &&
udp_non_data_port == new_udp_non_data_port;
}
internal_address = new_internal_address;
tcp_port = new_tcp_port;
udp_port = new_udp_port;
udp_non_data_port = new_udp_non_data_port;
if ( !same ){
manager.informChanged( this );
}
}
private InetAddress
readExternalAddress()
{
InetAddress external_address = null;
// no point in kicking off any queries if we're closing
if ( manager.isClosing()){
external_address = last_external_address;
if ( external_address == null ){
try{
external_address = InetAddress.getByName("127.0.0.1");
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
return( external_address );
}
DHTPlugin dht = adapter.getDHTPlugin();
// if DHT has informed us of an address then we use this - most reliable up to date one
// unless the version server cache time is more recent
if ( dht_address != null && dht_address_time <= SystemTime.getCurrentTime()){
AZInstanceManagerAdapter.VCPublicAddress a = adapter.getVCPublicAddress();
if ( a != null ){
long cache_time = a.getCacheTime();
if ( cache_time <= dht_address_time ){
external_address = dht_address;
}
}
}
if ( external_address == null &&
( dht == null || dht.getStatus() != DHTPlugin.STATUS_RUNNING )){
// use cached version if available and the DHT isn't
AZInstanceManagerAdapter.VCPublicAddress a = adapter.getVCPublicAddress();
if ( a != null ){
try{
external_address = InetAddress.getByName( a.getAddress());
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
if ( external_address == null && dht != null ){
// no cache, use DHT (this will hang during initialisation, hence the use of cached
// version above
try{
InetAddress latest_dht_address = dht.getLocalAddress().getAddress().getAddress();
// ignore any v6 addresses from DHT
if ( sameFamily( internal_address, latest_dht_address )){
external_address = latest_dht_address;
}
}catch( Throwable e ){
}
}
long now = SystemTime.getCurrentTime();
if ( last_force_read_ext > now ){
last_force_read_ext = now;
}
boolean ok_to_try_ext = now - last_force_read_ext > FORCE_READ_EXT_MIN;
// try upnp - limit frequency unless external read is possible in which
// case we try upnp first
// currently we only use UPnP to validate our current external address, not
// to deduce new ones (as for example there may be multiple upnp devices and
// we don't know which one to believe
if ( external_address == null && last_external_address != null ){
if ( last_upnp_read > now ){
last_upnp_read = now;
}
if ( now - last_upnp_read > UPNP_READ_MIN || ok_to_try_ext ){
last_upnp_read = now;
try{
UPnPPlugin upnp = adapter.getUPnPPlugin();
if ( upnp != null ){
String[] addresses = upnp.getExternalIPAddresses();
for (int i=0;i<addresses.length;i++){
if ( addresses[i].equals( last_external_address.getHostAddress())){
external_address = last_external_address;
break;
}
}
}
}catch( Throwable e ){
}
}
}
if ( external_address == null ){
// force read it
if ( ok_to_try_ext ){
last_force_read_ext = now;
external_address = adapter.getPublicAddress();
}
}
// no good address available
if ( external_address == null ){
if ( last_external_address != null ){
external_address = last_external_address;
}else{
try{
external_address = InetAddress.getByName("127.0.0.1");
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}else{
last_external_address = external_address;
}
return( external_address );
}
private boolean
sameFamily(
InetAddress a1,
InetAddress a2 )
{
return( a1 instanceof Inet4Address == a2 instanceof Inet4Address );
}
public String
getID()
{
return( id );
}
public String
getApplicationID()
{
return( SystemProperties.getApplicationIdentifier() + "_" + SystemProperties.getApplicationVersion());
}
public InetAddress
getInternalAddress()
{
return( internal_address );
}
public List
getInternalAddresses()
{
List l = new ArrayList();
if ( internal_address != null ){
l.add( internal_address );
}
return( l );
}
public InetAddress
getExternalAddress()
{
return( readExternalAddress());
}
public int
getTCPListenPort()
{
return( tcp_port );
}
public int
getUDPListenPort()
{
return( udp_port );
}
public int
getUDPNonDataListenPort()
{
return( udp_non_data_port );
}
public Map<String, Object>
getProperties()
{
return((Map<String, Object>)COConfigurationManager.getMapParameter( "instance.manager.props", null ));
}
}