mirror of
https://github.com/moonlight-stream/moonlight-ios.git
synced 2026-02-16 10:31:02 +00:00
Refactored http communications to be more abstract and OOP
This commit is contained in:
@@ -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 = "<group>"; };
|
||||
FB9AFD301A7D867C00872C98 /* AppAssetRetriever.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetRetriever.h; sourceTree = "<group>"; };
|
||||
FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetRetriever.m; sourceTree = "<group>"; };
|
||||
FB9AFD351A7E02DB00872C98 /* HttpRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HttpRequest.h; sourceTree = "<group>"; };
|
||||
FB9AFD361A7E02DB00872C98 /* HttpRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HttpRequest.m; sourceTree = "<group>"; };
|
||||
FB9AFD381A7E05CE00872C98 /* ServerInfoResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServerInfoResponse.h; sourceTree = "<group>"; };
|
||||
FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ServerInfoResponse.m; sourceTree = "<group>"; };
|
||||
FB9AFD3B1A7E111600872C98 /* AppAssetResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetResponse.h; sourceTree = "<group>"; };
|
||||
FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetResponse.m; sourceTree = "<group>"; };
|
||||
FB9AFD3E1A7E127D00872C98 /* AppListResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppListResponse.h; sourceTree = "<group>"; };
|
||||
FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppListResponse.m; sourceTree = "<group>"; };
|
||||
FBD3494119FC9C04002D2A60 /* AppAssetManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetManager.h; sourceTree = "<group>"; };
|
||||
FBD3494219FC9C04002D2A60 /* AppAssetManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetManager.m; sourceTree = "<group>"; };
|
||||
FBD3494E19FF2174002D2A60 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = "<group>"; };
|
||||
@@ -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 = "<group>";
|
||||
@@ -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;
|
||||
|
||||
16
Limelight/Network/AppAssetResponse.h
Normal file
16
Limelight/Network/AppAssetResponse.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// AppAssetResponse.h
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 2/1/15.
|
||||
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HttpResponse.h"
|
||||
|
||||
@interface AppAssetResponse : NSObject <Response>
|
||||
|
||||
|
||||
|
||||
@end
|
||||
25
Limelight/Network/AppAssetResponse.m
Normal file
25
Limelight/Network/AppAssetResponse.m
Normal file
@@ -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
|
||||
@@ -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) {
|
||||
|
||||
17
Limelight/Network/AppListResponse.h
Normal file
17
Limelight/Network/AppListResponse.h
Normal file
@@ -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 <Response>
|
||||
|
||||
- (void)populateWithData:(NSData *)data;
|
||||
- (NSArray*) getAppList;
|
||||
- (BOOL) isStatusOk;
|
||||
|
||||
@end
|
||||
106
Limelight/Network/AppListResponse.m
Normal file
106
Limelight/Network/AppListResponse.m
Normal file
@@ -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 <libxml2/libxml/xmlreader.h>
|
||||
|
||||
@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
|
||||
@@ -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]) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Host.h"
|
||||
#import "HttpResponse.h"
|
||||
#import "HttpRequest.h"
|
||||
|
||||
@interface HttpManager : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
20
Limelight/Network/HttpRequest.h
Normal file
20
Limelight/Network/HttpRequest.h
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// HttpRequest.h
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 2/1/15.
|
||||
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HttpResponse.h"
|
||||
|
||||
@interface HttpRequest : NSObject
|
||||
|
||||
@property (nonatomic) id<Response> response;
|
||||
@property (nonatomic) NSURLRequest* request;
|
||||
|
||||
+ (instancetype) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req;
|
||||
+ (instancetype) requestWithUrlRequest:(NSURLRequest*)req;
|
||||
|
||||
@end
|
||||
28
Limelight/Network/HttpRequest.m
Normal file
28
Limelight/Network/HttpRequest.m
Normal file
@@ -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>)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
|
||||
@@ -9,18 +9,25 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Host.h"
|
||||
|
||||
@interface HttpResponse : NSObject
|
||||
static NSString* TAG_STATUS_CODE = @"status_code";
|
||||
static NSString* TAG_STATUS_MESSAGE = @"status_message";
|
||||
|
||||
@protocol Response <NSObject>
|
||||
|
||||
- (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 <Response>
|
||||
|
||||
- (void) populateWithData:(NSData*)data;
|
||||
- (void) parseData;
|
||||
- (NSString*) getStringTag:(NSString*)tag;
|
||||
- (BOOL) getIntTag:(NSString *)tag value:(NSInteger*)value;
|
||||
- (BOOL) isStatusOk;
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,86 +10,22 @@
|
||||
#import "App.h"
|
||||
#import <libxml2/libxml/xmlreader.h>
|
||||
|
||||
@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
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#import "CryptoManager.h"
|
||||
#import "Utils.h"
|
||||
#import "HttpResponse.h"
|
||||
#import "HttpRequest.h"
|
||||
#import "ServerInfoResponse.h"
|
||||
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
16
Limelight/Network/ServerInfoResponse.h
Normal file
16
Limelight/Network/ServerInfoResponse.h
Normal file
@@ -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 <Response>
|
||||
|
||||
- (void) populateWithData:(NSData *)data;
|
||||
- (void) populateHost:(Host*)host;
|
||||
|
||||
@end
|
||||
55
Limelight/Network/ServerInfoResponse.m
Normal file
55
Limelight/Network/ServerInfoResponse.m
Normal file
@@ -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 <libxml2/libxml/xmlreader.h>
|
||||
|
||||
@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
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user