Alex did something while Hydraing, and wants me to commit. I don't know
[ITFoundation.git] / ITInetSocket.m
1 //
2 //  ITInetSocket.m
3 //  ITFoundation
4 //
5 //  Created by Alexander Strange on Tue Feb 11 2003.
6 //  Copyright (c) 2003 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "ITInetSocket.h"
10 #import "ITServiceBrowserDelegate.h"
11 #import <sys/socket.h>
12 #import <arpa/inet.h>
13 #import <unistd.h>
14
15 @interface ITInetSocket(Debugging)
16 -(NSString*)dumpv6Addrinfo:(struct addrinfo *)_ai;
17 @end
18
19 @interface ITInetSocket(Private)
20 -(void)doConnSetupWithHost:(NSString*)host namedPort:(NSString*)namedPort;
21 -(void)realDoConnection;
22 -(void)spinoffReadLoop;
23 -(void)socketReadLoop:(id)data;
24 @end
25
26 @implementation ITInetSocket
27 +(void)startAutoconnectingToService:(NSString*)type delegate:(id <ITInetSocketDelegate,NSObject>)d
28 {
29     NSNetServiceBrowser *browse = [[NSNetServiceBrowser alloc] init];
30     ITServiceBrowserDelegate *bd = [[ITServiceBrowserDelegate alloc] initWithDelegate:d];
31
32     [browse setDelegate:bd];
33     [browse searchForServicesOfType:[NSString stringWithFormat:@"_%@._tcp.",type] inDomain:@""];
34 }
35
36 -(id)initWithFD:(int)fd delegate:(id <ITInetSocketDelegate,NSObject>)d
37 {
38     if (self = [super init])
39            {
40            state = ITInetSocketListening;
41            sockfd = fd;
42            delegate = [d retain];
43            port = 0;
44            writePipe = [[ITByteStream alloc] initWithDelegate:self];
45            readPipe = [[ITByteStream alloc] initWithDelegate:d];
46            ai = nil;
47            sarr = nil;
48            bufs = 512;
49            actionflag = dieflag = 0;
50            nc = 0;
51            }
52     [self spinoffReadLoop];
53     return self;
54 }
55
56 -(id)initWithDelegate:(id <ITInetSocketDelegate,NSObject>)d
57 {
58     if (self = [super init])
59            {
60            state = ITInetSocketDisconnected;
61            sockfd = -1;
62            delegate = [d retain];
63            port = 0;
64            writePipe = [[ITByteStream alloc] initWithDelegate:self];
65            readPipe = [[ITByteStream alloc] initWithDelegate:d];
66            ai = nil;
67            sarr = nil;
68            bufs = 512;
69            actionflag = dieflag = 0;
70            nc = 1;
71            }
72     return self;
73 }
74
75
76 -(void) dealloc
77 {
78     shutdown(sockfd,2);
79     [delegate release];
80     [writePipe release];
81     [readPipe release];
82     if (!sarr) freeaddrinfo(ai);
83     [sarr release];
84 }
85
86 -(void) connectToHost:(NSString*)host onPort:(short)thePort
87 {
88     if (state == ITInetSocketDisconnected)
89            {
90            NSString *nport = [[NSNumber numberWithShort:thePort] stringValue];
91            [self doConnSetupWithHost:host namedPort:nport];
92            }
93 }
94
95 -(void) connectToHost:(NSString*)host onNamedPort:(NSString*)_port
96 {
97     if (state == ITInetSocketDisconnected)
98            {
99            [self doConnSetupWithHost:host namedPort:_port];
100            }
101 }
102
103 -(void) connectWithSockaddrArray:(NSArray*)arr
104 {
105     if (state == ITInetSocketDisconnected)
106            {
107            NSEnumerator *e = [arr objectEnumerator];
108            NSData *d;
109            struct addrinfo *a,*oa;
110            ai = malloc(sizeof(struct addrinfo));
111            ai_cur = ai;
112            oa = a = ai;
113            bzero(a,sizeof(struct addrinfo));
114            while (d = [e nextObject])
115            {
116                   struct sockaddr *s = (struct sockaddr*)[d bytes];
117                   bzero(a,sizeof(struct addrinfo));
118                   a->ai_family = s->sa_family;
119                   a->ai_addr = s;
120                   a->ai_next = malloc(sizeof(struct addrinfo));
121                   oa = a;
122                   a = a->ai_next;
123            }
124            free(a);
125            oa->ai_next = NULL;
126            NSLog(@"Sockaddr connecting....");
127            [self dumpv6Addrinfo:ai];
128            [self realDoConnection];
129            }
130 }
131
132 -(void)disconnect
133 {
134     NSLog(@"Got a disconnect");
135     dieflag = 1;
136     do {} while (dieflag == 1);
137 }
138
139 -(void)retryConnection
140 {
141     ai_cur = ai_cur->ai_next?ai_cur->ai_next:ai_cur;
142     [self disconnect];
143     [self realDoConnection];
144 }
145
146 -(ITInetSocketState)state
147 {
148     return state;
149 }
150 -(id <ITInetSocketDelegate>)delegate
151 {
152     return delegate;
153 }
154
155 -(unsigned short)bufferSize
156 {
157     return bufs;
158 }
159
160 -(void)setBufferSize:(unsigned short)_bufs
161 {
162     bufs = _bufs;
163 }
164
165 -(void)newDataAdded:(ITByteStream*)sender
166 {
167 }
168
169 -(ITByteStream*)readPipe {return readPipe;}
170 -(ITByteStream*)writePipe {return writePipe;}
171 @end
172
173 @implementation ITInetSocket(Debugging)
174 -(NSString*)dumpv6Addrinfo:(struct addrinfo *)_ai
175 {
176     const char *cfmt =
177     "{\n"
178     "Flags = %x\n"
179     "Family = %x\n"
180     "Socktype = %x\n"
181     "Protocol = %x\n"
182     "Canonname = %s\n"
183     "Sockaddr = \n"
184     "\t{\n"
185     "\tLength = %x\n"
186     "\tFamily = %x\n"
187     "\tPort = %d\n"
188     "\tFlowinfo = %x\n"
189     "\tAddr = {%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx}\n"
190     "\tScope = %x\n"
191     "\t}\n"
192     "Next = %@\n"
193     "}\n";
194     NSString *nsfmt = [NSString stringWithCString:cfmt];
195     struct sockaddr_in6 *sa = (struct sockaddr_in6 *)_ai->ai_addr;
196     NSString *buf = [[NSMutableString alloc] initWithFormat:nsfmt,_ai->ai_flags,_ai->ai_family,_ai->ai_socktype,_ai->ai_protocol,_ai->ai_canonname?_ai->ai_canonname:"",sa->sin6_len,sa->sin6_family,sa->sin6_port,sa->sin6_flowinfo,sa->sin6_addr.__u6_addr.__u6_addr16[0],sa->sin6_addr.__u6_addr.__u6_addr16[1],sa->sin6_addr.__u6_addr.__u6_addr16[2],sa->sin6_addr.__u6_addr.__u6_addr16[3],sa->sin6_addr.__u6_addr.__u6_addr16[4],sa->sin6_addr.__u6_addr.__u6_addr16[5],sa->sin6_addr.__u6_addr.__u6_addr16[6],sa->sin6_addr.__u6_addr.__u6_addr16[7],sa->sin6_scope_id,_ai->ai_next?[self dumpv6Addrinfo:_ai->ai_next]:@"nil"];
197
198     return buf;
199 }
200 @end
201
202 @implementation ITInetSocket(Private)
203 -(void)doConnSetupWithHost:(NSString*)host namedPort:(NSString*)namedPort
204 {
205     struct addrinfo hints;
206            int err;
207            const char *portNam = [namedPort cString], *hostCStr = [host cString];
208            state = ITInetSocketConnecting;
209            hints.ai_flags = 0;
210            hints.ai_family = PF_UNSPEC;
211            hints.ai_socktype = SOCK_STREAM;
212            hints.ai_protocol = IPPROTO_TCP;
213            hints.ai_addrlen = 0;
214            hints.ai_canonname = NULL;
215            hints.ai_addr = NULL;
216            hints.ai_next = NULL;
217
218            err = getaddrinfo(hostCStr,portNam,&hints,&ai);
219
220            NSLog(@"%s, h %@ p %@",gai_strerror(err),host,namedPort);
221            NSLog(ai?[self dumpv6Addrinfo:ai]:@"");
222            ai_cur = ai;
223            [self realDoConnection];
224 }
225
226 -(void)realDoConnection
227 {
228     sockfd = socket(ai_cur->ai_family,SOCK_STREAM,IPPROTO_TCP);
229     [self spinoffReadLoop];
230 }
231
232 -(void)spinoffReadLoop
233 {
234     NSPort *p1 = [NSPort port], *p2 = [NSPort port];
235     NSConnection *dcon = [[NSConnection alloc] initWithReceivePort:p1 sendPort:p2];
236     NSArray *par = [NSArray arrayWithObjects:p2,p1,nil];
237     [dcon setRootObject:delegate];
238     [NSThread detachNewThreadSelector:@selector(socketReadLoop:) toTarget:self withObject:par]; //spawn read thread
239 }
240
241 -(void)socketReadLoop:(id)data
242 {
243     NSAutoreleasePool *ap = [[NSAutoreleasePool alloc] init];
244     NSConnection *dcon = [[NSConnection alloc] initWithReceivePort:[data objectAtIndex:0] sendPort:[data objectAtIndex:1]];
245     NSProxy *dp = [[dcon rootProxy] retain];
246     char *buf = malloc(bufs);
247     unsigned long readLen = 0,wpl = 0;
248     signed int err;
249     [readPipe setDelegate:(id <ITInetSocketDelegate>)dp];
250     if (nc){
251     NSLog(@"Connecting");
252     err = connect(sockfd,ai_cur->ai_addr,ai_cur->ai_addrlen);
253     if (err == -1)
254            {
255            perror("CAwh");
256            *((char*)NULL) = 12;
257            [(id)dp errorOccured:ITInetCouldNotConnect during:ITInetSocketConnecting onSocket:self];
258            goto dieaction;
259            }
260     }
261     NSLog(@"Sending finishedConnecting");
262     [(id)dp finishedConnecting:self];
263 lstart:
264            state = ITInetSocketListening;
265            while (!actionflag && !dieflag && !(wpl = CFDataGetLength((CFDataRef)writePipe->data)))
266            {
267                   readLen = recv(sockfd,buf,bufs,0);
268                   state = ITInetSocketReading;
269                   if (readLen == -1) {[(id)dp errorOccured:ITInetConnectionDropped during:ITInetSocketReading onSocket:self];goto dieaction;}
270                   if (readLen) {
271                          NSLog(@"recv'd");
272                          NSLog(@"Doing writeData to readPipe");
273                          [readPipe writeBytes:buf len:readLen];
274                          [ap release];
275                          ap = [[NSAutoreleasePool alloc] init];
276                   }
277            }
278            state = ITInetSocketListening;
279     actionflag = 0;
280
281     if (dieflag)
282            {
283 dieaction:
284            state = ITInetSocketDisconnected;
285            perror("Awh");
286            free(buf);
287            shutdown(sockfd,2);
288            [dcon release];
289            [dp release];
290            [ap release];
291            dieflag = 0;
292            return;
293            }
294
295     {
296            const char *d = CFDataGetBytePtr((CFDataRef)writePipe->data);
297            state = ITInetSocketWriting;
298            NSLog(@"Writing");
299            [writePipe lockStream];
300            wpl = send(sockfd,d,wpl,0);
301            [writePipe shortenData:wpl];
302            [writePipe unlockStream];
303            [ap release];
304            ap = [[NSAutoreleasePool alloc] init];
305            goto lstart;
306            }
307     goto dieaction;
308 }
309 @end