📄 trhostimpl.java
字号:
/*
* File : TRHostImpl.java
* Created : 24-Oct-2003
* By : parg
*
* Azureus - a Java Bittorrent client
*
* 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.
*
* 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 ( see the LICENSE file ).
*
* 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
*/
package org.gudy.azureus2.core3.tracker.host.impl;
/**
* @author parg
*/
import java.util.*;
import java.io.*;
import java.net.*;
import org.gudy.azureus2.core3.logging.*;
import org.gudy.azureus2.core3.config.*;
import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.core3.tracker.host.*;
import org.gudy.azureus2.core3.tracker.server.*;
import org.gudy.azureus2.core3.tracker.client.*;
import org.gudy.azureus2.core3.torrent.*;
public class
TRHostImpl
implements TRHost, TRTrackerClientFactoryListener,
TRTrackerServerListener, TRTrackerServerFactoryListener,
TRTrackerServerRequestListener, TRTrackerServerAuthenticationListener
{
protected static final int URL_DEFAULT_PORT = 80; // port to use if none in announce URL
protected static final int URL_DEFAULT_PORT_SSL = 443; // port to use if none in announce URL
protected static final int STATS_PERIOD_SECS = 60;
protected static TRHostImpl singleton;
protected static AEMonitor class_mon = new AEMonitor( "TRHost:class" );
protected TRHostConfigImpl config;
protected Hashtable server_map = new Hashtable();
protected List host_torrents = new ArrayList();
protected Map host_torrent_hash_map = new HashMap();
protected Map host_torrent_map = new HashMap();
protected Map tracker_client_map = new HashMap();
private static final int LDT_TORRENT_ADDED = 1;
private static final int LDT_TORRENT_REMOVED = 2;
private static final int LDT_TORRENT_CHANGED = 3;
private ListenerManager listeners = ListenerManager.createAsyncManager(
"TRHost:ListenDispatcher",
new ListenerManagerDispatcher()
{
public void
dispatch(
Object _listener,
int type,
Object value )
{
TRHostListener target = (TRHostListener)_listener;
if ( type == LDT_TORRENT_ADDED ){
target.torrentAdded((TRHostTorrent)value);
}else if ( type == LDT_TORRENT_REMOVED ){
target.torrentRemoved((TRHostTorrent)value);
}else if ( type == LDT_TORRENT_CHANGED ){
target.torrentChanged((TRHostTorrent)value);
}
}
});
protected List auth_listeners = new ArrayList();
protected boolean server_factory_listener_added;
protected AEMonitor this_mon = new AEMonitor( "TRHost" );
public static TRHost
create()
{
try{
class_mon.enter();
if ( singleton == null ){
singleton = new TRHostImpl();
}
return( singleton );
}finally{
class_mon.exit();
}
}
protected
TRHostImpl()
{
// we need to synchronize this so that the async (possible) establishment of
// a server within the stats loop (to deal with public trackers with no locally
// hosted torrents) doesn't get ahead of the reading of persisted torrents
// If we allow the server to start early then it can potentially receive an
// announce/scrape and result in the creation of an "external" torrent when
// it should really be using an existing torrent
try{
this_mon.enter();
config = new TRHostConfigImpl(this);
TRTrackerClientFactory.addListener( this );
Thread t = new AEThread("TRHost::stats.loop")
{
public void
runSupport()
{
while(true){
try{
if ( COConfigurationManager.getBooleanParameter( "Tracker Port Enable", false )){
try{
int port = COConfigurationManager.getIntParameter("Tracker Port", TRHost.DEFAULT_PORT );
startServer( TRTrackerServerFactory.PR_TCP, port, false );
}catch( Throwable e ){
Debug.printStackTrace( e );
}
}
if ( COConfigurationManager.getBooleanParameter( "Tracker Port UDP Enable", false )){
try{
int port = COConfigurationManager.getIntParameter("Tracker Port", TRHost.DEFAULT_PORT );
startServer( TRTrackerServerFactory.PR_UDP, port, false );
}catch( Throwable e ){
Debug.printStackTrace( e );
}
}
if ( COConfigurationManager.getBooleanParameter( "Tracker Port SSL Enable", false )){
try{
int port = COConfigurationManager.getIntParameter("Tracker Port SSL", TRHost.DEFAULT_PORT_SSL );
startServer( TRTrackerServerFactory.PR_TCP, port, true );
}catch( Throwable e ){
Debug.printStackTrace( e );
}
}
Thread.sleep( STATS_PERIOD_SECS*1000 );
try{
this_mon.enter();
for (int i=0;i<host_torrents.size();i++){
TRHostTorrent ht = (TRHostTorrent)host_torrents.get(i);
if ( ht instanceof TRHostTorrentHostImpl ){
((TRHostTorrentHostImpl)ht).updateStats();
}else{
((TRHostTorrentPublishImpl)ht).updateStats();
}
}
}finally{
this_mon.exit();
}
config.saveConfig();
}catch( InterruptedException e ){
Debug.printStackTrace( e );
break;
}
}
}
};
t.setDaemon(true);
// try to ensure that the tracker stats are collected reasonably
// regularly
t.setPriority( Thread.MAX_PRIORITY -1);
t.start();
}finally{
this_mon.exit();
}
}
public void
initialise(
TRHostTorrentFinder finder )
{
config.loadConfig( finder );
}
public String
getName()
{
return( TRTrackerServer.DEFAULT_NAME );
}
public TRHostTorrent
hostTorrent(
TOTorrent torrent )
throws TRHostException
{
return( hostTorrent( torrent, true ));
}
public TRHostTorrent
hostTorrent(
TOTorrent torrent,
boolean persistent )
throws TRHostException
{
return( addTorrent( torrent, TRHostTorrent.TS_STARTED, persistent ));
}
public TRHostTorrent
publishTorrent(
TOTorrent torrent )
throws TRHostException
{
return( addTorrent( torrent, TRHostTorrent.TS_PUBLISHED, true ));
}
protected TRHostTorrent
addTorrent(
TOTorrent torrent,
int state,
boolean persistent )
throws TRHostException
{
try{
this_mon.enter();
TRHostTorrent ht = lookupHostTorrent( torrent );
if ( ht != null ){
// check that this isn't the explicit publish/host of a torrent already there
// as an external torrent. If so then just replace the torrent
try{
ht = lookupHostTorrentViaHash( torrent.getHash());
if ( ht instanceof TRHostTorrentHostImpl ){
TRHostTorrentHostImpl hti = (TRHostTorrentHostImpl)ht;
if ( hti.getTorrent() != torrent ){
hti.setTorrent( torrent );
if ( persistent && !hti.isPersistent()){
hti.setPersistent( true );
}
if ( state != TRHostTorrent.TS_PUBLISHED ){
startHosting( hti );
if ( state == TRHostTorrent.TS_STARTED ){
hti.start();
}
}
listeners.dispatch( LDT_TORRENT_CHANGED, ht );
}
}
}catch( TOTorrentException e ){
Debug.printStackTrace( e );
}
return( ht );
}
int port;
boolean ssl;
int protocol = TRTrackerServerFactory.PR_TCP;
if ( state == TRHostTorrent.TS_PUBLISHED ){
port = COConfigurationManager.getIntParameter("Tracker Port", TRHost.DEFAULT_PORT );
ssl = false;
}else{
URL announce_url = torrent.getAnnounceURL();
String protocol_str = announce_url.getProtocol();
ssl = protocol_str.equalsIgnoreCase("https");
if ( protocol_str.equalsIgnoreCase("udp")){
protocol = TRTrackerServerFactory.PR_UDP;
}
boolean force_external = COConfigurationManager.getBooleanParameter("Tracker Port Force External", false );
port = announce_url.getPort();
if ( force_external ){
String tracker_ip = COConfigurationManager.getStringParameter("Tracker IP", "");
if ( tracker_ip.length() > 0 &&
!announce_url.getHost().equalsIgnoreCase( tracker_ip )){
if ( ssl ){
port = COConfigurationManager.getIntParameter("Tracker Port SSL", TRHost.DEFAULT_PORT_SSL );
}else{
port = COConfigurationManager.getIntParameter("Tracker Port", TRHost.DEFAULT_PORT );
}
}
}
if ( port == -1 ){
port = ssl?URL_DEFAULT_PORT_SSL:URL_DEFAULT_PORT;
}
}
TRTrackerServer server = startServer( protocol, port, ssl );
TRHostTorrent host_torrent;
if ( state == TRHostTorrent.TS_PUBLISHED ){
host_torrent = new TRHostTorrentPublishImpl( this, torrent );
}else{
host_torrent = new TRHostTorrentHostImpl( this, server, torrent, port );
}
host_torrent.setPersistent( persistent );
host_torrents.add( host_torrent );
try{
host_torrent_hash_map.put( new HashWrapper( torrent.getHash()), host_torrent );
}catch( TOTorrentException e ){
Debug.printStackTrace( e );
}
host_torrent_map.put( torrent, host_torrent );
if ( state != TRHostTorrent.TS_PUBLISHED ){
startHosting((TRHostTorrentHostImpl)host_torrent );
if ( state == TRHostTorrent.TS_STARTED ){
host_torrent.start();
}
// if not persistent, see if we can recover the stats
if ( !persistent ){
config.recoverStats( (TRHostTorrentHostImpl)host_torrent );
}
}
listeners.dispatch( LDT_TORRENT_ADDED, host_torrent );
config.saveConfig();
return( host_torrent );
}finally{
this_mon.exit();
}
}
protected TRTrackerServer
startServer(
int protocol,
int port,
boolean ssl )
throws TRHostException
{
try{
this_mon.enter();
String key = ""+protocol+ ":" + port;
TRTrackerServer server = (TRTrackerServer)server_map.get( key );
if ( server == null ){
try{
if ( ssl ){
server = TRTrackerServerFactory.createSSL( protocol, port, true );
}else{
server = TRTrackerServerFactory.create( protocol, port, true );
}
server_map.put( key, server );
if ( auth_listeners.size() > 0 ){
server.addAuthenticationListener( this );
}
server.addListener( this );
}catch( TRTrackerServerException e ){
LGLogger.log(0, 0, LGLogger.ERROR, "Tracker Host: failed to start server: " + e.toString());
throw( new TRHostException( e.getMessage()));
}
}
return( server );
}finally{
this_mon.exit();
}
}
protected TRHostTorrent
lookupHostTorrent(
TOTorrent torrent )
{
if (torrent == null)
return null;
try{
return((TRHostTorrent)host_torrent_hash_map.get( torrent.getHashWrapper()));
}catch( TOTorrentException e ){
Debug.printStackTrace( e );
}
return( null );
}
protected void
startHosting(
TRHostTorrentHostImpl host_torrent )
{
TOTorrent torrent = host_torrent.getTorrent();
TRTrackerClient tc = (TRTrackerClient)tracker_client_map.get( torrent );
if ( tc != null ){
startHosting( host_torrent, tc );
}
}
protected void
startHosting(
TRTrackerClient tracker_client )
{
TRHostTorrent host_torrent = (TRHostTorrent)host_torrent_map.get( tracker_client.getTorrent());
if ( host_torrent instanceof TRHostTorrentHostImpl ){
startHosting( (TRHostTorrentHostImpl)host_torrent, tracker_client );
}
}
protected void
startHosting(
TRHostTorrentHostImpl host_torrent,
final TRTrackerClient tracker_client )
{
final TOTorrent torrent = host_torrent.getTorrent();
// set the ip override so that we announce ourselves to other peers via the
// real external address, not the local one used to connect to the tracker
tracker_client.setIPOverride( torrent.getAnnounceURL().getHost());
// hook into the client so that when the announce succeeds after the refresh below
// we can force a rescrape to pick up the new status
TRTrackerClientListener listener =
new TRTrackerClientListener()
{
public void
receivedTrackerResponse(
TRTrackerResponse response )
{
try{
TRTrackerScraperFactory.getSingleton().scrape( torrent, true );
}finally{
tracker_client.removeListener( this );
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -