Created http response class and added error checking

This commit is contained in:
Diego Waxemberg
2015-01-31 01:57:23 -05:00
parent 4224d02eae
commit e3e95c29f6
10 changed files with 401 additions and 313 deletions
+4 -2
View File
@@ -9,6 +9,7 @@
#import "AppManager.h"
#import "CryptoManager.h"
#import "Utils.h"
#import "HttpResponse.h"
@implementation AppManager {
NSOperationQueue* _opQueue;
@@ -60,8 +61,9 @@
}
if (appImage == nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
NSData* appAsset = [hMan executeRequestSynchronously:[hMan newAppAssetRequestWithAppId:app.appId]];
appImage = [UIImage imageWithData:appAsset];
HttpResponse* appAssetResp = [hMan executeRequestSynchronously:[hMan newAppAssetRequestWithAppId:app.appId]];
appImage = [UIImage imageWithData:appAssetResp.responseData];
app.appImage = appImage;
if (appImage != nil) {
@synchronized(_imageCache) {
+3 -3
View File
@@ -39,14 +39,14 @@
- (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *))callback {
HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
HttpResponse* serverInfoResponse = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
Host* host = nil;
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) {
if ([serverInfoResponse isStatusOk]) {
DataManager* dataMan = [[DataManager alloc] init];
host = [dataMan createHost];
host.address = hostAddress;
[HttpManager populateHostFromXML:serverInfoData host:host];
[serverInfoResponse populateHost:host];
if (![self addHostToDiscovery:host]) {
[dataMan removeHost:host];
}
+9 -9
View File
@@ -43,18 +43,18 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
BOOL receivedResponse = NO;
if (!self.cancelled && _host.localAddress != nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.localAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) {
[HttpManager populateHostFromXML:serverInfoData host:_host];
HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
if ([serverInfoResp isStatusOk]) {
[serverInfoResp populateHost:_host];
_host.address = _host.localAddress;
receivedResponse = YES;
}
}
if (!self.cancelled && !receivedResponse && _host.externalAddress != nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.externalAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) {
[HttpManager populateHostFromXML:serverInfoData host:_host];
HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
if ([serverInfoResp isStatusOk]) {
[serverInfoResp populateHost:_host];
_host.address = _host.externalAddress;
receivedResponse = YES;
}
@@ -62,9 +62,9 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
if (!self.cancelled && !receivedResponse && _host.address != nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) {
[HttpManager populateHostFromXML:serverInfoData host:_host];
HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
if ([serverInfoResp isStatusOk]) {
[serverInfoResp populateHost:_host];
receivedResponse = YES;
}
}
+4 -6
View File
@@ -8,14 +8,10 @@
#import <Foundation/Foundation.h>
#import "Host.h"
#import "HttpResponse.h"
@interface HttpManager : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
+ (NSArray*) getAppListFromXML:(NSData*)xml;
+ (void) populateHostFromXML:(NSData*)xml host:(Host*)host;
+ (NSString*) getStringFromXML:(NSData*)xml tag:(NSString*)tag;
+ (NSString*) getStatusStringFromXML:(NSData*)xml;
- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert;
- (NSURLRequest*) newPairRequest:(NSData*)salt;
- (NSURLRequest*) newUnpairRequest;
@@ -29,7 +25,9 @@
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId;
- (NSURLRequest*) newQuitAppRequest;
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId;
- (NSData*) executeRequestSynchronously:(NSURLRequest*)request;
- (HttpResponse*) executeRequestSynchronously:(NSURLRequest*)request;
- (void) executeRequest:(NSURLRequest*)request;
@end
+2 -203
View File
@@ -26,207 +26,6 @@
static const NSString* PORT = @"47984";
+ (NSArray*) getAppListFromXML:(NSData*)xml {
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return NULL;
}
xmlNodePtr node;
xmlNodePtr rootNode = node = xmlDocGetRootElement(docPtr);
// Check root status_code
if (![HttpManager verifyStatus: rootNode]) {
NSLog(@"ERROR: Request returned with failure status");
xmlFreeDoc(docPtr);
return NULL;
}
// Skip the root node
node = node->children;
NSMutableArray* appList = [[NSMutableArray alloc] init];
while (node != NULL) {
//NSLog(@"node: %s", node->name);
if (!xmlStrcmp(node->name, (const xmlChar*)"App")) {
xmlNodePtr appInfoNode = node->xmlChildrenNode;
NSString* appName;
NSString* appId;
BOOL appIsRunning = NO;
while (appInfoNode != NULL) {
//NSLog(@"appInfoNode: %s", appInfoNode->name);
if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"AppTitle")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appName = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"ID")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"IsRunning")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appIsRunning = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"];
xmlFree(nodeVal);
}
appInfoNode = appInfoNode->next;
}
App* app = [[App alloc] init];
app.appName = appName;
app.appId = appId;
app.isRunning = appIsRunning;
[appList addObject:app];
}
node = node->next;
}
xmlFreeDoc(docPtr);
return appList;
}
+ (void) populateHostFromXML:(NSData*)xml host:(Host*)host {
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return;
}
xmlNodePtr node;
xmlNodePtr rootNode = node = xmlDocGetRootElement(docPtr);
// Check root status_code
if (![HttpManager verifyStatus: rootNode]) {
NSLog(@"ERROR: Request returned with failure status");
xmlFreeDoc(docPtr);
return;
}
// Skip the root node
node = node->children;
while (node != NULL) {
//NSLog(@"node: %s", node->name);
if (!xmlStrcmp(node->name, (const xmlChar*)"hostname")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.name = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"ExternalIP")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.externalAddress = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"LocalIP")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.localAddress = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"uniqueid")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.uuid = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"mac")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.mac = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"PairStatus")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.pairState = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"] ? PairStatePaired : PairStateUnpaired;
xmlFree(nodeVal);
}
node = node->next;
}
xmlFreeDoc(docPtr);
}
+ (NSString*) getStatusStringFromXML:(NSData*)xml {
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return NULL;
}
NSString* string;
xmlNodePtr rootNode = xmlDocGetRootElement(docPtr);
if (rootNode == NULL) {
NSLog(@"ERROR: No root XML element.");
xmlFreeDoc(docPtr);
return NULL;
}
string = [HttpManager getStatusMessage: rootNode];
xmlFreeDoc(docPtr);
return string;
}
+ (NSString*) getStringFromXML:(NSData*)xml tag:(NSString*)tag {
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return NULL;
}
NSString* value;
xmlNodePtr node;
xmlNodePtr rootNode = node = xmlDocGetRootElement(docPtr);
// Check root status_code
if (![HttpManager verifyStatus: rootNode]) {
NSLog(@"ERROR: Request returned with failure status");
xmlFreeDoc(docPtr);
return NULL;
}
// Skip the root node
node = node->children;
while (node != NULL) {
//NSLog(@"node: %s", node->name);
if (!xmlStrcmp(node->name, (const xmlChar*)[tag UTF8String])) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
value = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
}
node = node->next;
}
//NSLog(@"xmlValue: %@", value);
xmlFreeDoc(docPtr);
return value;
}
+ (NSString*) getStatusMessage:(xmlNodePtr)docRoot {
xmlChar* statusMsgXml = xmlGetProp(docRoot, (const xmlChar*)"status_message");
NSString* statusMsg;
if (statusMsgXml != NULL) {
statusMsg = [NSString stringWithUTF8String:(const char*)statusMsgXml];
xmlFree(statusMsgXml);
}
else {
statusMsg = @"Server Error";
}
return statusMsg;
}
+ (bool) verifyStatus:(xmlNodePtr)docRoot {
xmlChar* statusStr = xmlGetProp(docRoot, (const xmlChar*)"status_code");
if (statusStr != NULL) {
int status = [[NSString stringWithUTF8String:(const char*)statusStr] intValue];
xmlFree(statusStr);
return status == 200;
}
return false;
}
+ (NSData*) fixXmlVersion:(NSData*) xmlData {
NSString* dataString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding];
NSString* xmlString = [dataString stringByReplacingOccurrencesOfString:@"UTF-16" withString:@"UTF-8" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [dataString length])];
@@ -247,14 +46,14 @@ static const NSString* PORT = @"47984";
return self;
}
- (NSData*) executeRequestSynchronously:(NSURLRequest*)request {
- (HttpResponse*) executeRequestSynchronously:(NSURLRequest*)request {
NSLog(@"Making Request: %@", request);
[_respData setLength:0];
dispatch_sync(dispatch_get_main_queue(), ^{
[NSURLConnection connectionWithRequest:request delegate:self];
});
dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER);
return _requestResp;
return [HttpResponse responseWithData:_requestResp];
}
- (void) executeRequest:(NSURLRequest*)request {
+26
View File
@@ -0,0 +1,26 @@
//
// HttpResponse.h
// Limelight
//
// Created by Diego Waxemberg on 1/30/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Host.h"
@interface HttpResponse : NSObject
@property (nonatomic) NSInteger statusCode;
@property (nonatomic) NSString* statusMessage;
@property (nonatomic) NSData* responseData;
+ (HttpResponse*) responseWithData:(NSData*)xml;
- (NSString*) parseStringTag:(NSString*)tag;
- (BOOL)parseIntTag:(NSString *)tag value:(NSInteger*)value;
- (BOOL) isStatusOk;
- (BOOL) populateHost:(Host*)host;
- (NSArray*) getAppList;
@end
+222
View File
@@ -0,0 +1,222 @@
//
// HttpResponse.m
// Limelight
//
// Created by Diego Waxemberg on 1/30/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved.
//
#import "HttpResponse.h"
#import "App.h"
#import <libxml2/libxml/xmlreader.h>
@implementation HttpResponse
+ (HttpResponse*) responseWithData:(NSData*)xml {
HttpResponse* response = [[HttpResponse alloc] init];
response.responseData = xml;
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return response;
}
xmlNodePtr rootNode = xmlDocGetRootElement(docPtr);
if (rootNode == NULL) {
NSLog(@"ERROR: No root XML element.");
xmlFreeDoc(docPtr);
return response;
}
xmlChar* statusStr = xmlGetProp(rootNode, (const xmlChar*)"status_code");
if (statusStr != NULL) {
int status = [[NSString stringWithUTF8String:(const char*)statusStr] intValue];
xmlFree(statusStr);
response.statusCode = status;
}
xmlChar* statusMsgXml = xmlGetProp(rootNode, (const xmlChar*)"status_message");
NSString* statusMsg;
if (statusMsgXml != NULL) {
statusMsg = [NSString stringWithUTF8String:(const char*)statusMsgXml];
xmlFree(statusMsgXml);
}
else {
statusMsg = @"Server Error";
}
response.statusMessage = statusMsg;
return response;
}
- (NSString*)parseStringTag:(NSString *)tag {
xmlDocPtr docPtr = xmlParseMemory([self.responseData bytes], (int)[self.responseData length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return nil;
}
xmlNodePtr node = xmlDocGetRootElement(docPtr);
// Check root status_code
if (![self isStatusOk]) {
NSLog(@"ERROR: Request returned with failure status");
xmlFreeDoc(docPtr);
return nil;
}
// Skip the root node
node = node->children;
NSString* value;
while (node != NULL) {
//NSLog(@"node: %s", node->name);
if (!xmlStrcmp(node->name, (const xmlChar*)[tag UTF8String])) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
value = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
}
node = node->next;
}
//NSLog(@"xmlValue: %@", value);
xmlFreeDoc(docPtr);
return value;
}
- (BOOL)parseIntTag:(NSString *)tag value:(NSInteger*)value {
NSString* stringVal = [self parseStringTag:tag];
if (stringVal != nil) {
*value = [stringVal integerValue];
return true;
} else {
return false;
}
}
- (BOOL) isStatusOk {
return self.statusCode == 200;
}
- (BOOL) populateHost:(Host*)host {
xmlDocPtr docPtr = xmlParseMemory([self.responseData bytes], (int)[self.responseData length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return false;
}
xmlNodePtr node = xmlDocGetRootElement(docPtr);
// Check root status_code
if (![self isStatusOk]) {
NSLog(@"ERROR: Request returned with failure status");
xmlFreeDoc(docPtr);
return false;
}
// Skip the root node
node = node->children;
while (node != NULL) {
//NSLog(@"node: %s", node->name);
if (!xmlStrcmp(node->name, (const xmlChar*)"hostname")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.name = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"ExternalIP")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.externalAddress = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"LocalIP")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.localAddress = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"uniqueid")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.uuid = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"mac")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.mac = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"PairStatus")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.pairState = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"] ? PairStatePaired : PairStateUnpaired;
xmlFree(nodeVal);
}
node = node->next;
}
xmlFreeDoc(docPtr);
return true;
}
- (NSArray*) getAppList {
xmlDocPtr docPtr = xmlParseMemory([self.responseData bytes], (int)[self.responseData length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return nil;
}
xmlNodePtr node = xmlDocGetRootElement(docPtr);
// Check root status_code
if (![self isStatusOk]) {
NSLog(@"ERROR: Request returned with failure status");
xmlFreeDoc(docPtr);
return nil;
}
// Skip the root node
node = node->children;
NSMutableArray* appList = [[NSMutableArray alloc] init];
while (node != NULL) {
//NSLog(@"node: %s", node->name);
if (!xmlStrcmp(node->name, (const xmlChar*)"App")) {
xmlNodePtr appInfoNode = node->xmlChildrenNode;
NSString* appName;
NSString* appId;
BOOL appIsRunning = NO;
while (appInfoNode != NULL) {
//NSLog(@"appInfoNode: %s", appInfoNode->name);
if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"AppTitle")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appName = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"ID")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"IsRunning")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appIsRunning = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"];
xmlFree(nodeVal);
}
appInfoNode = appInfoNode->next;
}
App* app = [[App alloc] init];
app.appName = appName;
app.appId = appId;
app.isRunning = appIsRunning;
[appList addObject:app];
}
node = node->next;
}
xmlFreeDoc(docPtr);
return appList;
}
@end
+61 -35
View File
@@ -9,6 +9,7 @@
#import "PairManager.h"
#import "CryptoManager.h"
#import "Utils.h"
#import "HttpResponse.h"
#include <dispatch/dispatch.h>
@@ -27,18 +28,19 @@
}
- (void) main {
NSData* serverInfo = [_httpManager executeRequestSynchronously:[_httpManager newServerInfoRequest]];
if (serverInfo == NULL) {
HttpResponse* serverInfo = [_httpManager executeRequestSynchronously:[_httpManager newServerInfoRequest]];
if (serverInfo == nil) {
[_callback pairFailed:@"Unable to connect to PC"];
return;
}
if (![[HttpManager getStringFromXML:serverInfo tag:@"currentgame"] isEqual:@"0"]) {
[_callback pairFailed:@"You must stop streaming before attempting to pair."];
}
else if (![[HttpManager getStringFromXML:serverInfo tag:@"PairStatus"] isEqual:@"1"]) {
[self initiatePair];
} else {
[_callback alreadyPaired];
if ([serverInfo isStatusOk]) {
if (![[serverInfo parseStringTag:@"currentgame"] isEqual:@"0"]) {
[_callback pairFailed:@"You must stop streaming before attempting to pair."];
} else if (![[serverInfo parseStringTag:@"PairStatus"] isEqual:@"1"]) {
[self initiatePair];
} else {
[_callback alreadyPaired];
}
}
}
@@ -48,16 +50,18 @@
NSLog(@"PIN: %@, saltedPIN: %@", PIN, salt);
[_callback showPIN:PIN];
NSData* pairResp = [_httpManager executeRequestSynchronously:[_httpManager newPairRequest:salt]];
NSString* pairedString;
pairedString = [HttpManager getStringFromXML:pairResp tag:@"paired"];
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
HttpResponse* pairResp = [_httpManager executeRequestSynchronously:[_httpManager newPairRequest:salt]];
if (![self verifyResponseStatus:pairResp]) {
return;
}
NSInteger* pairedStatus;
if (![pairResp parseIntTag:@"paired" value:pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:@"Pairing was declined by the target."];
return;
}
NSString* plainCert = [HttpManager getStringFromXML:pairResp tag:@"plaincert"];
NSString* plainCert = [pairResp parseStringTag:@"plaincert"];
CryptoManager* cryptoMan = [[CryptoManager alloc] init];
NSData* aesKey = [cryptoMan createAESKeyFromSalt:salt];
@@ -65,15 +69,17 @@
NSData* randomChallenge = [Utils randomBytes:16];
NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey];
NSData* challengeResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRequest:encryptedChallenge]];
pairedString = [HttpManager getStringFromXML:challengeResp tag:@"paired"];
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
HttpResponse* challengeResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRequest:encryptedChallenge]];
if (![self verifyResponseStatus:challengeResp]) {
return;
}
if (![challengeResp parseIntTag:@"paired" value:pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:@"Pairing stage #2 failed"];
return;
}
NSData* encServerChallengeResp = [Utils hexToBytes:[HttpManager getStringFromXML:challengeResp tag:@"challengeresponse"]];
NSData* encServerChallengeResp = [Utils hexToBytes:[challengeResp parseStringTag:@"challengeresponse"]];
NSData* decServerChallengeResp = [cryptoMan aesDecrypt:encServerChallengeResp withKey:aesKey];
NSData* serverResponse = [decServerChallengeResp subdataWithRange:NSMakeRange(0, 20)];
@@ -83,50 +89,70 @@
NSData* challengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_cert]] with:clientSecret]];
NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey];
NSData* secretResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRespRequest:challengeRespEncrypted]];
pairedString = [HttpManager getStringFromXML:secretResp tag:@"paired"];
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
HttpResponse* secretResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRespRequest:challengeRespEncrypted]];
if (![self verifyResponseStatus:secretResp]) {
return;
}
if (![secretResp parseIntTag:@"paired" value:pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:@"Pairing stage #3 failed"];
return;
}
NSData* serverSecretResp = [Utils hexToBytes:[HttpManager getStringFromXML:secretResp tag:@"pairingsecret"]];
NSData* serverSecretResp = [Utils hexToBytes:[secretResp parseStringTag:@"pairingsecret"]];
NSData* serverSecret = [serverSecretResp subdataWithRange:NSMakeRange(0, 16)];
NSData* serverSignature = [serverSecretResp subdataWithRange:NSMakeRange(16, 256)];
if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) {
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
[_httpManager executeRequest:[_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 executeRequestSynchronously:[_httpManager newUnpairRequest]];
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:@"Incorrect PIN"];
return;
}
NSData* clientPairingSecret = [self concatData:clientSecret with:[cryptoMan signData:clientSecret withKey:[CryptoManager readKeyFromFile]]];
NSData* clientSecretResp = [_httpManager executeRequestSynchronously:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]];
pairedString = [HttpManager getStringFromXML:clientSecretResp tag:@"paired"];
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
HttpResponse* clientSecretResp = [_httpManager executeRequestSynchronously:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]];
if (![self verifyResponseStatus:clientSecretResp]) {
return;
}
if ([clientSecretResp parseIntTag:@"paired" value:pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:@"Pairing stage #4 failed"];
return;
}
NSData* clientPairChallenge = [_httpManager executeRequestSynchronously:[_httpManager newPairChallenge]];
pairedString = [HttpManager getStringFromXML:clientPairChallenge tag:@"paired"];
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
HttpResponse* clientPairChallengeResp = [_httpManager executeRequestSynchronously:[_httpManager newPairChallenge]];
if (![self verifyResponseStatus:clientPairChallengeResp]) {
return;
}
if (![clientPairChallengeResp parseIntTag:@"paired" value:pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:@"Pairing stage #5 failed"];
return;
}
[_callback pairSuccessful];
}
- (BOOL) verifyResponseStatus:(HttpResponse*)resp {
if (resp == nil) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:@"Network error occured."];
return false;
} else if (![resp isStatusOk]) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:resp.statusMessage];
return false;
} else {
return true;
}
}
- (NSData*) concatData:(NSData*)data with:(NSData*)moreData {
NSMutableData* concatData = [[NSMutableData alloc] initWithData:data];
[concatData appendData:moreData];