PageRenderTime 91ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 1ms

/io/libraries/CocoaAsyncSocket/AsyncSocket.m

https://gitlab.com/base.io/io
Objective C | 1632 lines | 1091 code | 288 blank | 253 comment | 238 complexity | e02a0d7d31b5ca43593281396cf8de94 MD5 | raw file
  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. #if ! __has_feature(objc_arc)
  11. #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
  12. #endif
  13. #import "AsyncSocket.h"
  14. #import <sys/socket.h>
  15. #import <netinet/in.h>
  16. #import <arpa/inet.h>
  17. #import <netdb.h>
  18. #if TARGET_OS_IPHONE
  19. // Note: You may need to add the CFNetwork Framework to your project
  20. #import <CFNetwork/CFNetwork.h>
  21. #endif
  22. #pragma mark Declarations
  23. #define DEFAULT_PREBUFFERING YES // Whether pre-buffering is enabled by default
  24. #define READQUEUE_CAPACITY 5 // Initial capacity
  25. #define WRITEQUEUE_CAPACITY 5 // Initial capacity
  26. #define READALL_CHUNKSIZE 256 // Incremental increase in buffer size
  27. #define WRITE_CHUNKSIZE (1024 * 4) // Limit on size of each write pass
  28. // AsyncSocket is RunLoop based, and is thus not thread-safe.
  29. // You must always access your AsyncSocket instance from the thread/runloop in which the instance is running.
  30. // You can use methods such as performSelectorOnThread to accomplish this.
  31. // Failure to comply with these thread-safety rules may result in errors.
  32. // You can enable this option to help diagnose where you are incorrectly accessing your socket.
  33. #if DEBUG
  34. #define DEBUG_THREAD_SAFETY 1
  35. #else
  36. #define DEBUG_THREAD_SAFETY 0
  37. #endif
  38. //
  39. // If you constantly need to access your socket from multiple threads
  40. // then you may consider using GCDAsyncSocket instead, which is thread-safe.
  41. NSString *const AsyncSocketException = @"AsyncSocketException";
  42. NSString *const AsyncSocketErrorDomain = @"AsyncSocketErrorDomain";
  43. enum AsyncSocketFlags
  44. {
  45. kEnablePreBuffering = 1 << 0, // If set, pre-buffering is enabled
  46. kDidStartDelegate = 1 << 1, // If set, disconnection results in delegate call
  47. kDidCompleteOpenForRead = 1 << 2, // If set, open callback has been called for read stream
  48. kDidCompleteOpenForWrite = 1 << 3, // If set, open callback has been called for write stream
  49. kStartingReadTLS = 1 << 4, // If set, we're waiting for TLS negotiation to complete
  50. kStartingWriteTLS = 1 << 5, // If set, we're waiting for TLS negotiation to complete
  51. kForbidReadsWrites = 1 << 6, // If set, no new reads or writes are allowed
  52. kDisconnectAfterReads = 1 << 7, // If set, disconnect after no more reads are queued
  53. kDisconnectAfterWrites = 1 << 8, // If set, disconnect after no more writes are queued
  54. kClosingWithError = 1 << 9, // If set, the socket is being closed due to an error
  55. kDequeueReadScheduled = 1 << 10, // If set, a maybeDequeueRead operation is already scheduled
  56. kDequeueWriteScheduled = 1 << 11, // If set, a maybeDequeueWrite operation is already scheduled
  57. kSocketCanAcceptBytes = 1 << 12, // If set, we know socket can accept bytes. If unset, it's unknown.
  58. kSocketHasBytesAvailable = 1 << 13, // If set, we know socket has bytes available. If unset, it's unknown.
  59. };
  60. @interface AsyncSocket (Private)
  61. // Connecting
  62. - (void)startConnectTimeout:(NSTimeInterval)timeout;
  63. - (void)endConnectTimeout;
  64. - (void)doConnectTimeout:(NSTimer *)timer;
  65. // Socket Implementation
  66. - (CFSocketRef)newAcceptSocketForAddress:(NSData *)addr error:(NSError **)errPtr;
  67. - (BOOL)createSocketForAddress:(NSData *)remoteAddr error:(NSError **)errPtr;
  68. - (BOOL)bindSocketToAddress:(NSData *)interfaceAddr error:(NSError **)errPtr;
  69. - (BOOL)attachSocketsToRunLoop:(NSRunLoop *)runLoop error:(NSError **)errPtr;
  70. - (BOOL)configureSocketAndReturnError:(NSError **)errPtr;
  71. - (BOOL)connectSocketToAddress:(NSData *)remoteAddr error:(NSError **)errPtr;
  72. - (void)doAcceptWithSocket:(CFSocketNativeHandle)newSocket;
  73. - (void)doSocketOpen:(CFSocketRef)sock withCFSocketError:(CFSocketError)err;
  74. // Stream Implementation
  75. - (BOOL)createStreamsFromNative:(CFSocketNativeHandle)native error:(NSError **)errPtr;
  76. - (BOOL)createStreamsToHost:(NSString *)hostname onPort:(UInt16)port error:(NSError **)errPtr;
  77. - (BOOL)attachStreamsToRunLoop:(NSRunLoop *)runLoop error:(NSError **)errPtr;
  78. - (BOOL)configureStreamsAndReturnError:(NSError **)errPtr;
  79. - (BOOL)openStreamsAndReturnError:(NSError **)errPtr;
  80. - (void)doStreamOpen;
  81. - (BOOL)setSocketFromStreamsAndReturnError:(NSError **)errPtr;
  82. // Disconnect Implementation
  83. - (void)closeWithError:(NSError *)err;
  84. - (void)recoverUnreadData;
  85. - (void)emptyQueues;
  86. - (void)close;
  87. // Errors
  88. - (NSError *)getErrnoError;
  89. - (NSError *)getAbortError;
  90. - (NSError *)getStreamError;
  91. - (NSError *)getSocketError;
  92. - (NSError *)getConnectTimeoutError;
  93. - (NSError *)getReadMaxedOutError;
  94. - (NSError *)getReadTimeoutError;
  95. - (NSError *)getWriteTimeoutError;
  96. - (NSError *)errorFromCFStreamError:(CFStreamError)err;
  97. // Diagnostics
  98. - (BOOL)isDisconnected;
  99. - (BOOL)areStreamsConnected;
  100. - (NSString *)connectedHostFromNativeSocket4:(CFSocketNativeHandle)theNativeSocket;
  101. - (NSString *)connectedHostFromNativeSocket6:(CFSocketNativeHandle)theNativeSocket;
  102. - (NSString *)connectedHostFromCFSocket4:(CFSocketRef)socket;
  103. - (NSString *)connectedHostFromCFSocket6:(CFSocketRef)socket;
  104. - (UInt16)connectedPortFromNativeSocket4:(CFSocketNativeHandle)theNativeSocket;
  105. - (UInt16)connectedPortFromNativeSocket6:(CFSocketNativeHandle)theNativeSocket;
  106. - (UInt16)connectedPortFromCFSocket4:(CFSocketRef)socket;
  107. - (UInt16)connectedPortFromCFSocket6:(CFSocketRef)socket;
  108. - (NSString *)localHostFromNativeSocket4:(CFSocketNativeHandle)theNativeSocket;
  109. - (NSString *)localHostFromNativeSocket6:(CFSocketNativeHandle)theNativeSocket;
  110. - (NSString *)localHostFromCFSocket4:(CFSocketRef)socket;
  111. - (NSString *)localHostFromCFSocket6:(CFSocketRef)socket;
  112. - (UInt16)localPortFromNativeSocket4:(CFSocketNativeHandle)theNativeSocket;
  113. - (UInt16)localPortFromNativeSocket6:(CFSocketNativeHandle)theNativeSocket;
  114. - (UInt16)localPortFromCFSocket4:(CFSocketRef)socket;
  115. - (UInt16)localPortFromCFSocket6:(CFSocketRef)socket;
  116. - (NSString *)hostFromAddress4:(struct sockaddr_in *)pSockaddr4;
  117. - (NSString *)hostFromAddress6:(struct sockaddr_in6 *)pSockaddr6;
  118. - (UInt16)portFromAddress4:(struct sockaddr_in *)pSockaddr4;
  119. - (UInt16)portFromAddress6:(struct sockaddr_in6 *)pSockaddr6;
  120. // Reading
  121. - (void)doBytesAvailable;
  122. - (void)completeCurrentRead;
  123. - (void)endCurrentRead;
  124. - (void)scheduleDequeueRead;
  125. - (void)maybeDequeueRead;
  126. - (void)doReadTimeout:(NSTimer *)timer;
  127. // Writing
  128. - (void)doSendBytes;
  129. - (void)completeCurrentWrite;
  130. - (void)endCurrentWrite;
  131. - (void)scheduleDequeueWrite;
  132. - (void)maybeDequeueWrite;
  133. - (void)maybeScheduleDisconnect;
  134. - (void)doWriteTimeout:(NSTimer *)timer;
  135. // Run Loop
  136. - (void)runLoopAddSource:(CFRunLoopSourceRef)source;
  137. - (void)runLoopRemoveSource:(CFRunLoopSourceRef)source;
  138. - (void)runLoopAddTimer:(NSTimer *)timer;
  139. - (void)runLoopRemoveTimer:(NSTimer *)timer;
  140. - (void)runLoopUnscheduleReadStream;
  141. - (void)runLoopUnscheduleWriteStream;
  142. // Security
  143. - (void)maybeStartTLS;
  144. - (void)onTLSHandshakeSuccessful;
  145. // Callbacks
  146. - (void)doCFCallback:(CFSocketCallBackType)type
  147. forSocket:(CFSocketRef)sock withAddress:(NSData *)address withData:(const void *)pData;
  148. - (void)doCFReadStreamCallback:(CFStreamEventType)type forStream:(CFReadStreamRef)stream;
  149. - (void)doCFWriteStreamCallback:(CFStreamEventType)type forStream:(CFWriteStreamRef)stream;
  150. @end
  151. static void MyCFSocketCallback(CFSocketRef, CFSocketCallBackType, CFDataRef, const void *, void *);
  152. static void MyCFReadStreamCallback(CFReadStreamRef stream, CFStreamEventType type, void *pInfo);
  153. static void MyCFWriteStreamCallback(CFWriteStreamRef stream, CFStreamEventType type, void *pInfo);
  154. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  155. #pragma mark -
  156. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  157. /**
  158. * The AsyncReadPacket encompasses the instructions for any given read.
  159. * The content of a read packet allows the code to determine if we're:
  160. * - reading to a certain length
  161. * - reading to a certain separator
  162. * - or simply reading the first chunk of available data
  163. **/
  164. @interface AsyncReadPacket : NSObject
  165. {
  166. @public
  167. NSMutableData *buffer;
  168. NSUInteger startOffset;
  169. NSUInteger bytesDone;
  170. NSUInteger maxLength;
  171. NSTimeInterval timeout;
  172. NSUInteger readLength;
  173. NSData *term;
  174. BOOL bufferOwner;
  175. NSUInteger originalBufferLength;
  176. long tag;
  177. }
  178. - (id)initWithData:(NSMutableData *)d
  179. startOffset:(NSUInteger)s
  180. maxLength:(NSUInteger)m
  181. timeout:(NSTimeInterval)t
  182. readLength:(NSUInteger)l
  183. terminator:(NSData *)e
  184. tag:(long)i;
  185. - (NSUInteger)readLengthForNonTerm;
  186. - (NSUInteger)readLengthForTerm;
  187. - (NSUInteger)readLengthForTermWithPreBuffer:(NSData *)preBuffer found:(BOOL *)foundPtr;
  188. - (NSUInteger)prebufferReadLengthForTerm;
  189. - (NSInteger)searchForTermAfterPreBuffering:(NSUInteger)numBytes;
  190. @end
  191. @implementation AsyncReadPacket
  192. - (id)initWithData:(NSMutableData *)d
  193. startOffset:(NSUInteger)s
  194. maxLength:(NSUInteger)m
  195. timeout:(NSTimeInterval)t
  196. readLength:(NSUInteger)l
  197. terminator:(NSData *)e
  198. tag:(long)i
  199. {
  200. if((self = [super init]))
  201. {
  202. if (d)
  203. {
  204. buffer = d;
  205. startOffset = s;
  206. bufferOwner = NO;
  207. originalBufferLength = [d length];
  208. }
  209. else
  210. {
  211. if (readLength > 0)
  212. buffer = [[NSMutableData alloc] initWithLength:readLength];
  213. else
  214. buffer = [[NSMutableData alloc] initWithLength:0];
  215. startOffset = 0;
  216. bufferOwner = YES;
  217. originalBufferLength = 0;
  218. }
  219. bytesDone = 0;
  220. maxLength = m;
  221. timeout = t;
  222. readLength = l;
  223. term = [e copy];
  224. tag = i;
  225. }
  226. return self;
  227. }
  228. /**
  229. * For read packets without a set terminator, returns the safe length of data that can be read
  230. * without exceeding the maxLength, or forcing a resize of the buffer if at all possible.
  231. **/
  232. - (NSUInteger)readLengthForNonTerm
  233. {
  234. NSAssert(term == nil, @"This method does not apply to term reads");
  235. if (readLength > 0)
  236. {
  237. // Read a specific length of data
  238. return readLength - bytesDone;
  239. // No need to avoid resizing the buffer.
  240. // It should be resized if the buffer space is less than the requested read length.
  241. }
  242. else
  243. {
  244. // Read all available data
  245. NSUInteger result = READALL_CHUNKSIZE;
  246. if (maxLength > 0)
  247. {
  248. result = MIN(result, (maxLength - bytesDone));
  249. }
  250. if (!bufferOwner)
  251. {
  252. // We did NOT create the buffer.
  253. // It is owned by the caller.
  254. // Avoid resizing the buffer if at all possible.
  255. if ([buffer length] == originalBufferLength)
  256. {
  257. NSUInteger buffSize = [buffer length];
  258. NSUInteger buffSpace = buffSize - startOffset - bytesDone;
  259. if (buffSpace > 0)
  260. {
  261. result = MIN(result, buffSpace);
  262. }
  263. }
  264. }
  265. return result;
  266. }
  267. }
  268. /**
  269. * For read packets with a set terminator, returns the safe length of data that can be read
  270. * without going over a terminator, or the maxLength, or forcing a resize of the buffer if at all possible.
  271. *
  272. * It is assumed the terminator has not already been read.
  273. **/
  274. - (NSUInteger)readLengthForTerm
  275. {
  276. NSAssert(term != nil, @"This method does not apply to non-term reads");
  277. // What we're going to do is look for a partial sequence of the terminator at the end of the buffer.
  278. // If a partial sequence occurs, then we must assume the next bytes to arrive will be the rest of the term,
  279. // and we can only read that amount.
  280. // Otherwise, we're safe to read the entire length of the term.
  281. NSUInteger termLength = [term length];
  282. // Shortcuts
  283. if (bytesDone == 0) return termLength;
  284. if (termLength == 1) return termLength;
  285. // i = index within buffer at which to check data
  286. // j = length of term to check against
  287. NSUInteger i, j;
  288. if (bytesDone >= termLength)
  289. {
  290. i = bytesDone - termLength + 1;
  291. j = termLength - 1;
  292. }
  293. else
  294. {
  295. i = 0;
  296. j = bytesDone;
  297. }
  298. NSUInteger result = termLength;
  299. void *buf = [buffer mutableBytes];
  300. const void *termBuf = [term bytes];
  301. while (i < bytesDone)
  302. {
  303. void *subbuf = buf + startOffset + i;
  304. if (memcmp(subbuf, termBuf, j) == 0)
  305. {
  306. result = termLength - j;
  307. break;
  308. }
  309. i++;
  310. j--;
  311. }
  312. if (maxLength > 0)
  313. {
  314. result = MIN(result, (maxLength - bytesDone));
  315. }
  316. if (!bufferOwner)
  317. {
  318. // We did NOT create the buffer.
  319. // It is owned by the caller.
  320. // Avoid resizing the buffer if at all possible.
  321. if ([buffer length] == originalBufferLength)
  322. {
  323. NSUInteger buffSize = [buffer length];
  324. NSUInteger buffSpace = buffSize - startOffset - bytesDone;
  325. if (buffSpace > 0)
  326. {
  327. result = MIN(result, buffSpace);
  328. }
  329. }
  330. }
  331. return result;
  332. }
  333. /**
  334. * For read packets with a set terminator,
  335. * returns the safe length of data that can be read from the given preBuffer,
  336. * without going over a terminator or the maxLength.
  337. *
  338. * It is assumed the terminator has not already been read.
  339. **/
  340. - (NSUInteger)readLengthForTermWithPreBuffer:(NSData *)preBuffer found:(BOOL *)foundPtr
  341. {
  342. NSAssert(term != nil, @"This method does not apply to non-term reads");
  343. NSAssert([preBuffer length] > 0, @"Invoked with empty pre buffer!");
  344. // We know that the terminator, as a whole, doesn't exist in our own buffer.
  345. // But it is possible that a portion of it exists in our buffer.
  346. // So we're going to look for the terminator starting with a portion of our own buffer.
  347. //
  348. // Example:
  349. //
  350. // term length = 3 bytes
  351. // bytesDone = 5 bytes
  352. // preBuffer length = 5 bytes
  353. //
  354. // If we append the preBuffer to our buffer,
  355. // it would look like this:
  356. //
  357. // ---------------------
  358. // |B|B|B|B|B|P|P|P|P|P|
  359. // ---------------------
  360. //
  361. // So we start our search here:
  362. //
  363. // ---------------------
  364. // |B|B|B|B|B|P|P|P|P|P|
  365. // -------^-^-^---------
  366. //
  367. // And move forwards...
  368. //
  369. // ---------------------
  370. // |B|B|B|B|B|P|P|P|P|P|
  371. // ---------^-^-^-------
  372. //
  373. // Until we find the terminator or reach the end.
  374. //
  375. // ---------------------
  376. // |B|B|B|B|B|P|P|P|P|P|
  377. // ---------------^-^-^-
  378. BOOL found = NO;
  379. NSUInteger termLength = [term length];
  380. NSUInteger preBufferLength = [preBuffer length];
  381. if ((bytesDone + preBufferLength) < termLength)
  382. {
  383. // Not enough data for a full term sequence yet
  384. return preBufferLength;
  385. }
  386. NSUInteger maxPreBufferLength;
  387. if (maxLength > 0) {
  388. maxPreBufferLength = MIN(preBufferLength, (maxLength - bytesDone));
  389. // Note: maxLength >= termLength
  390. }
  391. else {
  392. maxPreBufferLength = preBufferLength;
  393. }
  394. Byte seq[termLength];
  395. const void *termBuf = [term bytes];
  396. NSUInteger bufLen = MIN(bytesDone, (termLength - 1));
  397. void *buf = [buffer mutableBytes] + startOffset + bytesDone - bufLen;
  398. NSUInteger preLen = termLength - bufLen;
  399. void *pre = (void *)[preBuffer bytes];
  400. NSUInteger loopCount = bufLen + maxPreBufferLength - termLength + 1; // Plus one. See example above.
  401. NSUInteger result = preBufferLength;
  402. NSUInteger i;
  403. for (i = 0; i < loopCount; i++)
  404. {
  405. if (bufLen > 0)
  406. {
  407. // Combining bytes from buffer and preBuffer
  408. memcpy(seq, buf, bufLen);
  409. memcpy(seq + bufLen, pre, preLen);
  410. if (memcmp(seq, termBuf, termLength) == 0)
  411. {
  412. result = preLen;
  413. found = YES;
  414. break;
  415. }
  416. buf++;
  417. bufLen--;
  418. preLen++;
  419. }
  420. else
  421. {
  422. // Comparing directly from preBuffer
  423. if (memcmp(pre, termBuf, termLength) == 0)
  424. {
  425. NSUInteger preOffset = pre - [preBuffer bytes]; // pointer arithmetic
  426. result = preOffset + termLength;
  427. found = YES;
  428. break;
  429. }
  430. pre++;
  431. }
  432. }
  433. // There is no need to avoid resizing the buffer in this particular situation.
  434. if (foundPtr) *foundPtr = found;
  435. return result;
  436. }
  437. /**
  438. * Assuming pre-buffering is enabled, returns the amount of data that can be read
  439. * without going over the maxLength.
  440. **/
  441. - (NSUInteger)prebufferReadLengthForTerm
  442. {
  443. NSAssert(term != nil, @"This method does not apply to non-term reads");
  444. NSUInteger result = READALL_CHUNKSIZE;
  445. if (maxLength > 0)
  446. {
  447. result = MIN(result, (maxLength - bytesDone));
  448. }
  449. if (!bufferOwner)
  450. {
  451. // We did NOT create the buffer.
  452. // It is owned by the caller.
  453. // Avoid resizing the buffer if at all possible.
  454. if ([buffer length] == originalBufferLength)
  455. {
  456. NSUInteger buffSize = [buffer length];
  457. NSUInteger buffSpace = buffSize - startOffset - bytesDone;
  458. if (buffSpace > 0)
  459. {
  460. result = MIN(result, buffSpace);
  461. }
  462. }
  463. }
  464. return result;
  465. }
  466. /**
  467. * For read packets with a set terminator, scans the packet buffer for the term.
  468. * It is assumed the terminator had not been fully read prior to the new bytes.
  469. *
  470. * If the term is found, the number of excess bytes after the term are returned.
  471. * If the term is not found, this method will return -1.
  472. *
  473. * Note: A return value of zero means the term was found at the very end.
  474. **/
  475. - (NSInteger)searchForTermAfterPreBuffering:(NSUInteger)numBytes
  476. {
  477. NSAssert(term != nil, @"This method does not apply to non-term reads");
  478. NSAssert(bytesDone >= numBytes, @"Invoked with invalid numBytes!");
  479. // We try to start the search such that the first new byte read matches up with the last byte of the term.
  480. // We continue searching forward after this until the term no longer fits into the buffer.
  481. NSUInteger termLength = [term length];
  482. const void *termBuffer = [term bytes];
  483. // Remember: This method is called after the bytesDone variable has been updated.
  484. NSUInteger prevBytesDone = bytesDone - numBytes;
  485. NSUInteger i;
  486. if (prevBytesDone >= termLength)
  487. i = prevBytesDone - termLength + 1;
  488. else
  489. i = 0;
  490. while ((i + termLength) <= bytesDone)
  491. {
  492. void *subBuffer = [buffer mutableBytes] + startOffset + i;
  493. if(memcmp(subBuffer, termBuffer, termLength) == 0)
  494. {
  495. return bytesDone - (i + termLength);
  496. }
  497. i++;
  498. }
  499. return -1;
  500. }
  501. @end
  502. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  503. #pragma mark -
  504. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  505. /**
  506. * The AsyncWritePacket encompasses the instructions for any given write.
  507. **/
  508. @interface AsyncWritePacket : NSObject
  509. {
  510. @public
  511. NSData *buffer;
  512. NSUInteger bytesDone;
  513. long tag;
  514. NSTimeInterval timeout;
  515. }
  516. - (id)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i;
  517. @end
  518. @implementation AsyncWritePacket
  519. - (id)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i
  520. {
  521. if((self = [super init]))
  522. {
  523. buffer = d;
  524. timeout = t;
  525. tag = i;
  526. bytesDone = 0;
  527. }
  528. return self;
  529. }
  530. @end
  531. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  532. #pragma mark -
  533. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  534. /**
  535. * The AsyncSpecialPacket encompasses special instructions for interruptions in the read/write queues.
  536. * This class my be altered to support more than just TLS in the future.
  537. **/
  538. @interface AsyncSpecialPacket : NSObject
  539. {
  540. @public
  541. NSDictionary *tlsSettings;
  542. }
  543. - (id)initWithTLSSettings:(NSDictionary *)settings;
  544. @end
  545. @implementation AsyncSpecialPacket
  546. - (id)initWithTLSSettings:(NSDictionary *)settings
  547. {
  548. if((self = [super init]))
  549. {
  550. tlsSettings = [settings copy];
  551. }
  552. return self;
  553. }
  554. @end
  555. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  556. #pragma mark -
  557. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  558. @implementation AsyncSocket
  559. - (id)init
  560. {
  561. return [self initWithDelegate:nil userData:0];
  562. }
  563. - (id)initWithDelegate:(id)delegate
  564. {
  565. return [self initWithDelegate:delegate userData:0];
  566. }
  567. // Designated initializer.
  568. - (id)initWithDelegate:(id)delegate userData:(long)userData
  569. {
  570. if((self = [super init]))
  571. {
  572. theFlags = DEFAULT_PREBUFFERING ? kEnablePreBuffering : 0;
  573. theDelegate = delegate;
  574. theUserData = userData;
  575. theNativeSocket4 = 0;
  576. theNativeSocket6 = 0;
  577. theSocket4 = NULL;
  578. theSource4 = NULL;
  579. theSocket6 = NULL;
  580. theSource6 = NULL;
  581. theRunLoop = NULL;
  582. theReadStream = NULL;
  583. theWriteStream = NULL;
  584. theConnectTimer = nil;
  585. theReadQueue = [[NSMutableArray alloc] initWithCapacity:READQUEUE_CAPACITY];
  586. theCurrentRead = nil;
  587. theReadTimer = nil;
  588. partialReadBuffer = [[NSMutableData alloc] initWithCapacity:READALL_CHUNKSIZE];
  589. theWriteQueue = [[NSMutableArray alloc] initWithCapacity:WRITEQUEUE_CAPACITY];
  590. theCurrentWrite = nil;
  591. theWriteTimer = nil;
  592. // Socket context
  593. NSAssert(sizeof(CFSocketContext) == sizeof(CFStreamClientContext), @"CFSocketContext != CFStreamClientContext");
  594. theContext.version = 0;
  595. theContext.info = (__bridge void *)(self);
  596. theContext.retain = nil;
  597. theContext.release = nil;
  598. theContext.copyDescription = nil;
  599. // Default run loop modes
  600. theRunLoopModes = [NSArray arrayWithObject:NSDefaultRunLoopMode];
  601. }
  602. return self;
  603. }
  604. // The socket may been initialized in a connected state and auto-released, so this should close it down cleanly.
  605. - (void)dealloc
  606. {
  607. [self close];
  608. [NSObject cancelPreviousPerformRequestsWithTarget:self];
  609. }
  610. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  611. #pragma mark Thread-Safety
  612. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  613. - (void)checkForThreadSafety
  614. {
  615. if (theRunLoop && (theRunLoop != CFRunLoopGetCurrent()))
  616. {
  617. // AsyncSocket is RunLoop based.
  618. // It is designed to be run and accessed from a particular thread/runloop.
  619. // As such, it is faster as it does not have the overhead of locks/synchronization.
  620. //
  621. // However, this places a minimal requirement on the developer to maintain thread-safety.
  622. // If you are seeing errors or crashes in AsyncSocket,
  623. // it is very likely that thread-safety has been broken.
  624. // This method may be enabled via the DEBUG_THREAD_SAFETY macro,
  625. // and will allow you to discover the place in your code where thread-safety is being broken.
  626. //
  627. // Note:
  628. //
  629. // If you find you constantly need to access your socket from various threads,
  630. // you may prefer to use GCDAsyncSocket which is thread-safe.
  631. [NSException raise:AsyncSocketException
  632. format:@"Attempting to access AsyncSocket instance from incorrect thread."];
  633. }
  634. }
  635. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  636. #pragma mark Accessors
  637. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  638. - (long)userData
  639. {
  640. #if DEBUG_THREAD_SAFETY
  641. [self checkForThreadSafety];
  642. #endif
  643. return theUserData;
  644. }
  645. - (void)setUserData:(long)userData
  646. {
  647. #if DEBUG_THREAD_SAFETY
  648. [self checkForThreadSafety];
  649. #endif
  650. theUserData = userData;
  651. }
  652. - (id)delegate
  653. {
  654. #if DEBUG_THREAD_SAFETY
  655. [self checkForThreadSafety];
  656. #endif
  657. return theDelegate;
  658. }
  659. - (void)setDelegate:(id)delegate
  660. {
  661. #if DEBUG_THREAD_SAFETY
  662. [self checkForThreadSafety];
  663. #endif
  664. theDelegate = delegate;
  665. }
  666. - (BOOL)canSafelySetDelegate
  667. {
  668. #if DEBUG_THREAD_SAFETY
  669. [self checkForThreadSafety];
  670. #endif
  671. return ([theReadQueue count] == 0 && [theWriteQueue count] == 0 && theCurrentRead == nil && theCurrentWrite == nil);
  672. }
  673. - (CFSocketRef)getCFSocket
  674. {
  675. #if DEBUG_THREAD_SAFETY
  676. [self checkForThreadSafety];
  677. #endif
  678. if(theSocket4)
  679. return theSocket4;
  680. else
  681. return theSocket6;
  682. }
  683. - (CFReadStreamRef)getCFReadStream
  684. {
  685. #if DEBUG_THREAD_SAFETY
  686. [self checkForThreadSafety];
  687. #endif
  688. return theReadStream;
  689. }
  690. - (CFWriteStreamRef)getCFWriteStream
  691. {
  692. #if DEBUG_THREAD_SAFETY
  693. [self checkForThreadSafety];
  694. #endif
  695. return theWriteStream;
  696. }
  697. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  698. #pragma mark Progress
  699. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  700. - (float)progressOfReadReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total
  701. {
  702. #if DEBUG_THREAD_SAFETY
  703. [self checkForThreadSafety];
  704. #endif
  705. // Check to make sure we're actually reading something right now,
  706. // and that the read packet isn't an AsyncSpecialPacket (upgrade to TLS).
  707. if (!theCurrentRead || ![theCurrentRead isKindOfClass:[AsyncReadPacket class]])
  708. {
  709. if (tag != NULL) *tag = 0;
  710. if (done != NULL) *done = 0;
  711. if (total != NULL) *total = 0;
  712. return NAN;
  713. }
  714. // It's only possible to know the progress of our read if we're reading to a certain length.
  715. // If we're reading to data, we of course have no idea when the data will arrive.
  716. // If we're reading to timeout, then we have no idea when the next chunk of data will arrive.
  717. NSUInteger d = theCurrentRead->bytesDone;
  718. NSUInteger t = theCurrentRead->readLength;
  719. if (tag != NULL) *tag = theCurrentRead->tag;
  720. if (done != NULL) *done = d;
  721. if (total != NULL) *total = t;
  722. if (t > 0.0)
  723. return (float)d / (float)t;
  724. else
  725. return 1.0F;
  726. }
  727. - (float)progressOfWriteReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total
  728. {
  729. #if DEBUG_THREAD_SAFETY
  730. [self checkForThreadSafety];
  731. #endif
  732. // Check to make sure we're actually writing something right now,
  733. // and that the write packet isn't an AsyncSpecialPacket (upgrade to TLS).
  734. if (!theCurrentWrite || ![theCurrentWrite isKindOfClass:[AsyncWritePacket class]])
  735. {
  736. if (tag != NULL) *tag = 0;
  737. if (done != NULL) *done = 0;
  738. if (total != NULL) *total = 0;
  739. return NAN;
  740. }
  741. NSUInteger d = theCurrentWrite->bytesDone;
  742. NSUInteger t = [theCurrentWrite->buffer length];
  743. if (tag != NULL) *tag = theCurrentWrite->tag;
  744. if (done != NULL) *done = d;
  745. if (total != NULL) *total = t;
  746. return (float)d / (float)t;
  747. }
  748. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  749. #pragma mark Run Loop
  750. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  751. - (void)runLoopAddSource:(CFRunLoopSourceRef)source
  752. {
  753. for (NSString *runLoopMode in theRunLoopModes)
  754. {
  755. CFRunLoopAddSource(theRunLoop, source, (__bridge CFStringRef)runLoopMode);
  756. }
  757. }
  758. - (void)runLoopRemoveSource:(CFRunLoopSourceRef)source
  759. {
  760. for (NSString *runLoopMode in theRunLoopModes)
  761. {
  762. CFRunLoopRemoveSource(theRunLoop, source, (__bridge CFStringRef)runLoopMode);
  763. }
  764. }
  765. - (void)runLoopAddSource:(CFRunLoopSourceRef)source mode:(NSString *)runLoopMode
  766. {
  767. CFRunLoopAddSource(theRunLoop, source, (__bridge CFStringRef)runLoopMode);
  768. }
  769. - (void)runLoopRemoveSource:(CFRunLoopSourceRef)source mode:(NSString *)runLoopMode
  770. {
  771. CFRunLoopRemoveSource(theRunLoop, source, (__bridge CFStringRef)runLoopMode);
  772. }
  773. - (void)runLoopAddTimer:(NSTimer *)timer
  774. {
  775. for (NSString *runLoopMode in theRunLoopModes)
  776. {
  777. CFRunLoopAddTimer(theRunLoop, (__bridge CFRunLoopTimerRef)timer, (__bridge CFStringRef)runLoopMode);
  778. }
  779. }
  780. - (void)runLoopRemoveTimer:(NSTimer *)timer
  781. {
  782. for (NSString *runLoopMode in theRunLoopModes)
  783. {
  784. CFRunLoopRemoveTimer(theRunLoop, (__bridge CFRunLoopTimerRef)timer, (__bridge CFStringRef)runLoopMode);
  785. }
  786. }
  787. - (void)runLoopAddTimer:(NSTimer *)timer mode:(NSString *)runLoopMode
  788. {
  789. CFRunLoopAddTimer(theRunLoop, (__bridge CFRunLoopTimerRef)timer, (__bridge CFStringRef)runLoopMode);
  790. }
  791. - (void)runLoopRemoveTimer:(NSTimer *)timer mode:(NSString *)runLoopMode
  792. {
  793. CFRunLoopRemoveTimer(theRunLoop, (__bridge CFRunLoopTimerRef)timer, (__bridge CFStringRef)runLoopMode);
  794. }
  795. - (void)runLoopUnscheduleReadStream
  796. {
  797. for (NSString *runLoopMode in theRunLoopModes)
  798. {
  799. CFReadStreamUnscheduleFromRunLoop(theReadStream, theRunLoop, (__bridge CFStringRef)runLoopMode);
  800. }
  801. CFReadStreamSetClient(theReadStream, kCFStreamEventNone, NULL, NULL);
  802. }
  803. - (void)runLoopUnscheduleWriteStream
  804. {
  805. for (NSString *runLoopMode in theRunLoopModes)
  806. {
  807. CFWriteStreamUnscheduleFromRunLoop(theWriteStream, theRunLoop, (__bridge CFStringRef)runLoopMode);
  808. }
  809. CFWriteStreamSetClient(theWriteStream, kCFStreamEventNone, NULL, NULL);
  810. }
  811. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  812. #pragma mark Configuration
  813. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  814. /**
  815. * See the header file for a full explanation of pre-buffering.
  816. **/
  817. - (void)enablePreBuffering
  818. {
  819. #if DEBUG_THREAD_SAFETY
  820. [self checkForThreadSafety];
  821. #endif
  822. theFlags |= kEnablePreBuffering;
  823. }
  824. /**
  825. * See the header file for a full explanation of this method.
  826. **/
  827. - (BOOL)moveToRunLoop:(NSRunLoop *)runLoop
  828. {
  829. NSAssert((theRunLoop == NULL) || (theRunLoop == CFRunLoopGetCurrent()),
  830. @"moveToRunLoop must be called from within the current RunLoop!");
  831. if(runLoop == nil)
  832. {
  833. return NO;
  834. }
  835. if(theRunLoop == [runLoop getCFRunLoop])
  836. {
  837. return YES;
  838. }
  839. [NSObject cancelPreviousPerformRequestsWithTarget:self];
  840. theFlags &= ~kDequeueReadScheduled;
  841. theFlags &= ~kDequeueWriteScheduled;
  842. if(theReadStream && theWriteStream)
  843. {
  844. [self runLoopUnscheduleReadStream];
  845. [self runLoopUnscheduleWriteStream];
  846. }
  847. if(theSource4) [self runLoopRemoveSource:theSource4];
  848. if(theSource6) [self runLoopRemoveSource:theSource6];
  849. if(theReadTimer) [self runLoopRemoveTimer:theReadTimer];
  850. if(theWriteTimer) [self runLoopRemoveTimer:theWriteTimer];
  851. theRunLoop = [runLoop getCFRunLoop];
  852. if(theReadTimer) [self runLoopAddTimer:theReadTimer];
  853. if(theWriteTimer) [self runLoopAddTimer:theWriteTimer];
  854. if(theSource4) [self runLoopAddSource:theSource4];
  855. if(theSource6) [self runLoopAddSource:theSource6];
  856. if(theReadStream && theWriteStream)
  857. {
  858. if(![self attachStreamsToRunLoop:runLoop error:nil])
  859. {
  860. return NO;
  861. }
  862. }
  863. [runLoop performSelector:@selector(maybeDequeueRead) target:self argument:nil order:0 modes:theRunLoopModes];
  864. [runLoop performSelector:@selector(maybeDequeueWrite) target:self argument:nil order:0 modes:theRunLoopModes];
  865. [runLoop performSelector:@selector(maybeScheduleDisconnect) target:self argument:nil order:0 modes:theRunLoopModes];
  866. return YES;
  867. }
  868. /**
  869. * See the header file for a full explanation of this method.
  870. **/
  871. - (BOOL)setRunLoopModes:(NSArray *)runLoopModes
  872. {
  873. NSAssert((theRunLoop == NULL) || (theRunLoop == CFRunLoopGetCurrent()),
  874. @"setRunLoopModes must be called from within the current RunLoop!");
  875. if([runLoopModes count] == 0)
  876. {
  877. return NO;
  878. }
  879. if([theRunLoopModes isEqualToArray:runLoopModes])
  880. {
  881. return YES;
  882. }
  883. [NSObject cancelPreviousPerformRequestsWithTarget:self];
  884. theFlags &= ~kDequeueReadScheduled;
  885. theFlags &= ~kDequeueWriteScheduled;
  886. if(theReadStream && theWriteStream)
  887. {
  888. [self runLoopUnscheduleReadStream];
  889. [self runLoopUnscheduleWriteStream];
  890. }
  891. if(theSource4) [self runLoopRemoveSource:theSource4];
  892. if(theSource6) [self runLoopRemoveSource:theSource6];
  893. if(theReadTimer) [self runLoopRemoveTimer:theReadTimer];
  894. if(theWriteTimer) [self runLoopRemoveTimer:theWriteTimer];
  895. theRunLoopModes = [runLoopModes copy];
  896. if(theReadTimer) [self runLoopAddTimer:theReadTimer];
  897. if(theWriteTimer) [self runLoopAddTimer:theWriteTimer];
  898. if(theSource4) [self runLoopAddSource:theSource4];
  899. if(theSource6) [self runLoopAddSource:theSource6];
  900. if(theReadStream && theWriteStream)
  901. {
  902. // Note: theRunLoop variable is a CFRunLoop, and NSRunLoop is NOT toll-free bridged with CFRunLoop.
  903. // So we cannot pass theRunLoop to the method below, which is expecting a NSRunLoop parameter.
  904. // Instead we pass nil, which will result in the method properly using the current run loop.
  905. if(![self attachStreamsToRunLoop:nil error:nil])
  906. {
  907. return NO;
  908. }
  909. }
  910. [self performSelector:@selector(maybeDequeueRead) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  911. [self performSelector:@selector(maybeDequeueWrite) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  912. [self performSelector:@selector(maybeScheduleDisconnect) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  913. return YES;
  914. }
  915. - (BOOL)addRunLoopMode:(NSString *)runLoopMode
  916. {
  917. NSAssert((theRunLoop == NULL) || (theRunLoop == CFRunLoopGetCurrent()),
  918. @"addRunLoopMode must be called from within the current RunLoop!");
  919. if(runLoopMode == nil)
  920. {
  921. return NO;
  922. }
  923. if([theRunLoopModes containsObject:runLoopMode])
  924. {
  925. return YES;
  926. }
  927. [NSObject cancelPreviousPerformRequestsWithTarget:self];
  928. theFlags &= ~kDequeueReadScheduled;
  929. theFlags &= ~kDequeueWriteScheduled;
  930. NSArray *newRunLoopModes = [theRunLoopModes arrayByAddingObject:runLoopMode];
  931. theRunLoopModes = newRunLoopModes;
  932. if(theReadTimer) [self runLoopAddTimer:theReadTimer mode:runLoopMode];
  933. if(theWriteTimer) [self runLoopAddTimer:theWriteTimer mode:runLoopMode];
  934. if(theSource4) [self runLoopAddSource:theSource4 mode:runLoopMode];
  935. if(theSource6) [self runLoopAddSource:theSource6 mode:runLoopMode];
  936. if(theReadStream && theWriteStream)
  937. {
  938. CFReadStreamScheduleWithRunLoop(theReadStream, CFRunLoopGetCurrent(), (__bridge CFStringRef)runLoopMode);
  939. CFWriteStreamScheduleWithRunLoop(theWriteStream, CFRunLoopGetCurrent(), (__bridge CFStringRef)runLoopMode);
  940. }
  941. [self performSelector:@selector(maybeDequeueRead) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  942. [self performSelector:@selector(maybeDequeueWrite) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  943. [self performSelector:@selector(maybeScheduleDisconnect) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  944. return YES;
  945. }
  946. - (BOOL)removeRunLoopMode:(NSString *)runLoopMode
  947. {
  948. NSAssert((theRunLoop == NULL) || (theRunLoop == CFRunLoopGetCurrent()),
  949. @"addRunLoopMode must be called from within the current RunLoop!");
  950. if(runLoopMode == nil)
  951. {
  952. return NO;
  953. }
  954. if(![theRunLoopModes containsObject:runLoopMode])
  955. {
  956. return YES;
  957. }
  958. NSMutableArray *newRunLoopModes = [theRunLoopModes mutableCopy];
  959. [newRunLoopModes removeObject:runLoopMode];
  960. if([newRunLoopModes count] == 0)
  961. {
  962. return NO;
  963. }
  964. [NSObject cancelPreviousPerformRequestsWithTarget:self];
  965. theFlags &= ~kDequeueReadScheduled;
  966. theFlags &= ~kDequeueWriteScheduled;
  967. theRunLoopModes = [newRunLoopModes copy];
  968. if(theReadTimer) [self runLoopRemoveTimer:theReadTimer mode:runLoopMode];
  969. if(theWriteTimer) [self runLoopRemoveTimer:theWriteTimer mode:runLoopMode];
  970. if(theSource4) [self runLoopRemoveSource:theSource4 mode:runLoopMode];
  971. if(theSource6) [self runLoopRemoveSource:theSource6 mode:runLoopMode];
  972. if(theReadStream && theWriteStream)
  973. {
  974. CFReadStreamScheduleWithRunLoop(theReadStream, CFRunLoopGetCurrent(), (__bridge CFStringRef)runLoopMode);
  975. CFWriteStreamScheduleWithRunLoop(theWriteStream, CFRunLoopGetCurrent(), (__bridge CFStringRef)runLoopMode);
  976. }
  977. [self performSelector:@selector(maybeDequeueRead) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  978. [self performSelector:@selector(maybeDequeueWrite) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  979. [self performSelector:@selector(maybeScheduleDisconnect) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  980. return YES;
  981. }
  982. - (NSArray *)runLoopModes
  983. {
  984. #if DEBUG_THREAD_SAFETY
  985. [self checkForThreadSafety];
  986. #endif
  987. return theRunLoopModes;
  988. }
  989. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  990. #pragma mark Accepting
  991. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  992. - (BOOL)acceptOnPort:(UInt16)port error:(NSError **)errPtr
  993. {
  994. return [self acceptOnInterface:nil port:port error:errPtr];
  995. }
  996. /**
  997. * To accept on a certain interface, pass the address to accept on.
  998. * To accept on any interface, pass nil or an empty string.
  999. * To accept only connections from localhost pass "localhost" or "loopback".
  1000. **/
  1001. - (BOOL)acceptOnInterface:(NSString *)interface port:(UInt16)port error:(NSError **)errPtr
  1002. {
  1003. if (theDelegate == NULL)
  1004. {
  1005. [NSException raise:AsyncSocketException
  1006. format:@"Attempting to accept without a delegate. Set a delegate first."];
  1007. }
  1008. if (![self isDisconnected])
  1009. {
  1010. [NSException raise:AsyncSocketException
  1011. format:@"Attempting to accept while connected or accepting connections. Disconnect first."];
  1012. }
  1013. // Clear queues (spurious read/write requests post disconnect)
  1014. [self emptyQueues];
  1015. // Set up the listen sockaddr structs if needed.
  1016. NSData *address4 = nil, *address6 = nil;
  1017. if(interface == nil || ([interface length] == 0))
  1018. {
  1019. // Accept on ANY address
  1020. struct sockaddr_in nativeAddr4;
  1021. nativeAddr4.sin_len = sizeof(struct sockaddr_in);
  1022. nativeAddr4.sin_family = AF_INET;
  1023. nativeAddr4.sin_port = htons(port);
  1024. nativeAddr4.sin_addr.s_addr = htonl(INADDR_ANY);
  1025. memset(&(nativeAddr4.sin_zero), 0, sizeof(nativeAddr4.sin_zero));
  1026. struct sockaddr_in6 nativeAddr6;
  1027. nativeAddr6.sin6_len = sizeof(struct sockaddr_in6);
  1028. nativeAddr6.sin6_family = AF_INET6;
  1029. nativeAddr6.sin6_port = htons(port);
  1030. nativeAddr6.sin6_flowinfo = 0;
  1031. nativeAddr6.sin6_addr = in6addr_any;
  1032. nativeAddr6.sin6_scope_id = 0;
  1033. // Wrap the native address structures for CFSocketSetAddress.
  1034. address4 = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
  1035. address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
  1036. }
  1037. else if([interface isEqualToString:@"localhost"] || [interface isEqualToString:@"loopback"])
  1038. {
  1039. // Accept only on LOOPBACK address
  1040. struct sockaddr_in nativeAddr4;
  1041. nativeAddr4.sin_len = sizeof(struct sockaddr_in);
  1042. nativeAddr4.sin_family = AF_INET;
  1043. nativeAddr4.sin_port = htons(port);
  1044. nativeAddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  1045. memset(&(nativeAddr4.sin_zero), 0, sizeof(nativeAddr4.sin_zero));
  1046. struct sockaddr_in6 nativeAddr6;
  1047. nativeAddr6.sin6_len = sizeof(struct sockaddr_in6);
  1048. nativeAddr6.sin6_family = AF_INET6;
  1049. nativeAddr6.sin6_port = htons(port);
  1050. nativeAddr6.sin6_flowinfo = 0;
  1051. nativeAddr6.sin6_addr = in6addr_loopback;
  1052. nativeAddr6.sin6_scope_id = 0;
  1053. // Wrap the native address structures for CFSocketSetAddress.
  1054. address4 = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
  1055. address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
  1056. }
  1057. else
  1058. {
  1059. NSString *portStr = [NSString stringWithFormat:@"%hu", port];
  1060. struct addrinfo hints, *res, *res0;
  1061. memset(&hints, 0, sizeof(hints));
  1062. hints.ai_family = PF_UNSPEC;
  1063. hints.ai_socktype = SOCK_STREAM;
  1064. hints.ai_protocol = IPPROTO_TCP;
  1065. hints.ai_flags = AI_PASSIVE;
  1066. int error = getaddrinfo([interface UTF8String], [portStr UTF8String], &hints, &res0);
  1067. if (error)
  1068. {
  1069. if (errPtr)
  1070. {
  1071. NSString *errMsg = [NSString stringWithCString:gai_strerror(error) encoding:NSASCIIStringEncoding];
  1072. NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  1073. *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:error userInfo:info];
  1074. }
  1075. }
  1076. else
  1077. {
  1078. for (res = res0; res; res = res->ai_next)
  1079. {
  1080. if (!address4 && (res->ai_family == AF_INET))
  1081. {
  1082. // Found IPv4 address
  1083. // Wrap the native address structures for CFSocketSetAddress.
  1084. address4 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
  1085. }
  1086. else if (!address6 && (res->ai_family == AF_INET6))
  1087. {
  1088. // Found IPv6 address
  1089. // Wrap the native address structures for CFSocketSetAddress.
  1090. address6 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
  1091. }
  1092. }
  1093. freeaddrinfo(res0);
  1094. }
  1095. if(!address4 && !address6) return NO;
  1096. }
  1097. // Create the sockets.
  1098. if (address4)
  1099. {
  1100. theSocket4 = [self newAcceptSocketForAddress:address4 error:errPtr];
  1101. if (theSocket4 == NULL) goto Failed;
  1102. }
  1103. if (address6)
  1104. {
  1105. theSocket6 = [self newAcceptSocketForAddress:address6 error:errPtr];
  1106. // Note: The iPhone doesn't currently support IPv6
  1107. #if !TARGET_OS_IPHONE
  1108. if (theSocket6 == NULL) goto Failed;
  1109. #endif
  1110. }
  1111. // Attach the sockets to the run loop so that callback methods work
  1112. [self attachSocketsToRunLoop:nil error:nil];
  1113. // Set the SO_REUSEADDR flags.
  1114. int reuseOn = 1;
  1115. if (theSocket4) setsockopt(CFSocketGetNative(theSocket4), SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
  1116. if (theSocket6) setsockopt(CFSocketGetNative(theSocket6), SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
  1117. // Set the local bindings which causes the sockets to start listening.
  1118. CFSocketError err;
  1119. if (theSocket4)
  1120. {
  1121. err = CFSocketSetAddress(theSocket4, (__bridge CFDataRef)address4);
  1122. if (err != kCFSocketSuccess) goto Failed;
  1123. //NSLog(@"theSocket4: %hu", [self localPortFromCFSocket4:theSocket4]);
  1124. }
  1125. if(port == 0 && theSocket4 && theSocket6)
  1126. {
  1127. // The user has passed in port 0, which means he wants to allow the kernel to choose the port for them
  1128. // However, the kernel will choose a different port for both theSocket4 and theSocket6
  1129. // So we grab the port the kernel choose for theSocket4, and set it as the port for theSocket6
  1130. UInt16 chosenPort = [self localPortFromCFSocket4:theSocket4];
  1131. struct sockaddr_in6 *pSockAddr6 = (struct sockaddr_in6 *)[address6 bytes];
  1132. if (pSockAddr6) // If statement to quiet the static analyzer
  1133. {
  1134. pSockAddr6->sin6_port = htons(chosenPort);
  1135. }
  1136. }
  1137. if (theSocket6)
  1138. {
  1139. err = CFSocketSetAddress(theSocket6, (__bridge CFDataRef)address6);
  1140. if (err != kCFSocketSuccess) goto Failed;
  1141. //NSLog(@"theSocket6: %hu", [self localPortFromCFSocket6:theSocket6]);
  1142. }
  1143. theFlags |= kDidStartDelegate;
  1144. return YES;
  1145. Failed:
  1146. if(errPtr) *errPtr = [self getSocketError];
  1147. if(theSocket4 != NULL)
  1148. {
  1149. CFSocketInvalidate(theSocket4);
  1150. CFRelease(theSocket4);
  1151. theSocket4 = NULL;
  1152. }
  1153. if(theSocket6 != NULL)
  1154. {
  1155. CFSocketInvalidate(theSocket6);
  1156. CFRelease(theSocket6);
  1157. theSocket6 = NULL;
  1158. }
  1159. return NO;
  1160. }
  1161. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1162. #pragma mark Connecting
  1163. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1164. - (BOOL)connectToHost:(NSString*)hostname onPort:(UInt16)port error:(NSError **)errPtr
  1165. {
  1166. return [self connectToHost:hostname onPort:port withTimeout:-1 error:errPtr];
  1167. }
  1168. /**
  1169. * This method creates an initial CFReadStream and CFWriteStream to the given host on the given port.
  1170. * The connection is then opened, and the corresponding CFSocket will be extracted after the connection succeeds.
  1171. *
  1172. * Thus the delegate will have access to the CFReadStream and CFWriteStream prior to connection,
  1173. * specifically in the onSocketWillConnect: method.
  1174. **/
  1175. - (BOOL)connectToHost:(NSString *)hostname
  1176. onPort:(UInt16)port
  1177. withTimeout:(NSTimeInterval)timeout
  1178. error:(NSError **)errPtr
  1179. {
  1180. if (theDelegate == NULL)
  1181. {
  1182. [NSException raise:AsyncSocketException
  1183. format:@"Attempting to connect without a delegate. Set a delegate first."];
  1184. }
  1185. if (![self isDisconnected])
  1186. {
  1187. [NSException raise:AsyncSocketException
  1188. format:@"Attempting to connect while connected or accepting connections. Disconnect first."];
  1189. }
  1190. // Clear queues (spurious read/write requests post disconnect)
  1191. [self emptyQueues];
  1192. if(![self createStreamsToHost:hostname onPort:port error:errPtr]) goto Failed;
  1193. if(![self attachStreamsToRunLoop:nil error:errPtr]) goto Failed;
  1194. if(![self configureStreamsAndReturnError:errPtr]) goto Failed;
  1195. if(![self openStreamsAndReturnError:errPtr]) goto Failed;
  1196. [self startConnectTimeout:timeout];
  1197. theFlags |= kDidStartDelegate;
  1198. return YES;
  1199. Failed:
  1200. [self close];
  1201. return NO;
  1202. }
  1203. - (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr
  1204. {
  1205. return [self connectToAddress:remoteAddr viaInterfaceAddress:nil withTimeout:-1 error:errPtr];
  1206. }
  1207. /**
  1208. * This method creates an initial CFSocket to the given address.
  1209. * The connection is then opened, and the corresponding CFReadStream and CFWriteStream will be
  1210. * created from the low-level sockets after the connection succeeds.
  1211. *
  1212. * Thus the delegate will have access to the CFSocket and CFSocketNativeHandle (BSD socket) prior to connection,
  1213. * specifically in the onSocketWillConnect: method.
  1214. *
  1215. * Note: The NSData parameter is expected to be a sockaddr structure. For example, an NSData object returned from
  1216. * NSNetService addresses method.
  1217. * If you have an existing struct sockaddr you can convert it to an NSData object like so:
  1218. * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
  1219. * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
  1220. **/
  1221. - (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr
  1222. {
  1223. return [self connectToAddress:remoteAddr viaInterfaceAddress:nil withTimeout:timeout error:errPtr];
  1224. }
  1225. /**
  1226. * This method is similar to the one above, but allows you to specify which socket interface
  1227. * the connection should run over. E.g. ethernet, wifi, bluetooth, etc.
  1228. **/
  1229. - (BOOL)connectToAddress:(NSData *)remoteAddr
  1230. viaInterfaceAddress:(NSData *)interfaceAddr
  1231. withTimeout:(NSTimeInterval)timeout
  1232. error:(NSError **)errPtr
  1233. {
  1234. if (theDelegate == NULL)
  1235. {
  1236. [NSException raise:AsyncSocketException
  1237. format:@"Attempting to connect without a delegate. Set a delegate first."];
  1238. }
  1239. if (![self isDisconnected])
  1240. {
  1241. [NSException raise:AsyncSocketException
  1242. format:@"Attempting to connect while connected or accepting connections. Disconnect first."];
  1243. }
  1244. // Clear queues (spurious read/write requests post disconnect)
  1245. [self emptyQueues];
  1246. if(![self createSocketForAddress:remoteAddr error:errPtr]) goto Failed;
  1247. if(![self bindSocketToAddress:interfaceAddr error:errPtr]) goto Failed;
  1248. if(![self attachSocketsToRunLoop:nil error:errPtr]) goto Failed;
  1249. if(![self configureSocketAndReturnError:errPtr]) goto Failed;
  1250. if(![self connectSocketToAddress:remoteAddr error:errPtr]) goto Failed;
  1251. [self startConnectTimeout:timeout];
  1252. theFlags |= kDidStartDelegate;
  1253. return YES;
  1254. Failed:
  1255. [self close];
  1256. return NO;
  1257. }
  1258. - (void)startConnectTimeout:(NSTimeInterval)timeout
  1259. {
  1260. if(timeout >= 0.0)
  1261. {
  1262. theConnectTimer = [NSTimer timerWithTimeInterval:timeout
  1263. target:self
  1264. selector:@selector(doConnectTimeout:)
  1265. userInfo:nil
  1266. repeats:NO];
  1267. [self runLoopAddTimer:theConnectTimer];
  1268. }
  1269. }
  1270. - (void)endConnectTimeout
  1271. {
  1272. [theConnectTimer invalidate];
  1273. theConnectTimer = nil;
  1274. }
  1275. - (void)doConnectTimeout:(NSTimer *)timer
  1276. {
  1277. #pragma unused(timer)
  1278. [self endConnectTimeout];
  1279. [self closeWithError:[self getConnectTimeoutError]];
  1280. }
  1281. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1282. #pragma mark Socket Implementation
  1283. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1284. /**
  1285. * Creates the accept sockets.
  1286. * Returns true if either IPv4 or IPv6 is created.
  1287. * If either is missing, an error is returned (even though the method may return true).
  1288. **/
  1289. - (CFSocketRef)newAcceptSocketForAddress:(NSData *)addr error:(NSError **)errPtr
  1290. {
  1291. struct sockaddr *pSockAddr = (struct sockaddr *)[addr bytes];
  1292. int addressFamily = pSockAddr->sa_family;
  1293. CFSocketRef theSocket = CFSocketCreate(kCFAllocatorDefault,
  1294. addressFamily,
  1295. SOCK_STREAM,
  1296. 0,
  1297. kCFSocketAcceptCallBack, // Callback flags
  1298. (CFSocketCallBack)&MyCFSocketCallback, // Callback method
  1299. &theContext);
  1300. if(theSocket == NULL)
  1301. {
  1302. if(errPtr) *errPtr = [self getSocketError];
  1303. }
  1304. return theSocket;
  1305. }
  1306. - (BOOL)createSocketForAddress:(NSData *)remoteAddr error:(NSError **)errPtr
  1307. {
  1308. struct sockaddr *pSockAddr = (struct sockaddr *)[remoteAddr bytes];
  1309. if(pSockAddr->sa_family == AF_INET)
  1310. {
  1311. theSocket4 = CFSocketCreate(NULL, // Default allocator
  1312. PF_INET, // Protocol Family
  1313. SOCK_STREAM, // Socket Type
  1314. IPPROTO_TCP, // Protocol
  1315. kCFSocketConnectCallBack, // Callback flags
  1316. (CFSocketCallBack)&MyCFSocketCallback, // Callback method
  1317. &theContext); // Socket Context
  1318. if(theSocket4 == NULL)
  1319. {
  1320. if (errPtr) *errPtr = [self getSocketError];
  1321. return NO;
  1322. }
  1323. }
  1324. else if(pSockAddr->sa_family == AF_INET6)
  1325. {
  1326. theSocket6 = CFSocketCreate(NULL, // Default allocator
  1327. PF_INET6, // Protocol Family
  1328. SOCK_STREAM, // Socket Type
  1329. IPPROTO_TCP, // Protocol
  1330. kCFSocketConnectCallBack, // Callback flags
  1331. (CFSocketCallBack)&MyCFSocketCallback, // Callback method
  1332. &theContext); // Socket Context
  1333. if(theSocket6 == NULL)
  1334. {
  1335. if (errPtr) *errPtr = [self getSocketError];
  1336. return NO;
  1337. }
  1338. }
  1339. else
  1340. {
  1341. if (errPtr)
  1342. {
  1343. NSString *errMsg = @"Remote address is not IPv4 or IPv6";
  1344. NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg for