X-Git-Url: http://git.ithinksw.org/ITFoundation.git/blobdiff_plain/d7b4e9008bca3278755f8b96c0ea9d5e3c94c39d..086eb4c9abbda3c5d5f74c07800ad5cb04a50505:/ITInetServerSocket.m diff --git a/ITInetServerSocket.m b/ITInetServerSocket.m index 8f75326..8fd8c54 100755 --- a/ITInetServerSocket.m +++ b/ITInetServerSocket.m @@ -9,6 +9,7 @@ #import "ITInetServerSocket.h" #import "ITInetSocket.h" #import +#import #import #import #import @@ -16,31 +17,19 @@ #import #import -/* Too bad Objective-C doesn't have class variables... */ -static NSMutableDictionary *servsockets; -static NSTimer *timer; - @interface ITInetServerSocket(Private) -+(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; +-(void)setupThread; +-(void)stopThread; +-(void)newClient:(int)cfd; +-(void)socketAcceptLoop:(id)data; @end @implementation ITInetServerSocket -+ (void)initialize -{ - servsockets = [[NSMutableDictionary alloc] init]; - [self setupTimer]; -} - - (id)init { if (self = [super init]) @@ -50,7 +39,9 @@ static NSTimer *timer; clients = [[NSMutableSet alloc] init]; service = nil; port = 0; + dieflag = 0; rndType = rndName = nil; + timer = nil; } return self; } @@ -64,7 +55,9 @@ static NSTimer *timer; clients = [[NSMutableSet alloc] init]; service = nil; port = 0; + dieflag = 0; rndType = rndName = nil; + timer = nil; } return self; } @@ -81,7 +74,7 @@ static NSTimer *timer; - (BOOL)start { if (!rndName || !rndType || !port) return NO; - [ITInetServerSocket registerSocket:self]; + [self setupConnection]; return YES; } @@ -107,7 +100,7 @@ static NSTimer *timer; - (void)stop { - [ITInetServerSocket unregisterSocket:self]; + [self stopConnection]; } - (void)setServiceType:(NSString*)type useForPort:(BOOL)p @@ -130,34 +123,12 @@ static NSTimer *timer; @end @implementation ITInetServerSocket(Private) -+(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; + struct addrinfo *res; short p; - - hints.ai_flags = AI_PASSIVE; - hints.ai_family = PF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_addrlen = 0; - hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; - - getaddrinfo(NULL,_name,&hints,&res); + getaddrinfo(NULL,_name,NULL,&res); p = ntohs(((struct sockaddr_in *)res->ai_addr)->sin_port); freeaddrinfo(res); return p; @@ -165,30 +136,36 @@ static NSTimer *timer; -(void)setupConnection { - 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); - bind(sockfd,(struct sockaddr *)&sa,sizeof(sa)); + struct addrinfo hints, *ai; + hints.ai_flags = AI_PASSIVE; + hints.ai_family = PF_INET6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_addrlen = 0; + hints.ai_canonname = hints.ai_addr = hints.ai_next = NULL; + getaddrinfo(NULL,[[[NSNumber numberWithShort:port] stringValue] cString],&hints,&ai); + sockfd = socket(PF_INET6,SOCK_STREAM,IPPROTO_TCP); + bind(sockfd,ai->ai_addr,ai->ai_addrlen); listen(sockfd, SOMAXCONN); - fcntl(sockfd,F_SETFL,O_NONBLOCK); + freeaddrinfo(ai); [self setupRendezvousAdvertising]; + [self setupThread]; } - (void)stopConnection { [self stopRendezvousAdvertising]; [clients makeObjectsPerformSelector:@selector(disconnect)]; - shutdown(sockfd,2); + [self stopThread]; close(sockfd); sockfd = -1; } - (void)setupRendezvousAdvertising { - service = [[NSNetService alloc] initWithDomain:@"" type:[NSString stringWithFormat:@"_%@._tcp.",rndType] name:rndName port:htons(port)]; + NSString *a = [NSString stringWithFormat:@"_%@._tcp.",rndType]; + service = [[NSNetService alloc] initWithDomain:@"" type:a name:rndName port:htons(port)]; + NSLog(@"Advertising a service of type %@ name %@",a,rndName); [service publish]; } @@ -199,49 +176,49 @@ static NSTimer *timer; service = nil; } -+ (void)setupTimer +- (void)setupThread { - if (!timer) timer = [NSTimer timerWithTimeInterval:0 target:self selector:@selector(globalTimerFunc:) userInfo:nil repeats:YES]; - [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; + NSPort *p1 = [NSPort port], *p2 = [NSPort port]; + NSConnection *dcon = [[NSConnection alloc] initWithReceivePort:p1 sendPort:p2]; + NSArray *par = [NSArray arrayWithObjects:p2,p1,nil]; + [dcon setRootObject:self]; + NSLog(@"detached server thread"); + [NSThread detachNewThreadSelector:@selector(socketAcceptLoop:) toTarget:self withObject:par]; } -+ (void)stopTimer +- (void)stopThread { - [timer invalidate]; - [timer release]; - timer = nil; + NSLog(@"stopping server thread"); + dieflag = 1; + do {} while (dieflag == 1); } -+ (void)globalTimerFunc:(NSTimer*)timer +- (void)newClient:(int)cfd { - NSEnumerator *enume = [servsockets objectEnumerator]; - id obj; - - while (obj = [enume nextObject]) - { - [obj timerFunc]; - } + ITInetSocket *csocket = [[ITInetSocket alloc] initWithFD:cfd delegate:delegate]; + NSLog(@"new client for this server"); + [clients addObject:csocket]; } -- (BOOL)timerFunc +- (void)socketAcceptLoop:(id)data { - if (sockfd != -1) + NSAutoreleasePool *ap = [[NSAutoreleasePool alloc] init]; + NSArray *par = data; + NSConnection *dcon = [[NSConnection alloc] initWithReceivePort:[par objectAtIndex:0] sendPort:[par objectAtIndex:1]]; + NSProxy *dp = [dcon rootProxy]; + while ((sockfd >= 0) && !dieflag) { - 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]; - return YES; - } + cfd = accept(sockfd,NULL,NULL); + NSLog(@"Someone connected!"); + [(id)dp newClient:cfd]; + [ap release]; + ap = [[NSAutoreleasePool alloc] init]; } - return NO; + + NSLog(@"suiciding"); + dieflag = 0; + [dcon release]; + [ap release]; } @end \ No newline at end of file