📄 azinstancemanagerimpl.java
字号:
/*
* 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.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.config.ParameterListener;
import org.gudy.azureus2.core3.download.DownloadManager;
import org.gudy.azureus2.core3.logging.LogEvent;
import org.gudy.azureus2.core3.logging.LogIDs;
import org.gudy.azureus2.core3.logging.Logger;
import org.gudy.azureus2.core3.torrent.TOTorrent;
import org.gudy.azureus2.core3.util.AEMonitor;
import org.gudy.azureus2.core3.util.AESemaphore;
import org.gudy.azureus2.core3.util.AEThread;
import org.gudy.azureus2.core3.util.BDecoder;
import org.gudy.azureus2.core3.util.BEncoder;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.SHA1Simple;
import org.gudy.azureus2.core3.util.SimpleTimer;
import org.gudy.azureus2.core3.util.SystemTime;
import org.gudy.azureus2.core3.util.TimerEvent;
import org.gudy.azureus2.core3.util.TimerEventPerformer;
import org.gudy.azureus2.plugins.download.Download;
import org.gudy.azureus2.pluginsimpl.local.download.DownloadManagerImpl;
import com.aelitis.azureus.core.AzureusCore;
import com.aelitis.azureus.core.AzureusCoreLifecycleAdapter;
import com.aelitis.azureus.core.instancemanager.AZInstance;
import com.aelitis.azureus.core.instancemanager.AZInstanceManager;
import com.aelitis.azureus.core.instancemanager.AZInstanceManagerListener;
import com.aelitis.azureus.core.instancemanager.AZInstanceTracked;
import com.aelitis.azureus.core.util.NetUtils;
import com.aelitis.net.udp.mc.MCGroup;
import com.aelitis.net.udp.mc.MCGroupAdapter;
import com.aelitis.net.udp.mc.MCGroupFactory;
public class
AZInstanceManagerImpl
implements AZInstanceManager, MCGroupAdapter
{
private static final boolean DISABLE_LAN_LOCAL_STUFF = false;
static{
if ( DISABLE_LAN_LOCAL_STUFF ){
System.out.println( "**** LAN LOCAL STUFF DISABLED ****" );
}
}
private static final LogIDs LOGID = LogIDs.NET;
private String MC_GROUP_ADDRESS = "239.255.067.250"; // 239.255.000.000-239.255.255.255
private int MC_GROUP_PORT = 16680; //
private int MC_CONTROL_PORT = 0;
private static final int MT_VERSION = 1;
private static final int MT_ALIVE = 1;
private static final int MT_BYE = 2;
private static final int MT_REQUEST = 3;
private static final int MT_REPLY = 4;
private static final int MT_REQUEST_SEARCH = 1;
private static final int MT_REQUEST_TRACK = 2;
private static final long ALIVE_PERIOD = 30*60*1000;
private static AZInstanceManagerImpl singleton;
private List listeners = new ArrayList();
private static AEMonitor class_mon = new AEMonitor( "AZInstanceManager:class" );
private static String socks_proxy = null;
static{
COConfigurationManager.addAndFireParameterListeners(
new String[]{ "Proxy.Data.Enable", "Proxy.Host", "Proxy.Data.Same", "Proxy.Data.Host" },
new ParameterListener()
{
public void
parameterChanged(
String parameterName )
{
if ( !COConfigurationManager.getBooleanParameter("Proxy.Data.Enable")){
socks_proxy = null;
return;
}
if ( COConfigurationManager.getBooleanParameter("Proxy.Data.Same")){
socks_proxy = COConfigurationManager.getStringParameter( "Proxy.Host" );
}else{
socks_proxy = COConfigurationManager.getStringParameter( "Proxy.Data.Host" );
}
if ( socks_proxy != null ){
socks_proxy = socks_proxy.trim();
}
}
});
}
public static AZInstanceManager
getSingleton(
AzureusCore core )
{
try{
class_mon.enter();
if ( singleton == null ){
singleton = new AZInstanceManagerImpl( core );
}
}finally{
class_mon.exit();
}
return( singleton );
}
private AzureusCore core;
private MCGroup mc_group;
private long search_id_next;
private List requests = new ArrayList();
private AZMyInstanceImpl my_instance;
private Map other_instances = new HashMap();
private volatile Map tcp_lan_to_ext = new HashMap();
private volatile Map udp_lan_to_ext = new HashMap();
private volatile Map udp2_lan_to_ext = new HashMap();
private volatile Map tcp_ext_to_lan = new HashMap();
private volatile Map udp_ext_to_lan = new HashMap();
private volatile Map udp2_ext_to_lan = new HashMap();
private volatile Set lan_addresses = new HashSet();
private volatile Set ext_addresses = new HashSet();
private volatile List lan_subnets = new ArrayList();
private volatile List explicit_peers = new ArrayList();
private volatile boolean include_well_known_lans = true;
private AESemaphore initial_search_sem = new AESemaphore( "AZInstanceManager:initialSearch" );
private AEMonitor this_mon = new AEMonitor( "AZInstanceManager" );
private boolean closing;
protected
AZInstanceManagerImpl(
AzureusCore _core )
{
core = _core;
my_instance = new AZMyInstanceImpl( core, this );
new AZPortClashHandler( this );
}
public void
initialize()
{
try{
mc_group =
MCGroupFactory.getSingleton(
this,
MC_GROUP_ADDRESS,
MC_GROUP_PORT,
MC_CONTROL_PORT,
null );
core.addLifecycleListener(
new AzureusCoreLifecycleAdapter()
{
public void
stopping(
AzureusCore core )
{
closing = true;
sendByeBye();
}
});
SimpleTimer.addPeriodicEvent(
"InstManager:timeouts",
ALIVE_PERIOD,
new TimerEventPerformer()
{
public void
perform(
TimerEvent event )
{
checkTimeouts();
sendAlive();
}
});
}catch( Throwable e ){
initial_search_sem.releaseForever();
Debug.printStackTrace(e);
}
new AEThread( "AZInstanceManager:initialSearch", true )
{
public void
runSupport()
{
try{
search();
// pick up our own details as soon as we can
addAddresses( my_instance );
}finally{
initial_search_sem.releaseForever();
}
}
}.start();
}
public void
trace(
String str )
{
if ( Logger.isEnabled()){
Logger.log(new LogEvent( LOGID, str ));
}
}
public void
log(
Throwable e )
{
Debug.printStackTrace(e);
}
public boolean
isInitialized()
{
return( initial_search_sem.isReleasedForever());
}
protected boolean
isClosing()
{
return( closing );
}
protected void
sendAlive()
{
sendMessage( MT_ALIVE );
}
protected void
sendAlive(
InetSocketAddress target )
{
sendMessage( MT_ALIVE, target );
}
protected void
sendByeBye()
{
sendMessage( MT_BYE );
}
protected void
sendByeBye(
InetSocketAddress target )
{
sendMessage( MT_BYE, target );
}
protected void
sendMessage(
int type )
{
sendMessage( type, (Map)null );
}
protected void
sendMessage(
int type,
InetSocketAddress target )
{
sendMessage( type, null, target );
}
protected void
sendMessage(
int type,
Map body )
{
sendMessage( type, body, null );
}
protected void
sendMessage(
int type,
Map body,
InetSocketAddress member )
{
Map map = new HashMap();
map.put( "ver", new Long(MT_VERSION));
map.put( "type", new Long(type));
Map originator = new HashMap();
map.put( "orig", originator );
my_instance.encode( originator );
if ( body != null ){
map.put( "body", body );
}
try{
if ( member == null ){
byte[] data = BEncoder.encode( map );
mc_group.sendToGroup( data );
if ( explicit_peers.size() > 0 ){
map.put( "explicit", new Long(1));
byte[] explicit_data = BEncoder.encode( map );
Iterator it = explicit_peers.iterator();
while( it.hasNext()){
mc_group.sendToMember((InetSocketAddress)it.next(), explicit_data );
}
}
}else{
if ( explicit_peers.contains( member )){
map.put( "explicit", new Long(1));
}
byte[] explicit_data = BEncoder.encode( map );
mc_group.sendToMember( member, explicit_data );
}
}catch( Throwable e ){
}
}
public void
received(
NetworkInterface network_interface,
InetAddress local_address,
InetSocketAddress originator,
byte[] data,
int length )
{
try{
Map map = BDecoder.decode(new BufferedInputStream(new ByteArrayInputStream( data, 0, length )));
long version = ((Long)map.get( "ver" )).longValue();
long type = ((Long)map.get( "type" )).longValue();
InetAddress originator_address = originator.getAddress();
if ( map.get( "explicit" ) != null ){
addInstanceSupport( originator_address, false );
}
AZOtherInstanceImpl instance = AZOtherInstanceImpl.decode( originator_address, (Map)map.get( "orig" ));
if ( type == MT_ALIVE ){
checkAdd( instance );
}else if ( type == MT_BYE ){
checkRemove( instance );
}else{
checkAdd( instance );
Map body = (Map)map.get( "body" );
if ( type == MT_REQUEST ){
String originator_id = instance.getID();
if ( !originator_id.equals( my_instance.getID())){
Map reply = requestReceived( instance, body );
if ( reply != null ){
reply.put( "oid", originator_id.getBytes());
reply.put( "rid", body.get( "rid" ));
sendMessage( MT_REPLY, reply, originator );
}
}
}else if ( type == MT_REPLY ){
String originator_id = new String((byte[])body.get( "oid" ));
if ( originator_id.equals( my_instance.getID())){
long req_id = ((Long)body.get("rid")).longValue();
try{
this_mon.enter();
for (int i=0;i<requests.size();i++){
request req = (request)requests.get(i);
if ( req.getID() == req_id ){
req.addReply( instance, body );
}
}
}finally{
this_mon.exit();
}
}
}
}
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
protected Map
requestReceived(
AZInstance instance,
Map body )
{
// System.out.println( "received result: " + ST + "/" + AL );
long type = ((Long)body.get( "type")).longValue();
if ( type == MT_REQUEST_SEARCH ){
return( new HashMap());
}else if ( type == MT_REQUEST_TRACK ){
byte[] hash = (byte[])body.get( "hash" );
boolean seed = ((Long)body.get( "seed" )).intValue() == 1;
List dms = core.getGlobalManager().getDownloadManagers();
Iterator it = dms.iterator();
DownloadManager matching_dm = null;
try{
while( it.hasNext()){
DownloadManager dm = (DownloadManager)it.next();
TOTorrent torrent = dm.getTorrent();
if ( torrent == null ){
continue;
}
byte[] sha1_hash = (byte[])dm.getData( "AZInstanceManager::sha1_hash" );
if ( sha1_hash == null ){
sha1_hash = new SHA1Simple().calculateHash( torrent.getHash());
dm.setData( "AZInstanceManager::sha1_hash", sha1_hash );
}
if ( Arrays.equals( hash, sha1_hash )){
matching_dm = dm;
break;
}
}
}catch( Throwable e ){
Debug.printStackTrace(e);
}
if ( matching_dm == null ){
return( null );
}
int dm_state = matching_dm.getState();
if ( dm_state == DownloadManager.STATE_ERROR || dm_state == DownloadManager.STATE_STOPPED ){
return( null );
}
try{
informTracked(
new trackedInstance( instance, DownloadManagerImpl.getDownloadStatic( matching_dm ), seed ));
}catch( Throwable e ){
Debug.printStackTrace(e);
}
Map reply = new HashMap();
// XXX include DND? I don't know
reply.put( "seed", new Long( matching_dm.isDownloadComplete(true)?1:0));
return( reply );
}else{
return( null );
}
}
public void
interfaceChanged(
NetworkInterface network_interface )
{
sendAlive();
}
protected AZOtherInstanceImpl
checkAdd(
AZOtherInstanceImpl inst )
{
if ( inst.getID().equals( my_instance.getID())){
return( inst );
}
boolean added = false;
boolean changed = false;
try{
this_mon.enter();
AZOtherInstanceImpl existing = (AZOtherInstanceImpl)other_instances.get( inst.getID());
if ( existing == null ){
added = true;
other_instances.put( inst.getID(), inst );
}else{
changed = existing.update( inst );
inst = existing;
}
}finally{
this_mon.exit();
}
if ( added ){
informAdded( inst );
}else if ( changed ){
informChanged( inst );
}
return( inst );
}
protected void
checkRemove(
AZOtherInstanceImpl inst )
{
if ( inst.getID().equals( my_instance.getID())){
return;
}
boolean removed = false;
try{
this_mon.enter();
removed = other_instances.remove( inst.getID()) != null;
}finally{
this_mon.exit();
}
if ( removed ){
informRemoved( inst );
}
}
public AZInstance
getMyInstance()
{
return( my_instance );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -