mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-04 00:35:47 +00:00
Increase connection timeouts when the PC is presumed to be online
This commit is contained in:
parent
57f55e6856
commit
392e3c7fe3
@ -416,7 +416,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
|
|
||||||
PairingManager pm = httpConn.getPairingManager();
|
PairingManager pm = httpConn.getPairingManager();
|
||||||
|
|
||||||
PairState pairState = pm.pair(httpConn.getServerInfo(), pinStr);
|
PairState pairState = pm.pair(httpConn.getServerInfo(true), pinStr);
|
||||||
if (pairState == PairState.PIN_WRONG) {
|
if (pairState == PairState.PIN_WRONG) {
|
||||||
message = getResources().getString(R.string.pair_incorrect_pin);
|
message = getResources().getString(R.string.pair_incorrect_pin);
|
||||||
}
|
}
|
||||||
|
@ -553,7 +553,7 @@ public class ComputerManagerService extends Service {
|
|||||||
NvHTTP http = new NvHTTP(address, 0, idManager.getUniqueId(), details.serverCert,
|
NvHTTP http = new NvHTTP(address, 0, idManager.getUniqueId(), details.serverCert,
|
||||||
PlatformBinding.getCryptoProvider(ComputerManagerService.this));
|
PlatformBinding.getCryptoProvider(ComputerManagerService.this));
|
||||||
|
|
||||||
ComputerDetails newDetails = http.getComputerDetails();
|
ComputerDetails newDetails = http.getComputerDetails(false);
|
||||||
|
|
||||||
// Check if this is the PC we expected
|
// Check if this is the PC we expected
|
||||||
if (newDetails.uuid == null) {
|
if (newDetails.uuid == null) {
|
||||||
|
@ -255,7 +255,7 @@ public class NvConnection {
|
|||||||
{
|
{
|
||||||
NvHTTP h = new NvHTTP(context.serverAddress, context.httpsPort, uniqueId, context.serverCert, cryptoProvider);
|
NvHTTP h = new NvHTTP(context.serverAddress, context.httpsPort, uniqueId, context.serverCert, cryptoProvider);
|
||||||
|
|
||||||
String serverInfo = h.getServerInfo();
|
String serverInfo = h.getServerInfo(true);
|
||||||
|
|
||||||
context.serverAppVersion = h.getServerVersion(serverInfo);
|
context.serverAppVersion = h.getServerVersion(serverInfo);
|
||||||
if (context.serverAppVersion == null) {
|
if (context.serverAppVersion == null) {
|
||||||
|
@ -64,8 +64,9 @@ public class NvHTTP {
|
|||||||
|
|
||||||
private static final int DEFAULT_HTTPS_PORT = 47984;
|
private static final int DEFAULT_HTTPS_PORT = 47984;
|
||||||
public static final int DEFAULT_HTTP_PORT = 47989;
|
public static final int DEFAULT_HTTP_PORT = 47989;
|
||||||
public static final int CONNECTION_TIMEOUT = 3000;
|
public static final int SHORT_CONNECTION_TIMEOUT = 3000;
|
||||||
public static final int READ_TIMEOUT = 5000;
|
public static final int LONG_CONNECTION_TIMEOUT = 5000;
|
||||||
|
public static final int READ_TIMEOUT = 7000;
|
||||||
|
|
||||||
// Print URL and content to logcat on debug builds
|
// Print URL and content to logcat on debug builds
|
||||||
private static boolean verbose = BuildConfig.DEBUG;
|
private static boolean verbose = BuildConfig.DEBUG;
|
||||||
@ -74,8 +75,9 @@ public class NvHTTP {
|
|||||||
|
|
||||||
private int httpsPort;
|
private int httpsPort;
|
||||||
|
|
||||||
private OkHttpClient httpClient;
|
private OkHttpClient httpClientLongConnectTimeout;
|
||||||
private OkHttpClient httpClientWithReadTimeout;
|
private OkHttpClient httpClientLongConnectNoReadTimeout;
|
||||||
|
private OkHttpClient httpClientShortConnectTimeout;
|
||||||
|
|
||||||
private X509TrustManager defaultTrustManager;
|
private X509TrustManager defaultTrustManager;
|
||||||
private X509TrustManager trustManager;
|
private X509TrustManager trustManager;
|
||||||
@ -168,23 +170,28 @@ public class NvHTTP {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
httpClient = new OkHttpClient.Builder()
|
httpClientLongConnectTimeout = new OkHttpClient.Builder()
|
||||||
.connectionPool(new ConnectionPool(0, 1, TimeUnit.MILLISECONDS))
|
.connectionPool(new ConnectionPool(0, 1, TimeUnit.MILLISECONDS))
|
||||||
.hostnameVerifier(hv)
|
.hostnameVerifier(hv)
|
||||||
.readTimeout(0, TimeUnit.MILLISECONDS)
|
.readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||||
.connectTimeout(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
|
.connectTimeout(LONG_CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||||
.proxy(Proxy.NO_PROXY)
|
.proxy(Proxy.NO_PROXY)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
httpClientWithReadTimeout = httpClient.newBuilder()
|
httpClientShortConnectTimeout = httpClientLongConnectTimeout.newBuilder()
|
||||||
.readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS)
|
.connectTimeout(SHORT_CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
httpClientLongConnectNoReadTimeout = httpClientLongConnectTimeout.newBuilder()
|
||||||
|
.readTimeout(0, TimeUnit.MILLISECONDS)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpUrl getHttpsUrl() throws IOException {
|
public HttpUrl getHttpsUrl(boolean likelyOnline) throws IOException {
|
||||||
if (httpsPort == 0) {
|
if (httpsPort == 0) {
|
||||||
// Fetch the HTTPS port if we don't have it already
|
// Fetch the HTTPS port if we don't have it already
|
||||||
httpsPort = getHttpsPort(openHttpConnectionToString(baseUrlHttp, "serverinfo", true));
|
httpsPort = getHttpsPort(openHttpConnectionToString(likelyOnline ? httpClientLongConnectTimeout : httpClientShortConnectTimeout,
|
||||||
|
baseUrlHttp, "serverinfo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HttpUrl.Builder().scheme("https").host(baseUrlHttp.host()).port(httpsPort).build();
|
return new HttpUrl.Builder().scheme("https").host(baseUrlHttp.host()).port(httpsPort).build();
|
||||||
@ -277,9 +284,12 @@ public class NvHTTP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getServerInfo() throws IOException, XmlPullParserException {
|
public String getServerInfo(boolean likelyOnline) throws IOException, XmlPullParserException {
|
||||||
String resp;
|
String resp;
|
||||||
|
|
||||||
|
// If we believe the PC is online, give it a little extra time to respond
|
||||||
|
OkHttpClient client = likelyOnline ? httpClientLongConnectTimeout : httpClientShortConnectTimeout;
|
||||||
|
|
||||||
//
|
//
|
||||||
// TODO: Shield Hub uses HTTP for this and is able to get an accurate PairStatus with HTTP.
|
// TODO: Shield Hub uses HTTP for this and is able to get an accurate PairStatus with HTTP.
|
||||||
// For some reason, we always see PairStatus is 0 over HTTP and only 1 over HTTPS. It looks
|
// For some reason, we always see PairStatus is 0 over HTTP and only 1 over HTTPS. It looks
|
||||||
@ -290,7 +300,7 @@ public class NvHTTP {
|
|||||||
if (serverCert != null) {
|
if (serverCert != null) {
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
resp = openHttpConnectionToString(getHttpsUrl(), "serverinfo", true);
|
resp = openHttpConnectionToString(client, getHttpsUrl(likelyOnline), "serverinfo");
|
||||||
} catch (SSLHandshakeException e) {
|
} catch (SSLHandshakeException e) {
|
||||||
// Detect if we failed due to a server cert mismatch
|
// Detect if we failed due to a server cert mismatch
|
||||||
if (e.getCause() instanceof CertificateException) {
|
if (e.getCause() instanceof CertificateException) {
|
||||||
@ -310,7 +320,7 @@ public class NvHTTP {
|
|||||||
catch (GfeHttpResponseException e) {
|
catch (GfeHttpResponseException e) {
|
||||||
if (e.getErrorCode() == 401) {
|
if (e.getErrorCode() == 401) {
|
||||||
// Cert validation error - fall back to HTTP
|
// Cert validation error - fall back to HTTP
|
||||||
return openHttpConnectionToString(baseUrlHttp, "serverinfo", true);
|
return openHttpConnectionToString(client, baseUrlHttp, "serverinfo");
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's not a cert validation error, throw it
|
// If it's not a cert validation error, throw it
|
||||||
@ -321,7 +331,7 @@ public class NvHTTP {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// No pinned cert, so use HTTP
|
// No pinned cert, so use HTTP
|
||||||
return openHttpConnectionToString(baseUrlHttp, "serverinfo", true);
|
return openHttpConnectionToString(client, baseUrlHttp, "serverinfo");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,9 +343,9 @@ public class NvHTTP {
|
|||||||
return new ComputerDetails.AddressTuple(address, port);
|
return new ComputerDetails.AddressTuple(address, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ComputerDetails getComputerDetails() throws IOException, XmlPullParserException {
|
public ComputerDetails getComputerDetails(boolean likelyOnline) throws IOException, XmlPullParserException {
|
||||||
ComputerDetails details = new ComputerDetails();
|
ComputerDetails details = new ComputerDetails();
|
||||||
String serverInfo = getServerInfo();
|
String serverInfo = getServerInfo(likelyOnline);
|
||||||
|
|
||||||
details.name = getXmlString(serverInfo, "hostname", false);
|
details.name = getXmlString(serverInfo, "hostname", false);
|
||||||
if (details.name == null || details.name.isEmpty()) {
|
if (details.name == null || details.name.isEmpty()) {
|
||||||
@ -397,25 +407,18 @@ public class NvHTTP {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResponseBody openHttpConnection(HttpUrl baseUrl, String path, boolean enableReadTimeout) throws IOException {
|
private ResponseBody openHttpConnection(OkHttpClient client, HttpUrl baseUrl, String path) throws IOException {
|
||||||
return openHttpConnection(baseUrl, path, null, enableReadTimeout);
|
return openHttpConnection(client, baseUrl, path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read timeout should be enabled for any HTTP query that requires no outside action
|
// Read timeout should be enabled for any HTTP query that requires no outside action
|
||||||
// on the GFE server. Examples of queries that DO require outside action are launch, resume, and quit.
|
// on the GFE server. Examples of queries that DO require outside action are launch, resume, and quit.
|
||||||
// The initial pair query does require outside action (user entering a PIN) but subsequent pairing
|
// The initial pair query does require outside action (user entering a PIN) but subsequent pairing
|
||||||
// queries do not.
|
// queries do not.
|
||||||
private ResponseBody openHttpConnection(HttpUrl baseUrl, String path, String query, boolean enableReadTimeout) throws IOException {
|
private ResponseBody openHttpConnection(OkHttpClient client, HttpUrl baseUrl, String path, String query) throws IOException {
|
||||||
HttpUrl completeUrl = getCompleteUrl(baseUrl, path, query);
|
HttpUrl completeUrl = getCompleteUrl(baseUrl, path, query);
|
||||||
Request request = new Request.Builder().url(completeUrl).get().build();
|
Request request = new Request.Builder().url(completeUrl).get().build();
|
||||||
Response response;
|
Response response = performAndroidTlsHack(client).newCall(request).execute();
|
||||||
|
|
||||||
if (enableReadTimeout) {
|
|
||||||
response = performAndroidTlsHack(httpClientWithReadTimeout).newCall(request).execute();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
response = performAndroidTlsHack(httpClient).newCall(request).execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
ResponseBody body = response.body();
|
ResponseBody body = response.body();
|
||||||
|
|
||||||
@ -436,13 +439,13 @@ public class NvHTTP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String openHttpConnectionToString(HttpUrl baseUrl, String path, boolean enableReadTimeout) throws IOException {
|
private String openHttpConnectionToString(OkHttpClient client, HttpUrl baseUrl, String path) throws IOException {
|
||||||
return openHttpConnectionToString(baseUrl, path, null, enableReadTimeout);
|
return openHttpConnectionToString(client, baseUrl, path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String openHttpConnectionToString(HttpUrl baseUrl, String path, String query, boolean enableReadTimeout) throws IOException {
|
private String openHttpConnectionToString(OkHttpClient client, HttpUrl baseUrl, String path, String query) throws IOException {
|
||||||
try {
|
try {
|
||||||
ResponseBody resp = openHttpConnection(baseUrl, path, query, enableReadTimeout);
|
ResponseBody resp = openHttpConnection(client, baseUrl, path, query);
|
||||||
String respString = resp.string();
|
String respString = resp.string();
|
||||||
resp.close();
|
resp.close();
|
||||||
|
|
||||||
@ -467,7 +470,7 @@ public class NvHTTP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public PairingManager.PairState getPairState() throws IOException, XmlPullParserException {
|
public PairingManager.PairState getPairState() throws IOException, XmlPullParserException {
|
||||||
return getPairState(getServerInfo());
|
return getPairState(getServerInfo(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public PairingManager.PairState getPairState(String serverInfo) throws IOException, XmlPullParserException {
|
public PairingManager.PairState getPairState(String serverInfo) throws IOException, XmlPullParserException {
|
||||||
@ -663,7 +666,7 @@ public class NvHTTP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getAppListRaw() throws IOException {
|
public String getAppListRaw() throws IOException {
|
||||||
return openHttpConnectionToString(getHttpsUrl(), "applist", true);
|
return openHttpConnectionToString(httpClientLongConnectTimeout, getHttpsUrl(true), "applist");
|
||||||
}
|
}
|
||||||
|
|
||||||
public LinkedList<NvApp> getAppList() throws GfeHttpResponseException, IOException, XmlPullParserException {
|
public LinkedList<NvApp> getAppList() throws GfeHttpResponseException, IOException, XmlPullParserException {
|
||||||
@ -672,30 +675,28 @@ public class NvHTTP {
|
|||||||
return getAppListByReader(new StringReader(getAppListRaw()));
|
return getAppListByReader(new StringReader(getAppListRaw()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try (final ResponseBody resp = openHttpConnection(getHttpsUrl(), "applist", true)) {
|
try (final ResponseBody resp = openHttpConnection(httpClientLongConnectTimeout, getHttpsUrl(true), "applist")) {
|
||||||
return getAppListByReader(new InputStreamReader(resp.byteStream()));
|
return getAppListByReader(new InputStreamReader(resp.byteStream()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String executePairingCommand(String additionalArguments, boolean enableReadTimeout) throws GfeHttpResponseException, IOException {
|
String executePairingCommand(String additionalArguments, boolean enableReadTimeout) throws GfeHttpResponseException, IOException {
|
||||||
return openHttpConnectionToString(baseUrlHttp, "pair",
|
return openHttpConnectionToString(enableReadTimeout ? httpClientLongConnectTimeout : httpClientLongConnectNoReadTimeout,
|
||||||
"devicename=roth&updateState=1&" + additionalArguments,
|
baseUrlHttp, "pair", "devicename=roth&updateState=1&" + additionalArguments);
|
||||||
enableReadTimeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String executePairingChallenge() throws GfeHttpResponseException, IOException {
|
String executePairingChallenge() throws GfeHttpResponseException, IOException {
|
||||||
return openHttpConnectionToString(getHttpsUrl(), "pair",
|
return openHttpConnectionToString(httpClientLongConnectTimeout, getHttpsUrl(true),
|
||||||
"devicename=roth&updateState=1&phrase=pairchallenge",
|
"pair", "devicename=roth&updateState=1&phrase=pairchallenge");
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unpair() throws IOException {
|
public void unpair() throws IOException {
|
||||||
openHttpConnectionToString(baseUrlHttp, "unpair", true);
|
openHttpConnectionToString(httpClientLongConnectTimeout, baseUrlHttp, "unpair");
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream getBoxArt(NvApp app) throws IOException {
|
public InputStream getBoxArt(NvApp app) throws IOException {
|
||||||
ResponseBody resp = openHttpConnection(getHttpsUrl(), "appasset", "appid=" + app.getAppId() + "&AssetType=2&AssetIdx=0", true);
|
ResponseBody resp = openHttpConnection(httpClientLongConnectTimeout, getHttpsUrl(true), "appasset", "appid=" + app.getAppId() + "&AssetType=2&AssetIdx=0");
|
||||||
return resp.byteStream();
|
return resp.byteStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -750,7 +751,7 @@ public class NvHTTP {
|
|||||||
enableSops = false;
|
enableSops = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String xmlStr = openHttpConnectionToString(getHttpsUrl(), "launch",
|
String xmlStr = openHttpConnectionToString(httpClientLongConnectNoReadTimeout, getHttpsUrl(true), "launch",
|
||||||
"appid=" + appId +
|
"appid=" + appId +
|
||||||
"&mode=" + context.negotiatedWidth + "x" + context.negotiatedHeight + "x" + fps +
|
"&mode=" + context.negotiatedWidth + "x" + context.negotiatedHeight + "x" + fps +
|
||||||
"&additionalStates=1&sops=" + (enableSops ? 1 : 0) +
|
"&additionalStates=1&sops=" + (enableSops ? 1 : 0) +
|
||||||
@ -760,8 +761,7 @@ public class NvHTTP {
|
|||||||
"&localAudioPlayMode=" + (context.streamConfig.getPlayLocalAudio() ? 1 : 0) +
|
"&localAudioPlayMode=" + (context.streamConfig.getPlayLocalAudio() ? 1 : 0) +
|
||||||
"&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo() +
|
"&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo() +
|
||||||
(context.streamConfig.getAttachedGamepadMask() != 0 ? "&remoteControllersBitmap=" + context.streamConfig.getAttachedGamepadMask() : "") +
|
(context.streamConfig.getAttachedGamepadMask() != 0 ? "&remoteControllersBitmap=" + context.streamConfig.getAttachedGamepadMask() : "") +
|
||||||
(context.streamConfig.getAttachedGamepadMask() != 0 ? "&gcmap=" + context.streamConfig.getAttachedGamepadMask() : ""),
|
(context.streamConfig.getAttachedGamepadMask() != 0 ? "&gcmap=" + context.streamConfig.getAttachedGamepadMask() : ""));
|
||||||
false);
|
|
||||||
if (!getXmlString(xmlStr, "gamesession", true).equals("0")) {
|
if (!getXmlString(xmlStr, "gamesession", true).equals("0")) {
|
||||||
// sessionUrl0 will be missing for older GFE versions
|
// sessionUrl0 will be missing for older GFE versions
|
||||||
context.rtspSessionUrl = getXmlString(xmlStr, "sessionUrl0", false);
|
context.rtspSessionUrl = getXmlString(xmlStr, "sessionUrl0", false);
|
||||||
@ -773,11 +773,10 @@ public class NvHTTP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean resumeApp(ConnectionContext context) throws IOException, XmlPullParserException {
|
public boolean resumeApp(ConnectionContext context) throws IOException, XmlPullParserException {
|
||||||
String xmlStr = openHttpConnectionToString(getHttpsUrl(), "resume",
|
String xmlStr = openHttpConnectionToString(httpClientLongConnectNoReadTimeout, getHttpsUrl(true), "resume",
|
||||||
"rikey="+bytesToHex(context.riKey.getEncoded()) +
|
"rikey="+bytesToHex(context.riKey.getEncoded()) +
|
||||||
"&rikeyid="+context.riKeyId +
|
"&rikeyid="+context.riKeyId +
|
||||||
"&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo(),
|
"&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo());
|
||||||
false);
|
|
||||||
if (!getXmlString(xmlStr, "resume", true).equals("0")) {
|
if (!getXmlString(xmlStr, "resume", true).equals("0")) {
|
||||||
// sessionUrl0 will be missing for older GFE versions
|
// sessionUrl0 will be missing for older GFE versions
|
||||||
context.rtspSessionUrl = getXmlString(xmlStr, "sessionUrl0", false);
|
context.rtspSessionUrl = getXmlString(xmlStr, "sessionUrl0", false);
|
||||||
@ -789,14 +788,14 @@ public class NvHTTP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean quitApp() throws IOException, XmlPullParserException {
|
public boolean quitApp() throws IOException, XmlPullParserException {
|
||||||
String xmlStr = openHttpConnectionToString(getHttpsUrl(), "cancel", false);
|
String xmlStr = openHttpConnectionToString(httpClientLongConnectNoReadTimeout, getHttpsUrl(true), "cancel");
|
||||||
if (getXmlString(xmlStr, "cancel", true).equals("0")) {
|
if (getXmlString(xmlStr, "cancel", true).equals("0")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Newer GFE versions will just return success even if quitting fails
|
// Newer GFE versions will just return success even if quitting fails
|
||||||
// if we're not the original requestor.
|
// if we're not the original requestor.
|
||||||
if (getCurrentGame(getServerInfo()) != 0) {
|
if (getCurrentGame(getServerInfo(true)) != 0) {
|
||||||
// Generate a synthetic GfeResponseException letting the caller know
|
// Generate a synthetic GfeResponseException letting the caller know
|
||||||
// that they can't kill someone else's stream.
|
// that they can't kill someone else's stream.
|
||||||
throw new GfeHttpResponseException(599, "");
|
throw new GfeHttpResponseException(599, "");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user