Sockets don't quite work, but they will almost work.
[ITFoundation.git] / ITInetServerSocket.m
index f4b9720..08a8fe0 100755 (executable)
@@ -9,6 +9,7 @@
 #import "ITInetServerSocket.h"
 #import "ITInetSocket.h"
 #import <sys/types.h>
+#import <sys/time.h>
 #import <arpa/inet.h>
 #import <netinet/in.h>
 #import <sys/socket.h>
@@ -17,8 +18,7 @@
 #import <unistd.h>
 
 /* Too bad Objective-C doesn't have class variables... */
-static NSMutableDictionary *servsockets;
-static NSTimer *timer;
+static NSMutableSet *servsockets;
 
 @interface ITInetServerSocket(Private)
 +(void)registerSocket:(ITInetServerSocket*)sock;
@@ -28,17 +28,17 @@ static NSTimer *timer;
 -(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];
+    servsockets = [[NSMutableSet alloc] init];
+    //[self setupTimer];
 }
 
 - (id)init
@@ -50,7 +50,9 @@ static NSTimer *timer;
           clients = [[NSMutableSet alloc] init];
           service = nil;
           port = 0;
+          dieflag = 0;
           rndType = rndName = nil;
+          timer = nil;
           }
     return self;
 }
@@ -64,7 +66,9 @@ static NSTimer *timer;
           clients = [[NSMutableSet alloc] init];
           service = nil;
           port = 0;
+          dieflag = 0;
           rndType = rndName = nil;
+          timer = nil;
           }
     return self;
 }
@@ -78,7 +82,7 @@ static NSTimer *timer;
     [rndType release];
 }
 
-- (BOOL)registerSocket
+- (BOOL)start
 {
     if (!rndName || !rndType || !port) return NO;
     [ITInetServerSocket registerSocket:self];
@@ -133,31 +137,21 @@ static NSTimer *timer;
 +(void)registerSocket:(ITInetServerSocket*)sock
 {
     [sock setupConnection];
-    [servsockets setObject:sock forKey:[NSString stringWithFormat:@"%lu",[sock port]]];
+    [servsockets addObject:sock];
 }
 
 +(void)unregisterSocket:(ITInetServerSocket*)sock
 {
     [sock stopConnection];
-    [servsockets removeObjectForKey:[NSString stringWithFormat:@"%lu",[sock port]]];
+    [servsockets removeObject:sock];
 }
 
 -(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,16 +159,19 @@ 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);
+    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
@@ -188,7 +185,9 @@ static NSTimer *timer;
 
 - (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 +198,42 @@ 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;
+    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];
+    [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 != -1) && !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];
           }
-    return NO;
+    dieflag = 0;
+    [dcon release];
+    [ap release];
 }
 @end
\ No newline at end of file