X-Git-Url: http://git.ithinksw.org/ITFoundation.git/blobdiff_plain/2f6f5b098085f36298e23e690cf27b61b4e2ec36..5fadb328bb7952174fcb7a6bb867c9c11f801df9:/ITInetServerSocket.m diff --git a/ITInetServerSocket.m b/ITInetServerSocket.m index dcc8805..f4b9720 100755 --- a/ITInetServerSocket.m +++ b/ITInetServerSocket.m @@ -14,55 +14,75 @@ #import #import #import +#import + +/* Too bad Objective-C doesn't have class variables... */ +static NSMutableDictionary *servsockets; +static NSTimer *timer; @interface ITInetServerSocket(Private) --(void)setupConnectionWithServiceName:(NSString*)name; --(void)setupConnectionWithPortNumber:(NSNumber*)port; --(void)setupRendezvousAdvertising:(NSString*)name; --(void)setupTimer; --(void)timerFunc:(NSTimer*)timer; ++(void)registerSocket:(ITInetServerSocket*)sock; ++(void)unregisterSocket:(ITInetServerSocket*)sock; +-(short)lookupPortForServiceType:(NSString*)name; +-(void)setupConnection; +-(void)stopConnection; +-(void)setupRendezvousAdvertising; +-(void)stopRendezvousAdvertising; ++(void)setupTimer; ++(void)stopTimer; ++(void)globalTimerFunc:(NSTimer*)timer; +-(BOOL)timerFunc; @end @implementation ITInetServerSocket -- (id)init ++ (void)initialize { - if (self = [super init]) - { - sockfd = 0; - delegate = clients = nil; - } - return self; + servsockets = [[NSMutableDictionary alloc] init]; + [self setupTimer]; } -- (id)initWithServiceName:(NSString*)name delegate:(id)d +- (id)init { if (self = [super init]) { - delegate = [d retain]; + sockfd = -1; + delegate = nil; clients = [[NSMutableSet alloc] init]; - [self setupConnectionWithServiceName:name]; + service = nil; + port = 0; + rndType = rndName = nil; } return self; } -- (id)initWithPort:(NSNumber*)port rendezvousName:(NSString*)name delegate:(id)d +- (id)initWithDelegate:(id)d { if (self = [super init]) { + sockfd = -1; delegate = [d retain]; clients = [[NSMutableSet alloc] init]; - [self setupConnectionWithPortNumber:port]; + service = nil; + port = 0; + rndType = rndName = nil; } return self; } - (void)dealloc { - [service stop]; - [service release]; + [self stopConnection]; [clients release]; [delegate release]; - shutdown(sockfd,2); + [rndName release]; + [rndType release]; +} + +- (BOOL)registerSocket +{ + if (!rndName || !rndType || !port) return NO; + [ITInetServerSocket registerSocket:self]; + return YES; } - (int)sockfd @@ -79,13 +99,54 @@ { return delegate; } + +- (short)port +{ + return port; +} + +- (void)stop +{ + [ITInetServerSocket unregisterSocket:self]; +} + +- (void)setServiceType:(NSString*)type useForPort:(BOOL)p +{ + rndType = [type retain]; + if (p) { + port = [self lookupPortForServiceType:type]; + } +} + +- (void)setServiceName:(NSString*)name +{ + rndName = [name retain]; +} + +- (void)setPort:(short)p +{ + port = p; +} @end @implementation ITInetServerSocket(Private) --(void)setupConnectionWithServiceName:(NSString*)name ++(void)registerSocket:(ITInetServerSocket*)sock +{ + [sock setupConnection]; + [servsockets setObject:sock forKey:[NSString stringWithFormat:@"%lu",[sock port]]]; +} + ++(void)unregisterSocket:(ITInetServerSocket*)sock +{ + [sock stopConnection]; + [servsockets removeObjectForKey:[NSString stringWithFormat:@"%lu",[sock port]]]; +} + +-(short)lookupPortForServiceType:(NSString*)name { const char *_name = [name cString]; struct addrinfo hints,*res; + short p; hints.ai_flags = AI_PASSIVE; hints.ai_family = PF_INET; @@ -97,55 +158,90 @@ hints.ai_next = NULL; getaddrinfo(NULL,_name,&hints,&res); - sockfd = socket(res->ai_family, res->ai_socktype,res->ai_protocol); - bind(sockfd, res->ai_addr, res->ai_addrlen); - listen(sockfd, SOMAXCONN); - fcntl(sockfd,F_SETFL,O_NONBLOCK); + p = ntohs(((struct sockaddr_in *)res->ai_addr)->sin_port); freeaddrinfo(res); + return p; } --(void)setupConnectionWithPortNumber:(NSNumber*)port +-(void)setupConnection { - short _port = [port shortValue]; struct sockaddr_in sa; sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); sa.sin_addr.s_addr = INADDR_ANY; sa.sin_family = AF_INET; - sa.sin_port = htons(_port); + sa.sin_port = htons(port); bind(sockfd,(struct sockaddr *)&sa,sizeof(sa)); listen(sockfd, SOMAXCONN); fcntl(sockfd,F_SETFL,O_NONBLOCK); + [self setupRendezvousAdvertising]; } -- (void)setupRendezvousAdvertising:(NSString*)name port:(NSNumber*)port +- (void)stopConnection { - service = [[NSNetService alloc] initWithDomain:@"" type:[NSString stringWithFormat:@"_%@._tcp.",name] port:htons([port shortValue])]; + [self stopRendezvousAdvertising]; + [clients makeObjectsPerformSelector:@selector(disconnect)]; + shutdown(sockfd,2); + close(sockfd); + sockfd = -1; +} + +- (void)setupRendezvousAdvertising +{ + service = [[NSNetService alloc] initWithDomain:@"" type:[NSString stringWithFormat:@"_%@._tcp.",rndType] name:rndName port:htons(port)]; [service publish]; } -- (void)setupTimer +- (void)stopRendezvousAdvertising +{ + [service stop]; + [service release]; + service = nil; +} + ++ (void)setupTimer { - NSTimer *timer = [NSTimer timerWithTimeInterval:0 target:self selector:@selector(timerFunc:) userInfo:nil repeats:YES]; + if (!timer) timer = [NSTimer timerWithTimeInterval:0 target:self selector:@selector(globalTimerFunc:) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; } -- (void)timerFunc:(NSTimer*)timer ++ (void)stopTimer +{ + [timer invalidate]; + [timer release]; + timer = nil; +} + ++ (void)globalTimerFunc:(NSTimer*)timer +{ + NSEnumerator *enume = [servsockets objectEnumerator]; + id obj; + + while (obj = [enume nextObject]) + { + [obj timerFunc]; + } +} + +- (BOOL)timerFunc { - struct sockaddr_in csa; - int csalen; - signed int cfd; - (void) timer; - cfd = accept(sockfd,(struct sockaddr*)&csa,&csalen); - if (cfd == -1) { - if (errno == EWOULDBLOCK) return; - else {perror("Too bad I haven't implemented error checking yet");} + if (sockfd != -1) + { + struct sockaddr_in csa; + int csalen; + signed int cfd; + cfd = accept(sockfd,(struct sockaddr*)&csa,&csalen); + if (cfd == -1) { + if (errno == EWOULDBLOCK) return NO; + else {perror("Too bad I haven't implemented error checking yet");} } else { - ITInetSocket *csocket = [[[ITInetSocket alloc] initWithFD:cfd delegate:self] autorelease]; - [clients addObject:csocket]; - [delegate newClientJoined:csocket]; - + ITInetSocket *csocket = [[[ITInetSocket alloc] initWithFD:cfd delegate:self] autorelease]; + [clients addObject:csocket]; + [delegate newClientJoined:csocket]; + return YES; + } } + return NO; } @end \ No newline at end of file