From 815a33de95fccbe5be1814e18c7f89d641754f20 Mon Sep 17 00:00:00 2001 From: David Robles Date: Sun, 22 Mar 2015 16:09:38 -0700 Subject: [PATCH] Allow the option to receive multicast SSDP notifications (not just send) by not supplying a network interface to bind the socket to. Implement [SSDPServiceBrowser _notifyDelegateWithRemovedService] for reporting removed devices. --- Classes/SSDPService.m | 2 +- Classes/SSDPServiceBrowser.h | 17 +++++++------- Classes/SSDPServiceBrowser.m | 44 ++++++++++++++++++++++++++++-------- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/Classes/SSDPService.m b/Classes/SSDPService.m index 80a93d8..4358567 100644 --- a/Classes/SSDPService.m +++ b/Classes/SSDPService.m @@ -30,7 +30,7 @@ - (id)initWithHeaders:(NSDictionary *)headers { self = [super init]; if (self) { _location = [NSURL URLWithString:[headers objectForKey:@"location"]]; - _serviceType = [headers objectForKey:@"st"]; + _serviceType = [headers objectForKey:@"st"] ? [headers objectForKey:@"st"] : [headers objectForKey:@"nt"]; _uniqueServiceName = [headers objectForKey:@"usn"]; _server = [headers objectForKey:@"server"]; } diff --git a/Classes/SSDPServiceBrowser.h b/Classes/SSDPServiceBrowser.h index c6f355c..507accb 100644 --- a/Classes/SSDPServiceBrowser.h +++ b/Classes/SSDPServiceBrowser.h @@ -27,9 +27,9 @@ @class SSDPService; @protocol SSDPServiceBrowserDelegate -- (void) ssdpBrowser:(SSDPServiceBrowser *)browser didNotStartBrowsingForServices:(NSError *)error; -- (void) ssdpBrowser:(SSDPServiceBrowser *)browser didFindService:(SSDPService *)service; -- (void) ssdpBrowser:(SSDPServiceBrowser *)browser didRemoveService:(SSDPService *)service; +- (void)ssdpBrowser:(SSDPServiceBrowser *)browser didNotStartBrowsingForServices:(NSError *)error; +- (void)ssdpBrowser:(SSDPServiceBrowser *)browser didFindService:(SSDPService *)service; +- (void)ssdpBrowser:(SSDPServiceBrowser *)browser didRemoveService:(SSDPService *)service; @end @@ -39,13 +39,12 @@ @property(readonly, nonatomic) NSString *networkInterface; @property(assign, nonatomic) id delegate; -- (id) initWithServiceType:(NSString *)serviceType onInterface:(NSString *)networkInterface; -- (id) initWithServiceType:(NSString *)serviceType; +- (id)initWithServiceType:(NSString *)serviceType onInterface:(NSString *)networkInterface; +- (id)initWithServiceType:(NSString *)serviceType; -- (void) startBrowsingForServices; -- (void) stopBrowsingForServices; +- (void)startBrowsingForServices; +- (void)stopBrowsingForServices; - -+ (NSDictionary *) availableNetworkInterfaces; ++ (NSDictionary *)availableNetworkInterfaces; @end diff --git a/Classes/SSDPServiceBrowser.m b/Classes/SSDPServiceBrowser.m index 66e0c81..8b18cf5 100644 --- a/Classes/SSDPServiceBrowser.m +++ b/Classes/SSDPServiceBrowser.m @@ -59,7 +59,7 @@ @interface SSDPServiceBrowser () { @implementation SSDPServiceBrowser -- (id) initWithServiceType:(NSString *)serviceType onInterface:(NSString *)networkInterface { +- (id)initWithServiceType:(NSString *)serviceType onInterface:(NSString *)networkInterface { self = [super init]; if (self) { _serviceType = [serviceType copy]; @@ -112,13 +112,23 @@ - (void)startBrowsingForServices { NSDictionary *interfaces = [SSDPServiceBrowser availableNetworkInterfaces]; NSData *sourceAddress = _networkInterface? [interfaces objectForKey:_networkInterface] : nil; - if( !sourceAddress ) sourceAddress = [[interfaces allValues] firstObject]; - - if(![_socket bindToAddress:sourceAddress error:&err]) { - [self _notifyDelegateWithError:err]; - return; + + if(sourceAddress) { + // Bind to address to receive unicast datagrams only + if(![_socket bindToAddress:sourceAddress error:&err]) { + [self _notifyDelegateWithError:err]; + return; + } + } + else { + // Bind to port to receive unicast and multicast datagrams + if(![_socket bindToPort:SSDPMulticastUDPPort error:&err]) { + [self _notifyDelegateWithError:err]; + return; + } } + // Join multicast group in order to receive multicast datagrams if(![_socket joinMulticastGroup:SSDPMulticastGroupAddress error:&err]) { [self _notifyDelegateWithError:err]; return; @@ -157,10 +167,18 @@ - (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; if( msg ) { NSDictionary *headers = [self _parseHeadersFromMessage:msg]; - if( [headers objectForKey:SSDPResponseStatusKey] ) { - SSDPService *service = [[SSDPService alloc] initWithHeaders:headers]; + SSDPService *service = [[SSDPService alloc] initWithHeaders:headers]; + if( [[headers objectForKey:SSDPResponseStatusKey] isEqualToString:@"200"] ) { [self _notifyDelegateWithFoundService:service]; } + else if ([[headers objectForKey:SSDPRequestMethodKey] isEqualToString:@"NOTIFY"]) { + if ([[headers objectForKey:@"nts"] isEqualToString:@"ssdp:alive"]) { + [self _notifyDelegateWithFoundService:service]; + } + else if ([[headers objectForKey:@"nts"] isEqualToString:@"ssdp:byebye"]) { + [self _notifyDelegateWithRemovedService:service]; + } + } } else { NSString *host = nil; @@ -231,8 +249,16 @@ - (void)_notifyDelegateWithFoundService:(SSDPService *)service }); } +- (void)_notifyDelegateWithRemovedService:(SSDPService *)service +{ + dispatch_async(dispatch_get_main_queue(), ^{ + @autoreleasepool { + [_delegate ssdpBrowser:self didRemoveService:service]; + } + }); +} -+ (NSDictionary *) availableNetworkInterfaces { ++ (NSDictionary *)availableNetworkInterfaces { NSMutableDictionary *addresses = [NSMutableDictionary dictionary]; struct ifaddrs *interfaces = NULL; struct ifaddrs *ifa = NULL;