Mmmmmm..... oneway void
[ITFoundation.git] / ITInetServerSocket.m
1 //
2 //  ITInetServerSocket.m
3 //  ITFoundation
4 //
5 //  Created by Alexander Strange on Thu Feb 13 2003.
6 //  Copyright (c) 2003 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "ITInetServerSocket.h"
10 #import "ITInetSocket.h"
11 #import <sys/types.h>
12 #import <sys/time.h>
13 #import <arpa/inet.h>
14 #import <netinet/in.h>
15 #import <sys/socket.h>
16 #import <netdb.h>
17 #import <fcntl.h>
18 #import <unistd.h>
19
20 /* Too bad Objective-C doesn't have class variables... */
21 static NSMutableSet *servsockets;
22
23 @interface ITInetServerSocket(Private)
24 +(void)registerSocket:(ITInetServerSocket*)sock;
25 +(void)unregisterSocket:(ITInetServerSocket*)sock;
26 -(short)lookupPortForServiceType:(NSString*)name;
27 -(void)setupConnection;
28 -(void)stopConnection;
29 -(void)setupRendezvousAdvertising;
30 -(void)stopRendezvousAdvertising;
31 -(void)setupThread;
32 -(void)stopThread;
33 -(void)newClient:(int)cfd;
34 -(void)socketAcceptLoop:(id)data;
35 @end
36
37 @implementation ITInetServerSocket
38 + (void)initialize
39 {
40     servsockets = [[NSMutableSet alloc] init];
41     //[self setupTimer];
42 }
43
44 - (id)init
45 {
46     if (self = [super init])
47            {
48            sockfd = -1;
49            delegate = nil;
50            clients = [[NSMutableSet alloc] init];
51            service = nil;
52            port = 0;
53            dieflag = 0;
54            rndType = rndName = nil;
55            timer = nil;
56            }
57     return self;
58 }
59
60 - (id)initWithDelegate:(id)d
61 {
62     if (self = [super init])
63            {
64            sockfd = -1;
65            delegate = [d retain];
66            clients = [[NSMutableSet alloc] init];
67            service = nil;
68            port = 0;
69            dieflag = 0;
70            rndType = rndName = nil;
71            timer = nil;
72            }
73     return self;
74 }
75
76 - (void)dealloc
77 {
78     [self stopConnection];
79     [clients release];
80     [delegate release];
81     [rndName release];
82     [rndType release];
83 }
84
85 - (BOOL)start
86 {
87     if (!rndName || !rndType || !port) return NO;
88     [ITInetServerSocket registerSocket:self];
89     return YES;
90 }
91
92 - (int)sockfd
93 {
94     return sockfd;
95 }
96
97 - (NSSet*)clients
98 {
99     return clients;
100 }
101
102 - (id)delegate
103 {
104     return delegate;
105 }
106
107 - (short)port
108 {
109     return port;
110 }
111
112 - (void)stop
113 {
114     [ITInetServerSocket unregisterSocket:self];
115 }
116
117 - (void)setServiceType:(NSString*)type useForPort:(BOOL)p
118 {
119     rndType = [type retain];
120     if (p) {
121            port = [self lookupPortForServiceType:type];
122     }
123 }
124
125 - (void)setServiceName:(NSString*)name
126 {
127     rndName = [name retain];
128 }
129
130 - (void)setPort:(short)p
131 {
132     port = p;
133 }
134 @end
135
136 @implementation ITInetServerSocket(Private)
137 +(void)registerSocket:(ITInetServerSocket*)sock
138 {
139     [sock setupConnection];
140     [servsockets addObject:sock];
141 }
142
143 +(void)unregisterSocket:(ITInetServerSocket*)sock
144 {
145     [sock stopConnection];
146     [servsockets removeObject:sock];
147 }
148
149 -(short)lookupPortForServiceType:(NSString*)name
150 {
151     const char *_name = [name cString];
152     struct addrinfo *res;
153     short p;
154     getaddrinfo(NULL,_name,NULL,&res);
155     p = ntohs(((struct sockaddr_in *)res->ai_addr)->sin_port);
156     freeaddrinfo(res);
157     return p;
158 }
159
160 -(void)setupConnection
161 {
162     struct addrinfo hints, *ai;
163     hints.ai_flags = AI_PASSIVE;
164     hints.ai_family = PF_INET6;
165     hints.ai_socktype = SOCK_STREAM;
166     hints.ai_protocol = IPPROTO_TCP;
167     hints.ai_addrlen = 0;
168     hints.ai_canonname = hints.ai_addr = hints.ai_next = NULL;
169     getaddrinfo(NULL,[[[NSNumber numberWithShort:port] stringValue] cString],&hints,&ai);
170     bind(sockfd,ai->ai_addr,ai->ai_addrlen);
171     listen(sockfd, SOMAXCONN);
172     freeaddrinfo(ai);
173     [self setupRendezvousAdvertising];
174     [self setupThread];
175 }
176
177 - (void)stopConnection
178 {
179     [self stopRendezvousAdvertising];
180     [clients makeObjectsPerformSelector:@selector(disconnect)];
181     shutdown(sockfd,2);
182     close(sockfd);
183     sockfd = -1;
184 }
185
186 - (void)setupRendezvousAdvertising
187 {
188     service = [[NSNetService alloc] initWithDomain:@"" type:[NSString stringWithFormat:@"_%@._tcp.",rndType] name:rndName port:htons(port)];
189     [service publish];
190 }
191
192 - (void)stopRendezvousAdvertising
193 {
194     [service stop];
195     [service release];
196     service = nil;
197 }
198
199 - (void)setupThread
200 {
201     NSPort *p1 = [NSPort port], *p2 = [NSPort port];
202     NSConnection *dcon = [[NSConnection alloc] initWithReceivePort:p1 sendPort:p2];
203     NSArray *par = [NSArray arrayWithObjects:p2,p1,nil];
204     [dcon setRootObject:self];
205     [NSThread detachNewThreadSelector:@selector(socketAcceptLoop:) toTarget:self withObject:par]; 
206 }
207
208 - (void)stopThread
209 {
210     dieflag = 1;
211 }
212
213 - (void)newClient:(int)cfd
214 {
215     ITInetSocket *csocket = [[ITInetSocket alloc] initWithFD:cfd delegate:delegate];
216     [clients addObject:csocket];
217 }
218
219 - (void)socketAcceptLoop:(id)data
220 {
221     NSAutoreleasePool *ap = [[NSAutoreleasePool alloc] init];
222     NSArray *par = data;
223     NSConnection *dcon = [[NSConnection alloc] initWithReceivePort:[par objectAtIndex:0] sendPort:[par objectAtIndex:1]];
224     NSProxy *dp = [dcon rootProxy];
225     while ((sockfd != -1) && !dieflag)
226            {
227            signed int cfd;
228            cfd = accept(sockfd,NULL,NULL);
229            [(id)dp newClient:cfd];
230            }
231     dieflag = 0;
232     [dcon release];
233     [ap release];
234 }
235 @end