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 "AppManager.h"
#import "CryptoManager.h" #import "CryptoManager.h"
#import "Utils.h" #import "Utils.h"
#import "HttpResponse.h"
@implementation AppManager { @implementation AppManager {
NSOperationQueue* _opQueue; NSOperationQueue* _opQueue;
@@ -60,8 +61,9 @@
} }
if (appImage == nil) { if (appImage == nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
NSData* appAsset = [hMan executeRequestSynchronously:[hMan newAppAssetRequestWithAppId:app.appId]]; HttpResponse* appAssetResp = [hMan executeRequestSynchronously:[hMan newAppAssetRequestWithAppId:app.appId]];
appImage = [UIImage imageWithData:appAsset];
appImage = [UIImage imageWithData:appAssetResp.responseData];
app.appImage = appImage; app.appImage = appImage;
if (appImage != nil) { if (appImage != nil) {
@synchronized(_imageCache) { @synchronized(_imageCache) {
+3 -3
View File
@@ -39,14 +39,14 @@
- (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *))callback { - (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *))callback {
HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; 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; Host* host = nil;
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) { if ([serverInfoResponse isStatusOk]) {
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
host = [dataMan createHost]; host = [dataMan createHost];
host.address = hostAddress; host.address = hostAddress;
[HttpManager populateHostFromXML:serverInfoData host:host]; [serverInfoResponse populateHost:host];
if (![self addHostToDiscovery:host]) { if (![self addHostToDiscovery:host]) {
[dataMan removeHost: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; BOOL receivedResponse = NO;
if (!self.cancelled && _host.localAddress != nil) { if (!self.cancelled && _host.localAddress != nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.localAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.localAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) { if ([serverInfoResp isStatusOk]) {
[HttpManager populateHostFromXML:serverInfoData host:_host]; [serverInfoResp populateHost:_host];
_host.address = _host.localAddress; _host.address = _host.localAddress;
receivedResponse = YES; receivedResponse = YES;
} }
} }
if (!self.cancelled && !receivedResponse && _host.externalAddress != nil) { if (!self.cancelled && !receivedResponse && _host.externalAddress != nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.externalAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.externalAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) { if ([serverInfoResp isStatusOk]) {
[HttpManager populateHostFromXML:serverInfoData host:_host]; [serverInfoResp populateHost:_host];
_host.address = _host.externalAddress; _host.address = _host.externalAddress;
receivedResponse = YES; receivedResponse = YES;
} }
@@ -62,9 +62,9 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
if (!self.cancelled && !receivedResponse && _host.address != nil) { if (!self.cancelled && !receivedResponse && _host.address != nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) { if ([serverInfoResp isStatusOk]) {
[HttpManager populateHostFromXML:serverInfoData host:_host]; [serverInfoResp populateHost:_host];
receivedResponse = YES; receivedResponse = YES;
} }
} }
+4 -6
View File
@@ -8,14 +8,10 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Host.h" #import "Host.h"
#import "HttpResponse.h"
@interface HttpManager : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate> @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; - (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert;
- (NSURLRequest*) newPairRequest:(NSData*)salt; - (NSURLRequest*) newPairRequest:(NSData*)salt;
- (NSURLRequest*) newUnpairRequest; - (NSURLRequest*) newUnpairRequest;
@@ -29,7 +25,9 @@
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId; - (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId;
- (NSURLRequest*) newQuitAppRequest; - (NSURLRequest*) newQuitAppRequest;
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId; - (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId;
- (NSData*) executeRequestSynchronously:(NSURLRequest*)request; - (HttpResponse*) executeRequestSynchronously:(NSURLRequest*)request;
- (void) executeRequest:(NSURLRequest*)request;
@end @end
+2 -203
View File
@@ -26,207 +26,6 @@
static const NSString* PORT = @"47984"; 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 { + (NSData*) fixXmlVersion:(NSData*) xmlData {
NSString* dataString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding]; NSString* dataString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding];
NSString* xmlString = [dataString stringByReplacingOccurrencesOfString:@"UTF-16" withString:@"UTF-8" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [dataString length])]; 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; return self;
} }
- (NSData*) executeRequestSynchronously:(NSURLRequest*)request { - (HttpResponse*) executeRequestSynchronously:(NSURLRequest*)request {
NSLog(@"Making Request: %@", request); NSLog(@"Making Request: %@", request);
[_respData setLength:0]; [_respData setLength:0];
dispatch_sync(dispatch_get_main_queue(), ^{ dispatch_sync(dispatch_get_main_queue(), ^{
[NSURLConnection connectionWithRequest:request delegate:self]; [NSURLConnection connectionWithRequest:request delegate:self];
}); });
dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER);
return _requestResp; return [HttpResponse responseWithData:_requestResp];
} }
- (void) executeRequest:(NSURLRequest*)request { - (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
+57 -31
View File
@@ -9,6 +9,7 @@
#import "PairManager.h" #import "PairManager.h"
#import "CryptoManager.h" #import "CryptoManager.h"
#import "Utils.h" #import "Utils.h"
#import "HttpResponse.h"
#include <dispatch/dispatch.h> #include <dispatch/dispatch.h>
@@ -27,20 +28,21 @@
} }
- (void) main { - (void) main {
NSData* serverInfo = [_httpManager executeRequestSynchronously:[_httpManager newServerInfoRequest]]; HttpResponse* serverInfo = [_httpManager executeRequestSynchronously:[_httpManager newServerInfoRequest]];
if (serverInfo == NULL) { if (serverInfo == nil) {
[_callback pairFailed:@"Unable to connect to PC"]; [_callback pairFailed:@"Unable to connect to PC"];
return; return;
} }
if (![[HttpManager getStringFromXML:serverInfo tag:@"currentgame"] isEqual:@"0"]) { if ([serverInfo isStatusOk]) {
if (![[serverInfo parseStringTag:@"currentgame"] isEqual:@"0"]) {
[_callback pairFailed:@"You must stop streaming before attempting to pair."]; [_callback pairFailed:@"You must stop streaming before attempting to pair."];
} } else if (![[serverInfo parseStringTag:@"PairStatus"] isEqual:@"1"]) {
else if (![[HttpManager getStringFromXML:serverInfo tag:@"PairStatus"] isEqual:@"1"]) {
[self initiatePair]; [self initiatePair];
} else { } else {
[_callback alreadyPaired]; [_callback alreadyPaired];
} }
} }
}
- (void) initiatePair { - (void) initiatePair {
NSString* PIN = [self generatePIN]; NSString* PIN = [self generatePIN];
@@ -48,16 +50,18 @@
NSLog(@"PIN: %@, saltedPIN: %@", PIN, salt); NSLog(@"PIN: %@, saltedPIN: %@", PIN, salt);
[_callback showPIN:PIN]; [_callback showPIN:PIN];
NSData* pairResp = [_httpManager executeRequestSynchronously:[_httpManager newPairRequest:salt]]; HttpResponse* pairResp = [_httpManager executeRequestSynchronously:[_httpManager newPairRequest:salt]];
NSString* pairedString; if (![self verifyResponseStatus:pairResp]) {
pairedString = [HttpManager getStringFromXML:pairResp tag:@"paired"]; return;
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { }
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; NSInteger* pairedStatus;
if (![pairResp parseIntTag:@"paired" value:pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:@"Pairing was declined by the target."]; [_callback pairFailed:@"Pairing was declined by the target."];
return; return;
} }
NSString* plainCert = [HttpManager getStringFromXML:pairResp tag:@"plaincert"]; NSString* plainCert = [pairResp parseStringTag:@"plaincert"];
CryptoManager* cryptoMan = [[CryptoManager alloc] init]; CryptoManager* cryptoMan = [[CryptoManager alloc] init];
NSData* aesKey = [cryptoMan createAESKeyFromSalt:salt]; NSData* aesKey = [cryptoMan createAESKeyFromSalt:salt];
@@ -65,15 +69,17 @@
NSData* randomChallenge = [Utils randomBytes:16]; NSData* randomChallenge = [Utils randomBytes:16];
NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey]; NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey];
NSData* challengeResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRequest:encryptedChallenge]]; HttpResponse* challengeResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRequest:encryptedChallenge]];
pairedString = [HttpManager getStringFromXML:challengeResp tag:@"paired"]; if (![self verifyResponseStatus:challengeResp]) {
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { return;
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; }
if (![challengeResp parseIntTag:@"paired" value:pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:@"Pairing stage #2 failed"]; [_callback pairFailed:@"Pairing stage #2 failed"];
return; 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* decServerChallengeResp = [cryptoMan aesDecrypt:encServerChallengeResp withKey:aesKey];
NSData* serverResponse = [decServerChallengeResp subdataWithRange:NSMakeRange(0, 20)]; 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* challengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_cert]] with:clientSecret]];
NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey]; NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey];
NSData* secretResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRespRequest:challengeRespEncrypted]]; HttpResponse* secretResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRespRequest:challengeRespEncrypted]];
pairedString = [HttpManager getStringFromXML:secretResp tag:@"paired"]; if (![self verifyResponseStatus:secretResp]) {
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { return;
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; }
if (![secretResp parseIntTag:@"paired" value:pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:@"Pairing stage #3 failed"]; [_callback pairFailed:@"Pairing stage #3 failed"];
return; 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* serverSecret = [serverSecretResp subdataWithRange:NSMakeRange(0, 16)];
NSData* serverSignature = [serverSecretResp subdataWithRange:NSMakeRange(16, 256)]; NSData* serverSignature = [serverSecretResp subdataWithRange:NSMakeRange(16, 256)];
if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) { if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) {
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; [_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:@"Server certificate invalid"]; [_callback pairFailed:@"Server certificate invalid"];
return; return;
} }
NSData* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret]]; NSData* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret]];
if (![serverChallengeRespHash isEqual:serverResponse]) { if (![serverChallengeRespHash isEqual:serverResponse]) {
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; [_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:@"Incorrect PIN"]; [_callback pairFailed:@"Incorrect PIN"];
return; return;
} }
NSData* clientPairingSecret = [self concatData:clientSecret with:[cryptoMan signData:clientSecret withKey:[CryptoManager readKeyFromFile]]]; NSData* clientPairingSecret = [self concatData:clientSecret with:[cryptoMan signData:clientSecret withKey:[CryptoManager readKeyFromFile]]];
NSData* clientSecretResp = [_httpManager executeRequestSynchronously:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]]; HttpResponse* clientSecretResp = [_httpManager executeRequestSynchronously:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]];
pairedString = [HttpManager getStringFromXML:clientSecretResp tag:@"paired"]; if (![self verifyResponseStatus:clientSecretResp]) {
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { return;
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; }
if ([clientSecretResp parseIntTag:@"paired" value:pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:@"Pairing stage #4 failed"]; [_callback pairFailed:@"Pairing stage #4 failed"];
return; return;
} }
NSData* clientPairChallenge = [_httpManager executeRequestSynchronously:[_httpManager newPairChallenge]]; HttpResponse* clientPairChallengeResp = [_httpManager executeRequestSynchronously:[_httpManager newPairChallenge]];
pairedString = [HttpManager getStringFromXML:clientPairChallenge tag:@"paired"]; if (![self verifyResponseStatus:clientPairChallengeResp]) {
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { return;
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; }
if (![clientPairChallengeResp parseIntTag:@"paired" value:pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_callback pairFailed:@"Pairing stage #5 failed"]; [_callback pairFailed:@"Pairing stage #5 failed"];
return; return;
} }
[_callback pairSuccessful]; [_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 { - (NSData*) concatData:(NSData*)data with:(NSData*)moreData {
NSMutableData* concatData = [[NSMutableData alloc] initWithData:data]; NSMutableData* concatData = [[NSMutableData alloc] initWithData:data];
[concatData appendData:moreData]; [concatData appendData:moreData];
+17 -13
View File
@@ -41,11 +41,11 @@
deviceName:@"roth" deviceName:@"roth"
cert:cert]; cert:cert];
NSData* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
NSString* currentGame = [HttpManager getStringFromXML:serverInfoResp tag:@"currentgame"]; NSString* currentGame = [serverInfoResp parseStringTag:@"currentgame"];
NSString* pairStatus = [HttpManager getStringFromXML:serverInfoResp tag:@"PairStatus"]; NSString* pairStatus = [serverInfoResp parseStringTag:@"PairStatus"];
NSString* currentClient = [HttpManager getStringFromXML:serverInfoResp tag:@"CurrentClient"]; NSString* currentClient = [serverInfoResp parseStringTag:@"CurrentClient"];
if (currentGame == NULL || pairStatus == NULL) { if (![serverInfoResp isStatusOk] || currentGame == NULL || pairStatus == NULL) {
[_callbacks launchFailed:@"Failed to connect to PC"]; [_callbacks launchFailed:@"Failed to connect to PC"];
return; return;
} }
@@ -102,19 +102,21 @@
} }
- (BOOL) launchApp:(HttpManager*)hMan { - (BOOL) launchApp:(HttpManager*)hMan {
NSData* launchResp = [hMan executeRequestSynchronously: HttpResponse* launchResp = [hMan executeRequestSynchronously:
[hMan newLaunchRequest:_config.appID [hMan newLaunchRequest:_config.appID
width:_config.width width:_config.width
height:_config.height height:_config.height
refreshRate:_config.frameRate refreshRate:_config.frameRate
rikey:[Utils bytesToHex:_config.riKey] rikey:[Utils bytesToHex:_config.riKey]
rikeyid:_config.riKeyId]]; rikeyid:_config.riKeyId]];
NSString *gameSession = [HttpManager getStringFromXML:launchResp tag:@"gamesession"]; NSString *gameSession = [launchResp parseStringTag:@"gamesession"];
if (launchResp == NULL) { if (launchResp == NULL || ![launchResp isStatusOk]) {
[_callbacks launchFailed:@"Failed to launch app"]; [_callbacks launchFailed:@"Failed to launch app"];
NSLog(@"Failed Launch Response: %@", launchResp.statusMessage);
return FALSE; return FALSE;
} else if (gameSession == NULL || [gameSession isEqualToString:@"0"]) { } else if (gameSession == NULL || [gameSession isEqualToString:@"0"]) {
[_callbacks launchFailed:[HttpManager getStatusStringFromXML:launchResp]]; [_callbacks launchFailed:launchResp.statusMessage];
NSLog(@"Failed to parse game session. Code: %ld Response: %@", (long)launchResp.statusCode, launchResp.statusMessage);
return FALSE; return FALSE;
} }
@@ -122,15 +124,17 @@
} }
- (BOOL) resumeApp:(HttpManager*)hMan { - (BOOL) resumeApp:(HttpManager*)hMan {
NSData* resumeResp = [hMan executeRequestSynchronously: HttpResponse* resumeResp = [hMan executeRequestSynchronously:
[hMan newResumeRequestWithRiKey:[Utils bytesToHex:_config.riKey] [hMan newResumeRequestWithRiKey:[Utils bytesToHex:_config.riKey]
riKeyId:_config.riKeyId]]; riKeyId:_config.riKeyId]];
NSString *resume = [HttpManager getStringFromXML:resumeResp tag:@"resume"]; NSString* resume = [resumeResp parseStringTag:@"resume"];
if (resumeResp == NULL) { if (resumeResp == NULL || ![resumeResp isStatusOk]) {
[_callbacks launchFailed:@"Failed to resume app"]; [_callbacks launchFailed:@"Failed to resume app"];
NSLog(@"Failed Resume Response: %@", resumeResp.statusMessage);
return FALSE; return FALSE;
} else if (resume == NULL || [resume isEqualToString:@"0"]) { } else if (resume == NULL || [resume isEqualToString:@"0"]) {
[_callbacks launchFailed:[HttpManager getStatusStringFromXML:resumeResp]]; [_callbacks launchFailed:resumeResp.statusMessage];
NSLog(@"Failed to parse resume response. Code: %ld Response: %@", (long)resumeResp.statusCode, resumeResp.statusMessage);
return FALSE; return FALSE;
} }
@@ -72,15 +72,22 @@ static StreamConfiguration* streamConfig;
[self.navigationController.navigationBar setNeedsLayout]; [self.navigationController.navigationBar setNeedsLayout];
}); });
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
NSData* appListResp = [hMan executeRequestSynchronously:[hMan newAppListRequest]]; HttpResponse* appListResp = [hMan executeRequestSynchronously:[hMan newAppListRequest]];
appList = [HttpManager getAppListFromXML:appListResp]; if (appListResp == nil || ![appListResp isStatusOk]) {
NSLog(@"Failed to get applist: %@", appListResp.statusMessage);
} else {
appList = [appListResp getAppList];
if (appList == nil) {
NSLog(@"Failed to parse applist");
} else {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self updateApps]; [self updateApps];
}); });
[_appManager stopRetrieving]; [_appManager stopRetrieving];
[_appManager retrieveAssets:appList fromHost:_selectedHost]; [_appManager retrieveAssets:appList fromHost:_selectedHost];
}
}
}); });
} }
@@ -108,8 +115,11 @@ static StreamConfiguration* streamConfig;
_selectedHost = host; _selectedHost = host;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
NSData* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
if ([[HttpManager getStringFromXML:serverInfoResp tag:@"PairStatus"] isEqualToString:@"1"]) { if (serverInfoResp == nil || ![serverInfoResp isStatusOk]) {
NSLog(@"Failed to get server info: %@", serverInfoResp.statusMessage);
} else {
if ([[serverInfoResp parseStringTag:@"PairStatus"] isEqualToString:@"1"]) {
NSLog(@"Already Paired"); NSLog(@"Already Paired");
[self alreadyPaired]; [self alreadyPaired];
} else { } else {
@@ -119,6 +129,7 @@ static StreamConfiguration* streamConfig;
PairManager* pMan = [[PairManager alloc] initWithManager:hMan andCert:_cert callback:self]; PairManager* pMan = [[PairManager alloc] initWithManager:hMan andCert:_cert callback:self];
[_opQueue addOperation:pMan]; [_opQueue addOperation:pMan];
} }
}
}); });
} }