diff --git a/Limelight.xcodeproj/project.pbxproj b/Limelight.xcodeproj/project.pbxproj index 809ca62..820faf7 100644 --- a/Limelight.xcodeproj/project.pbxproj +++ b/Limelight.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678F91A55FFAD00377732 /* DiscoveryManager.m */; }; FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */; }; FB4679011A57048000377732 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB4679001A57048000377732 /* CoreFoundation.framework */; }; + FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */ = {isa = PBXBuildFile; fileRef = FB6549551A57907E001C8F39 /* DiscoveryWorker.m */; }; FB7E794419C8B71B00A15F68 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB7E794319C8B71B00A15F68 /* libiconv.dylib */; }; FB89462819F646E200339C8A /* CryptoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB89460619F646E200339C8A /* CryptoManager.m */; }; FB89462919F646E200339C8A /* mkcert.c in Sources */ = {isa = PBXBuildFile; fileRef = FB89460719F646E200339C8A /* mkcert.c */; }; @@ -117,6 +118,8 @@ FB4678FD1A565DAC00377732 /* WakeOnLanManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WakeOnLanManager.h; sourceTree = ""; }; FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WakeOnLanManager.m; sourceTree = ""; }; FB4679001A57048000377732 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + FB6549541A57907E001C8F39 /* DiscoveryWorker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscoveryWorker.h; sourceTree = ""; }; + FB6549551A57907E001C8F39 /* DiscoveryWorker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DiscoveryWorker.m; sourceTree = ""; }; FB7E794319C8B71B00A15F68 /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = usr/lib/libiconv.dylib; sourceTree = SDKROOT; }; FB89460519F646E200339C8A /* CryptoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoManager.h; sourceTree = ""; }; FB89460619F646E200339C8A /* CryptoManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CryptoManager.m; sourceTree = ""; }; @@ -420,10 +423,12 @@ FB89461419F646E200339C8A /* PairManager.m */, FBD3494119FC9C04002D2A60 /* AppManager.h */, FBD3494219FC9C04002D2A60 /* AppManager.m */, - FB4678F81A55FFAD00377732 /* DiscoveryManager.h */, - FB4678F91A55FFAD00377732 /* DiscoveryManager.m */, FB4678FD1A565DAC00377732 /* WakeOnLanManager.h */, FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */, + FB4678F81A55FFAD00377732 /* DiscoveryManager.h */, + FB4678F91A55FFAD00377732 /* DiscoveryManager.m */, + FB6549541A57907E001C8F39 /* DiscoveryWorker.h */, + FB6549551A57907E001C8F39 /* DiscoveryWorker.m */, ); path = Network; sourceTree = ""; @@ -787,6 +792,7 @@ FB4678ED1A50C40900377732 /* OnScreenControls.m in Sources */, FB290D0019B2C406004C83CF /* main.m in Sources */, FBD3494319FC9C04002D2A60 /* AppManager.m in Sources */, + FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */, FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */, FBD349621A0089F6002D2A60 /* DataManager.m in Sources */, FB89463119F646E200339C8A /* StreamManager.m in Sources */, diff --git a/Limelight/Network/DiscoveryManager.h b/Limelight/Network/DiscoveryManager.h index 4252420..8d330a7 100644 --- a/Limelight/Network/DiscoveryManager.h +++ b/Limelight/Network/DiscoveryManager.h @@ -16,12 +16,12 @@ @end -@interface DiscoveryManager : NSOperation +@interface DiscoveryManager : NSObject - (id) initWithHosts:(NSArray*)hosts andCallback:(id) callback; - (void) startDiscovery; - (void) stopDiscovery; -- (void) addHostToDiscovery:(Host*)host; +- (BOOL) addHostToDiscovery:(Host*)host; - (void) removeHostFromDiscovery:(Host*)host; - (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(Host*))callback; diff --git a/Limelight/Network/DiscoveryManager.m b/Limelight/Network/DiscoveryManager.m index 9bff988..9694b86 100644 --- a/Limelight/Network/DiscoveryManager.m +++ b/Limelight/Network/DiscoveryManager.m @@ -11,6 +11,7 @@ #import "HttpManager.h" #import "Utils.h" #import "DataManager.h" +#import "DiscoveryWorker.h" @implementation DiscoveryManager { NSMutableArray* _hostQueue; @@ -27,7 +28,6 @@ self = [super init]; _hostQueue = [NSMutableArray arrayWithArray:hosts]; _callback = callback; - _discoveredHosts = [[NSMutableArray alloc] init]; _opQueue = [[NSOperationQueue alloc] init]; _mdnsMan = [[MDNSManager alloc] initWithCallback:self]; [CryptoManager generateKeyPairUsingSSl]; @@ -43,111 +43,77 @@ Host* host = nil; if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) { - host = [[[DataManager alloc] init] createHost]; + DataManager* dataMan = [[DataManager alloc] init]; + host = [dataMan createHost]; host.address = hostAddress; - [self updateHost:host withServerInfo:serverInfoData]; - [self addHostToDiscovery:host]; + [DiscoveryWorker updateHost:host withServerInfo:serverInfoData]; + if (![self addHostToDiscovery:host]) { + [dataMan removeHost:host]; + } } callback(host); } -- (void) discoverHost:(Host*)host { - if (!shouldDiscover) return; - BOOL receivedResponse = NO; - if (host.localAddress != nil) { - HttpManager* hMan = [[HttpManager alloc] initWithHost:host.localAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; - NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; - if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) { - [self updateHost:host withServerInfo:serverInfoData]; - host.address = host.localAddress; - receivedResponse = YES; - } - } - if (shouldDiscover && !receivedResponse && host.externalAddress != nil) { - HttpManager* hMan = [[HttpManager alloc] initWithHost:host.externalAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; - NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; - if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) { - [self updateHost:host withServerInfo:serverInfoData]; - host.address = host.externalAddress; - receivedResponse = YES; - } - } - - if (shouldDiscover && !receivedResponse && host.address != nil) { - HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; - NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; - if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) { - [self updateHost:host withServerInfo:serverInfoData]; - receivedResponse = YES; - } - } - 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); - } - // If the host has already been discovered, we update the reference - BOOL hostInList = NO; - for (int i = 0; i < _discoveredHosts.count; i++) { - Host* discoveredHost = [_discoveredHosts objectAtIndex:i]; - if ([discoveredHost.uuid isEqualToString:host.uuid]) { - [_discoveredHosts removeObject:discoveredHost]; - [_discoveredHosts insertObject:host atIndex:i]; - hostInList = YES; - } - } - if (!hostInList) { - [_discoveredHosts addObject:host]; - } -} - -- (void) updateHost:(Host*)host withServerInfo:(NSData*)serverInfoData { - host.name = [HttpManager getStringFromXML:serverInfoData tag:@"hostname"]; - host.externalAddress = [HttpManager getStringFromXML:serverInfoData tag:@"ExternalIP"]; - host.localAddress = [HttpManager getStringFromXML:serverInfoData tag:@"LocalIP"]; - host.uuid = [HttpManager getStringFromXML:serverInfoData tag:@"uniqueid"]; - host.mac = [HttpManager getStringFromXML:serverInfoData tag:@"mac"]; - NSString* pairState = [HttpManager getStringFromXML:serverInfoData tag:@"PairStatus"]; - if ([pairState isEqualToString:@"1"]) { - host.pairState = PairStatePaired; - } else { - host.pairState = PairStateUnpaired; - } -} - - (void) startDiscovery { NSLog(@"Starting discovery"); shouldDiscover = YES; [_mdnsMan searchForHosts]; - [_opQueue addOperation:self]; + for (Host* host in _hostQueue) { + [_opQueue addOperation:[self createWorkerForHost:host]]; + } } - (void) stopDiscovery { + NSLog(@"Stopping discovery"); + shouldDiscover = NO; + [_mdnsMan stopSearching]; + [_opQueue cancelAllOperations]; +} shouldDiscover = NO; [_mdnsMan stopSearching]; } -- (void) addHostToDiscovery:(Host *)host { - [_hostQueue addObject:host]; +- (BOOL) addHostToDiscovery:(Host *)host { + if (![self isHostInDiscovery:host]) { + [_hostQueue addObject:host]; + if (shouldDiscover) { + [_opQueue addOperation:[self createWorkerForHost:host]]; + } + return YES; + } + return NO; } - (void) removeHostFromDiscovery:(Host *)host { + for (DiscoveryWorker* worker in [_opQueue operations]) { + if ([worker getHost] == host) { + [worker cancel]; + } + } [_hostQueue removeObject:host]; } - (void)updateHosts:(NSArray *)hosts { - [_hostQueue addObjectsFromArray:hosts]; -} - -- (void)main { - while (shouldDiscover && !self.isCancelled) { - NSLog(@"Running discovery loop"); - [_discoveredHosts removeAllObjects]; - for (Host* host in _hostQueue) { - [self discoverHost:host]; + for (Host* host in hosts) { + if ([self addHostToDiscovery:host]) { + [_callback updateAllHosts:_hostQueue]; } - [_callback updateAllHosts:_discoveredHosts]; - [NSThread sleepForTimeInterval:2.0f]; } } +- (BOOL) isHostInDiscovery:(Host*)host { + for (int i = 0; i < _hostQueue.count; i++) { + Host* discoveredHost = [_hostQueue objectAtIndex:i]; + if ([discoveredHost.uuid isEqualToString:host.uuid]) { + return YES; + } + } + return NO; +} + +- (NSOperation*) createWorkerForHost:(Host*)host { + DiscoveryWorker* worker = [[DiscoveryWorker alloc] initWithHost:host uniqueId:_uniqueId cert:_cert]; + return worker; +} + @end diff --git a/Limelight/Network/DiscoveryWorker.h b/Limelight/Network/DiscoveryWorker.h new file mode 100644 index 0000000..5c4ea82 --- /dev/null +++ b/Limelight/Network/DiscoveryWorker.h @@ -0,0 +1,19 @@ +// +// DiscoveryWorker.h +// Limelight +// +// Created by Diego Waxemberg on 1/2/15. +// Copyright (c) 2015 Limelight Stream. All rights reserved. +// + +#import +#import "Host.h" + +@interface DiscoveryWorker : NSOperation + +- (id) initWithHost:(Host*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert; +- (Host*) getHost; + ++ (void) updateHost:(Host*)host withServerInfo:(NSData*)serverInfoData; + +@end diff --git a/Limelight/Network/DiscoveryWorker.m b/Limelight/Network/DiscoveryWorker.m new file mode 100644 index 0000000..cd4b2f1 --- /dev/null +++ b/Limelight/Network/DiscoveryWorker.m @@ -0,0 +1,90 @@ +// +// DiscoveryWorker.m +// Limelight +// +// Created by Diego Waxemberg on 1/2/15. +// Copyright (c) 2015 Limelight Stream. All rights reserved. +// + +#import "DiscoveryWorker.h" +#import "Utils.h" +#import "HttpManager.h" + +@implementation DiscoveryWorker { + Host* _host; + NSString* _uniqueId; + NSData* _cert; +} + +static const float POLL_RATE = 2.0f; // Poll every 2 seconds + +- (id) initWithHost:(Host*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert { + self = [super init]; + _host = host; + _uniqueId = uniqueId; + _cert = cert; + return self; +} + +- (Host*) getHost { + return _host; +} + +- (void)main { + while (!self.cancelled) { + BOOL receivedResponse = NO; + if (!self.cancelled && _host.localAddress != nil) { + HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.localAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; + NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; + if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) { + [DiscoveryWorker updateHost:_host withServerInfo:serverInfoData]; + _host.address = _host.localAddress; + receivedResponse = YES; + } + } + if (!self.cancelled && !receivedResponse && _host.externalAddress != nil) { + HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.externalAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; + NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; + if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) { + [DiscoveryWorker updateHost:_host withServerInfo:serverInfoData]; + _host.address = _host.externalAddress; + receivedResponse = YES; + } + } + + if (!self.cancelled && !receivedResponse && _host.address != nil) { + HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; + NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; + if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) { + [DiscoveryWorker updateHost:_host withServerInfo:serverInfoData]; + receivedResponse = YES; + } + } + _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); + } else { + // If the host is not online, we do not know the pairstate + _host.pairState = PairStateUnknown; + } + if (!self.cancelled) { + [NSThread sleepForTimeInterval:POLL_RATE]; + } + } +} + ++ (void) updateHost:(Host*)host withServerInfo:(NSData*)serverInfoData { + host.name = [HttpManager getStringFromXML:serverInfoData tag:@"hostname"]; + host.externalAddress = [HttpManager getStringFromXML:serverInfoData tag:@"ExternalIP"]; + host.localAddress = [HttpManager getStringFromXML:serverInfoData tag:@"LocalIP"]; + host.uuid = [HttpManager getStringFromXML:serverInfoData tag:@"uniqueid"]; + host.mac = [HttpManager getStringFromXML:serverInfoData tag:@"mac"]; + NSString* pairState = [HttpManager getStringFromXML:serverInfoData tag:@"PairStatus"]; + if ([pairState isEqualToString:@"1"]) { + host.pairState = PairStatePaired; + } else { + host.pairState = PairStateUnpaired; + } +} + +@end