diff --git a/Limelight/Network/HttpManager.m b/Limelight/Network/HttpManager.m index 21121e7..98ef1df 100644 --- a/Limelight/Network/HttpManager.m +++ b/Limelight/Network/HttpManager.m @@ -102,63 +102,75 @@ static const NSString* PORT = @"47984"; [NSURLConnection connectionWithRequest:request delegate:self]; } -- (NSURLRequest*) createRequestFromString:(NSString*) urlString { +- (NSURLRequest*) createRequestFromString:(NSString*) urlString enableTimeout:(BOOL)normalTimeout { NSString* escapedUrl = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSURL* url = [[NSURL alloc] initWithString:escapedUrl]; - return [NSURLRequest requestWithURL:url]; + NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url]; + if (normalTimeout) { + // Timeout the request after 5 seconds + [request setTimeoutInterval:5]; + } + else { + // Timeout the request after 60 seconds + [request setTimeoutInterval:60]; + } + return request; } - (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]]; - return [self createRequestFromString:urlString]; + // 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]; - return [self createRequestFromString:urlString]; + 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]]; - return [self createRequestFromString:urlString]; + 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]]; - return [self createRequestFromString:urlString]; + return [self createRequestFromString:urlString enableTimeout:TRUE]; } - (NSURLRequest*) newClientSecretRespRequest:(NSString*)clientPairSecret { NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientpairingsecret=%@", _baseURL, _uniqueId, _deviceName, clientPairSecret]; - return [self createRequestFromString:urlString]; + return [self createRequestFromString:urlString enableTimeout:TRUE]; } - (NSURLRequest*) newPairChallenge { NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=pairchallenge", _baseURL, _uniqueId, _deviceName]; - return [self createRequestFromString:urlString]; + return [self createRequestFromString:urlString enableTimeout:TRUE]; } - (NSURLRequest *)newAppListRequest { NSString* urlString = [NSString stringWithFormat:@"%@/applist?uniqueid=%@", _baseURL, _uniqueId]; - return [self createRequestFromString:urlString]; + return [self createRequestFromString:urlString enableTimeout:TRUE]; } - (NSURLRequest *)newServerInfoRequest { NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo?uniqueid=%@", _baseURL, _uniqueId]; - return [self createRequestFromString:urlString]; + 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]; - return [self createRequestFromString:urlString]; + // 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]; - return [self createRequestFromString:urlString]; + // This blocks while the app is resuming + return [self createRequestFromString:urlString enableTimeout:FALSE]; } - (NSString*) bytesToHex:(NSData*)data { diff --git a/Limelight/Network/PairManager.m b/Limelight/Network/PairManager.m index 9c77f68..a13835a 100644 --- a/Limelight/Network/PairManager.m +++ b/Limelight/Network/PairManager.m @@ -43,7 +43,9 @@ [_callback showPIN:PIN]; NSData* pairResp = [_httpManager executeRequestSynchronously:[_httpManager newPairRequest:salt]]; - if ([[HttpManager getStringFromXML:pairResp tag:@"paired"] intValue] != 1) { + NSString* pairedString; + pairedString = [HttpManager getStringFromXML:pairResp tag:@"paired"]; + if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { [_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; //TODO: better message [_callback pairFailed:@"pairResp failed"]; @@ -59,7 +61,8 @@ NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey]; NSData* challengeResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRequest:encryptedChallenge]]; - if ([[HttpManager getStringFromXML:challengeResp tag:@"paired"] intValue] != 1) { + pairedString = [HttpManager getStringFromXML:challengeResp tag:@"paired"]; + if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { [_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; //TODO: better message [_callback pairFailed:@"challengeResp failed"]; @@ -77,7 +80,8 @@ NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey]; NSData* secretResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRespRequest:challengeRespEncrypted]]; - if ([[HttpManager getStringFromXML:secretResp tag:@"paired"] intValue] != 1) { + pairedString = [HttpManager getStringFromXML:secretResp tag:@"paired"]; + if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { [_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; //TODO: better message [_callback pairFailed:@"secretResp failed"]; @@ -105,7 +109,8 @@ NSData* clientPairingSecret = [self concatData:clientSecret with:[cryptoMan signData:clientSecret withKey:[CryptoManager readKeyFromFile]]]; NSData* clientSecretResp = [_httpManager executeRequestSynchronously:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]]; - if (![[HttpManager getStringFromXML:clientSecretResp tag:@"paired"] isEqual:@"1"]) { + pairedString = [HttpManager getStringFromXML:clientSecretResp tag:@"paired"]; + if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { [_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; //TODO: better message [_callback pairFailed:@"clientSecretResp failed"]; @@ -113,7 +118,8 @@ } NSData* clientPairChallenge = [_httpManager executeRequestSynchronously:[_httpManager newPairChallenge]]; - if (![[HttpManager getStringFromXML:clientPairChallenge tag:@"paired"] isEqual:@"1"]) { + pairedString = [HttpManager getStringFromXML:clientPairChallenge tag:@"paired"]; + if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { [_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; //TODO: better message [_callback pairFailed:@"clientPairChallenge failed"]; diff --git a/Limelight/Stream/StreamManager.m b/Limelight/Stream/StreamManager.m index d8135df..d13deec 100644 --- a/Limelight/Stream/StreamManager.m +++ b/Limelight/Stream/StreamManager.m @@ -41,12 +41,23 @@ cert:cert]; NSData* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; - if (![[HttpManager getStringFromXML:serverInfoResp tag:@"currentgame"] isEqualToString:@"0"]) { + NSString* currentGame = [HttpManager getStringFromXML:serverInfoResp tag:@"currentgame"]; + if (currentGame == NULL) { + [_callbacks launchFailed]; + return; + } + else if ([currentGame isEqualToString:@"0"]) { // App already running, resume it - [self resumeApp:hMan]; + if (![self resumeApp:hMan]) { + [_callbacks launchFailed]; + return; + } } else { // Start app - [self launchApp:hMan]; + if (![self launchApp:hMan]) { + [_callbacks launchFailed]; + return; + } } VideoDecoderRenderer* renderer = [[VideoDecoderRenderer alloc]initWithView:_renderView]; diff --git a/Limelight/ViewControllers/StreamFrameViewController.m b/Limelight/ViewControllers/StreamFrameViewController.m index 18758c2..fc6e0cb 100644 --- a/Limelight/ViewControllers/StreamFrameViewController.m +++ b/Limelight/ViewControllers/StreamFrameViewController.m @@ -81,7 +81,13 @@ } - (void) launchFailed { - + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Failed" + message:@"Failed to start app" + preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){ + [self performSegueWithIdentifier:@"returnToMainFrame" sender:self]; + }]]; + [self presentViewController:alert animated:YES completion:nil]; } - (void) displayMessage:(char*)message { diff --git a/MainFrame-iPad.storyboard b/MainFrame-iPad.storyboard index c786399..1fa91ef 100644 --- a/MainFrame-iPad.storyboard +++ b/MainFrame-iPad.storyboard @@ -1,5 +1,5 @@ - + @@ -109,7 +109,7 @@ - + diff --git a/MainFrame-iPhone.storyboard b/MainFrame-iPhone.storyboard index 82c4c19..0b04f23 100644 --- a/MainFrame-iPhone.storyboard +++ b/MainFrame-iPhone.storyboard @@ -1,5 +1,5 @@ - + @@ -103,7 +103,7 @@ - +