OSDN Git Service

Adding a localAddress and connectedAddress method
[syncr/master.git] / CocoaAsyncSocket / CocoaAsyncSocket-5.2.1 / AsyncSocket.m
1 //
2 //  AsyncSocket.m
3 //  
4 //  This class is in the public domain.
5 //  Originally created by Dustin Voss on Wed Jan 29 2003.
6 //  Updated and maintained by Deusty Designs and the Mac development community.
7 //
8 //  http://code.google.com/p/cocoaasyncsocket/
9 //
10
11 #import "AsyncSocket.h"
12 #import <sys/socket.h>
13 #import <netinet/in.h>
14 #import <arpa/inet.h>
15 #import <netdb.h>
16
17 #if TARGET_OS_IPHONE
18 // Note: You may need to add the CFNetwork Framework to your project
19 #import <CFNetwork/CFNetwork.h>
20 #endif
21
22 #pragma mark Declarations
23
24 #define DEFAULT_PREBUFFERING YES        // Whether pre-buffering is enabled by default
25
26 #define READQUEUE_CAPACITY      5           // Initial capacity
27 #define WRITEQUEUE_CAPACITY 5           // Initial capacity
28 #define READALL_CHUNKSIZE       256         // Incremental increase in buffer size
29 #define WRITE_CHUNKSIZE    (1024 * 4)   // Limit on size of each write pass
30
31 NSString *const AsyncSocketException = @"AsyncSocketException";
32 NSString *const AsyncSocketErrorDomain = @"AsyncSocketErrorDomain";
33
34 // Mutex lock used by all instances of AsyncSocket, to protect getaddrinfo.
35 // The man page says it is not thread-safe. (As of Mac OS X 10.4.7, and possibly earlier)
36 static NSString *getaddrinfoLock = @"lock";
37
38 enum AsyncSocketFlags
39 {
40         kEnablePreBuffering      = 1 << 0,  // If set, pre-buffering is enabled
41         kDidPassConnectMethod    = 1 << 1,  // If set, disconnection results in delegate call
42         kDidCallConnectDelegate  = 1 << 2,  // If set, connect delegate has been called
43         kStartingTLS             = 1 << 3,  // If set, we're waiting for TLS negotiation to complete
44         kForbidReadsWrites       = 1 << 4,  // If set, no new reads or writes are allowed
45         kDisconnectAfterReads    = 1 << 5,  // If set, disconnect after no more reads are queued
46         kDisconnectAfterWrites   = 1 << 6,  // If set, disconnect after no more writes are queued
47         kClosingWithError        = 1 << 7,  // If set, the socket is being closed due to an error
48 };
49
50 @interface AsyncSocket (Private)
51
52 // Socket Implementation
53 - (CFSocketRef) createAcceptSocketForAddress:(NSData *)addr error:(NSError **)errPtr;
54 - (BOOL) createSocketForAddress:(NSData *)remoteAddr error:(NSError **)errPtr;
55 - (BOOL) attachSocketsToRunLoop:(NSRunLoop *)runLoop error:(NSError **)errPtr;
56 - (BOOL) configureSocketAndReturnError:(NSError **)errPtr;
57 - (BOOL) connectSocketToAddress:(NSData *)remoteAddr error:(NSError **)errPtr;
58 - (void) doAcceptWithSocket:(CFSocketNativeHandle)newSocket;
59 - (void) doSocketOpen:(CFSocketRef)sock withCFSocketError:(CFSocketError)err;
60
61 // Stream Implementation
62 - (BOOL) createStreamsFromNative:(CFSocketNativeHandle)native error:(NSError **)errPtr;
63 - (BOOL) createStreamsToHost:(NSString *)hostname onPort:(UInt16)port error:(NSError **)errPtr;
64 - (BOOL) attachStreamsToRunLoop:(NSRunLoop *)runLoop error:(NSError **)errPtr;
65 - (BOOL) configureStreamsAndReturnError:(NSError **)errPtr;
66 - (BOOL) openStreamsAndReturnError:(NSError **)errPtr;
67 - (void) doStreamOpen;
68 - (BOOL) setSocketFromStreamsAndReturnError:(NSError **)errPtr;
69
70 // Disconnect Implementation
71 - (void) closeWithError:(NSError *)err;
72 - (void) recoverUnreadData;
73 - (void) emptyQueues;
74 - (void) close;
75
76 // Errors
77 - (NSError *) getErrnoError;
78 - (NSError *) getAbortError;
79 - (NSError *) getStreamError;
80 - (NSError *) getSocketError;
81 - (NSError *) getReadMaxedOutError;
82 - (NSError *) getReadTimeoutError;
83 - (NSError *) getWriteTimeoutError;
84 - (NSError *) errorFromCFStreamError:(CFStreamError)err;
85
86 // Diagnostics
87 - (BOOL) isSocketConnected;
88 - (BOOL) areStreamsConnected;
89 - (NSString *) connectedHost: (CFSocketRef)socket;
90 - (UInt16) connectedPort: (CFSocketRef)socket;
91 - (NSString *) localHost: (CFSocketRef)socket;
92 - (UInt16) localPort: (CFSocketRef)socket;
93 - (NSString *) addressHost: (CFDataRef)cfaddr;
94 - (UInt16) addressPort: (CFDataRef)cfaddr;
95
96 // Reading
97 - (void) doBytesAvailable;
98 - (void) completeCurrentRead;
99 - (void) endCurrentRead;
100 - (void) scheduleDequeueRead;
101 - (void) maybeDequeueRead;
102 - (void) doReadTimeout:(NSTimer *)timer;
103
104 // Writing
105 - (void) doSendBytes;
106 - (void) completeCurrentWrite;
107 - (void) endCurrentWrite;
108 - (void) scheduleDequeueWrite;
109 - (void) maybeDequeueWrite;
110 - (void) maybeScheduleDisconnect;
111 - (void) doWriteTimeout:(NSTimer *)timer;
112
113 // Security
114 - (void)maybeStartTLS;
115 - (void)onTLSStarted:(BOOL)flag;
116
117 // Callbacks
118 - (void) doCFCallback:(CFSocketCallBackType)type forSocket:(CFSocketRef)sock withAddress:(NSData *)address withData:(const void *)pData;
119 - (void) doCFReadStreamCallback:(CFStreamEventType)type forStream:(CFReadStreamRef)stream;
120 - (void) doCFWriteStreamCallback:(CFStreamEventType)type forStream:(CFWriteStreamRef)stream;
121
122 @end
123
124 static void MyCFSocketCallback (CFSocketRef, CFSocketCallBackType, CFDataRef, const void *, void *);
125 static void MyCFReadStreamCallback (CFReadStreamRef stream, CFStreamEventType type, void *pInfo);
126 static void MyCFWriteStreamCallback (CFWriteStreamRef stream, CFStreamEventType type, void *pInfo);
127
128 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
129 #pragma mark -
130 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
131
132 /**
133  * The AsyncReadPacket encompasses the instructions for any given read.
134  * The content of a read packet allows the code to determine if we're:
135  *  - reading to a certain length
136  *  - reading to a certain separator
137  *  - or simply reading the first chunk of available data
138 **/
139 @interface AsyncReadPacket : NSObject
140 {
141   @public
142         NSMutableData *buffer;
143         CFIndex bytesDone;
144         NSTimeInterval timeout;
145         CFIndex maxLength;
146         long tag;
147         NSData *term;
148         BOOL readAllAvailableData;
149 }
150 - (id)initWithData:(NSMutableData *)d
151                    timeout:(NSTimeInterval)t
152                            tag:(long)i
153   readAllAvailable:(BOOL)a
154                 terminator:(NSData *)e
155                  maxLength:(CFIndex)m;
156
157 - (unsigned)readLengthForTerm;
158
159 - (unsigned)prebufferReadLengthForTerm;
160 - (CFIndex)searchForTermAfterPreBuffering:(CFIndex)numBytes;
161 @end
162
163 @implementation AsyncReadPacket
164
165 - (id)initWithData:(NSMutableData *)d
166                    timeout:(NSTimeInterval)t
167                            tag:(long)i
168   readAllAvailable:(BOOL)a
169                 terminator:(NSData *)e
170          maxLength:(CFIndex)m
171 {
172         if(self = [super init])
173         {
174                 buffer = [d retain];
175                 timeout = t;
176                 tag = i;
177                 readAllAvailableData = a;
178                 term = [e copy];
179                 bytesDone = 0;
180                 maxLength = m;
181         }
182         return self;
183 }
184
185 /**
186  * For read packets with a set terminator, returns the safe length of data that can be read
187  * without going over a terminator, or the maxLength.
188  * 
189  * It is assumed the terminator has not already been read.
190 **/
191 - (unsigned)readLengthForTerm
192 {
193         NSAssert(term != nil, @"Searching for term in data when there is no term.");
194         
195         // What we're going to do is look for a partial sequence of the terminator at the end of the buffer.
196         // If a partial sequence occurs, then we must assume the next bytes to arrive will be the rest of the term,
197         // and we can only read that amount.
198         // Otherwise, we're safe to read the entire length of the term.
199         
200         unsigned result = [term length];
201         
202         // Shortcut when term is a single byte
203         if(result == 1) return result;
204         
205         // i = index within buffer at which to check data
206         // j = length of term to check against
207         
208         // Note: Beware of implicit casting rules
209         // This could give you -1: MAX(0, (0 - [term length] + 1));
210         
211         CFIndex i = MAX(0, (CFIndex)(bytesDone - [term length] + 1));
212         CFIndex j = MIN([term length] - 1, bytesDone);
213         
214         while(i < bytesDone)
215         {
216                 const void *subBuffer = [buffer bytes] + i;
217                 
218                 if(memcmp(subBuffer, [term bytes], j) == 0)
219                 {
220                         result = [term length] - j;
221                         break;
222                 }
223                 
224                 i++;
225                 j--;
226         }
227         
228         if(maxLength > 0)
229                 return MIN(result, (maxLength - bytesDone));
230         else
231                 return result;
232 }
233
234 /**
235  * Assuming pre-buffering is enabled, returns the amount of data that can be read
236  * without going over the maxLength.
237 **/
238 - (unsigned)prebufferReadLengthForTerm
239 {
240         if(maxLength > 0)
241                 return MIN(READALL_CHUNKSIZE, (maxLength - bytesDone));
242         else
243                 return READALL_CHUNKSIZE;
244 }
245
246 /**
247  * For read packets with a set terminator, scans the packet buffer for the term.
248  * It is assumed the terminator had not been fully read prior to the new bytes.
249  * 
250  * If the term is found, the number of excess bytes after the term are returned.
251  * If the term is not found, this method will return -1.
252  * 
253  * Note: A return value of zero means the term was found at the very end.
254 **/
255 - (CFIndex)searchForTermAfterPreBuffering:(CFIndex)numBytes
256 {
257         NSAssert(term != nil, @"Searching for term in data when there is no term.");
258         
259         // We try to start the search such that the first new byte read matches up with the last byte of the term.
260         // We continue searching forward after this until the term no longer fits into the buffer.
261         
262         // Note: Beware of implicit casting rules
263         // This could give you -1: MAX(0, 1 - 1 - [term length] + 1);
264         
265         CFIndex i = MAX(0, (CFIndex)(bytesDone - numBytes - [term length] + 1));
266         
267         while(i + [term length] <= bytesDone)
268         {
269                 const void *subBuffer = [buffer bytes] + i;
270                 
271                 if(memcmp(subBuffer, [term bytes], [term length]) == 0)
272                 {
273                         return bytesDone - (i + [term length]);
274                 }
275                 
276                 i++;
277         }
278         
279         return -1;
280 }
281
282 - (void)dealloc
283 {
284         [buffer release];
285         [term release];
286         [super dealloc];
287 }
288
289 @end
290
291 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
292 #pragma mark -
293 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
294
295 /**
296  * The AsyncWritePacket encompasses the instructions for any given write.
297 **/
298 @interface AsyncWritePacket : NSObject
299 {
300   @public
301         NSData *buffer;
302         CFIndex bytesDone;
303         long tag;
304         NSTimeInterval timeout;
305 }
306 - (id)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i;
307 @end
308
309 @implementation AsyncWritePacket
310
311 - (id)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i
312 {
313         if(self = [super init])
314         {
315                 buffer = [d retain];
316                 timeout = t;
317                 tag = i;
318                 bytesDone = 0;
319         }
320         return self;
321 }
322
323 - (void)dealloc
324 {
325         [buffer release];
326         [super dealloc];
327 }
328
329 @end
330
331 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
332 #pragma mark -
333 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
334
335 /**
336  * The AsyncSpecialPacket encompasses special instructions for interruptions in the read/write queues.
337  * This class my be altered to support more than just TLS in the future.
338 **/
339 @interface AsyncSpecialPacket : NSObject
340 {
341   @public
342         NSDictionary *tlsSettings;
343 }
344 - (id)initWithTLSSettings:(NSDictionary *)settings;
345 @end
346
347 @implementation AsyncSpecialPacket
348
349 - (id)initWithTLSSettings:(NSDictionary *)settings
350 {
351         if(self = [super init])
352         {
353                 tlsSettings = [settings copy];
354         }
355         return self;
356 }
357
358 - (void)dealloc
359 {
360         [tlsSettings release];
361         [super dealloc];
362 }
363
364 @end
365
366 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
367 #pragma mark -
368 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
369
370 @implementation AsyncSocket
371
372 - (id)init
373 {
374         return [self initWithDelegate:nil userData:0];
375 }
376
377 - (id)initWithDelegate:(id)delegate
378 {
379         return [self initWithDelegate:delegate userData:0];
380 }
381
382 // Designated initializer.
383 - (id)initWithDelegate:(id)delegate userData:(long)userData
384 {
385         if(self = [super init])
386         {
387                 theFlags = DEFAULT_PREBUFFERING ? kEnablePreBuffering : 0x00;
388                 theDelegate = delegate;
389                 theUserData = userData;
390                 
391                 theSocket = NULL;
392                 theSource = NULL;
393                 theSocket6 = NULL;
394                 theSource6 = NULL;
395                 theRunLoop = NULL;
396                 theReadStream = NULL;
397                 theWriteStream = NULL;
398                 
399                 theReadQueue = [[NSMutableArray alloc] initWithCapacity:READQUEUE_CAPACITY];
400                 theCurrentRead = nil;
401                 theReadTimer = nil;
402                 
403                 partialReadBuffer = [[NSMutableData alloc] initWithCapacity:READALL_CHUNKSIZE];
404                 
405                 theWriteQueue = [[NSMutableArray alloc] initWithCapacity:WRITEQUEUE_CAPACITY];
406                 theCurrentWrite = nil;
407                 theWriteTimer = nil;
408                 
409                 // Socket context
410                 NSAssert(sizeof(CFSocketContext) == sizeof(CFStreamClientContext), @"CFSocketContext != CFStreamClientContext");
411                 theContext.version = 0;
412                 theContext.info = self;
413                 theContext.retain = nil;
414                 theContext.release = nil;
415                 theContext.copyDescription = nil;
416                 
417                 // Default run loop modes
418                 theRunLoopModes = [[NSArray arrayWithObject:NSDefaultRunLoopMode] retain];
419         }
420         return self;
421 }
422
423 // The socket may been initialized in a connected state and auto-released, so this should close it down cleanly.
424 - (void)dealloc
425 {
426         [self close];
427         [theReadQueue release];
428         [theWriteQueue release];
429         [theRunLoopModes release];
430         [NSObject cancelPreviousPerformRequestsWithTarget:theDelegate selector:@selector(onSocketDidDisconnect:) object:self];
431         [NSObject cancelPreviousPerformRequestsWithTarget:self];
432         [super dealloc];
433 }
434
435 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
436 #pragma mark Accessors
437 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
438
439 - (long)userData
440 {
441         return theUserData;
442 }
443
444 - (void)setUserData:(long)userData
445 {
446         theUserData = userData;
447 }
448
449 - (id)delegate
450 {
451         return theDelegate;
452 }
453
454 - (void)setDelegate:(id)delegate
455 {
456         theDelegate = delegate;
457 }
458
459 - (BOOL)canSafelySetDelegate
460 {
461         return ([theReadQueue count] == 0 && [theWriteQueue count] == 0 && theCurrentRead == nil && theCurrentWrite == nil);
462 }
463
464 - (CFSocketRef)getCFSocket
465 {
466         if(theSocket)
467                 return theSocket;
468         else
469                 return theSocket6;
470 }
471
472 - (CFReadStreamRef)getCFReadStream
473 {
474         return theReadStream;
475 }
476
477 - (CFWriteStreamRef)getCFWriteStream
478 {
479         return theWriteStream;
480 }
481
482 - (float)progressOfReadReturningTag:(long *)tag bytesDone:(CFIndex *)done total:(CFIndex *)total
483 {
484         // Check to make sure we're actually reading something right now
485         if (!theCurrentRead) return NAN;
486         
487         // It's only possible to know the progress of our read if we're reading to a certain length
488         // If we're reading to data, we of course have no idea when the data will arrive
489         // If we're reading to timeout, then we have no idea when the next chunk of data will arrive.
490         BOOL hasTotal = (theCurrentRead->readAllAvailableData == NO && theCurrentRead->term == nil);
491         
492         CFIndex d = theCurrentRead->bytesDone;
493         CFIndex t = hasTotal ? [theCurrentRead->buffer length] : 0;
494         if (tag != NULL)   *tag = theCurrentRead->tag;
495         if (done != NULL)  *done = d;
496         if (total != NULL) *total = t;
497         float ratio = (float)d/(float)t;
498         return isnan(ratio) ? 1.0 : ratio; // 0 of 0 bytes is 100% done.
499 }
500
501 - (float)progressOfWriteReturningTag:(long *)tag bytesDone:(CFIndex *)done total:(CFIndex *)total
502 {
503         if (!theCurrentWrite) return NAN;
504         CFIndex d = theCurrentWrite->bytesDone;
505         CFIndex t = [theCurrentWrite->buffer length];
506         if (tag != NULL)   *tag = theCurrentWrite->tag;
507         if (done != NULL)  *done = d;
508         if (total != NULL) *total = t;
509         return (float)d/(float)t;
510 }
511
512 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
513 #pragma mark Configuration
514 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
515
516 /**
517  * See the header file for a full explanation of pre-buffering.
518 **/
519 - (void)enablePreBuffering
520 {
521         theFlags |= kEnablePreBuffering;
522 }
523
524 /**
525  * See the header file for a full explanation of this method.
526 **/
527 - (BOOL)moveToRunLoop:(NSRunLoop *)runLoop
528 {
529         NSAssert((theRunLoop == CFRunLoopGetCurrent()), @"moveToRunLoop must be called from within the current RunLoop!");
530         
531         if(runLoop == nil)
532         {
533                 return NO;
534         }
535         if(theRunLoop == [runLoop getCFRunLoop])
536         {
537                 return YES;
538         }
539         
540         int i;
541         
542         [NSObject cancelPreviousPerformRequestsWithTarget:self];
543         
544         if(theReadStream && theWriteStream)
545         {
546                 for(i = 0; i < [theRunLoopModes count]; i++)
547                 {
548                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
549                         
550                         CFReadStreamUnscheduleFromRunLoop(theReadStream, theRunLoop, runLoopMode);
551                         CFWriteStreamUnscheduleFromRunLoop(theWriteStream, theRunLoop, runLoopMode);
552                 }
553                 CFReadStreamSetClient(theReadStream, kCFStreamEventNone, NULL, NULL);
554                 CFWriteStreamSetClient(theWriteStream, kCFStreamEventNone, NULL, NULL);
555         }
556         if(theSource)
557         {
558                 for(i = 0; i < [theRunLoopModes count]; i++)
559                 {
560                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
561                         CFRunLoopRemoveSource(theRunLoop, theSource, runLoopMode);
562                 }
563         }
564         if(theSource6)
565         {
566                 for(i = 0; i < [theRunLoopModes count]; i++)
567                 {
568                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
569                         CFRunLoopRemoveSource(theRunLoop, theSource6, runLoopMode);
570                 }
571         }
572         if(theReadTimer)
573         {
574                 // We do not retain the read timer - it gets retained by the runloop when we add it as a source.
575                 // Since we're about to remove it as a source, we retain it now, and release it again below.
576                 [theReadTimer retain];
577                 
578                 for(i = 0; i < [theRunLoopModes count]; i++)
579                 {
580                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
581                         CFRunLoopRemoveTimer(theRunLoop, (CFRunLoopTimerRef)theReadTimer, runLoopMode);
582                 }
583         }
584         if(theWriteTimer)
585         {
586                 // We do not retain the write timer - it gets retained by the runloop when we add it as a source.
587                 // Since we're about to remove it as a source, we retain it now, and release it again below.
588                 [theWriteTimer retain];
589                 
590                 for(i = 0; i < [theRunLoopModes count]; i++)
591                 {
592                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
593                         CFRunLoopRemoveTimer(theRunLoop, (CFRunLoopTimerRef)theWriteTimer, runLoopMode);
594                 }
595         }
596         
597         theRunLoop = [runLoop getCFRunLoop];
598         
599         if(theSource)
600         {
601                 for(i = 0; i < [theRunLoopModes count]; i++)
602                 {
603                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
604                         CFRunLoopAddSource(theRunLoop, theSource, runLoopMode);
605                 }
606         }
607         if(theSource6)
608         {
609                 for(i = 0; i < [theRunLoopModes count]; i++)
610                 {
611                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
612                         CFRunLoopAddSource(theRunLoop, theSource6, runLoopMode);
613                 }
614         }
615         if(theReadStream && theWriteStream)
616         {
617                 if(![self attachStreamsToRunLoop:runLoop error:nil])
618                 {
619                         return NO;
620                 }
621         }
622         if(theReadTimer)
623         {
624                 for(i = 0; i < [theRunLoopModes count]; i++)
625                 {
626                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
627                         CFRunLoopAddTimer(theRunLoop, (CFRunLoopTimerRef)theReadTimer, runLoopMode);
628                 }
629                 
630                 // Release here since we retained it above
631                 [theReadTimer release];
632         }
633         if(theWriteTimer)
634         {
635                 for(i = 0; i < [theRunLoopModes count]; i++)
636                 {
637                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
638                         CFRunLoopAddTimer(theRunLoop, (CFRunLoopTimerRef)theWriteTimer, runLoopMode);
639                 }
640                 
641                 // Release here since we retained it above
642                 [theWriteTimer release];
643         }
644         
645         [runLoop performSelector:@selector(maybeDequeueRead) target:self argument:nil order:0 modes:theRunLoopModes];
646         [runLoop performSelector:@selector(maybeDequeueWrite) target:self argument:nil order:0 modes:theRunLoopModes];
647         [runLoop performSelector:@selector(maybeScheduleDisconnect) target:self argument:nil order:0 modes:theRunLoopModes];
648         
649         return YES;
650 }
651
652 /**
653  * See the header file for a full explanation of this method.
654 **/
655 - (BOOL)setRunLoopModes:(NSArray *)runLoopModes
656 {
657         if([runLoopModes count] == 0)
658         {
659                 return NO;
660         }
661         if([theRunLoopModes isEqualToArray:runLoopModes])
662         {
663                 return YES;
664         }
665         
666         int i;
667         
668         [NSObject cancelPreviousPerformRequestsWithTarget:self];
669         
670         if(theReadStream && theWriteStream)
671         {
672                 for(i = 0; i < [theRunLoopModes count]; i++)
673                 {
674                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
675                         
676                         CFReadStreamUnscheduleFromRunLoop(theReadStream, theRunLoop, runLoopMode);
677                         CFWriteStreamUnscheduleFromRunLoop(theWriteStream, theRunLoop, runLoopMode);
678                 }
679                 CFReadStreamSetClient(theReadStream, kCFStreamEventNone, NULL, NULL);
680                 CFWriteStreamSetClient(theWriteStream, kCFStreamEventNone, NULL, NULL);
681         }
682         if(theSource)
683         {
684                 for(i = 0; i < [theRunLoopModes count]; i++)
685                 {
686                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
687                         CFRunLoopRemoveSource(theRunLoop, theSource, runLoopMode);
688                 }
689         }
690         if(theSource6)
691         {
692                 for(i = 0; i < [theRunLoopModes count]; i++)
693                 {
694                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
695                         CFRunLoopRemoveSource(theRunLoop, theSource6, runLoopMode);
696                 }
697         }
698         if(theReadTimer)
699         {
700                 // We do not retain the read timer - it gets retained by the runloop when we add it as a source.
701                 // Since we're about to remove it as a source, we retain it now, and release it again below.
702                 [theReadTimer retain];
703                 
704                 for(i = 0; i < [theRunLoopModes count]; i++)
705                 {
706                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
707                         CFRunLoopRemoveTimer(theRunLoop, (CFRunLoopTimerRef)theReadTimer, runLoopMode);
708                 }
709         }
710         if(theWriteTimer)
711         {
712                 // We do not retain the write timer - it gets retained by the runloop when we add it as a source.
713                 // Since we're about to remove it as a source, we retain it now, and release it again below.
714                 [theWriteTimer retain];
715                 
716                 for(i = 0; i < [theRunLoopModes count]; i++)
717                 {
718                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
719                         CFRunLoopRemoveTimer(theRunLoop, (CFRunLoopTimerRef)theWriteTimer, runLoopMode);
720                 }
721         }
722         
723         [theRunLoopModes release];
724         theRunLoopModes = [runLoopModes copy];
725         
726         if(theSource)
727         {
728                 for(i = 0; i < [theRunLoopModes count]; i++)
729                 {
730                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
731                         CFRunLoopAddSource(theRunLoop, theSource, runLoopMode);
732                 }
733         }
734         if(theSource6)
735         {
736                 for(i = 0; i < [theRunLoopModes count]; i++)
737                 {
738                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
739                         CFRunLoopAddSource(theRunLoop, theSource6, runLoopMode);
740                 }
741         }
742         if(theReadStream && theWriteStream)
743         {
744                 if(![self attachStreamsToRunLoop:(NSRunLoop *)theRunLoop error:nil])
745                 {
746                         return NO;
747                 }
748         }
749         if(theReadTimer)
750         {
751                 for(i = 0; i < [theRunLoopModes count]; i++)
752                 {
753                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
754                         CFRunLoopAddTimer(theRunLoop, (CFRunLoopTimerRef)theReadTimer, runLoopMode);
755                 }
756                 
757                 // Release here since we retained it above
758                 [theReadTimer release];
759         }
760         if(theWriteTimer)
761         {
762                 for(i = 0; i < [theRunLoopModes count]; i++)
763                 {
764                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
765                         CFRunLoopAddTimer(theRunLoop, (CFRunLoopTimerRef)theWriteTimer, runLoopMode);
766                 }
767                 
768                 // Release here since we retained it above
769                 [theWriteTimer release];
770         }
771         
772         [self performSelector:@selector(maybeDequeueRead) withObject:nil afterDelay:0 inModes:theRunLoopModes];
773         [self performSelector:@selector(maybeDequeueWrite) withObject:nil afterDelay:0 inModes:theRunLoopModes];
774         [self performSelector:@selector(maybeScheduleDisconnect) withObject:nil afterDelay:0 inModes:theRunLoopModes];
775         
776         return YES;
777 }
778
779 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
780 #pragma mark Connection
781 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
782
783 - (BOOL)acceptOnPort:(UInt16)port error:(NSError **)errPtr
784 {
785         return [self acceptOnAddress:nil port:port error:errPtr];
786 }
787         
788 /**
789  * To accept on a certain address, pass the address to accept on.
790  * To accept on any address, pass nil or an empty string.
791  * To accept only connections from localhost pass "localhost" or "loopback".
792 **/
793 - (BOOL)acceptOnAddress:(NSString *)hostaddr port:(UInt16)port error:(NSError **)errPtr
794 {
795         if (theDelegate == NULL)
796                 [NSException raise:AsyncSocketException format:@"Attempting to accept without a delegate. Set a delegate first."];
797         
798         if (theSocket != NULL || theSocket6 != NULL)
799                 [NSException raise:AsyncSocketException format:@"Attempting to accept while connected or accepting connections. Disconnect first."];
800
801         // Set up the listen sockaddr structs if needed.
802         
803         NSData *address = nil, *address6 = nil;
804         if(hostaddr == nil || ([hostaddr length] == 0))
805         {
806                 // Accept on ANY address
807                 struct sockaddr_in nativeAddr;
808                 nativeAddr.sin_len         = sizeof(struct sockaddr_in);
809                 nativeAddr.sin_family      = AF_INET;
810                 nativeAddr.sin_port        = htons(port);
811                 nativeAddr.sin_addr.s_addr = htonl(INADDR_ANY);
812                 memset(&(nativeAddr.sin_zero), 0, sizeof(nativeAddr.sin_zero));
813                 
814                 struct sockaddr_in6 nativeAddr6;
815                 nativeAddr6.sin6_len       = sizeof(struct sockaddr_in6);
816                 nativeAddr6.sin6_family    = AF_INET6;
817                 nativeAddr6.sin6_port      = htons(port);
818                 nativeAddr6.sin6_flowinfo  = 0;
819                 nativeAddr6.sin6_addr      = in6addr_any;
820                 nativeAddr6.sin6_scope_id  = 0;
821                 
822                 // Wrap the native address structures for CFSocketSetAddress.
823                 address = [NSData dataWithBytes:&nativeAddr length:sizeof(nativeAddr)];
824                 address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
825         }
826         else if([hostaddr isEqualToString:@"localhost"] || [hostaddr isEqualToString:@"loopback"])
827         {
828                 // Accept only on LOOPBACK address
829                 struct sockaddr_in nativeAddr;
830                 nativeAddr.sin_len         = sizeof(struct sockaddr_in);
831                 nativeAddr.sin_family      = AF_INET;
832                 nativeAddr.sin_port        = htons(port);
833                 nativeAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
834                 memset(&(nativeAddr.sin_zero), 0, sizeof(nativeAddr.sin_zero));
835         
836                 struct sockaddr_in6 nativeAddr6;
837                 nativeAddr6.sin6_len       = sizeof(struct sockaddr_in6);
838                 nativeAddr6.sin6_family    = AF_INET6;
839                 nativeAddr6.sin6_port      = htons(port);
840                 nativeAddr6.sin6_flowinfo  = 0;
841                 nativeAddr6.sin6_addr      = in6addr_loopback;
842                 nativeAddr6.sin6_scope_id  = 0;
843                 
844                 // Wrap the native address structures for CFSocketSetAddress.
845                 address = [NSData dataWithBytes:&nativeAddr length:sizeof(nativeAddr)];
846                 address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
847         }
848         else
849         {
850                 NSString *portStr = [NSString stringWithFormat:@"%hu", port];
851                 
852                 @synchronized (getaddrinfoLock)
853                 {
854                         struct addrinfo hints, *res, *res0;
855                         
856                         memset(&hints, 0, sizeof(hints));
857                         hints.ai_family   = PF_UNSPEC;
858                         hints.ai_socktype = SOCK_STREAM;
859                         hints.ai_protocol = IPPROTO_TCP;
860                         hints.ai_flags    = AI_PASSIVE;
861                         
862                         int error = getaddrinfo([hostaddr UTF8String], [portStr UTF8String], &hints, &res0);
863                         
864                         if(error)
865                         {
866                                 if(errPtr)
867                                 {
868                                         NSString *errMsg = [NSString stringWithCString:gai_strerror(error) encoding:NSASCIIStringEncoding];
869                                         NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
870                                         
871                                         *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:error userInfo:info];
872                                 }
873                         }
874                         
875                         for(res = res0; res; res = res->ai_next)
876                         {
877                                 if(!address && (res->ai_family == AF_INET))
878                                 {
879                                         // Found IPv4 address
880                                         // Wrap the native address structures for CFSocketSetAddress.
881                                         address = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
882                                 }
883                                 else if(!address6 && (res->ai_family == AF_INET6))
884                                 {
885                                         // Found IPv6 address
886                                         // Wrap the native address structures for CFSocketSetAddress.
887                                         address6 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
888                                 }
889                         }
890                         freeaddrinfo(res0);
891                 }
892                 
893                 if(!address && !address6) return NO;
894         }
895
896         // Create the sockets.
897
898         if (address)
899         {
900                 theSocket = [self createAcceptSocketForAddress:address error:errPtr];
901                 if (theSocket == NULL) goto Failed;
902         }
903         
904         if (address6)
905         {
906                 theSocket6 = [self createAcceptSocketForAddress:address6 error:errPtr];
907                 
908                 // Note: The iPhone doesn't currently support IPv6
909                 
910 #if !TARGET_OS_IPHONE
911                 if (theSocket6 == NULL) goto Failed;
912 #endif
913         }
914         
915         // Attach the sockets to the run loop so that callback methods work
916         
917         [self attachSocketsToRunLoop:nil error:nil];
918         
919         // Set the SO_REUSEADDR flags.
920
921         int reuseOn = 1;
922         if (theSocket)  setsockopt(CFSocketGetNative(theSocket), SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
923         if (theSocket6) setsockopt(CFSocketGetNative(theSocket6), SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
924
925         // Set the local bindings which causes the sockets to start listening.
926
927         CFSocketError err;
928         if (theSocket)
929         {
930                 err = CFSocketSetAddress (theSocket, (CFDataRef)address);
931                 if (err != kCFSocketSuccess) goto Failed;
932                 
933                 //NSLog(@"theSocket4: %hu", [self localPort:theSocket]);
934         }
935         
936         if(port == 0 && theSocket && theSocket6)
937         {
938                 // The user has passed in port 0, which means he wants to allow the kernel to choose the port for them
939                 // However, the kernel will choose a different port for both theSocket and theSocket6
940                 // So we grab the port the kernel choose for theSocket, and set it as the port for theSocket6
941                 UInt16 chosenPort = [self localPort:theSocket];
942                 
943                 struct sockaddr_in6 *pSockAddr6 = (struct sockaddr_in6 *)[address6 bytes];
944                 pSockAddr6->sin6_port = htons(chosenPort);
945     }
946         
947         if (theSocket6)
948         {
949                 err = CFSocketSetAddress (theSocket6, (CFDataRef)address6);
950                 if (err != kCFSocketSuccess) goto Failed;
951                 
952                 //NSLog(@"theSocket6: %hu", [self localPort:theSocket6]);
953         }
954
955         theFlags |= kDidPassConnectMethod;
956         return YES;
957         
958 Failed:;
959         if(errPtr) *errPtr = [self getSocketError];
960         if(theSocket != NULL)
961         {
962                 CFSocketInvalidate(theSocket);
963                 CFRelease(theSocket);
964                 theSocket = NULL;
965         }
966         if(theSocket6 != NULL)
967         {
968                 CFSocketInvalidate(theSocket6);
969                 CFRelease(theSocket6);
970                 theSocket6 = NULL;
971         }
972         return NO;
973 }
974
975 /**
976  * This method creates an initial CFReadStream and CFWriteStream to the given host on the given port.
977  * The connection is then opened, and the corresponding CFSocket will be extracted after the connection succeeds.
978  *
979  * Thus the delegate will have access to the CFReadStream and CFWriteStream prior to connection,
980  * specifically in the onSocketWillConnect: method.
981 **/
982 - (BOOL)connectToHost:(NSString*)hostname onPort:(UInt16)port error:(NSError **)errPtr
983 {
984         if(theDelegate == NULL)
985         {
986                 NSString *message = @"Attempting to connect without a delegate. Set a delegate first.";
987                 [NSException raise:AsyncSocketException format:message];
988         }
989
990         if(theSocket != NULL || theSocket6 != NULL)
991         {
992                 NSString *message = @"Attempting to connect while connected or accepting connections. Disconnect first.";
993                 [NSException raise:AsyncSocketException format:message];
994         }
995         
996         BOOL pass = YES;
997         
998         if(pass && ![self createStreamsToHost:hostname onPort:port error:errPtr]) pass = NO;
999         if(pass && ![self attachStreamsToRunLoop:nil error:errPtr])               pass = NO;
1000         if(pass && ![self configureStreamsAndReturnError:errPtr])                 pass = NO;
1001         if(pass && ![self openStreamsAndReturnError:errPtr])                      pass = NO;
1002         
1003         if(pass)
1004                 theFlags |= kDidPassConnectMethod;
1005         else
1006                 [self close];
1007         
1008         return pass;
1009 }
1010
1011 /**
1012  * This method creates an initial CFSocket to the given address.
1013  * The connection is then opened, and the corresponding CFReadStream and CFWriteStream will be
1014  * created from the low-level sockets after the connection succeeds.
1015  *
1016  * Thus the delegate will have access to the CFSocket and CFSocketNativeHandle (BSD socket) prior to connection,
1017  * specifically in the onSocketWillConnect: method.
1018  * 
1019  * Note: The NSData parameter is expected to be a sockaddr structure. For example, an NSData object returned from
1020  * NSNetservice addresses method.
1021  * If you have an existing struct sockaddr you can convert it to an NSData object like so:
1022  * struct sockaddr sa  -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
1023  * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
1024 **/
1025 - (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr
1026 {
1027         if (theDelegate == NULL)
1028         {
1029                 NSString *message = @"Attempting to connect without a delegate. Set a delegate first.";
1030                 [NSException raise:AsyncSocketException format:message];
1031         }
1032         
1033         if (theSocket != NULL || theSocket6 != NULL)
1034         {
1035                 NSString *message = @"Attempting to connect while connected or accepting connections. Disconnect first.";
1036                 [NSException raise:AsyncSocketException format:message];
1037         }
1038         
1039         BOOL pass = YES;
1040         
1041         if(pass && ![self createSocketForAddress:remoteAddr error:errPtr])   pass = NO;
1042         if(pass && ![self attachSocketsToRunLoop:nil error:errPtr])          pass = NO;
1043         if(pass && ![self configureSocketAndReturnError:errPtr])             pass = NO;
1044         if(pass && ![self connectSocketToAddress:remoteAddr error:errPtr])   pass = NO;
1045         
1046         if(pass)
1047                 theFlags |= kDidPassConnectMethod;
1048         else
1049                 [self close];
1050         
1051         return pass;
1052 }
1053
1054 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1055 #pragma mark Socket Implementation
1056 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1057
1058 /**
1059  * Creates the accept sockets.
1060  * Returns true if either IPv4 or IPv6 is created.
1061  * If either is missing, an error is returned (even though the method may return true).
1062 **/
1063 - (CFSocketRef)createAcceptSocketForAddress:(NSData *)addr error:(NSError **)errPtr
1064 {
1065         struct sockaddr *pSockAddr = (struct sockaddr *)[addr bytes];
1066         int addressFamily = pSockAddr->sa_family;
1067         
1068         CFSocketRef socket = CFSocketCreate(kCFAllocatorDefault,
1069                                                                                 addressFamily,
1070                                                                                 SOCK_STREAM,
1071                                                                                 0,
1072                                                                                 kCFSocketAcceptCallBack,                // Callback flags
1073                                                                                 (CFSocketCallBack)&MyCFSocketCallback,  // Callback method
1074                                                                                 &theContext);
1075
1076         if(socket == NULL)
1077         {
1078                 if(errPtr) *errPtr = [self getSocketError];
1079         }
1080         
1081         return socket;
1082 }
1083
1084 - (BOOL)createSocketForAddress:(NSData *)remoteAddr error:(NSError **)errPtr
1085 {
1086         struct sockaddr *pSockAddr = (struct sockaddr *)[remoteAddr bytes];
1087         
1088         if(pSockAddr->sa_family == AF_INET)
1089         {
1090                 theSocket = CFSocketCreate(NULL,                                   // Default allocator
1091                                                                    PF_INET,                                // Protocol Family
1092                                                                    SOCK_STREAM,                            // Socket Type
1093                                                                    IPPROTO_TCP,                            // Protocol
1094                                                                    kCFSocketConnectCallBack,               // Callback flags
1095                                                                    (CFSocketCallBack)&MyCFSocketCallback,  // Callback method
1096                                                                    &theContext);                           // Socket Context
1097                 
1098                 if(theSocket == NULL)
1099                 {
1100                         if (errPtr) *errPtr = [self getSocketError];
1101                         return NO;
1102                 }
1103         }
1104         else if(pSockAddr->sa_family == AF_INET6)
1105         {
1106                 theSocket6 = CFSocketCreate(NULL,                                   // Default allocator
1107                                                                     PF_INET6,                               // Protocol Family
1108                                                                     SOCK_STREAM,                            // Socket Type
1109                                                                     IPPROTO_TCP,                            // Protocol
1110                                                                     kCFSocketConnectCallBack,               // Callback flags
1111                                                                     (CFSocketCallBack)&MyCFSocketCallback,  // Callback method
1112                                                                     &theContext);                           // Socket Context
1113                 
1114                 if(theSocket6 == NULL)
1115                 {
1116                         if (errPtr) *errPtr = [self getSocketError];
1117                         return NO;
1118                 }
1119         }
1120         else
1121         {
1122                 if (errPtr) *errPtr = [self getSocketError];
1123                 return NO;
1124         }
1125         
1126         return YES;
1127 }
1128
1129 /**
1130  * Adds the CFSocket's to the run-loop so that callbacks will work properly.
1131 **/
1132 - (BOOL)attachSocketsToRunLoop:(NSRunLoop *)runLoop error:(NSError **)errPtr
1133 {
1134         int i;
1135         
1136         // Get the CFRunLoop to which the socket should be attached.
1137         theRunLoop = (runLoop == nil) ? CFRunLoopGetCurrent() : [runLoop getCFRunLoop];
1138         
1139         if(theSocket)
1140         {
1141                 theSource  = CFSocketCreateRunLoopSource (kCFAllocatorDefault, theSocket, 0);
1142                 for(i = 0; i < [theRunLoopModes count]; i++)
1143                 {
1144                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
1145                         CFRunLoopAddSource (theRunLoop, theSource, runLoopMode);
1146                 }
1147         }
1148         
1149         if(theSocket6)
1150         {
1151                 theSource6 = CFSocketCreateRunLoopSource (kCFAllocatorDefault, theSocket6, 0);
1152                 for(i = 0; i < [theRunLoopModes count]; i++)
1153                 {
1154                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
1155                         CFRunLoopAddSource (theRunLoop, theSource6, runLoopMode);
1156                 }
1157         }
1158         
1159         return YES;
1160 }
1161
1162 /**
1163  * Allows the delegate method to configure the CFSocket or CFNativeSocket as desired before we connect.
1164  * Note that the CFReadStream and CFWriteStream will not be available until after the connection is opened.
1165 **/
1166 - (BOOL)configureSocketAndReturnError:(NSError **)errPtr
1167 {
1168         // Call the delegate method for further configuration.
1169         if([theDelegate respondsToSelector:@selector(onSocketWillConnect:)])
1170         {
1171                 if([theDelegate onSocketWillConnect:self] == NO)
1172                 {
1173                         if (errPtr) *errPtr = [self getAbortError];
1174                         return NO;
1175                 }
1176         }
1177         return YES;
1178 }
1179
1180 - (BOOL)connectSocketToAddress:(NSData *)remoteAddr error:(NSError **)errPtr
1181 {
1182         // Start connecting to the given address in the background
1183         // The MyCFSocketCallback method will be called when the connection succeeds or fails
1184         if(theSocket)
1185         {
1186                 CFSocketError err = CFSocketConnectToAddress(theSocket, (CFDataRef)remoteAddr, -1);
1187                 if(err != kCFSocketSuccess)
1188                 {
1189                         if (errPtr) *errPtr = [self getSocketError];
1190                         return NO;
1191                 }
1192         }
1193         else if(theSocket6)
1194         {
1195                 CFSocketError err = CFSocketConnectToAddress(theSocket6, (CFDataRef)remoteAddr, -1);
1196                 if(err != kCFSocketSuccess)
1197                 {
1198                         if (errPtr) *errPtr = [self getSocketError];
1199                         return NO;
1200                 }
1201         }
1202         
1203         return YES;
1204 }
1205
1206 /**
1207  * Attempt to make the new socket.
1208  * If an error occurs, ignore this event.
1209 **/
1210 - (void)doAcceptWithSocket:(CFSocketNativeHandle)newNative
1211 {
1212         // New socket inherits same delegate and run loop modes.
1213         // Note: We use [self class] to support subclassing AsyncSocket.
1214         AsyncSocket *newSocket = [[[[self class] alloc] initWithDelegate:theDelegate] autorelease];
1215         [newSocket setRunLoopModes:theRunLoopModes];
1216         
1217         if(newSocket)
1218         {
1219                 if ([theDelegate respondsToSelector:@selector(onSocket:didAcceptNewSocket:)])
1220                         [theDelegate onSocket:self didAcceptNewSocket:newSocket];
1221                 
1222                 NSRunLoop *runLoop = nil;
1223                 if ([theDelegate respondsToSelector:@selector(onSocket:wantsRunLoopForNewSocket:)])
1224                         runLoop = [theDelegate onSocket:self wantsRunLoopForNewSocket:newSocket];
1225                 
1226                 BOOL pass = YES;
1227                 
1228                 if(pass && ![newSocket createStreamsFromNative:newNative error:nil]) pass = NO;
1229                 if(pass && ![newSocket attachStreamsToRunLoop:runLoop error:nil])    pass = NO;
1230                 if(pass && ![newSocket configureStreamsAndReturnError:nil])          pass = NO;
1231                 if(pass && ![newSocket openStreamsAndReturnError:nil])               pass = NO;
1232                 
1233                 if(pass)
1234                         newSocket->theFlags |= kDidPassConnectMethod;
1235                 else {
1236                         // No NSError, but errors will still get logged from the above functions.
1237                         [newSocket close];
1238                 }
1239                 
1240         }
1241 }
1242
1243 /**
1244  * Description forthcoming...
1245 **/
1246 - (void)doSocketOpen:(CFSocketRef)sock withCFSocketError:(CFSocketError)socketError
1247 {
1248         NSParameterAssert ((sock == theSocket) || (sock == theSocket6));
1249         
1250         if(socketError == kCFSocketTimeout || socketError == kCFSocketError)
1251         {
1252                 [self closeWithError:[self getSocketError]];
1253                 return;
1254         }
1255         
1256         // Get the underlying native (BSD) socket
1257         CFSocketNativeHandle nativeSocket = CFSocketGetNative(sock);
1258         
1259         // Setup the socket so that invalidating the socket will not close the native socket
1260         CFSocketSetSocketFlags(sock, 0);
1261         
1262         // Invalidate and release the CFSocket - All we need from here on out is the nativeSocket
1263         // Note: If we don't invalidate the socket (leaving the native socket open)
1264         // then theReadStream and theWriteStream won't function properly.
1265         // Specifically, their callbacks won't work, with the exception of kCFStreamEventOpenCompleted.
1266         // I'm not entirely sure why this is, but I'm guessing that events on the socket fire to the CFSocket we created,
1267         // as opposed to the CFReadStream/CFWriteStream.
1268         
1269         CFSocketInvalidate(sock);
1270         CFRelease(sock);
1271         theSocket = NULL;
1272         theSocket6 = NULL;
1273         
1274         NSError *err;
1275         BOOL pass = YES;
1276         
1277         if(pass && ![self createStreamsFromNative:nativeSocket error:&err]) pass = NO;
1278         if(pass && ![self attachStreamsToRunLoop:nil error:&err])           pass = NO;
1279         if(pass && ![self openStreamsAndReturnError:&err])                  pass = NO;
1280         
1281         if(!pass)
1282         {
1283                 [self closeWithError:err];
1284         }
1285 }
1286
1287 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1288 #pragma mark Stream Implementation
1289 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1290
1291 /**
1292  * Creates the CFReadStream and CFWriteStream from the given native socket.
1293  * The CFSocket may be extracted from either stream after the streams have been opened.
1294  * 
1295  * Note: The given native socket must already be connected!
1296 **/
1297 - (BOOL)createStreamsFromNative:(CFSocketNativeHandle)native error:(NSError **)errPtr
1298 {
1299         // Create the socket & streams.
1300         CFStreamCreatePairWithSocket(kCFAllocatorDefault, native, &theReadStream, &theWriteStream);
1301         if (theReadStream == NULL || theWriteStream == NULL)
1302         {
1303                 NSError *err = [self getStreamError];
1304                 NSLog (@"AsyncSocket %p couldn't create streams from accepted socket: %@", self, err);
1305                 if (errPtr) *errPtr = err;
1306                 return NO;
1307         }
1308         
1309         // Ensure the CF & BSD socket is closed when the streams are closed.
1310         CFReadStreamSetProperty(theReadStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
1311         CFWriteStreamSetProperty(theWriteStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
1312         
1313         return YES;
1314 }
1315
1316 /**
1317  * Creates the CFReadStream and CFWriteStream from the given hostname and port number.
1318  * The CFSocket may be extracted from either stream after the streams have been opened.
1319 **/
1320 - (BOOL)createStreamsToHost:(NSString *)hostname onPort:(UInt16)port error:(NSError **)errPtr
1321 {
1322         // Create the socket & streams.
1323         CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (CFStringRef)hostname, port, &theReadStream, &theWriteStream);
1324         if (theReadStream == NULL || theWriteStream == NULL)
1325         {
1326                 if (errPtr) *errPtr = [self getStreamError];
1327                 return NO;
1328         }
1329         
1330         // Ensure the CF & BSD socket is closed when the streams are closed.
1331         CFReadStreamSetProperty(theReadStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
1332         CFWriteStreamSetProperty(theWriteStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
1333         
1334         return YES;
1335 }
1336
1337 - (BOOL)attachStreamsToRunLoop:(NSRunLoop *)runLoop error:(NSError **)errPtr
1338 {
1339         int i;
1340         
1341         // Get the CFRunLoop to which the socket should be attached.
1342         theRunLoop = (runLoop == nil) ? CFRunLoopGetCurrent() : [runLoop getCFRunLoop];
1343
1344         // Make read stream non-blocking.
1345         if (!CFReadStreamSetClient (theReadStream,
1346                 kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered | kCFStreamEventOpenCompleted,
1347                 (CFReadStreamClientCallBack)&MyCFReadStreamCallback,
1348                 (CFStreamClientContext *)(&theContext) ))
1349         {
1350                 NSError *err = [self getStreamError];
1351                 
1352                 NSLog (@"AsyncSocket %p couldn't attach read stream to run-loop,", self);
1353                 NSLog (@"Error: %@", err);
1354                 
1355                 if (errPtr) *errPtr = err;
1356                 return NO;
1357         }
1358         for(i = 0; i < [theRunLoopModes count]; i++)
1359         {
1360                 CFReadStreamScheduleWithRunLoop(theReadStream, theRunLoop, (CFStringRef)[theRunLoopModes objectAtIndex:i]);
1361         }
1362
1363         // Make write stream non-blocking.
1364         if (!CFWriteStreamSetClient (theWriteStream,
1365                 kCFStreamEventCanAcceptBytes | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered | kCFStreamEventOpenCompleted,
1366                 (CFWriteStreamClientCallBack)&MyCFWriteStreamCallback,
1367                 (CFStreamClientContext *)(&theContext) ))
1368         {
1369                 NSError *err = [self getStreamError];
1370                 
1371                 NSLog (@"AsyncSocket %p couldn't attach write stream to run-loop,", self);
1372                 NSLog (@"Error: %@", err);
1373                 
1374                 if (errPtr) *errPtr = err;
1375                 return NO;
1376                 
1377         }
1378         for(i = 0; i < [theRunLoopModes count]; i++)
1379         {
1380                 CFWriteStreamScheduleWithRunLoop (theWriteStream, theRunLoop, (CFStringRef)[theRunLoopModes objectAtIndex:i]);
1381         }
1382         
1383         return YES;
1384 }
1385
1386 /**
1387  * Allows the delegate method to configure the CFReadStream and/or CFWriteStream as desired before we connect.
1388  * Note that the CFSocket and CFNativeSocket will not be available until after the connection is opened.
1389 **/
1390 - (BOOL)configureStreamsAndReturnError:(NSError **)errPtr
1391 {
1392         // Call the delegate method for further configuration.
1393         if([theDelegate respondsToSelector:@selector(onSocketWillConnect:)])
1394         {
1395                 if([theDelegate onSocketWillConnect:self] == NO)
1396                 {
1397                         if (errPtr) *errPtr = [self getAbortError];
1398                         return NO;
1399                 }
1400         }
1401         return YES;
1402 }
1403
1404 - (BOOL)openStreamsAndReturnError:(NSError **)errPtr
1405 {
1406         BOOL pass = YES;
1407         
1408         if(pass && !CFReadStreamOpen (theReadStream))
1409         {
1410                 NSLog (@"AsyncSocket %p couldn't open read stream,", self);
1411                 pass = NO;
1412         }
1413         
1414         if(pass && !CFWriteStreamOpen (theWriteStream))
1415         {
1416                 NSLog (@"AsyncSocket %p couldn't open write stream,", self);
1417                 pass = NO;
1418         }
1419         
1420         if(!pass)
1421         {
1422                 if (errPtr) *errPtr = [self getStreamError];
1423         }
1424         
1425         return pass;
1426 }
1427
1428 /**
1429  * Called when read or write streams open.
1430  * When the socket is connected and both streams are open, consider the AsyncSocket instance to be ready.
1431 **/
1432 - (void)doStreamOpen
1433 {
1434         NSError *err = nil;
1435         if ([self areStreamsConnected] && !(theFlags & kDidCallConnectDelegate))
1436         {
1437                 // Get the socket.
1438                 if (![self setSocketFromStreamsAndReturnError: &err])
1439                 {
1440                         NSLog (@"AsyncSocket %p couldn't get socket from streams, %@. Disconnecting.", self, err);
1441                         [self closeWithError:err];
1442                         return;
1443                 }
1444                 
1445                 // Call the delegate.
1446                 theFlags |= kDidCallConnectDelegate;
1447                 if ([theDelegate respondsToSelector:@selector(onSocket:didConnectToHost:port:)])
1448                 {
1449                         [theDelegate onSocket:self didConnectToHost:[self connectedHost] port:[self connectedPort]];
1450                 }
1451                 
1452                 // Immediately deal with any already-queued requests.
1453                 [self maybeDequeueRead];
1454                 [self maybeDequeueWrite];
1455         }
1456 }
1457
1458 - (BOOL)setSocketFromStreamsAndReturnError:(NSError **)errPtr
1459 {
1460         // Get the CFSocketNativeHandle from theReadStream
1461         CFSocketNativeHandle native;
1462         CFDataRef nativeProp = CFReadStreamCopyProperty(theReadStream, kCFStreamPropertySocketNativeHandle);
1463         if(nativeProp == NULL)
1464         {
1465                 if (errPtr) *errPtr = [self getStreamError];
1466                 return NO;
1467         }
1468         
1469         CFDataGetBytes(nativeProp, CFRangeMake(0, CFDataGetLength(nativeProp)), (UInt8 *)&native);
1470         CFRelease(nativeProp);
1471         
1472         CFSocketRef socket = CFSocketCreateWithNative(kCFAllocatorDefault, native, 0, NULL, NULL);
1473         if(socket == NULL)
1474         {
1475                 if (errPtr) *errPtr = [self getSocketError];
1476                 return NO;
1477         }
1478         
1479         // Determine whether the connection was IPv4 or IPv6
1480         CFDataRef peeraddr = CFSocketCopyPeerAddress(socket);
1481         struct sockaddr *sa = (struct sockaddr *)CFDataGetBytePtr(peeraddr);
1482         
1483         if(sa->sa_family == AF_INET)
1484         {
1485                 theSocket = socket;
1486         }
1487         else
1488         {
1489                 theSocket6 = socket;
1490         }
1491         
1492         CFRelease(peeraddr);
1493
1494         return YES;
1495 }
1496
1497 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1498 #pragma mark Disconnect Implementation
1499 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1500
1501 // Sends error message and disconnects
1502 - (void)closeWithError:(NSError *)err
1503 {
1504         theFlags |= kClosingWithError;
1505         
1506         if (theFlags & kDidPassConnectMethod)
1507         {
1508                 // Try to salvage what data we can.
1509                 [self recoverUnreadData];
1510                 
1511                 // Let the delegate know, so it can try to recover if it likes.
1512                 if ([theDelegate respondsToSelector:@selector(onSocket:willDisconnectWithError:)])
1513                 {
1514                         [theDelegate onSocket:self willDisconnectWithError:err];
1515                 }
1516         }
1517         [self close];
1518 }
1519
1520 // Prepare partially read data for recovery.
1521 - (void)recoverUnreadData
1522 {
1523         if((theCurrentRead != nil) && (theCurrentRead->bytesDone > 0))
1524         {
1525                 // We never finished the current read.
1526                 // We need to move its data into the front of the partial read buffer.
1527                 
1528                 [partialReadBuffer replaceBytesInRange:NSMakeRange(0, 0)
1529                                                                          withBytes:[theCurrentRead->buffer bytes]
1530                                                                                 length:theCurrentRead->bytesDone];
1531         }
1532         
1533         [self emptyQueues];
1534 }
1535
1536 - (void)emptyQueues
1537 {
1538         if (theCurrentRead != nil)      [self endCurrentRead];
1539         if (theCurrentWrite != nil)     [self endCurrentWrite];
1540         [theReadQueue removeAllObjects];
1541         [theWriteQueue removeAllObjects];
1542         [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(maybeDequeueRead) object:nil];
1543         [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(maybeDequeueWrite) object:nil];
1544 }
1545
1546 /**
1547  * Disconnects. This is called for both error and clean disconnections.
1548 **/
1549 - (void)close
1550 {
1551         unsigned i;
1552         
1553         // Empty queues
1554         [self emptyQueues];
1555         
1556         // Clear partialReadBuffer (pre-buffer and also unreadData buffer in case of error)
1557         [partialReadBuffer replaceBytesInRange:NSMakeRange(0, [partialReadBuffer length]) withBytes:NULL length:0];
1558         
1559         [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(disconnect) object:nil];
1560         
1561         // Close streams.
1562         if (theReadStream != NULL)
1563         {
1564                 for(i = 0; i < [theRunLoopModes count]; i++)
1565                 {
1566                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
1567                         CFReadStreamUnscheduleFromRunLoop(theReadStream, theRunLoop, runLoopMode);
1568                 }
1569                 CFReadStreamSetClient(theReadStream, kCFStreamEventNone, NULL, NULL);
1570                 CFReadStreamClose(theReadStream);
1571                 CFRelease(theReadStream);
1572                 theReadStream = NULL;
1573         }
1574         if (theWriteStream != NULL)
1575         {
1576                 for(i = 0; i < [theRunLoopModes count]; i++)
1577                 {
1578                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
1579                         CFWriteStreamUnscheduleFromRunLoop(theWriteStream, theRunLoop, runLoopMode);
1580                 }
1581                 CFWriteStreamSetClient(theWriteStream, kCFStreamEventNone, NULL, NULL);
1582                 CFWriteStreamClose(theWriteStream);
1583                 CFRelease(theWriteStream);
1584                 theWriteStream = NULL;
1585         }
1586         
1587         // Close sockets.
1588         if (theSocket != NULL)
1589         {
1590                 CFSocketInvalidate (theSocket);
1591                 CFRelease (theSocket);
1592                 theSocket = NULL;
1593         }
1594         if (theSocket6 != NULL)
1595         {
1596                 CFSocketInvalidate (theSocket6);
1597                 CFRelease (theSocket6);
1598                 theSocket6 = NULL;
1599         }
1600         if (theSource != NULL)
1601         {
1602                 for(i = 0; i < [theRunLoopModes count]; i++)
1603                 {
1604                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
1605                         CFRunLoopRemoveSource(theRunLoop, theSource, runLoopMode);
1606                 }
1607                 CFRelease (theSource);
1608                 theSource = NULL;
1609         }
1610         if (theSource6 != NULL)
1611         {
1612                 for(i = 0; i < [theRunLoopModes count]; i++)
1613                 {
1614                         CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
1615                         CFRunLoopRemoveSource(theRunLoop, theSource6, runLoopMode);
1616                 }
1617                 CFRelease (theSource6);
1618                 theSource6 = NULL;
1619         }
1620         theRunLoop = NULL;
1621         
1622         // If the client has passed the connect/accept method, then the connection has at least begun.
1623         // Notify delegate that it is now ending.
1624         if (theFlags & kDidPassConnectMethod)
1625         {
1626                 // Delay notification to give dev freedom to release without returning here and core-dumping.
1627                 if ([theDelegate respondsToSelector: @selector(onSocketDidDisconnect:)])
1628                 {
1629                         [theDelegate performSelector:@selector(onSocketDidDisconnect:)
1630                                                           withObject:self
1631                                                           afterDelay:0
1632                                                                  inModes:theRunLoopModes];
1633                 }
1634         }
1635         
1636         // Clear all flags (except the pre-buffering flag, which should remain as is)
1637         theFlags &= kEnablePreBuffering;
1638 }
1639
1640 /**
1641  * Disconnects immediately. Any pending reads or writes are dropped.
1642 **/
1643 - (void)disconnect
1644 {
1645         [self close];
1646 }
1647
1648 /**
1649  * Diconnects after all pending reads have completed.
1650 **/
1651 - (void)disconnectAfterReading
1652 {
1653         theFlags |= (kForbidReadsWrites | kDisconnectAfterReads);
1654         
1655         [self maybeScheduleDisconnect];
1656 }
1657
1658 /**
1659  * Disconnects after all pending writes have completed.
1660 **/
1661 - (void)disconnectAfterWriting
1662 {
1663         theFlags |= (kForbidReadsWrites | kDisconnectAfterWrites);
1664         
1665         [self maybeScheduleDisconnect];
1666 }
1667
1668 /**
1669  * Disconnects after all pending reads and writes have completed.
1670 **/
1671 - (void)disconnectAfterReadingAndWriting
1672 {
1673         theFlags |= (kForbidReadsWrites | kDisconnectAfterReads | kDisconnectAfterWrites);
1674         
1675         [self maybeScheduleDisconnect];
1676 }
1677
1678 /**
1679  * Schedules a call to disconnect if possible.
1680  * That is, if all writes have completed, and we're set to disconnect after writing,
1681  * or if all reads have completed, and we're set to disconnect after reading.
1682 **/
1683 - (void)maybeScheduleDisconnect
1684 {
1685         BOOL shouldDisconnect = NO;
1686         
1687         if(theFlags & kDisconnectAfterReads)
1688         {
1689                 if(([theReadQueue count] == 0) && (theCurrentRead == nil))
1690                 {
1691                         if(theFlags & kDisconnectAfterWrites)
1692                         {
1693                                 if(([theWriteQueue count] == 0) && (theCurrentWrite == nil))
1694                                 {
1695                                         shouldDisconnect = YES;
1696                                 }
1697                         }
1698                         else
1699                         {
1700                                 shouldDisconnect = YES;
1701                         }
1702                 }
1703         }
1704         else if(theFlags & kDisconnectAfterWrites)
1705         {
1706                 if(([theWriteQueue count] == 0) && (theCurrentWrite == nil))
1707                 {
1708                         shouldDisconnect = YES;
1709                 }
1710         }
1711         
1712         if(shouldDisconnect)
1713         {
1714                 [self performSelector:@selector(disconnect) withObject:nil afterDelay:0 inModes:theRunLoopModes];
1715         }
1716 }
1717
1718 /**
1719  * In the event of an error, this method may be called during onSocket:willDisconnectWithError: to read
1720  * any data that's left on the socket.
1721 **/
1722 - (NSData *)unreadData
1723 {
1724         // Ensure this method will only return data in the event of an error
1725         if(!(theFlags & kClosingWithError)) return nil;
1726         
1727         if(theReadStream == NULL) return nil;
1728         
1729         CFIndex totalBytesRead = [partialReadBuffer length];
1730         BOOL error = NO;
1731         while(!error && CFReadStreamHasBytesAvailable(theReadStream))
1732         {
1733                 [partialReadBuffer increaseLengthBy:READALL_CHUNKSIZE];
1734                 
1735                 // Number of bytes to read is space left in packet buffer.
1736                 CFIndex bytesToRead = [partialReadBuffer length] - totalBytesRead;
1737                 
1738                 // Read data into packet buffer
1739                 UInt8 *packetbuf = (UInt8 *)( [partialReadBuffer mutableBytes] + totalBytesRead );
1740                 CFIndex bytesRead = CFReadStreamRead(theReadStream, packetbuf, bytesToRead);
1741                 
1742                 // Check results
1743                 if(bytesRead < 0)
1744                 {
1745                         error = YES;
1746                 }
1747                 else
1748                 {
1749                         totalBytesRead += bytesRead;
1750                 }
1751         }
1752         
1753         [partialReadBuffer setLength:totalBytesRead];
1754         
1755         return partialReadBuffer;
1756 }
1757
1758 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1759 #pragma mark Errors
1760 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1761
1762 /**
1763  * Returns a standard error object for the current errno value.
1764  * Errno is used for low-level BSD socket errors.
1765 **/
1766 - (NSError *)getErrnoError
1767 {
1768         NSString *errorMsg = [NSString stringWithUTF8String:strerror(errno)];
1769         NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errorMsg forKey:NSLocalizedDescriptionKey];
1770         
1771         return [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:userInfo];
1772 }
1773
1774 /**
1775  * Returns a standard error message for a CFSocket error.
1776  * Unfortunately, CFSocket offers no feedback on its errors.
1777 **/
1778 - (NSError *)getSocketError
1779 {
1780         NSString *errMsg = NSLocalizedStringWithDefaultValue(@"AsyncSocketCFSocketError",
1781                                                                                                                  @"AsyncSocket", [NSBundle mainBundle],
1782                                                                                                                  @"General CFSocket error", nil);
1783         
1784         NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
1785         
1786         return [NSError errorWithDomain:AsyncSocketErrorDomain code:AsyncSocketCFSocketError userInfo:info];
1787 }
1788
1789 - (NSError *) getStreamError
1790 {
1791         CFStreamError err;
1792         if (theReadStream != NULL)
1793         {
1794                 err = CFReadStreamGetError (theReadStream);
1795                 if (err.error != 0) return [self errorFromCFStreamError: err];
1796         }
1797         
1798         if (theWriteStream != NULL)
1799         {
1800                 err = CFWriteStreamGetError (theWriteStream);
1801                 if (err.error != 0) return [self errorFromCFStreamError: err];
1802         }
1803         
1804         return nil;
1805 }
1806
1807 /**
1808  * Returns a standard AsyncSocket abort error.
1809 **/
1810 - (NSError *)getAbortError
1811 {
1812         NSString *errMsg = NSLocalizedStringWithDefaultValue(@"AsyncSocketCanceledError",
1813                                                                                                                  @"AsyncSocket", [NSBundle mainBundle],
1814                                                                                                                  @"Connection canceled", nil);
1815         
1816         NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
1817         
1818         return [NSError errorWithDomain:AsyncSocketErrorDomain code:AsyncSocketCanceledError userInfo:info];
1819 }
1820
1821 - (NSError *)getReadMaxedOutError
1822 {
1823         NSString *errMsg = NSLocalizedStringWithDefaultValue(@"AsyncSocketReadMaxedOutError",
1824                                                                                                                  @"AsyncSocket", [NSBundle mainBundle],
1825                                                                                                                  @"Read operation reached set maximum length", nil);
1826         
1827         NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
1828         
1829         return [NSError errorWithDomain:AsyncSocketErrorDomain code:AsyncSocketReadMaxedOutError userInfo:info];
1830 }
1831
1832 /**
1833  * Returns a standard AsyncSocket read timeout error.
1834 **/
1835 - (NSError *)getReadTimeoutError
1836 {
1837         NSString *errMsg = NSLocalizedStringWithDefaultValue(@"AsyncSocketReadTimeoutError",
1838                                                                                                                  @"AsyncSocket", [NSBundle mainBundle],
1839                                                                                                                  @"Read operation timed out", nil);
1840         
1841         NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
1842         
1843         return [NSError errorWithDomain:AsyncSocketErrorDomain code:AsyncSocketReadTimeoutError userInfo:info];
1844 }
1845
1846 /**
1847  * Returns a standard AsyncSocket write timeout error.
1848 **/
1849 - (NSError *)getWriteTimeoutError
1850 {
1851         NSString *errMsg = NSLocalizedStringWithDefaultValue(@"AsyncSocketWriteTimeoutError",
1852                                                                                                                  @"AsyncSocket", [NSBundle mainBundle],
1853                                                                                                                  @"Write operation timed out", nil);
1854         
1855         NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
1856         
1857         return [NSError errorWithDomain:AsyncSocketErrorDomain code:AsyncSocketWriteTimeoutError userInfo:info];
1858 }
1859
1860 - (NSError *)errorFromCFStreamError:(CFStreamError)err
1861 {
1862         if (err.domain == 0 && err.error == 0) return nil;
1863         
1864         // Can't use switch; these constants aren't int literals.
1865         NSString *domain = @"CFStreamError (unlisted domain)";
1866         NSString *message = nil;
1867         
1868         if(err.domain == kCFStreamErrorDomainPOSIX) {
1869                 domain = NSPOSIXErrorDomain;
1870         }
1871         else if(err.domain == kCFStreamErrorDomainMacOSStatus) {
1872                 domain = NSOSStatusErrorDomain;
1873         }
1874         else if(err.domain == kCFStreamErrorDomainMach) {
1875                 domain = NSMachErrorDomain;
1876         }
1877         else if(err.domain == kCFStreamErrorDomainNetDB)
1878         {
1879                 domain = @"kCFStreamErrorDomainNetDB";
1880                 message = [NSString stringWithCString:gai_strerror(err.error) encoding:NSASCIIStringEncoding];
1881         }
1882         else if(err.domain == kCFStreamErrorDomainNetServices) {
1883                 domain = @"kCFStreamErrorDomainNetServices";
1884         }
1885         else if(err.domain == kCFStreamErrorDomainSOCKS) {
1886                 domain = @"kCFStreamErrorDomainSOCKS";
1887         }
1888         else if(err.domain == kCFStreamErrorDomainSystemConfiguration) {
1889                 domain = @"kCFStreamErrorDomainSystemConfiguration";
1890         }
1891         else if(err.domain == kCFStreamErrorDomainSSL) {
1892                 domain = @"kCFStreamErrorDomainSSL";
1893         }
1894         
1895         NSDictionary *info = nil;
1896         if(message != nil)
1897         {
1898                 info = [NSDictionary dictionaryWithObject:message forKey:NSLocalizedDescriptionKey];
1899         }
1900         return [NSError errorWithDomain:domain code:err.error userInfo:info];
1901 }
1902
1903 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1904 #pragma mark Diagnostics
1905 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1906
1907 - (BOOL)isConnected
1908 {
1909         return [self isSocketConnected] && [self areStreamsConnected];
1910 }
1911
1912 - (NSString *)connectedHost
1913 {
1914         if(theSocket)
1915                 return [self connectedHost:theSocket];
1916         else
1917                 return [self connectedHost:theSocket6];
1918 }
1919
1920 - (UInt16)connectedPort
1921 {
1922         if(theSocket)
1923                 return [self connectedPort:theSocket];
1924         else
1925                 return [self connectedPort:theSocket6];
1926 }
1927
1928 - (NSString *)localHost
1929 {
1930         if(theSocket)
1931                 return [self localHost:theSocket];
1932         else
1933                 return [self localHost:theSocket6];
1934 }
1935
1936 - (UInt16)localPort
1937 {
1938         if(theSocket)
1939                 return [self localPort:theSocket];
1940         else
1941                 return [self localPort:theSocket6];
1942 }
1943
1944 - (NSString *)connectedHost:(CFSocketRef)socket
1945 {
1946         if (socket == NULL) return nil;
1947         CFDataRef peeraddr;
1948         NSString *peerstr = nil;
1949
1950         if(socket && (peeraddr = CFSocketCopyPeerAddress(socket)))
1951         {
1952                 peerstr = [self addressHost:peeraddr];
1953                 CFRelease (peeraddr);
1954         }
1955
1956         return peerstr;
1957 }
1958
1959 - (UInt16)connectedPort:(CFSocketRef)socket
1960 {
1961         if (socket == NULL) return 0;
1962         CFDataRef peeraddr;
1963         UInt16 peerport = 0;
1964
1965         if(socket && (peeraddr = CFSocketCopyPeerAddress(socket)))
1966         {
1967                 peerport = [self addressPort:peeraddr];
1968                 CFRelease (peeraddr);
1969         }
1970
1971         return peerport;
1972 }
1973
1974 - (NSString *)localHost:(CFSocketRef)socket
1975 {
1976         if (socket == NULL) return nil;
1977         CFDataRef selfaddr;
1978         NSString *selfstr = nil;
1979
1980         if(socket && (selfaddr = CFSocketCopyAddress(socket)))
1981         {
1982                 selfstr = [self addressHost:selfaddr];
1983                 CFRelease (selfaddr);
1984         }
1985
1986         return selfstr;
1987 }
1988
1989 - (UInt16)localPort:(CFSocketRef)socket
1990 {
1991         if (socket == NULL) return 0;
1992         CFDataRef selfaddr;
1993         UInt16 selfport = 0;
1994
1995         if (socket && (selfaddr = CFSocketCopyAddress(socket)))
1996         {
1997                 selfport = [self addressPort:selfaddr];
1998                 CFRelease (selfaddr);
1999         }
2000
2001         return selfport;
2002 }
2003
2004 - (BOOL)isSocketConnected
2005 {
2006         if(theSocket != NULL)
2007                 return CFSocketIsValid(theSocket);
2008         else if(theSocket6 != NULL)
2009                 return CFSocketIsValid(theSocket6);
2010         else
2011                 return NO;
2012 }
2013
2014 - (BOOL)areStreamsConnected
2015 {
2016         CFStreamStatus s;
2017
2018         if (theReadStream != NULL)
2019         {
2020                 s = CFReadStreamGetStatus (theReadStream);
2021                 if ( !(s == kCFStreamStatusOpen || s == kCFStreamStatusReading || s == kCFStreamStatusError) )
2022                         return NO;
2023         }
2024         else return NO;
2025
2026         if (theWriteStream != NULL)
2027         {
2028                 s = CFWriteStreamGetStatus (theWriteStream);
2029                 if ( !(s == kCFStreamStatusOpen || s == kCFStreamStatusWriting || s == kCFStreamStatusError) )
2030                         return NO;
2031         }
2032         else return NO;
2033
2034         return YES;
2035 }
2036
2037 - (NSString *)addressHost:(CFDataRef)cfaddr
2038 {
2039         if (cfaddr == NULL) return nil;
2040         
2041         char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
2042         struct sockaddr *pSockAddr = (struct sockaddr *) CFDataGetBytePtr (cfaddr);
2043         struct sockaddr_in  *pSockAddrV4 = (struct sockaddr_in *) pSockAddr;
2044         struct sockaddr_in6 *pSockAddrV6 = (struct sockaddr_in6 *)pSockAddr;
2045
2046         const void *pAddr = (pSockAddr->sa_family == AF_INET) ?
2047                                                         (void *)(&(pSockAddrV4->sin_addr)) :
2048                                                         (void *)(&(pSockAddrV6->sin6_addr));
2049
2050         const char *pStr = inet_ntop (pSockAddr->sa_family, pAddr, addrBuf, sizeof(addrBuf));
2051         if (pStr == NULL) [NSException raise: NSInternalInconsistencyException
2052                                                                   format: @"Cannot convert address to string."];
2053
2054         return [NSString stringWithCString:pStr encoding:NSASCIIStringEncoding];
2055 }
2056
2057 - (UInt16)addressPort:(CFDataRef)cfaddr
2058 {
2059         if (cfaddr == NULL) return 0;
2060         struct sockaddr_in *pAddr = (struct sockaddr_in *) CFDataGetBytePtr (cfaddr);
2061         return ntohs (pAddr->sin_port);
2062 }
2063
2064 - (BOOL)isIPv4
2065 {
2066         return (theSocket != NULL);
2067 }
2068
2069 - (BOOL)isIPv6
2070 {
2071         return (theSocket6 != NULL);
2072 }
2073
2074 - (NSString *)description
2075 {
2076         static const char *statstr[] = {"not open","opening","open","reading","writing","at end","closed","has error"};
2077         CFStreamStatus rs = (theReadStream != NULL) ? CFReadStreamGetStatus(theReadStream) : 0;
2078         CFStreamStatus ws = (theWriteStream != NULL) ? CFWriteStreamGetStatus(theWriteStream) : 0;
2079         
2080         NSString *peerstr, *selfstr;
2081         CFDataRef peeraddr = NULL, peeraddr6 = NULL, selfaddr = NULL, selfaddr6 = NULL;
2082
2083         if (theSocket || theSocket6)
2084         {
2085                 if (theSocket)  peeraddr  = CFSocketCopyPeerAddress(theSocket);
2086                 if (theSocket6) peeraddr6 = CFSocketCopyPeerAddress(theSocket6);
2087         
2088                 if(theSocket6 && theSocket)
2089                 {
2090                         peerstr = [NSString stringWithFormat: @"%@/%@ %u", 
2091                                            [self addressHost:peeraddr], [self addressHost:peeraddr6], [self addressPort:peeraddr]];
2092                 }
2093                 else if(theSocket6)
2094                 {
2095                         peerstr = [NSString stringWithFormat: @"%@ %u", [self addressHost:peeraddr6], [self addressPort:peeraddr6]];
2096                 }
2097                 else
2098                 {
2099                         peerstr = [NSString stringWithFormat: @"%@ %u", [self addressHost:peeraddr], [self addressPort:peeraddr]];
2100                 }
2101                 
2102                 if(peeraddr)  CFRelease(peeraddr);
2103                 if(peeraddr6) CFRelease(peeraddr6);
2104                 peeraddr = NULL;
2105                 peeraddr6 = NULL;
2106         }
2107         else peerstr = @"nowhere";
2108
2109         if (theSocket || theSocket6)
2110         {
2111                 if (theSocket)  selfaddr  = CFSocketCopyAddress (theSocket);
2112                 if (theSocket6) selfaddr6 = CFSocketCopyAddress (theSocket6);
2113         
2114                 if (theSocket6 && theSocket)
2115                 {
2116                         selfstr = [NSString stringWithFormat: @"%@/%@ %u",
2117                                            [self addressHost:selfaddr], [self addressHost:selfaddr6], [self addressPort:selfaddr]];
2118                 }
2119                 else if (theSocket6)
2120                 {
2121                         selfstr = [NSString stringWithFormat: @"%@ %u", [self addressHost:selfaddr6], [self addressPort:selfaddr6]];
2122                 }
2123                 else
2124                 {
2125                         selfstr = [NSString stringWithFormat: @"%@ %u", [self addressHost:selfaddr], [self addressPort:selfaddr]];
2126                 }
2127
2128                 if(selfaddr)  CFRelease(selfaddr);
2129                 if(selfaddr6) CFRelease(selfaddr6);
2130                 selfaddr = NULL;
2131                 selfaddr6 = NULL;
2132         }
2133         else selfstr = @"nowhere";
2134         
2135         NSMutableString *ms = [[NSMutableString alloc] initWithCapacity:150];
2136         
2137         [ms appendString:[NSString stringWithFormat:@"<AsyncSocket %p", self]];
2138         [ms appendString:[NSString stringWithFormat:@" local %@ remote %@ ", selfstr, peerstr]];
2139         
2140         unsigned readQueueCount  = (unsigned)[theReadQueue count];
2141         unsigned writeQueueCount = (unsigned)[theWriteQueue count];
2142         
2143         [ms appendString:[NSString stringWithFormat:@"has queued %u reads %u writes, ", readQueueCount, writeQueueCount]];
2144
2145         if (theCurrentRead == nil)
2146                 [ms appendString: @"no current read, "];
2147         else
2148         {
2149                 int percentDone;
2150                 if ([theCurrentRead->buffer length] != 0)
2151                         percentDone = (float)theCurrentRead->bytesDone /
2152                                                   (float)[theCurrentRead->buffer length] * 100.0;
2153                 else
2154                         percentDone = 100;
2155
2156                 [ms appendString: [NSString stringWithFormat:@"currently read %u bytes (%d%% done), ",
2157                         (unsigned int)[theCurrentRead->buffer length],
2158                         theCurrentRead->bytesDone ? percentDone : 0]];
2159         }
2160
2161         if (theCurrentWrite == nil)
2162                 [ms appendString: @"no current write, "];
2163         else
2164         {
2165                 int percentDone;
2166                 if ([theCurrentWrite->buffer length] != 0)
2167                         percentDone = (float)theCurrentWrite->bytesDone /
2168                                                   (float)[theCurrentWrite->buffer length] * 100.0;
2169                 else
2170                         percentDone = 100;
2171
2172                 [ms appendString: [NSString stringWithFormat:@"currently written %u (%d%%), ",
2173                         (unsigned int)[theCurrentWrite->buffer length],
2174                         theCurrentWrite->bytesDone ? percentDone : 0]];
2175         }
2176         
2177         [ms appendString:[NSString stringWithFormat:@"read stream %p %s, ", theReadStream, statstr[rs]]];
2178         [ms appendString:[NSString stringWithFormat:@"write stream %p %s", theWriteStream, statstr[ws]]];
2179         
2180         if(theFlags & kDisconnectAfterReads)
2181         {
2182                 if(theFlags & kDisconnectAfterWrites)
2183                         [ms appendString: @", will disconnect after reads & writes"];
2184                 else
2185                         [ms appendString: @", will disconnect after reads"];
2186         }
2187         else if(theFlags & kDisconnectAfterWrites)
2188         {
2189                 [ms appendString: @", will disconnect after writes"];
2190         }
2191         
2192         if (![self isConnected]) [ms appendString: @", not connected"];
2193
2194         [ms appendString:@">"];
2195
2196         return [ms autorelease];
2197 }
2198
2199 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2200 #pragma mark Reading
2201 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2202
2203 - (void)readDataToLength:(CFIndex)length withTimeout:(NSTimeInterval)timeout tag:(long)tag;
2204 {
2205         if(length == 0) return;
2206         if(theFlags & kForbidReadsWrites) return;
2207         
2208         NSMutableData *buffer = [[NSMutableData alloc] initWithLength:length];
2209         AsyncReadPacket *packet = [[AsyncReadPacket alloc] initWithData:buffer
2210                                                                                                                         timeout:timeout
2211                                                                                                                                 tag:tag
2212                                                                                                    readAllAvailable:NO
2213                                                                                                                  terminator:nil
2214                                                                                                                   maxLength:length];
2215
2216         [theReadQueue addObject:packet];
2217         [self scheduleDequeueRead];
2218
2219         [packet release];
2220         [buffer release];
2221 }
2222
2223 - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag
2224 {
2225         [self readDataToData:data withTimeout:timeout maxLength:-1 tag:tag];
2226 }
2227
2228 - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(CFIndex)length tag:(long)tag
2229 {
2230         if(data == nil || [data length] == 0) return;
2231         if(length >= 0 && length < [data length]) return;
2232         if(theFlags & kForbidReadsWrites) return;
2233         
2234         NSMutableData *buffer = [[NSMutableData alloc] initWithLength:0];
2235         AsyncReadPacket *packet = [[AsyncReadPacket alloc] initWithData:buffer
2236                                                                                                                         timeout:timeout
2237                                                                                                                                 tag:tag 
2238                                                                                                    readAllAvailable:NO 
2239                                                                                                                  terminator:data
2240                                                                                                                   maxLength:length];
2241         
2242         [theReadQueue addObject:packet];
2243         [self scheduleDequeueRead];
2244         
2245         [packet release];
2246         [buffer release];
2247 }
2248
2249 - (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag
2250 {
2251         if (theFlags & kForbidReadsWrites) return;
2252         
2253         NSMutableData *buffer = [[NSMutableData alloc] initWithLength:0];
2254         AsyncReadPacket *packet = [[AsyncReadPacket alloc] initWithData:buffer
2255                                                                                                                         timeout:timeout
2256                                                                                                                                 tag:tag
2257                                                                                                    readAllAvailable:YES
2258                                                                                                                  terminator:nil
2259                                                                                                                   maxLength:-1];
2260         
2261         [theReadQueue addObject:packet];
2262         [self scheduleDequeueRead];
2263         
2264         [packet release];
2265         [buffer release];
2266 }
2267
2268 /**
2269  * Puts a maybeDequeueRead on the run loop. 
2270  * An assumption here is that selectors will be performed consecutively within their priority.
2271 **/
2272 - (void)scheduleDequeueRead
2273 {
2274         [self performSelector:@selector(maybeDequeueRead) withObject:nil afterDelay:0 inModes:theRunLoopModes];
2275 }
2276
2277 /**
2278  * This method starts a new read, if needed.
2279  * It is called when a user requests a read,
2280  * or when a stream opens that may have requested reads sitting in the queue, etc.
2281 **/
2282 - (void)maybeDequeueRead
2283 {
2284         // If we're not currently processing a read AND we have an available read stream
2285         if((theCurrentRead == nil) && (theReadStream != NULL))
2286         {
2287                 if([theReadQueue count] > 0)
2288                 {
2289                         // Dequeue the next object in the write queue
2290                         theCurrentRead = [[theReadQueue objectAtIndex:0] retain];
2291                         [theReadQueue removeObjectAtIndex:0];
2292                         
2293                         if([theCurrentRead isKindOfClass:[AsyncSpecialPacket class]])
2294                         {
2295                                 // Attempt to start TLS
2296                                 // This method won't do anything unless both theCurrentRead and theCurrentWrite are start TLS packets
2297                                 [self maybeStartTLS];
2298                         }
2299                         else
2300                         {
2301                                 // Start time-out timer
2302                                 if(theCurrentRead->timeout >= 0.0)
2303                                 {
2304                                         theReadTimer = [NSTimer timerWithTimeInterval:theCurrentRead->timeout
2305                                                                                                                    target:self 
2306                                                                                                                  selector:@selector(doReadTimeout:)
2307                                                                                                                  userInfo:nil
2308                                                                                                                   repeats:NO];
2309                                         unsigned i;
2310                                         for(i = 0; i < [theRunLoopModes count]; i++)
2311                                         {
2312                                                 CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
2313                                                 CFRunLoopAddTimer(theRunLoop, (CFRunLoopTimerRef)theReadTimer, runLoopMode);
2314                                         }
2315                                 }
2316                                 
2317                                 // Immediately read, if possible
2318                                 [self doBytesAvailable];
2319                         }
2320                 }
2321                 else if(theFlags & kDisconnectAfterReads)
2322                 {
2323                         if(theFlags & kDisconnectAfterWrites)
2324                         {
2325                                 if(([theWriteQueue count] == 0) && (theCurrentWrite == nil))
2326                                 {
2327                                         [self disconnect];
2328                                 }
2329                         }
2330                         else
2331                         {
2332                                 [self disconnect];
2333                         }
2334                 }
2335         }
2336 }
2337
2338 /**
2339  * Call this method in doBytesAvailable instead of CFReadStreamHasBytesAvailable().
2340  * This method supports pre-buffering properly.
2341 **/
2342 - (BOOL)hasBytesAvailable
2343 {
2344         return ([partialReadBuffer length] > 0) || CFReadStreamHasBytesAvailable(theReadStream);
2345 }
2346
2347 /**
2348  * Call this method in doBytesAvailable instead of CFReadStreamRead().
2349  * This method support pre-buffering properly.
2350 **/
2351 - (CFIndex)readIntoBuffer:(UInt8 *)buffer maxLength:(CFIndex)length
2352 {
2353         if([partialReadBuffer length] > 0)
2354         {
2355                 // Determine the maximum amount of data to read
2356                 CFIndex bytesToRead = MIN(length, [partialReadBuffer length]);
2357                 
2358                 // Copy the bytes from the buffer
2359                 memcpy(buffer, [partialReadBuffer bytes], bytesToRead);
2360                 
2361                 // Remove the copied bytes from the buffer
2362                 [partialReadBuffer replaceBytesInRange:NSMakeRange(0, bytesToRead) withBytes:NULL length:0];
2363                 
2364                 return bytesToRead;
2365         }
2366         else
2367         {
2368                 return CFReadStreamRead(theReadStream, buffer, length);
2369         }
2370 }
2371
2372 /**
2373  * This method is called when a new read is taken from the read queue or when new data becomes available on the stream.
2374 **/
2375 - (void)doBytesAvailable
2376 {
2377         // If data is available on the stream, but there is no read request, then we don't need to process the data yet.
2378         // Also, if there is a read request, but no read stream setup yet, we can't process any data yet.
2379         if(theCurrentRead != nil && theReadStream != NULL)
2380         {
2381                 CFIndex totalBytesRead = 0;
2382                 
2383                 BOOL done = NO;
2384                 BOOL socketError = NO;
2385                 BOOL maxoutError = NO;
2386                 
2387                 while(!done && !socketError && !maxoutError && [self hasBytesAvailable])
2388                 {
2389                         BOOL didPreBuffer = NO;
2390                         
2391                         // If reading all available data, make sure there's room in the packet buffer.
2392                         if(theCurrentRead->readAllAvailableData == YES)
2393                         {
2394                                 // Make sure there is at least READALL_CHUNKSIZE bytes available.
2395                                 // We don't want to increase the buffer any more than this or we'll waste space.
2396                                 // With prebuffering it's possible to read in a small chunk on the first read.
2397                                 
2398                                 unsigned buffInc = READALL_CHUNKSIZE - ([theCurrentRead->buffer length] - theCurrentRead->bytesDone);
2399                                 [theCurrentRead->buffer increaseLengthBy:buffInc];
2400                         }
2401
2402                         // If reading until data, we may only want to read a few bytes.
2403                         // Just enough to ensure we don't go past our term or over our max limit.
2404                         // Unless pre-buffering is enabled, in which case we may want to read in a larger chunk.
2405                         if(theCurrentRead->term != nil)
2406                         {
2407                                 // If we already have data pre-buffered, we obviously don't want to pre-buffer it again.
2408                                 // So in this case we'll just read as usual.
2409                                 
2410                                 if(([partialReadBuffer length] > 0) || !(theFlags & kEnablePreBuffering))
2411                                 {
2412                                         unsigned maxToRead = [theCurrentRead readLengthForTerm];
2413                                         
2414                                         unsigned bufInc = maxToRead - ([theCurrentRead->buffer length] - theCurrentRead->bytesDone);
2415                                         [theCurrentRead->buffer increaseLengthBy:bufInc];
2416                                 }
2417                                 else
2418                                 {
2419                                         didPreBuffer = YES;
2420                                         unsigned maxToRead = [theCurrentRead prebufferReadLengthForTerm];
2421                                         
2422                                         unsigned buffInc = maxToRead - ([theCurrentRead->buffer length] - theCurrentRead->bytesDone);
2423                                         [theCurrentRead->buffer increaseLengthBy:buffInc];
2424
2425                                 }
2426                         }
2427                         
2428                         // Number of bytes to read is space left in packet buffer.
2429                         CFIndex bytesToRead = [theCurrentRead->buffer length] - theCurrentRead->bytesDone;
2430                         
2431                         // Read data into packet buffer
2432                         UInt8 *subBuffer = (UInt8 *)([theCurrentRead->buffer mutableBytes] + theCurrentRead->bytesDone);
2433                         CFIndex bytesRead = [self readIntoBuffer:subBuffer maxLength:bytesToRead];
2434                         
2435                         // Check results
2436                         if(bytesRead < 0)
2437                         {
2438                                 socketError = YES;
2439                         }
2440                         else
2441                         {
2442                                 // Update total amound read for the current read
2443                                 theCurrentRead->bytesDone += bytesRead;
2444                                 
2445                                 // Update total amount read in this method invocation
2446                                 totalBytesRead += bytesRead;
2447                         }
2448
2449                         // Is packet done?
2450                         if(theCurrentRead->readAllAvailableData != YES)
2451                         {
2452                                 if(theCurrentRead->term != nil)
2453                                 {
2454                                         if(didPreBuffer)
2455                                         {
2456                                                 // Search for the terminating sequence within the big chunk we just read.
2457                                                 CFIndex overflow = [theCurrentRead searchForTermAfterPreBuffering:bytesRead];
2458                                                 
2459                                                 if(overflow > 0)
2460                                                 {
2461                                                         // Copy excess data into partialReadBuffer
2462                                                         NSMutableData *buffer = theCurrentRead->buffer;
2463                                                         const void *overflowBuffer = [buffer bytes] + theCurrentRead->bytesDone - overflow;
2464                                                         
2465                                                         [partialReadBuffer appendBytes:overflowBuffer length:overflow];
2466                                                         
2467                                                         // Update the bytesDone variable.
2468                                                         // Note: The completeCurrentRead method will trim the buffer for us.
2469                                                         theCurrentRead->bytesDone -= overflow;
2470                                                 }
2471                                                 
2472                                                 done = (overflow >= 0);
2473                                         }
2474                                         else
2475                                         {
2476                                                 // Search for the terminating sequence at the end of the buffer
2477                                                 int termlen = [theCurrentRead->term length];
2478                                                 if(theCurrentRead->bytesDone >= termlen)
2479                                                 {
2480                                                         const void *buf = [theCurrentRead->buffer bytes] + (theCurrentRead->bytesDone - termlen);
2481                                                         const void *seq = [theCurrentRead->term bytes];
2482                                                         done = (memcmp (buf, seq, termlen) == 0);
2483                                                 }
2484                                         }
2485                                         
2486                                         if(!done && theCurrentRead->maxLength >= 0 && theCurrentRead->bytesDone >= theCurrentRead->maxLength)
2487                                         {
2488                                                 // There's a set maxLength, and we've reached that maxLength without completing the read
2489                                                 maxoutError = YES;
2490                                         }
2491                                 }
2492                                 else
2493                                 {
2494                                         // Done when (sized) buffer is full.
2495                                         done = ([theCurrentRead->buffer length] == theCurrentRead->bytesDone);
2496                                 }
2497                         }
2498                         // else readAllAvailable doesn't end until all readable is read.
2499                 }
2500                 
2501                 if(theCurrentRead->readAllAvailableData && theCurrentRead->bytesDone > 0)
2502                         done = YES;     // Ran out of bytes, so the "read-all-data" type packet is done
2503
2504                 if(done)
2505                 {
2506                         [self completeCurrentRead];
2507                         if (!socketError) [self scheduleDequeueRead];
2508                 }
2509                 else if(theCurrentRead->bytesDone > 0)
2510                 {
2511                         // We're not done with the readToLength or readToData yet, but we have read in some bytes
2512                         if ([theDelegate respondsToSelector:@selector(onSocket:didReadPartialDataOfLength:tag:)])
2513                         {
2514                                 [theDelegate onSocket:self didReadPartialDataOfLength:totalBytesRead tag:theCurrentRead->tag];
2515                         }
2516                 }
2517
2518                 if(socketError)
2519                 {
2520                         CFStreamError err = CFReadStreamGetError(theReadStream);
2521                         [self closeWithError:[self errorFromCFStreamError:err]];
2522                         return;
2523                 }
2524                 if(maxoutError)
2525                 {
2526                         [self closeWithError:[self getReadMaxedOutError]];
2527                         return;
2528                 }
2529         }
2530 }
2531
2532 // Ends current read and calls delegate.
2533 - (void)completeCurrentRead
2534 {
2535         NSAssert (theCurrentRead, @"Trying to complete current read when there is no current read.");
2536         
2537         [theCurrentRead->buffer setLength:theCurrentRead->bytesDone];
2538         if([theDelegate respondsToSelector:@selector(onSocket:didReadData:withTag:)])
2539         {
2540                 [theDelegate onSocket:self didReadData:theCurrentRead->buffer withTag:theCurrentRead->tag];
2541         }
2542         
2543         if (theCurrentRead != nil) [self endCurrentRead]; // Caller may have disconnected.
2544 }
2545
2546 // Ends current read.
2547 - (void)endCurrentRead
2548 {
2549         NSAssert (theCurrentRead, @"Trying to end current read when there is no current read.");
2550         
2551         [theReadTimer invalidate];
2552         theReadTimer = nil;
2553         
2554         [theCurrentRead release];
2555         theCurrentRead = nil;
2556 }
2557
2558 - (void)doReadTimeout:(NSTimer *)timer
2559 {
2560         if (timer != theReadTimer) return; // Old timer. Ignore it.
2561         if (theCurrentRead != nil)
2562         {
2563                 [self endCurrentRead];
2564         }
2565         [self closeWithError:[self getReadTimeoutError]];
2566 }
2567
2568 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2569 #pragma mark Writing
2570 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2571
2572 - (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
2573 {
2574         if (data == nil || [data length] == 0) return;
2575         if (theFlags & kForbidReadsWrites) return;
2576         
2577         AsyncWritePacket *packet = [[AsyncWritePacket alloc] initWithData:data timeout:timeout tag:tag];
2578         
2579         [theWriteQueue addObject:packet];
2580         [self scheduleDequeueWrite];
2581         
2582         [packet release];
2583 }
2584
2585 - (void)scheduleDequeueWrite
2586 {
2587         [self performSelector:@selector(maybeDequeueWrite) withObject:nil afterDelay:0 inModes:theRunLoopModes];
2588 }
2589
2590 // Start a new write.
2591 - (void)maybeDequeueWrite
2592 {
2593         // If we're not currently processing a write AND we have an available write stream
2594         if((theCurrentWrite == nil) && (theWriteStream != NULL))
2595         {
2596                 if([theWriteQueue count] > 0)
2597                 {
2598                         // Dequeue the next object in the write queue
2599                         theCurrentWrite = [[theWriteQueue objectAtIndex:0] retain];
2600                         [theWriteQueue removeObjectAtIndex:0];
2601                         
2602                         if([theCurrentWrite isKindOfClass:[AsyncSpecialPacket class]])
2603                         {
2604                                 // Attempt to start TLS
2605                                 // This method won't do anything unless both theCurrentWrite and theCurrentRead are start TLS packets
2606                                 [self maybeStartTLS];
2607                         }
2608                         else
2609                         {
2610                                 // Start time-out timer
2611                                 if (theCurrentWrite->timeout >= 0.0)
2612                                 {
2613                                         theWriteTimer = [NSTimer timerWithTimeInterval:theCurrentWrite->timeout
2614                                                                                                                         target:self
2615                                                                                                                   selector:@selector(doWriteTimeout:)
2616                                                                                                                   userInfo:nil
2617                                                                                                                    repeats:NO];
2618                                         unsigned i;
2619                                         for(i = 0; i < [theRunLoopModes count]; i++)
2620                                         {
2621                                                 CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
2622                                                 CFRunLoopAddTimer(theRunLoop, (CFRunLoopTimerRef)theWriteTimer, runLoopMode);
2623                                         }
2624                                 }
2625                                 
2626                                 // Immediately write, if possible
2627                                 [self doSendBytes];
2628                         }
2629                 }
2630                 else if(theFlags & kDisconnectAfterWrites)
2631                 {
2632                         if(theFlags & kDisconnectAfterReads)
2633                         {
2634                                 if(([theReadQueue count] == 0) && (theCurrentRead == nil))
2635                                 {
2636                                         [self disconnect];
2637                                 }
2638                         }
2639                         else
2640                         {
2641                                 [self disconnect];
2642                         }
2643                 }
2644         }
2645 }
2646
2647 - (void)doSendBytes
2648 {
2649         if (theCurrentWrite != nil && theWriteStream != NULL)
2650         {
2651                 BOOL done = NO, error = NO;
2652                 while (!done && !error && CFWriteStreamCanAcceptBytes (theWriteStream))
2653                 {
2654                         // Figure out what to write.
2655                         CFIndex bytesRemaining = [theCurrentWrite->buffer length] - theCurrentWrite->bytesDone;
2656                         CFIndex bytesToWrite = (bytesRemaining < WRITE_CHUNKSIZE) ? bytesRemaining : WRITE_CHUNKSIZE;
2657                         UInt8 *writestart = (UInt8 *)([theCurrentWrite->buffer bytes] + theCurrentWrite->bytesDone);
2658
2659                         // Write.
2660                         CFIndex bytesWritten = CFWriteStreamWrite (theWriteStream, writestart, bytesToWrite);
2661
2662                         // Check results.
2663                         if (bytesWritten < 0)
2664                         {
2665                                 bytesWritten = 0;
2666                                 error = YES;
2667                         }
2668
2669                         // Is packet done?
2670                         theCurrentWrite->bytesDone += bytesWritten;
2671                         done = ([theCurrentWrite->buffer length] == theCurrentWrite->bytesDone);
2672                 }
2673
2674                 if(done)
2675                 {
2676                         [self completeCurrentWrite];
2677                         if (!error) [self scheduleDequeueWrite];
2678                 }
2679
2680                 if(error)
2681                 {
2682                         CFStreamError err = CFWriteStreamGetError (theWriteStream);
2683                         [self closeWithError: [self errorFromCFStreamError:err]];
2684                         return;
2685                 }
2686         }
2687 }
2688
2689 // Ends current write and calls delegate.
2690 - (void)completeCurrentWrite
2691 {
2692         NSAssert (theCurrentWrite, @"Trying to complete current write when there is no current write.");
2693         
2694         if ([theDelegate respondsToSelector:@selector(onSocket:didWriteDataWithTag:)])
2695         {
2696                 [theDelegate onSocket:self didWriteDataWithTag:theCurrentWrite->tag];
2697         }
2698         
2699         if (theCurrentWrite != nil) [self endCurrentWrite]; // Caller may have disconnected.
2700 }
2701
2702 // Ends current write.
2703 - (void)endCurrentWrite
2704 {
2705         NSAssert (theCurrentWrite, @"Trying to complete current write when there is no current write.");
2706         
2707         [theWriteTimer invalidate];
2708         theWriteTimer = nil;
2709         
2710         [theCurrentWrite release];
2711         theCurrentWrite = nil;
2712 }
2713
2714 - (void)doWriteTimeout:(NSTimer *)timer
2715 {
2716         if(timer != theWriteTimer)
2717         {
2718                 // Old timer - Ignore it
2719                 return;
2720         }
2721         if(theCurrentWrite != nil)
2722         {
2723                 [self endCurrentWrite];
2724         }
2725         [self closeWithError:[self getWriteTimeoutError]];
2726 }
2727
2728 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2729 #pragma mark Security
2730 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2731
2732 - (void)startTLS:(NSDictionary *)tlsSettings
2733 {
2734         if([tlsSettings count] == 0) return;
2735         
2736         AsyncSpecialPacket *packet = [[AsyncSpecialPacket alloc] initWithTLSSettings:tlsSettings];
2737         
2738         [theReadQueue addObject:packet];
2739         [self scheduleDequeueRead];
2740         
2741         [theWriteQueue addObject:packet];
2742         [self scheduleDequeueWrite];
2743         
2744         [packet release];
2745 }
2746
2747 - (void)maybeStartTLS
2748 {
2749         NSAssert((theFlags & kStartingTLS) == 0, @"Trying to start TLS after TLS has already been started");
2750         
2751         // We can't start TLS until:
2752         // - All queued reads prior to the user calling StartTLS are complete
2753         // - All queued writes prior to the user calling StartTLS are complete
2754         // 
2755         // We'll know these conditions are met when both theCurrentRead and theCurrentWrite variables
2756         // are of type AsyncSpecialPacket.
2757         
2758         Class SpecialPacketClass = [AsyncSpecialPacket class];
2759         
2760         if([theCurrentRead isKindOfClass:SpecialPacketClass] && [theCurrentWrite isKindOfClass:SpecialPacketClass])
2761         {
2762                 theFlags |= kStartingTLS;
2763                 
2764                 AsyncSpecialPacket *tlsPacket = (AsyncSpecialPacket *)theCurrentRead;
2765                 
2766                 BOOL didSecureReadStream = CFReadStreamSetProperty(theReadStream, kCFStreamPropertySSLSettings,
2767                                                                                                                    (CFDictionaryRef)tlsPacket->tlsSettings);
2768                 BOOL didSecureWriteStream = CFWriteStreamSetProperty(theWriteStream, kCFStreamPropertySSLSettings,
2769                                                                                                                          (CFDictionaryRef)tlsPacket->tlsSettings);
2770                 
2771                 if(!didSecureReadStream || !didSecureWriteStream)
2772                 {
2773                         [self onTLSStarted:NO];
2774                 }
2775         }
2776 }
2777
2778 - (void)onTLSStarted:(BOOL)flag
2779 {
2780         theFlags &= ~kStartingTLS;
2781         
2782         if([theDelegate respondsToSelector:@selector(onSocket:didSecure:)])
2783         {
2784                 [theDelegate onSocket:self didSecure:flag];
2785         }
2786         
2787         [self endCurrentRead];
2788         [self endCurrentWrite];
2789         
2790         [self scheduleDequeueRead];
2791         [self scheduleDequeueWrite];
2792 }
2793
2794 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2795 #pragma mark CF Callbacks
2796 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2797
2798 - (void)doCFSocketCallback:(CFSocketCallBackType)type
2799                                  forSocket:(CFSocketRef)sock
2800                            withAddress:(NSData *)address
2801                                   withData:(const void *)pData
2802 {
2803         NSParameterAssert ((sock == theSocket) || (sock == theSocket6));
2804         
2805         switch (type)
2806         {
2807                 case kCFSocketConnectCallBack:
2808                         // The data argument is either NULL or a pointer to an SInt32 error code, if the connect failed.
2809                         if(pData)
2810                                 [self doSocketOpen:sock withCFSocketError:kCFSocketError];
2811                         else
2812                                 [self doSocketOpen:sock withCFSocketError:kCFSocketSuccess];
2813                         break;
2814                 case kCFSocketAcceptCallBack:
2815                         [self doAcceptWithSocket: *((CFSocketNativeHandle *)pData)];
2816                         break;
2817                 default:
2818                         NSLog (@"AsyncSocket %p received unexpected CFSocketCallBackType %d.", self, type);
2819                         break;
2820         }
2821 }
2822
2823 - (void)doCFReadStreamCallback:(CFStreamEventType)type forStream:(CFReadStreamRef)stream
2824 {
2825         NSParameterAssert(theReadStream != NULL);
2826         
2827         CFStreamError err;
2828         switch (type)
2829         {
2830                 case kCFStreamEventOpenCompleted:
2831                         [self doStreamOpen];
2832                         break;
2833                 case kCFStreamEventHasBytesAvailable:
2834                         if(theFlags & kStartingTLS)
2835                                 [self onTLSStarted:YES];
2836                         else
2837                                 [self doBytesAvailable];
2838                         break;
2839                 case kCFStreamEventErrorOccurred:
2840                 case kCFStreamEventEndEncountered:
2841                         err = CFReadStreamGetError (theReadStream);
2842                         [self closeWithError: [self errorFromCFStreamError:err]];
2843                         break;
2844                 default:
2845                         NSLog (@"AsyncSocket %p received unexpected CFReadStream callback, CFStreamEventType %d.", self, type);
2846         }
2847 }
2848
2849 - (void)doCFWriteStreamCallback:(CFStreamEventType)type forStream:(CFWriteStreamRef)stream
2850 {
2851         NSParameterAssert(theWriteStream != NULL);
2852         
2853         CFStreamError err;
2854         switch (type)
2855         {
2856                 case kCFStreamEventOpenCompleted:
2857                         [self doStreamOpen];
2858                         break;
2859                 case kCFStreamEventCanAcceptBytes:
2860                         if(theFlags & kStartingTLS)
2861                                 [self onTLSStarted:YES];
2862                         else
2863                                 [self doSendBytes];
2864                         break;
2865                 case kCFStreamEventErrorOccurred:
2866                 case kCFStreamEventEndEncountered:
2867                         err = CFWriteStreamGetError (theWriteStream);
2868                         [self closeWithError: [self errorFromCFStreamError:err]];
2869                         break;
2870                 default:
2871                         NSLog (@"AsyncSocket %p received unexpected CFWriteStream callback, CFStreamEventType %d.", self, type);
2872         }
2873 }
2874
2875 /**
2876  * This is the callback we setup for CFSocket.
2877  * This method does nothing but forward the call to it's Objective-C counterpart
2878 **/
2879 static void MyCFSocketCallback (CFSocketRef sref, CFSocketCallBackType type, CFDataRef address, const void *pData, void *pInfo)
2880 {
2881         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2882         
2883         AsyncSocket *socket = [[(AsyncSocket *)pInfo retain] autorelease];
2884         [socket doCFSocketCallback:type forSocket:sref withAddress:(NSData *)address withData:pData];
2885         
2886         [pool release];
2887 }
2888
2889 /**
2890  * This is the callback we setup for CFReadStream.
2891  * This method does nothing but forward the call to it's Objective-C counterpart
2892 **/
2893 static void MyCFReadStreamCallback (CFReadStreamRef stream, CFStreamEventType type, void *pInfo)
2894 {
2895         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2896         
2897         AsyncSocket *socket = [[(AsyncSocket *)pInfo retain] autorelease];
2898         [socket doCFReadStreamCallback:type forStream:stream];
2899         
2900         [pool release];
2901 }
2902
2903 /**
2904  * This is the callback we setup for CFWriteStream.
2905  * This method does nothing but forward the call to it's Objective-C counterpart
2906 **/
2907 static void MyCFWriteStreamCallback (CFWriteStreamRef stream, CFStreamEventType type, void *pInfo)
2908 {
2909         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2910         
2911         AsyncSocket *socket = [[(AsyncSocket *)pInfo retain] autorelease];
2912         [socket doCFWriteStreamCallback:type forStream:stream];
2913         
2914         [pool release];
2915 }
2916
2917 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2918 #pragma mark Class Methods
2919 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2920
2921 // Return line separators.
2922 + (NSData *)CRLFData
2923 {
2924         return [NSData dataWithBytes:"\x0D\x0A" length:2];
2925 }
2926
2927 + (NSData *)CRData
2928 {
2929         return [NSData dataWithBytes:"\x0D" length:1];
2930 }
2931
2932 + (NSData *)LFData
2933 {
2934         return [NSData dataWithBytes:"\x0A" length:1];
2935 }
2936
2937 + (NSData *)ZeroData
2938 {
2939         return [NSData dataWithBytes:"" length:1];
2940 }
2941
2942 @end