From 8c36cf40fd0795097fedee714cf433e52a7985db Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 8 Jul 2015 19:16:17 -0700 Subject: [PATCH 1/6] Update common for a leak fix and other minor bugs --- limelight-common-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/limelight-common-c b/limelight-common-c index 678afd9..1cd1753 160000 --- a/limelight-common-c +++ b/limelight-common-c @@ -1 +1 @@ -Subproject commit 678afd9c300ae4591aa53e3bbf0e14783803671e +Subproject commit 1cd17536dbc8163f48833940faf76cd76d8ecd38 From c0b2bbe55297655ba2747eb598c2287682d5cac0 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 8 Jul 2015 19:16:48 -0700 Subject: [PATCH 2/6] Remove a parameter from LiStartConnection --- Limelight/Stream/Connection.m | 1 - 1 file changed, 1 deletion(-) diff --git a/Limelight/Stream/Connection.m b/Limelight/Stream/Connection.m index d70a0ca..1aaf0f1 100644 --- a/Limelight/Stream/Connection.m +++ b/Limelight/Stream/Connection.m @@ -399,7 +399,6 @@ static OSStatus playbackCallback(void *inRefCon, &_clCallbacks, &_drCallbacks, &_arCallbacks, - NULL, NULL, 0, _serverMajorVersion); } From 6bb559303b905494fe4b040d3481566b6e58419d Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 8 Jul 2015 21:26:01 -0700 Subject: [PATCH 3/6] Remove executeRequest from HttpManager. It has some show-stopping bugs, like leaking semaphore counts (since it never waited) and being generally thread-unsafe. Implementing it in a way that would be asynchronous and thread-safe is a non-trivial task, so I've opted to remove it and change callers to use executeRequestSynchronously. --- Limelight/Network/HttpManager.h | 1 - Limelight/Network/HttpManager.m | 4 ---- Limelight/Network/PairManager.m | 18 +++++++++--------- .../ViewControllers/MainFrameViewController.m | 2 +- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/Limelight/Network/HttpManager.h b/Limelight/Network/HttpManager.h index 29f15aa..262a306 100644 --- a/Limelight/Network/HttpManager.h +++ b/Limelight/Network/HttpManager.h @@ -27,7 +27,6 @@ - (NSURLRequest*) newQuitAppRequest; - (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId; - (void) executeRequestSynchronously:(HttpRequest*)request; -- (void) executeRequest:(HttpRequest*)request; @end diff --git a/Limelight/Network/HttpManager.m b/Limelight/Network/HttpManager.m index 9e580d7..6533a3e 100644 --- a/Limelight/Network/HttpManager.m +++ b/Limelight/Network/HttpManager.m @@ -62,10 +62,6 @@ static const NSString* PORT = @"47984"; _errorOccurred = false; } -- (void) executeRequest:(HttpRequest*)request { - [NSURLConnection connectionWithRequest:request.request delegate:self]; -} - - (NSURLRequest*) createRequestFromString:(NSString*) urlString enableTimeout:(BOOL)normalTimeout { NSURL* url = [[NSURL alloc] initWithString:urlString]; NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url]; diff --git a/Limelight/Network/PairManager.m b/Limelight/Network/PairManager.m index 93e6995..616bb32 100644 --- a/Limelight/Network/PairManager.m +++ b/Limelight/Network/PairManager.m @@ -60,7 +60,7 @@ } NSInteger pairedStatus; if (![pairResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { - [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; + [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Pairing was declined by the target."]; return; } @@ -79,7 +79,7 @@ return; } if (![challengeResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { - [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; + [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Pairing stage #2 failed"]; return; } @@ -100,7 +100,7 @@ return; } if (![secretResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { - [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; + [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Pairing stage #3 failed"]; return; } @@ -110,14 +110,14 @@ NSData* serverSignature = [serverSecretResp subdataWithRange:NSMakeRange(16, 256)]; if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) { - [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; + [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Server certificate invalid"]; return; } NSData* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret]]; if (![serverChallengeRespHash isEqual:serverResponse]) { - [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; + [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Incorrect PIN"]; return; } @@ -129,7 +129,7 @@ return; } if (![clientSecretResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { - [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; + [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Pairing stage #4 failed"]; return; } @@ -140,7 +140,7 @@ return; } if (![clientPairChallengeResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { - [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; + [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Pairing stage #5 failed"]; return; } @@ -149,11 +149,11 @@ - (BOOL) verifyResponseStatus:(HttpResponse*)resp { if (resp == nil) { - [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; + [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Network error occured."]; return false; } else if (![resp isStatusOk]) { - [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; + [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:resp.statusMessage]; return false; } else { diff --git a/Limelight/ViewControllers/MainFrameViewController.m b/Limelight/ViewControllers/MainFrameViewController.m index 929b30b..d797d1e 100644 --- a/Limelight/ViewControllers/MainFrameViewController.m +++ b/Limelight/ViewControllers/MainFrameViewController.m @@ -160,7 +160,7 @@ static NSArray* appList; [longClickAlert addAction:[UIAlertAction actionWithTitle:@"Unpair" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; - [hMan executeRequest:[HttpRequest requestWithUrlRequest:[hMan newUnpairRequest]]]; + [hMan executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[hMan newUnpairRequest]]]; }); }]]; } else { From f13051aa311c80344ee1b34de9df5268f14461fc Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 8 Jul 2015 21:31:47 -0700 Subject: [PATCH 4/6] Prepare for HTTP requests --- Limelight/Network/HttpManager.m | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Limelight/Network/HttpManager.m b/Limelight/Network/HttpManager.m index 6533a3e..aaf6793 100644 --- a/Limelight/Network/HttpManager.m +++ b/Limelight/Network/HttpManager.m @@ -15,7 +15,8 @@ #include @implementation HttpManager { - NSString* _baseURL; + NSString* _baseHTTPURL; + NSString* _baseHTTPSURL; NSString* _host; NSString* _uniqueId; NSString* _deviceName; @@ -27,7 +28,8 @@ BOOL _errorOccurred; } -static const NSString* PORT = @"47984"; +static const NSString* HTTP_PORT = @"47989"; +static const NSString* HTTPS_PORT = @"47984"; + (NSData*) fixXmlVersion:(NSData*) xmlData { NSString* dataString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding]; @@ -42,7 +44,8 @@ static const NSString* PORT = @"47984"; _uniqueId = uniqueId; _deviceName = deviceName; _cert = cert; - _baseURL = [NSString stringWithFormat:@"https://%@:%@", host, PORT]; + _baseHTTPURL = [NSString stringWithFormat:@"http://%@:%@", host, HTTP_PORT]; + _baseHTTPSURL = [NSString stringWithFormat:@"https://%@:%@", host, HTTPS_PORT]; _requestLock = dispatch_semaphore_create(0); _respData = [[NSMutableData alloc] init]; return self; @@ -78,67 +81,67 @@ static const NSString* PORT = @"47984"; - (NSURLRequest*) newPairRequest:(NSData*)salt { NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=getservercert&salt=%@&clientcert=%@", - _baseURL, _uniqueId, _deviceName, [self bytesToHex:salt], [self bytesToHex:_cert]]; + _baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:salt], [self bytesToHex:_cert]]; // This call blocks while waiting for the user to input the PIN on the PC return [self createRequestFromString:urlString enableTimeout:FALSE]; } - (NSURLRequest*) newUnpairRequest { - NSString* urlString = [NSString stringWithFormat:@"%@/unpair?uniqueid=%@", _baseURL, _uniqueId]; + NSString* urlString = [NSString stringWithFormat:@"%@/unpair?uniqueid=%@", _baseHTTPSURL, _uniqueId]; return [self createRequestFromString:urlString enableTimeout:TRUE]; } - (NSURLRequest*) newChallengeRequest:(NSData*)challenge { NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientchallenge=%@", - _baseURL, _uniqueId, _deviceName, [self bytesToHex:challenge]]; + _baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:challenge]]; return [self createRequestFromString:urlString enableTimeout:TRUE]; } - (NSURLRequest*) newChallengeRespRequest:(NSData*)challengeResp { NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&serverchallengeresp=%@", - _baseURL, _uniqueId, _deviceName, [self bytesToHex:challengeResp]]; + _baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:challengeResp]]; return [self createRequestFromString:urlString enableTimeout:TRUE]; } - (NSURLRequest*) newClientSecretRespRequest:(NSString*)clientPairSecret { - NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientpairingsecret=%@", _baseURL, _uniqueId, _deviceName, clientPairSecret]; + NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientpairingsecret=%@", _baseHTTPSURL, _uniqueId, _deviceName, clientPairSecret]; return [self createRequestFromString:urlString enableTimeout:TRUE]; } - (NSURLRequest*) newPairChallenge { - NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=pairchallenge", _baseURL, _uniqueId, _deviceName]; + NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=pairchallenge", _baseHTTPSURL, _uniqueId, _deviceName]; return [self createRequestFromString:urlString enableTimeout:TRUE]; } - (NSURLRequest *)newAppListRequest { - NSString* urlString = [NSString stringWithFormat:@"%@/applist?uniqueid=%@", _baseURL, _uniqueId]; + NSString* urlString = [NSString stringWithFormat:@"%@/applist?uniqueid=%@", _baseHTTPSURL, _uniqueId]; return [self createRequestFromString:urlString enableTimeout:TRUE]; } - (NSURLRequest *)newServerInfoRequest { - NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo?uniqueid=%@", _baseURL, _uniqueId]; + NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo?uniqueid=%@", _baseHTTPSURL, _uniqueId]; return [self createRequestFromString:urlString enableTimeout:TRUE]; } - (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid { - NSString* urlString = [NSString stringWithFormat:@"%@/launch?uniqueid=%@&appid=%@&mode=%dx%dx%d&additionalStates=1&sops=1&rikey=%@&rikeyid=%d", _baseURL, _uniqueId, appId, width, height, refreshRate, rikey, rikeyid]; + NSString* urlString = [NSString stringWithFormat:@"%@/launch?uniqueid=%@&appid=%@&mode=%dx%dx%d&additionalStates=1&sops=1&rikey=%@&rikeyid=%d", _baseHTTPSURL, _uniqueId, appId, width, height, refreshRate, rikey, rikeyid]; // This blocks while the app is launching return [self createRequestFromString:urlString enableTimeout:FALSE]; } - (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId { - NSString* urlString = [NSString stringWithFormat:@"%@/resume?uniqueid=%@&rikey=%@&rikeyid=%d", _baseURL, _uniqueId, riKey, riKeyId]; + NSString* urlString = [NSString stringWithFormat:@"%@/resume?uniqueid=%@&rikey=%@&rikeyid=%d", _baseHTTPSURL, _uniqueId, riKey, riKeyId]; // This blocks while the app is resuming return [self createRequestFromString:urlString enableTimeout:FALSE]; } - (NSURLRequest*) newQuitAppRequest { - NSString* urlString = [NSString stringWithFormat:@"%@/cancel?uniqueid=%@", _baseURL, _uniqueId]; + NSString* urlString = [NSString stringWithFormat:@"%@/cancel?uniqueid=%@", _baseHTTPSURL, _uniqueId]; return [self createRequestFromString:urlString enableTimeout:FALSE]; } - (NSURLRequest*) newAppAssetRequestWithAppId:(NSString *)appId { - NSString* urlString = [NSString stringWithFormat:@"%@/appasset?uniqueid=%@&appid=%@&AssetType=2&AssetIdx=0", _baseURL, _uniqueId, appId]; + NSString* urlString = [NSString stringWithFormat:@"%@/appasset?uniqueid=%@&appid=%@&AssetType=2&AssetIdx=0", _baseHTTPSURL, _uniqueId, appId]; return [self createRequestFromString:urlString enableTimeout:FALSE]; } From 84a986bc88c7994c02c117b81168cf6e773a6b34 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 8 Jul 2015 22:35:25 -0700 Subject: [PATCH 5/6] Switch from deprecated NSURLConnection to NSURLSession --- Limelight/Network/HttpManager.h | 2 +- Limelight/Network/HttpManager.m | 78 +++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/Limelight/Network/HttpManager.h b/Limelight/Network/HttpManager.h index 262a306..b96ee47 100644 --- a/Limelight/Network/HttpManager.h +++ b/Limelight/Network/HttpManager.h @@ -11,7 +11,7 @@ #import "HttpResponse.h" #import "HttpRequest.h" -@interface HttpManager : NSObject +@interface HttpManager : NSObject - (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert; - (NSURLRequest*) newPairRequest:(NSData*)salt; diff --git a/Limelight/Network/HttpManager.m b/Limelight/Network/HttpManager.m index aaf6793..70bf8c7 100644 --- a/Limelight/Network/HttpManager.m +++ b/Limelight/Network/HttpManager.m @@ -15,6 +15,7 @@ #include @implementation HttpManager { + NSURLSession* _urlSession; NSString* _baseHTTPURL; NSString* _baseHTTPSURL; NSString* _host; @@ -48,15 +49,36 @@ static const NSString* HTTPS_PORT = @"47984"; _baseHTTPSURL = [NSString stringWithFormat:@"https://%@:%@", host, HTTPS_PORT]; _requestLock = dispatch_semaphore_create(0); _respData = [[NSMutableData alloc] init]; + NSURLSessionConfiguration* config = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + _urlSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil]; return self; } - (void) executeRequestSynchronously:(HttpRequest*)request { Log(LOG_D, @"Making Request: %@", request); [_respData setLength:0]; - dispatch_sync(dispatch_get_main_queue(), ^{ - [NSURLConnection connectionWithRequest:request.request delegate:self]; - }); + [[_urlSession dataTaskWithRequest:request.request completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error) { + + if (error != NULL) { + Log(LOG_D, @"Connection error: %@", error); + _errorOccurred = true; + } + else { + Log(LOG_D, @"Received response: %@", response); + + if (data != NULL) { + Log(LOG_D, @"\n\nReceived data: %@\n\n", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); + [_respData appendData:data]; + if ([[NSString alloc] initWithData:_respData encoding:NSUTF8StringEncoding] != nil) { + _requestResp = [HttpManager fixXmlVersion:_respData]; + } else { + _requestResp = _respData; + } + } + } + + dispatch_semaphore_signal(_requestLock); + }] resume]; dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER); if (!_errorOccurred && request.response) { @@ -154,33 +176,6 @@ static const NSString* HTTPS_PORT = @"47984"; return hex; } -- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { - Log(LOG_D, @"Received response: %@", response); -} - -- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { - Log(LOG_D, @"\n\nReceived data: %@\n\n", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); - [_respData appendData:data]; -} - -- (void)connectionDidFinishLoading:(NSURLConnection *)connection { - if ([[NSString alloc] initWithData:_respData encoding:NSUTF8StringEncoding] != nil) { - _requestResp = [HttpManager fixXmlVersion:_respData]; - } else { - _requestResp = _respData; - } - dispatch_semaphore_signal(_requestLock); -} - -- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { - SecIdentityRef identity = [self getClientCertificate]; - NSArray *certArray = [self getCertificate:identity]; - - NSURLCredential *newCredential = [NSURLCredential credentialWithIdentity:identity certificates:certArray persistence:NSURLCredentialPersistencePermanent]; - - [challenge.sender useCredential:newCredential forAuthenticationChallenge:challenge]; -} - // Returns an array containing the certificate - (NSArray*)getCertificate:(SecIdentityRef) identity { SecCertificateRef certificate = nil; @@ -216,10 +211,25 @@ static const NSString* HTTPS_PORT = @"47984"; return identityApp; } -- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { - Log(LOG_D, @"connection error: %@", error); - _errorOccurred = true; - dispatch_semaphore_signal(_requestLock); +- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(nonnull void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * __nullable))completionHandler { + // Allow untrusted server certificates + if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) + { + completionHandler(NSURLSessionAuthChallengeUseCredential, + [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust]); + } + // Respond to client certificate challenge with our certificate + else if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]) + { + SecIdentityRef identity = [self getClientCertificate]; + NSArray* certArray = [self getCertificate:identity]; + NSURLCredential* newCredential = [NSURLCredential credentialWithIdentity:identity certificates:certArray persistence:NSURLCredentialPersistencePermanent]; + completionHandler(NSURLSessionAuthChallengeUseCredential, newCredential); + } + else + { + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, NULL); + } } @end From 73364127d2066a0332b2c81d03fa41217d117cf5 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 8 Jul 2015 23:03:23 -0700 Subject: [PATCH 6/6] Fix pairing with GFE 2.4.5.57+ --- Limelight/Network/DiscoveryManager.m | 2 +- Limelight/Network/DiscoveryWorker.m | 3 ++- Limelight/Network/HttpManager.h | 1 + Limelight/Network/HttpManager.m | 14 ++++++++++++++ Limelight/Network/HttpRequest.h | 3 +++ Limelight/Network/HttpRequest.m | 9 +++++++++ Limelight/Network/PairManager.m | 3 ++- Limelight/Stream/StreamManager.m | 3 ++- .../ViewControllers/MainFrameViewController.m | 3 ++- 9 files changed, 36 insertions(+), 5 deletions(-) diff --git a/Limelight/Network/DiscoveryManager.m b/Limelight/Network/DiscoveryManager.m index 05f5b1d..de17574 100644 --- a/Limelight/Network/DiscoveryManager.m +++ b/Limelight/Network/DiscoveryManager.m @@ -41,7 +41,7 @@ - (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *, NSString*))callback { HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init]; - [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest]]]; + [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest] fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]]; Host* host = nil; if ([serverInfoResponse isStatusOk]) { diff --git a/Limelight/Network/DiscoveryWorker.m b/Limelight/Network/DiscoveryWorker.m index e871aca..9d9314e 100644 --- a/Limelight/Network/DiscoveryWorker.m +++ b/Limelight/Network/DiscoveryWorker.m @@ -68,7 +68,8 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds cert:_cert]; ServerInfoResponse* response = [[ServerInfoResponse alloc] init]; [hMan executeRequestSynchronously:[HttpRequest requestForResponse:response - withUrlRequest:[hMan newServerInfoRequest]]]; + withUrlRequest:[hMan newServerInfoRequest] + fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]]; return response; } diff --git a/Limelight/Network/HttpManager.h b/Limelight/Network/HttpManager.h index b96ee47..d72a618 100644 --- a/Limelight/Network/HttpManager.h +++ b/Limelight/Network/HttpManager.h @@ -22,6 +22,7 @@ - (NSURLRequest*) newPairChallenge; - (NSURLRequest*) newAppListRequest; - (NSURLRequest*) newServerInfoRequest; +- (NSURLRequest*) newHttpServerInfoRequest; - (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid; - (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId; - (NSURLRequest*) newQuitAppRequest; diff --git a/Limelight/Network/HttpManager.m b/Limelight/Network/HttpManager.m index 70bf8c7..da6f20a 100644 --- a/Limelight/Network/HttpManager.m +++ b/Limelight/Network/HttpManager.m @@ -83,6 +83,15 @@ static const NSString* HTTPS_PORT = @"47984"; if (!_errorOccurred && request.response) { [request.response populateWithData:_requestResp]; + + // If the fallback error code was detected, issue the fallback request + if (request.response.statusCode == request.fallbackError && request.fallbackRequest != NULL) { + Log(LOG_D, @"Request failed with fallback error code: %d", request.fallbackError); + request.request = request.fallbackRequest; + request.fallbackError = 0; + request.fallbackRequest = NULL; + [self executeRequestSynchronously:request]; + } } _errorOccurred = false; } @@ -145,6 +154,11 @@ static const NSString* HTTPS_PORT = @"47984"; return [self createRequestFromString:urlString enableTimeout:TRUE]; } +- (NSURLRequest *)newHttpServerInfoRequest { + NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo", _baseHTTPURL]; + return [self createRequestFromString:urlString enableTimeout:TRUE]; +} + - (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid { NSString* urlString = [NSString stringWithFormat:@"%@/launch?uniqueid=%@&appid=%@&mode=%dx%dx%d&additionalStates=1&sops=1&rikey=%@&rikeyid=%d", _baseHTTPSURL, _uniqueId, appId, width, height, refreshRate, rikey, rikeyid]; // This blocks while the app is launching diff --git a/Limelight/Network/HttpRequest.h b/Limelight/Network/HttpRequest.h index bead208..743b58b 100644 --- a/Limelight/Network/HttpRequest.h +++ b/Limelight/Network/HttpRequest.h @@ -13,7 +13,10 @@ @property (nonatomic) id response; @property (nonatomic) NSURLRequest* request; +@property (nonatomic) int fallbackError; +@property (nonatomic) NSURLRequest* fallbackRequest; ++ (instancetype) requestForResponse:(id)response withUrlRequest:(NSURLRequest*)req fallbackError:(int)error fallbackRequest:(NSURLRequest*) fallbackReq; + (instancetype) requestForResponse:(id)response withUrlRequest:(NSURLRequest*)req; + (instancetype) requestWithUrlRequest:(NSURLRequest*)req; diff --git a/Limelight/Network/HttpRequest.m b/Limelight/Network/HttpRequest.m index 69298ed..afb1c89 100644 --- a/Limelight/Network/HttpRequest.m +++ b/Limelight/Network/HttpRequest.m @@ -25,4 +25,13 @@ return request; } ++ (HttpRequest*) requestForResponse:(id)response withUrlRequest:(NSURLRequest*)req fallbackError:(int)error fallbackRequest:(NSURLRequest*) fallbackReq { + HttpRequest* request = [[HttpRequest alloc] init]; + request.request = req; + request.response = response; + request.fallbackError = error; + request.fallbackRequest = fallbackReq; + return request; +} + @end diff --git a/Limelight/Network/PairManager.m b/Limelight/Network/PairManager.m index 616bb32..82ff2b2 100644 --- a/Limelight/Network/PairManager.m +++ b/Limelight/Network/PairManager.m @@ -31,7 +31,8 @@ - (void) main { ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; - [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[_httpManager newServerInfoRequest]]]; + [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[_httpManager newServerInfoRequest] + fallbackError:401 fallbackRequest:[_httpManager newHttpServerInfoRequest]]]; if (serverInfoResp == nil) { [_callback pairFailed:@"Unable to connect to PC"]; return; diff --git a/Limelight/Stream/StreamManager.m b/Limelight/Stream/StreamManager.m index 3308ad1..d9087c3 100644 --- a/Limelight/Stream/StreamManager.m +++ b/Limelight/Stream/StreamManager.m @@ -45,7 +45,8 @@ cert:cert]; ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; - [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]]; + [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest] + fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]]; NSString* currentGame = [serverInfoResp getStringTag:@"currentgame"]; NSString* pairStatus = [serverInfoResp getStringTag:@"PairStatus"]; NSString* currentClient = [serverInfoResp getStringTag:@"CurrentClient"]; diff --git a/Limelight/ViewControllers/MainFrameViewController.m b/Limelight/ViewControllers/MainFrameViewController.m index d797d1e..e188607 100644 --- a/Limelight/ViewControllers/MainFrameViewController.m +++ b/Limelight/ViewControllers/MainFrameViewController.m @@ -133,7 +133,8 @@ static NSArray* appList; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; - [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]]; + [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest] + fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]]; if (serverInfoResp == nil || ![serverInfoResp isStatusOk]) { Log(LOG_W, @"Failed to get server info: %@", serverInfoResp.statusMessage); [self hideLoadingFrame];