AsyncSocket.m
上传用户:kc0325
上传日期:2020-06-20
资源大小:204k
文件大小:86k
源码类别:

iPhone

开发平台:

Objective-C

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