FileDocCategorySizeDatePackage
UPnPSSWANConnectionImpl.javaAPI DocAzureus 3.0.3.415186Thu Feb 15 05:08:54 GMT 2007com.aelitis.net.upnp.impl.services

UPnPSSWANConnectionImpl

public class UPnPSSWANConnectionImpl extends Object implements com.aelitis.net.upnp.services.UPnPWANConnection
author
parg

Fields Summary
private static AEMonitor
class_mon
private static List
services
private UPnPServiceImpl
service
private List
mappings
private List
listeners
private boolean
recheck_mappings
private boolean
last_mapping_check_failed
Constructors Summary
protected UPnPSSWANConnectionImpl(UPnPServiceImpl _service)

	
	
	
				 
	
		service	= _service;
		
		try{
			class_mon.enter();

			services.add( this );
			
		}finally{
			
			class_mon.exit();
		}
	
Methods Summary
public voidaddListener(com.aelitis.net.upnp.services.UPnPWANConnectionListener listener)

		listeners.add( listener );
	
public voidaddPortMapping(boolean tcp, int port, java.lang.String description)

		UPnPAction act = service.getAction( "AddPortMapping" );
		
		if ( act == null ){
			
			log( "Action 'AddPortMapping' not supported, binding not established" );
			
		}else{
					
			UPnPActionInvocation add_inv = act.getInvocation();
			
			add_inv.addArgument( "NewRemoteHost", 				"" );		// "" = wildcard for hosts, 0 = wildcard for ports
			add_inv.addArgument( "NewExternalPort", 			"" + port );
			add_inv.addArgument( "NewProtocol", 				tcp?"TCP":"UDP" );
			add_inv.addArgument( "NewInternalPort", 			"" + port );
			add_inv.addArgument( "NewInternalClient",			service.getDevice().getRootDevice().getLocalAddress().getHostAddress());
			add_inv.addArgument( "NewEnabled", 					"1" );
			add_inv.addArgument( "NewPortMappingDescription", 	description );
			add_inv.addArgument( "NewLeaseDuration",			"0" );		// 0 -> infinite (?)
			
			boolean	ok = false;
			
			try{
				add_inv.invoke();
				
				ok	= true;
			
			}catch( UPnPException original_error ){
				
					// some routers won't add properly if the mapping's already there
				
				try{
					log("Problem when adding port mapping - will try to see if an existing mapping is in the way");
					deletePortMapping(tcp, port);
					
				}catch( Throwable e ){
					
					throw( original_error );
				}
				
				add_inv.invoke();
					
				ok	= true;
	
			}finally{
									
				((UPnPRootDeviceImpl)service.getDevice().getRootDevice()).portMappingResult(ok);
				
				for (int i=0;i<listeners.size();i++){
					
					UPnPWANConnectionListener	listener = (UPnPWANConnectionListener)listeners.get(i);
					
					try{
						listener.mappingResult( this, ok );
					
					}catch( Throwable e){
						
						Debug.printStackTrace(e);
					}
				}
			}
			
			try{
				class_mon.enter();
			
				Iterator	it = mappings.iterator();
				
				while( it.hasNext()){
					
					portMapping	m = (portMapping)it.next();
					
					if ( m.getExternalPort() == port && m.isTCP() == tcp ){
						
						it.remove();
					}
				}
				
				mappings.add( new portMapping( port, tcp, "", description ));
				
			}finally{
				
				class_mon.exit();
			}
		}
	
protected voidcheckMappings()

		
		if ( !recheck_mappings ){
			
			return;
		}
		
		List	mappings_copy;
		
		try{
			class_mon.enter();

			mappings_copy = new ArrayList( mappings );
		
		}finally{
			
			class_mon.exit();
		}
		
		UPnPWANConnectionPortMapping[]	current = getPortMappings();

		Iterator	it = mappings_copy.iterator();
				
		while( it.hasNext()){
		
			portMapping	mapping = (portMapping)it.next();
			
			for (int j=0;j<current.length;j++){
				
				UPnPWANConnectionPortMapping	c = current[j];
				
				if ( 	c.getExternalPort() == mapping.getExternalPort() &&
						c.isTCP() 			== mapping.isTCP()){
							
					it.remove();
					
					break;
				}
			}
		}
		
		boolean	log	= false;

		if ( mappings_copy.size() > 0 ){
			
			if ( !last_mapping_check_failed ){
				
				last_mapping_check_failed	= true;
				
				log	= true;
			}
		}else{
			
			last_mapping_check_failed	= false;
		}

		it = mappings_copy.iterator();
		
		while( it.hasNext()){
			
			portMapping	mapping = (portMapping)it.next();
		
			try{
					// some routers appear to continually fail to report the mappings - avoid 
					// reporting this
				
				if ( log ){
					
					log( "Re-establishing mapping " + mapping.getString());
				}

				addPortMapping(  mapping.isTCP(), mapping.getExternalPort(), mapping.getDescription());
				
			}catch( Throwable e ){
				
				Debug.printStackTrace(e);
			}
		}
	
