/* * 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 org.gudy.azureus2.pluginsimpl.local.PluginCoreUtils; import org.gudy.azureus2.pluginsimpl.local.PluginInitializer; 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; public static final int TRAVERSE_REASON_PAIR_TUNNEL = 3; 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 ){ if ( !PluginCoreUtils.isInitialisationComplete()){ listener.failed( new Exception( "NAT traversal failed, initialisation not complete" )); return; } PluginInterface dht_pi = core.getPluginManager().getPluginInterfaceByClass( DHTPlugin.class ); if ( dht_pi != null ){ DHTPlugin dht_plugin = (DHTPlugin)dht_pi.getPlugin(); if ( dht_plugin.isEnabled()){ DHT dht = dht_plugin.getDHT( DHT.NW_MAIN ); if ( dht == null ){ dht = dht_plugin.getDHT( DHT.NW_CVS ); } if ( dht != null ){ puncher = dht.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 ); } }