gt:             ifName = iface.getName();
context: /*
   * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package net.java.sip.communicator.impl.netaddr;
  
  import java.beans.*;
  import java.io.*;
  import java.lang.reflect.*;
  import java.net.*;
  import java.text.*;
  import java.util.*;
  
  import net.java.sip.communicator.service.dns.*;
  import net.java.sip.communicator.service.netaddr.*;
  import net.java.sip.communicator.service.netaddr.event.*;
  import net.java.sip.communicator.util.*;
  import net.java.sip.communicator.util.Logger;
  import net.java.sip.communicator.util.NetworkUtils;
  
  import org.ice4j.*;
  import org.ice4j.ice.*;
  import org.ice4j.ice.harvest.*;
  import org.ice4j.security.*;
  import org.ice4j.stack.*;
  import org.jitsi.service.configuration.*;
  import org.jitsi.util.*;
  
  /**
   * This implementation of the Network Address Manager allows you to
   * intelligently retrieve the address of your localhost according to the
   * destinations that you will be trying to reach. It also provides an interface
   * to the ICE implementation in ice4j.
   *
   * @author Emil Ivov
   */
  public class NetworkAddressManagerServiceImpl
      implements NetworkAddressManagerService
  {
      /**
       * Our class logger.
       */
      private static  Logger logger =
          Logger.getLogger(NetworkAddressManagerServiceImpl.class);
  
      /**
       * The socket that we use for dummy connections during selection of a local
       * address that has to be used when communicating with a specific location.
       */
      DatagramSocket localHostFinderSocket = null;
  
      /**
       * A random (unused)local port to use when trying to select a local host
       * address to use when sending messages to a specific destination.
       */
      private static final int RANDOM_ADDR_DISC_PORT = 55721;
  
      /**
       * The name of the property containing the number of binds that we should
       * should execute in case a port is already bound to (each retry would be on
       * a new random port).
       */
      public static final String BIND_RETRIES_PROPERTY_NAME
          = "net.java.sip.communicator.service.netaddr.BIND_RETRIES";
  
      /**
       * Default STUN server port.
       */
      public static final int DEFAULT_STUN_SERVER_PORT = 3478;
  
      /**
       * A thread which periodically scans network interfaces and reports
       * changes in network configuration.
       */
      private NetworkConfigurationWatcher networkConfigurationWatcher = null;
  
      /**
       * The service name to use when discovering TURN servers through DNS using
       * SRV requests as per RFC 5766.
       */
      public static final String TURN_SRV_NAME = "turn";
  
      /**
       * The service name to use when discovering STUN servers through DNS using
       * SRV requests as per RFC 5389.
       */
      public static final String STUN_SRV_NAME = "stun";
  
       /**
        * Initializes this network address manager service implementation.
        */
       public void start()
       {
           this.localHostFinderSocket = initRandomPortSocket();
  
           // set packet logging to ice4j stack
           StunStack.setPacketLogger(new Ice4jPacketLogger());
       }
  
       /**
        * Kills all threads/processes launched by this thread (if any) and
        * prepares it for shutdown. You may use this method as a reinitialization
        * technique (you'll have to call start afterwards)
        */
       public void stop()
       {
           try
           {
               if(networkConfigurationWatcher != null)
                   networkConfigurationWatcher.stop();
           }
           finally
           {
               logger.logExit();
           }
       }
  
      /**
       * Returns an InetAddress instance that represents the localhost, and that
       * a socket can bind upon or distribute to peers as a contact address.
       *
       * @param intendedDestination the destination that we'd like to use the
       * localhost address with.
       *
       * @return an InetAddress instance representing the local host, and that
       * a socket can bind upon or distribute to peers as a contact address.
       */
      public synchronized InetAddress getLocalHost(
              InetAddress intendedDestination)
      {
          InetAddress localHost = null;
  
          if(logger.isTraceEnabled())
          {
              logger.trace(
                      "Querying for a localhost address"
                          + " for intended destination '"
                          + intendedDestination
                          + "'");
          }
  
          /* use native code (JNI) to find source address for a specific
           * destination address on Windows XP SP1 and over.
           *
           * For other systems, we used method based on DatagramSocket.connect
           * which will returns us source address. The reason why we cannot use it
           * on Windows is because its socket implementation returns the any
           * address...
           */
          String osVersion;
  
          if (OSUtils.IS_WINDOWS
                  && !(osVersion = System.getProperty("os.version")).startsWith(
                          "4") /* 95/98/Me/NT */
                  && !osVersion.startsWith("5.0")) /* 2000 */
          {
              byte[] src
                  = Win32LocalhostRetriever.getSourceForDestination(
                          intendedDestination.getAddress());
  
              if (src == null)
              {
                  logger.warn("Failed to get localhost ");
              }
              else
              {
                  try
                  {
                      localHost = InetAddress.getByAddress(src);
                  }
                  catch(UnknownHostException uhe)
                  {
                      logger.warn("Failed to get localhost", uhe);
                  }
              }
          }
          else
          {
              //no point in making sure that the localHostFinderSocket is
              //initialized.
              //better let it through a NullPointerException.
              localHostFinderSocket.connect(intendedDestination,
                                            RANDOM_ADDR_DISC_PORT);
              localHost = localHostFinderSocket.getLocalAddress();
              localHostFinderSocket.disconnect();
          }
  
          //windows socket implementations return the any address so we need to
          //find something else here ... InetAddress.getLocalHost seems to work
          //better on windows so let's hope it'll do the trick.
          if (localHost == null)
          {
              try
              {
                  localHost = InetAddress.getLocalHost();
              }
              catch (UnknownHostException e)
              {
                  logger.warn("Failed to get localhost ", e);
              }
          }
          if (localHost.isAnyLocalAddress())
          {
              if (logger.isTraceEnabled())
              {
                  logger.trace(
                          "Socket returned the ANY local address."
                              + " Trying a workaround.");
              }
              try
              {
                  //all that's inside the if is an ugly IPv6 hack
                  //(good ol' IPv6 - always causing more problems than it solves.)
                  if (intendedDestination instanceof Inet6Address)
                  {
                      //return the first globally routable ipv6 address we find
                      //on the machine (and hope it's a good one)
                      boolean done = false;
                      Enumeration<NetworkInterface> ifaces
                          = NetworkInterface.getNetworkInterfaces();
  
                      while (!done && ifaces.hasMoreElements())
                      {
                          Enumeration<InetAddress> addresses
                              = ifaces.nextElement().getInetAddresses();
  
                          while (addresses.hasMoreElements())
                          {
                              InetAddress address = addresses.nextElement();
  
                              if ((address instanceof Inet6Address)
                                      && !address.isAnyLocalAddress()
                                      && !address.isLinkLocalAddress()
                                      && !address.isLoopbackAddress()
                                      && !address.isSiteLocalAddress())
                              {
                                  localHost = address;
                                  done = true;
                                  break;
                              }
                          }
                      }
                  }
                  else
                  // an IPv4 destination
                  {
                      // first try the easy way
                      localHost = InetAddress.getLocalHost();
  
                      // Make sure we got an IPv4 address.
                      if (!(localHost instanceof Inet4Address))
                      {
                          // return the first non-loopback interface we find.
                          boolean done = false;
                          Enumeration<NetworkInterface> ifaces
                              = NetworkInterface.getNetworkInterfaces();
  
                          while (!done && ifaces.hasMoreElements())
                          {
                              Enumeration<InetAddress> addresses
                                  = ifaces.nextElement().getInetAddresses();
  
                              while (addresses.hasMoreElements())
                              {
                                  InetAddress address = addresses.nextElement();
  
                                  if ((address instanceof Inet4Address)
                                          && !address.isLoopbackAddress())
                                  {
                                      localHost = address;
                                      done = true;
                                      break;
                                  }
                              }
                          }
                      }
                  }
              }
              catch (Exception e)
              {
                  //sigh ... ok return 0.0.0.0
                  logger.warn("Failed to get localhost", e);
              }
          }
  
          if (logger.isTraceEnabled())
              logger.trace("Returning the localhost address '" + localHost + "'");
          return localHost;
      }
  
      /**
       * Returns the hardware address (i.e. MAC address) of the specified
       * interface name.
       *
       * @param iface the <tt>NetworkInterface</tt>
       * @return array of bytes representing the layer 2 address or null if
       * interface does not exist
       */
      public byte[] getHardwareAddress(NetworkInterface iface)
      {
          String ifName = null;
          byte hwAddress[] = null;
  
          /* try reflection */
          try
          {
              Method method = iface.getClass().
                  getMethod("getHardwareAddress");
  
              if(method != null)
              {
                  hwAddress = (byte[])method.invoke(iface, new Object[]{});
                  return hwAddress;
              }
          }
          catch(Exception e)
          {
          }
  
          /* maybe getHardwareAddress not available on this JVM try
           * with our JNI
           */
          if(OSUtils.IS_WINDOWS)
          {
              ifName = iface.getDisplayName();
          }
          else
          {
  