public voiddeletePortMapping(boolean tcp, int port)

		UPnPAction act = service.getAction( "DeletePortMapping" );
		
		if ( act == null ){
			
			log( "Action 'DeletePortMapping' not supported, binding not removed" );
			
		}else{	

			boolean	mapping_found = false;
			
			try{
				class_mon.enter();

				Iterator	it = mappings.iterator();
				
				while( it.hasNext()){
					
					portMapping	mapping = (portMapping)it.next();
					
					if ( 	mapping.getExternalPort() == port && 
							mapping.isTCP() == tcp ){
						
						it.remove();
						
						mapping_found	= true;
						
						break;
					}
				}
			}finally{
				
				class_mon.exit();
			}
			
			try{
				long	start = SystemTime.getCurrentTime();
				
				UPnPActionInvocation inv = act.getInvocation();
				
				inv.addArgument( "NewRemoteHost", 				"" );		// "" = wildcard for hosts, 0 = wildcard for ports
				inv.addArgument( "NewProtocol", 				tcp?"TCP":"UDP" );
				inv.addArgument( "NewExternalPort", 			"" + port );
				
				inv.invoke();
				
				long	elapsed = SystemTime.getCurrentTime() - start;
	
				if ( elapsed > 4000 ){
					
					String	info = service.getDevice().getRootDevice().getInfo();
					
					((UPnPImpl)service.getDevice().getRootDevice().getUPnP()).logAlert( 
							"UPnP device '" + info + "' is taking a long time to release port mappings, consider disabling this via the UPnP configuration.",
							false,
							UPnPLogListener.TYPE_ONCE_EVER );
				}
			}catch( UPnPException e ){
				
					// only bitch about the failure if we believed we mapped it in the first place
				
				if ( mapping_found ){
					
					throw( e );
					
				}else{
					
					log( "Removal of mapping failed but not established explicitly so ignoring error" );
				}
			}
		}
	
public intgetCapabilities()

		String	device_name = service.getDevice().getRootDevice().getDevice().getFriendlyName();
		
		int	capabilities = CAP_ALL;
		
		if ( device_name.equals( "WRT54G" )){
		
			capabilities = CAP_ALL & ~CAP_UDP_TCP_SAME_PORT;
		}
		
		return( capabilities );
	
public java.lang.StringgetExternalIPAddress()

		UPnPAction act = service.getAction( "GetExternalIPAddress" );
		
		if ( act == null ){
			
			log( "Action 'GetExternalIPAddress' not supported, binding not established" );
			
			throw( new UPnPException( "GetExternalIPAddress not supported" ));
			
		}else{
					
			UPnPActionInvocation inv = act.getInvocation();
						
			UPnPActionArgument[]	args = inv.invoke();
			
			String	ip	= null;
			
			for (int i=0;i<args.length;i++){
				
				UPnPActionArgument	arg = args[i];
			
				String	name = arg.getName();
				
				if ( name.equalsIgnoreCase("NewExternalIPAddress")){
					
					ip = arg.getValue();
				}
			}
			
			return( ip );
		}	
	
public UPnPServicegetGenericService()

		return( service );
	
