Package com.aelitis.net.upnp.impl.services

Source Code of com.aelitis.net.upnp.impl.services.UPnPSSWANConnectionImpl$portMapping

/*
* Created on 15-Jun-2004
* Created by Paul Gardner
* Copyright (C) 2004, 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.net.upnp.impl.services;

import java.util.*;

import org.gudy.azureus2.core3.util.*;


import com.aelitis.net.upnp.*;
import com.aelitis.net.upnp.impl.UPnPImpl;
import com.aelitis.net.upnp.impl.device.UPnPRootDeviceImpl;
import com.aelitis.net.upnp.services.UPnPWANConnection;
import com.aelitis.net.upnp.services.UPnPWANConnectionListener;
import com.aelitis.net.upnp.services.UPnPWANConnectionPortMapping;

/**
* @author parg
*
*/

public abstract class
UPnPSSWANConnectionImpl
  implements UPnPWANConnection
{
  private static AEMonitor  class_mon   = new AEMonitor( "UPnPSSWANConnection" );
  private static List      services  = new ArrayList();
 
  static{
   
    SimpleTimer.addPeriodicEvent(
        "UPnPSSWAN:checker",
        10*60*1000,
        new TimerEventPerformer() {
          public void perform( TimerEvent ev ) {
      
            try{             
              List  to_check = new ArrayList();
             
              try{
                class_mon.enter();
               
                Iterator  it = services.iterator();
               
                while( it.hasNext()){
                 
                  UPnPSSWANConnectionImpl  s = (UPnPSSWANConnectionImpl)it.next();
               
                  if ( s.getGenericService().getDevice().getRootDevice().isDestroyed()){
                   
                    it.remove();
                   
                  }else{
                   
                    to_check.add( s );
                  }
                }
                               
              }finally{
               
                class_mon.exit();
              }
             
              for (int i=0;i<to_check.size();i++){
   
                try{
                  ((UPnPSSWANConnectionImpl)to_check.get(i)).checkMappings();
                 
                }catch( Throwable e ){
                 
                  //Debug.printStackTrace(e);
                }
              }
            }catch( Throwable e ){
             
              Debug.printStackTrace(e);
            }
          }
        }
     );
   
  }
 
  private UPnPServiceImpl    service;
  private List        mappings  = new ArrayList();
  private List        listeners  = new ArrayList();
 
  private boolean        recheck_mappings  = true;
 
    // start off true to avoid logging first of repetitive failures
 
  private boolean        last_mapping_check_failed  = true;
 
  protected
  UPnPSSWANConnectionImpl(
    UPnPServiceImpl    _service )
  {
    service  = _service;
   
    try{
      class_mon.enter();

      services.add( this );
     
    }finally{
     
      class_mon.exit();
    }
  }
 
  public int
  getCapabilities()
  {
    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 UPnPService
  getGenericService()
  {
    return( service );
  }
 
  public String[]
     getStatusInfo()
             
       throws UPnPException
     {
    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 });
    }   
     }
 
  public void
  periodicallyRecheckMappings(
    boolean  on )
  {
    recheck_mappings  = on;
  }
 
  protected void
  checkMappings()
 
    throws UPnPException
  {   
    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());
        }

        addPortMappingmapping.isTCP(), mapping.getExternalPort(), mapping.getDescription());
       
      }catch( Throwable e ){
       
        Debug.printStackTrace(e);
      }
    }
  }
 
  public void
  addPortMapping(
    boolean    tcp,      // false -> UDP
    int      port,
    String    description )
 
    throws UPnPException
  {
    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();
      }
    }
  }
 
  public void
  deletePortMapping(
    boolean    tcp,     
    int      port )
 
    throws UPnPException
  {
    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 UPnPWANConnectionPortMapping[]
  getPortMappings()
                   
    throws UPnPException
  {
    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 String
  getExternalIPAddress()
 
    throws UPnPException
  {
    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 );
   
  }
 
  protected void
  log(
    String  str )
  {
    service.getDevice().getRootDevice().getUPnP().log( str );
  }
 
  public void
  addListener(
    UPnPWANConnectionListener  listener )
  {
    listeners.add( listener );
  }
 
  public void
  removeListener(
    UPnPWANConnectionListener  listener )
  {
    listeners.add( listener );
  }
 
  protected class
  portMapping
    implements UPnPWANConnectionPortMapping
  {
    protected int      external_port;
    protected boolean    tcp;
    protected String    internal_host;
    protected String    description;
   
    protected
    portMapping(
      int      _external_port,
      boolean    _tcp,
      String    _internal_host,
      String    _description )
    {
      external_port  = _external_port;
      tcp        = _tcp;
      internal_host  = _internal_host;
      description    = _description;
    }
   
    public boolean
    isTCP()
    {
      return( tcp );
    }
   
    public int
    getExternalPort()
    {
      return( external_port );
    }
   
    public String
    getInternalHost()
    {
      return( internal_host );
    }
   
    public String
    getDescription()
    {
      return( description );
    }
   
    protected String
    getString()
    {
      return( getDescription() + " [" + getExternalPort() + ":" + (isTCP()?"TCP":"UDP") + "]");
    }
  }
}
TOP

Related Classes of com.aelitis.net.upnp.impl.services.UPnPSSWANConnectionImpl$portMapping

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.