Refactored http communications to be more abstract and OOP

This commit is contained in:
Diego Waxemberg
2015-02-01 04:26:47 -05:00
parent 75d3f23f0a
commit 879f304a79
19 changed files with 460 additions and 240 deletions
+16
View 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
View 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
+5 -3
View File
@@ -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
View 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
View 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
+3 -1
View File
@@ -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]) {
+10 -4
View File
@@ -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;
+3 -2
View File
@@ -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
+8 -5
View File
@@ -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
View 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
View 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
+17 -10
View File
@@ -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
+45 -173
View File
@@ -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
+35 -27
View File
@@ -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
View 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
View 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