View Javadoc
1   /*
2    * Copyright (C) 2013 4th Line GmbH, Switzerland
3    *
4    * The contents of this file are subject to the terms of either the GNU
5    * Lesser General Public License Version 2 or later ("LGPL") or the
6    * Common Development and Distribution License Version 1 or later
7    * ("CDDL") (collectively, the "License"). You may not use this file
8    * except in compliance with the License. See LICENSE.txt for more
9    * information.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14   */
15  
16  package org.fourthline.cling.android;
17  
18  import org.fourthline.cling.transport.impl.NetworkAddressFactoryImpl;
19  import org.fourthline.cling.transport.spi.InitializationException;
20  
21  import java.lang.reflect.Field;
22  import java.net.Inet4Address;
23  import java.net.Inet6Address;
24  import java.net.InetAddress;
25  import java.net.NetworkInterface;
26  import java.util.logging.Level;
27  import java.util.logging.Logger;
28  
29  /**
30   * This factory tries to work around and patch some Android bugs.
31   *
32   * @author Michael Pujos
33   * @author Christian Bauer
34   */
35  public class AndroidNetworkAddressFactory extends NetworkAddressFactoryImpl {
36  
37      final private static Logger log = Logger.getLogger(AndroidUpnpServiceConfiguration.class.getName());
38  
39      public AndroidNetworkAddressFactory(int streamListenPort) {
40          super(streamListenPort);
41      }
42  
43      @Override
44      protected boolean requiresNetworkInterface() {
45          return false;
46      }
47  
48      @Override
49      protected boolean isUsableAddress(NetworkInterface networkInterface, InetAddress address) {
50          boolean result = super.isUsableAddress(networkInterface, address);
51          if (result) {
52              // TODO: Workaround Android DNS reverse lookup issue, still a problem on ICS+?
53              // http://4thline.org/projects/mailinglists.html#nabble-td3011461
54              String hostName = address.getHostAddress();
55  
56  	    Field field0 = null;
57  	    Object target = null;
58  
59  	    try {
60  
61  		    try {
62  			field0 = InetAddress.class.getDeclaredField("holder");
63  			field0.setAccessible(true);
64  			target = field0.get(address);
65  			field0 = target.getClass().getDeclaredField("hostName");
66  		    } catch( NoSuchFieldException e ) {
67  			// Let's try the non-OpenJDK variant
68  			field0 = InetAddress.class.getDeclaredField("hostName");
69  			target = address;
70  		    }                
71  
72  		    if (field0 != null && target != null && hostName != null) {
73  			field0.setAccessible(true);
74  			field0.set(target, hostName);
75  		    } else {
76  			return false;
77  		    }
78  
79  	    } catch (Exception ex) {
80                  log.log(Level.SEVERE,
81                      "Failed injecting hostName to work around Android InetAddress DNS bug: " + address,
82                      ex
83                  );
84                  return false;
85              }
86          }
87          return result;
88      }
89  
90      @Override
91      public InetAddress getLocalAddress(NetworkInterface networkInterface, boolean isIPv6, InetAddress remoteAddress) {
92          // TODO: This is totally random because we can't access low level InterfaceAddress on Android!
93          for (InetAddress localAddress : getInetAddresses(networkInterface)) {
94              if (isIPv6 && localAddress instanceof Inet6Address)
95                  return localAddress;
96              if (!isIPv6 && localAddress instanceof Inet4Address)
97                  return localAddress;
98          }
99          throw new IllegalStateException("Can't find any IPv4 or IPv6 address on interface: " + networkInterface.getDisplayName());
100     }
101 
102     @Override
103     protected void discoverNetworkInterfaces() throws InitializationException {
104         try {
105             super.discoverNetworkInterfaces();
106         } catch (Exception ex) {
107             // TODO: ICS bug on some models with network interface disappearing while enumerated
108             // http://code.google.com/p/android/issues/detail?id=33661
109             log.warning("Exception while enumerating network interfaces, trying once more: " + ex);
110             super.discoverNetworkInterfaces();
111         }
112     }
113 }