X-Git-Url: http://git.ithinksw.org/ITFoundation.git/blobdiff_plain/2f6f5b098085f36298e23e690cf27b61b4e2ec36..1d23d1181a753fffef7a9d28db4b0b0546bd0032:/ITInetServerSocket.m diff --git a/ITInetServerSocket.m b/ITInetServerSocket.m index dcc8805..08a8fe0 100755 --- a/ITInetServerSocket.m +++ b/ITInetServerSocket.m @@ -9,60 +9,84 @@ #import "ITInetServerSocket.h" #import "ITInetSocket.h" #import +#import #import #import #import #import #import +#import + +/* Too bad Objective-C doesn't have class variables... */ +static NSMutableSet *servsockets; @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)setupThread; +-(void)stopThread; +-(void)newClient:(int)cfd; +-(void)socketAcceptLoop:(id)data; @end @implementation ITInetServerSocket -- (id)init ++ (void)initialize { - if (self = [super init]) - { - sockfd = 0; - delegate = clients = nil; - } - return self; + servsockets = [[NSMutableSet 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; + dieflag = 0; + rndType = rndName = nil; + timer = 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; + dieflag = 0; + rndType = rndName = nil; + timer = nil; } return self; } - (void)dealloc { - [service stop]; - [service release]; + [self stopConnection]; [clients release]; [delegate release]; - shutdown(sockfd,2); + [rndName release]; + [rndType release]; +} + +- (BOOL)start +{ + if (!rndName || !rndType || !port) return NO; + [ITInetServerSocket registerSocket:self]; + return YES; } - (int)sockfd @@ -79,73 +103,137 @@ { 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 addObject:sock]; +} + ++(void)unregisterSocket:(ITInetServerSocket*)sock +{ + [sock stopConnection]; + [servsockets removeObject:sock]; +} + +-(short)lookupPortForServiceType:(NSString*)name { const char *_name = [name cString]; - struct addrinfo hints,*res; + struct addrinfo *res; + short p; + getaddrinfo(NULL,_name,NULL,&res); + p = ntohs(((struct sockaddr_in *)res->ai_addr)->sin_port); + freeaddrinfo(res); + return p; +} +-(void)setupConnection +{ + struct addrinfo hints, *ai; hints.ai_flags = AI_PASSIVE; - hints.ai_family = PF_INET; + hints.ai_family = PF_INET6; 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); - sockfd = socket(res->ai_family, res->ai_socktype,res->ai_protocol); - bind(sockfd, res->ai_addr, res->ai_addrlen); + hints.ai_canonname = hints.ai_addr = hints.ai_next = NULL; + getaddrinfo(NULL,[[[NSNumber numberWithShort:port] stringValue] cString],&hints,&ai); + bind(sockfd,ai->ai_addr,ai->ai_addrlen); listen(sockfd, SOMAXCONN); - fcntl(sockfd,F_SETFL,O_NONBLOCK); - freeaddrinfo(res); + freeaddrinfo(ai); + [self setupRendezvousAdvertising]; + [self setupThread]; } --(void)setupConnectionWithPortNumber:(NSNumber*)port +- (void)stopConnection { - 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); - bind(sockfd,(struct sockaddr *)&sa,sizeof(sa)); - listen(sockfd, SOMAXCONN); - fcntl(sockfd,F_SETFL,O_NONBLOCK); + [self stopRendezvousAdvertising]; + [clients makeObjectsPerformSelector:@selector(disconnect)]; + shutdown(sockfd,2); + close(sockfd); + sockfd = -1; } -- (void)setupRendezvousAdvertising:(NSString*)name port:(NSNumber*)port +- (void)setupRendezvousAdvertising { - service = [[NSNetService alloc] initWithDomain:@"" type:[NSString stringWithFormat:@"_%@._tcp.",name] port:htons([port shortValue])]; + 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]; } -- (void)setupTimer +- (void)stopRendezvousAdvertising { - NSTimer *timer = [NSTimer timerWithTimeInterval:0 target:self selector:@selector(timerFunc:) userInfo:nil repeats:YES]; - [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; + [service stop]; + [service release]; + service = nil; } -- (void)timerFunc:(NSTimer*)timer +- (void)setupThread { - 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");} - } - else { - ITInetSocket *csocket = [[[ITInetSocket alloc] initWithFD:cfd delegate:self] autorelease]; - [clients addObject:csocket]; - [delegate newClientJoined:csocket]; - + 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)stopThread +{ + dieflag = 1; +} + +- (void)newClient:(int)cfd +{ + ITInetSocket *csocket = [[ITInetSocket alloc] initWithFD:cfd delegate:delegate]; + [clients addObject:csocket]; +} + +- (void)socketAcceptLoop:(id)data +{ + 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 != -1) && !dieflag) + { + signed int cfd; + cfd = accept(sockfd,NULL,NULL); + NSLog(@"Someone connected!"); + [(id)dp newClient:cfd]; } + dieflag = 0; + [dcon release]; + [ap release]; } @end \ No newline at end of file