Mmmmmm..... oneway void
[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:nil];
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            }
51     return self;
52 }
53
54 -(id)initWithDelegate:(id <ITInetSocketDelegate,NSObject>)d
55 {
56     if (self = [super init])
57            {
58            state = ITInetSocketDisconnected;
59            sockfd = -1;
60            delegate = [d retain];
61            port = 0;
62            writePipe = [[ITByteStream alloc] initWithDelegate:self];
63            readPipe = [[ITByteStream alloc] initWithDelegate:d];
64            ai = nil;
65            sarr = nil;
66            bufs = 512;
67            actionflag = dieflag = 0;
68            }
69     return self;
70 }
71
72
73 -(void) dealloc
74 {
75     shutdown(sockfd,2);
76     [delegate release];
77     [writePipe release];
78     [readPipe release];
79     if (!sarr) freeaddrinfo(ai);
80     [sarr release];
81 }
82
83 -(void) connectToHost:(NSString*)host onPort:(short)thePort
84 {
85     if (state == ITInetSocketDisconnected)
86            {
87            NSString *nport = [[NSNumber numberWithShort:thePort] stringValue];
88            [self doConnSetupWithHost:host namedPort:nport];
89            }
90 }
91
92 -(void) connectToHost:(NSString*)host onNamedPort:(NSString*)_port
93 {
94     if (state == ITInetSocketDisconnected)
95            {
96            [self doConnSetupWithHost:host namedPort:_port];
97            }
98 }
99
100 -(void) connectWithSockaddrArray:(NSArray*)arr
101 {
102     if (state == ITInetSocketDisconnected)
103            {
104            NSEnumerator *e = [arr objectEnumerator];
105            NSData *d;
106            struct addrinfo *a;
107            ai = malloc(sizeof(struct addrinfo));
108            a = ai;
109            while (d = [e nextObject])
110            {
111                   struct sockaddr *s = (struct sockaddr*)[d bytes];
112                   a->ai_family = s->sa_family;
113                   a->ai_addr = s;
114                   a->ai_next = malloc(sizeof(struct addrinfo));
115                   a = a->ai_next;
116            }
117            ai_cur = ai;
118            [self realDoConnection];
119            }
120 }
121
122 -(void)disconnect
123 {
124     NSLog(@"Got a disconnect");
125     dieflag = 1;
126 }
127
128 -(void)retryConnection
129 {
130     ai_cur = ai_cur->ai_next?ai_cur->ai_next:ai_cur;
131     [self disconnect];
132     [self realDoConnection];
133 }
134
135 -(ITInetSocketState)state
136 {
137     return state;
138 }
139 -(id <ITInetSocketDelegate>)delegate
140 {
141     return delegate;
142 }
143
144 -(unsigned short)bufferSize
145 {
146     return bufs;
147 }
148
149 -(void)setBufferSize:(unsigned short)_bufs
150 {
151     bufs = _bufs;
152 }
153
154 -(void)newDataAdded:(ITByteStream*)sender
155 {
156     NSLog(@"writePipe got something");
157     actionflag = 1;
158     do {} while (actionflag == 1);
159     NSLog(@"thread saw actionFlag");
160 }
161 @end
162
163 @implementation ITInetSocket(Debugging)
164 -(NSString*)dumpv6Addrinfo:(struct addrinfo *)_ai
165 {
166     const char *cfmt =
167     "{\n"
168     "Flags = %x\n"
169     "Family = %x\n"
170     "Socktype = %x\n"
171     "Protocol = %x\n"
172     "Canonname = %s\n"
173     "Sockaddr = \n"
174     "\t{\n"
175     "\tLength = %x\n"
176     "\tFamily = %x\n"
177     "\tPort = %d\n"
178     "\tFlowinfo = %x\n"
179     "\tAddr = {%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx}\n"
180     "\tScope = %x\n"
181     "\t}\n"
182     "Next = %@\n"
183     "}\n";
184     NSString *nsfmt = [NSString stringWithCString:cfmt];
185     struct sockaddr_in6 *sa = (struct sockaddr_in6 *)_ai->ai_addr;
186     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"];
187
188     return buf;
189 }
190 @end
191
192 @implementation ITInetSocket(Private)
193 -(void)doConnSetupWithHost:(NSString*)host namedPort:(NSString*)namedPort
194 {
195     struct addrinfo hints;
196            int err;
197            const char *portNam = [namedPort cString], *hostCStr = [host cString];
198            state = ITInetSocketConnecting;
199            hints.ai_flags = 0;
200            hints.ai_family = PF_UNSPEC;
201            hints.ai_socktype = SOCK_STREAM;
202            hints.ai_protocol = IPPROTO_TCP;
203            hints.ai_addrlen = 0;
204            hints.ai_canonname = NULL;
205            hints.ai_addr = NULL;
206            hints.ai_next = NULL;
207
208            err = getaddrinfo(hostCStr,portNam,&hints,&ai);
209
210            NSLog(@"%s, h %@ p %@",gai_strerror(err),host,namedPort);
211            NSLog(ai?[self dumpv6Addrinfo:ai]:@"");
212            ai_cur = ai;
213            [self realDoConnection];
214 }
215
216 -(void)realDoConnection
217 {
218     sockfd = socket(ai_cur->ai_addr->sa_family,SOCK_STREAM,IPPROTO_TCP);
219     [self spinoffReadLoop];
220 }
221
222 -(void)spinoffReadLoop
223 {
224     NSPort *p1 = [NSPort port], *p2 = [NSPort port];
225     NSConnection *dcon = [[NSConnection alloc] initWithReceivePort:p1 sendPort:p2];
226     NSArray *par = [NSArray arrayWithObjects:p2,p1,nil];
227     [dcon setRootObject:delegate];
228     [NSThread detachNewThreadSelector:@selector(socketReadLoop:) toTarget:self withObject:par]; //spawn read thread
229 }
230
231 -(void)socketReadLoop:(id)data
232 {
233     NSAutoreleasePool *ap = [[NSAutoreleasePool alloc] init];
234     NSConnection *dcon = [[NSConnection alloc] initWithReceivePort:[data objectAtIndex:0] sendPort:[data objectAtIndex:1]];
235     NSProxy *dp = [[dcon rootProxy] retain];
236     char *buf = malloc(bufs);
237     unsigned long readLen = 0;
238     signed int err;
239     [readPipe setDelegate:dp];
240     NSLog(@"Connecting");
241     err = connect(sockfd,ai_cur->ai_addr,ai_cur->ai_addrlen);
242     if (err == -1)
243            {
244            perror("CAwh");
245            [(id)dp errorOccured:ITInetCouldNotConnect during:ITInetSocketConnecting onSocket:self];
246            goto dieaction;
247            }
248     NSLog(@"Sending finishedConnecting");
249     [(id)dp finishedConnecting:self];
250 lstart:
251            state = ITInetSocketListening;
252            while (!actionflag && !dieflag)
253            {
254                   readLen = recv(sockfd,buf,bufs,0);
255                   state = ITInetSocketReading;
256                   if (readLen == -1) {[(id)dp errorOccured:ITInetConnectionDropped during:ITInetSocketReading onSocket:self];goto dieaction;}
257                   if (readLen) {
258                          NSLog(@"recv'd");
259                          NSLog(@"Doing writeData to readPipe");
260                          [readPipe writeBytes:buf len:readLen];
261                          [ap release];
262                          ap = [[NSAutoreleasePool alloc] init];
263                   }
264            }
265            state = ITInetSocketListening;
266     actionflag = 0;
267
268     if (dieflag)
269            {
270 dieaction:
271            state = ITInetSocketDisconnected;
272            perror("Awh");
273            free(buf);
274            shutdown(sockfd,2);
275            [dcon release];
276            [dp release];
277            [ap release];
278            dieflag = 0;
279            return;
280            }
281
282     {
283            state = ITInetSocketWriting;
284            NSLog(@"Emptying writePipe");
285            NSData *d = [writePipe readAllData];
286            write(sockfd,[d bytes],[d length]);
287            [ap release];
288            ap = [[NSAutoreleasePool alloc] init];
289            goto lstart;
290            }
291     goto dieaction;
292 }
293 @end