public com.aelitis.net.upnp.services.UPnPWANConnectionPortMapping[]getPortMappings()

		boolean	ok = true;
		
		try{
			//UPnPStateVariable noe = service.getStateVariable("PortMappingNumberOfEntries");
			//System.out.println( "NOE = " + noe.getValue());
			
			int	entries = 0; //Integer.parseInt( noe.getValue());
			
				// some routers (e.g. Gudy's) return 0 here whatever!
				// In this case take mindless approach
				// hmm, even for my router the state variable isn't accurate...
			
			UPnPAction act	= service.getAction( "GetGenericPortMappingEntry" );
	
			if ( act == null ){
				
				log( "Action 'GetGenericPortMappingEntry' not supported, can't enumerate bindings" );
			
				return( new UPnPWANConnectionPortMapping[0] );
				
			}else{
				
				List	res = new ArrayList();
				
					// I've also seen some routers loop here rather than failing when the index gets too large (they
					// seem to keep returning the last entry) - check for a duplicate entry and exit if found
				
				portMapping	prev_mapping	= null;
				
				for (int i=0;i<(entries==0?512:entries);i++){
							
					UPnPActionInvocation inv = act.getInvocation();
		
					inv.addArgument( "NewPortMappingIndex", "" + i );
					
					try{
						UPnPActionArgument[] outs = inv.invoke();
						
						int		port			= 0;
						boolean	tcp				= false;
						String	internal_host	= null;
						String	description		= "";
						
						for (int j=0;j<outs.length;j++){
							
							UPnPActionArgument	out = outs[j];
							
							String	out_name = out.getName();
							
							if ( out_name.equalsIgnoreCase("NewExternalPort")){
								
								port	= Integer.parseInt( out.getValue());
								
							}else if ( out_name.equalsIgnoreCase( "NewProtocol" )){
								
								tcp = out.getValue().equalsIgnoreCase("TCP");
					
							}else if ( out_name.equalsIgnoreCase( "NewInternalClient" )){
								
								internal_host = out.getValue();
								
							}else if ( out_name.equalsIgnoreCase( "NewPortMappingDescription" )){
								
								description = out.getValue();
							}
						}
				
						if ( prev_mapping != null ){
							
							if ( 	prev_mapping.getExternalPort() == port &&
									prev_mapping.isTCP() == tcp ){
						
									// repeat, get out
								
								break;
							}
						}
						
						prev_mapping = new portMapping( port, tcp, internal_host, description );
						
						res.add( prev_mapping );
						
					}catch( UPnPException e ){
						
						if ( entries == 0 ){
							
							break;
						}
						
						ok	= false;
						
						throw(e);
					}
				}
				
				UPnPWANConnectionPortMapping[]	res2= new UPnPWANConnectionPortMapping[res.size()];
				
				res.toArray( res2 );
		
				return( res2 );
			}
		}finally{
			
			for (int i=0;i<listeners.size();i++){
				
				UPnPWANConnectionListener	listener = (UPnPWANConnectionListener)listeners.get(i);
				
				try{
					listener.mappingsReadResult( this, ok );
				
				}catch( Throwable e){
					
					Debug.printStackTrace(e);
				}
				
			}
		}
	
public java.lang.String[]getStatusInfo()

		UPnPAction act = service.getAction( "GetStatusInfo" );
		
		if ( act == null ){
			
			log( "Action 'GetStatusInfo' not supported, binding not established" );
			
			throw( new UPnPException( "GetStatusInfo not supported" ));
			
		}else{
					
			UPnPActionInvocation inv = act.getInvocation();
						
			UPnPActionArgument[]	args = inv.invoke();
			
			String	connection_status	= null;
			String	connection_error	= null;
			String	uptime				= null;
			
			for (int i=0;i<args.length;i++){
				
				UPnPActionArgument	arg = args[i];
			
				String	name = arg.getName();
				
				if ( name.equalsIgnoreCase("NewConnectionStatus")){
					
					connection_status = arg.getValue();
					
				}else if ( name.equalsIgnoreCase("NewLastConnectionError")){
					
					connection_error = arg.getValue();
					
				}else if ( name.equalsIgnoreCase("NewUptime")){
					
					uptime = arg.getValue();
				}
			}
			
			return( new String[]{ connection_status, connection_error, uptime });
		}		
   	
protected voidlog(java.lang.String str)

		service.getDevice().getRootDevice().getUPnP().log( str );
	
public voidperiodicallyRecheckMappings(boolean on)

		recheck_mappings	= on;
	
public voidremoveListener(com.aelitis.net.upnp.services.UPnPWANConnectionListener listener)

		listeners.add( listener );