diff --git a/libs/limelight-common.jar b/libs/limelight-common.jar index 1e8b23c8..e62ea43c 100644 Binary files a/libs/limelight-common.jar and b/libs/limelight-common.jar differ diff --git a/src/com/limelight/Game.java b/src/com/limelight/Game.java index 56e143eb..534ea2c2 100644 --- a/src/com/limelight/Game.java +++ b/src/com/limelight/Game.java @@ -1,5 +1,12 @@ package com.limelight; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; + import com.limelight.binding.PlatformBinding; import com.limelight.binding.input.ControllerHandler; import com.limelight.binding.input.KeyboardTranslator; @@ -19,6 +26,7 @@ import android.content.SharedPreferences; import android.graphics.Point; import android.media.AudioManager; import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.Handler; @@ -161,10 +169,29 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM wifiLock = wifiMgr.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "Limelight"); wifiLock.setReferenceCounted(false); wifiLock.acquire(); + + String host = Game.this.getIntent().getStringExtra("host"); + InetAddress addr; + boolean enableLargePackets; + try { + // If this does a DNS lookup, it could cause a NetworkOnMainThread exception + // Chances are if it has to do this, we're not on the same network anyways + addr = InetAddress.getByName(host); + + // Check if we can enable large packets if we get this far + enableLargePackets = shouldEnableLargePackets(addr); + } catch (Exception e) { + // We don't want to deal with any exceptions here. The user will be notified + // when the connection fails + enableLargePackets = false; + } + + LimeLog.info("Using large packets? "+enableLargePackets); // Start the connection - conn = new NvConnection(Game.this.getIntent().getStringExtra("host"), Game.this, - new StreamConfiguration(width, height, refreshRate, bitrate * 1000), PlatformBinding.getCryptoProvider(this)); + conn = new NvConnection(host, Game.this, + new StreamConfiguration(width, height, refreshRate, bitrate * 1000, + enableLargePackets ? 1460 : 1024), PlatformBinding.getCryptoProvider(this)); keybTranslator = new KeyboardTranslator(conn); controllerHandler = new ControllerHandler(conn); @@ -172,6 +199,89 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM sh.addCallback(this); } + private boolean shouldEnableLargePackets(InetAddress targetAddress) { + ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo(); + String matchingPrefix; + + if (activeNetworkInfo == null) { + return false; + } + + switch (activeNetworkInfo.getType()) + { + case ConnectivityManager.TYPE_ETHERNET: + matchingPrefix = "eth"; + break; + case ConnectivityManager.TYPE_WIFI: + matchingPrefix = "wlan"; + break; + + default: + // Must be on Ethernet or Wifi to consider that we can send large packets + return false; + } + + // Try to find the interface that corresponds to the active network + try { + Enumeration ifaceList = NetworkInterface.getNetworkInterfaces(); + while (ifaceList.hasMoreElements()) { + NetworkInterface iface = ifaceList.nextElement(); + + // Look for an interface that matches the prefix we expect + if (iface.isUp() && iface.getName().startsWith(matchingPrefix)) { + // Find the IPv4 address for the interface + for (InterfaceAddress addr : iface.getInterfaceAddresses()) { + if (!(addr.getAddress() instanceof Inet4Address)) { + // Skip non-IPv4 addresses + continue; + } + + // Found the right address on the right interface + return isOnSameSubnet(targetAddress, addr.getAddress(), addr.getNetworkPrefixLength()); + } + } + } + } catch (SocketException e) { + e.printStackTrace(); + } + + // We didn't find the interface or something else went wrong + return false; + } + + private boolean isOnSameSubnet(InetAddress targetAddress, InetAddress localAddress, short networkPrefixLength) { + byte[] targetBytes = targetAddress.getAddress(); + byte[] localBytes = localAddress.getAddress(); + + for (int byteIndex = 0; networkPrefixLength > 0; byteIndex++) { + byte target = targetBytes[byteIndex]; + byte local = localBytes[byteIndex]; + + if (networkPrefixLength >= 8) { + // Do a full byte comparison + if (target != local) { + return false; + } + + networkPrefixLength -= 8; + } + else { + target &= (byte)(0xFF << (8 - networkPrefixLength)); + local &= (byte)(0xFF << (8 - networkPrefixLength)); + + // Do a masked comparison + if (target != local) { + return false; + } + + networkPrefixLength = 0; + } + } + + return true; + } + private void checkDataConnection() { ConnectivityManager mgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);