From 879f304a79e5adf9fceb198c47f878db2b9fe30f Mon Sep 17 00:00:00 2001 From: Diego Waxemberg Date: Sun, 1 Feb 2015 04:26:47 -0500 Subject: [PATCH] Refactored http communications to be more abstract and OOP --- Limelight.xcodeproj/project.pbxproj | 24 ++ Limelight/Network/AppAssetResponse.h | 16 ++ Limelight/Network/AppAssetResponse.m | 25 ++ Limelight/Network/AppAssetRetriever.m | 8 +- Limelight/Network/AppListResponse.h | 17 ++ Limelight/Network/AppListResponse.m | 106 +++++++++ Limelight/Network/DiscoveryManager.m | 4 +- Limelight/Network/DiscoveryWorker.m | 14 +- Limelight/Network/HttpManager.h | 5 +- Limelight/Network/HttpManager.m | 13 +- Limelight/Network/HttpRequest.h | 20 ++ Limelight/Network/HttpRequest.m | 28 +++ Limelight/Network/HttpResponse.h | 27 ++- Limelight/Network/HttpResponse.m | 218 ++++-------------- Limelight/Network/PairManager.m | 62 ++--- Limelight/Network/ServerInfoResponse.h | 16 ++ Limelight/Network/ServerInfoResponse.m | 55 +++++ Limelight/Stream/StreamManager.m | 26 ++- .../ViewControllers/MainFrameViewController.m | 16 +- 19 files changed, 460 insertions(+), 240 deletions(-) create mode 100644 Limelight/Network/AppAssetResponse.h create mode 100644 Limelight/Network/AppAssetResponse.m create mode 100644 Limelight/Network/AppListResponse.h create mode 100644 Limelight/Network/AppListResponse.m create mode 100644 Limelight/Network/HttpRequest.h create mode 100644 Limelight/Network/HttpRequest.m create mode 100644 Limelight/Network/ServerInfoResponse.h create mode 100644 Limelight/Network/ServerInfoResponse.m diff --git a/Limelight.xcodeproj/project.pbxproj b/Limelight.xcodeproj/project.pbxproj index 9d4a5111..e215a719 100644 --- a/Limelight.xcodeproj/project.pbxproj +++ b/Limelight.xcodeproj/project.pbxproj @@ -60,6 +60,10 @@ FB8946ED19F6AFE800339C8A /* libopus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946EA19F6AFB800339C8A /* libopus.a */; }; FB9AFD281A7C84ED00872C98 /* HttpResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD271A7C84ED00872C98 /* HttpResponse.m */; }; FB9AFD321A7D867C00872C98 /* AppAssetRetriever.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */; }; + FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD361A7E02DB00872C98 /* HttpRequest.m */; }; + FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */; }; + FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */; }; + FB9AFD401A7E127D00872C98 /* AppListResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */; }; FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494219FC9C04002D2A60 /* AppAssetManager.m */; }; FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494F19FF2174002D2A60 /* SettingsViewController.m */; }; FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */; }; @@ -253,6 +257,14 @@ FB9AFD271A7C84ED00872C98 /* HttpResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HttpResponse.m; sourceTree = ""; }; FB9AFD301A7D867C00872C98 /* AppAssetRetriever.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetRetriever.h; sourceTree = ""; }; FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetRetriever.m; sourceTree = ""; }; + FB9AFD351A7E02DB00872C98 /* HttpRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HttpRequest.h; sourceTree = ""; }; + FB9AFD361A7E02DB00872C98 /* HttpRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HttpRequest.m; sourceTree = ""; }; + FB9AFD381A7E05CE00872C98 /* ServerInfoResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServerInfoResponse.h; sourceTree = ""; }; + FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ServerInfoResponse.m; sourceTree = ""; }; + FB9AFD3B1A7E111600872C98 /* AppAssetResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetResponse.h; sourceTree = ""; }; + FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetResponse.m; sourceTree = ""; }; + FB9AFD3E1A7E127D00872C98 /* AppListResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppListResponse.h; sourceTree = ""; }; + FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppListResponse.m; sourceTree = ""; }; FBD3494119FC9C04002D2A60 /* AppAssetManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetManager.h; sourceTree = ""; }; FBD3494219FC9C04002D2A60 /* AppAssetManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetManager.m; sourceTree = ""; }; FBD3494E19FF2174002D2A60 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = ""; }; @@ -677,8 +689,16 @@ children = ( FB89460F19F646E200339C8A /* HttpManager.h */, FB89461019F646E200339C8A /* HttpManager.m */, + FB9AFD351A7E02DB00872C98 /* HttpRequest.h */, + FB9AFD361A7E02DB00872C98 /* HttpRequest.m */, FB9AFD261A7C84ED00872C98 /* HttpResponse.h */, FB9AFD271A7C84ED00872C98 /* HttpResponse.m */, + FB9AFD381A7E05CE00872C98 /* ServerInfoResponse.h */, + FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */, + FB9AFD3B1A7E111600872C98 /* AppAssetResponse.h */, + FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */, + FB9AFD3E1A7E127D00872C98 /* AppListResponse.h */, + FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */, ); name = Http; sourceTree = ""; @@ -849,6 +869,7 @@ FB89463219F646E200339C8A /* VideoDecoderRenderer.m in Sources */, FBD3495E1A004412002D2A60 /* Settings.m in Sources */, FB290D0419B2C406004C83CF /* AppDelegate.m in Sources */, + FB9AFD401A7E127D00872C98 /* AppListResponse.m in Sources */, FB89463419F646E200339C8A /* Utils.m in Sources */, FBDE86E619F82297001C18A8 /* UIAppView.m in Sources */, FB89462F19F646E200339C8A /* Connection.m in Sources */, @@ -870,12 +891,15 @@ FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */, FB89462819F646E200339C8A /* CryptoManager.m in Sources */, FB89462E19F646E200339C8A /* PairManager.m in Sources */, + FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */, FB4678ED1A50C40900377732 /* OnScreenControls.m in Sources */, FB290D0019B2C406004C83CF /* main.m in Sources */, FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */, FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */, FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */, + FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */, FBD349621A0089F6002D2A60 /* DataManager.m in Sources */, + FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */, FB89463119F646E200339C8A /* StreamManager.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Limelight/Network/AppAssetResponse.h b/Limelight/Network/AppAssetResponse.h new file mode 100644 index 00000000..e4fead48 --- /dev/null +++ b/Limelight/Network/AppAssetResponse.h @@ -0,0 +1,16 @@ +// +// AppAssetResponse.h +// Limelight +// +// Created by Diego Waxemberg on 2/1/15. +// Copyright (c) 2015 Limelight Stream. All rights reserved. +// + +#import +#import "HttpResponse.h" + +@interface AppAssetResponse : NSObject + + + +@end diff --git a/Limelight/Network/AppAssetResponse.m b/Limelight/Network/AppAssetResponse.m new file mode 100644 index 00000000..94a2f1e2 --- /dev/null +++ b/Limelight/Network/AppAssetResponse.m @@ -0,0 +1,25 @@ +// +// AppAssetResponse.m +// Limelight +// +// Created by Diego Waxemberg on 2/1/15. +// Copyright (c) 2015 Limelight Stream. All rights reserved. +// + +#import "AppAssetResponse.h" + +@implementation AppAssetResponse +@synthesize data, statusCode, statusMessage; + +- (void)populateWithData:(NSData *)imageData { + self.data = imageData; + self.statusMessage = @"App asset has no status message"; + self.statusCode = -1; +} + +- (UIImage*) getImage { + UIImage* appImage = [[UIImage alloc] initWithData:self.data]; + return appImage; +} + +@end diff --git a/Limelight/Network/AppAssetRetriever.m b/Limelight/Network/AppAssetRetriever.m index 384772fa..3a220eab 100644 --- a/Limelight/Network/AppAssetRetriever.m +++ b/Limelight/Network/AppAssetRetriever.m @@ -9,7 +9,8 @@ #import "AppAssetRetriever.h" #import "HttpManager.h" #import "CryptoManager.h" -#import "HttpResponse.h" +#import "AppAssetResponse.h" +#import "HttpRequest.h" @implementation AppAssetRetriever static const double RETRY_DELAY = 1; // seconds @@ -29,9 +30,10 @@ static const double RETRY_DELAY = 1; // seconds } if (appImage == nil) { HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:[CryptoManager getUniqueID] deviceName:deviceName cert:[CryptoManager readCertFromFile]]; - HttpResponse* appAssetResp = [hMan executeRequestSynchronously:[hMan newAppAssetRequestWithAppId:self.app.appId]]; + AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init]; + [hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.appId]]]; - appImage = [UIImage imageWithData:appAssetResp.responseData]; + appImage = [UIImage imageWithData:appAssetResp.data]; self.app.appImage = appImage; if (appImage != nil) { @synchronized(self.cache) { diff --git a/Limelight/Network/AppListResponse.h b/Limelight/Network/AppListResponse.h new file mode 100644 index 00000000..8c953feb --- /dev/null +++ b/Limelight/Network/AppListResponse.h @@ -0,0 +1,17 @@ +// +// AppListResponse.h +// Limelight +// +// Created by Diego Waxemberg on 2/1/15. +// Copyright (c) 2015 Limelight Stream. All rights reserved. +// + +#import "HttpResponse.h" + +@interface AppListResponse : NSObject + +- (void)populateWithData:(NSData *)data; +- (NSArray*) getAppList; +- (BOOL) isStatusOk; + +@end diff --git a/Limelight/Network/AppListResponse.m b/Limelight/Network/AppListResponse.m new file mode 100644 index 00000000..5c8e929e --- /dev/null +++ b/Limelight/Network/AppListResponse.m @@ -0,0 +1,106 @@ +// +// AppListResponse.m +// Limelight +// +// Created by Diego Waxemberg on 2/1/15. +// Copyright (c) 2015 Limelight Stream. All rights reserved. +// + +#import "AppListResponse.h" +#import "App.h" +#import + +@implementation AppListResponse { + NSMutableArray* _appList; +} +@synthesize data, statusCode, statusMessage; + +static const char* TAG_APP = "App"; +static const char* TAG_APP_TITLE = "AppTitle"; +static const char* TAG_APP_ID = "ID"; +static const char* TAG_APP_IS_RUNNING = "IsRunning"; + +- (void)populateWithData:(NSData *)xml { + self.data = xml; + _appList = [[NSMutableArray alloc] init]; + [self parseData]; +} + +- (void) parseData { + xmlDocPtr docPtr = xmlParseMemory([self.data bytes], (int)[self.data length]); + if (docPtr == NULL) { + NSLog(@"ERROR: An error occured trying to parse xml."); + return; + } + + xmlNodePtr node = xmlDocGetRootElement(docPtr); + if (node == NULL) { + NSLog(@"ERROR: No root XML element."); + xmlFreeDoc(docPtr); + return; + } + + xmlChar* statusStr = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_CODE UTF8String]); + if (statusStr != NULL) { + int status = [[NSString stringWithUTF8String:(const char*)statusStr] intValue]; + xmlFree(statusStr); + self.statusCode = status; + } + + xmlChar* statusMsgXml = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_MESSAGE UTF8String]); + NSString* statusMsg; + if (statusMsgXml != NULL) { + statusMsg = [NSString stringWithUTF8String:(const char*)statusMsgXml]; + xmlFree(statusMsgXml); + } + else { + statusMsg = @"Server Error"; + } + self.statusMessage = statusMsg; + + node = node->children; + + while (node != NULL) { + //NSLog(@"node: %s", node->name); + if (!xmlStrcmp(node->name, (xmlChar*)TAG_APP)) { + xmlNodePtr appInfoNode = node->xmlChildrenNode; + NSString* appName; + NSString* appId; + BOOL appIsRunning = NO; + while (appInfoNode != NULL) { + if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) { + xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1); + appName = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding]; + xmlFree(nodeVal); + } else if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_ID)) { + xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1); + appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding]; + xmlFree(nodeVal); + } else if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_IS_RUNNING)) { + 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); +} + +- (NSArray*) getAppList { + return _appList; +} + +- (BOOL) isStatusOk { + return self.statusCode == 200; +} + +@end diff --git a/Limelight/Network/DiscoveryManager.m b/Limelight/Network/DiscoveryManager.m index a58aebef..d2c7e4fa 100644 --- a/Limelight/Network/DiscoveryManager.m +++ b/Limelight/Network/DiscoveryManager.m @@ -12,6 +12,7 @@ #import "Utils.h" #import "DataManager.h" #import "DiscoveryWorker.h" +#import "ServerInfoResponse.h" @implementation DiscoveryManager { NSMutableArray* _hostQueue; @@ -39,7 +40,8 @@ - (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *))callback { HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; - HttpResponse* serverInfoResponse = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; + ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init]; + [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest]]]; Host* host = nil; if ([serverInfoResponse isStatusOk]) { diff --git a/Limelight/Network/DiscoveryWorker.m b/Limelight/Network/DiscoveryWorker.m index dce456c4..9aeb0570 100644 --- a/Limelight/Network/DiscoveryWorker.m +++ b/Limelight/Network/DiscoveryWorker.m @@ -9,6 +9,8 @@ #import "DiscoveryWorker.h" #import "Utils.h" #import "HttpManager.h" +#import "ServerInfoResponse.h" +#import "HttpRequest.h" @implementation DiscoveryWorker { Host* _host; @@ -43,7 +45,9 @@ 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]; - HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; + + ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; + [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]]; if ([serverInfoResp isStatusOk]) { [serverInfoResp populateHost:_host]; _host.address = _host.localAddress; @@ -52,7 +56,8 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds } if (!self.cancelled && !receivedResponse && _host.externalAddress != nil) { HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.externalAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; - HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; + ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc]init]; + [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]]; if ([serverInfoResp isStatusOk]) { [serverInfoResp populateHost:_host]; _host.address = _host.externalAddress; @@ -62,7 +67,8 @@ 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]; - HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; + ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; + [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]]; if ([serverInfoResp isStatusOk]) { [serverInfoResp populateHost:_host]; receivedResponse = YES; @@ -70,7 +76,7 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds } _host.online = receivedResponse; if (receivedResponse) { - NSLog(@"Received response from: %@\n{\n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n}", _host.name, _host.address, _host.localAddress, _host.externalAddress, _host.uuid, _host.mac, _host.pairState, _host.online); + NSLog(@"Received response from: %@\n{\n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n}", _host.name, _host.address, _host.localAddress, _host.externalAddress, _host.uuid, _host.mac, _host.pairState, _host.online); } else { // If the host is not online, we do not know the pairstate _host.pairState = PairStateUnknown; diff --git a/Limelight/Network/HttpManager.h b/Limelight/Network/HttpManager.h index 77f7bb8e..c7cba953 100644 --- a/Limelight/Network/HttpManager.h +++ b/Limelight/Network/HttpManager.h @@ -9,6 +9,7 @@ #import #import "Host.h" #import "HttpResponse.h" +#import "HttpRequest.h" @interface HttpManager : NSObject @@ -25,8 +26,8 @@ - (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId; - (NSURLRequest*) newQuitAppRequest; - (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId; -- (HttpResponse*) executeRequestSynchronously:(NSURLRequest*)request; -- (void) executeRequest:(NSURLRequest*)request; +- (void) executeRequestSynchronously:(HttpRequest*)request; +- (void) executeRequest:(HttpRequest*)request; @end diff --git a/Limelight/Network/HttpManager.m b/Limelight/Network/HttpManager.m index df72d5d4..a3d1a9b7 100644 --- a/Limelight/Network/HttpManager.m +++ b/Limelight/Network/HttpManager.m @@ -7,6 +7,7 @@ // #import "HttpManager.h" +#import "HttpRequest.h" #import "CryptoManager.h" #import "App.h" @@ -46,18 +47,20 @@ static const NSString* PORT = @"47984"; return self; } -- (HttpResponse*) executeRequestSynchronously:(NSURLRequest*)request { +- (void) executeRequestSynchronously:(HttpRequest*)request { NSLog(@"Making Request: %@", request); [_respData setLength:0]; dispatch_sync(dispatch_get_main_queue(), ^{ - [NSURLConnection connectionWithRequest:request delegate:self]; + [NSURLConnection connectionWithRequest:request.request delegate:self]; }); dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER); - return [HttpResponse responseWithData:_requestResp]; + if (request.response) { + [request.response populateWithData:_requestResp]; + } } -- (void) executeRequest:(NSURLRequest*)request { - [NSURLConnection connectionWithRequest:request delegate:self]; +- (void) executeRequest:(HttpRequest*)request { + [NSURLConnection connectionWithRequest:request.request delegate:self]; } - (NSURLRequest*) createRequestFromString:(NSString*) urlString enableTimeout:(BOOL)normalTimeout { diff --git a/Limelight/Network/HttpRequest.h b/Limelight/Network/HttpRequest.h new file mode 100644 index 00000000..6cb71583 --- /dev/null +++ b/Limelight/Network/HttpRequest.h @@ -0,0 +1,20 @@ +// +// HttpRequest.h +// Limelight +// +// Created by Diego Waxemberg on 2/1/15. +// Copyright (c) 2015 Limelight Stream. All rights reserved. +// + +#import +#import "HttpResponse.h" + +@interface HttpRequest : NSObject + +@property (nonatomic) id response; +@property (nonatomic) NSURLRequest* request; + ++ (instancetype) requestForResponse:(id)response withUrlRequest:(NSURLRequest*)req; ++ (instancetype) requestWithUrlRequest:(NSURLRequest*)req; + +@end diff --git a/Limelight/Network/HttpRequest.m b/Limelight/Network/HttpRequest.m new file mode 100644 index 00000000..e07954b7 --- /dev/null +++ b/Limelight/Network/HttpRequest.m @@ -0,0 +1,28 @@ +// +// HttpRequest.m +// Limelight +// +// Created by Diego Waxemberg on 2/1/15. +// Copyright (c) 2015 Limelight Stream. All rights reserved. +// + +#import "HttpRequest.h" +#import "HttpResponse.h" +#import "HttpManager.h" + +@implementation HttpRequest + ++ (HttpRequest*) requestForResponse:(id)response withUrlRequest:(NSURLRequest*)req { + HttpRequest* request = [[HttpRequest alloc] init]; + request.request = req; + request.response = response; + return request; +} + ++ (HttpRequest*) requestWithUrlRequest:(NSURLRequest*)req { + HttpRequest* request = [[HttpRequest alloc] init]; + request.request = req; + return request; +} + +@end diff --git a/Limelight/Network/HttpResponse.h b/Limelight/Network/HttpResponse.h index accef07a..d5a2612d 100644 --- a/Limelight/Network/HttpResponse.h +++ b/Limelight/Network/HttpResponse.h @@ -9,18 +9,25 @@ #import #import "Host.h" -@interface HttpResponse : NSObject +static NSString* TAG_STATUS_CODE = @"status_code"; +static NSString* TAG_STATUS_MESSAGE = @"status_message"; + +@protocol Response + +- (void) populateWithData:(NSData*)data; @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; +@property (nonatomic) NSData* data; + +@end + +@interface HttpResponse : NSObject + +- (void) populateWithData:(NSData*)data; +- (void) parseData; +- (NSString*) getStringTag:(NSString*)tag; +- (BOOL) getIntTag:(NSString *)tag value:(NSInteger*)value; +- (BOOL) isStatusOk; @end diff --git a/Limelight/Network/HttpResponse.m b/Limelight/Network/HttpResponse.m index 11f4031b..f2d2a1c3 100644 --- a/Limelight/Network/HttpResponse.m +++ b/Limelight/Network/HttpResponse.m @@ -10,86 +10,22 @@ #import "App.h" #import -@implementation HttpResponse +@implementation HttpResponse { + NSMutableDictionary* _elements; +} +@synthesize data, statusCode, statusMessage; -+ (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; +- (void) populateWithData:(NSData*)xml { + self.data = xml; + [self parseData]; } -- (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; +- (NSString*) getStringTag:(NSString*)tag { + return [_elements objectForKey:tag]; } -- (BOOL)parseIntTag:(NSString *)tag value:(NSInteger*)value { - NSString* stringVal = [self parseStringTag:tag]; +- (BOOL) getIntTag:(NSString *)tag value:(NSInteger*)value { + NSString* stringVal = [self getStringTag:tag]; if (stringVal != nil) { *value = [stringVal integerValue]; return true; @@ -102,121 +38,57 @@ return self.statusCode == 200; } -- (BOOL) populateHost:(Host*)host { - xmlDocPtr docPtr = xmlParseMemory([self.responseData bytes], (int)[self.responseData length]); - +- (void) parseData { + _elements = [[NSMutableDictionary alloc] init]; + xmlDocPtr docPtr = xmlParseMemory([self.data bytes], (int)[self.data length]); if (docPtr == NULL) { NSLog(@"ERROR: An error occured trying to parse xml."); - return false; + return; } xmlNodePtr node = xmlDocGetRootElement(docPtr); - - // Check root status_code - if (![self isStatusOk]) { - NSLog(@"ERROR: Request returned with failure status"); + if (node == NULL) { + NSLog(@"ERROR: No root XML element."); xmlFreeDoc(docPtr); - return false; + return; + } + + xmlChar* statusStr = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_CODE UTF8String]); + if (statusStr != NULL) { + int status = [[NSString stringWithUTF8String:(const char*)statusStr] intValue]; + xmlFree(statusStr); + self.statusCode = status; } - // Skip the root node + xmlChar* statusMsgXml = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_MESSAGE UTF8String]); + NSString* statusMsg; + if (statusMsgXml != NULL) { + statusMsg = [NSString stringWithUTF8String:(const char*)statusMsgXml]; + xmlFree(statusMsgXml); + } + else { + statusMsg = @"Server Error"; + } + self.statusMessage = statusMsg; + 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); - } + xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1); - 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]; + NSString* value; + if (nodeVal == NULL) { + value = @""; + } else { + value = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding]; } + NSString* key = [[NSString alloc] initWithCString:(const char*)node->name encoding:NSUTF8StringEncoding]; + [_elements setObject:value forKey:key]; + xmlFree(nodeVal); node = node->next; } xmlFreeDoc(docPtr); - - return appList; } - @end diff --git a/Limelight/Network/PairManager.m b/Limelight/Network/PairManager.m index 84e17b88..b462486c 100644 --- a/Limelight/Network/PairManager.m +++ b/Limelight/Network/PairManager.m @@ -10,6 +10,8 @@ #import "CryptoManager.h" #import "Utils.h" #import "HttpResponse.h" +#import "HttpRequest.h" +#import "ServerInfoResponse.h" #include @@ -28,15 +30,16 @@ } - (void) main { - HttpResponse* serverInfo = [_httpManager executeRequestSynchronously:[_httpManager newServerInfoRequest]]; - if (serverInfo == nil) { + ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; + [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[_httpManager newServerInfoRequest]]]; + if (serverInfoResp == nil) { [_callback pairFailed:@"Unable to connect to PC"]; return; } - if ([serverInfo isStatusOk]) { - if (![[serverInfo parseStringTag:@"currentgame"] isEqual:@"0"]) { + if ([serverInfoResp isStatusOk]) { + if (![[serverInfoResp getStringTag:@"currentgame"] isEqual:@"0"]) { [_callback pairFailed:@"You must stop streaming before attempting to pair."]; - } else if (![[serverInfo parseStringTag:@"PairStatus"] isEqual:@"1"]) { + } else if (![[serverInfoResp getStringTag:@"PairStatus"] isEqual:@"1"]) { [self initiatePair]; } else { [_callback alreadyPaired]; @@ -50,18 +53,19 @@ NSLog(@"PIN: %@, saltedPIN: %@", PIN, salt); [_callback showPIN:PIN]; - HttpResponse* pairResp = [_httpManager executeRequestSynchronously:[_httpManager newPairRequest:salt]]; + HttpResponse* pairResp = [[HttpResponse alloc] init]; + [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:pairResp withUrlRequest:[_httpManager newPairRequest:salt]]]; if (![self verifyResponseStatus:pairResp]) { return; } NSInteger pairedStatus; - if (![pairResp parseIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { - [_httpManager executeRequest:[_httpManager newUnpairRequest]]; + if (![pairResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { + [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Pairing was declined by the target."]; return; } - NSString* plainCert = [pairResp parseStringTag:@"plaincert"]; + NSString* plainCert = [pairResp getStringTag:@"plaincert"]; CryptoManager* cryptoMan = [[CryptoManager alloc] init]; NSData* aesKey = [cryptoMan createAESKeyFromSalt:salt]; @@ -69,17 +73,18 @@ NSData* randomChallenge = [Utils randomBytes:16]; NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey]; - HttpResponse* challengeResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRequest:encryptedChallenge]]; + HttpResponse* challengeResp = [[HttpResponse alloc] init]; + [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:challengeResp withUrlRequest:[_httpManager newChallengeRequest:encryptedChallenge]]]; if (![self verifyResponseStatus:challengeResp]) { return; } - if (![challengeResp parseIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { - [_httpManager executeRequest:[_httpManager newUnpairRequest]]; + if (![challengeResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { + [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Pairing stage #2 failed"]; return; } - NSData* encServerChallengeResp = [Utils hexToBytes:[challengeResp parseStringTag:@"challengeresponse"]]; + NSData* encServerChallengeResp = [Utils hexToBytes:[challengeResp getStringTag:@"challengeresponse"]]; NSData* decServerChallengeResp = [cryptoMan aesDecrypt:encServerChallengeResp withKey:aesKey]; NSData* serverResponse = [decServerChallengeResp subdataWithRange:NSMakeRange(0, 20)]; @@ -89,50 +94,53 @@ NSData* challengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_cert]] with:clientSecret]]; NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey]; - HttpResponse* secretResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRespRequest:challengeRespEncrypted]]; + HttpResponse* secretResp = [[HttpResponse alloc] init]; + [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:secretResp withUrlRequest:[_httpManager newChallengeRespRequest:challengeRespEncrypted]]]; if (![self verifyResponseStatus:secretResp]) { return; } - if (![secretResp parseIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { - [_httpManager executeRequest:[_httpManager newUnpairRequest]]; + if (![secretResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { + [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Pairing stage #3 failed"]; return; } - NSData* serverSecretResp = [Utils hexToBytes:[secretResp parseStringTag:@"pairingsecret"]]; + NSData* serverSecretResp = [Utils hexToBytes:[secretResp getStringTag:@"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 executeRequest:[_httpManager newUnpairRequest]]; + [_httpManager executeRequest:[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:[_httpManager newUnpairRequest]]; + [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Incorrect PIN"]; return; } NSData* clientPairingSecret = [self concatData:clientSecret with:[cryptoMan signData:clientSecret withKey:[CryptoManager readKeyFromFile]]]; - HttpResponse* clientSecretResp = [_httpManager executeRequestSynchronously:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]]; + HttpResponse* clientSecretResp = [[HttpResponse alloc] init]; + [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:clientSecretResp withUrlRequest:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]]]; if (![self verifyResponseStatus:clientSecretResp]) { return; } - if (![clientSecretResp parseIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { - [_httpManager executeRequest:[_httpManager newUnpairRequest]]; + if (![clientSecretResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { + [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Pairing stage #4 failed"]; return; } - HttpResponse* clientPairChallengeResp = [_httpManager executeRequestSynchronously:[_httpManager newPairChallenge]]; + HttpResponse* clientPairChallengeResp = [[HttpResponse alloc] init]; + [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:clientPairChallengeResp withUrlRequest:[_httpManager newPairChallenge]]]; if (![self verifyResponseStatus:clientPairChallengeResp]) { return; } - if (![clientPairChallengeResp parseIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { - [_httpManager executeRequest:[_httpManager newUnpairRequest]]; + if (![clientPairChallengeResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { + [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Pairing stage #5 failed"]; return; } @@ -141,11 +149,11 @@ - (BOOL) verifyResponseStatus:(HttpResponse*)resp { if (resp == nil) { - [_httpManager executeRequest:[_httpManager newUnpairRequest]]; + [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:@"Network error occured."]; return false; } else if (![resp isStatusOk]) { - [_httpManager executeRequest:[_httpManager newUnpairRequest]]; + [_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_callback pairFailed:resp.statusMessage]; return false; } else { diff --git a/Limelight/Network/ServerInfoResponse.h b/Limelight/Network/ServerInfoResponse.h new file mode 100644 index 00000000..bae71d0e --- /dev/null +++ b/Limelight/Network/ServerInfoResponse.h @@ -0,0 +1,16 @@ +// +// ServerInfoResponse.h +// Limelight +// +// Created by Diego Waxemberg on 2/1/15. +// Copyright (c) 2015 Limelight Stream. All rights reserved. +// + +#import "HttpResponse.h" + +@interface ServerInfoResponse : HttpResponse + +- (void) populateWithData:(NSData *)data; +- (void) populateHost:(Host*)host; + +@end diff --git a/Limelight/Network/ServerInfoResponse.m b/Limelight/Network/ServerInfoResponse.m new file mode 100644 index 00000000..56cfc486 --- /dev/null +++ b/Limelight/Network/ServerInfoResponse.m @@ -0,0 +1,55 @@ +// +// ServerInfoResponse.m +// Limelight +// +// Created by Diego Waxemberg on 2/1/15. +// Copyright (c) 2015 Limelight Stream. All rights reserved. +// + +#import "ServerInfoResponse.h" +#import + +@implementation ServerInfoResponse +@synthesize data, statusCode, statusMessage; + +static NSString* TAG_HOSTNAME = @"hostname"; +static NSString* TAG_EXTERNAL_IP = @"ExternalIP"; +static NSString* TAG_LOCAL_IP = @"LocalIP"; +static NSString* TAG_UNIQUE_ID = @"uniqueid"; +static NSString* TAG_MAC_ADDRESS = @"mac"; +static NSString* TAG_PAIR_STATUS = @"PairStatus"; + +- (void) populateWithData:(NSData *)xml { + self.data = xml; + [super parseData]; +} + +- (void) populateHost:(Host*)host { + NSString* hostname = [self getStringTag:TAG_HOSTNAME]; + NSString* externalIp = [self getStringTag:TAG_EXTERNAL_IP]; + NSString* localIp = [self getStringTag:TAG_LOCAL_IP]; + NSString* uniqueId = [self getStringTag:TAG_UNIQUE_ID]; + NSString* macAddress = [self getStringTag:TAG_MAC_ADDRESS]; + NSString* pairStatus = [self getStringTag:TAG_PAIR_STATUS]; + + if (hostname) { + host.name = hostname; + } + if (externalIp) { + host.externalAddress = externalIp; + } + if (localIp) { + host.localAddress = localIp; + } + if (uniqueId) { + host.uuid = uniqueId; + } + if (macAddress) { + host.mac = macAddress; + } + if (pairStatus) { + host.pairState = [pairStatus isEqualToString:@"1"] ? PairStatePaired : PairStateUnpaired; + } +} + +@end diff --git a/Limelight/Stream/StreamManager.m b/Limelight/Stream/StreamManager.m index 94e48861..dc77bce9 100644 --- a/Limelight/Stream/StreamManager.m +++ b/Limelight/Stream/StreamManager.m @@ -12,6 +12,9 @@ #import "Utils.h" #import "OnScreenControls.h" #import "StreamView.h" +#import "ServerInfoResponse.h" +#import "HttpResponse.h" +#import "HttpRequest.h" @implementation StreamManager { StreamConfiguration* _config; @@ -41,10 +44,11 @@ deviceName:@"roth" cert:cert]; - HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; - NSString* currentGame = [serverInfoResp parseStringTag:@"currentgame"]; - NSString* pairStatus = [serverInfoResp parseStringTag:@"PairStatus"]; - NSString* currentClient = [serverInfoResp parseStringTag:@"CurrentClient"]; + ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; + [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]]; + NSString* currentGame = [serverInfoResp getStringTag:@"currentgame"]; + NSString* pairStatus = [serverInfoResp getStringTag:@"PairStatus"]; + NSString* currentClient = [serverInfoResp getStringTag:@"CurrentClient"]; if (![serverInfoResp isStatusOk] || currentGame == NULL || pairStatus == NULL) { [_callbacks launchFailed:@"Failed to connect to PC"]; return; @@ -102,14 +106,15 @@ } - (BOOL) launchApp:(HttpManager*)hMan { - HttpResponse* launchResp = [hMan executeRequestSynchronously: + HttpResponse* launchResp = [[HttpResponse alloc] init]; + [hMan executeRequestSynchronously:[HttpRequest requestForResponse:launchResp withUrlRequest: [hMan newLaunchRequest:_config.appID width:_config.width height:_config.height refreshRate:_config.frameRate rikey:[Utils bytesToHex:_config.riKey] - rikeyid:_config.riKeyId]]; - NSString *gameSession = [launchResp parseStringTag:@"gamesession"]; + rikeyid:_config.riKeyId]]]; + NSString *gameSession = [launchResp getStringTag:@"gamesession"]; if (launchResp == NULL || ![launchResp isStatusOk]) { [_callbacks launchFailed:@"Failed to launch app"]; NSLog(@"Failed Launch Response: %@", launchResp.statusMessage); @@ -124,10 +129,11 @@ } - (BOOL) resumeApp:(HttpManager*)hMan { - HttpResponse* resumeResp = [hMan executeRequestSynchronously: + HttpResponse* resumeResp = [[HttpResponse alloc] init]; + [hMan executeRequestSynchronously:[HttpRequest requestForResponse:resumeResp withUrlRequest: [hMan newResumeRequestWithRiKey:[Utils bytesToHex:_config.riKey] - riKeyId:_config.riKeyId]]; - NSString* resume = [resumeResp parseStringTag:@"resume"]; + riKeyId:_config.riKeyId]]]; + NSString* resume = [resumeResp getStringTag:@"resume"]; if (resumeResp == NULL || ![resumeResp isStatusOk]) { [_callbacks launchFailed:@"Failed to resume app"]; NSLog(@"Failed Resume Response: %@", resumeResp.statusMessage); diff --git a/Limelight/ViewControllers/MainFrameViewController.m b/Limelight/ViewControllers/MainFrameViewController.m index 4952c5b5..60377642 100644 --- a/Limelight/ViewControllers/MainFrameViewController.m +++ b/Limelight/ViewControllers/MainFrameViewController.m @@ -19,6 +19,8 @@ #import "DataManager.h" #import "Settings.h" #import "WakeOnLanManager.h" +#import "AppListResponse.h" +#import "ServerInfoResponse.h" @implementation MainFrameViewController { NSOperationQueue* _opQueue; @@ -72,7 +74,9 @@ static StreamConfiguration* streamConfig; [self.navigationController.navigationBar setNeedsLayout]; }); HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; - HttpResponse* appListResp = [hMan executeRequestSynchronously:[hMan newAppListRequest]]; + + AppListResponse* appListResp = [[AppListResponse alloc] init]; + [hMan executeRequestSynchronously:[HttpRequest requestForResponse:appListResp withUrlRequest:[hMan newAppListRequest]]]; if (appListResp == nil || ![appListResp isStatusOk]) { NSLog(@"Failed to get applist: %@", appListResp.statusMessage); } else { @@ -115,11 +119,13 @@ static StreamConfiguration* streamConfig; _selectedHost = host; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; - HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; + ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; + [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]]; if (serverInfoResp == nil || ![serverInfoResp isStatusOk]) { NSLog(@"Failed to get server info: %@", serverInfoResp.statusMessage); } else { - if ([[serverInfoResp parseStringTag:@"PairStatus"] isEqualToString:@"1"]) { + NSLog(@"server info pair status: %@", [serverInfoResp getStringTag:@"PairStatus"]); + if ([[serverInfoResp getStringTag:@"PairStatus"] isEqualToString:@"1"]) { NSLog(@"Already Paired"); [self alreadyPaired]; } else { @@ -140,7 +146,7 @@ static StreamConfiguration* streamConfig; [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 executeRequestSynchronously:[hMan newUnpairRequest]]; + [hMan executeRequest:[HttpRequest requestWithUrlRequest:[hMan newUnpairRequest]]]; }); }]]; } else { @@ -250,7 +256,7 @@ static StreamConfiguration* streamConfig; NSLog(@"Quitting application: %@", currentApp.appName); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; - [hMan executeRequestSynchronously:[hMan newQuitAppRequest]]; + [hMan executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[hMan newQuitAppRequest]]]; // TODO: handle failure to quit app currentApp.isRunning = NO;