diff --git a/moonlight-common/src/main/java/com/limelight/nvstream/ConnectionContext.java b/moonlight-common/src/main/java/com/limelight/nvstream/ConnectionContext.java index a07a09ba..d1c933e4 100644 --- a/moonlight-common/src/main/java/com/limelight/nvstream/ConnectionContext.java +++ b/moonlight-common/src/main/java/com/limelight/nvstream/ConnectionContext.java @@ -7,7 +7,7 @@ import javax.crypto.SecretKey; import com.limelight.nvstream.av.video.VideoDecoderRenderer; public class ConnectionContext { - public InetAddress serverAddress; + public String serverAddress; public StreamConfiguration streamConfig; public NvConnectionListener connListener; public SecretKey riKey; diff --git a/moonlight-common/src/main/java/com/limelight/nvstream/NvConnection.java b/moonlight-common/src/main/java/com/limelight/nvstream/NvConnection.java index 53159c21..c2fea522 100644 --- a/moonlight-common/src/main/java/com/limelight/nvstream/NvConnection.java +++ b/moonlight-common/src/main/java/com/limelight/nvstream/NvConnection.java @@ -223,13 +223,7 @@ public class NvConnection { String appName = context.streamConfig.getApp().getAppName(); - try { - context.serverAddress = InetAddress.getByName(host); - } catch (UnknownHostException e) { - context.connListener.connectionTerminated(-1); - return; - } - + context.serverAddress = host; context.connListener.stageStarting(appName); try { @@ -249,7 +243,7 @@ public class NvConnection { // we must not invoke that functionality in parallel. synchronized (MoonBridge.class) { MoonBridge.setupBridge(videoDecoderRenderer, audioRenderer, connectionListener); - MoonBridge.startConnection(context.serverAddress.getHostAddress(), + MoonBridge.startConnection(context.serverAddress, context.serverAppVersion, context.serverGfeVersion, context.negotiatedWidth, context.negotiatedHeight, context.negotiatedFps, context.streamConfig.getBitrate(), diff --git a/moonlight-common/src/main/java/com/limelight/nvstream/http/ComputerDetails.java b/moonlight-common/src/main/java/com/limelight/nvstream/http/ComputerDetails.java index ebf7419a..e1ab1d44 100644 --- a/moonlight-common/src/main/java/com/limelight/nvstream/http/ComputerDetails.java +++ b/moonlight-common/src/main/java/com/limelight/nvstream/http/ComputerDetails.java @@ -16,8 +16,8 @@ public class ComputerDetails { public Reachability reachability; public String name; public UUID uuid; - public InetAddress localAddress; - public InetAddress remoteAddress; + public String localAddress; + public String remoteAddress; public PairingManager.PairState pairState; public String macAddress; public int runningGameId; diff --git a/moonlight-common/src/main/java/com/limelight/nvstream/http/NvHTTP.java b/moonlight-common/src/main/java/com/limelight/nvstream/http/NvHTTP.java index 2dede3ae..faa0ef03 100644 --- a/moonlight-common/src/main/java/com/limelight/nvstream/http/NvHTTP.java +++ b/moonlight-common/src/main/java/com/limelight/nvstream/http/NvHTTP.java @@ -10,6 +10,8 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; import java.security.Principal; import java.security.PrivateKey; import java.security.SecureRandom; @@ -46,7 +48,7 @@ import com.squareup.okhttp.ResponseBody; public class NvHTTP { private String uniqueId; private PairingManager pm; - private InetAddress address; + private String address; public static final int HTTPS_PORT = 47984; public static final int HTTP_PORT = 47989; @@ -104,23 +106,21 @@ public class NvHTTP { httpClientWithReadTimeout.setReadTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS); } - public NvHTTP(InetAddress host, String uniqueId, String deviceName, LimelightCryptoProvider cryptoProvider) { + public NvHTTP(String address, String uniqueId, String deviceName, LimelightCryptoProvider cryptoProvider) throws IOException { this.uniqueId = uniqueId; - this.address = host; - - String safeAddress; - if (host instanceof Inet6Address) { - // RFC2732-formatted IPv6 address for use in URL - safeAddress = "["+host.getHostAddress()+"]"; - } - else { - safeAddress = host.getHostAddress(); - } + this.address = address; initializeHttpState(cryptoProvider); - - this.baseUrlHttps = "https://" + safeAddress + ":" + HTTPS_PORT; - this.baseUrlHttp = "http://" + safeAddress + ":" + HTTP_PORT; + + try { + // The URI constructor takes care of escaping IPv6 literals + this.baseUrlHttps = new URI("https", null, address, HTTPS_PORT, null, null, null).toString(); + this.baseUrlHttp = new URI("http", null, address, HTTP_PORT, null, null, null).toString(); + } catch (URISyntaxException e) { + // Encapsulate URISyntaxException into IOException for callers to handle more easily + throw new IOException(e); + } + this.pm = new PairingManager(this, cryptoProvider); } @@ -212,20 +212,17 @@ public class NvHTTP { details.macAddress = getXmlString(serverInfo, "mac"); // If there's no LocalIP field, use the address we hit the server on - String localIpStr = getXmlString(serverInfo, "LocalIP"); - if (localIpStr == null) { - localIpStr = address.getHostAddress(); + details.localAddress = getXmlString(serverInfo, "LocalIP"); + if (details.localAddress == null) { + details.localAddress = address; } // If there's no ExternalIP field, use the address we hit the server on - String externalIpStr = getXmlString(serverInfo, "ExternalIP"); - if (externalIpStr == null) { - externalIpStr = address.getHostAddress(); + details.remoteAddress = getXmlString(serverInfo, "ExternalIP"); + if (details.remoteAddress == null) { + details.remoteAddress = address; } - details.localAddress = InetAddress.getByName(localIpStr); - details.remoteAddress = InetAddress.getByName(externalIpStr); - try { details.pairState = Integer.parseInt(getXmlString(serverInfo, "PairStatus")) == 1 ? PairState.PAIRED : PairState.NOT_PAIRED; diff --git a/moonlight-common/src/main/java/com/limelight/nvstream/mdns/MdnsComputer.java b/moonlight-common/src/main/java/com/limelight/nvstream/mdns/MdnsComputer.java index 67242ca8..fe7761aa 100644 --- a/moonlight-common/src/main/java/com/limelight/nvstream/mdns/MdnsComputer.java +++ b/moonlight-common/src/main/java/com/limelight/nvstream/mdns/MdnsComputer.java @@ -1,12 +1,12 @@ package com.limelight.nvstream.mdns; -import java.net.InetAddress; +import java.net.Inet4Address; public class MdnsComputer { - private InetAddress ipAddr; + private Inet4Address ipAddr; private String name; - public MdnsComputer(String name, InetAddress addr) { + public MdnsComputer(String name, Inet4Address addr) { this.name = name; this.ipAddr = addr; } @@ -15,7 +15,7 @@ public class MdnsComputer { return name; } - public InetAddress getAddress() { + public Inet4Address getAddress() { return ipAddr; } diff --git a/moonlight-common/src/main/java/com/limelight/nvstream/wol/WakeOnLanSender.java b/moonlight-common/src/main/java/com/limelight/nvstream/wol/WakeOnLanSender.java index 0eee7348..72bd5c33 100644 --- a/moonlight-common/src/main/java/com/limelight/nvstream/wol/WakeOnLanSender.java +++ b/moonlight-common/src/main/java/com/limelight/nvstream/wol/WakeOnLanSender.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.Scanner; import com.limelight.LimeLog; @@ -17,28 +18,41 @@ public class WakeOnLanSender { public static void sendWolPacket(ComputerDetails computer) throws IOException { DatagramSocket sock = new DatagramSocket(0); - byte[] payload = createWolPayload(computer); - // Try both remote and local addresses - for (int i = 0; i < 2; i++) { - InetAddress addr; - if (i == 0) { - addr = computer.localAddress; - } - else { - addr = computer.remoteAddress; - } - - // Try all the ports for each address - for (int port : PORTS_TO_TRY) { - DatagramPacket dp = new DatagramPacket(payload, payload.length); - dp.setAddress(addr); - dp.setPort(port); - sock.send(dp); + IOException lastException = null; + boolean sentWolPacket = false; + + try { + // Try all resolved remote and local addresses + for (String unresolvedAddress : new String[] {computer.localAddress, computer.remoteAddress}) { + try { + for (InetAddress resolvedAddress : InetAddress.getAllByName(unresolvedAddress)) { + // Try all the ports for each resolved address + for (int port : PORTS_TO_TRY) { + DatagramPacket dp = new DatagramPacket(payload, payload.length); + dp.setAddress(resolvedAddress); + dp.setPort(port); + sock.send(dp); + sentWolPacket = true; + } + } + } catch (IOException e) { + // We may have addresses that don't resolve on this subnet, + // but don't throw and exit the whole function if that happens. + // We'll throw it at the end if we didn't send a single packet. + e.printStackTrace(); + lastException = e; + } } + } finally { + sock.close(); + } + + // Propagate the DNS resolution exception if we didn't + // manage to get a single packet out to the host. + if (!sentWolPacket && lastException != null) { + throw lastException; } - - sock.close(); } private static byte[] macStringToBytes(String macAddress) {