/* FILE: TrystController.m * * Project Tryst * Class TrystController * Creator Chris B. Vetter * Maintainer Chris B. Vetter * Creation Date Mon Jan 8 16:12:07 CET 2007 * * Copyright (c) 2007 * * Tryst is free software under the terms of a dual BSD/LGPL license. * For a full copyright description, see the COPYRIGHT file. * ***************************************************************************/ // // Include // #import "TrystController.h" #import #import #import #import #import #import #import #import // // Define // // // Typedef // // // Public // // // Private // // // Private Interface // // // Prototype // /*************************************************************************** ** ** Implementation ** */ @implementation TrystController /*************************************************************************** ** ** Private Methods ** */ /** * Description forthcoming * * */ - (void) createSocket { if( _socketPort ) { return; } while( ! _socketPort ) { // Would be nice if // _socketPort = [[NSSocketPort alloc] initWithTCPPort: _portNumber]; // was possible... _socketPort = [NSSocketPort portWithNumber: _portNumber onHost: [NSHost currentHost] forceAddress: nil listener: YES]; _portNumber++; } _portNumber--; } /** * Description forthcoming * * */ - (void) createService { if( _service ) { return; } _service = [[NSNetService alloc] initWithDomain: @"" type: _serviceType name: _serviceName port: _portNumber]; [_service setDelegate: self]; [_service publish]; } /** * Description forthcoming * * */ - (void) createBrowser { if( !_serviceBrowser ) { _serviceBrowser = [[NSNetServiceBrowser alloc] init]; [_serviceBrowser setDelegate: self]; } } /** * Description forthcoming * * */ - (void) startBrowsing { if( _browsing ) { return; } _browsing = YES; [_serviceBrowser searchForServicesOfType: _serviceType inDomain: @""]; } /** * Description forthcoming * * */ - (BOOL) addInfoService: (NSNetService *) service name: (NSString *) name ip: (NSString *) ip port: (int) port { NSMutableDictionary *dict = nil; NSEnumerator *e = nil; e = [_discoveredServicesWithInfo objectEnumerator]; while( (dict = [e nextObject]) ) { if( [[dict objectForKey: @"ip"] isEqualToString: ip] ) { if( [[dict objectForKey: @"port"] intValue] == port ) { return NO; } } } dict = [NSMutableDictionary dictionary]; [dict setObject: ip forKey: @"ip"]; [dict setObject: [NSNumber numberWithInt: port] forKey: @"port"]; [dict setObject: name forKey: @"name"]; [dict setObject: service forKey: @"service"]; [_discoveredServicesWithInfo addObject: dict]; return YES; } /** * Description forthcoming * * */ - (BOOL) removeInfoService: (NSNetService *) service { NSDictionary *dict = nil; NSEnumerator *e = nil; NSMutableArray *delete = nil; delete = [NSMutableArray array]; e = [_discoveredServicesWithInfo objectEnumerator]; while( (dict = [e nextObject]) ) { if( [[dict objectForKey: @"service"] isEqual: service] ) { [delete addObject: dict]; } } e = [delete objectEnumerator]; while( (dict = [e nextObject]) ) { [_discoveredServicesWithInfo removeObject: dict]; } return NO; } /*************************************************************************** ** ** Factory Methods ** */ /*************************************************************************** ** ** Instance Methods ** */ /** * Description forthcoming * * */ - (id) initWithName: (NSString *) name type: (NSString *) type port: (int) port { if( (self = [super init]) ) { [self setName:name]; _serviceType = [type retain]; _portNumber = port; _discoveredServicesWithInfo = [[NSMutableArray alloc] init]; [self createSocket]; [self createBrowser]; } return self; } /** * Description forthcoming * * */ - (void) refreshBrowsing { if( ! _browsing ) { return; } [self activateBrowsing: NO]; [self performSelector: @selector(startBrowsing) withObject: nil afterDelay: 0.0]; } /** * Description forthcoming * * */ - (void) activateBrowsing: (BOOL) flag { if( flag == _browsing ) { return; } if( flag ) { _browsing = YES; [_serviceBrowser searchForServicesOfType: _serviceType inDomain: @""]; } else { _browsing = NO; [_serviceBrowser stop]; [_discoveredServicesWithInfo removeAllObjects]; [_delegate discoveredServicesDidChange: self]; } } /** * Description forthcoming * * */ - (void) activatePublishing: (BOOL) flag { if( _publishing == flag ) { return; } if( flag ) { [self createService]; } else { [_service stop]; _service = nil; } _publishing = flag; } /*************************************************************************** ** ** Accessor Methods ** */ /** * Description forthcoming * * */ - (BOOL) isBrowsing { return _browsing; } /** * Description forthcoming * * */ - (BOOL) isPublished { return _publishing; } /** * Description forthcoming * * */ - (NSArray *) discoveredServicesWithInfo { return [NSArray arrayWithArray: _discoveredServicesWithInfo]; } /** * Description forthcoming * * */ - (id) delegate { return _delegate; } /** * Description forthcoming * * */ - (void) setDelegate: (id) object { if( ! [object respondsToSelector: @selector(discoveredServicesDidChange:)] ) { NSLog(@"Warning: delegate does not respond to '-discoveredServicesDidChange:'!"); } _delegate = object; } /** * Description forthcoming * * */ - (NSString *) name { return _serviceName; } /** * Description forthcoming * * */ - (void) setName: (NSString *) name { if( ! _publishing ) { [name retain]; [_serviceName release]; _serviceName = name; } else { NSLog(@"Cannot change name while service is published!"); } return; } /** * Description forthcoming * * */ - (NSSocketPort *) socket { return _socketPort; } /** * Description forthcoming * * */ - (NSString *) ipForName: (NSString *) name { NSEnumerator *e = nil; NSDictionary *dict = nil; e = [_discoveredServicesWithInfo objectEnumerator]; while( (dict = [e nextObject]) ) { if( [[dict objectForKey: @"name"] isEqualToString: name] ) { return [dict objectForKey: @"ip"]; } } return nil; } /** * Description forthcoming * * */ - (int) portForName: (NSString *) name { NSEnumerator *e = nil; NSDictionary *dict = nil; e = [_discoveredServicesWithInfo objectEnumerator]; while( (dict = [e nextObject]) ) { if( [[dict objectForKey: @"name"] isEqualToString: name] ) { return [[dict objectForKey: @"port"] intValue]; } } return 0; } /*************************************************************************** ** ** Protocol Methods ** */ /*************************************************************************** ** ** Delegate Methods ** */ /** * Description forthcoming * * */ - (void) netService: (NSNetService *) sender didNotPublish: (NSDictionary *) errorDict { _publishing = NO; [_delegate discoveredServicesDidChange: self]; } /** * Description forthcoming * * */ - (void) netServiceWillPublish: (NSNetService *) sender { /* Currently does nothing */ } /** * Description forthcoming * * */ - (void) netServiceDidStop: (NSNetService *) sender { /* Currently does nothing */ } /** * Description forthcoming * * */ - (void) netService: (NSNetService *) sender didNotResolve: (NSDictionary *) errorDict { /* Currently does nothing */ } /** * Description forthcoming * * */ - (void) netServiceDidResolveAddress: (NSNetService *) sender { NSData *address = nil; struct sockaddr_in *socketAddress = NULL; NSString *ipString = nil; int port, i = 0; for( ; i < [[sender addresses] count]; i++ ) { address = [[sender addresses] objectAtIndex: i]; socketAddress = (struct sockaddr_in *) [address bytes]; ipString = [NSString stringWithFormat: @"%s", inet_ntoa (socketAddress->sin_addr)]; port = socketAddress->sin_port; if( [ipString isEqualToString: @"127.0.0.1"] ) { continue; } if( [self addInfoService: sender name: [sender name] ip: ipString port: port] ) { [_delegate discoveredServicesDidChange: self]; } } } /** * Description forthcoming * * */ - (void) netServiceWillResolve: (NSNetService *) sender { /* Currently does nothing */ } /** * Description forthcoming * * */ - (void) netServiceBrowser: (NSNetServiceBrowser *) aNetServiceBrowser didFindService: (NSNetService *) aNetService moreComing: (BOOL) moreComing { [aNetService setDelegate: self]; [aNetService resolve]; } /** * Description forthcoming * * */ - (void) netServiceBrowser: (NSNetServiceBrowser *) aNetServiceBrowser didRemoveService: (NSNetService *) aNetService moreComing: (BOOL) moreComing { [self removeInfoService: aNetService]; [_delegate discoveredServicesDidChange: self]; } /** * Description forthcoming * * */ - (void) netServiceBrowserDidStopSearch: (NSNetServiceBrowser *)aNetServiceBrowser { if( aNetServiceBrowser == _serviceBrowser ) { [_discoveredServicesWithInfo removeAllObjects]; [_delegate discoveredServicesDidChange: self]; } } /** * Description forthcoming * * */ - (void) netServiceBrowser: (NSNetServiceBrowser *) aNetServiceBrowser didNotSearch: (NSDictionary *) errorDict { /* Currently does nothing */ } /** * Description forthcoming * * */ - (void) netServiceBrowserWillSearch: (NSNetServiceBrowser *) aNetServiceBrowser { /* Currently does nothing */ } /** * Description forthcoming * * */ - (void) netServiceBrowser: (NSNetServiceBrowser *) aNetServiceBrowser didFindDomain: (NSString *) domainString moreComing: (BOOL) moreComing { /* Currently does nothing */ } /** * Description forthcoming * * */ - (void) netServiceBrowser: (NSNetServiceBrowser *) aNetServiceBrowser didRemoveDomain: (NSString *) domainString moreComing: (BOOL) moreComing { /* Currently does nothing */ } /*************************************************************************** ** ** Override Methods ** */ /** * Description forthcoming * * */ - (void) dealloc { [self activatePublishing: NO]; [_serviceBrowser stop]; [_domainBrowser stop]; [_socketPort release]; [_discoveredServicesWithInfo release]; [super dealloc]; } @end /*************************************************************************** ** ** Functions ** */ /* ** End of File. ** ****************************************************************************/