Skip to content

Commit

Permalink
Added sample code, fixed potential callback concurrency problems, add…
Browse files Browse the repository at this point in the history
…ed support for specifying dispatch queue to be used.
  • Loading branch information
tolo committed Dec 5, 2013
1 parent 5a03ec3 commit bd1758a
Show file tree
Hide file tree
Showing 30 changed files with 1,660 additions and 87 deletions.
11 changes: 11 additions & 0 deletions .gitignore
@@ -0,0 +1,11 @@
.DS_Store

**/xcuserdata/**
*.xcuserstate
*.pbxuser
*.xccheckout
*.hmap
*.ipa
build/

Pods
112 changes: 56 additions & 56 deletions HHService.m
Expand Up @@ -49,6 +49,7 @@ @interface HHService ()
@property (nonatomic, retain, readwrite) NSData* txtData;

@property (nonatomic, retain) NSMutableArray* resolveResults;
@property (assign) uint16_t lastResolvedPort;

- (void) didResolveService:(ResolveResult*)resolveResult txtData:(NSData*)svcTxtData moreComing:(BOOL)moreComing error:(DNSServiceErrorType)error;
- (void) didResolveServiceAddress:(NSData*)addressData error:(DNSServiceErrorType)error;
Expand All @@ -63,66 +64,75 @@ - (void) didResolveServiceAddress:(NSData*)addressData error:(DNSServiceErrorTyp
static void getAddrInfoCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
const char* hostName, const struct sockaddr* address, uint32_t ttl, void* context ) {

ResolveResult* resolveResult = (ResolveResult*)context;
HHService* serviceResolver = resolveResult.serviceResolver;
NSData* addressData = nil;
if ( errorCode == kDNSServiceErr_NoError ) {
ContextWrapper* contextWrapper = (ContextWrapper*)context;
HHService* serviceResolver = contextWrapper.contextRetained;

if( serviceResolver ) {
NSData* addressData = nil;
if ( errorCode == kDNSServiceErr_NoError ) {

// Set port if not set
struct sockaddr_in* sin = (struct sockaddr_in*)address;
if( sin->sin_port == 0 ) sin->sin_port = resolveResult.port;
// Set port if not set
struct sockaddr_in* sin = (struct sockaddr_in*)address;
if( sin->sin_port == 0 ) sin->sin_port = serviceResolver.lastResolvedPort;

addressData = [[NSData alloc] initWithBytes:address length:sizeof(struct sockaddr)];
addressData = [[NSData alloc] initWithBytes:address length:sizeof(struct sockaddr)];
}
dispatch_async(serviceResolver.mainDispatchQueue, ^{
[serviceResolver didResolveServiceAddress:addressData error:errorCode];

[addressData release];
});
}
dispatch_async(dispatch_get_main_queue(), ^{
[serviceResolver didResolveServiceAddress:addressData error:errorCode];

[addressData release];
});

[serviceResolver release];
}

static void resolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
const char* fullname, const char* hosttarget, uint16_t port, uint16_t txtLen,
const unsigned char* txtRecord, void* context) {

HHService* serviceResolver = (HHService*)context;
BOOL moreComing = flags & kDNSServiceFlagsMoreComing;

ResolveResult* resolveResult = nil;
NSString* newName = [[NSString alloc] initWithCString:hosttarget encoding:NSUTF8StringEncoding];
ContextWrapper* contextWrapper = (ContextWrapper*)context;
HHService* serviceResolver = contextWrapper.contextRetained;

if (errorCode == kDNSServiceErr_NoError) {
char interfaceName[IFNAMSIZ];
if( if_indextoname(interfaceIndex, interfaceName) != NULL ) {
[serviceResolver HHLogDebug:@"Resolved host %@, port %d, interface index %d ('%s') - getting address info", newName, port, interfaceIndex, interfaceName];
resolveResult = [[ResolveResult alloc] init];
resolveResult.hostName = newName;
resolveResult.port = port; // Keep network byte ordering since we will use this in struct sockaddr_in
resolveResult.interfaceIndex = interfaceIndex;
} else {
[serviceResolver HHLogDebug:@"Resolve returned invalid interface index (%d)", interfaceIndex];
if( serviceResolver ) {
BOOL moreComing = flags & kDNSServiceFlagsMoreComing;

ResolveResult* resolveResult = nil;
NSString* newName = [[NSString alloc] initWithCString:hosttarget encoding:NSUTF8StringEncoding];

if (errorCode == kDNSServiceErr_NoError) {
char interfaceName[IFNAMSIZ];
if( if_indextoname(interfaceIndex, interfaceName) != NULL ) {
[serviceResolver HHLogDebug:@"Resolved host %@, port %d, interface index %d ('%s') - getting address info", newName, port, interfaceIndex, interfaceName];
resolveResult = [[ResolveResult alloc] init];
resolveResult.hostName = newName;
resolveResult.port = port; // Keep network byte ordering since we will use this in struct sockaddr_in
resolveResult.interfaceIndex = interfaceIndex;
} else {
[serviceResolver HHLogDebug:@"Resolve returned invalid interface index (%d)", interfaceIndex];
}
}

NSData* txtData = [[NSData alloc] initWithBytes:txtRecord length:txtLen];

dispatch_async(serviceResolver.mainDispatchQueue, ^{
[serviceResolver didResolveService:resolveResult txtData:txtData moreComing:moreComing error:errorCode];

[resolveResult release];
[newName release];
[txtData release];
});
}

NSData* txtData = [[NSData alloc] initWithBytes:txtRecord length:txtLen];

dispatch_async(dispatch_get_main_queue(), ^{
[serviceResolver didResolveService:resolveResult txtData:txtData moreComing:moreComing error:errorCode];

[resolveResult release];
[newName release];
[txtData release];
});
[serviceResolver release];
}


#pragma mark -
#pragma mark HHService


@implementation HHService {
// DNSServiceRef getAddressInfoRef;
}
@implementation HHService

@synthesize delegate,
name, type, domain, includeP2P,
Expand Down Expand Up @@ -220,14 +230,6 @@ - (void) dealloc {
[super dealloc];
}

//- (void) doDestroy {
// if ( getAddressInfoRef != NULL ) {
// DNSServiceRefDeallocate(getAddressInfoRef);
// getAddressInfoRef = NULL;
// }
// [super doDestroy];
//}


#pragma mark -
#pragma mark Get address info methods (resolve step2)
Expand All @@ -236,16 +238,12 @@ - (void) dealloc {
- (void) getNextAddressInfo {
ResolveResult* result = [self.resolveResults lastObject];
if( result ) {
// if( getAddressInfoRef ) {
// DNSServiceRefDeallocate(getAddressInfoRef);
// }
// DNSServiceRef getAddressInfoRef = self.sharedConnection.connectionRef;
// getAddressInfoRef = NULL;
DNSServiceRef getAddressInfoRef = NULL;
self.lastResolvedPort = result.port;

const char* hosttarget = [result.hostName cStringUsingEncoding:NSUTF8StringEncoding];
// DNSServiceErrorType err = DNSServiceGetAddrInfo(&getAddressInfoRef, kDNSServiceFlagsShareConnection, result.interfaceIndex, kDNSServiceProtocol_IPv4, hosttarget, getAddrInfoCallback, result);
DNSServiceErrorType err = DNSServiceGetAddrInfo(&getAddressInfoRef, 0, result.interfaceIndex, kDNSServiceProtocol_IPv4, hosttarget, getAddrInfoCallback, result);
DNSServiceErrorType err = DNSServiceGetAddrInfo(&getAddressInfoRef, 0, result.interfaceIndex, kDNSServiceProtocol_IPv4,
hosttarget, getAddrInfoCallback, [self setCurrentCallbackContextWithContext:self]);

if( err == kDNSServiceErr_NoError ) {
[self HHLogDebug:@"Beginning address lookup"];
Expand All @@ -263,6 +261,8 @@ - (void) getNextAddressInfo {


- (BOOL) beginResolve {
//[super resetServiceRef];

self.resolved = NO;
self.resolvedAddresses = [NSMutableArray array];
self.resolveResults = [NSMutableArray array];
Expand All @@ -278,7 +278,7 @@ - (BOOL) beginResolve {

DNSServiceRef resolveRef = nil;
DNSServiceErrorType err = DNSServiceResolve(&resolveRef, flags, kDNSServiceInterfaceIndexAny,
_name, _type, _domain, resolveCallback, self);
_name, _type, _domain, resolveCallback, [self setCurrentCallbackContextWithContext:self]);

if( err == kDNSServiceErr_NoError ) {
[self HHLogDebug:@"Beginning resolve"];
Expand Down
38 changes: 22 additions & 16 deletions HHServiceBrowser.m 100755 → 100644
Expand Up @@ -29,24 +29,30 @@ - (void) browserReceviedResult:(DNSServiceErrorType)error serviceName:(NSString*

static void browseCallBack(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
const char *serviceName, const char *regtype, const char *replyDomain, void *context) {
HHServiceBrowser * serviceBrowser = (HHServiceBrowser *)context;

if( errorCode == kDNSServiceErr_NoError ) {
BOOL add = flags & kDNSServiceFlagsAdd;
BOOL moreComing = flags & kDNSServiceFlagsMoreComing;

NSString* newName = serviceName ? [[NSString alloc] initWithCString:serviceName encoding:NSUTF8StringEncoding] : nil;
NSString* newDomain = replyDomain ? [[NSString alloc] initWithCString:replyDomain encoding:NSUTF8StringEncoding] : nil;

dispatch_async(dispatch_get_main_queue(), ^{
[serviceBrowser browserReceviedResult:errorCode serviceName:newName serviceDomain:newDomain add:add moreComing:moreComing];
ContextWrapper* contextWrapper = (ContextWrapper*)context;
HHServiceBrowser* serviceBrowser = contextWrapper.contextRetained;

if( serviceBrowser ) {
if( errorCode == kDNSServiceErr_NoError ) {
BOOL add = flags & kDNSServiceFlagsAdd;
BOOL moreComing = flags & kDNSServiceFlagsMoreComing;

[newName release];
[newDomain release];
});
} else {
[serviceBrowser dnsServiceError:errorCode];
NSString* newName = serviceName ? [[NSString alloc] initWithCString:serviceName encoding:NSUTF8StringEncoding] : nil;
NSString* newDomain = replyDomain ? [[NSString alloc] initWithCString:replyDomain encoding:NSUTF8StringEncoding] : nil;

dispatch_async(serviceBrowser.mainDispatchQueue, ^{
[serviceBrowser browserReceviedResult:errorCode serviceName:newName serviceDomain:newDomain add:add moreComing:moreComing];

[newName release];
[newDomain release];
});
} else {
[serviceBrowser dnsServiceError:errorCode];
}
}

[serviceBrowser release];
}


Expand Down Expand Up @@ -120,7 +126,7 @@ - (BOOL) beginBrowse {

DNSServiceRef browseRef = NULL;
DNSServiceErrorType err = DNSServiceBrowse(&browseRef, flags, kDNSServiceInterfaceIndexAny, _type, _domain,
browseCallBack, self);
browseCallBack, [self setCurrentCallbackContextWithContext:self]);

if( err == kDNSServiceErr_NoError ) {
[self HHLogDebug:@"Beginning browse"];
Expand Down
28 changes: 17 additions & 11 deletions HHServicePublisher.m
Expand Up @@ -30,18 +30,24 @@ - (void) seviceDidRegister:(NSString*)newName error:(DNSServiceErrorType)error;

static void registerServiceCallBack(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode,
const char* name, const char* regType, const char* domain, void* context) {
HHServicePublisher * servicePublisher = (HHServicePublisher *)context;

if( errorCode == kDNSServiceErr_NoError ) {
NSString* newName = name ? [[NSString alloc] initWithCString:name encoding:NSUTF8StringEncoding] : nil;
dispatch_async(dispatch_get_main_queue(), ^{
[servicePublisher seviceDidRegister:newName error:errorCode];

[newName release];
});
} else {
[servicePublisher dnsServiceError:errorCode];
ContextWrapper* contextWrapper = (ContextWrapper*)context;
HHServicePublisher* servicePublisher = contextWrapper.contextRetained;

if( servicePublisher ) {
if( errorCode == kDNSServiceErr_NoError ) {
NSString* newName = name ? [[NSString alloc] initWithCString:name encoding:NSUTF8StringEncoding] : nil;
dispatch_async(servicePublisher.mainDispatchQueue, ^{
[servicePublisher seviceDidRegister:newName error:errorCode];

[newName release];
});
} else {
[servicePublisher dnsServiceError:errorCode];
}
}

[servicePublisher release];
}


Expand Down Expand Up @@ -125,7 +131,7 @@ - (BOOL) beginPublish {

DNSServiceRef registerRef;
DNSServiceErrorType err = DNSServiceRegister(&registerRef, flags, kDNSServiceInterfaceIndexAny, _name, _type, _domain, NULL,
bigEndianPort, _txtLen, _txtData, registerServiceCallBack, self);
bigEndianPort, _txtLen, _txtData, registerServiceCallBack, [self setCurrentCallbackContextWithContext:self]);

if( err == kDNSServiceErr_NoError ) {
return [super setServiceRef:registerRef];
Expand Down
16 changes: 16 additions & 0 deletions HHServiceSupport.h
Expand Up @@ -9,16 +9,32 @@
#import <Foundation/Foundation.h>
#import <dns_sd.h>


@interface ContextWrapper : NSObject

@property (assign) id context;
@property (readonly) id contextRetained;

@end


@interface HHServiceSupport : NSObject

@property (nonatomic, assign) DNSServiceErrorType lastError;
@property (nonatomic, readonly) BOOL hasFailed;
@property (nonatomic, strong) ContextWrapper* currentCallbackContext;

/** If you use HHServices in a different dispatch queue than the main dispatch queue, set this property to that queue. */
@property (nonatomic, assign) dispatch_queue_t mainDispatchQueue;


- (void) dnsServiceError:(DNSServiceErrorType)error;

- (BOOL) setServiceRef:(DNSServiceRef)serviceRef;
- (void) resetServiceRef;

- (ContextWrapper*) setCurrentCallbackContextWithContext:(id)context;

@end


Expand Down

0 comments on commit bd1758a

Please sign in to comment.