/*
* Created on 10 Jul 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.nat;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import org.gudy.azureus2.core3.util.AERunnable;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.ThreadPool;
import org.gudy.azureus2.plugins.PluginInterface;
import com.aelitis.azureus.core.AzureusCore;
import com.aelitis.azureus.core.dht.DHT;
import com.aelitis.azureus.core.dht.nat.DHTNATPuncher;
import com.aelitis.azureus.core.dht.nat.DHTNATPuncherAdapter;
import com.aelitis.azureus.core.dht.transport.DHTTransportContact;
import com.aelitis.azureus.plugins.dht.DHTPlugin;
public class
NATTraverser
implements DHTNATPuncherAdapter
{
public static final int TRAVERSE_REASON_PEER_DATA = 1;
public static final int TRAVERSE_REASON_GENERIC_MESSAGING = 2;
private static final int MAX_QUEUE_SIZE = 128;
private AzureusCore core;
private DHTNATPuncher puncher;
private ThreadPool thread_pool = new ThreadPool("NATTraverser", 16, true );
private Map handlers = new HashMap();
public
NATTraverser(
AzureusCore _core )
{
core = _core;
}
public void
registerHandler(
NATTraversalHandler handler )
{
synchronized( handlers ){
handlers.put( new Integer(handler.getType()), handler );
}
}
public NATTraversal
attemptTraversal(
final NATTraversalHandler handler,
final InetSocketAddress target,
final Map request,
boolean sync,
final NATTraversalObserver listener )
{
final NATTraversal traversal =
new NATTraversal()
{
private boolean cancelled;
public void
cancel()
{
cancelled = true;
}
public boolean
isCancelled()
{
return( cancelled );
}
};
if ( sync ){
syncTraverse( handler, target, request, listener );
}else{
if ( thread_pool.getQueueSize() >= MAX_QUEUE_SIZE ){
Debug.out( "NATTraversal queue full" );
listener.failed( NATTraversalObserver.FT_QUEUE_FULL );
}else{
thread_pool.run(
new AERunnable()
{
public void
runSupport()
{
if ( traversal.isCancelled()){
listener.failed( NATTraversalObserver.FT_CANCELLED );
}else{
syncTraverse( handler, target, request, listener );
}
}
});
}
}
return( traversal );
}
protected void
syncTraverse(
NATTraversalHandler handler,
InetSocketAddress target,
Map request,
NATTraversalObserver listener )
{
try{
int type = handler.getType();
synchronized( this ){
if ( puncher == null ){
PluginInterface dht_pi =
core.getPluginManager().getPluginInterfaceByClass( DHTPlugin.class );
if ( dht_pi != null ){
DHTPlugin dht_plugin = (DHTPlugin)dht_pi.getPlugin();
if ( dht_plugin.isEnabled()){
DHT[] dhts = dht_plugin.getDHTs();
if ( dhts.length > 0 ){
puncher = dhts[dhts.length-1].getNATPuncher();
}
}
}
}
if ( puncher == null ){
listener.disabled();
return;
}
}
if ( request == null ){
request = new HashMap();
}
request.put( "_travreas", new Long( type ));
InetSocketAddress[] target_a = { target };
DHTTransportContact[] rendezvous_used = {null};
Map reply = puncher.punch( handler.getName(), target_a, rendezvous_used, request );
if ( reply == null ){
if ( rendezvous_used[0] == null ){
listener.failed( NATTraversalObserver.FT_NO_RENDEZVOUS );
}else{
listener.failed( new Exception( "NAT traversal failed" ));
}
}else{
listener.succeeded( rendezvous_used[0].getAddress(), target_a[0], reply );
}
}catch( Throwable e ){
listener.failed( e );
}
}
public Map
sendMessage(
NATTraversalHandler handler,
InetSocketAddress rendezvous,
InetSocketAddress target,
Map message )
throws NATTraversalException
{
if ( puncher == null ){
throw( new NATTraversalException( "Puncher unavailable" ));
}
message.put( "_travreas", new Long( handler.getType()));
Map reply = puncher.sendMessage( rendezvous, target, message );
if ( reply == null ){
throw( new NATTraversalException( "Send message failed" ));
}
return( reply );
}
public Map
getClientData(
InetSocketAddress originator,
Map originator_data )
{
Long type = (Long)originator_data.get( "_travreas" );
if ( type != null ){
NATTraversalHandler handler;
synchronized( handlers ){
handler = (NATTraversalHandler)handlers.get( new Integer( type.intValue()));
}
if ( handler != null ){
return( handler.process( originator, originator_data ));
}
}
return( null );
}
}